@openinc/parse-server-opendash 4.0.27 → 4.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/features/openservice/schedules/calendarSync/functions/eventToSchedule.d.ts +2 -2
- package/dist/features/openservice/schedules/calendarSync/functions/eventToSchedule.js +8 -11
- package/dist/features/openservice/schedules/calendarSync/functions/scheduleToEvent.js +24 -9
- package/dist/features/openservice/schedules/calendarSync/service/CalendarManager.d.ts +21 -2
- package/dist/features/openservice/schedules/calendarSync/service/CalendarManager.js +74 -15
- package/dist/features/openservice/schedules/calendarSync/service/CalendarSyncPoller.d.ts +17 -0
- package/dist/features/openservice/schedules/calendarSync/service/CalendarSyncPoller.js +165 -0
- package/dist/features/openservice/schedules/calendarSync/service/calendarMetaHelper.d.ts +36 -0
- package/dist/features/openservice/schedules/calendarSync/service/calendarMetaHelper.js +89 -0
- package/dist/features/openservice/schedules/calendarSync/types/Event.d.ts +1 -1
- package/dist/features/openservice/schedules/initSchedulesFeature.js +2 -0
- package/dist/hooks/MES_Order.js +0 -12
- package/dist/hooks/Maintenance_Schedule.js +18 -16
- package/dist/types/Meta_Config.d.ts +4 -3
- package/dist/types/Meta_Entry.d.ts +4 -3
- package/dist/types/custom/MetaField.d.ts +117 -0
- package/dist/types/custom/MetaField.js +21 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +4 -2
- package/package.json +1 -1
|
@@ -29,29 +29,26 @@ function eventToSchedule(event) {
|
|
|
29
29
|
? pattern.interval
|
|
30
30
|
: 1;
|
|
31
31
|
// Prefer explicit range.startDate, fallback to event.start.dateTime
|
|
32
|
-
let
|
|
32
|
+
let startDate;
|
|
33
33
|
if (range?.startDate) {
|
|
34
34
|
// range.startDate is YYYY-MM-DD
|
|
35
|
-
|
|
35
|
+
startDate = new Date(range.startDate + "T00:00:00Z");
|
|
36
36
|
}
|
|
37
37
|
else if (event.start?.dateTime) {
|
|
38
|
-
|
|
38
|
+
startDate = new Date(event.start.dateTime);
|
|
39
39
|
}
|
|
40
40
|
// For end, prefer range.endDate. If range.type === 'noEnd' leave undefined.
|
|
41
|
-
let
|
|
41
|
+
let endDate;
|
|
42
42
|
if (range?.type === "endDate" && range?.endDate) {
|
|
43
|
-
|
|
43
|
+
endDate = new Date(range.endDate + "T00:00:00Z");
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
endData = new Date(event.end.dateTime);
|
|
47
|
-
}
|
|
48
|
-
if (!startData)
|
|
45
|
+
if (!startDate)
|
|
49
46
|
return undefined;
|
|
50
47
|
return {
|
|
51
48
|
schedule_type: "timestamp",
|
|
52
49
|
timestamp: {
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
startDate,
|
|
51
|
+
endDate,
|
|
55
52
|
number: interval,
|
|
56
53
|
unit,
|
|
57
54
|
},
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.scheduleToEvent = scheduleToEvent;
|
|
7
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
4
8
|
async function scheduleToEvent(schedule) {
|
|
5
9
|
console.log("Converting Schedule to Event...");
|
|
6
10
|
try {
|
|
7
|
-
await schedule.fetchWithInclude("template"
|
|
11
|
+
await schedule.fetchWithInclude(["template"], {
|
|
12
|
+
useMasterKey: true,
|
|
13
|
+
});
|
|
8
14
|
}
|
|
9
15
|
catch (error) {
|
|
10
16
|
console.error("Error fetching template:", error);
|
|
@@ -16,19 +22,21 @@ async function scheduleToEvent(schedule) {
|
|
|
16
22
|
const end = scheduleCron?.timestamp?.endDate ?? templateCron?.timestamp?.endDate;
|
|
17
23
|
const interval = scheduleCron?.timestamp?.number ?? templateCron?.timestamp?.number;
|
|
18
24
|
const unit = scheduleCron?.timestamp?.unit ?? templateCron?.timestamp?.unit;
|
|
19
|
-
if (!start || !
|
|
25
|
+
if (!start || !interval || !unit) {
|
|
20
26
|
console.log("Insufficient data to create event from schedule.");
|
|
21
27
|
return;
|
|
22
28
|
}
|
|
29
|
+
const description = schedule.get("description");
|
|
23
30
|
const event = {
|
|
24
31
|
subject: schedule.get("title"),
|
|
32
|
+
body: { contentType: "Text", content: description ?? "" },
|
|
25
33
|
start: {
|
|
26
34
|
// for single-day/all-day events we use date-only; keep full ISO otherwise
|
|
27
35
|
dateTime: start.toISOString().slice(0, 19),
|
|
28
36
|
timeZone: "UTC",
|
|
29
37
|
},
|
|
30
38
|
end: {
|
|
31
|
-
dateTime:
|
|
39
|
+
dateTime: (0, dayjs_1.default)(start).add(1, "day").toISOString().slice(0, 19),
|
|
32
40
|
timeZone: "UTC",
|
|
33
41
|
},
|
|
34
42
|
isAllDay: true,
|
|
@@ -65,22 +73,29 @@ async function scheduleToEvent(schedule) {
|
|
|
65
73
|
pattern = null;
|
|
66
74
|
}
|
|
67
75
|
if (pattern) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
range: {
|
|
76
|
+
const range = end
|
|
77
|
+
? {
|
|
71
78
|
type: "endDate",
|
|
72
79
|
startDate: toDateOnly(start),
|
|
73
80
|
endDate: toDateOnly(end),
|
|
74
|
-
}
|
|
81
|
+
}
|
|
82
|
+
: {
|
|
83
|
+
type: "noEnd",
|
|
84
|
+
startDate: toDateOnly(start),
|
|
85
|
+
};
|
|
86
|
+
event.recurrence = {
|
|
87
|
+
pattern,
|
|
88
|
+
range,
|
|
75
89
|
};
|
|
76
|
-
// if event is all-day, set start/end to date-only values (Graph expects dates)
|
|
90
|
+
// if event is all-day, set start/end to date-only values (Graph expects dates) => always true for schedules
|
|
77
91
|
if (event.isAllDay) {
|
|
78
92
|
event.start.dateTime = toDateOnly(start);
|
|
79
93
|
// Graph's endDate in event object is exclusive for all-day events; keep as provided for recurrence range
|
|
80
94
|
// Set end to next day to represent an all-day event that begins and ends the same day
|
|
81
95
|
const endForEvent = new Date(start);
|
|
82
96
|
endForEvent.setUTCDate(endForEvent.getUTCDate() + 1);
|
|
83
|
-
event.end
|
|
97
|
+
if (event.end)
|
|
98
|
+
event.end.dateTime = toDateOnly(endForEvent);
|
|
84
99
|
}
|
|
85
100
|
}
|
|
86
101
|
console.log("Schedule converted to Event:", event);
|
|
@@ -3,7 +3,11 @@ import { GraphEvent, GraphEventResponse } from "../types/Event.js";
|
|
|
3
3
|
* Manager for calendar operations via Microsoft Graph API
|
|
4
4
|
*/
|
|
5
5
|
export declare class CalendarManager {
|
|
6
|
-
|
|
6
|
+
tenantID: string;
|
|
7
|
+
clientID: string;
|
|
8
|
+
clientSecret: string;
|
|
9
|
+
userMail: string;
|
|
10
|
+
get isValid(): true | string;
|
|
7
11
|
private getAccess;
|
|
8
12
|
/**
|
|
9
13
|
* Create a new event in the calendar
|
|
@@ -17,13 +21,14 @@ export declare class CalendarManager {
|
|
|
17
21
|
* @param event The updated event data
|
|
18
22
|
* @returns
|
|
19
23
|
*/
|
|
20
|
-
updateEvent(eventId: string, event: Partial<GraphEvent>): Promise<
|
|
24
|
+
updateEvent(eventId: string, event: Partial<GraphEvent>): Promise<GraphEventResponse | undefined>;
|
|
21
25
|
/**
|
|
22
26
|
* Delete an event from the calendar
|
|
23
27
|
* @param eventId The ID of the event to delete
|
|
24
28
|
* @returns whether the deletion was successful
|
|
25
29
|
*/
|
|
26
30
|
deleteEvent(eventId: string): Promise<boolean | undefined>;
|
|
31
|
+
fetchEvent(eventId: string): Promise<GraphEventResponse | null>;
|
|
27
32
|
/**
|
|
28
33
|
* Fetch all events in calendar
|
|
29
34
|
* @returns the list of events
|
|
@@ -31,4 +36,18 @@ export declare class CalendarManager {
|
|
|
31
36
|
fetchEvents(): Promise<{
|
|
32
37
|
value: GraphEventResponse[];
|
|
33
38
|
} | undefined>;
|
|
39
|
+
/**
|
|
40
|
+
* Fetch changed events since the last delta sync.
|
|
41
|
+
* On the first call (no deltaLink), returns all current events and a deltaLink
|
|
42
|
+
* for subsequent incremental calls.
|
|
43
|
+
* @param deltaLink token from the previous call; omit for the initial full sync
|
|
44
|
+
*/
|
|
45
|
+
fetchDelta(deltaLink?: string): Promise<{
|
|
46
|
+
events: (GraphEventResponse & {
|
|
47
|
+
"@removed"?: {
|
|
48
|
+
reason: string;
|
|
49
|
+
};
|
|
50
|
+
})[];
|
|
51
|
+
deltaLink: string;
|
|
52
|
+
} | null>;
|
|
34
53
|
}
|
|
@@ -2,26 +2,40 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CalendarManager = void 0;
|
|
4
4
|
const index_js_1 = require("../../../../config/index.js");
|
|
5
|
-
const tenantID = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_TENANT_ID");
|
|
6
|
-
const clientID = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_CLIENT_ID");
|
|
7
|
-
const clientSecret = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_CLIENT_SECRET");
|
|
8
|
-
const userMail = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_USER_EMAIL");
|
|
9
5
|
/**
|
|
10
6
|
* Manager for calendar operations via Microsoft Graph API
|
|
11
7
|
*/
|
|
12
8
|
class CalendarManager {
|
|
13
|
-
|
|
9
|
+
tenantID = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_TENANT_ID") ||
|
|
10
|
+
index_js_1.ConfigInstance.getInstance().get("OI_MICROSOFT_TENANT_ID");
|
|
11
|
+
clientID = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_CLIENT_ID") ||
|
|
12
|
+
index_js_1.ConfigInstance.getInstance().get("OI_MICROSOFT_APP_ID");
|
|
13
|
+
clientSecret = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_CLIENT_SECRET") ||
|
|
14
|
+
index_js_1.ConfigInstance.getInstance().get("OI_MICROSOFT_CLIENT_SECRET");
|
|
15
|
+
userMail = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_USER_EMAIL") ||
|
|
16
|
+
index_js_1.ConfigInstance.getInstance().get("OI_MICROSOFT_USER_EMAIL");
|
|
17
|
+
get isValid() {
|
|
18
|
+
if (!this.tenantID)
|
|
19
|
+
return "Missing Microsoft Tenant ID";
|
|
20
|
+
if (!this.clientID)
|
|
21
|
+
return "Missing Microsoft Client ID";
|
|
22
|
+
if (!this.clientSecret)
|
|
23
|
+
return "Missing Microsoft Client Secret";
|
|
24
|
+
if (!this.userMail)
|
|
25
|
+
return "Missing Microsoft User Email";
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
14
28
|
async getAccess() {
|
|
15
|
-
if (
|
|
29
|
+
if (this.isValid !== true)
|
|
16
30
|
return null;
|
|
17
31
|
console.log("Getting access token...");
|
|
18
32
|
try {
|
|
19
33
|
const params = new URLSearchParams();
|
|
20
|
-
params.append("client_id", clientID);
|
|
21
|
-
params.append("client_secret", clientSecret);
|
|
34
|
+
params.append("client_id", this.clientID);
|
|
35
|
+
params.append("client_secret", this.clientSecret);
|
|
22
36
|
params.append("scope", "https://graph.microsoft.com/.default");
|
|
23
37
|
params.append("grant_type", "client_credentials");
|
|
24
|
-
const response = await fetch(`https://login.microsoftonline.com/${tenantID}/oauth2/v2.0/token`, {
|
|
38
|
+
const response = await fetch(`https://login.microsoftonline.com/${this.tenantID}/oauth2/v2.0/token`, {
|
|
25
39
|
method: "POST",
|
|
26
40
|
headers: {
|
|
27
41
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
@@ -43,12 +57,15 @@ class CalendarManager {
|
|
|
43
57
|
* @returns the created event response
|
|
44
58
|
*/
|
|
45
59
|
async createEvent(event) {
|
|
46
|
-
if (!userMail ||
|
|
60
|
+
if (!this.userMail ||
|
|
61
|
+
!this.tenantID ||
|
|
62
|
+
!this.clientID ||
|
|
63
|
+
!this.clientSecret)
|
|
47
64
|
return;
|
|
48
65
|
const accessData = await this.getAccess();
|
|
49
66
|
if (!accessData?.access_token)
|
|
50
67
|
return;
|
|
51
|
-
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events`, {
|
|
68
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events`, {
|
|
52
69
|
method: "POST",
|
|
53
70
|
headers: {
|
|
54
71
|
Authorization: `Bearer ${accessData.access_token}`,
|
|
@@ -70,7 +87,7 @@ class CalendarManager {
|
|
|
70
87
|
const accessData = await this.getAccess();
|
|
71
88
|
if (!accessData?.access_token)
|
|
72
89
|
return;
|
|
73
|
-
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events/${eventId}`, {
|
|
90
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events/${eventId}`, {
|
|
74
91
|
method: "PATCH",
|
|
75
92
|
headers: {
|
|
76
93
|
Authorization: `Bearer ${accessData.access_token}`,
|
|
@@ -78,7 +95,7 @@ class CalendarManager {
|
|
|
78
95
|
},
|
|
79
96
|
body: JSON.stringify(event),
|
|
80
97
|
});
|
|
81
|
-
const data = await res.json();
|
|
98
|
+
const data = (await res.json());
|
|
82
99
|
console.log("Event update response:", data);
|
|
83
100
|
return data;
|
|
84
101
|
}
|
|
@@ -92,7 +109,7 @@ class CalendarManager {
|
|
|
92
109
|
if (!accessData?.access_token)
|
|
93
110
|
return;
|
|
94
111
|
// on successful deletion, Microsoft Graph returns 204 No Content, so no JSON to parse
|
|
95
|
-
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events/${eventId}`, {
|
|
112
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events/${eventId}`, {
|
|
96
113
|
method: "DELETE",
|
|
97
114
|
headers: {
|
|
98
115
|
Authorization: `Bearer ${accessData.access_token}`,
|
|
@@ -101,6 +118,15 @@ class CalendarManager {
|
|
|
101
118
|
console.log("Event deletion response:", res);
|
|
102
119
|
return res.ok;
|
|
103
120
|
}
|
|
121
|
+
async fetchEvent(eventId) {
|
|
122
|
+
const accessData = await this.getAccess();
|
|
123
|
+
if (!accessData?.access_token)
|
|
124
|
+
return null;
|
|
125
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events/${eventId}`, { headers: { Authorization: `Bearer ${accessData.access_token}` } });
|
|
126
|
+
if (!res.ok)
|
|
127
|
+
return null;
|
|
128
|
+
return (await res.json());
|
|
129
|
+
}
|
|
104
130
|
/**
|
|
105
131
|
* Fetch all events in calendar
|
|
106
132
|
* @returns the list of events
|
|
@@ -109,7 +135,7 @@ class CalendarManager {
|
|
|
109
135
|
const accessData = await this.getAccess();
|
|
110
136
|
if (!accessData?.access_token)
|
|
111
137
|
return;
|
|
112
|
-
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events`, {
|
|
138
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events`, {
|
|
113
139
|
method: "GET",
|
|
114
140
|
headers: {
|
|
115
141
|
Authorization: `Bearer ${accessData.access_token}`,
|
|
@@ -119,5 +145,38 @@ class CalendarManager {
|
|
|
119
145
|
console.log("Calendar events:", data);
|
|
120
146
|
return data;
|
|
121
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Fetch changed events since the last delta sync.
|
|
150
|
+
* On the first call (no deltaLink), returns all current events and a deltaLink
|
|
151
|
+
* for subsequent incremental calls.
|
|
152
|
+
* @param deltaLink token from the previous call; omit for the initial full sync
|
|
153
|
+
*/
|
|
154
|
+
async fetchDelta(deltaLink) {
|
|
155
|
+
const accessData = await this.getAccess();
|
|
156
|
+
if (!accessData?.access_token)
|
|
157
|
+
return null;
|
|
158
|
+
const events = [];
|
|
159
|
+
let nextUrl = deltaLink || // treat empty string same as missing
|
|
160
|
+
`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events/delta`;
|
|
161
|
+
let newDeltaLink = "";
|
|
162
|
+
while (nextUrl) {
|
|
163
|
+
const res = await fetch(nextUrl, {
|
|
164
|
+
headers: { Authorization: `Bearer ${accessData.access_token}` },
|
|
165
|
+
});
|
|
166
|
+
if (!res.ok) {
|
|
167
|
+
console.error(`[CalendarManager] fetchDelta HTTP ${res.status}:`, await res.text());
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
const data = (await res.json());
|
|
171
|
+
events.push(...(data.value ?? []));
|
|
172
|
+
nextUrl = data["@odata.nextLink"];
|
|
173
|
+
if (data["@odata.deltaLink"])
|
|
174
|
+
newDeltaLink = data["@odata.deltaLink"];
|
|
175
|
+
}
|
|
176
|
+
console.log("Delta fetch result:", { events, newDeltaLink });
|
|
177
|
+
if (!newDeltaLink)
|
|
178
|
+
return null;
|
|
179
|
+
return { events, deltaLink: newDeltaLink };
|
|
180
|
+
}
|
|
122
181
|
}
|
|
123
182
|
exports.CalendarManager = CalendarManager;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare class CalendarSyncPoller {
|
|
2
|
+
private manager;
|
|
3
|
+
private timer;
|
|
4
|
+
/**
|
|
5
|
+
* Start polling the Microsoft Calendar delta feed.
|
|
6
|
+
* @param intervalMs polling interval in milliseconds (default: 5 minutes)
|
|
7
|
+
*/
|
|
8
|
+
start(intervalMs?: number): void;
|
|
9
|
+
stop(): void;
|
|
10
|
+
private poll;
|
|
11
|
+
private processEvent;
|
|
12
|
+
private updateScheduleFromEvent;
|
|
13
|
+
private createScheduleFromEvent;
|
|
14
|
+
private handleDeleted;
|
|
15
|
+
private loadDeltaLink;
|
|
16
|
+
private saveDeltaLink;
|
|
17
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CalendarSyncPoller = void 0;
|
|
7
|
+
const node_1 = __importDefault(require("parse/node"));
|
|
8
|
+
const eventToSchedule_js_1 = require("../functions/eventToSchedule.js");
|
|
9
|
+
const calendarMetaHelper_js_1 = require("./calendarMetaHelper.js");
|
|
10
|
+
const CalendarManager_js_1 = require("./CalendarManager.js");
|
|
11
|
+
const index_js_1 = require("../../../../../types/index.js");
|
|
12
|
+
const DELTA_LINK_CONFIG_KEY = "microsoftCalendarDeltaLink";
|
|
13
|
+
class CalendarSyncPoller {
|
|
14
|
+
manager = new CalendarManager_js_1.CalendarManager();
|
|
15
|
+
timer = null;
|
|
16
|
+
/**
|
|
17
|
+
* Start polling the Microsoft Calendar delta feed.
|
|
18
|
+
* @param intervalMs polling interval in milliseconds (default: 5 minutes)
|
|
19
|
+
*/
|
|
20
|
+
start(intervalMs = 5 * 60 * 1000) {
|
|
21
|
+
if (this.manager.isValid !== true) {
|
|
22
|
+
console.log("[CalendarSyncPoller] Not started — missing Microsoft credentials.", this.manager.isValid);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
this.poll().catch(console.error);
|
|
26
|
+
this.timer = setInterval(() => this.poll().catch(console.error), intervalMs);
|
|
27
|
+
}
|
|
28
|
+
stop() {
|
|
29
|
+
if (this.timer)
|
|
30
|
+
clearInterval(this.timer);
|
|
31
|
+
}
|
|
32
|
+
async poll() {
|
|
33
|
+
console.log("[CalendarSyncPoller] Polling calendar delta...");
|
|
34
|
+
const deltaLink = await this.loadDeltaLink();
|
|
35
|
+
const result = await this.manager.fetchDelta(deltaLink ?? undefined);
|
|
36
|
+
if (!result) {
|
|
37
|
+
console.log("[CalendarSyncPoller] Failed to fetch calendar delta.");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
for (const event of result.events) {
|
|
41
|
+
try {
|
|
42
|
+
await this.processEvent(event);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
console.error("[CalendarSyncPoller] Error processing event:", event.id, err);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
await this.saveDeltaLink(result.deltaLink);
|
|
49
|
+
}
|
|
50
|
+
async processEvent(event) {
|
|
51
|
+
if (event["@removed"]) {
|
|
52
|
+
await this.handleDeleted(event.id);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const metaEntry = await (0, calendarMetaHelper_js_1.findCalendarMetaByEventId)(event.id);
|
|
56
|
+
if (metaEntry) {
|
|
57
|
+
const storedChangeKey = metaEntry.get("values")?.microsoftCalendarChangeKey;
|
|
58
|
+
// Skip if we caused this change (our write already stored this changeKey)
|
|
59
|
+
if (event.changeKey && storedChangeKey === event.changeKey)
|
|
60
|
+
return;
|
|
61
|
+
await this.updateScheduleFromEvent(metaEntry, event);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Delta responses omit most properties; fetch the full event before creating a schedule
|
|
65
|
+
const fullEvent = await this.manager.fetchEvent(event.id);
|
|
66
|
+
if (!fullEvent)
|
|
67
|
+
return;
|
|
68
|
+
await this.createScheduleFromEvent(fullEvent);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async updateScheduleFromEvent(metaEntry, event) {
|
|
72
|
+
const scheduleId = metaEntry.get("entryObjectId");
|
|
73
|
+
if (!scheduleId)
|
|
74
|
+
return;
|
|
75
|
+
// Delta responses omit most fields; fetch the full event for title/body/cron
|
|
76
|
+
const fullEvent = await this.manager.fetchEvent(event.id) ?? event;
|
|
77
|
+
const schedule = await new node_1.default.Query(index_js_1.Maintenance_Schedule).get(scheduleId, { useMasterKey: true });
|
|
78
|
+
if (fullEvent.subject)
|
|
79
|
+
schedule.set("title", fullEvent.subject);
|
|
80
|
+
if (fullEvent.bodyPreview)
|
|
81
|
+
schedule.set("description", fullEvent.bodyPreview);
|
|
82
|
+
const cronData = (0, eventToSchedule_js_1.eventToSchedule)(fullEvent);
|
|
83
|
+
if (cronData)
|
|
84
|
+
schedule.set("cron", cronData);
|
|
85
|
+
// useMasterKey prevents afterSaveHook from re-syncing back to calendar
|
|
86
|
+
await schedule.save(null, { useMasterKey: true });
|
|
87
|
+
if (event.changeKey) {
|
|
88
|
+
await (0, calendarMetaHelper_js_1.updateCalendarChangeKey)(metaEntry, event.changeKey, fullEvent);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async createScheduleFromEvent(event) {
|
|
92
|
+
const parsed = parseEventSubject(event.subject);
|
|
93
|
+
if (!parsed) {
|
|
94
|
+
console.log(`[CalendarSyncPoller] Skipping event "${event.subject}" (${event.id}) — subject does not match expected format: '"<source>" - <title>'.`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const source = await new node_1.default.Query(index_js_1.Source)
|
|
98
|
+
.equalTo("name", parsed.sourceName)
|
|
99
|
+
.first({ useMasterKey: true });
|
|
100
|
+
if (!source) {
|
|
101
|
+
console.log(`[CalendarSyncPoller] Skipping event "${event.subject}" (${event.id}) — no Source found with name "${parsed.sourceName}".`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const schedule = new index_js_1.Maintenance_Schedule();
|
|
105
|
+
schedule.set("title", event.subject);
|
|
106
|
+
schedule.set("source", source);
|
|
107
|
+
schedule.set("enabled", true);
|
|
108
|
+
schedule.set("tenant", source.get("tenant"));
|
|
109
|
+
if (event.bodyPreview)
|
|
110
|
+
schedule.set("description", event.bodyPreview);
|
|
111
|
+
const cronData = (0, eventToSchedule_js_1.eventToSchedule)(event);
|
|
112
|
+
if (cronData)
|
|
113
|
+
schedule.set("cron", cronData);
|
|
114
|
+
// useMasterKey prevents afterSaveHook from syncing back to calendar
|
|
115
|
+
await schedule.save(null, { useMasterKey: true });
|
|
116
|
+
await (0, calendarMetaHelper_js_1.saveCalendarMeta)(schedule.id, event.id, event.changeKey, source.get("tenant"), event);
|
|
117
|
+
console.log(`[CalendarSyncPoller] Created schedule "${event.subject}" for source "${parsed.sourceName}" from calendar event ${event.id}.`);
|
|
118
|
+
}
|
|
119
|
+
async handleDeleted(eventId) {
|
|
120
|
+
const metaEntry = await (0, calendarMetaHelper_js_1.findCalendarMetaByEventId)(eventId);
|
|
121
|
+
if (!metaEntry)
|
|
122
|
+
return;
|
|
123
|
+
const scheduleId = metaEntry.get("entryObjectId");
|
|
124
|
+
if (scheduleId) {
|
|
125
|
+
try {
|
|
126
|
+
const schedule = await new node_1.default.Query(index_js_1.Maintenance_Schedule).get(scheduleId, { useMasterKey: true });
|
|
127
|
+
// Disable rather than delete to preserve execution history
|
|
128
|
+
schedule.set("enabled", false);
|
|
129
|
+
await schedule.save(null, { useMasterKey: true });
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
console.error("[CalendarSyncPoller] Could not disable schedule for deleted event:", scheduleId, err);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
await metaEntry.destroy({ useMasterKey: true });
|
|
136
|
+
}
|
|
137
|
+
async loadDeltaLink() {
|
|
138
|
+
try {
|
|
139
|
+
const config = await node_1.default.Config.get({ useMasterKey: true });
|
|
140
|
+
return config.get(DELTA_LINK_CONFIG_KEY) || null;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async saveDeltaLink(link) {
|
|
147
|
+
await node_1.default.Config.save({ [DELTA_LINK_CONFIG_KEY]: link }, { useMasterKey: true });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.CalendarSyncPoller = CalendarSyncPoller;
|
|
151
|
+
// Parses the source name out of an Outlook-originated event subject.
|
|
152
|
+
// Expected format for externally-created events: "<source.name>" - <anything>
|
|
153
|
+
// Quotes around the source name are optional.
|
|
154
|
+
function parseEventSubject(subject) {
|
|
155
|
+
if (!subject)
|
|
156
|
+
return null;
|
|
157
|
+
const separatorIdx = subject.indexOf(" - ");
|
|
158
|
+
if (separatorIdx === -1)
|
|
159
|
+
return null;
|
|
160
|
+
const rawSource = subject.slice(0, separatorIdx).trim();
|
|
161
|
+
if (!rawSource)
|
|
162
|
+
return null;
|
|
163
|
+
const sourceName = rawSource.replace(/^"(.*)"$/, "$1");
|
|
164
|
+
return { sourceName };
|
|
165
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Meta_Entry, Tenant } from "../../../../../types/index.js";
|
|
2
|
+
import { MetaConfig } from "../../../../../types/custom/MetaField.js";
|
|
3
|
+
import { GraphEventResponse } from "../types/Event.js";
|
|
4
|
+
export declare const CALENDAR_SYNC_CONTEXT: string;
|
|
5
|
+
export interface CalendarEventSnapshot {
|
|
6
|
+
id: string;
|
|
7
|
+
subject?: string;
|
|
8
|
+
start: {
|
|
9
|
+
dateTime: string;
|
|
10
|
+
timeZone: string;
|
|
11
|
+
};
|
|
12
|
+
end: {
|
|
13
|
+
dateTime: string;
|
|
14
|
+
timeZone: string;
|
|
15
|
+
};
|
|
16
|
+
isAllDay?: boolean;
|
|
17
|
+
isCancelled?: boolean;
|
|
18
|
+
body?: {
|
|
19
|
+
contentType?: string;
|
|
20
|
+
content?: string;
|
|
21
|
+
};
|
|
22
|
+
recurrence?: GraphEventResponse["recurrence"];
|
|
23
|
+
location?: {
|
|
24
|
+
displayName?: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export interface CalendarMetaValues {
|
|
28
|
+
microsoftCalendarEventId: string;
|
|
29
|
+
microsoftCalendarChangeKey?: string;
|
|
30
|
+
microsoftCalendarEvent?: CalendarEventSnapshot;
|
|
31
|
+
}
|
|
32
|
+
export declare const CalendarMetaConfig: MetaConfig;
|
|
33
|
+
export declare function findCalendarMetaForSchedule(scheduleId: string): Promise<Meta_Entry | null>;
|
|
34
|
+
export declare function findCalendarMetaByEventId(eventId: string): Promise<Meta_Entry | null>;
|
|
35
|
+
export declare function saveCalendarMeta(scheduleId: string, eventId: string, changeKey?: string, tenant?: Tenant, event?: GraphEventResponse): Promise<Meta_Entry>;
|
|
36
|
+
export declare function updateCalendarChangeKey(entry: Meta_Entry, changeKey: string, event?: GraphEventResponse): Promise<void>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CalendarMetaConfig = exports.CALENDAR_SYNC_CONTEXT = void 0;
|
|
7
|
+
exports.findCalendarMetaForSchedule = findCalendarMetaForSchedule;
|
|
8
|
+
exports.findCalendarMetaByEventId = findCalendarMetaByEventId;
|
|
9
|
+
exports.saveCalendarMeta = saveCalendarMeta;
|
|
10
|
+
exports.updateCalendarChangeKey = updateCalendarChangeKey;
|
|
11
|
+
const node_1 = __importDefault(require("parse/node"));
|
|
12
|
+
const index_js_1 = require("../../../../../types/index.js");
|
|
13
|
+
exports.CALENDAR_SYNC_CONTEXT = JSON.stringify([
|
|
14
|
+
"schedule",
|
|
15
|
+
"sync",
|
|
16
|
+
"microsoft",
|
|
17
|
+
]);
|
|
18
|
+
function toEventSnapshot(event) {
|
|
19
|
+
return {
|
|
20
|
+
id: event.id,
|
|
21
|
+
subject: event.subject,
|
|
22
|
+
start: event.start,
|
|
23
|
+
end: event.end,
|
|
24
|
+
isAllDay: event.isAllDay,
|
|
25
|
+
isCancelled: event.isCancelled,
|
|
26
|
+
body: event.body
|
|
27
|
+
? { contentType: event.body.contentType, content: event.body.content }
|
|
28
|
+
: undefined,
|
|
29
|
+
recurrence: event.recurrence ?? undefined,
|
|
30
|
+
location: event.location?.displayName
|
|
31
|
+
? { displayName: event.location.displayName }
|
|
32
|
+
: undefined,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
exports.CalendarMetaConfig = {
|
|
36
|
+
fields: [
|
|
37
|
+
{
|
|
38
|
+
name: "microsoftCalendarEventId",
|
|
39
|
+
type: "string",
|
|
40
|
+
label: "Microsoft Calendar Event ID",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "microsoftCalendarChangeKey",
|
|
44
|
+
type: "string",
|
|
45
|
+
label: "Microsoft Calendar Change Key",
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
async function findCalendarMetaForSchedule(scheduleId) {
|
|
50
|
+
return ((await new node_1.default.Query(index_js_1.Meta_Entry)
|
|
51
|
+
.equalTo("context", exports.CALENDAR_SYNC_CONTEXT)
|
|
52
|
+
.equalTo("entryClassName", index_js_1.Maintenance_Schedule.className)
|
|
53
|
+
.equalTo("entryObjectId", scheduleId)
|
|
54
|
+
.first({ useMasterKey: true })) ?? null);
|
|
55
|
+
}
|
|
56
|
+
async function findCalendarMetaByEventId(eventId) {
|
|
57
|
+
return ((await new node_1.default.Query(index_js_1.Meta_Entry)
|
|
58
|
+
.equalTo("context", exports.CALENDAR_SYNC_CONTEXT)
|
|
59
|
+
.equalTo("entryClassName", index_js_1.Maintenance_Schedule.className)
|
|
60
|
+
// @ts-expect-error
|
|
61
|
+
.equalTo("values.microsoftCalendarEventId", eventId)
|
|
62
|
+
.first({ useMasterKey: true })) ?? null);
|
|
63
|
+
}
|
|
64
|
+
async function saveCalendarMeta(scheduleId, eventId, changeKey, tenant, event) {
|
|
65
|
+
let entry = await findCalendarMetaForSchedule(scheduleId);
|
|
66
|
+
if (!entry) {
|
|
67
|
+
entry = new index_js_1.Meta_Entry();
|
|
68
|
+
entry.set("context", exports.CALENDAR_SYNC_CONTEXT);
|
|
69
|
+
entry.set("entryClassName", index_js_1.Maintenance_Schedule.className);
|
|
70
|
+
entry.set("entryObjectId", scheduleId);
|
|
71
|
+
entry.set("tenant", tenant);
|
|
72
|
+
entry.set("config", {});
|
|
73
|
+
}
|
|
74
|
+
const values = { microsoftCalendarEventId: eventId };
|
|
75
|
+
if (changeKey)
|
|
76
|
+
values.microsoftCalendarChangeKey = changeKey;
|
|
77
|
+
if (event)
|
|
78
|
+
values.microsoftCalendarEvent = toEventSnapshot(event);
|
|
79
|
+
entry.set("values", values);
|
|
80
|
+
return entry.save(null, { useMasterKey: true });
|
|
81
|
+
}
|
|
82
|
+
async function updateCalendarChangeKey(entry, changeKey, event) {
|
|
83
|
+
entry.set("values", {
|
|
84
|
+
...entry.get("values"),
|
|
85
|
+
microsoftCalendarChangeKey: changeKey,
|
|
86
|
+
...(event ? { microsoftCalendarEvent: toEventSnapshot(event) } : {}),
|
|
87
|
+
});
|
|
88
|
+
await entry.save(null, { useMasterKey: true });
|
|
89
|
+
}
|
|
@@ -6,8 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.initSchedulesFeature = initSchedulesFeature;
|
|
7
7
|
const node_1 = __importDefault(require("parse/node"));
|
|
8
8
|
const index_js_1 = require("../../../types/index.js");
|
|
9
|
+
const CalendarSyncPoller_js_1 = require("./calendarSync/service/CalendarSyncPoller.js");
|
|
9
10
|
async function initSchedulesFeature() {
|
|
10
11
|
updateFiinishedSchedules();
|
|
12
|
+
new CalendarSyncPoller_js_1.CalendarSyncPoller().start(1000 * 60);
|
|
11
13
|
}
|
|
12
14
|
async function updateFiinishedSchedules() {
|
|
13
15
|
const executionsToUpdate = await new node_1.default.Query(index_js_1.Maintenance_Schedule_Execution)
|
package/dist/hooks/MES_Order.js
CHANGED
|
@@ -80,8 +80,6 @@ async function init() {
|
|
|
80
80
|
scheduleOrderStartedStatusCheck("0 * * * * *");
|
|
81
81
|
(0, index_js_2.beforeSaveHook)(index_js_3.MES_Order, async (request) => {
|
|
82
82
|
const { object, original, user } = request;
|
|
83
|
-
console.log("===".repeat(10) + " BEFORE SAVE HOOK " + "===".repeat(10));
|
|
84
|
-
console.log("[MES] - beforeSaveHook: Received order \n" + JSON.stringify(object.toJSON(), null, 2) + "\n with original \n" + JSON.stringify(original?.toJSON(), null, 2) + "\n by user " + user?.getEmail());
|
|
85
83
|
await (0, index_js_2.defaultHandler)(request);
|
|
86
84
|
await (0, index_js_2.defaultAclHandler)(request, {
|
|
87
85
|
allowCustomACL: true,
|
|
@@ -152,13 +150,9 @@ async function init() {
|
|
|
152
150
|
}
|
|
153
151
|
}
|
|
154
152
|
}
|
|
155
|
-
console.log("[MES] - beforeSaveHook: Finished processing order " + object.id + " with final status " + object.get("status"));
|
|
156
|
-
console.log("===".repeat(10) + " END BEFORE SAVE HOOK " + "===".repeat(10));
|
|
157
153
|
});
|
|
158
154
|
(0, index_js_2.afterSaveHook)(index_js_3.MES_Order, async (request) => {
|
|
159
155
|
const { object, original, user } = request;
|
|
160
|
-
console.log("===".repeat(10) + " AFTER SAVE HOOK " + "===".repeat(10));
|
|
161
|
-
console.log("[MES] - afterSaveHook: Received order \n" + JSON.stringify(object.toJSON(), null, 2) + " with original \n" + JSON.stringify(original?.toJSON(), null, 2) + " by user \n" + user?.getEmail());
|
|
162
156
|
try {
|
|
163
157
|
if (original) {
|
|
164
158
|
// If the order is canceled, publish it as canceled
|
|
@@ -193,7 +187,6 @@ async function init() {
|
|
|
193
187
|
runningData.name = "Order_Running";
|
|
194
188
|
console.log("-".repeat(20));
|
|
195
189
|
console.log("Publishing running order " + object.id);
|
|
196
|
-
console.log("Data:", JSON.stringify(runningData));
|
|
197
190
|
console.log("-".repeat(20));
|
|
198
191
|
await (0, index_js_1.publishDataItem)(runningData, user?.getEmail() || undefined, true);
|
|
199
192
|
}
|
|
@@ -202,12 +195,9 @@ async function init() {
|
|
|
202
195
|
console.error(e);
|
|
203
196
|
console.log("Order Data not published:" + e.message, e);
|
|
204
197
|
}
|
|
205
|
-
console.log("[MES] - afterSaveHook: Finished processing order " + object.id);
|
|
206
|
-
console.log("===".repeat(10) + " END AFTER SAVE HOOK " + "===".repeat(10));
|
|
207
198
|
});
|
|
208
199
|
}
|
|
209
200
|
async function object2OWItem(object) {
|
|
210
|
-
console.log("[MES] - object2OWItem: Converting order " + JSON.stringify(object.toJSON(), null, 2) + " to DataItemInterface");
|
|
211
201
|
const tag = object.get("tag");
|
|
212
202
|
const configString = await new node_1.default.Query("OD3_Config")
|
|
213
203
|
.equalTo("key", "ow.mes.unitInfo")
|
|
@@ -280,7 +270,6 @@ function createCustomValueTypes(object, fields, fieldInfos) {
|
|
|
280
270
|
});
|
|
281
271
|
}
|
|
282
272
|
async function createValueArrayForObject(object, extraValues, fields) {
|
|
283
|
-
console.log("[MES] - createValueArrayForObject: Creating values object " + JSON.stringify(object.toJSON(), null, 2) + " with extraValues " + JSON.stringify(extraValues));
|
|
284
273
|
const values = [];
|
|
285
274
|
const status = object.get("status");
|
|
286
275
|
const ordernr = object.get("ordernr");
|
|
@@ -319,7 +308,6 @@ async function createValueArrayForObject(object, extraValues, fields) {
|
|
|
319
308
|
}
|
|
320
309
|
values.push(value);
|
|
321
310
|
}
|
|
322
|
-
console.log("[MES] - createValueArrayForObject: Created values object for order " + object.id + ": ", values);
|
|
323
311
|
return [{ date: object.get("start").getTime(), value: values }];
|
|
324
312
|
}
|
|
325
313
|
function scheduleOrderStartedStatusCheck(cronInterval) {
|
|
@@ -6,12 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.init = init;
|
|
7
7
|
const node_1 = __importDefault(require("parse/node"));
|
|
8
8
|
const scheduleToEvent_1 = require("../features/openservice/schedules/calendarSync/functions/scheduleToEvent");
|
|
9
|
+
const calendarMetaHelper_1 = require("../features/openservice/schedules/calendarSync/service/calendarMetaHelper");
|
|
9
10
|
const CalendarManager_1 = require("../features/openservice/schedules/calendarSync/service/CalendarManager");
|
|
10
11
|
const schema_1 = require("../features/schema");
|
|
11
12
|
const types_1 = require("../types");
|
|
12
13
|
async function init() {
|
|
13
14
|
(0, schema_1.beforeSaveHook)(types_1.Maintenance_Schedule, async (request) => {
|
|
14
|
-
const { object, original, user } = request;
|
|
15
15
|
await (0, schema_1.defaultHandler)(request);
|
|
16
16
|
// await defaultAclHandler(request, { allowCustomACL: true });
|
|
17
17
|
});
|
|
@@ -51,7 +51,7 @@ async function init() {
|
|
|
51
51
|
}
|
|
52
52
|
});
|
|
53
53
|
(0, schema_1.beforeDeleteHook)(types_1.Maintenance_Schedule, async (request) => {
|
|
54
|
-
const { object
|
|
54
|
+
const { object } = request;
|
|
55
55
|
const scheduleFetched = await object?.fetchWithInclude(["template", "source"], {
|
|
56
56
|
useMasterKey: true,
|
|
57
57
|
});
|
|
@@ -60,9 +60,13 @@ async function init() {
|
|
|
60
60
|
if (source)
|
|
61
61
|
template?.relation("sources").remove(source);
|
|
62
62
|
await template?.save(null, { useMasterKey: true });
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
|
|
63
|
+
const metaEntry = await (0, calendarMetaHelper_1.findCalendarMetaForSchedule)(object.id);
|
|
64
|
+
if (metaEntry) {
|
|
65
|
+
const eventId = metaEntry.get("values")?.microsoftCalendarEventId;
|
|
66
|
+
if (eventId) {
|
|
67
|
+
await new CalendarManager_1.CalendarManager().deleteEvent(eventId);
|
|
68
|
+
}
|
|
69
|
+
await metaEntry.destroy({ useMasterKey: true });
|
|
66
70
|
}
|
|
67
71
|
});
|
|
68
72
|
}
|
|
@@ -89,11 +93,14 @@ async function updateCalendarEvent(schedule) {
|
|
|
89
93
|
if (!event)
|
|
90
94
|
return;
|
|
91
95
|
const calendarManager = new CalendarManager_1.CalendarManager();
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
96
|
+
const metaEntry = await (0, calendarMetaHelper_1.findCalendarMetaForSchedule)(schedule.id);
|
|
97
|
+
const eventId = metaEntry?.get("values")?.microsoftCalendarEventId;
|
|
98
|
+
if (eventId) {
|
|
95
99
|
console.log("Updating schedule in calendar...");
|
|
96
|
-
await calendarManager.updateEvent(
|
|
100
|
+
const updatedEvent = await calendarManager.updateEvent(eventId, event);
|
|
101
|
+
if (updatedEvent?.changeKey && metaEntry) {
|
|
102
|
+
await (0, calendarMetaHelper_1.updateCalendarChangeKey)(metaEntry, updatedEvent.changeKey, updatedEvent);
|
|
103
|
+
}
|
|
97
104
|
}
|
|
98
105
|
else {
|
|
99
106
|
await addToCalendar(schedule);
|
|
@@ -110,12 +117,7 @@ async function addToCalendar(schedule) {
|
|
|
110
117
|
return;
|
|
111
118
|
const calendarManager = new CalendarManager_1.CalendarManager();
|
|
112
119
|
const createdEvent = await calendarManager.createEvent(event);
|
|
113
|
-
if (createdEvent
|
|
114
|
-
|
|
115
|
-
schedule.set("meta", {
|
|
116
|
-
...existingMeta,
|
|
117
|
-
microsoftCalendarEventId: createdEvent.id,
|
|
118
|
-
});
|
|
119
|
-
await schedule.save(null, { useMasterKey: true });
|
|
120
|
+
if (createdEvent?.id) {
|
|
121
|
+
await (0, calendarMetaHelper_1.saveCalendarMeta)(schedule.id, createdEvent.id, createdEvent.changeKey, schedule.get("tenant"), createdEvent);
|
|
120
122
|
}
|
|
121
123
|
}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import Parse from "parse/node";
|
|
2
2
|
import type { Tenant } from "./Tenant";
|
|
3
|
+
import { MetaConfig } from "./custom/MetaField";
|
|
3
4
|
export interface Meta_ConfigAttributes {
|
|
4
5
|
id: string;
|
|
5
6
|
objectId: string;
|
|
6
7
|
createdAt: Date;
|
|
7
8
|
updatedAt: Date;
|
|
8
|
-
config:
|
|
9
|
+
config: MetaConfig;
|
|
9
10
|
context?: string | undefined;
|
|
10
11
|
tenant?: Tenant | undefined;
|
|
11
12
|
}
|
|
12
13
|
export declare class Meta_Config extends Parse.Object<Meta_ConfigAttributes> {
|
|
13
14
|
static className: string;
|
|
14
15
|
constructor(data?: Partial<Meta_ConfigAttributes>);
|
|
15
|
-
get config():
|
|
16
|
-
set config(value:
|
|
16
|
+
get config(): MetaConfig;
|
|
17
|
+
set config(value: MetaConfig);
|
|
17
18
|
get context(): string | undefined;
|
|
18
19
|
set context(value: string | undefined);
|
|
19
20
|
get tenant(): Tenant | undefined;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import Parse from "parse/node";
|
|
2
2
|
import type { Meta_Config } from "./Meta_Config";
|
|
3
3
|
import type { Tenant } from "./Tenant";
|
|
4
|
+
import { MetaConfig } from "./custom/MetaField";
|
|
4
5
|
export interface Meta_EntryAttributes {
|
|
5
6
|
id: string;
|
|
6
7
|
objectId: string;
|
|
7
8
|
createdAt: Date;
|
|
8
9
|
updatedAt: Date;
|
|
9
|
-
config?:
|
|
10
|
+
config?: MetaConfig | undefined;
|
|
10
11
|
context?: string | undefined;
|
|
11
12
|
entryClassName?: string | undefined;
|
|
12
13
|
entryObjectId?: string | undefined;
|
|
@@ -17,8 +18,8 @@ export interface Meta_EntryAttributes {
|
|
|
17
18
|
export declare class Meta_Entry extends Parse.Object<Meta_EntryAttributes> {
|
|
18
19
|
static className: string;
|
|
19
20
|
constructor(data?: Partial<Meta_EntryAttributes>);
|
|
20
|
-
get config():
|
|
21
|
-
set config(value:
|
|
21
|
+
get config(): MetaConfig | undefined;
|
|
22
|
+
set config(value: MetaConfig | undefined);
|
|
22
23
|
get context(): string | undefined;
|
|
23
24
|
set context(value: string | undefined);
|
|
24
25
|
get entryClassName(): string | undefined;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base properties shared by all meta field types
|
|
3
|
+
*/
|
|
4
|
+
export type MetaFieldBaseConfig = {
|
|
5
|
+
name: string;
|
|
6
|
+
label: string;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
help?: string;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
/** Default value for the field */
|
|
11
|
+
defaultValue?: any;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* String field type with optional validation
|
|
15
|
+
*/
|
|
16
|
+
export type MetaFieldString = MetaFieldBaseConfig & {
|
|
17
|
+
type: "string";
|
|
18
|
+
minLength?: number;
|
|
19
|
+
maxLength?: number;
|
|
20
|
+
pattern?: string;
|
|
21
|
+
multiline?: boolean;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Number field type with min/max constraints
|
|
25
|
+
*/
|
|
26
|
+
export type MetaFieldNumber = MetaFieldBaseConfig & {
|
|
27
|
+
type: "number";
|
|
28
|
+
min?: number;
|
|
29
|
+
max?: number;
|
|
30
|
+
step?: number;
|
|
31
|
+
unit?: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Boolean field type (checkbox/switch)
|
|
35
|
+
*/
|
|
36
|
+
export type MetaFieldBoolean = MetaFieldBaseConfig & {
|
|
37
|
+
type: "boolean";
|
|
38
|
+
defaultValue?: boolean;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Date field type with optional date range constraints
|
|
42
|
+
*/
|
|
43
|
+
export type MetaFieldDate = MetaFieldBaseConfig & {
|
|
44
|
+
type: "date";
|
|
45
|
+
minDate?: Date;
|
|
46
|
+
maxDate?: Date;
|
|
47
|
+
includeTime?: boolean;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Select field type with predefined options
|
|
51
|
+
*/
|
|
52
|
+
export type MetaFieldSelect = MetaFieldBaseConfig & {
|
|
53
|
+
type: "select";
|
|
54
|
+
options: Array<{
|
|
55
|
+
label: string;
|
|
56
|
+
value: string;
|
|
57
|
+
disabled?: boolean;
|
|
58
|
+
}>;
|
|
59
|
+
/** Optional grouping for select options */
|
|
60
|
+
groups?: Array<{
|
|
61
|
+
label: string;
|
|
62
|
+
options: Array<{
|
|
63
|
+
label: string;
|
|
64
|
+
value: string;
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
}>;
|
|
67
|
+
}>;
|
|
68
|
+
multiple?: boolean;
|
|
69
|
+
defaultValue?: string | string[];
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Parse select field type for selecting Parse objects
|
|
73
|
+
*/
|
|
74
|
+
export type MetaFieldSelectParse = MetaFieldBaseConfig & {
|
|
75
|
+
type: "select_parse";
|
|
76
|
+
className: string;
|
|
77
|
+
display?: string;
|
|
78
|
+
multiple?: boolean;
|
|
79
|
+
defaultValue?: string | string[];
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Array of all available field types
|
|
83
|
+
*/
|
|
84
|
+
export declare const META_FIELD_TYPES: readonly ["string", "number", "boolean", "date", "select", "select_parse"];
|
|
85
|
+
/**
|
|
86
|
+
* Literal type for field types derived from the array
|
|
87
|
+
*/
|
|
88
|
+
export type MetaFieldTypes = (typeof META_FIELD_TYPES)[number];
|
|
89
|
+
/**
|
|
90
|
+
* Mapped type for accessing MetaField types by their string literal
|
|
91
|
+
* @example MetaFieldMap["string"] => MetaFieldString
|
|
92
|
+
*/
|
|
93
|
+
export type MetaFieldMap = {
|
|
94
|
+
string: MetaFieldString;
|
|
95
|
+
number: MetaFieldNumber;
|
|
96
|
+
boolean: MetaFieldBoolean;
|
|
97
|
+
date: MetaFieldDate;
|
|
98
|
+
select: MetaFieldSelect;
|
|
99
|
+
select_parse: MetaFieldSelectParse;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Union type of all specific meta field types
|
|
103
|
+
*/
|
|
104
|
+
export type MetaFieldConfig = MetaFieldString | MetaFieldNumber | MetaFieldBoolean | MetaFieldDate | MetaFieldSelect | MetaFieldSelectParse;
|
|
105
|
+
/**
|
|
106
|
+
* Helper type to extract specific field type from MetaField union
|
|
107
|
+
*/
|
|
108
|
+
export type MetaFieldOfType<T extends MetaFieldTypes> = Extract<MetaFieldConfig, {
|
|
109
|
+
type: T;
|
|
110
|
+
}>;
|
|
111
|
+
/**
|
|
112
|
+
* Type guard to check if a field is of a specific type
|
|
113
|
+
*/
|
|
114
|
+
export declare function isMetaFieldType<T extends MetaFieldTypes>(field: MetaFieldConfig, type: T): field is MetaFieldOfType<T>;
|
|
115
|
+
export type MetaConfig = {
|
|
116
|
+
fields: MetaFieldConfig[];
|
|
117
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.META_FIELD_TYPES = void 0;
|
|
4
|
+
exports.isMetaFieldType = isMetaFieldType;
|
|
5
|
+
/**
|
|
6
|
+
* Array of all available field types
|
|
7
|
+
*/
|
|
8
|
+
exports.META_FIELD_TYPES = [
|
|
9
|
+
"string",
|
|
10
|
+
"number",
|
|
11
|
+
"boolean",
|
|
12
|
+
"date",
|
|
13
|
+
"select",
|
|
14
|
+
"select_parse",
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* Type guard to check if a field is of a specific type
|
|
18
|
+
*/
|
|
19
|
+
function isMetaFieldType(field, type) {
|
|
20
|
+
return field.type === type;
|
|
21
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -140,6 +140,8 @@ export { Maintenance_Schedule_Step } from "./Maintenance_Schedule_Step";
|
|
|
140
140
|
export type { Maintenance_Schedule_StepAttributes } from "./Maintenance_Schedule_Step";
|
|
141
141
|
export { Maintenance_Schedule_Template } from "./Maintenance_Schedule_Template";
|
|
142
142
|
export type { Maintenance_Schedule_TemplateAttributes } from "./Maintenance_Schedule_Template";
|
|
143
|
+
export { Maintenance_SourceMeta } from "./Maintenance_SourceMeta";
|
|
144
|
+
export type { Maintenance_SourceMetaAttributes } from "./Maintenance_SourceMeta";
|
|
143
145
|
export { Maintenance_Source_File } from "./Maintenance_Source_File";
|
|
144
146
|
export type { Maintenance_Source_FileAttributes } from "./Maintenance_Source_File";
|
|
145
147
|
export { Maintenance_Ticket } from "./Maintenance_Ticket";
|
package/dist/types/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MES_OrderPlan = exports.MES_Order = exports.MES_Article = exports.Log = exports.Language = exports.Knowledge_Video = exports.Knowledge_DocumentPage = exports.Knowledge_Document = exports.Knowledge_ChatMessage = exports.Knowledge_Chat = exports.Knowledge_Category = exports.Knowledge_Article = exports.GTFS_Wheelchair_Boarding = exports.GTFS_Wheelchair_Accessible = exports.GTFS_Trip = exports.GTFS_Stop_Times = exports.GTFS_Stop = exports.GTFS_Route_Type = exports.GTFS_Route = exports.GTFS_Location_Type = exports.GTFS_Level = exports.GTFS_Direction = exports.GTFS_Calendar = exports.GTFS_Bikes_Allowed = exports.GTFS_Agency = exports.EMS_ChargePoint = exports.Documentation_Document = exports.Documentation_Config = exports.Documentation_Category = exports.Dashboard = exports.Core_Token = exports.Core_Email = exports.Contact = exports.Config = exports.Company = exports.Changelog = exports.BDE_WorkTime = exports.BDE_WorkOrder = exports.BDE_Unit = exports.BDE_Result = exports.BDE_Page = exports.BDE_ListEntry = exports.BDE_List = exports.BDE_Form = exports.BDE_Article = exports.Attachment = exports.Assets = exports.AlarmWebhook = exports.AlarmAction = exports.Alarm = void 0;
|
|
4
|
-
exports.
|
|
5
|
-
exports.WidgetPreset = exports.Widget = exports.WebPush = exports.VirtualKPI = exports.User_Setting = exports.UserData = exports.TenantTrustedDomain = exports.TenantMeta = exports.Tenant = exports.Spreadsheet_Workbook = exports.SourceMeta = exports.Source = exports.Share = exports.Report = exports.RAG_Request = exports.RAG_Questions = exports.RAG_Prompts = exports.RAG_Meta = exports.RAG_Interview = void 0;
|
|
4
|
+
exports.Push = exports.Permission = exports.OWPlcItem = exports.OWPlcDevice = exports.Notification_Setting = exports.Notification = exports.NavigationItem = exports.NavigationGroup = exports.Monitoring_Slideshow = exports.Monitoring_ReportImage = exports.Monitoring_ParseTableSensor = exports.Monitoring_Jobs = exports.Monitoring_DataHierachies = exports.Meta_Entry = exports.Meta_Config = exports.Maintenance_Ticket_Title = exports.Maintenance_Ticket_Source = exports.Maintenance_Ticket_QR_Code = exports.Maintenance_Ticket_Project = exports.Maintenance_Ticket_Material = exports.Maintenance_Ticket_Kanban_State_Current = exports.Maintenance_Ticket_Kanban_State = exports.Maintenance_Ticket_Issuecategory = exports.Maintenance_Ticket_FormConfig = exports.Maintenance_Ticket_Data = exports.Maintenance_Ticket_Assignment = exports.Maintenance_Ticket = exports.Maintenance_Source_File = exports.Maintenance_SourceMeta = exports.Maintenance_Schedule_Template = exports.Maintenance_Schedule_Step = exports.Maintenance_Schedule_Execution_Step = exports.Maintenance_Schedule_Execution = exports.Maintenance_Schedule = exports.Maintenance_Restriction = exports.Maintenance_Project = exports.Maintenance_Priority = exports.Maintenance_Order = exports.Maintenance_Message = exports.Maintenance_Media = exports.Maintenance_Kanban_State = exports.Maintenance_Item = exports.Maintenance_Issuecategory = exports.Maintenance_Frequency = exports.Maintenance_Duedate = exports.Maintenance_Downtime = exports.Mail_Groups = exports.MailTemplate = exports.ML_DataSelection = exports.MIAAS_MDSEndpoint = void 0;
|
|
5
|
+
exports.WidgetPreset = exports.Widget = exports.WebPush = exports.VirtualKPI = exports.User_Setting = exports.UserData = exports.TenantTrustedDomain = exports.TenantMeta = exports.Tenant = exports.Spreadsheet_Workbook = exports.SourceMeta = exports.Source = exports.Share = exports.Report = exports.RAG_Request = exports.RAG_Questions = exports.RAG_Prompts = exports.RAG_Meta = exports.RAG_Interview = exports.RAG_Data = void 0;
|
|
6
6
|
var Alarm_1 = require("./Alarm");
|
|
7
7
|
Object.defineProperty(exports, "Alarm", { enumerable: true, get: function () { return Alarm_1.Alarm; } });
|
|
8
8
|
var AlarmAction_1 = require("./AlarmAction");
|
|
@@ -145,6 +145,8 @@ var Maintenance_Schedule_Step_1 = require("./Maintenance_Schedule_Step");
|
|
|
145
145
|
Object.defineProperty(exports, "Maintenance_Schedule_Step", { enumerable: true, get: function () { return Maintenance_Schedule_Step_1.Maintenance_Schedule_Step; } });
|
|
146
146
|
var Maintenance_Schedule_Template_1 = require("./Maintenance_Schedule_Template");
|
|
147
147
|
Object.defineProperty(exports, "Maintenance_Schedule_Template", { enumerable: true, get: function () { return Maintenance_Schedule_Template_1.Maintenance_Schedule_Template; } });
|
|
148
|
+
var Maintenance_SourceMeta_1 = require("./Maintenance_SourceMeta");
|
|
149
|
+
Object.defineProperty(exports, "Maintenance_SourceMeta", { enumerable: true, get: function () { return Maintenance_SourceMeta_1.Maintenance_SourceMeta; } });
|
|
148
150
|
var Maintenance_Source_File_1 = require("./Maintenance_Source_File");
|
|
149
151
|
Object.defineProperty(exports, "Maintenance_Source_File", { enumerable: true, get: function () { return Maintenance_Source_File_1.Maintenance_Source_File; } });
|
|
150
152
|
var Maintenance_Ticket_1 = require("./Maintenance_Ticket");
|