@openinc/parse-server-opendash 2.4.77 → 2.4.80

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.
@@ -1 +1,23 @@
1
+ type FilterParams = {
2
+ attribute: "objectId" | "state" | "issuecategory" | "user" | "role" | "userRole" | "source";
3
+ /**
4
+ * the objectId of the attribute to filter by
5
+ */
6
+ value: string;
7
+ };
8
+ type FetchObject = {
9
+ filterBy?: {
10
+ junction?: "and" | "or";
11
+ filter: FilterParams[];
12
+ };
13
+ sortBy?: string;
14
+ limit?: number;
15
+ skip?: number;
16
+ order?: "asc" | "desc";
17
+ };
18
+ export type FetchParams = {
19
+ junction: "and" | "or";
20
+ config: Array<FetchObject>;
21
+ };
1
22
  export declare function init(name: string): Promise<void>;
23
+ export {};
@@ -13,10 +13,58 @@ async function handleRequest(request) {
13
13
  }
14
14
  console.log("Handling request with", request.params);
15
15
  try {
16
- const ticketData = await getTicketData(request.params);
16
+ const queries = [];
17
+ for await (const config of request.params.config) {
18
+ let ticketQuery = new Parse.Query(types_1.Maintenance_Ticket).equalTo("enabled", true);
19
+ // apply filters defined in the filterQueryMap depending on the request
20
+ if (config.filterBy?.filter.length) {
21
+ const filterQueries = [];
22
+ for await (const filter of config.filterBy.filter) {
23
+ const query = new Parse.Query(types_1.Maintenance_Ticket).equalTo("enabled", true);
24
+ await filterQueryMap[filter.attribute](query, filter.value);
25
+ filterQueries.push(query);
26
+ }
27
+ if (config.filterBy.junction === "or") {
28
+ ticketQuery = Parse.Query.or(...filterQueries);
29
+ }
30
+ else {
31
+ ticketQuery = Parse.Query.and(...filterQueries);
32
+ }
33
+ }
34
+ queries.push(ticketQuery);
35
+ }
36
+ const ticketQuery = request.params.junction === "or"
37
+ ? Parse.Query.or(...queries)
38
+ : Parse.Query.and(...queries);
39
+ // fetch all tickets for sorting by data
40
+ const tickets = await ticketQuery
41
+ .limit(1000000000)
42
+ .find({ useMasterKey: true });
43
+ // get total count of tickets before applying pagination
44
+ const totalCount = tickets.length;
45
+ // fetch ticket data for those tickets
46
+ const ticketData = await getTicketData(tickets);
47
+ // apply sorting
48
+ if (request.params.config[0].sortBy && request.params.config[0].order) {
49
+ ticketData.sort((a, b) => {
50
+ const valueA = findSortByValue(request.params.config[0]?.sortBy ?? "", a);
51
+ const valueB = findSortByValue(request.params.config[0]?.sortBy ?? "", b);
52
+ if (valueA < valueB) {
53
+ return request.params.config[0].order === "asc" ? -1 : 1;
54
+ }
55
+ return request.params.config[0].order === "asc" ? 1 : -1;
56
+ });
57
+ }
58
+ let ticketDataPaginated = ticketData;
59
+ // apply pagination with skip and limit if set
60
+ if (request.params.config[0].skip !== undefined &&
61
+ request.params.config[0].limit !== undefined) {
62
+ ticketDataPaginated = ticketData.slice(request.params.config[0].skip, request.params.config[0].skip + request.params.config[0].limit);
63
+ }
17
64
  return {
18
65
  success: true,
19
- data: ticketData,
66
+ data: ticketDataPaginated,
67
+ total: totalCount,
20
68
  };
21
69
  }
22
70
  catch (error) {
@@ -27,157 +75,241 @@ async function handleRequest(request) {
27
75
  };
28
76
  }
29
77
  }
30
- async function getTicketData(params) {
31
- const tickets = await new Parse.Query(types_1.Maintenance_Ticket)
32
- .containedIn("objectId", params.ticketIds)
78
+ async function getTicketData(tickets) {
79
+ const ticketIds = tickets.map((ticket) => ticket.id);
80
+ // get assigned users and roles
81
+ console.log("fetching assigned users and roles");
82
+ const ticketDataPromises = tickets.map(async (ticket) => {
83
+ let assignedusers = [];
84
+ let assignedroles = [];
85
+ if (typeof ticket.assignedusers !== "undefined") {
86
+ assignedusers = await ticket.assignedusers
87
+ .query()
88
+ .find({ useMasterKey: true });
89
+ }
90
+ if (typeof ticket.assignedroles !== "undefined") {
91
+ assignedroles = await ticket.assignedroles
92
+ .query()
93
+ .find({ useMasterKey: true });
94
+ }
95
+ return {
96
+ ticket: ticket,
97
+ assignedTo: [...assignedusers, ...assignedroles],
98
+ };
99
+ });
100
+ const ticketData = await Promise.all(ticketDataPromises);
101
+ // fetch daily schedule
102
+ console.log("fetching daily schedule");
103
+ const schedules = await new Parse.Query(types_1.Maintenance_DailySchedule)
104
+ .include("tickets")
105
+ .matchesQuery("tickets", new Parse.Query(types_1.Maintenance_DailySchedule).matchesQuery("tickets", new Parse.Query(types_1.Maintenance_Ticket).containedIn("objectId", ticketIds)))
33
106
  .limit(1000000)
34
107
  .find({ useMasterKey: true });
35
- const ticketData = tickets.map((ticket) => ({
36
- ticket: ticket,
108
+ const scheduleTickets = await Promise.all(schedules.map(async (schedule) => {
109
+ return {
110
+ schedule,
111
+ tickets: await schedule
112
+ .get("tickets")
113
+ .query()
114
+ .find({ useMasterKey: true }),
115
+ };
37
116
  }));
38
- // fetch daily schedule
39
- if (params.options.dailySchedule) {
40
- console.log("fetching daily schedule");
41
- const schedules = await new Parse.Query(types_1.Maintenance_DailySchedule)
42
- .include("tickets")
43
- .matchesQuery("tickets", new Parse.Query(types_1.Maintenance_DailySchedule).matchesQuery("tickets", new Parse.Query(types_1.Maintenance_Ticket).containedIn("objectId", params.ticketIds)))
44
- .limit(1000000)
45
- .find({ useMasterKey: true });
46
- const scheduleTickets = await Promise.all(schedules.map(async (schedule) => {
47
- return {
48
- schedule,
49
- tickets: await schedule
50
- .get("tickets")
51
- .query()
52
- .find({ useMasterKey: true }),
53
- };
54
- }));
55
- ticketData.forEach((data) => {
56
- const scheduleTicket = scheduleTickets.find((scheduleTicket) => scheduleTicket.tickets.some((ticket) => ticket.id === data.ticket.id));
57
- if (scheduleTicket) {
58
- data.dailySchedule = scheduleTicket.schedule;
59
- }
60
- });
61
- }
117
+ ticketData.forEach((data) => {
118
+ const scheduleTicket = scheduleTickets.find((scheduleTicket) => scheduleTicket.tickets.some((ticket) => ticket.id === data.ticket.id));
119
+ if (scheduleTicket) {
120
+ data.dailySchedule = scheduleTicket.schedule;
121
+ }
122
+ });
62
123
  // fetch downtime
63
- if (params.options.downtime) {
64
- console.log("fetching downtime");
65
- const downtimes = await new Parse.Query(types_1.Maintenance_Downtime)
66
- .descending("updatedAt")
67
- .containedIn("ticket", params.ticketIds)
68
- .limit(1000000)
69
- .find({ useMasterKey: true });
70
- ticketData.forEach((data) => {
71
- data.downtime = downtimes.find((downtime) => downtime.get("ticket").id === data.ticket.id);
72
- });
73
- }
124
+ console.log("fetching downtime");
125
+ const downtimes = await new Parse.Query(types_1.Maintenance_Downtime)
126
+ .descending("updatedAt")
127
+ .containedIn("ticket", ticketIds)
128
+ .limit(1000000)
129
+ .find({ useMasterKey: true });
130
+ ticketData.forEach((data) => {
131
+ data.downtime = downtimes.find((downtime) => downtime.get("ticket").id === data.ticket.id);
132
+ });
74
133
  // fetch duedate
75
- if (params.options.duedate) {
76
- console.log("fetching duedate");
77
- const duedates = await new Parse.Query(types_1.Maintenance_Duedate)
78
- .descending("updatedAt")
79
- .containedIn("ticket", params.ticketIds)
80
- .limit(1000000)
81
- .find({ useMasterKey: true });
82
- ticketData.forEach((data) => {
83
- data.duedate = duedates.find((duedate) => duedate.get("ticket").id === data.ticket.id);
84
- });
85
- }
134
+ console.log("fetching duedate");
135
+ const duedates = await new Parse.Query(types_1.Maintenance_Duedate)
136
+ .descending("updatedAt")
137
+ .containedIn("ticket", ticketIds)
138
+ .limit(1000000)
139
+ .find({ useMasterKey: true });
140
+ ticketData.forEach((data) => {
141
+ data.duedate = duedates.find((duedate) => duedate.get("ticket").id === data.ticket.id);
142
+ });
86
143
  // fetch frequency
87
- if (params.options.frequency) {
88
- console.log("fetching frequency");
89
- const frequencies = await new Parse.Query(types_1.Maintenance_Frequency)
90
- .descending("updatedAt")
91
- .containedIn("ticket", params.ticketIds)
92
- .limit(1000000)
93
- .find({ useMasterKey: true });
94
- ticketData.forEach((data) => {
95
- data.frequency = frequencies.find((frequency) => frequency.get("ticket").id === data.ticket.id);
96
- });
97
- }
144
+ console.log("fetching frequency");
145
+ const frequencies = await new Parse.Query(types_1.Maintenance_Frequency)
146
+ .descending("updatedAt")
147
+ .containedIn("ticket", ticketIds)
148
+ .limit(1000000)
149
+ .find({ useMasterKey: true });
150
+ ticketData.forEach((data) => {
151
+ data.frequency = frequencies.find((frequency) => frequency.get("ticket").id === data.ticket.id);
152
+ });
98
153
  // fetch issuecategory
99
- if (params.options.issuecategory) {
100
- console.log("fetching issuecategory");
101
- const issuecategories = await new Parse.Query(types_1.Maintenance_Ticket_Issuecategory)
102
- .includeAll()
103
- .descending("updatedAt")
104
- .containedIn("ticket", params.ticketIds)
105
- .limit(1000000)
106
- .find({ useMasterKey: true });
107
- ticketData.forEach((data) => {
108
- data.issuecategory = issuecategories
109
- .find((issuecategory) => issuecategory.get("ticket").id === data.ticket.id)
110
- ?.get("issuecategory");
111
- });
112
- }
154
+ console.log("fetching issuecategory");
155
+ const issuecategories = await new Parse.Query(types_1.Maintenance_Ticket_Issuecategory)
156
+ .includeAll()
157
+ .descending("updatedAt")
158
+ .containedIn("ticket", ticketIds)
159
+ .limit(1000000)
160
+ .find({ useMasterKey: true });
161
+ ticketData.forEach((data) => {
162
+ data.issuecategory = issuecategories
163
+ .find((issuecategory) => issuecategory.get("ticket").id === data.ticket.id)
164
+ ?.get("issuecategory");
165
+ });
113
166
  // fetch state
114
- if (params.options.state) {
115
- console.log("fetching state");
116
- const ticketStates = await new Parse.Query(types_1.Maintenance_Ticket_Kanban_State_Current)
117
- .descending("updatedAt")
118
- .includeAll()
119
- .matchesQuery("ticket", new Parse.Query(types_1.Maintenance_Ticket).containedIn("objectId", params.ticketIds))
120
- .limit(1000000)
121
- .find({ useMasterKey: true });
122
- ticketData.forEach((data) => {
123
- data.state = ticketStates.find((ts) => ts.get("ticket")?.id === data.ticket.id)?.state;
124
- });
125
- }
167
+ console.log("fetching state");
168
+ const ticketStates = await new Parse.Query(types_1.Maintenance_Ticket_Kanban_State_Current)
169
+ .descending("updatedAt")
170
+ .includeAll()
171
+ .matchesQuery("ticket", new Parse.Query(types_1.Maintenance_Ticket).containedIn("objectId", ticketIds))
172
+ .limit(1000000)
173
+ .find({ useMasterKey: true });
174
+ ticketData.forEach((data) => {
175
+ data.state = ticketStates.find((ts) => ts.get("ticket")?.id === data.ticket.id)?.state;
176
+ });
126
177
  // fetch messages
127
- if (params.options.messages) {
128
- console.log("fetching messages");
129
- const messageBodies = await new Parse.Query(types_1.Maintenance_Message_Body)
130
- .include("message")
131
- .matchesQuery("message", new Parse.Query(types_1.Maintenance_Message)
132
- .descending("updatedAt")
133
- .containedIn("referencedObjectId", params.ticketIds)
134
- .limit(1000000))
135
- .limit(1000000)
136
- .find({ useMasterKey: true });
137
- const messages = messageBodies
138
- .map((msgB) => msgB.message)
139
- .filter((msg) => !!msg);
140
- ticketData.forEach((data) => {
141
- data.messages = messages.filter((msg) => msg?.get("referencedObjectId") === data.ticket.id);
142
- data.messageBodies = messageBodies.filter((msgB) => data.messages?.some((msg) => msg.id === msgB.get("message")?.id));
143
- });
144
- }
178
+ console.log("fetching messages");
179
+ const messageBodies = await new Parse.Query(types_1.Maintenance_Message_Body)
180
+ .include("message")
181
+ .matchesQuery("message", new Parse.Query(types_1.Maintenance_Message)
182
+ .descending("updatedAt")
183
+ .containedIn("referencedObjectId", ticketIds)
184
+ .limit(1000000))
185
+ .limit(1000000)
186
+ .find({ useMasterKey: true });
187
+ const messages = messageBodies
188
+ .map((msgB) => msgB.message)
189
+ .filter((msg) => !!msg);
190
+ ticketData.forEach((data) => {
191
+ data.messages = messages.filter((msg) => msg?.get("referencedObjectId") === data.ticket.id);
192
+ data.messageBodies = messageBodies.filter((msgB) => data.messages?.some((msg) => msg.id === msgB.get("message")?.id));
193
+ });
145
194
  // fetch priority
146
- if (params.options.priority) {
147
- console.log("fetching priority");
148
- const priorities = await new Parse.Query(types_1.Maintenance_Priority)
149
- .descending("updatedAt")
150
- .containedIn("ticket", params.ticketIds)
151
- .limit(1000000)
152
- .find({ useMasterKey: true });
153
- ticketData.forEach((data) => {
154
- data.priority = priorities.find((priority) => priority.get("ticket").id === data.ticket.id);
155
- });
156
- }
195
+ console.log("fetching priority");
196
+ const priorities = await new Parse.Query(types_1.Maintenance_Priority)
197
+ .descending("updatedAt")
198
+ .containedIn("ticket", ticketIds)
199
+ .limit(1000000)
200
+ .find({ useMasterKey: true });
201
+ ticketData.forEach((data) => {
202
+ data.priority = priorities.find((priority) => priority.get("ticket").id === data.ticket.id);
203
+ });
157
204
  // fetch restriction
158
- if (params.options.restriction) {
159
- console.log("fetching restriction");
160
- const restrictions = await new Parse.Query(types_1.Maintenance_Restriction)
161
- .descending("updatedAt")
162
- .containedIn("ticket", params.ticketIds)
163
- .limit(1000000)
164
- .find({ useMasterKey: true });
165
- ticketData.forEach((data) => {
166
- data.restriction = restrictions.find((restriction) => restriction.get("ticket").id === data.ticket.id);
167
- });
168
- }
205
+ console.log("fetching restriction");
206
+ const restrictions = await new Parse.Query(types_1.Maintenance_Restriction)
207
+ .descending("updatedAt")
208
+ .containedIn("ticket", ticketIds)
209
+ .limit(1000000)
210
+ .find({ useMasterKey: true });
211
+ ticketData.forEach((data) => {
212
+ data.restriction = restrictions.find((restriction) => restriction.get("ticket").id === data.ticket.id);
213
+ });
169
214
  // fetch source
170
- if (params.options.source) {
171
- console.log("fetching source");
172
- const sources = await new Parse.Query(types_1.Maintenance_Ticket_Source)
215
+ console.log("fetching source");
216
+ const sources = await new Parse.Query(types_1.Maintenance_Ticket_Source)
217
+ .includeAll()
218
+ .descending("updatedAt")
219
+ .containedIn("ticket", ticketIds)
220
+ .limit(1000000)
221
+ .find({ useMasterKey: true });
222
+ ticketData.forEach((data) => {
223
+ data.source = sources.find((source) => source.get("ticket").id === data.ticket.id)?.source;
224
+ });
225
+ return ticketData;
226
+ }
227
+ /**
228
+ * Used to filter tickets based on the filterBy attribute
229
+ */
230
+ const filterQueryMap = {
231
+ objectId: async (query, value) => {
232
+ query.equalTo("objectId", value);
233
+ },
234
+ state: async (query, value) => {
235
+ const stateQuery = new Parse.Query(types_1.Maintenance_Ticket_Kanban_State_Current).equalTo("state", new types_1.Maintenance_Kanban_State({ objectId: value }));
236
+ // @ts-ignore
237
+ query.matchesKeyInQuery("objectId", "ticket.objectId", stateQuery);
238
+ },
239
+ source: async (query, value) => {
240
+ const allTicketSources = await new Parse.Query(types_1.Maintenance_Ticket_Source)
241
+ .descending("createdAt")
242
+ .matchesQuery("ticket", query)
173
243
  .includeAll()
174
- .descending("updatedAt")
175
- .containedIn("ticket", params.ticketIds)
176
- .limit(1000000)
177
244
  .find({ useMasterKey: true });
178
- ticketData.forEach((data) => {
179
- data.source = sources.find((source) => source.get("ticket").id === data.ticket.id)?.source;
180
- });
181
- }
182
- return ticketData;
245
+ const filteredTicketSources = arrayToDistinct(allTicketSources, (ts) => ts.get("ticket").id, (ts) => ts.get("source").id === value);
246
+ console.log("filtered Array", filteredTicketSources.map((ts) => ts.get("ticket").title +
247
+ " - " +
248
+ ts.get("source").name +
249
+ " - " +
250
+ ts.get("source").id));
251
+ // @ts-ignore
252
+ query.containedIn("objectId", filteredTicketSources.map((ts) => ts.get("ticket").id));
253
+ },
254
+ issuecategory: async (query, value) => {
255
+ const ticketIssuecategories = await new Parse.Query(types_1.Maintenance_Ticket_Issuecategory)
256
+ .matchesQuery("ticket", query)
257
+ .descending("createdAt")
258
+ .includeAll()
259
+ .find({ useMasterKey: true });
260
+ const filteredTicketIssuecategories = arrayToDistinct(ticketIssuecategories, (tic) => tic.get("ticket").id, (tic) => tic.get("issuecategory").id === value);
261
+ // @ts-ignore
262
+ query.containedIn("objectId", filteredTicketIssuecategories.map((tic) => tic.get("ticket").id));
263
+ },
264
+ user: async (query, value) => {
265
+ const userQuery = new Parse.Query(Parse.User).equalTo("objectId", value);
266
+ query.matchesQuery("assignedusers", userQuery);
267
+ },
268
+ role: async (query, value) => {
269
+ const roleQuery = new Parse.Query(Parse.Role).equalTo("objectId", value);
270
+ query.include("assignedroles").matchesQuery("assignedroles", roleQuery);
271
+ },
272
+ userRole: async (query, value) => {
273
+ const userQuery = new Parse.Query(Parse.User).equalTo("objectId", value);
274
+ const roleQuery = new Parse.Query(Parse.Role)
275
+ .include("users")
276
+ .matchesQuery("users", userQuery);
277
+ query.include("assignedroles").matchesQuery("assignedroles", roleQuery);
278
+ },
279
+ };
280
+ /**
281
+ * Creates a distinct array based on the getId function and can afterwards filter the array
282
+ * @param arr the array to get distinct values from
283
+ * @param getId the identifier function to get the id of the item
284
+ * @param filter the filter function to filter the array afterwards
285
+ * @returns an array with distinct values based on the getId function
286
+ */
287
+ function arrayToDistinct(arr, getId, filter) {
288
+ console.log("Whole Array", arr.map((ts) => ts.get("ticket").title +
289
+ " - " +
290
+ ts.get("source").name +
291
+ " - " +
292
+ ts.get("source").id));
293
+ const map = new Map();
294
+ arr.forEach((item) => {
295
+ if (map.has(getId(item)))
296
+ return;
297
+ map.set(getId(item), item);
298
+ });
299
+ const array = Array.from(map.values());
300
+ console.log("Distinct Array", array.map((ts) => ts.get("ticket").title +
301
+ " - " +
302
+ ts.get("source").name +
303
+ " - " +
304
+ ts.get("source").id));
305
+ return filter ? array.filter(filter) : array;
306
+ }
307
+ function findSortByValue(sortBy, obj) {
308
+ if (!sortBy)
309
+ return "";
310
+ const keyChain = sortBy.split(".");
311
+ let currentValue = obj;
312
+ for (const key of keyChain)
313
+ currentValue = currentValue[key];
314
+ return currentValue;
183
315
  }
@@ -6,7 +6,7 @@ async function init(name) {
6
6
  if (typeof request.user === "undefined") {
7
7
  return { success: false, error: "User not found" };
8
8
  }
9
- const user = await new Parse.Query(Parse.User).get(request.user?.id, {
9
+ const user = await new Parse.Query(Parse.User).get(request.user.id, {
10
10
  useMasterKey: true,
11
11
  });
12
12
  const roles = (await new Parse.Query(Parse.Role)
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.init = init;
4
4
  const __1 = require("..");
5
+ const catchError_1 = require("../helper/catchError");
5
6
  const types_1 = require("../types");
6
7
  /**
7
8
  * This handles all config changes for a key starting with 'OPENSERVICE_' in class OD3_Config
@@ -32,5 +33,48 @@ async function init() {
32
33
  object.setACL(acl);
33
34
  }
34
35
  });
35
- (0, __1.afterSaveHook)(types_1.Config, async ({ object, original, user }) => { });
36
+ (0, __1.afterSaveHook)(types_1.Config, async ({ object, original, user }) => {
37
+ if (object.get("key").startsWith("OPENSERVICE_")) {
38
+ console.log("Config changed: ", object.get("key"));
39
+ console.log("Check Meta Fields in Maintenance_Schedule_Step...");
40
+ //Get all Entries in OD3_Maintenance_Step and remove all entries in field "fields" (type: array) that are not in the config
41
+ //object.value can look like this: [{"label":"PSA","allowedValues":[],"required":false},{"label":"Typ","allowedValues":[],"required":false,"onlyOneAllowedValue":false},{"label":"Material","allowedValues":["@OD3_Maintenance_Item"],"required":false,"onlyOneAllowedValue":false},{"label":"Dienstleister","allowedValues":["@OD3_COMPANY","@OD3_CONTACT"],"required":false,"onlyOneAllowedValue":false}]
42
+ //fields in Maintenance_Step can look like this: [{"value":"Handschuhe","metafield":{"label":"PSA","allowedValues":[],"required":false}},{"value":"Auffüllen","metafield":{"label":"Typ","allowedValues":[],"required":false,"onlyOneAllowedValue":false}}]
43
+ const metafieldsconfig = JSON.parse(object.get("value"));
44
+ const [maintenanceStepQueryError, maintenanceStepQuery] = await (0, catchError_1.catchError)(new Parse.Query(types_1.Maintenance_Schedule_Step).find({
45
+ useMasterKey: true,
46
+ }));
47
+ if (maintenanceStepQueryError) {
48
+ console.error("Error while querying Maintenance_Step objects", maintenanceStepQueryError);
49
+ return;
50
+ }
51
+ for (const maintenanceStep of maintenanceStepQuery) {
52
+ const fields = maintenanceStep.get("fields");
53
+ if (fields) {
54
+ //Loop through fields and remove all fields that are not in the config
55
+ for (let i = 0; i < fields.length; i++) {
56
+ if (!metafieldsconfig.find((el) => el.label === fields[i].metafield?.label)) {
57
+ console.log("Remove field:", fields[i].metafield?.label);
58
+ fields.splice(i, 1);
59
+ i--;
60
+ }
61
+ }
62
+ //Loop through config and add all fields that are not in the fields array
63
+ for (const metafield of metafieldsconfig) {
64
+ if (!fields.find((el) => el.metafield?.label === metafield.label)) {
65
+ console.log("Add field:", metafield.label);
66
+ fields.push({
67
+ value: "",
68
+ metafield,
69
+ });
70
+ }
71
+ }
72
+ maintenanceStep.set("fields", fields);
73
+ console.log("Save Maintenance_Schedule_Step " + maintenanceStep.id);
74
+ await maintenanceStep.save(null, { useMasterKey: true });
75
+ }
76
+ }
77
+ console.log("Meta Fields in Maintenance_Schedule_Template checked. Done.");
78
+ }
79
+ });
36
80
  }
@@ -1,20 +1,150 @@
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.init = init;
7
+ const bree_1 = __importDefault(require("bree"));
8
+ const node_path_1 = __importDefault(require("node:path"));
4
9
  const __1 = require("..");
10
+ const catchError_1 = require("../helper/catchError");
5
11
  const types_1 = require("../types");
12
+ bree_1.default.extend(require("@breejs/ts-worker"));
6
13
  async function init() {
14
+ initScheduling();
7
15
  (0, __1.beforeSaveHook)(types_1.Maintenance_Schedule_Template, async (request) => {
8
16
  const { object, original, user } = request;
9
17
  await (0, __1.defaultHandler)(request);
10
18
  await (0, __1.defaultAclHandler)(request);
11
- // TODO
12
19
  });
13
20
  (0, __1.afterSaveHook)(types_1.Maintenance_Schedule_Template, async (request) => {
14
21
  const { object, original, user } = request;
15
- const cronstring = object.get("cron")["run_cron"];
16
- // Create a file for bree to run it.
17
22
  //TODO: Create notification object
18
23
  //TODO: Send mail or anything that is enabled
24
+ startBree([object]);
19
25
  });
26
+ /**
27
+ * This function is called upon initialization and uses bree to schedule all jobs.
28
+ */
29
+ async function initScheduling() {
30
+ console.log("Init Scheduling Maintenance_Schedule_Template jobs");
31
+ //Get all Maintenance_Schedule_Template objects
32
+ const [queryError, query] = await (0, catchError_1.catchError)(new Parse.Query(types_1.Maintenance_Schedule_Template).find());
33
+ //Create an new bree object for all Maintenance_Schedule_Template objects that have cron.is_one_time = false
34
+ if (queryError) {
35
+ console.error("Error while querying Maintenance_Schedule_Template objects", queryError);
36
+ return;
37
+ }
38
+ //TODO
39
+ }
40
+ async function startBree(query) {
41
+ console.log("Starting Bree");
42
+ const jobs = [];
43
+ for (const schedule of query) {
44
+ const cron = schedule.get("cron");
45
+ if (cron["is_one_time"] === false) {
46
+ if (cron["scheduletype"] === "human") {
47
+ jobs.push({
48
+ name: `Schedule ${schedule.id}`,
49
+ path: "open_service_notifyOnSchedule",
50
+ timeout: 0,
51
+ interval: createHumanReadableFormat(cron["run_cron"]),
52
+ hasSeconds: true,
53
+ worker: {
54
+ workerData: {
55
+ scheduleId: schedule.id,
56
+ MaintenanceTicketClass: types_1.Maintenance_Ticket,
57
+ NotificationClass: types_1.Notification,
58
+ },
59
+ },
60
+ });
61
+ }
62
+ else if (cron["scheduletype"] === "quartz") {
63
+ jobs.push({
64
+ name: `Schedule ${schedule.id}`,
65
+ cron: cron["run_cron"],
66
+ path: "open_service_notifyOnSchedule",
67
+ timeout: 0,
68
+ interval: 0,
69
+ hasSeconds: true,
70
+ worker: {
71
+ workerData: {
72
+ scheduleId: schedule.id,
73
+ MaintenanceTicketType: types_1.Maintenance_Ticket,
74
+ NotificationType: types_1.Notification,
75
+ },
76
+ },
77
+ });
78
+ }
79
+ }
80
+ }
81
+ //Create bree object
82
+ console.log("Creating bree object");
83
+ const bree = new bree_1.default({
84
+ errorHandler: (error, workerMetadata) => {
85
+ console.error(`An error occurred in worker ${workerMetadata.name} with the following error: ${error}`);
86
+ },
87
+ root: node_path_1.default.join(__dirname, "..", "jobs"),
88
+ jobs: ["open_service_notifyOnSchedule"],
89
+ });
90
+ //Start bree object
91
+ // const graceful = new Graceful({ brees: [bree] });
92
+ // graceful.listen();
93
+ (async () => {
94
+ console.log("Starting bree");
95
+ await bree.start();
96
+ })();
97
+ }
98
+ // async function notifyOnSchedule() {
99
+ // console.log("Notify on schedule");
100
+ // console.log("Creating new ticket");
101
+ // //Create a new ticket
102
+ // const ticketObject = new Maintenance_Ticket();
103
+ // await ticketObject.save(null, { useMasterKey: true });
104
+ // console.log("Creating new notification object");
105
+ // //Create a new notification object in the database, class name: OD3_Notification
106
+ // const notificationObject = new Notification();
107
+ // notificationObject.set("title", "Maintenance Notification");
108
+ // notificationObject.set("description", "Maintenance is scheduled");
109
+ // notificationObject.set("data", { test: "test" });
110
+ // await notificationObject.save(null, { useMasterKey: true });
111
+ // console.log("Ticket and Notification object created");
112
+ // }
113
+ function createHumanReadableFormat(value) {
114
+ //value looks like this: "1 1 1 1 1 1 1"
115
+ //1. seconds
116
+ //2. minutes
117
+ //3. hours
118
+ //4. days
119
+ //5. weeks
120
+ //6. months
121
+ //7. years
122
+ const valueArray = value.split(" ");
123
+ //Should be in the format: "every 1 second" when second is 1
124
+ //If any value is 0, it should be ignored
125
+ //Values should be separated by a comma
126
+ const returnArray = [];
127
+ if (valueArray[0] !== "0") {
128
+ returnArray.push(`every ${valueArray[0]} seconds`);
129
+ }
130
+ if (valueArray[1] !== "0") {
131
+ returnArray.push(`every ${valueArray[1]} minutes`);
132
+ }
133
+ if (valueArray[2] !== "0") {
134
+ returnArray.push(`every ${valueArray[2]} hours`);
135
+ }
136
+ if (valueArray[3] !== "0") {
137
+ returnArray.push(`every ${valueArray[3]} days`);
138
+ }
139
+ if (valueArray[4] !== "0") {
140
+ returnArray.push(`every ${valueArray[4]} weeks`);
141
+ }
142
+ if (valueArray[5] !== "0") {
143
+ returnArray.push(`every ${valueArray[5]} months`);
144
+ }
145
+ if (valueArray[6] !== "0") {
146
+ returnArray.push(`every ${valueArray[6]} years`);
147
+ }
148
+ return returnArray.join(", ");
149
+ }
20
150
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
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
+ const node_process_1 = __importDefault(require("node:process"));
7
+ const node_worker_threads_1 = require("node:worker_threads");
8
+ const node_1 = __importDefault(require("parse/node"));
9
+ const Maintenance_Ticket_1 = require("../types/Maintenance_Ticket");
10
+ const Notification_1 = require("../types/Notification");
11
+ // const Maintenance_Ticket = workerData.MaintenanceTicketClass;
12
+ // const Notification = workerData.NotificationClass;
13
+ console.log("Notify on schedule");
14
+ (async () => {
15
+ console.log("Creating new ticket");
16
+ //Create a new ticket
17
+ const ticketObject = new node_1.default.Object(Maintenance_Ticket_1.Maintenance_Ticket.className);
18
+ await ticketObject.save(null, { useMasterKey: true });
19
+ console.log("Creating new notification object");
20
+ //Create a new notification object in the database, class name: OD3_Notification
21
+ const notificationObject = new node_1.default.Object(Notification_1.Notification.className);
22
+ notificationObject.set("title", "Maintenance Notification");
23
+ notificationObject.set("description", "Maintenance is scheduled");
24
+ notificationObject.set("data", { test: "test" });
25
+ await notificationObject.save(null, { useMasterKey: true });
26
+ console.log("Ticket and Notification object created");
27
+ // signal to parent that the job is done
28
+ if (node_worker_threads_1.parentPort) {
29
+ node_worker_threads_1.parentPort.postMessage("done");
30
+ }
31
+ else {
32
+ node_process_1.default.exit(0);
33
+ }
34
+ })();
@@ -1,3 +1,4 @@
1
+ import type { Tenant } from "./Tenant";
1
2
  export interface MES_ArticleAttributes {
2
3
  id: string;
3
4
  objectId: string;
@@ -6,6 +7,7 @@ export interface MES_ArticleAttributes {
6
7
  artnr: string;
7
8
  name: string;
8
9
  targettime: number;
10
+ tenant?: Tenant;
9
11
  }
10
12
  export declare class MES_Article extends Parse.Object<MES_ArticleAttributes> {
11
13
  static className: string;
@@ -16,4 +18,6 @@ export declare class MES_Article extends Parse.Object<MES_ArticleAttributes> {
16
18
  set name(value: string);
17
19
  get targettime(): number;
18
20
  set targettime(value: number);
21
+ get tenant(): Tenant | undefined;
22
+ set tenant(value: Tenant | undefined);
19
23
  }
@@ -23,6 +23,12 @@ class MES_Article extends Parse.Object {
23
23
  set targettime(value) {
24
24
  super.set("targettime", value);
25
25
  }
26
+ get tenant() {
27
+ return super.get("tenant");
28
+ }
29
+ set tenant(value) {
30
+ super.set("tenant", value);
31
+ }
26
32
  }
27
33
  exports.MES_Article = MES_Article;
28
34
  MES_Article.className = "OD3_MES_Article";
@@ -1,5 +1,6 @@
1
1
  import type { MES_Article } from "./MES_Article";
2
2
  import type { Source } from "./Source";
3
+ import type { Tenant } from "./Tenant";
3
4
  export interface MES_OrderPlanAttributes {
4
5
  id: string;
5
6
  objectId: string;
@@ -12,6 +13,7 @@ export interface MES_OrderPlanAttributes {
12
13
  setup_time: number;
13
14
  source?: Source;
14
15
  target_quantity: number;
16
+ tenant?: Tenant;
15
17
  }
16
18
  export declare class MES_OrderPlan extends Parse.Object<MES_OrderPlanAttributes> {
17
19
  static className: string;
@@ -30,4 +32,6 @@ export declare class MES_OrderPlan extends Parse.Object<MES_OrderPlanAttributes>
30
32
  set source(value: Source | undefined);
31
33
  get target_quantity(): number;
32
34
  set target_quantity(value: number);
35
+ get tenant(): Tenant | undefined;
36
+ set tenant(value: Tenant | undefined);
33
37
  }
@@ -47,6 +47,12 @@ class MES_OrderPlan extends Parse.Object {
47
47
  set target_quantity(value) {
48
48
  super.set("target_quantity", value);
49
49
  }
50
+ get tenant() {
51
+ return super.get("tenant");
52
+ }
53
+ set tenant(value) {
54
+ super.set("tenant", value);
55
+ }
50
56
  }
51
57
  exports.MES_OrderPlan = MES_OrderPlan;
52
58
  MES_OrderPlan.className = "OD3_MES_OrderPlan";
@@ -1,4 +1,5 @@
1
1
  import type { Source } from "./Source";
2
+ import type { Tenant } from "./Tenant";
2
3
  export interface Monitoring_ParseTableSensorAttributes {
3
4
  id: string;
4
5
  objectId: string;
@@ -6,9 +7,9 @@ export interface Monitoring_ParseTableSensorAttributes {
6
7
  updatedAt: Date;
7
8
  dateColumn?: string;
8
9
  name: string;
9
- pipe?: any;
10
10
  query: any;
11
11
  source: Source;
12
+ tenant: Tenant;
12
13
  }
13
14
  export declare class Monitoring_ParseTableSensor extends Parse.Object<Monitoring_ParseTableSensorAttributes> {
14
15
  static className: string;
@@ -17,10 +18,10 @@ export declare class Monitoring_ParseTableSensor extends Parse.Object<Monitoring
17
18
  set dateColumn(value: string | undefined);
18
19
  get name(): string;
19
20
  set name(value: string);
20
- get pipe(): any | undefined;
21
- set pipe(value: any | undefined);
22
21
  get query(): any;
23
22
  set query(value: any);
24
23
  get source(): Source;
25
24
  set source(value: Source);
25
+ get tenant(): Tenant;
26
+ set tenant(value: Tenant);
26
27
  }
@@ -17,12 +17,6 @@ class Monitoring_ParseTableSensor extends Parse.Object {
17
17
  set name(value) {
18
18
  super.set("name", value);
19
19
  }
20
- get pipe() {
21
- return super.get("pipe");
22
- }
23
- set pipe(value) {
24
- super.set("pipe", value);
25
- }
26
20
  get query() {
27
21
  return super.get("query");
28
22
  }
@@ -35,6 +29,12 @@ class Monitoring_ParseTableSensor extends Parse.Object {
35
29
  set source(value) {
36
30
  super.set("source", value);
37
31
  }
32
+ get tenant() {
33
+ return super.get("tenant");
34
+ }
35
+ set tenant(value) {
36
+ super.set("tenant", value);
37
+ }
38
38
  }
39
39
  exports.Monitoring_ParseTableSensor = Monitoring_ParseTableSensor;
40
40
  Monitoring_ParseTableSensor.className = "OD3_Monitoring_ParseTableSensor";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openinc/parse-server-opendash",
3
- "version": "2.4.77",
3
+ "version": "2.4.80",
4
4
  "description": "Parse Server Cloud Code for open.DASH",
5
5
  "keywords": [
6
6
  "parse",
@@ -26,8 +26,11 @@
26
26
  "hooks": "node ./scripts/create-hooks.js"
27
27
  },
28
28
  "dependencies": {
29
+ "@breejs/ts-worker": "^2.0.0",
30
+ "@ladjs/graceful": "^4.2.0",
29
31
  "@openinc/parse-server-schema": "^1.7.8",
30
32
  "bree": "^9.2.4",
33
+ "cabin": "^14.0.0",
31
34
  "cron": "^3.3.2",
32
35
  "fast-equals": "^5.0.1",
33
36
  "jsonwebtoken": "^9.0.2",
@@ -45,6 +48,7 @@
45
48
  "@types/nodemailer": "^6.4.17",
46
49
  "@types/nunjucks": "^3.2.6",
47
50
  "@types/parse": "^3.0.9",
51
+ "@types/safe-timers": "^1.1.2",
48
52
  "@types/web-push": "^3.6.4",
49
53
  "typedoc": "^0.26.11",
50
54
  "typedoc-plugin-markdown": "^4.3.0",