@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.
- package/dist/functions/openinc-openservice-ticket-data.d.ts +22 -0
- package/dist/functions/openinc-openservice-ticket-data.js +273 -141
- package/dist/functions/openinc-user-roles.js +1 -1
- package/dist/hooks/Config_open_service.js +45 -1
- package/dist/hooks/Maintenance_Schedule_Template.js +133 -3
- package/dist/jobs/open_service_notifyOnSchedule.d.ts +1 -0
- package/dist/jobs/open_service_notifyOnSchedule.js +34 -0
- package/dist/types/MES_Article.d.ts +4 -0
- package/dist/types/MES_Article.js +6 -0
- package/dist/types/MES_OrderPlan.d.ts +4 -0
- package/dist/types/MES_OrderPlan.js +6 -0
- package/dist/types/Monitoring_ParseTableSensor.d.ts +4 -3
- package/dist/types/Monitoring_ParseTableSensor.js +6 -6
- package/package.json +5 -1
|
@@ -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
|
|
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:
|
|
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(
|
|
31
|
-
const
|
|
32
|
-
|
|
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
|
|
36
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
|
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.
|
|
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",
|