@openinc/parse-server-opendash 3.32.3 → 3.32.5

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.
@@ -533,4 +533,77 @@ exports.customoptions = {
533
533
  public: false,
534
534
  description: "Comma separated list of class names which should be excluded from ChangeLog entries.",
535
535
  },
536
+ CHANGELOG_PUBLISH_ENABLE: {
537
+ env: "OPENINC_PARSE_CHANGELOG_PUBLISH_ENABLE",
538
+ type: "boolean",
539
+ required: false,
540
+ secret: false,
541
+ public: false,
542
+ default: "false",
543
+ description: "Enable publishing of ChangeLog entries to RabbitMQ.",
544
+ },
545
+ CHANGELOG_PUBLISH_HOST: {
546
+ env: "OPENINC_PARSE_CHANGELOG_PUBLISH_HOST",
547
+ type: "string",
548
+ required: false,
549
+ secret: false,
550
+ public: false,
551
+ description: "RabbitMQ host for publishing ChangeLog entries.",
552
+ },
553
+ CHANGELOG_PUBLISH_VHOST: {
554
+ env: "OPENINC_PARSE_CHANGELOG_PUBLISH_VHOST",
555
+ type: "string",
556
+ required: false,
557
+ secret: false,
558
+ public: false,
559
+ description: "RabbitMQ virtual host for publishing ChangeLog entries.",
560
+ },
561
+ CHANGELOG_PUBLISH_PORT: {
562
+ env: "OPENINC_PARSE_CHANGELOG_PUBLISH_PORT",
563
+ type: "int",
564
+ required: false,
565
+ secret: false,
566
+ public: false,
567
+ description: "RabbitMQ port for publishing ChangeLog entries.",
568
+ },
569
+ CHANGELOG_PUBLISH_MANAGEMENT_PORT: {
570
+ env: "OPENINC_PARSE_CHANGELOG_PUBLISH_MANAGEMENT_PORT",
571
+ type: "int",
572
+ required: false,
573
+ secret: false,
574
+ public: false,
575
+ description: "RabbitMQ management port for publishing ChangeLog entries.",
576
+ },
577
+ CHANGELOG_PUBLISH_USERNAME: {
578
+ env: "OPENINC_PARSE_CHANGELOG_PUBLISH_USERNAME",
579
+ type: "string",
580
+ required: false,
581
+ secret: false,
582
+ public: false,
583
+ description: "RabbitMQ username for publishing ChangeLog entries.",
584
+ },
585
+ CHANGELOG_PUBLISH_PASSWORD: {
586
+ env: "OPENINC_PARSE_CHANGELOG_PUBLISH_PASSWORD",
587
+ type: "string",
588
+ required: false,
589
+ secret: true,
590
+ public: false,
591
+ description: "RabbitMQ password for publishing ChangeLog entries.",
592
+ },
593
+ CHANGELOG_PUBLISH_EXCHANGE: {
594
+ env: "OPENINC_PARSE_CHANGELOG_PUBLISH_EXCHANGE",
595
+ type: "string",
596
+ required: false,
597
+ secret: false,
598
+ public: false,
599
+ description: "RabbitMQ exchange for publishing ChangeLog entries.",
600
+ },
601
+ CHANGELOG_PUBLISH_TOPIC_PREFIX: {
602
+ env: "OPENINC_PARSE_CHANGELOG_PUBLISH_TOPIC_PREFIX",
603
+ type: "string",
604
+ required: false,
605
+ secret: false,
606
+ public: false,
607
+ description: "RabbitMQ topic prefix for publishing ChangeLog entries.",
608
+ },
536
609
  };
@@ -1,4 +1,8 @@
1
1
  import { ConfigState, customoptions } from "..";
2
+ /**
3
+ * Singleton class to manage configuration state.
4
+ * Use this to get values from process.env based on the defined custom options.
5
+ */
2
6
  export default class ConfigInstance {
3
7
  private static instance;
4
8
  static getInstance(): ConfigState<Extract<keyof typeof customoptions, string>>;
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const __1 = require("..");
4
+ /**
5
+ * Singleton class to manage configuration state.
6
+ * Use this to get values from process.env based on the defined custom options.
7
+ */
4
8
  class ConfigInstance {
5
9
  static getInstance() {
6
10
  if (!ConfigInstance.instance) {
@@ -0,0 +1,26 @@
1
+ export type AMQPConnectionParameters = {
2
+ topicPrefix?: string;
3
+ host: string;
4
+ vhost: string;
5
+ port: number;
6
+ managementPort: number;
7
+ username: string;
8
+ password: string;
9
+ exchange: string;
10
+ };
11
+ export declare class AMQPBusConnection {
12
+ private connectionParams;
13
+ private connection;
14
+ private channel;
15
+ private reconnectTimer;
16
+ private attempt;
17
+ private isIntentionalDisconnect;
18
+ constructor(conParams: AMQPConnectionParameters);
19
+ connect(): Promise<void>;
20
+ private establishConnection;
21
+ private handleConnectionLost;
22
+ disconnect(): Promise<void>;
23
+ publish(topic: string, message: any): Promise<void>;
24
+ private ensureVHostAndExchange;
25
+ private performRequest;
26
+ }
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AMQPBusConnection = void 0;
4
+ const amqp = require("amqplib");
5
+ class AMQPBusConnection {
6
+ constructor(conParams) {
7
+ this.attempt = 0;
8
+ this.isIntentionalDisconnect = false;
9
+ this.connectionParams = conParams;
10
+ }
11
+ async connect() {
12
+ this.isIntentionalDisconnect = false;
13
+ await this.establishConnection();
14
+ }
15
+ async establishConnection() {
16
+ try {
17
+ await this.ensureVHostAndExchange();
18
+ const { host, port, vhost, username, password } = this.connectionParams;
19
+ const url = `amqp://${username}:${password}@${host}:${port}/${vhost}`;
20
+ console.log(`AMQP Connecting to ${host}:${port}/${vhost}...`);
21
+ this.connection = await amqp.connect(url);
22
+ this.connection.on("error", (err) => {
23
+ console.error("AMQP Connection error:", err);
24
+ this.handleConnectionLost();
25
+ });
26
+ this.connection.on("close", () => {
27
+ if (!this.isIntentionalDisconnect) {
28
+ console.warn("AMQP Connection closed unexpectedly");
29
+ this.handleConnectionLost();
30
+ }
31
+ });
32
+ this.channel = await this.connection.createChannel();
33
+ console.log("AMQP Connected");
34
+ this.attempt = 0;
35
+ }
36
+ catch (err) {
37
+ console.error("Failed to establish AMQP connection:", err);
38
+ this.handleConnectionLost();
39
+ }
40
+ }
41
+ handleConnectionLost() {
42
+ this.connection = null;
43
+ this.channel = null;
44
+ if (this.reconnectTimer)
45
+ return;
46
+ if (this.isIntentionalDisconnect)
47
+ return;
48
+ // Max 30s
49
+ const timeout = Math.min(1000 * Math.pow(2, this.attempt), 30000);
50
+ this.attempt++;
51
+ console.log(`AMQP Reconnecting in ${timeout}ms (Attempt ${this.attempt})...`);
52
+ this.reconnectTimer = setTimeout(async () => {
53
+ this.reconnectTimer = undefined;
54
+ await this.establishConnection();
55
+ }, timeout);
56
+ }
57
+ async disconnect() {
58
+ this.isIntentionalDisconnect = true;
59
+ if (this.reconnectTimer) {
60
+ clearTimeout(this.reconnectTimer);
61
+ this.reconnectTimer = undefined;
62
+ }
63
+ if (this.channel) {
64
+ try {
65
+ await this.channel.close();
66
+ }
67
+ catch (e) {
68
+ // ignore
69
+ }
70
+ this.channel = null;
71
+ }
72
+ if (this.connection) {
73
+ try {
74
+ await this.connection.close();
75
+ }
76
+ catch (e) {
77
+ // ignore
78
+ }
79
+ this.connection = null;
80
+ }
81
+ console.log("AMQP Disconnected");
82
+ }
83
+ async publish(topic, message) {
84
+ if (!this.channel) {
85
+ throw new Error("AMQP Channel not available");
86
+ }
87
+ // Check if exchange is configured
88
+ const exchange = this.connectionParams.exchange;
89
+ // Convert message to Buffer if it's not
90
+ let content;
91
+ if (Buffer.isBuffer(message)) {
92
+ content = message;
93
+ }
94
+ else if (typeof message === "string") {
95
+ content = Buffer.from(message);
96
+ }
97
+ else {
98
+ content = Buffer.from(JSON.stringify(message));
99
+ }
100
+ this.channel.publish(exchange, this.connectionParams.topicPrefix
101
+ ? `${this.connectionParams.topicPrefix}.${topic}`
102
+ : topic, content);
103
+ }
104
+ async ensureVHostAndExchange() {
105
+ const { host, vhost, username, password, exchange, managementPort } = this.connectionParams;
106
+ const port = managementPort || 15672;
107
+ const auth = Buffer.from(`${username}:${password}`).toString("base64");
108
+ // 1. Ensure vHost exists
109
+ console.log(`Ensuring vHost '${vhost}' exists on ${host}:${port}...`);
110
+ await this.performRequest(host, port, "PUT", `/api/vhosts/${encodeURIComponent(vhost)}`, auth);
111
+ // 2. Ensure Exchange exists
112
+ console.log(`Ensuring Exchange '${exchange}' exists on ${host}:${port}...`);
113
+ await this.performRequest(host, port, "PUT", `/api/exchanges/${encodeURIComponent(vhost)}/${encodeURIComponent(exchange)}`, auth, JSON.stringify({
114
+ type: "topic",
115
+ auto_delete: false,
116
+ durable: true,
117
+ internal: false,
118
+ arguments: {},
119
+ }));
120
+ }
121
+ async performRequest(host, port, method, path, auth, body) {
122
+ const url = `http://${host}:${port}${path}`;
123
+ const response = await fetch(url, {
124
+ method,
125
+ headers: {
126
+ Authorization: `Basic ${auth}`,
127
+ "Content-Type": "application/json",
128
+ },
129
+ body,
130
+ });
131
+ if (!response.ok) {
132
+ const text = await response.text();
133
+ throw new Error(`RabbitMQ API Request failed: ${response.status} ${response.statusText} - ${text}`);
134
+ }
135
+ }
136
+ }
137
+ exports.AMQPBusConnection = AMQPBusConnection;
@@ -1,4 +1,7 @@
1
1
  import { Maintenance_Downtime, Maintenance_Frequency, Maintenance_Priority, Maintenance_Restriction, Maintenance_Ticket, Maintenance_Ticket_Issuecategory, Maintenance_Ticket_Kanban_State, Maintenance_Ticket_Source } from "../../../types";
2
+ /**
3
+ * @deprecated
4
+ */
2
5
  export type OpenWareTicketObject = {
3
6
  ticket: Maintenance_Ticket;
4
7
  priority: Maintenance_Priority | Number;
@@ -6,7 +6,6 @@ exports.saveTicketData = saveTicketData;
6
6
  exports.serializeTicketData = serializeTicketData;
7
7
  const parse_1 = require("parse");
8
8
  const openservice_1 = require("../features/openservice");
9
- const openware_1 = require("../features/openware");
10
9
  const catchError_1 = require("../helper/catchError");
11
10
  const types_1 = require("../types");
12
11
  const openinc_openservice_ticket_data_1 = require("./openinc-openservice-ticket-data");
@@ -71,16 +70,17 @@ async function saveTicketData(data, user, overrideFetchOptions) {
71
70
  (user ? { sessionToken: user.getSessionToken() } : { useMasterKey: true });
72
71
  console.log("[saveTicketData] effective fetchOptions:", fetchOptions);
73
72
  const ticket = await (0, openservice_1.getTicketObject)(data, user, fetchOptions);
74
- const owticketobj = {
75
- ticket: ticket,
76
- priority: 0,
77
- downtime: 0,
78
- restriction: 0,
79
- frequency: 0,
80
- issuecategory: "",
81
- state: "",
82
- source: new types_1.Maintenance_Ticket_Source(),
83
- };
73
+ // const owticketobj: OpenWareTicketObject = {
74
+ // ticket: ticket,
75
+ // priority: 0,
76
+ // downtime: 0,
77
+ // restriction: 0,
78
+ // frequency: 0,
79
+ // issuecategory: "",
80
+ // state: "",
81
+ // source: new Maintenance_Ticket_Source(),
82
+ // metadata: { fields: [] },
83
+ // };
84
84
  // needs to be the first save to save a message before data change messages are created on ticket creation
85
85
  if (data.message)
86
86
  await (0, openservice_1.saveMessage)(ticket, data.message, fetchOptions, data);
@@ -90,13 +90,11 @@ async function saveTicketData(data, user, overrideFetchOptions) {
90
90
  await (0, openservice_1.saveTicketTitle)(ticket, fetchOptions);
91
91
  if (data.description)
92
92
  await (0, openservice_1.saveDescription)(ticket, data, fetchOptions);
93
- if (data.meta)
94
- await (0, openservice_1.saveTicketMeta)(ticket, data.meta, fetchOptions);
95
93
  if (data.duedate)
96
94
  await (0, openservice_1.saveDuedate)(ticket, data.duedate, fetchOptions);
97
95
  if (data.priority !== undefined) {
98
96
  const savedpriority = await (0, openservice_1.savePriority)(ticket, data.priority, fetchOptions);
99
- owticketobj.priority = savedpriority;
97
+ // owticketobj.priority = savedpriority;
100
98
  }
101
99
  else {
102
100
  //Fetch last value so it won't publish a 0 value to openware and overwrite the last value with default 0
@@ -108,83 +106,101 @@ async function saveTicketData(data, user, overrideFetchOptions) {
108
106
  console.log("Error fetching last priority", lastPriorityError);
109
107
  }
110
108
  else {
111
- owticketobj.priority = lastPriority?.get("value") ?? 0;
109
+ // owticketobj.priority = lastPriority?.get("value") ?? 0;
112
110
  }
113
111
  }
114
112
  if (data.downtime !== undefined) {
115
113
  const saveddowntime = await (0, openservice_1.saveDowntime)(ticket, data.downtime, fetchOptions);
116
- owticketobj.downtime = saveddowntime;
117
- }
118
- else {
119
- //Fetch last value so it won't publish a 0 value to openware and overwrite the last value with default 0
120
- const [lastDowntimeError, lastDowntime] = await (0, catchError_1.catchError)(new Parse.Query(types_1.Maintenance_Downtime)
121
- .equalTo("ticket", ticket)
122
- .descending("createdAt")
123
- .first(fetchOptions), [Error]);
124
- if (lastDowntimeError) {
125
- console.log("Error fetching last downtime", lastDowntimeError);
126
- }
127
- else {
128
- owticketobj.downtime = lastDowntime?.get("value") ?? 0;
129
- }
114
+ // owticketobj.downtime = saveddowntime;
130
115
  }
116
+ // else {
117
+ // //Fetch last value so it won't publish a 0 value to openware and overwrite the last value with default 0
118
+ // const [lastDowntimeError, lastDowntime] = await catchError(
119
+ // new Parse.Query(Maintenance_Downtime)
120
+ // .equalTo("ticket", ticket)
121
+ // .descending("createdAt")
122
+ // .first(fetchOptions),
123
+ // [Error]
124
+ // );
125
+ // if (lastDowntimeError) {
126
+ // console.log("Error fetching last downtime", lastDowntimeError);
127
+ // } else {
128
+ // owticketobj.downtime = lastDowntime?.get("value") ?? 0;
129
+ // }
130
+ // }
131
131
  if (data.frequency !== undefined) {
132
132
  const savedfrequency = await (0, openservice_1.saveFrequency)(ticket, data.frequency, fetchOptions);
133
- owticketobj.frequency = savedfrequency;
134
- }
135
- else {
136
- //Fetch last value so it won't publish a 0 value to openware and overwrite the last value with default 0
137
- const [lastFrequencyError, lastFrequency] = await (0, catchError_1.catchError)(new Parse.Query(types_1.Maintenance_Frequency)
138
- .equalTo("ticket", ticket)
139
- .descending("createdAt")
140
- .first(fetchOptions), [Error]);
141
- if (lastFrequencyError) {
142
- console.log("Error fetching last frequency", lastFrequencyError);
143
- }
144
- else {
145
- owticketobj.frequency = lastFrequency?.get("value") ?? 0;
146
- }
133
+ // owticketobj.frequency = savedfrequency;
147
134
  }
135
+ // else {
136
+ // //Fetch last value so it won't publish a 0 value to openware and overwrite the last value with default 0
137
+ // const [lastFrequencyError, lastFrequency] = await catchError(
138
+ // new Parse.Query(Maintenance_Frequency)
139
+ // .equalTo("ticket", ticket)
140
+ // .descending("createdAt")
141
+ // .first(fetchOptions),
142
+ // [Error]
143
+ // );
144
+ // if (lastFrequencyError) {
145
+ // console.log("Error fetching last frequency", lastFrequencyError);
146
+ // } else {
147
+ // owticketobj.frequency = lastFrequency?.get("value") ?? 0;
148
+ // }
149
+ // }
148
150
  if (data.restriction !== undefined) {
149
151
  const savedrestriction = await (0, openservice_1.saveRestriction)(ticket, data.restriction, fetchOptions);
150
- owticketobj.restriction = savedrestriction;
151
- }
152
- else {
153
- //Fetch last value so it won't publish a 0 value to openware and overwrite the last value with default 0
154
- const [lastRestrictionError, lastRestriction] = await (0, catchError_1.catchError)(new Parse.Query(types_1.Maintenance_Restriction)
155
- .equalTo("ticket", ticket)
156
- .descending("createdAt")
157
- .first(fetchOptions), [Error]);
158
- if (lastRestrictionError) {
159
- console.log("Error fetching last restriction", lastRestrictionError);
160
- }
161
- else {
162
- owticketobj.restriction = lastRestriction?.get("value") ?? 0;
163
- }
152
+ // owticketobj.restriction = savedrestriction;
164
153
  }
154
+ // else {
155
+ // //Fetch last value so it won't publish a 0 value to openware and overwrite the last value with default 0
156
+ // const [lastRestrictionError, lastRestriction] = await catchError(
157
+ // new Parse.Query(Maintenance_Restriction)
158
+ // .equalTo("ticket", ticket)
159
+ // .descending("createdAt")
160
+ // .first(fetchOptions),
161
+ // [Error]
162
+ // );
163
+ // if (lastRestrictionError) {
164
+ // console.log("Error fetching last restriction", lastRestrictionError);
165
+ // } else {
166
+ // owticketobj.restriction = lastRestriction?.get("value") ?? 0;
167
+ // }
168
+ // }
165
169
  if (data.issuecategory) {
166
170
  const savedissuecategory = await (0, openservice_1.saveIssueCategory)(ticket, data.issuecategory, fetchOptions);
167
- const [fetchedSavedIssuecategoryError, fetchedSavedIssuecategory] = await (0, catchError_1.catchError)(new Parse.Query(types_1.Maintenance_Ticket_Issuecategory)
168
- .include("issuecategory")
169
- .get(savedissuecategory.id, fetchOptions), [Error]);
170
- if (fetchedSavedIssuecategoryError) {
171
- console.log("Error fetching saved issue category", fetchedSavedIssuecategoryError);
172
- }
173
- else {
174
- owticketobj.issuecategory = fetchedSavedIssuecategory;
175
- }
171
+ // const [fetchedSavedIssuecategoryError, fetchedSavedIssuecategory] =
172
+ // await catchError(
173
+ // new Parse.Query(Maintenance_Ticket_Issuecategory)
174
+ // .include("issuecategory")
175
+ // .get(savedissuecategory.id, fetchOptions),
176
+ // [Error]
177
+ // );
178
+ // if (fetchedSavedIssuecategoryError) {
179
+ // console.log(
180
+ // "Error fetching saved issue category",
181
+ // fetchedSavedIssuecategoryError
182
+ // );
183
+ // } else {
184
+ // owticketobj.issuecategory = fetchedSavedIssuecategory;
185
+ // }
176
186
  }
177
187
  if (data.state) {
178
188
  const savedstate = await (0, openservice_1.saveState)(ticket, data.state, fetchOptions);
179
- const [fetchedSavedStateError, fetchedSavedState] = await (0, catchError_1.catchError)(new Parse.Query(types_1.Maintenance_Ticket_Kanban_State)
180
- .include("state")
181
- .get(savedstate.id, fetchOptions), [Error]);
182
- if (fetchedSavedStateError) {
183
- console.log("Error fetching saved state", fetchedSavedStateError);
184
- }
185
- else {
186
- owticketobj.state = fetchedSavedState;
187
- }
189
+ // const [fetchedSavedStateError, fetchedSavedState] = await catchError(
190
+ // new Parse.Query(Maintenance_Ticket_Kanban_State)
191
+ // .include("state")
192
+ // .get(savedstate.id, fetchOptions),
193
+ // [Error]
194
+ // );
195
+ // if (fetchedSavedStateError) {
196
+ // console.log("Error fetching saved state", fetchedSavedStateError);
197
+ // } else {
198
+ // owticketobj.state = fetchedSavedState;
199
+ // }
200
+ }
201
+ if (data.meta) {
202
+ await (0, openservice_1.saveTicketMeta)(ticket, data.meta, fetchOptions);
203
+ // owticketobj.metadata = savedTicket.get("meta");
188
204
  }
189
205
  if (data.material) {
190
206
  try {
@@ -229,21 +245,27 @@ async function saveTicketData(data, user, overrideFetchOptions) {
229
245
  }
230
246
  }
231
247
  //Get source from ticket and save to openware
232
- const [fetchedTicketSourceError, ticketsource] = await (0, catchError_1.catchError)(new Parse.Query(types_1.Maintenance_Ticket_Source)
233
- .equalTo("ticket", new types_1.Maintenance_Ticket({ objectId: ticket.id }))
234
- .descending("createdAt")
235
- .include("source")
236
- .first({ useMasterKey: true }), [Error]);
237
- if (fetchedTicketSourceError) {
238
- console.log("Error fetching saved source", fetchedTicketSourceError);
239
- }
240
- else if (ticketsource && ticketsource.get("source")) {
241
- owticketobj.source = ticketsource;
242
- // publish to openware
243
- await publishToOpenWare(owticketobj, ticket, ticketsource.get("source").get("tag")
244
- ? ticketsource.get("source").get("tag")
245
- : "");
246
- }
248
+ // const [fetchedTicketSourceError, ticketsource] = await catchError(
249
+ // new Parse.Query(Maintenance_Ticket_Source)
250
+ // .equalTo("ticket", new Maintenance_Ticket({ objectId: ticket.id }))
251
+ // .descending("createdAt")
252
+ // .include("source")
253
+ // .first({ useMasterKey: true }),
254
+ // [Error]
255
+ // );
256
+ // if (fetchedTicketSourceError) {
257
+ // console.log("Error fetching saved source", fetchedTicketSourceError);
258
+ // } else if (ticketsource && ticketsource.get("source")) {
259
+ // owticketobj.source = ticketsource;
260
+ // // publish to openware
261
+ // await publishToOpenWare(
262
+ // owticketobj,
263
+ // ticket,
264
+ // ticketsource.get("source").get("tag")
265
+ // ? ticketsource.get("source").get("tag")!
266
+ // : ""
267
+ // );
268
+ // }
247
269
  // save TicketData in TicketData Table
248
270
  const [ticketData] = await (0, openinc_openservice_ticket_data_1.getTicketData)([ticket]);
249
271
  if (ticketData) {
@@ -269,126 +291,150 @@ async function saveTicketData(data, user, overrideFetchOptions) {
269
291
  * Publishes the ticket to open.WARE with all changed data
270
292
  * @param owticketobj OpenWareTicketObject
271
293
  * @param source OD3_Source
294
+ * @deprecated
272
295
  */
273
296
  async function publishToOpenWare(owticketobj, ticket, source) {
274
- const time = new Date().getTime();
275
- const values = {
276
- date: time,
277
- value: Object.entries(owticketobj).map(([key, value]) => {
278
- if (key === "downtime") {
279
- if (value instanceof types_1.Maintenance_Downtime) {
280
- return value.get("value");
281
- }
282
- return value;
283
- }
284
- else if (key === "frequency") {
285
- if (value instanceof types_1.Maintenance_Frequency) {
286
- return value.get("value");
287
- }
288
- return value;
289
- }
290
- else if (key === "priority") {
291
- if (value instanceof types_1.Maintenance_Priority) {
292
- return value.get("value");
293
- }
294
- return value;
295
- }
296
- else if (key === "restriction") {
297
- if (value instanceof types_1.Maintenance_Restriction) {
298
- return value.get("value");
299
- }
300
- return value;
301
- }
302
- else if (key === "issuecategory") {
303
- if (value instanceof types_1.Maintenance_Ticket_Issuecategory) {
304
- return value.get("issuecategory").id;
305
- }
306
- return value;
307
- }
308
- else if (key === "state") {
309
- if (value instanceof types_1.Maintenance_Ticket_Kanban_State) {
310
- return value.get("state").id;
311
- }
312
- return value;
313
- }
314
- else if (key === "ticket") {
315
- if (value instanceof types_1.Maintenance_Ticket) {
316
- return value.id;
317
- }
318
- return value;
319
- }
320
- else if (key === "source") {
321
- if (value instanceof types_1.Maintenance_Ticket_Source) {
322
- return value.get("source").id;
323
- }
324
- return value;
325
- }
326
- return value;
327
- }),
328
- };
329
- const valueTypes = Object.keys(owticketobj).map((key) => {
330
- const tmpvaluetype = {
331
- name: "",
332
- unit: "",
333
- type: "String",
334
- };
335
- if (key === "downtime") {
336
- tmpvaluetype.name = types_1.Maintenance_Downtime.className.replace("OD3_Maintenance_", "");
337
- tmpvaluetype.unit = "%";
338
- tmpvaluetype.type = "Number";
339
- }
340
- else if (key === "frequency") {
341
- tmpvaluetype.name = types_1.Maintenance_Frequency.className.replace("OD3_Maintenance_", "");
342
- tmpvaluetype.unit = "%";
343
- tmpvaluetype.type = "Number";
344
- }
345
- else if (key === "priority") {
346
- tmpvaluetype.name = types_1.Maintenance_Priority.className.replace("OD3_Maintenance_", "");
347
- tmpvaluetype.unit = "%";
348
- tmpvaluetype.type = "Number";
349
- }
350
- else if (key === "restriction") {
351
- tmpvaluetype.name = types_1.Maintenance_Restriction.className.replace("OD3_Maintenance_", "");
352
- tmpvaluetype.unit = "%";
353
- tmpvaluetype.type = "Number";
354
- }
355
- else if (key === "issuecategory") {
356
- tmpvaluetype.name = types_1.Maintenance_Ticket_Issuecategory.className.replace("OD3_Maintenance_", "");
357
- tmpvaluetype.unit = "";
358
- tmpvaluetype.type = "String";
359
- }
360
- else if (key === "state") {
361
- tmpvaluetype.name = types_1.Maintenance_Ticket_Kanban_State.className.replace("OD3_Maintenance_", "");
362
- tmpvaluetype.unit = "";
363
- tmpvaluetype.type = "String";
364
- }
365
- else if (key === "ticket") {
366
- tmpvaluetype.name = types_1.Maintenance_Ticket.className.replace("OD3_Maintenance_", "");
367
- tmpvaluetype.unit = "";
368
- tmpvaluetype.type = "String";
369
- }
370
- else if (key === "source") {
371
- tmpvaluetype.name = types_1.Maintenance_Ticket_Source.className.replace("OD3_Maintenance_", "");
372
- tmpvaluetype.unit = "";
373
- tmpvaluetype.type = "String";
374
- }
375
- return tmpvaluetype;
376
- });
377
- const dataitem = {
378
- id: `openservice_ticket_${ticket.id}`,
379
- name: `Ticket ${owticketobj.ticket.get("title")}`,
380
- source: source,
381
- values: [values],
382
- valueTypes: valueTypes,
383
- meta: {},
384
- };
385
- console.log("Publishing ticket to openware: ", dataitem, "with values", JSON.stringify(dataitem.values));
386
- try {
387
- await (0, openware_1.publishDataItem)(dataitem, ticket.get("user")?.get("email"), true);
388
- }
389
- catch (error) {
390
- console.error("Error publishing ticket to openware", error);
391
- }
297
+ // const time: number = new Date().getTime();
298
+ // const values: DataItemValueInterface = {
299
+ // date: time,
300
+ // value: Object.entries(owticketobj).map(([key, value]) => {
301
+ // if (key === "downtime") {
302
+ // if (value instanceof Maintenance_Downtime) {
303
+ // return value.get("value");
304
+ // }
305
+ // return value;
306
+ // } else if (key === "frequency") {
307
+ // if (value instanceof Maintenance_Frequency) {
308
+ // return value.get("value");
309
+ // }
310
+ // return value;
311
+ // } else if (key === "priority") {
312
+ // if (value instanceof Maintenance_Priority) {
313
+ // return value.get("value");
314
+ // }
315
+ // return value;
316
+ // } else if (key === "restriction") {
317
+ // if (value instanceof Maintenance_Restriction) {
318
+ // return value.get("value");
319
+ // }
320
+ // return value;
321
+ // } else if (key === "issuecategory") {
322
+ // if (value instanceof Maintenance_Ticket_Issuecategory) {
323
+ // return value.get("issuecategory").id;
324
+ // }
325
+ // return value;
326
+ // } else if (key === "state") {
327
+ // if (value instanceof Maintenance_Ticket_Kanban_State) {
328
+ // return value.get("state").id;
329
+ // }
330
+ // return value;
331
+ // } else if (key === "ticket") {
332
+ // if (value instanceof Maintenance_Ticket) {
333
+ // return value.id;
334
+ // }
335
+ // return value;
336
+ // } else if (key === "source") {
337
+ // if (value instanceof Maintenance_Ticket_Source) {
338
+ // return value.get("source").id;
339
+ // }
340
+ // return value;
341
+ // } else if (key === "metadata") {
342
+ // return value;
343
+ // }
344
+ // return value;
345
+ // }),
346
+ // };
347
+ // const valueTypes: DataItemValueTypeInterface[] = Object.keys(owticketobj).map(
348
+ // (key): DataItemValueTypeInterface => {
349
+ // const tmpvaluetype: DataItemValueTypeInterface = {
350
+ // name: "",
351
+ // unit: "",
352
+ // type: "String",
353
+ // };
354
+ // if (key === "downtime") {
355
+ // tmpvaluetype.name = Maintenance_Downtime.className.replace(
356
+ // "OD3_Maintenance_",
357
+ // ""
358
+ // );
359
+ // tmpvaluetype.unit = "%";
360
+ // tmpvaluetype.type = "Number";
361
+ // } else if (key === "frequency") {
362
+ // tmpvaluetype.name = Maintenance_Frequency.className.replace(
363
+ // "OD3_Maintenance_",
364
+ // ""
365
+ // );
366
+ // tmpvaluetype.unit = "%";
367
+ // tmpvaluetype.type = "Number";
368
+ // } else if (key === "priority") {
369
+ // tmpvaluetype.name = Maintenance_Priority.className.replace(
370
+ // "OD3_Maintenance_",
371
+ // ""
372
+ // );
373
+ // tmpvaluetype.unit = "%";
374
+ // tmpvaluetype.type = "Number";
375
+ // } else if (key === "restriction") {
376
+ // tmpvaluetype.name = Maintenance_Restriction.className.replace(
377
+ // "OD3_Maintenance_",
378
+ // ""
379
+ // );
380
+ // tmpvaluetype.unit = "%";
381
+ // tmpvaluetype.type = "Number";
382
+ // } else if (key === "issuecategory") {
383
+ // tmpvaluetype.name = Maintenance_Ticket_Issuecategory.className.replace(
384
+ // "OD3_Maintenance_",
385
+ // ""
386
+ // );
387
+ // tmpvaluetype.unit = "";
388
+ // tmpvaluetype.type = "String";
389
+ // } else if (key === "state") {
390
+ // tmpvaluetype.name = Maintenance_Ticket_Kanban_State.className.replace(
391
+ // "OD3_Maintenance_",
392
+ // ""
393
+ // );
394
+ // tmpvaluetype.unit = "";
395
+ // tmpvaluetype.type = "String";
396
+ // } else if (key === "ticket") {
397
+ // tmpvaluetype.name = Maintenance_Ticket.className.replace(
398
+ // "OD3_Maintenance_",
399
+ // ""
400
+ // );
401
+ // tmpvaluetype.unit = "";
402
+ // tmpvaluetype.type = "String";
403
+ // } else if (key === "source") {
404
+ // tmpvaluetype.name = Maintenance_Ticket_Source.className.replace(
405
+ // "OD3_Maintenance_",
406
+ // ""
407
+ // );
408
+ // tmpvaluetype.unit = "";
409
+ // tmpvaluetype.type = "String";
410
+ // }
411
+ // else if (key === "metadata") {
412
+ // tmpvaluetype.name = "meta";
413
+ // tmpvaluetype.unit = "";
414
+ // tmpvaluetype.type = "Object";
415
+ // }
416
+ // return tmpvaluetype;
417
+ // }
418
+ // );
419
+ // const dataitem: DataItemInterface = {
420
+ // id: `openservice_ticket_${ticket.id}`,
421
+ // name: `Ticket ${owticketobj.ticket.get("title")}`,
422
+ // source: source,
423
+ // values: [values],
424
+ // valueTypes: valueTypes,
425
+ // meta: {},
426
+ // };
427
+ // console.log(
428
+ // "Publishing ticket to openware: ",
429
+ // dataitem,
430
+ // "with values",
431
+ // JSON.stringify(dataitem.values)
432
+ // );
433
+ // try {
434
+ // await publishDataItem(dataitem, ticket.get("user")?.get("email"), true);
435
+ // } catch (error) {
436
+ // console.error("Error publishing ticket to openware", error);
437
+ // }
392
438
  }
393
439
  function serializeTicketData(obj) {
394
440
  if (!obj)
@@ -28,7 +28,7 @@ async function init() {
28
28
  if (form.next) {
29
29
  delete form.next;
30
30
  }
31
- object.set("form", {});
31
+ // object.set("form", {});
32
32
  let sCount = 1;
33
33
  const newEntries = [];
34
34
  res.forEach((element, idx) => {
@@ -38,15 +38,16 @@ async function init() {
38
38
  form["step" + (sCount - 1)].next = "step" + sCount;
39
39
  }
40
40
  });
41
- request.context.pages = res;
41
+ // request.context.pages = res;
42
42
  object.set("entries", newEntries);
43
43
  object.set("form", form);
44
44
  }
45
45
  });
46
46
  (0, schema_1.afterSaveHook)(types_1.BDE_Form, async (request) => {
47
47
  const { object, original, user } = request;
48
- for (const page of request.context.pages) {
49
- page.save(null, { useMasterKey: true });
50
- }
48
+ //Unclear why it was added...
49
+ // for (const page of request.context.pages as BDE_Page[]) {
50
+ // page.save(null, { useMasterKey: true });
51
+ // }
51
52
  });
52
53
  }
@@ -49,6 +49,16 @@ async function createSchedulesWithTemplate(template) {
49
49
  enabled: true,
50
50
  tenant: template.get("tenant"),
51
51
  });
52
- await newSchedule.save(null, { useMasterKey: true });
52
+ const savedSchedule = await newSchedule.save(null, { useMasterKey: true });
53
+ // Add steps to the schedule steps relation
54
+ const templateStepsRelation = template.relation("steps");
55
+ const scheduleStepsRelation = savedSchedule.relation("steps");
56
+ const templateSteps = await templateStepsRelation
57
+ .query()
58
+ .findAll({ useMasterKey: true });
59
+ for (const step of templateSteps) {
60
+ scheduleStepsRelation.add(step);
61
+ }
62
+ await savedSchedule.save(null, { useMasterKey: true });
53
63
  }
54
64
  }
@@ -1,10 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.init = init;
4
+ const AMQPBusConnection_1 = require("../features/openware/services/AMQPBusConnection");
4
5
  const schema_1 = require("../features/schema");
5
6
  const types_1 = require("../types");
6
7
  async function init() {
7
8
  const schema = await Parse.Schema.all();
9
+ const publishEnabled = (process.env.OPENINC_PARSE_CHANGELOG_PUBLISH_ENABLE || "FALSE").toUpperCase() === "TRUE";
10
+ console.log(`ChangeLog publishing enabled: ${publishEnabled}`);
8
11
  const blacklistedClasses = [
9
12
  "_Session",
10
13
  "_Installation",
@@ -22,6 +25,38 @@ async function init() {
22
25
  object.getACL().setReadAccess(user.id, true);
23
26
  }
24
27
  });
28
+ if (publishEnabled) {
29
+ const params = {
30
+ host: process.env.OPENINC_PARSE_CHANGELOG_PUBLISH_HOST || "localhost",
31
+ vhost: process.env.OPENINC_PARSE_CHANGELOG_PUBLISH_VHOST || "configuration",
32
+ port: parseInt(process.env.OPENINC_PARSE_CHANGELOG_PUBLISH_PORT || "5672"),
33
+ username: process.env.OPENINC_PARSE_CHANGELOG_PUBLISH_USERNAME || "guest",
34
+ password: process.env.OPENINC_PARSE_CHANGELOG_PUBLISH_PASSWORD || "guest",
35
+ exchange: process.env.OPENINC_PARSE_CHANGELOG_PUBLISH_EXCHANGE || "topic",
36
+ topicPrefix: process.env.OPENINC_PARSE_CHANGELOG_PUBLISH_TOPIC_PREFIX || "config",
37
+ managementPort: parseInt(process.env.OPENINC_PARSE_CHANGELOG_PUBLISH_MANAGEMENT_PORT || "15672"),
38
+ };
39
+ const connection = new AMQPBusConnection_1.AMQPBusConnection(params);
40
+ try {
41
+ const { host, port, vhost, username, password } = params;
42
+ const url = `amqp://${username}:*****@${host}:${port}/${vhost}`;
43
+ console.log(`Establishing Connection to ${url} for ChangeLog publishing...`);
44
+ await connection.connect();
45
+ console.log(`Connected to AMQPBus at ${url} for ChangeLog publishing.`);
46
+ (0, schema_1.afterSaveHook)(types_1.Changelog.className, async (request) => {
47
+ const { object: changelog } = request;
48
+ const msg = JSON.stringify(changelog.toJSON());
49
+ const topic = `${params.topicPrefix && params.topicPrefix.length > 0
50
+ ? params.topicPrefix + "."
51
+ : ""}${changelog.get("nameOfClass")}`;
52
+ await connection.publish(topic, msg);
53
+ console.log(`Published ChangeLog entry [${topic}]: ${msg}`);
54
+ });
55
+ }
56
+ catch (e) {
57
+ console.error("Failed to connect to AMQPBus for ChangeLog publishing:", e);
58
+ }
59
+ }
25
60
  schema.forEach((classSchema) => {
26
61
  if (!classSchema.className ||
27
62
  classSchema.className === types_1.Changelog.className ||
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@openinc/parse-server-opendash",
3
- "version": "3.32.3",
3
+ "version": "3.32.5",
4
4
  "description": "Parse Server Cloud Code for open.INC Stack.",
5
- "packageManager": "pnpm@10.26.2",
5
+ "packageManager": "pnpm@10.28.0",
6
6
  "keywords": [
7
7
  "parse",
8
8
  "opendash"
@@ -67,27 +67,28 @@
67
67
  },
68
68
  "dependencies": {
69
69
  "@openinc/parse-server-schema": "^3.0.7",
70
- "@opentelemetry/api-logs": "^0.208.0",
71
- "@opentelemetry/auto-instrumentations-node": "^0.67.3",
72
- "@opentelemetry/exporter-logs-otlp-http": "^0.208.0",
73
- "@opentelemetry/exporter-trace-otlp-http": "^0.208.0",
74
- "@opentelemetry/resources": "^2.2.0",
75
- "@opentelemetry/sdk-logs": "^0.208.0",
76
- "@opentelemetry/sdk-node": "^0.208.0",
77
- "@opentelemetry/semantic-conventions": "^1.38.0",
78
- "@opentelemetry/winston-transport": "^0.19.0",
79
- "rimraf": "^6.1.2",
70
+ "@opentelemetry/api-logs": "^0.210.0",
71
+ "@opentelemetry/auto-instrumentations-node": "^0.68.0",
72
+ "@opentelemetry/exporter-logs-otlp-http": "^0.210.0",
73
+ "@opentelemetry/exporter-trace-otlp-http": "^0.210.0",
74
+ "@opentelemetry/resources": "^2.4.0",
75
+ "@opentelemetry/sdk-logs": "^0.210.0",
76
+ "@opentelemetry/sdk-node": "^0.210.0",
77
+ "@opentelemetry/semantic-conventions": "^1.39.0",
78
+ "@opentelemetry/winston-transport": "^0.20.0",
79
+ "amqplib": "^0.10.9",
80
80
  "cron": "^4.4.0",
81
81
  "dayjs": "^1.11.19",
82
82
  "fast-equals": "^5.4.0",
83
- "i18next": "^25.7.3",
83
+ "i18next": "^25.7.4",
84
84
  "i18next-fs-backend": "^2.6.1",
85
85
  "jsonwebtoken": "^9.0.3",
86
- "jwks-rsa": "^3.2.0",
86
+ "jwks-rsa": "^3.2.1",
87
87
  "nodemailer": "^7.0.12",
88
88
  "nunjucks": "^3.2.4",
89
89
  "parse-server": "^9.1.1",
90
90
  "pdf-img-convert": "2.0.0",
91
+ "rimraf": "^6.1.2",
91
92
  "semantic-release": "^25.0.2",
92
93
  "table": "^6.9.0",
93
94
  "web-push": "^3.6.7",
@@ -102,8 +103,8 @@
102
103
  "@semantic-release/npm": "^13.1.3",
103
104
  "@semantic-release/release-notes-generator": "^14.1.0",
104
105
  "@types/jsonwebtoken": "^9.0.10",
105
- "@types/node": "^24.10.4",
106
- "@types/nodemailer": "^7.0.4",
106
+ "@types/node": "^24.10.9",
107
+ "@types/nodemailer": "^7.0.5",
107
108
  "@types/nunjucks": "^3.2.6",
108
109
  "@types/parse": "^3.0.9",
109
110
  "@types/safe-timers": "^1.1.2",
@@ -111,7 +112,7 @@
111
112
  "concurrently": "^9.2.1",
112
113
  "semantic-release-export-data": "^1.2.0",
113
114
  "ts-node": "^10.9.2",
114
- "typedoc": "^0.28.15",
115
+ "typedoc": "^0.28.16",
115
116
  "typedoc-plugin-markdown": "^4.9.0",
116
117
  "typescript": "^5.9.3"
117
118
  }