@openinc/parse-server-opendash 3.26.2 → 3.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,4 +47,13 @@ exports.baseoptions = {
47
47
  default: "true",
48
48
  description: "Enable (or disable) anonymous users, defaults to true",
49
49
  },
50
+ PARSE_PUBLIC_SERVER_URL: {
51
+ env: "PARSE_PUBLIC_SERVER_URL",
52
+ type: "string",
53
+ required: true,
54
+ secret: false,
55
+ public: true,
56
+ default: "",
57
+ description: "The public URL of your Parse Server. This will be used in various places such as email links and push notification callbacks.",
58
+ },
50
59
  };
@@ -105,7 +105,6 @@ class ConfigState {
105
105
  const t = this.configs[key]?.type;
106
106
  if (!types.includes(t)) {
107
107
  console.error(new Error(`Invalid getter for config key '${key}' is of type ${t} but was called as ${types.join("|")}.`));
108
- process.exit(1);
109
108
  }
110
109
  }
111
110
  log() {
@@ -1,10 +1,16 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.assignUsersAndRoles = assignUsersAndRoles;
7
+ const i18next_1 = __importDefault(require("i18next"));
4
8
  const parse_1 = require("parse");
5
9
  const openinc_openservice_save_ticket_data_1 = require("../../../functions/openinc-openservice-save-ticket-data");
6
10
  const openinc_openservice_ticket_data_1 = require("../../../functions/openinc-openservice-ticket-data");
11
+ const getUserLanguage_1 = require("../../../helper/getUserLanguage");
7
12
  const types_1 = require("../../../types");
13
+ const getTicketLink_1 = require("../ticket/getTicketLink");
8
14
  async function assignUsersAndRoles(ticket, assignedTo, fetchOptions, assigningUser) {
9
15
  const assignedUsers = (await ticket
10
16
  .relation("assignedusers")
@@ -41,7 +47,9 @@ async function assignUsersAndRoles(ticket, assignedTo, fetchOptions, assigningUs
41
47
  }));
42
48
  }
43
49
  const userNotifiedIds = [];
44
- for (const assignedTo of newUsers) {
50
+ for await (const assignedTo of newUsers) {
51
+ const resipientlanguage = await (0, getUserLanguage_1.getUserLanguage)(assignedTo);
52
+ await i18next_1.default.changeLanguage(resipientlanguage);
45
53
  assignments.push(new types_1.Maintenance_Ticket_Assignment({
46
54
  ticket,
47
55
  assignedUser: assignedTo,
@@ -61,10 +69,14 @@ async function assignUsersAndRoles(ticket, assignedTo, fetchOptions, assigningUs
61
69
  },
62
70
  },
63
71
  isSent: false,
64
- title: "maintenance:ticket.assignuser.notification.title",
72
+ title: i18next_1.default.t("maintenance:ticket.assignuser.notification.title"),
65
73
  user: assignedTo,
66
- description: "maintenance:ticket.assignuser.notification.description",
67
- }).save(null, fetchOptions);
74
+ description: i18next_1.default.t("maintenance:ticket.assignuser.notification.description", {
75
+ username: (0, openinc_openservice_save_ticket_data_1.getUsername)(assigningUser) ?? "System",
76
+ ticketName: ticket.get("title"),
77
+ ticketLink: (0, getTicketLink_1.getTicketLink)(ticket),
78
+ }),
79
+ }).save(null, { useMasterKey: true });
68
80
  userNotifiedIds.push(assignedTo.id);
69
81
  }
70
82
  for (const assignedTo of newRoles) {
@@ -79,10 +91,12 @@ async function assignUsersAndRoles(ticket, assignedTo, fetchOptions, assigningUs
79
91
  .relation("users")
80
92
  .query()
81
93
  .find(fetchOptions);
82
- for (const roleUser of roleUsers) {
94
+ for await (const roleUser of roleUsers) {
83
95
  if (userNotifiedIds.includes(roleUser.id) ||
84
96
  roleUser.id === assigningUser?.id)
85
97
  continue;
98
+ const resipientlanguage = await (0, getUserLanguage_1.getUserLanguage)(roleUser);
99
+ await i18next_1.default.changeLanguage(resipientlanguage);
86
100
  await new types_1.Notification({
87
101
  data: {
88
102
  ticketId: ticket.id,
@@ -94,10 +108,15 @@ async function assignUsersAndRoles(ticket, assignedTo, fetchOptions, assigningUs
94
108
  },
95
109
  },
96
110
  isSent: false,
97
- title: "maintenance:ticket.assignrole.notification.title",
111
+ title: i18next_1.default.t("maintenance:ticket.assignrole.notification.title"),
98
112
  user: roleUser,
99
- description: "maintenance:ticket.assignrole.notification.description",
100
- }).save(null, fetchOptions);
113
+ description: i18next_1.default.t("maintenance:ticket.assignrole.notification.description", {
114
+ username: (0, openinc_openservice_save_ticket_data_1.getUsername)(assigningUser) ?? "System",
115
+ ticketName: ticket.get("title"),
116
+ role: assignedTo.get("label"),
117
+ ticketLink: (0, getTicketLink_1.getTicketLink)(ticket),
118
+ }),
119
+ }).save(null, { useMasterKey: true });
101
120
  }
102
121
  }
103
122
  await types_1.Maintenance_Ticket_Assignment.saveAll(assignments, fetchOptions);
@@ -0,0 +1,2 @@
1
+ import { Maintenance_Ticket } from "../../../types";
2
+ export declare function getTicketLink(ticket: Maintenance_Ticket): string;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTicketLink = getTicketLink;
4
+ const config_1 = require("../../config");
5
+ function getTicketLink(ticket) {
6
+ //Get hostname from environment variable or default to localhost
7
+ let hostname = "localhost";
8
+ try {
9
+ const publicurl = config_1.ConfigInstance.getInstance()
10
+ .get("PARSE_PUBLIC_SERVER_URL")
11
+ .replace("/parse", "");
12
+ if (publicurl) {
13
+ hostname = publicurl;
14
+ }
15
+ }
16
+ catch (error) {
17
+ console.warn("[@openinc/parse-server-opendash] Could not get PARSE_PUBLIC_SERVER_URL from config, defaulting to localhost");
18
+ }
19
+ return `${hostname}/openservice/ticket/${ticket.id}`;
20
+ }
@@ -0,0 +1 @@
1
+ export { initTranslations } from "./services/initTranslation.js";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initTranslations = void 0;
4
+ var initTranslation_js_1 = require("./services/initTranslation.js");
5
+ Object.defineProperty(exports, "initTranslations", { enumerable: true, get: function () { return initTranslation_js_1.initTranslations; } });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @file Init Translations
3
+ * @description Initializes the translation service for the application.
4
+ */
5
+ export declare function initTranslations(): Promise<void>;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.initTranslations = initTranslations;
7
+ const i18next_1 = __importDefault(require("i18next"));
8
+ const i18next_fs_backend_1 = __importDefault(require("i18next-fs-backend"));
9
+ const path_1 = __importDefault(require("path"));
10
+ /**
11
+ * @file Init Translations
12
+ * @description Initializes the translation service for the application.
13
+ */
14
+ async function initTranslations() {
15
+ try {
16
+ console.log("[@openinc/parse-server-opendash] Init translations");
17
+ const i18npath = path_1.default.join(__dirname, "../../../i18n");
18
+ const loadPath = path_1.default.join(i18npath, "{{lng}}/{{ns}}.json");
19
+ const addPath = path_1.default.join(i18npath, "{{lng}}/{{ns}}.missing.json");
20
+ // Initialize i18next with backend configuration
21
+ await i18next_1.default.use(i18next_fs_backend_1.default).init({
22
+ // Backend configuration
23
+ backend: {
24
+ loadPath: loadPath,
25
+ addPath: addPath,
26
+ },
27
+ // Use the correct language codes that match your directory names
28
+ lng: "de-DE",
29
+ fallbackLng: "en-US",
30
+ // Specify available languages to match your directories
31
+ supportedLngs: ["de-DE", "en-US"],
32
+ ns: ["maintenance"],
33
+ defaultNS: "server",
34
+ debug: false,
35
+ // Ensure resources are loaded
36
+ initImmediate: false,
37
+ });
38
+ console.log("[@openinc/parse-server-opendash] Current language:", i18next_1.default.language);
39
+ }
40
+ catch (error) {
41
+ console.error("[@openinc/parse-server-opendash] Error while initializing translations");
42
+ console.error(error);
43
+ process.exit(1);
44
+ }
45
+ }
@@ -0,0 +1,2 @@
1
+ import { _User } from "../types";
2
+ export declare function getUserLanguage(recipient: _User): Promise<string>;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getUserLanguage = getUserLanguage;
4
+ async function getUserLanguage(recipient) {
5
+ const language = recipient.get("settings")
6
+ ? recipient.get("settings").get("preferred_language")
7
+ : "de-DE";
8
+ return language;
9
+ }
@@ -100,11 +100,9 @@ async function init() {
100
100
  : article?.get("targettime") || 0);
101
101
  }
102
102
  }
103
- if (object.get("status") === "canceled") {
104
- }
105
103
  // If the order is started and has a source, it is running
106
104
  if (object.get("start") &&
107
- object.get("start").getTime() > nowThresholded &&
105
+ object.get("start").getTime() < Date.now() + 60000 &&
108
106
  object.get("source") &&
109
107
  !object.get("status")) {
110
108
  object.set("status", "running");
@@ -127,6 +125,20 @@ async function init() {
127
125
  (object.get("status") === "running" || object.get("status") === "planned")) {
128
126
  object.set("status", "done");
129
127
  }
128
+ if (object.get("status") === "running") {
129
+ const runningOrdersQ = new Parse.Query(types_1.MES_Order);
130
+ runningOrdersQ.equalTo("tag", object.get("tag"));
131
+ runningOrdersQ.notEqualTo("objectId", object.id);
132
+ runningOrdersQ.equalTo("status", "running");
133
+ const runningOrders = await runningOrdersQ.find({ useMasterKey: true });
134
+ if (runningOrders.length > 0 && object.get("status") === "running") {
135
+ for (const runningOrder of runningOrders) {
136
+ runningOrder.set("duration", Date.now() - runningOrder.get("start").getTime());
137
+ console.log("Stopping running order " + runningOrder.id);
138
+ await runningOrder.save(null, { useMasterKey: true });
139
+ }
140
+ }
141
+ }
130
142
  });
131
143
  (0, __1.afterSaveHook)(types_1.MES_Order, async (request) => {
132
144
  const { object, original, user } = request;
@@ -24,6 +24,7 @@ async function init() {
24
24
  // Handle Email
25
25
  if (config_1.ConfigInstance.getInstance().getBoolean("APP_NOTIFICATIONS_PER_EMAIL")) {
26
26
  const email = user?.getEmail();
27
+ console.log("[@openinc/parse-server-opendash][Notification]", `notification="${object.id}"`, `type="email"`, `to="${email}"`);
27
28
  if (email) {
28
29
  let body = description || "";
29
30
  if (object.get("data")?.url) {
@@ -0,0 +1,16 @@
1
+ {
2
+ "ticket": {
3
+ "assignuser": {
4
+ "notification": {
5
+ "title": "Sie wurden einem Ticket zugewiesen",
6
+ "description": "Hallo,\n\n{{username}} hat Sie dem Ticket {{ticketName}} zugeordnet. \n\nLink zum Ticket: {{- ticketLink}}"
7
+ }
8
+ },
9
+ "assignrole": {
10
+ "notification": {
11
+ "title": "Ein Ticket wurde Ihrer Rolle zugewiesen",
12
+ "description": "Hallo,\n\n{{username}} hat das Ticket {{ticketName}} der Rolle {{role}} zugewiesen. \n\nLink zum Ticket: {{- ticketLink}}"
13
+ }
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "ticket": {
3
+ "assignuser": {
4
+ "notification": {
5
+ "title": "You've been assigned to a ticket",
6
+ "description": "Hello,\n\n{{username}} assigned you to the ticket {{ticketName}}. \n\nLink: {{- ticketLink}}"
7
+ }
8
+ },
9
+ "assignrole": {
10
+ "notification": {
11
+ "title": "A ticket was assigned to your role",
12
+ "description": "Hello,\n\n{{username}} assigned ticket {{ticketName}} to the role {{role}}. \n\nLink: {{- ticketLink}}"
13
+ }
14
+ }
15
+ }
16
+ }
package/dist/index.js CHANGED
@@ -41,6 +41,7 @@ const settings_1 = require("./features/user/settings");
41
41
  const Core_Email_1 = require("./hooks/Core_Email");
42
42
  const importDocs_1 = require("./features/documentation/functions/importDocs");
43
43
  const openservice_1 = require("./features/openservice");
44
+ const translations_1 = require("./features/translations");
44
45
  const _init_1 = require("./functions/_init");
45
46
  const _init_2 = require("./hooks/_init");
46
47
  dayjs_1.default.extend(objectSupport_1.default);
@@ -83,7 +84,7 @@ async function init() {
83
84
  catch (error) { }
84
85
  config = config_1.ConfigInstance.getInstance();
85
86
  await config.init(true);
86
- await initTranslations();
87
+ await (0, translations_1.initTranslations)();
87
88
  await (0, Core_Email_1.initEmailTransport)();
88
89
  await initWebPush();
89
90
  await initSchema();
@@ -100,17 +101,6 @@ async function init() {
100
101
  if ((0, config_1.isFeatureEnabled)("DOCUMENTATION"))
101
102
  await (0, importDocs_1.importDocs)();
102
103
  }
103
- async function initTranslations() {
104
- // try {
105
- // console.log("init translations");
106
- // registerLanguage("deu", "Deutsch", "eng", true);
107
- // registerTranslationResolver("deu", "server", async () => lang_deu);
108
- // } catch (error) {
109
- // console.error("Error while initializing translations");
110
- // console.error(error);
111
- // process.exit(1);
112
- // }
113
- }
114
104
  async function initWebPush() {
115
105
  try {
116
106
  if (config.getBoolean("WEB_PUSH_ENABLED")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openinc/parse-server-opendash",
3
- "version": "3.26.2",
3
+ "version": "3.28.0",
4
4
  "description": "Parse Server Cloud Code for open.INC Stack.",
5
5
  "packageManager": "pnpm@10.20.0",
6
6
  "keywords": [
@@ -46,7 +46,9 @@
46
46
  },
47
47
  "scripts": {
48
48
  "start": "tsc -w",
49
- "build": "tsc",
49
+ "dockerstart": "concurrently \"pnpm run start\" \"cd ./docker-dev && docker-compose watch\"",
50
+ "build": "tsc && node scripts/copyTranslationFiles.js",
51
+ "copy:i18n": "node scripts/copyTranslationFiles.js",
50
52
  "deploy": "opendash deploy",
51
53
  "schema-down": "parse-server-schema down --prefix OD3_ ./schema",
52
54
  "schema-up": "parse-server-schema up --prefix OD3_ ./schema",
@@ -72,14 +74,16 @@
72
74
  "@opentelemetry/winston-transport": "^0.19.0",
73
75
  "cron": "^4.3.4",
74
76
  "dayjs": "^1.11.19",
75
- "fast-equals": "^5.3.2",
77
+ "fast-equals": "^5.3.3",
78
+ "i18next": "^25.6.2",
79
+ "i18next-fs-backend": "^2.6.1",
76
80
  "jsonwebtoken": "^9.0.2",
77
81
  "jwks-rsa": "^3.2.0",
78
82
  "nodemailer": "^7.0.10",
79
83
  "nunjucks": "^3.2.4",
80
84
  "parse-server": "^8.4.0",
81
85
  "pdf-img-convert": "2.0.0",
82
- "semantic-release": "^25.0.1",
86
+ "semantic-release": "^25.0.2",
83
87
  "table": "^6.9.0",
84
88
  "web-push": "^3.6.7",
85
89
  "winston": "^3.18.3"
@@ -89,16 +93,17 @@
89
93
  "@semantic-release/commit-analyzer": "^13.0.1",
90
94
  "@semantic-release/exec": "^7.1.0",
91
95
  "@semantic-release/git": "^10.0.1",
92
- "@semantic-release/github": "^12.0.1",
93
- "@semantic-release/npm": "^13.1.1",
96
+ "@semantic-release/github": "^12.0.2",
97
+ "@semantic-release/npm": "^13.1.2",
94
98
  "@semantic-release/release-notes-generator": "^14.1.0",
95
99
  "@types/jsonwebtoken": "^9.0.10",
96
- "@types/node": "^24.10.0",
97
- "@types/nodemailer": "^7.0.3",
100
+ "@types/node": "^24.10.1",
101
+ "@types/nodemailer": "^7.0.4",
98
102
  "@types/nunjucks": "^3.2.6",
99
103
  "@types/parse": "^3.0.9",
100
104
  "@types/safe-timers": "^1.1.2",
101
105
  "@types/web-push": "^3.6.4",
106
+ "concurrently": "^9.2.1",
102
107
  "semantic-release-export-data": "^1.2.0",
103
108
  "ts-node": "^10.9.2",
104
109
  "typedoc": "^0.28.14",