@openinc/parse-server-opendash 3.24.6 → 3.25.0
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 +11 -0
- package/dist/features/openservice/schedules/calendarSync/functions/eventToSchedule.js +59 -0
- package/dist/features/openservice/schedules/calendarSync/functions/scheduleToEvent.d.ts +3 -0
- package/dist/features/openservice/schedules/calendarSync/functions/scheduleToEvent.js +88 -0
- package/dist/features/openservice/schedules/calendarSync/service/CalendarManager.d.ts +34 -0
- package/dist/features/openservice/schedules/calendarSync/service/CalendarManager.js +124 -0
- package/dist/features/openservice/schedules/calendarSync/types/Access.d.ts +9 -0
- package/dist/features/openservice/schedules/calendarSync/types/Access.js +2 -0
- package/dist/features/openservice/schedules/calendarSync/types/Event.d.ts +150 -0
- package/dist/features/openservice/schedules/calendarSync/types/Event.js +2 -0
- package/dist/hooks/Maintenance_Schedule.js +51 -3
- package/dist/types/Maintenance_Schedule.d.ts +12 -12
- package/dist/types/Maintenance_Schedule.js +6 -3
- package/package.json +1 -1
- package/schema/Maintenance_Schedule.json +4 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { GraphEventResponse } from "../types/Event";
|
|
2
|
+
export type ScheduleCronTimestamp = {
|
|
3
|
+
startData: Date;
|
|
4
|
+
endData?: Date;
|
|
5
|
+
number: number;
|
|
6
|
+
unit: "days" | "weeks" | "months";
|
|
7
|
+
};
|
|
8
|
+
export declare function eventToSchedule(event: GraphEventResponse): {
|
|
9
|
+
timestamp: ScheduleCronTimestamp;
|
|
10
|
+
schedule_type: "timestamp";
|
|
11
|
+
} | undefined;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.eventToSchedule = eventToSchedule;
|
|
4
|
+
function eventToSchedule(event) {
|
|
5
|
+
const recurrence = event?.recurrence;
|
|
6
|
+
if (!recurrence)
|
|
7
|
+
return undefined;
|
|
8
|
+
const pattern = recurrence.pattern;
|
|
9
|
+
const range = recurrence.range;
|
|
10
|
+
if (!pattern || !range || !pattern.type)
|
|
11
|
+
return undefined;
|
|
12
|
+
let unit;
|
|
13
|
+
switch (pattern.type) {
|
|
14
|
+
case "daily":
|
|
15
|
+
unit = "days";
|
|
16
|
+
break;
|
|
17
|
+
case "weekly":
|
|
18
|
+
unit = "weeks";
|
|
19
|
+
break;
|
|
20
|
+
case "absoluteMonthly":
|
|
21
|
+
case "relativeMonthly":
|
|
22
|
+
unit = "months";
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
// unsupported recurrence type
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const interval = typeof pattern.interval === "number" && pattern.interval > 0
|
|
29
|
+
? pattern.interval
|
|
30
|
+
: 1;
|
|
31
|
+
// Prefer explicit range.startDate, fallback to event.start.dateTime
|
|
32
|
+
let startData;
|
|
33
|
+
if (range?.startDate) {
|
|
34
|
+
// range.startDate is YYYY-MM-DD
|
|
35
|
+
startData = new Date(range.startDate + "T00:00:00Z");
|
|
36
|
+
}
|
|
37
|
+
else if (event.start?.dateTime) {
|
|
38
|
+
startData = new Date(event.start.dateTime);
|
|
39
|
+
}
|
|
40
|
+
// For end, prefer range.endDate. If range.type === 'noEnd' leave undefined.
|
|
41
|
+
let endData;
|
|
42
|
+
if (range?.type === "endDate" && range?.endDate) {
|
|
43
|
+
endData = new Date(range.endDate + "T00:00:00Z");
|
|
44
|
+
}
|
|
45
|
+
else if (event.end?.dateTime) {
|
|
46
|
+
endData = new Date(event.end.dateTime);
|
|
47
|
+
}
|
|
48
|
+
if (!startData)
|
|
49
|
+
return undefined;
|
|
50
|
+
return {
|
|
51
|
+
schedule_type: "timestamp",
|
|
52
|
+
timestamp: {
|
|
53
|
+
startData,
|
|
54
|
+
endData,
|
|
55
|
+
number: interval,
|
|
56
|
+
unit,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scheduleToEvent = scheduleToEvent;
|
|
4
|
+
async function scheduleToEvent(schedule) {
|
|
5
|
+
console.log("Converting Schedule to Event...");
|
|
6
|
+
try {
|
|
7
|
+
await schedule.fetchWithInclude("template");
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
console.error("Error fetching template:", error);
|
|
11
|
+
}
|
|
12
|
+
const template = schedule.get("template");
|
|
13
|
+
const templateCron = template?.get("cron");
|
|
14
|
+
const scheduleCron = schedule.get("cron");
|
|
15
|
+
const start = scheduleCron?.timestamp?.startDate ?? templateCron?.timestamp?.startDate;
|
|
16
|
+
const end = scheduleCron?.timestamp?.endDate ?? templateCron?.timestamp?.endDate;
|
|
17
|
+
const interval = scheduleCron?.timestamp?.number ?? templateCron?.timestamp?.number;
|
|
18
|
+
const unit = scheduleCron?.timestamp?.unit ?? templateCron?.timestamp?.unit;
|
|
19
|
+
if (!start || !end || !interval || !unit) {
|
|
20
|
+
console.log("Insufficient data to create event from schedule.");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const event = {
|
|
24
|
+
subject: schedule.get("title"),
|
|
25
|
+
start: {
|
|
26
|
+
// for single-day/all-day events we use date-only; keep full ISO otherwise
|
|
27
|
+
dateTime: start.toISOString().slice(0, 19),
|
|
28
|
+
timeZone: "UTC",
|
|
29
|
+
},
|
|
30
|
+
end: {
|
|
31
|
+
dateTime: end.toISOString().slice(0, 19),
|
|
32
|
+
timeZone: "UTC",
|
|
33
|
+
},
|
|
34
|
+
isAllDay: true,
|
|
35
|
+
};
|
|
36
|
+
// Helper to format date as YYYY-MM-DD for recurrence range
|
|
37
|
+
const toDateOnly = (d) => d.toISOString().slice(0, 10);
|
|
38
|
+
// determine pattern type and additional fields
|
|
39
|
+
let pattern = { interval };
|
|
40
|
+
if (unit === "days") {
|
|
41
|
+
pattern.type = "daily";
|
|
42
|
+
}
|
|
43
|
+
else if (unit === "weeks") {
|
|
44
|
+
pattern.type = "weekly";
|
|
45
|
+
// include the weekday of the start date so weekly recurrences occur on that weekday
|
|
46
|
+
const dayNames = [
|
|
47
|
+
"Sunday",
|
|
48
|
+
"Monday",
|
|
49
|
+
"Tuesday",
|
|
50
|
+
"Wednesday",
|
|
51
|
+
"Thursday",
|
|
52
|
+
"Friday",
|
|
53
|
+
"Saturday",
|
|
54
|
+
];
|
|
55
|
+
pattern.daysOfWeek = [dayNames[start.getUTCDay()]];
|
|
56
|
+
pattern.firstDayOfWeek = "Monday";
|
|
57
|
+
}
|
|
58
|
+
else if (unit === "months") {
|
|
59
|
+
pattern.type = "absoluteMonthly";
|
|
60
|
+
// Graph uses dayOfMonth for absoluteMonthly
|
|
61
|
+
pattern.dayOfMonth = start.getUTCDate();
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// unsupported unit -> skip recurrence
|
|
65
|
+
pattern = null;
|
|
66
|
+
}
|
|
67
|
+
if (pattern) {
|
|
68
|
+
event.recurrence = {
|
|
69
|
+
pattern,
|
|
70
|
+
range: {
|
|
71
|
+
type: "endDate",
|
|
72
|
+
startDate: toDateOnly(start),
|
|
73
|
+
endDate: toDateOnly(end),
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
// if event is all-day, set start/end to date-only values (Graph expects dates)
|
|
77
|
+
if (event.isAllDay) {
|
|
78
|
+
event.start.dateTime = toDateOnly(start);
|
|
79
|
+
// Graph's endDate in event object is exclusive for all-day events; keep as provided for recurrence range
|
|
80
|
+
// Set end to next day to represent an all-day event that begins and ends the same day
|
|
81
|
+
const endForEvent = new Date(start);
|
|
82
|
+
endForEvent.setUTCDate(endForEvent.getUTCDate() + 1);
|
|
83
|
+
event.end.dateTime = toDateOnly(endForEvent);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
console.log("Schedule converted to Event:", event);
|
|
87
|
+
return event;
|
|
88
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { GraphEvent, GraphEventResponse } from "../types/Event";
|
|
2
|
+
/**
|
|
3
|
+
* Manager for calendar operations via Microsoft Graph API
|
|
4
|
+
*/
|
|
5
|
+
export declare class CalendarManager {
|
|
6
|
+
isValid: boolean;
|
|
7
|
+
private getAccess;
|
|
8
|
+
/**
|
|
9
|
+
* Create a new event in the calendar
|
|
10
|
+
* @param event The event data to create
|
|
11
|
+
* @returns the created event response
|
|
12
|
+
*/
|
|
13
|
+
createEvent(event: GraphEvent): Promise<GraphEventResponse | undefined>;
|
|
14
|
+
/**
|
|
15
|
+
* Update an event in the calendar
|
|
16
|
+
* @param eventId The ID of the event to update
|
|
17
|
+
* @param event The updated event data
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
updateEvent(eventId: string, event: Partial<GraphEvent>): Promise<unknown>;
|
|
21
|
+
/**
|
|
22
|
+
* Delete an event from the calendar
|
|
23
|
+
* @param eventId The ID of the event to delete
|
|
24
|
+
* @returns whether the deletion was successful
|
|
25
|
+
*/
|
|
26
|
+
deleteEvent(eventId: string): Promise<boolean | undefined>;
|
|
27
|
+
/**
|
|
28
|
+
* Fetch all events in calendar
|
|
29
|
+
* @returns the list of events
|
|
30
|
+
*/
|
|
31
|
+
fetchEvents(): Promise<{
|
|
32
|
+
value: GraphEventResponse[];
|
|
33
|
+
} | undefined>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CalendarManager = void 0;
|
|
4
|
+
const tenantID = process.env.MICROSOFT_TENANT_ID;
|
|
5
|
+
const clientID = process.env.MICROSOFT_CLIENT_ID;
|
|
6
|
+
const clientSecret = process.env.MICROSOFT_CLIENT_SECRET;
|
|
7
|
+
const userMail = process.env.MICROSOFT_USER_EMAIL;
|
|
8
|
+
/**
|
|
9
|
+
* Manager for calendar operations via Microsoft Graph API
|
|
10
|
+
*/
|
|
11
|
+
class CalendarManager {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.isValid = !!(tenantID && clientID && clientSecret && userMail);
|
|
14
|
+
}
|
|
15
|
+
async getAccess() {
|
|
16
|
+
if (!this.isValid)
|
|
17
|
+
return null;
|
|
18
|
+
console.log("Getting access token...");
|
|
19
|
+
try {
|
|
20
|
+
const params = new URLSearchParams();
|
|
21
|
+
params.append("client_id", clientID);
|
|
22
|
+
params.append("client_secret", clientSecret);
|
|
23
|
+
params.append("scope", "https://graph.microsoft.com/.default");
|
|
24
|
+
params.append("grant_type", "client_credentials");
|
|
25
|
+
const response = await fetch(`https://login.microsoftonline.com/${tenantID}/oauth2/v2.0/token`, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: {
|
|
28
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
29
|
+
},
|
|
30
|
+
body: params.toString(),
|
|
31
|
+
});
|
|
32
|
+
const data = await response.json();
|
|
33
|
+
console.log("Access token fetched successfully:", data);
|
|
34
|
+
return data;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error("Error fetching access token:", error);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a new event in the calendar
|
|
43
|
+
* @param event The event data to create
|
|
44
|
+
* @returns the created event response
|
|
45
|
+
*/
|
|
46
|
+
async createEvent(event) {
|
|
47
|
+
if (!userMail || !tenantID || !clientID || !clientSecret)
|
|
48
|
+
return;
|
|
49
|
+
const accessData = await this.getAccess();
|
|
50
|
+
if (!accessData?.access_token)
|
|
51
|
+
return;
|
|
52
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events`, {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: {
|
|
55
|
+
Authorization: `Bearer ${accessData.access_token}`,
|
|
56
|
+
"Content-Type": "application/json",
|
|
57
|
+
},
|
|
58
|
+
body: JSON.stringify(event),
|
|
59
|
+
});
|
|
60
|
+
const data = (await res.json());
|
|
61
|
+
console.log("Event creation response:", data);
|
|
62
|
+
return data;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Update an event in the calendar
|
|
66
|
+
* @param eventId The ID of the event to update
|
|
67
|
+
* @param event The updated event data
|
|
68
|
+
* @returns
|
|
69
|
+
*/
|
|
70
|
+
async updateEvent(eventId, event) {
|
|
71
|
+
const accessData = await this.getAccess();
|
|
72
|
+
if (!accessData?.access_token)
|
|
73
|
+
return;
|
|
74
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events/${eventId}`, {
|
|
75
|
+
method: "PATCH",
|
|
76
|
+
headers: {
|
|
77
|
+
Authorization: `Bearer ${accessData.access_token}`,
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
},
|
|
80
|
+
body: JSON.stringify(event),
|
|
81
|
+
});
|
|
82
|
+
const data = await res.json();
|
|
83
|
+
console.log("Event update response:", data);
|
|
84
|
+
return data;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Delete an event from the calendar
|
|
88
|
+
* @param eventId The ID of the event to delete
|
|
89
|
+
* @returns whether the deletion was successful
|
|
90
|
+
*/
|
|
91
|
+
async deleteEvent(eventId) {
|
|
92
|
+
const accessData = await this.getAccess();
|
|
93
|
+
if (!accessData?.access_token)
|
|
94
|
+
return;
|
|
95
|
+
// on successful deletion, Microsoft Graph returns 204 No Content, so no JSON to parse
|
|
96
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events/${eventId}`, {
|
|
97
|
+
method: "DELETE",
|
|
98
|
+
headers: {
|
|
99
|
+
Authorization: `Bearer ${accessData.access_token}`,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
console.log("Event deletion response:", res);
|
|
103
|
+
return res.ok;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Fetch all events in calendar
|
|
107
|
+
* @returns the list of events
|
|
108
|
+
*/
|
|
109
|
+
async fetchEvents() {
|
|
110
|
+
const accessData = await this.getAccess();
|
|
111
|
+
if (!accessData?.access_token)
|
|
112
|
+
return;
|
|
113
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events`, {
|
|
114
|
+
method: "GET",
|
|
115
|
+
headers: {
|
|
116
|
+
Authorization: `Bearer ${accessData.access_token}`,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
const data = await res.json();
|
|
120
|
+
console.log("Calendar events:", data);
|
|
121
|
+
return data;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.CalendarManager = CalendarManager;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
export type DateTimeTimeZone = {
|
|
2
|
+
dateTime: string;
|
|
3
|
+
timeZone: string;
|
|
4
|
+
};
|
|
5
|
+
export type EmailAddress = {
|
|
6
|
+
name?: string;
|
|
7
|
+
address: string;
|
|
8
|
+
};
|
|
9
|
+
export type Attendee = {
|
|
10
|
+
type?: "required" | "optional" | "resource";
|
|
11
|
+
emailAddress: EmailAddress;
|
|
12
|
+
};
|
|
13
|
+
export type ItemBody = {
|
|
14
|
+
contentType?: "Text" | "HTML";
|
|
15
|
+
content?: string;
|
|
16
|
+
};
|
|
17
|
+
export type LocationAddress = {
|
|
18
|
+
street?: string;
|
|
19
|
+
city?: string;
|
|
20
|
+
state?: string;
|
|
21
|
+
countryOrRegion?: string;
|
|
22
|
+
postalCode?: string;
|
|
23
|
+
};
|
|
24
|
+
export type Location = {
|
|
25
|
+
displayName?: string;
|
|
26
|
+
locationEmailAddress?: string;
|
|
27
|
+
locationUri?: string;
|
|
28
|
+
address?: LocationAddress;
|
|
29
|
+
locationType?: string;
|
|
30
|
+
uniqueId?: string;
|
|
31
|
+
};
|
|
32
|
+
export type RecurrencePattern = {
|
|
33
|
+
type: "daily" | "weekly" | "absoluteMonthly" | "relativeMonthly" | "absoluteYearly" | "relativeYearly";
|
|
34
|
+
interval?: number;
|
|
35
|
+
daysOfWeek?: Array<"Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday">;
|
|
36
|
+
firstDayOfWeek?: "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday";
|
|
37
|
+
month?: number;
|
|
38
|
+
index?: "first" | "second" | "third" | "fourth" | "last";
|
|
39
|
+
};
|
|
40
|
+
export type RecurrenceRange = {
|
|
41
|
+
type: "noEnd";
|
|
42
|
+
startDate: string;
|
|
43
|
+
} | {
|
|
44
|
+
type: "endDate";
|
|
45
|
+
startDate: string;
|
|
46
|
+
endDate: string;
|
|
47
|
+
} | {
|
|
48
|
+
type: "numbered";
|
|
49
|
+
startDate: string;
|
|
50
|
+
numberOfOccurrences: number;
|
|
51
|
+
};
|
|
52
|
+
export type Recurrence = {
|
|
53
|
+
pattern: RecurrencePattern;
|
|
54
|
+
range: RecurrenceRange;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Graph Event type for creating/updating events
|
|
58
|
+
*/
|
|
59
|
+
export type GraphEvent = {
|
|
60
|
+
subject?: string;
|
|
61
|
+
body?: ItemBody;
|
|
62
|
+
start: DateTimeTimeZone;
|
|
63
|
+
end: DateTimeTimeZone;
|
|
64
|
+
location?: Location;
|
|
65
|
+
attendees?: Attendee[];
|
|
66
|
+
isAllDay?: boolean;
|
|
67
|
+
recurrence?: Recurrence;
|
|
68
|
+
sensitivity?: "normal" | "personal" | "private" | "confidential";
|
|
69
|
+
showAs?: "free" | "tentative" | "busy" | "oof" | "workingElsewhere" | "unknown";
|
|
70
|
+
importance?: "low" | "normal" | "high";
|
|
71
|
+
allowNewTimeProposals?: boolean;
|
|
72
|
+
reminderMinutesBeforeStart?: number;
|
|
73
|
+
isReminderOn?: boolean;
|
|
74
|
+
categories?: string[];
|
|
75
|
+
transactionId?: string;
|
|
76
|
+
onlineMeetingProvider?: "unknown" | "skypeForBusiness" | "skypeForConsumer" | "teamsForBusiness";
|
|
77
|
+
onlineMeeting?: {
|
|
78
|
+
joinUrl?: string;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
export type GraphEventResponse = {
|
|
82
|
+
"@odata.context"?: string;
|
|
83
|
+
"@odata.etag"?: string;
|
|
84
|
+
id: string;
|
|
85
|
+
createdDateTime?: string;
|
|
86
|
+
lastModifiedDateTime?: string;
|
|
87
|
+
changeKey?: string;
|
|
88
|
+
categories?: string[];
|
|
89
|
+
transactionId?: string | null;
|
|
90
|
+
originalStartTimeZone?: string;
|
|
91
|
+
originalEndTimeZone?: string;
|
|
92
|
+
iCalUId?: string;
|
|
93
|
+
uid?: string;
|
|
94
|
+
reminderMinutesBeforeStart?: number;
|
|
95
|
+
isReminderOn?: boolean;
|
|
96
|
+
hasAttachments?: boolean;
|
|
97
|
+
subject?: string;
|
|
98
|
+
bodyPreview?: string;
|
|
99
|
+
importance?: "low" | "normal" | "high";
|
|
100
|
+
sensitivity?: "normal" | "personal" | "private" | "confidential";
|
|
101
|
+
isAllDay?: boolean;
|
|
102
|
+
isCancelled?: boolean;
|
|
103
|
+
isOrganizer?: boolean;
|
|
104
|
+
responseRequested?: boolean;
|
|
105
|
+
seriesMasterId?: string | null;
|
|
106
|
+
showAs?: "free" | "tentative" | "busy" | "oof" | "workingElsewhere" | "unknown";
|
|
107
|
+
type?: string;
|
|
108
|
+
webLink?: string;
|
|
109
|
+
onlineMeetingUrl?: string | null;
|
|
110
|
+
isOnlineMeeting?: boolean;
|
|
111
|
+
onlineMeetingProvider?: "unknown" | "skypeForBusiness" | "skypeForConsumer" | "teamsForBusiness" | string;
|
|
112
|
+
allowNewTimeProposals?: boolean;
|
|
113
|
+
occurrenceId?: string | null;
|
|
114
|
+
isDraft?: boolean;
|
|
115
|
+
hideAttendees?: boolean;
|
|
116
|
+
responseStatus?: {
|
|
117
|
+
response?: string;
|
|
118
|
+
time?: string;
|
|
119
|
+
};
|
|
120
|
+
body?: {
|
|
121
|
+
contentType?: string;
|
|
122
|
+
content?: string;
|
|
123
|
+
};
|
|
124
|
+
start: DateTimeTimeZone;
|
|
125
|
+
end: DateTimeTimeZone;
|
|
126
|
+
location?: {
|
|
127
|
+
displayName?: string;
|
|
128
|
+
locationType?: string;
|
|
129
|
+
uniqueId?: string;
|
|
130
|
+
uniqueIdType?: string;
|
|
131
|
+
locationEmailAddress?: string;
|
|
132
|
+
address?: LocationAddress;
|
|
133
|
+
} | null;
|
|
134
|
+
locations?: Array<{
|
|
135
|
+
displayName?: string;
|
|
136
|
+
locationType?: string;
|
|
137
|
+
uniqueId?: string;
|
|
138
|
+
uniqueIdType?: string;
|
|
139
|
+
locationEmailAddress?: string;
|
|
140
|
+
address?: LocationAddress;
|
|
141
|
+
}>;
|
|
142
|
+
recurrence?: Recurrence | null;
|
|
143
|
+
attendees?: Attendee[];
|
|
144
|
+
organizer?: {
|
|
145
|
+
emailAddress: EmailAddress;
|
|
146
|
+
};
|
|
147
|
+
onlineMeeting?: {
|
|
148
|
+
joinUrl?: string;
|
|
149
|
+
} | null;
|
|
150
|
+
};
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.init = init;
|
|
4
4
|
const __1 = require("..");
|
|
5
|
+
const scheduleToEvent_1 = require("../features/openservice/schedules/calendarSync/functions/scheduleToEvent");
|
|
6
|
+
const CalendarManager_1 = require("../features/openservice/schedules/calendarSync/service/CalendarManager");
|
|
5
7
|
const types_1 = require("../types");
|
|
6
8
|
async function init() {
|
|
7
9
|
(0, __1.beforeSaveHook)(types_1.Maintenance_Schedule, async (request) => {
|
|
@@ -10,12 +12,19 @@ async function init() {
|
|
|
10
12
|
await (0, __1.defaultAclHandler)(request);
|
|
11
13
|
});
|
|
12
14
|
(0, __1.afterSaveHook)(types_1.Maintenance_Schedule, async (request) => {
|
|
13
|
-
const { object, original, user } = request;
|
|
14
|
-
if (!original)
|
|
15
|
+
const { object, original, user, master } = request;
|
|
16
|
+
if (!original) {
|
|
15
17
|
await addToTemplateSources(object);
|
|
18
|
+
if (!master) {
|
|
19
|
+
await addToCalendar(object);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (original && !master) {
|
|
23
|
+
await updateCalendarEvent(object);
|
|
24
|
+
}
|
|
16
25
|
});
|
|
17
26
|
(0, __1.beforeDeleteHook)(types_1.Maintenance_Schedule, async (request) => {
|
|
18
|
-
const { object, original, user } = request;
|
|
27
|
+
const { object, original, user, master } = request;
|
|
19
28
|
const scheduleFetched = await object?.fetchWithInclude(["template", "source"], {
|
|
20
29
|
useMasterKey: true,
|
|
21
30
|
});
|
|
@@ -24,6 +33,10 @@ async function init() {
|
|
|
24
33
|
if (source)
|
|
25
34
|
template?.relation("sources").remove(source);
|
|
26
35
|
await template?.save(null, { useMasterKey: true });
|
|
36
|
+
// Delete associated calendar event
|
|
37
|
+
if (object.get("meta")?.calendarEventId) {
|
|
38
|
+
await new CalendarManager_1.CalendarManager().deleteEvent(object.get("meta")?.calendarEventId);
|
|
39
|
+
}
|
|
27
40
|
});
|
|
28
41
|
}
|
|
29
42
|
async function addToTemplateSources(schedule) {
|
|
@@ -39,3 +52,38 @@ async function addToTemplateSources(schedule) {
|
|
|
39
52
|
template.relation("sources").add(schedule.source);
|
|
40
53
|
await template.save(null, { useMasterKey: true });
|
|
41
54
|
}
|
|
55
|
+
async function updateCalendarEvent(schedule) {
|
|
56
|
+
const event = await (0, scheduleToEvent_1.scheduleToEvent)(schedule);
|
|
57
|
+
if (!event)
|
|
58
|
+
return;
|
|
59
|
+
const calendarManager = new CalendarManager_1.CalendarManager();
|
|
60
|
+
const meta = schedule.get("meta") || {};
|
|
61
|
+
const calendarEventId = meta.calendarEventId;
|
|
62
|
+
if (calendarEventId) {
|
|
63
|
+
console.log("Updating schedule in calendar...");
|
|
64
|
+
await calendarManager.updateEvent(calendarEventId, event);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
await addToCalendar(schedule);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Add schedule as event to calendar when first created
|
|
72
|
+
* @param schedule
|
|
73
|
+
*/
|
|
74
|
+
async function addToCalendar(schedule) {
|
|
75
|
+
console.log("Creating new calendar event for schedule...");
|
|
76
|
+
const event = await (0, scheduleToEvent_1.scheduleToEvent)(schedule);
|
|
77
|
+
if (!event)
|
|
78
|
+
return;
|
|
79
|
+
const calendarManager = new CalendarManager_1.CalendarManager();
|
|
80
|
+
const createdEvent = await calendarManager.createEvent(event);
|
|
81
|
+
if (createdEvent && createdEvent.id) {
|
|
82
|
+
const existingMeta = schedule.get("meta") || {};
|
|
83
|
+
schedule.set("meta", {
|
|
84
|
+
...existingMeta,
|
|
85
|
+
calendarEventId: createdEvent.id,
|
|
86
|
+
});
|
|
87
|
+
await schedule.save(null, { useMasterKey: true });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -1,33 +1,31 @@
|
|
|
1
|
-
import type { Contact } from "./Contact";
|
|
2
1
|
import type { Maintenance_Schedule_Execution } from "./Maintenance_Schedule_Execution";
|
|
3
|
-
import type { Source } from "./Source";
|
|
4
2
|
import type { Maintenance_Schedule_Step } from "./Maintenance_Schedule_Step";
|
|
5
3
|
import type { Maintenance_Schedule_Template } from "./Maintenance_Schedule_Template";
|
|
4
|
+
import type { Source } from "./Source";
|
|
6
5
|
import type { Tenant } from "./Tenant";
|
|
7
6
|
export interface Maintenance_ScheduleAttributes {
|
|
8
7
|
id: string;
|
|
9
8
|
objectId: string;
|
|
10
9
|
createdAt: Date;
|
|
11
10
|
updatedAt: Date;
|
|
12
|
-
color?: string
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
description?: string | undefined;
|
|
11
|
+
color?: string;
|
|
12
|
+
cron?: any;
|
|
13
|
+
description?: string;
|
|
16
14
|
enabled: boolean;
|
|
17
|
-
lastExecution?: Maintenance_Schedule_Execution
|
|
18
|
-
|
|
15
|
+
lastExecution?: Maintenance_Schedule_Execution;
|
|
16
|
+
meta?: any;
|
|
17
|
+
notifyBeforeDue?: any;
|
|
19
18
|
source: Source;
|
|
20
19
|
steps: Parse.Relation<Maintenance_Schedule, Maintenance_Schedule_Step>;
|
|
21
|
-
template?: Maintenance_Schedule_Template
|
|
22
|
-
tenant?: Tenant
|
|
23
|
-
title?: string
|
|
20
|
+
template?: Maintenance_Schedule_Template;
|
|
21
|
+
tenant?: Tenant;
|
|
22
|
+
title?: string;
|
|
24
23
|
}
|
|
25
24
|
export declare class Maintenance_Schedule extends Parse.Object<Maintenance_ScheduleAttributes> {
|
|
26
25
|
static className: string;
|
|
27
26
|
constructor(data?: Partial<Maintenance_ScheduleAttributes>);
|
|
28
27
|
get color(): string | undefined;
|
|
29
28
|
set color(value: string | undefined);
|
|
30
|
-
get contacts(): Parse.Relation<Maintenance_Schedule, Contact>;
|
|
31
29
|
get cron(): any | undefined;
|
|
32
30
|
set cron(value: any | undefined);
|
|
33
31
|
get description(): string | undefined;
|
|
@@ -36,6 +34,8 @@ export declare class Maintenance_Schedule extends Parse.Object<Maintenance_Sched
|
|
|
36
34
|
set enabled(value: boolean);
|
|
37
35
|
get lastExecution(): Maintenance_Schedule_Execution | undefined;
|
|
38
36
|
set lastExecution(value: Maintenance_Schedule_Execution | undefined);
|
|
37
|
+
get meta(): any | undefined;
|
|
38
|
+
set meta(value: any | undefined);
|
|
39
39
|
get notifyBeforeDue(): any | undefined;
|
|
40
40
|
set notifyBeforeDue(value: any | undefined);
|
|
41
41
|
get source(): Source;
|
|
@@ -11,9 +11,6 @@ class Maintenance_Schedule extends Parse.Object {
|
|
|
11
11
|
set color(value) {
|
|
12
12
|
super.set("color", value);
|
|
13
13
|
}
|
|
14
|
-
get contacts() {
|
|
15
|
-
return super.relation("contacts");
|
|
16
|
-
}
|
|
17
14
|
get cron() {
|
|
18
15
|
return super.get("cron");
|
|
19
16
|
}
|
|
@@ -38,6 +35,12 @@ class Maintenance_Schedule extends Parse.Object {
|
|
|
38
35
|
set lastExecution(value) {
|
|
39
36
|
super.set("lastExecution", value);
|
|
40
37
|
}
|
|
38
|
+
get meta() {
|
|
39
|
+
return super.get("meta");
|
|
40
|
+
}
|
|
41
|
+
set meta(value) {
|
|
42
|
+
super.set("meta", value);
|
|
43
|
+
}
|
|
41
44
|
get notifyBeforeDue() {
|
|
42
45
|
return super.get("notifyBeforeDue");
|
|
43
46
|
}
|
package/package.json
CHANGED