@underpostnet/underpost 2.8.0 → 2.8.31

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.
Files changed (74) hide show
  1. package/.dockerignore +1 -0
  2. package/.github/workflows/ghpkg.yml +4 -4
  3. package/.vscode/extensions.json +8 -71
  4. package/.vscode/settings.json +2 -1
  5. package/CHANGELOG.md +55 -3
  6. package/Dockerfile +22 -36
  7. package/README.md +0 -27
  8. package/bin/deploy.js +54 -28
  9. package/bin/file.js +30 -2
  10. package/bin/index.js +6 -18
  11. package/bin/ssl.js +19 -11
  12. package/bin/util.js +18 -0
  13. package/bin/vs.js +3 -2
  14. package/conf.js +17 -1
  15. package/docker-compose.yml +1 -1
  16. package/manifests/mariadb/config.yaml +10 -0
  17. package/manifests/mariadb/kustomization.yaml +9 -0
  18. package/manifests/mariadb/pv.yaml +12 -0
  19. package/manifests/mariadb/pvc.yaml +10 -0
  20. package/manifests/mariadb/secret.yaml +8 -0
  21. package/manifests/mariadb/service.yaml +10 -0
  22. package/manifests/mariadb/statefulset.yaml +55 -0
  23. package/manifests/test/mongo-express.yaml +60 -0
  24. package/manifests/test/phpmyadmin.yaml +54 -0
  25. package/manifests/test/underpost-engine-mongodb-configmap.yaml +26 -0
  26. package/manifests/test/underpost-engine-pod.yaml +108 -0
  27. package/manifests/underpost-engine-backup-access.yaml +16 -0
  28. package/manifests/underpost-engine-backup-pv-pvc.yaml +22 -0
  29. package/manifests/underpost-engine-headless-service.yaml +10 -0
  30. package/manifests/underpost-engine-mongodb-backup-cronjob.yaml +40 -0
  31. package/manifests/underpost-engine-pv-pvc.yaml +23 -0
  32. package/manifests/underpost-engine-statefulset.yaml +91 -0
  33. package/manifests/valkey/kustomization.yaml +7 -0
  34. package/manifests/valkey/underpost-engine-valkey-service.yaml +17 -0
  35. package/manifests/valkey/underpost-engine-valkey-statefulset.yaml +39 -0
  36. package/package.json +22 -12
  37. package/src/api/user/user.model.js +9 -1
  38. package/src/api/user/user.service.js +1 -1
  39. package/src/client/components/core/Account.js +4 -2
  40. package/src/client/components/core/Auth.js +2 -2
  41. package/src/client/components/core/CalendarCore.js +112 -49
  42. package/src/client/components/core/CommonJs.js +125 -19
  43. package/src/client/components/core/Css.js +1 -1
  44. package/src/client/components/core/CssCore.js +6 -0
  45. package/src/client/components/core/Docs.js +2 -1
  46. package/src/client/components/core/DropDown.js +5 -1
  47. package/src/client/components/core/Input.js +17 -3
  48. package/src/client/components/core/JoyStick.js +8 -5
  49. package/src/client/components/core/Modal.js +12 -6
  50. package/src/client/components/core/Panel.js +82 -24
  51. package/src/client/components/core/PanelForm.js +11 -19
  52. package/src/client/components/core/SignUp.js +4 -1
  53. package/src/client/components/core/Translate.js +44 -8
  54. package/src/client/public/default/plantuml/client-conf.svg +1 -1
  55. package/src/client/public/default/plantuml/server-conf.svg +1 -1
  56. package/src/client/public/default/plantuml/server-schema.svg +1 -1
  57. package/src/client/public/default/plantuml/ssr-conf.svg +1 -1
  58. package/src/client/public/default/plantuml/ssr-schema.svg +1 -1
  59. package/src/client/services/core/core.service.js +2 -0
  60. package/src/client/ssr/body/CacheControl.js +2 -1
  61. package/src/client/ssr/body/DefaultSplashScreen.js +3 -3
  62. package/src/client/ssr/offline/Maintenance.js +63 -0
  63. package/src/client/sw/default.sw.js +23 -3
  64. package/src/db/mongo/MongooseDB.js +13 -1
  65. package/src/index.js +8 -0
  66. package/src/server/client-build.js +5 -4
  67. package/src/server/client-icons.js +1 -1
  68. package/src/server/conf.js +5 -5
  69. package/src/server/logger.js +8 -6
  70. package/src/server/process.js +25 -2
  71. package/src/server/ssl.js +1 -1
  72. package/src/server/valkey.js +3 -0
  73. package/startup.cjs +12 -0
  74. package/startup.js +0 -11
@@ -0,0 +1,39 @@
1
+ ---
2
+ apiVersion: apps/v1
3
+ kind: StatefulSet
4
+ metadata:
5
+ name: service-valkey
6
+ namespace: default
7
+ spec:
8
+ serviceName: service-valkey
9
+ replicas: 1
10
+ selector:
11
+ matchLabels:
12
+ app: service-valkey
13
+ template:
14
+ metadata:
15
+ labels:
16
+ app: service-valkey
17
+ spec:
18
+ containers:
19
+ - name: service-valkey
20
+ image: docker.io/valkey/valkey:latest
21
+ env:
22
+ - name: TZ
23
+ value: Europe/Zurich
24
+ ports:
25
+ - containerPort: 6379
26
+ startupProbe:
27
+ tcpSocket:
28
+ port: 6379
29
+ failureThreshold: 30
30
+ periodSeconds: 5
31
+ timeoutSeconds: 5
32
+ livenessProbe:
33
+ tcpSocket:
34
+ port: 6379
35
+ failureThreshold: 2
36
+ periodSeconds: 30
37
+ timeoutSeconds: 5
38
+ restartPolicy: Always
39
+ automountServiceAccountToken: false
package/package.json CHANGED
@@ -2,16 +2,16 @@
2
2
  "type": "module",
3
3
  "main": "src/index.js",
4
4
  "name": "@underpostnet/underpost",
5
- "version": "2.8.0",
5
+ "version": "2.8.31",
6
6
  "description": "pwa api rest template",
7
7
  "scripts": {
8
8
  "start": "env-cmd -f .env.production node --max-old-space-size=8192 src/server",
9
9
  "pm2": "env-cmd -f .env.production pm2 start src/server.js --node-args=\"--max-old-space-size=8192\" --name engine && pm2 logs",
10
10
  "ssl": "env-cmd -f .env.production node bin/ssl",
11
11
  "pm2-delete": "pm2 delete engine",
12
- "build": "node bin/deploy build-full-client",
12
+ "build": "node bin/deploy build-full-client && node bin/deploy fix-deps",
13
13
  "build-production": "env-cmd -f .env.production node bin/deploy build-full-client",
14
- "dev": "env-cmd -f .env.development node src/client.dev",
14
+ "dev": "env-cmd -f .env.development node src/client.dev default",
15
15
  "dev-api": "env-cmd -f .env.development nodemon --watch src --ignore src/client src/api",
16
16
  "docs": "jsdoc -c jsdoc.json",
17
17
  "backup": "node bin/db default.net/ export",
@@ -53,20 +53,25 @@
53
53
  "homepage": "https://github.com/underpostnet/pwa-microservices-template#readme",
54
54
  "dependencies": {
55
55
  "@fortawesome/fontawesome-free": "^6.4.2",
56
+ "@fullcalendar/rrule": "^6.1.15",
57
+ "@google/generative-ai": "^0.21.0",
56
58
  "@loadingio/css-spinner": "^2.0.2",
57
59
  "@neodrag/vanilla": "^2.0.3",
58
- "@xenova/transformers": "^2.17.2",
60
+ "@nomiclabs/hardhat-ethers": "^2.2.3",
61
+ "@nomiclabs/hardhat-etherscan": "^3.1.8",
62
+ "@nomiclabs/hardhat-waffle": "^2.0.6",
63
+ "@openzeppelin/contracts": "^5.0.2",
59
64
  "adm-zip": "^0.5.10",
60
65
  "ag-grid-community": "31.0.0",
61
66
  "axios": "^1.5.1",
62
67
  "chai": "^5.1.0",
63
68
  "cli-progress": "^3.12.0",
64
69
  "cli-spinners": "^3.0.0",
70
+ "clipboardy": "^4.0.0",
65
71
  "color": "^4.2.3",
66
72
  "colors": "^1.4.0",
67
73
  "commander": "^12.1.0",
68
74
  "compression": "^1.7.4",
69
- "copy-paste": "^1.5.3",
70
75
  "cors": "^2.8.5",
71
76
  "d3": "^7.9.0",
72
77
  "deepmerge": "^4.3.1",
@@ -84,27 +89,30 @@
84
89
  "html-minifier-terser": "^7.2.0",
85
90
  "http-proxy-middleware": "^2.0.6",
86
91
  "ignore-walk": "^6.0.4",
92
+ "iovalkey": "^0.2.1",
87
93
  "is-admin": "^4.0.0",
88
94
  "is-ip": "^5.0.1",
89
95
  "jimp": "^0.22.12",
90
96
  "joystick-controller": "^1.0.15",
91
97
  "json-colorizer": "^2.2.2",
92
98
  "jsonwebtoken": "^9.0.2",
99
+ "keyword-extractor": "^0.0.28",
93
100
  "kill-port-process": "^3.2.0",
94
101
  "log-update": "^6.0.0",
95
102
  "mariadb": "^3.2.2",
96
103
  "marked": "^12.0.2",
97
- "mongoose": "^8.0.1",
104
+ "mongoose": "^8.9.5",
98
105
  "morgan": "^1.10.0",
99
106
  "nodemailer": "^6.9.9",
100
107
  "nodemon": "^3.0.1",
101
108
  "pathfinding": "^0.4.18",
102
109
  "peer": "^1.0.2",
103
110
  "peerjs": "^1.5.2",
104
- "pixi.js": "7.4.0",
111
+ "pixi.js": "7.4.2",
105
112
  "prom-client": "^15.1.2",
106
113
  "public-ip": "^6.0.1",
107
114
  "read": "^2.1.0",
115
+ "rrule": "^2.8.1",
108
116
  "sharp": "^0.32.5",
109
117
  "shelljs": "^0.8.5",
110
118
  "simple-git": "^3.26.0",
@@ -114,18 +122,20 @@
114
122
  "sortablejs": "^1.15.0",
115
123
  "split-file": "^2.3.0",
116
124
  "swagger-ui-express": "^5.0.0",
117
- "systeminformation": "^5.21.17",
125
+ "systeminformation": "^5.23.7",
118
126
  "uglify-js": "^3.17.4",
119
127
  "validator": "^13.11.0",
120
- "winston": "^3.11.0",
121
- "iovalkey": "^0.2.1"
128
+ "vanilla-jsoneditor": "^2.3.2",
129
+ "web3": "^4.13.0",
130
+ "winston": "^3.11.0"
122
131
  },
123
132
  "devDependencies": {
124
133
  "clean-jsdoc-theme": "^4.3.0",
134
+ "easy-json-schema": "^0.0.2-beta",
135
+ "hardhat": "^2.22.13",
125
136
  "mocha": "^10.4.0",
126
137
  "plantuml": "^0.0.2",
127
- "swagger-autogen": "^2.23.7",
128
- "easy-json-schema": "^0.0.2-beta"
138
+ "swagger-autogen": "^2.23.7"
129
139
  },
130
140
  "publishConfig": {
131
141
  "provenance": true,
@@ -26,7 +26,11 @@ const UserSchema = new Schema(
26
26
  profileImageId: { type: Schema.Types.ObjectId, ref: 'File' },
27
27
  phoneNumbers: [
28
28
  {
29
- type: { type: String, enum: ['office', 'home', 'private'], number: { type: String } },
29
+ type: {
30
+ type: String,
31
+ enum: ['office', 'home', 'private'],
32
+ },
33
+ number: { type: String },
30
34
  },
31
35
  ],
32
36
  publicKey: {
@@ -58,6 +62,10 @@ const UserDto = {
58
62
  },
59
63
  },
60
64
  auth: {
65
+ // TODO: -> set login device, location, ip, fingerprint
66
+ // and validate on authorization middleware
67
+ // -> dynamic refresh 100 tokens per session with 12h interval
68
+ // -> back secret per user, registrarion user model -> secret: { type: String }
61
69
  payload: (user) => ({ _id: user._id.toString(), role: user.role, email: user.email }),
62
70
  },
63
71
  };
@@ -237,7 +237,7 @@ const UserService = {
237
237
  const validatePassword = validatePasswordMiddleware(req.body.password);
238
238
  if (validatePassword.status === 'error') throw new Error(validatePassword.message);
239
239
  req.body.password = await hashPassword(req.body.password);
240
- req.body.role = 'user';
240
+ req.body.role = req.body.role === 'guest' ? 'guest' : 'user';
241
241
  req.body.profileImageId = await getDefaultProfileImageId(File);
242
242
  const { _id } = await new User(req.body).save();
243
243
  if (_id) {
@@ -300,8 +300,10 @@ const Account = {
300
300
  s(`.account-profile-image`).style.opacity = 0;
301
301
  for (const inputData of this.formData)
302
302
  if (s(`.${inputData.id}`)) s(`.${inputData.id}`).value = user[inputData.model];
303
- s(`.account-profile-image`).src = LogIn.Scope.user.main.model.user.profileImage.imageSrc;
304
- s(`.account-profile-image`).style.opacity = 1;
303
+ if (LogIn.Scope.user.main.model.user.profileImage) {
304
+ s(`.account-profile-image`).src = LogIn.Scope.user.main.model.user.profileImage.imageSrc;
305
+ s(`.account-profile-image`).style.opacity = 1;
306
+ }
305
307
  },
306
308
  };
307
309
 
@@ -46,8 +46,8 @@ const Auth = {
46
46
  ) {
47
47
  try {
48
48
  localStorage.setItem('jwt', result.data.token);
49
- await Auth.sessionIn();
50
49
  await SignUp.Trigger(result.data);
50
+ await Auth.sessionIn();
51
51
  } catch (error) {
52
52
  logger.error(error);
53
53
  localStorage.removeItem('jwt');
@@ -76,7 +76,7 @@ const Auth = {
76
76
  await LogIn.Trigger({ user: data.user });
77
77
  await Account.updateForm(data.user);
78
78
  return { user: data.user };
79
- } else throw new Error(message);
79
+ }
80
80
  }
81
81
 
82
82
  // anon guest session
@@ -1,7 +1,7 @@
1
1
  import { EventSchedulerService } from '../../services/event-scheduler/event-scheduler.service.js';
2
2
  import { Auth } from './Auth.js';
3
3
  import { BtnIcon } from './BtnIcon.js';
4
- import { newInstance, range, s4 } from './CommonJs.js';
4
+ import { isValidDate, newInstance, range, s4 } from './CommonJs.js';
5
5
  import { renderCssAttr } from './Css.js';
6
6
  import { Modal } from './Modal.js';
7
7
  import { NotificationManager } from './NotificationManager.js';
@@ -13,15 +13,27 @@ import { append, getQueryParams, getTimeZone, htmls, s, sa } from './VanillaJs.j
13
13
 
14
14
  // https://fullcalendar.io/docs/event-object
15
15
 
16
+ const daysOfWeekOptions = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
17
+
18
+ const eventDateFactory = (event) =>
19
+ newInstance({
20
+ event: { ...event.extendedProps, title: event._def.title },
21
+ start: event.start,
22
+ end: event.end,
23
+ });
24
+
16
25
  const CalendarCore = {
17
26
  RenderStyle: async function () {},
18
27
  Data: {},
19
- Render: async function (options = { idModal: '', Elements: {}, heightTopBar: 50, heightBottomBar: 50 }) {
28
+ Render: async function (
29
+ options = { idModal: '', Elements: {}, heightTopBar: 50, heightBottomBar: 50, hiddenDates: [] },
30
+ ) {
20
31
  this.Data[options.idModal] = {
21
32
  data: [],
22
33
  originData: [],
23
34
  filesData: [],
24
35
  calendar: {},
36
+ hiddenDates: options.hiddenDates ? options.hiddenDates : [],
25
37
  };
26
38
 
27
39
  const { heightTopBar, heightBottomBar } = options;
@@ -40,56 +52,87 @@ const CalendarCore = {
40
52
  };
41
53
  getSrrData();
42
54
 
43
- const dateFormat = (date) =>
44
- html`<span
45
- style="${renderCssAttr({
46
- style: {
47
- 'font-size': '14px',
48
- color: '#888',
49
- },
50
- })}"
51
- >${new Date(date).toLocaleString().replaceAll(',', '')}</span
52
- >`;
53
-
54
55
  const getPanelData = async () => {
55
56
  const result = await EventSchedulerService.get({
56
- id: `${getQueryParams().cid ? getQueryParams().cid : 'creatorUser'}`,
57
+ id: `${getQueryParams().cid ? getQueryParams().cid : Auth.getToken() ? 'creatorUser' : ''}`,
57
58
  });
58
59
  NotificationManager.Push({
59
60
  html: result.status === 'success' ? Translate.Render('success-get-events-scheduler') : result.message,
60
61
  status: result.status,
61
62
  });
62
63
  if (result.status === 'success') {
63
- const resultData = Array.isArray(result.data) ? result.data : [result.data];
64
+ const resultData = Array.isArray(result.data) ? result.data : result.data ? [result.data] : [];
64
65
  this.Data[options.idModal].filesData = [];
65
66
  this.Data[options.idModal].originData = newInstance(resultData);
66
67
  this.Data[options.idModal].data = resultData.map((o) => {
67
68
  if (o.creatorUserId && options.Elements.Data.user.main.model.user._id === o.creatorUserId) o.tools = true;
68
69
  o.id = o._id;
69
- o.start = dateFormat(o.start);
70
- o.end = dateFormat(o.end);
70
+
71
71
  this.Data[options.idModal].filesData.push({});
72
72
  return o;
73
73
  });
74
+ setTimeout(() => {
75
+ renderCalendar(
76
+ resultData.map((o) => {
77
+ // FREQ=WEEKLY;
78
+ // if (o.daysOfWeek && o.daysOfWeek.length > 0) {
79
+ // o.rrule = `RRULE:BYDAY=${o.daysOfWeek.map((d) => `${d[0]}${d[1]}`.toUpperCase()).join(',')}`;
80
+ // }
81
+ // o.rrule = 'FREQ=WEEKLY;BYDAY=SU;BYHOUR=10,11;COUNT=10';
82
+ if (o.daysOfWeek && o.daysOfWeek.length > 0)
83
+ o.daysOfWeek = o.daysOfWeek.map((v, i) => daysOfWeekOptions.indexOf(v));
84
+ else delete o.daysOfWeek;
85
+ // o.exdate = ['2024-04-02'];
86
+ // delete o.end;
87
+ // delete o.start;
88
+
89
+ return o;
90
+ }),
91
+ );
92
+ });
74
93
  }
75
94
  };
76
95
 
77
- const renderCalendar = () => {
96
+ const renderCalendar = (events) => {
78
97
  const calendarEl = s(`.calendar-${idPanel}`);
79
98
  this.Data[options.idModal].calendar = new FullCalendar.Calendar(calendarEl, {
80
- plugins: [FullCalendar.DayGrid.default, FullCalendar.TimeGrid.default, FullCalendar.List.default],
99
+ plugins: [
100
+ FullCalendar.DayGrid.default,
101
+ FullCalendar.TimeGrid.default,
102
+ FullCalendar.List.default,
103
+ // https://fullcalendar.io/docs/rrule-plugin
104
+ FullCalendar.RRule.default,
105
+ ],
81
106
  // initialView: 'dayGridWeek',
82
107
  timeZone: getTimeZone(),
83
108
  dateClick: function (arg) {
84
109
  console.error('calendar dateClick', arg.date.toString());
85
110
  },
86
- events: [{ title: 'Meeting', start: new Date() }],
111
+ events: events ?? [{ title: 'Meeting', start: new Date() }],
87
112
  initialView: 'dayGridMonth',
88
113
  headerToolbar: {
89
114
  left: 'prev,next today',
90
115
  center: 'title',
91
116
  right: 'dayGridMonth,timeGridWeek,listWeek',
92
117
  },
118
+ eventClick: async function (args) {
119
+ const dateData = eventDateFactory(args.event);
120
+ // element -> args.el
121
+ // remove all events associated -> args.event.remove();
122
+ // console.error('eventClick', JSON.stringify(dateData, null, 4));
123
+ if (options.eventClick) await options.eventClick(dateData, args);
124
+ },
125
+ eventClassNames: function (args) {
126
+ // console.error('eventClassNames', JSON.stringify(dateData, null, 4));
127
+ if (!args.event.extendedProps._id) return args.event.remove();
128
+ const dateData = eventDateFactory(args.event);
129
+ if (
130
+ CalendarCore.Data[options.idModal].hiddenDates.find(
131
+ (d) => d.eventSchedulerId === dateData.event._id && d.date === dateData.start,
132
+ )
133
+ )
134
+ return ['hide'];
135
+ },
93
136
  });
94
137
 
95
138
  this.Data[options.idModal].calendar.render();
@@ -139,29 +182,52 @@ const CalendarCore = {
139
182
  rules: [{ type: 'isEmpty' }],
140
183
  },
141
184
  {
142
- id: 'description',
143
- model: 'description',
185
+ id: 'title',
186
+ model: 'title',
144
187
  inputType: 'text',
145
188
  rules: [{ type: 'isEmpty' }],
146
189
  panel: { type: 'title' },
147
190
  },
148
191
  {
149
- id: 'allDay',
150
- model: 'allDay',
151
- inputType: 'checkbox-on-off',
152
- rules: [],
153
- panel: { type: 'info-row', icon: html`<i class="fa-solid fa-infinity"></i>` },
192
+ id: 'description',
193
+ model: 'description',
194
+ inputType: 'text',
195
+ rules: [{ type: 'isEmpty' }],
196
+ panel: { type: 'info-row' },
154
197
  },
155
198
  {
156
199
  id: 'start',
157
200
  model: 'start',
158
201
  inputType: 'datetime-local',
159
- panel: { type: 'subtitle' },
202
+ translateCode: 'startTime',
203
+ panel: { type: 'info-row' },
160
204
  },
161
205
  {
162
206
  id: 'end',
163
207
  model: 'end',
164
208
  inputType: 'datetime-local',
209
+ translateCode: 'endTime',
210
+ panel: { type: 'info-row' },
211
+ },
212
+ {
213
+ id: 'daysOfWeek',
214
+ model: 'daysOfWeek',
215
+ inputType: 'dropdown-checkbox',
216
+ dropdown: {
217
+ options: daysOfWeekOptions,
218
+ },
219
+ panel: { type: 'list' },
220
+ },
221
+ {
222
+ id: 'startTime',
223
+ model: 'startTime',
224
+ inputType: 'time',
225
+ panel: { type: 'info-row' },
226
+ },
227
+ {
228
+ id: 'endTime',
229
+ model: 'endTime',
230
+ inputType: 'time',
165
231
  panel: { type: 'info-row' },
166
232
  },
167
233
  ];
@@ -215,8 +281,7 @@ const CalendarCore = {
215
281
  if (options.route) {
216
282
  setQueryPath({ path: options.route, queryPath: payload._id });
217
283
  if (options.parentIdModal) Modal.Data[options.parentIdModal].query = `${window.location.search}`;
218
- if (CalendarCore.Data[options.idModal].updatePanel)
219
- await CalendarCore.Data[options.idModal].updatePanel();
284
+ await CalendarCore.Data[options.idModal].updatePanel();
220
285
  }
221
286
  },
222
287
  titleIcon,
@@ -250,12 +315,19 @@ const CalendarCore = {
250
315
  ],
251
316
  on: {
252
317
  add: async function ({ data, editId }) {
318
+ if (data.daysOfWeek && data.daysOfWeek.length > 0 && daysOfWeekOptions[data.daysOfWeek[0]]) {
319
+ data.daysOfWeek = data.daysOfWeek.map((d) => daysOfWeekOptions[d]);
320
+ }
321
+ data.timeZoneClient = getTimeZone();
253
322
  const {
254
323
  status,
255
324
  message,
256
325
  data: documentData,
257
326
  } = editId
258
- ? await EventSchedulerService.put({ id: editId, body: { ...data, _id: undefined } })
327
+ ? await EventSchedulerService.put({
328
+ id: editId,
329
+ body: { ...data, _id: undefined },
330
+ })
259
331
  : await EventSchedulerService.post({ body: data });
260
332
  NotificationManager.Push({
261
333
  html:
@@ -268,10 +340,9 @@ const CalendarCore = {
268
340
  });
269
341
 
270
342
  if (status === 'success') {
271
- data.start = dateFormat(data.start);
272
- data.end = dateFormat(data.end);
273
- data.tools = true;
274
- data._id = documentData._id;
343
+ documentData.tools = true;
344
+ // data._id = documentData._id;
345
+ data = documentData;
275
346
 
276
347
  let originObj, indexOriginObj;
277
348
  let filesData = {};
@@ -291,8 +362,7 @@ const CalendarCore = {
291
362
 
292
363
  setQueryPath({ path: options.route, queryPath: documentData._id });
293
364
  if (options.parentIdModal) Modal.Data[options.parentIdModal].query = `${window.location.search}`;
294
- if (CalendarCore.Data[options.idModal].updatePanel)
295
- await CalendarCore.Data[options.idModal].updatePanel();
365
+ await CalendarCore.Data[options.idModal].updatePanel();
296
366
  }
297
367
  return { data, status, message };
298
368
  },
@@ -319,11 +389,8 @@ const CalendarCore = {
319
389
  status,
320
390
  });
321
391
 
322
- if (getQueryParams().cid === data.id) {
323
- setQueryPath({ path: options.route, queryPath: '' });
324
- if (CalendarCore.Data[options.idModal].updatePanel)
325
- await CalendarCore.Data[options.idModal].updatePanel();
326
- }
392
+ setQueryPath({ path: options.route, queryPath: '' });
393
+ await CalendarCore.Data[options.idModal].updatePanel();
327
394
 
328
395
  return { status };
329
396
  }
@@ -334,17 +401,13 @@ const CalendarCore = {
334
401
  <div class="in" style="margin-bottom: 100px"></div>`;
335
402
  };
336
403
 
337
- let lastCid;
338
- let lasUserId;
339
404
  this.Data[options.idModal].updatePanel = async () => {
340
405
  const cid = getQueryParams().cid ? getQueryParams().cid : '';
341
- if (lastCid === cid && lasUserId === options.Elements.Data.user.main.model.user._id) return;
342
406
  if (options.route === 'home') Modal.homeCid = newInstance(cid);
343
- lasUserId = newInstance(options.Elements.Data.user.main.model.user._id);
344
- lastCid = cid;
345
407
  if (s(`.main-body-calendar-${options.idModal}`)) {
346
- if (Auth.getToken()) await getPanelData();
347
- else getSrrData();
408
+ // if (Auth.getToken())
409
+ // else getSrrData();
410
+ await getPanelData();
348
411
  htmls(`.main-body-calendar-${options.idModal}`, await panelRender());
349
412
  }
350
413
  };
@@ -518,25 +518,25 @@ function getDirname(path) {
518
518
  return parts.join('/'); // Adjust separator if needed for Windows ('\')
519
519
  }
520
520
 
521
- const isDayValid = (day) => {
522
- const date = new Date();
523
- date.setDate(day);
524
- return date.getDate() === day;
525
- };
526
-
527
- const isMonthValid = (month) => {
528
- const date = new Date();
529
- date.setMonth(month - 1);
530
- return date.getMonth() === month - 1;
531
- };
532
-
533
521
  const isValidDate = (day, month, year) => {
534
- if (!isDayValid(day) || !isMonthValid(month)) {
535
- return false;
536
- }
522
+ if (!month && !year) return !(new Date(day) == 'Invalid Date');
523
+ // new Date('2025-12-28')
524
+ // Sat Dec 27 2025 19:00:00 GMT-0500 (Eastern Standard Time)
525
+ // new Date('2025/12/28')
526
+ // Sun Dec 28 2025 00:00:00 GMT-0500 (Eastern Standard Time)
527
+ return !(new Date(`${year}/${month}/${day}`) == 'Invalid Date');
528
+ };
537
529
 
538
- const date = new Date(year, month - 1, day);
539
- return !isNaN(date.getTime());
530
+ // console.log(req.body.timeZoneClient, Intl.DateTimeFormat().resolvedOptions().timeZone);
531
+ // DateTime.fromISO("2017-05-15T09:10:23", { zone: "Europe/Paris" });
532
+ const strToDateUTC = (date = '2025-01-30T14:32') => {
533
+ const year = parseInt(date.split('-')[0]);
534
+ const month = parseInt(date.split('-')[1]);
535
+ const day = parseInt(date.split('-')[2].split('T')[0]);
536
+ const hour = parseInt(date.split('T')[1].split(':')[0]);
537
+ const minute = parseInt(date.split('T')[1].split(':')[1]);
538
+ date = new Date(Date.UTC(year, month - 1, day, hour, minute, 0, 0));
539
+ return date;
540
540
  };
541
541
 
542
542
  const isValidFormat = (value, format) => {
@@ -685,6 +685,112 @@ const hexToNumber = (hex = 0xdc) => Number(hex) || parseFloat(hex, 16);
685
685
 
686
686
  const numberToHex = (number = 0) => number.toString(16);
687
687
 
688
+ const generateRandomPasswordSelection = (length) => {
689
+ const _random = (arr) => {
690
+ const rand = Math.floor(Math.random() * arr.length);
691
+ return arr[rand];
692
+ };
693
+
694
+ const uppercase = [
695
+ 'A',
696
+ 'B',
697
+ 'C',
698
+ 'D',
699
+ 'E',
700
+ 'F',
701
+ 'G',
702
+ 'H',
703
+ 'I',
704
+ 'J',
705
+ 'K',
706
+ 'L',
707
+ 'M',
708
+ 'N',
709
+ 'O',
710
+ 'P',
711
+ 'Q',
712
+ 'R',
713
+ 'S',
714
+ 'T',
715
+ 'U',
716
+ 'V',
717
+ 'W',
718
+ 'X',
719
+ 'Y',
720
+ 'Z',
721
+ ];
722
+ const lowercase = [
723
+ 'a',
724
+ 'b',
725
+ 'c',
726
+ 'd',
727
+ 'e',
728
+ 'f',
729
+ 'g',
730
+ 'h',
731
+ 'i',
732
+ 'j',
733
+ 'k',
734
+ 'l',
735
+ 'm',
736
+ 'n',
737
+ 'o',
738
+ 'p',
739
+ 'q',
740
+ 'r',
741
+ 's',
742
+ 't',
743
+ 'u',
744
+ 'v',
745
+ 'w',
746
+ 'x',
747
+ 'y',
748
+ 'z',
749
+ ];
750
+ const special = [
751
+ '~',
752
+ '!',
753
+ '@',
754
+ '#',
755
+ '$',
756
+ '%',
757
+ '^',
758
+ '&',
759
+ '*',
760
+ '(',
761
+ ')',
762
+ '_',
763
+ '+',
764
+ '-',
765
+ '=',
766
+ '{',
767
+ '}',
768
+ '[',
769
+ ']',
770
+ ':',
771
+ ';',
772
+ '?',
773
+ ',',
774
+ '.',
775
+ '|',
776
+ '\\',
777
+ ];
778
+ const numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
779
+
780
+ const nonSpecial = [...uppercase, ...lowercase, ...numbers];
781
+
782
+ let password = '';
783
+
784
+ for (let i = 0; i < length; i++) {
785
+ // Previous character is a special character
786
+ if (i !== 0 && special.includes(password[i - 1])) {
787
+ password += _random(nonSpecial);
788
+ } else password += _random([...nonSpecial, ...special]);
789
+ }
790
+
791
+ return password;
792
+ };
793
+
688
794
  // 0x = Hexadecimal
689
795
  // 0b = Binary
690
796
  // 0o = Octal
@@ -727,10 +833,9 @@ export {
727
833
  getSubpaths,
728
834
  formatBytes,
729
835
  getDirname,
730
- isDayValid,
731
- isMonthValid,
732
836
  isValidDate,
733
837
  isValidFormat,
838
+ strToDateUTC,
734
839
  getTimezoneOffset,
735
840
  cleanString,
736
841
  splitEveryXChar,
@@ -742,4 +847,5 @@ export {
742
847
  getCapVariableName,
743
848
  hexToNumber,
744
849
  numberToHex,
850
+ generateRandomPasswordSelection,
745
851
  };