@7365admin1/core 2.47.0 → 2.48.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.
package/dist/index.mjs CHANGED
@@ -2748,6 +2748,7 @@ var APP_POOL_MAINTENANCE = process.env.APP_POOL_MAINTENANCE ?? "http://localhost
2748
2748
  var ENCRYPTION_KEY = process.env.ENCRYPTION_KEY ?? "";
2749
2749
  var DOMAIN = process.env.DOMAIN ?? "localhost";
2750
2750
  var OPEN_AI_API_KEY = process.env.OPEN_AI_API_KEY;
2751
+ var STORAGE_API = process.env.STORAGE_API;
2751
2752
 
2752
2753
  // src/services/auth.service.ts
2753
2754
  import jwt from "jsonwebtoken";
@@ -5155,6 +5156,39 @@ function useVerificationRepoV2() {
5155
5156
  throw new InternalServerError11("Error updating verification status.");
5156
5157
  }
5157
5158
  }
5159
+ async function countPendingOrgInvites(orgId) {
5160
+ try {
5161
+ orgId = new ObjectId18(orgId);
5162
+ } catch (error) {
5163
+ throw new BadRequestError19("Invalid organization ID format.");
5164
+ }
5165
+ const query = {
5166
+ status: "pending" /* PENDING */,
5167
+ type: { $in: ["user-invite", "member-invite"] },
5168
+ "metadata.org": orgId
5169
+ };
5170
+ const cacheKey = makeCacheKey10(namespace_collection, {
5171
+ status: "pending" /* PENDING */,
5172
+ type: JSON.stringify(["user-invite", "member-invite"]),
5173
+ org: orgId.toString()
5174
+ });
5175
+ const cachedData = await getCache(cacheKey);
5176
+ if (typeof cachedData === "number") {
5177
+ logger13.info(`Cache hit for key: ${cacheKey}`);
5178
+ return cachedData;
5179
+ }
5180
+ try {
5181
+ const count = await collection.countDocuments(query);
5182
+ setCache(cacheKey, count, 15 * 60).then(() => {
5183
+ logger13.info(`Cache set for key: ${cacheKey}`);
5184
+ }).catch((err) => {
5185
+ logger13.error(`Failed to set cache for key: ${cacheKey}`, err);
5186
+ });
5187
+ return count;
5188
+ } catch (error) {
5189
+ throw new InternalServerError11("Failed to count pending invitations.");
5190
+ }
5191
+ }
5158
5192
  return {
5159
5193
  createIndex,
5160
5194
  createTextIndex,
@@ -5163,7 +5197,8 @@ function useVerificationRepoV2() {
5163
5197
  getByVerificationCode,
5164
5198
  getVerificationById,
5165
5199
  getVerifications,
5166
- updateStatusById
5200
+ updateStatusById,
5201
+ countPendingOrgInvites
5167
5202
  };
5168
5203
  }
5169
5204
 
@@ -5241,6 +5276,46 @@ function useVerificationService() {
5241
5276
  throw error;
5242
5277
  }
5243
5278
  }
5279
+ async function createSimpleUserInvite({
5280
+ email,
5281
+ metadata
5282
+ }) {
5283
+ const type = "user-invite";
5284
+ const value = {
5285
+ type,
5286
+ email,
5287
+ metadata,
5288
+ expireAt: new Date(
5289
+ (/* @__PURE__ */ new Date()).getTime() + 72 * 60 * 60 * 1e3
5290
+ ).toISOString(),
5291
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
5292
+ };
5293
+ if (value.metadata?.org) {
5294
+ await getOrgById(value.metadata?.org);
5295
+ }
5296
+ if (value.metadata?.siteId) {
5297
+ await getSiteById(value.metadata?.siteId);
5298
+ }
5299
+ const res = await add(value);
5300
+ const dir = __dirname;
5301
+ const filePath = getDirectory(dir, "./public/handlebars/user-invite");
5302
+ const link = `${APP_MAIN}/verify/invitation/${res}`;
5303
+ const emailContent = compileHandlebar({
5304
+ context: {
5305
+ email,
5306
+ validity: VERIFICATION_USER_INVITE_DURATION,
5307
+ link
5308
+ },
5309
+ filePath
5310
+ });
5311
+ mailer.sendMail({
5312
+ to: email,
5313
+ subject: "User Invite",
5314
+ html: emailContent,
5315
+ sender: "iService365"
5316
+ });
5317
+ return res;
5318
+ }
5244
5319
  const {
5245
5320
  add: _add,
5246
5321
  updateVerificationStatusById: _updateVerificationStatusById,
@@ -5534,7 +5609,8 @@ function useVerificationService() {
5534
5609
  cancelUserInvitation,
5535
5610
  updateStatusById,
5536
5611
  signUp,
5537
- checkExpiredInvitation
5612
+ checkExpiredInvitation,
5613
+ createSimpleUserInvite
5538
5614
  };
5539
5615
  }
5540
5616
 
@@ -6780,7 +6856,16 @@ function useUserController() {
6780
6856
  async function updateUserFieldById(req, res, next) {
6781
6857
  const validation = Joi13.object({
6782
6858
  _id: Joi13.string().hex().required(),
6783
- field: Joi13.string().valid("name", "email", "contact", "nric", "dateOfBirth", "profile", "gender", "defaultOrg").required(),
6859
+ field: Joi13.string().valid(
6860
+ "name",
6861
+ "email",
6862
+ "contact",
6863
+ "nric",
6864
+ "dateOfBirth",
6865
+ "profile",
6866
+ "gender",
6867
+ "defaultOrg"
6868
+ ).required(),
6784
6869
  value: Joi13.when("field", {
6785
6870
  switch: [
6786
6871
  { is: "email", then: Joi13.string().email().required() },
@@ -7384,6 +7469,7 @@ import Joi16 from "joi";
7384
7469
  function useVerificationController() {
7385
7470
  const {
7386
7471
  createUserInvite: _createUserInvite,
7472
+ createSimpleUserInvite: _createSimpleUserInvite,
7387
7473
  createServiceProviderInvite: _createServiceProviderInvite,
7388
7474
  createForgetPassword: _createForgetPassword,
7389
7475
  verify: _verify,
@@ -7434,6 +7520,58 @@ function useVerificationController() {
7434
7520
  return;
7435
7521
  }
7436
7522
  }
7523
+ async function createSimpleUserInvite(req, res, next) {
7524
+ const payload = { ...req.body };
7525
+ const validation = Joi16.object({
7526
+ email: Joi16.string().email().required(),
7527
+ app: Joi16.string().optional().allow("", null),
7528
+ role: Joi16.string().hex().optional().allow("", null),
7529
+ name: Joi16.string().optional().allow("", null),
7530
+ org: Joi16.string().hex().optional().allow("", null),
7531
+ siteId: Joi16.string().hex().optional().allow("", null),
7532
+ siteName: Joi16.string().optional().allow("", null)
7533
+ });
7534
+ const { error } = validation.validate(payload);
7535
+ if (error) {
7536
+ logger22.log({
7537
+ level: "error",
7538
+ message: `${error.message}`
7539
+ });
7540
+ next(new BadRequestError31(error.message));
7541
+ return;
7542
+ }
7543
+ const email = req.body.email ?? "";
7544
+ const app = req.body.app ?? "";
7545
+ const role = req.body.role ?? "";
7546
+ const name = req.body.name ?? "";
7547
+ const org = req.body.org ?? "";
7548
+ const siteId = req.body.siteId ?? "";
7549
+ const siteName = req.body.siteName ?? "";
7550
+ try {
7551
+ await _createSimpleUserInvite({
7552
+ email,
7553
+ metadata: {
7554
+ app,
7555
+ role,
7556
+ name,
7557
+ org,
7558
+ siteId,
7559
+ siteName
7560
+ }
7561
+ });
7562
+ res.status(201).json({
7563
+ message: "Successfully invited user."
7564
+ });
7565
+ return;
7566
+ } catch (error2) {
7567
+ logger22.log({
7568
+ level: "error",
7569
+ message: `${error2.message}`
7570
+ });
7571
+ next(error2);
7572
+ return;
7573
+ }
7574
+ }
7437
7575
  async function createServiceProviderInvite(req, res, next) {
7438
7576
  const payload = req.body;
7439
7577
  const validation = Joi16.object({
@@ -7575,7 +7713,8 @@ function useVerificationController() {
7575
7713
  createServiceProviderInvite,
7576
7714
  createForgetPassword,
7577
7715
  verify,
7578
- cancelUserInvitation
7716
+ cancelUserInvitation,
7717
+ createSimpleUserInvite
7579
7718
  };
7580
7719
  }
7581
7720
 
@@ -19545,7 +19684,7 @@ function useVehicleController() {
19545
19684
  next(new BadRequestError84("Spreadsheet file is required."));
19546
19685
  return;
19547
19686
  }
19548
- const { originalname, path: path5 } = req.file;
19687
+ const { originalname, path: path4 } = req.file;
19549
19688
  const lowerName = originalname.toLowerCase();
19550
19689
  const rowSchema = Joi46.object({
19551
19690
  fullName: Joi46.string().trim().required(),
@@ -19584,7 +19723,7 @@ function useVehicleController() {
19584
19723
  let rows = [];
19585
19724
  if (lowerName.endsWith(".xlsx") || lowerName.endsWith(".xls")) {
19586
19725
  const workbook = new ExcelJS.Workbook();
19587
- await workbook.xlsx.readFile(path5);
19726
+ await workbook.xlsx.readFile(path4);
19588
19727
  const worksheet = workbook.worksheets[0];
19589
19728
  if (!worksheet) {
19590
19729
  next(
@@ -19610,7 +19749,7 @@ function useVehicleController() {
19610
19749
  } else if (lowerName.endsWith(".csv")) {
19611
19750
  rows = await new Promise((resolve, reject) => {
19612
19751
  const parsed = [];
19613
- fs.createReadStream(path5).pipe(csv()).on("data", (row) => parsed.push(row)).on("end", () => resolve(parsed)).on("error", reject);
19752
+ fs.createReadStream(path4).pipe(csv()).on("data", (row) => parsed.push(row)).on("end", () => resolve(parsed)).on("error", reject);
19614
19753
  });
19615
19754
  } else {
19616
19755
  next(
@@ -19649,7 +19788,7 @@ function useVehicleController() {
19649
19788
  validationErrors: invalidRows,
19650
19789
  data
19651
19790
  });
19652
- fs.unlink(path5, () => {
19791
+ fs.unlink(path4, () => {
19653
19792
  });
19654
19793
  } catch (error) {
19655
19794
  logger65.log({ level: "error", message: error.message });
@@ -24102,7 +24241,6 @@ import {
24102
24241
  compileHandlebar as compileHandlebar3,
24103
24242
  getDirectory as getDirectory3
24104
24243
  } from "@7365admin1/node-server-utils";
24105
- import path2 from "path";
24106
24244
  function usePersonService() {
24107
24245
  const MailerConfig = {
24108
24246
  host: MAILER_TRANSPORT_HOST,
@@ -24317,13 +24455,8 @@ function usePersonService() {
24317
24455
  value.status = "active";
24318
24456
  }
24319
24457
  await _reviewResidentPerson(id, value, session);
24320
- const logoPath = path2.join(
24321
- __dirname,
24322
- "public",
24323
- "images",
24324
- "seven-365.svg"
24325
- );
24326
- const statusIconPath = path2.join(__dirname, "public", "icons");
24458
+ const logoPath = `${STORAGE_API}/seven-365.svg`;
24459
+ const statusIconPath = STORAGE_API;
24327
24460
  let title = "";
24328
24461
  let message2 = "";
24329
24462
  let hideLogin = true;
@@ -31929,9 +32062,8 @@ function useEventManagementController() {
31929
32062
  }
31930
32063
  }
31931
32064
  async function updateEventManagementById(req, res, next) {
31932
- const _id = req.params.id;
31933
- const payload = { _id, ...req.body };
31934
- const { error } = schemaUpdateEventManagement.validate(payload, {
32065
+ const payload = { _id: req.params.id, ...req.body };
32066
+ const { error, value } = schemaUpdateEventManagement.validate(payload, {
31935
32067
  abortEarly: false
31936
32068
  });
31937
32069
  if (error) {
@@ -31940,8 +32072,9 @@ function useEventManagementController() {
31940
32072
  next(new BadRequestError137(messages));
31941
32073
  return;
31942
32074
  }
32075
+ const { _id, ...rest } = value;
31943
32076
  try {
31944
- const result = await _updateEventManagementById(_id, req.body);
32077
+ const result = await _updateEventManagementById(_id, rest);
31945
32078
  res.status(200).json({ message: result });
31946
32079
  return;
31947
32080
  } catch (error2) {
@@ -33286,7 +33419,7 @@ import { ObjectId as ObjectId90 } from "mongodb";
33286
33419
 
33287
33420
  // src/utils/access-management.ts
33288
33421
  import fs2 from "fs";
33289
- import path3 from "path";
33422
+ import path2 from "path";
33290
33423
  import axios from "axios";
33291
33424
  import { parseStringPromise } from "xml2js";
33292
33425
  import crypto from "crypto";
@@ -33316,7 +33449,7 @@ var minifyXml = (xml) => {
33316
33449
  };
33317
33450
  var readTemplate = (name, params) => {
33318
33451
  const template = fs2.readFileSync(
33319
- path3.join(__dirname, `../dist/public/xml-templates/${name}.xml`),
33452
+ path2.join(__dirname, `../dist/public/xml-templates/${name}.xml`),
33320
33453
  "utf-8"
33321
33454
  );
33322
33455
  if (!params)
@@ -33447,9 +33580,9 @@ import { parseStringPromise as parseStringPromise2 } from "xml2js";
33447
33580
  // src/utils/rsa-encryption.ts
33448
33581
  import * as crypto2 from "crypto";
33449
33582
  import fs3 from "fs";
33450
- import path4 from "path";
33451
- var pub = path4.resolve(process.cwd(), "./src/public/rsa-keys/new_rsa_512_pub.pem");
33452
- var priv = path4.resolve(process.cwd(), "./src/public/rsa-keys/new_rsa_512_priv.pem");
33583
+ import path3 from "path";
33584
+ var pub = path3.resolve(process.cwd(), "./src/public/rsa-keys/new_rsa_512_pub.pem");
33585
+ var priv = path3.resolve(process.cwd(), "./src/public/rsa-keys/new_rsa_512_priv.pem");
33453
33586
  var EncryptionCredentials = class {
33454
33587
  };
33455
33588
  EncryptionCredentials.RAW_PUBLIC_KEY = fs3.readFileSync(pub, "utf8");
@@ -44659,14 +44792,15 @@ async function hrmLabsAuthentication({
44659
44792
  showPassword: false
44660
44793
  },
44661
44794
  {
44662
- headers: { "Content-Type": "application/json" }
44795
+ headers: { "Content-Type": "application/json" },
44796
+ validateStatus: () => true
44663
44797
  }
44664
44798
  );
44665
44799
  if (res.data?.success && res.data.data?.token) {
44666
44800
  return res.data.data.token;
44667
44801
  }
44668
44802
  throw new Error(
44669
- "HRMLabs Authentication failed. Please check your credentials."
44803
+ res.status === 401 || res.status === 403 ? "HRMLabs Authentication failed. Please check your credentials." : `HRMLabs Authentication failed with status ${res.status}.`
44670
44804
  );
44671
44805
  }
44672
44806
  async function fetchAttendanceData({
@@ -46890,7 +47024,7 @@ function useHrmLabsAttendanceSrvc() {
46890
47024
  } catch (error) {
46891
47025
  logger168.error(error.message || error);
46892
47026
  console.log("Error fetching attendance data:", error);
46893
- throw new Error(error?.message || "Internal Server Error!");
47027
+ return { success: false, message: error?.message || "Internal Server Error!", items: [], pages: 0, pageRange: "0-0 of 0", count: {} };
46894
47028
  }
46895
47029
  }
46896
47030
  async function getAttendanceDataCount(payload) {
@@ -47004,7 +47138,7 @@ function useHrmLabsAttendanceSrvc() {
47004
47138
  } catch (error) {
47005
47139
  logger168.error(error.message || error);
47006
47140
  console.log("Error fetching attendance data count:", error);
47007
- throw new Error(error?.message || "Internal Server Error!");
47141
+ return { success: false, message: error?.message || "Internal Server Error!", totalCount: null };
47008
47142
  }
47009
47143
  }
47010
47144
  async function getAllAttendance(payload) {
@@ -47176,7 +47310,7 @@ function useHrmLabsAttendanceSrvc() {
47176
47310
  } catch (error) {
47177
47311
  logger168.error(error.message || error);
47178
47312
  console.log("Error fetching attendance data:", error);
47179
- throw new Error(error?.message || "Internal Server Error!");
47313
+ return { success: false, message: error?.message || "Internal Server Error!", items: [], count: {}, countPerJobTitle: {}, totalCount: null, countPerStatus: {} };
47180
47314
  }
47181
47315
  }
47182
47316
  async function getChartAttendanceData(payload) {
@@ -47283,7 +47417,7 @@ function useHrmLabsAttendanceSrvc() {
47283
47417
  } catch (error) {
47284
47418
  logger168.error(error.message || error);
47285
47419
  console.log("Error fetching attendance data:", error);
47286
- throw new Error(error?.message || "Internal Server Error!");
47420
+ return { success: false, message: error?.message || "Internal Server Error!", chartCount: null };
47287
47421
  }
47288
47422
  }
47289
47423
  return {
@@ -48941,7 +49075,8 @@ function useVerificationServiceV2() {
48941
49075
  add: _add,
48942
49076
  updateVerificationStatusById: _updateVerificationStatusById,
48943
49077
  getByVerificationCode: _getByVerificationCode,
48944
- updateStatusById: _updateStatusById
49078
+ updateStatusById: _updateStatusById,
49079
+ countPendingOrgInvites: _countPendingOrgInvites
48945
49080
  } = useVerificationRepoV2();
48946
49081
  const {
48947
49082
  getUserByEmailStatus: _getUserByEmailStatus,
@@ -48949,6 +49084,8 @@ function useVerificationServiceV2() {
48949
49084
  } = useUserRepo();
48950
49085
  const { getById: getOrgById, getByEmail: _getByEmail } = useOrgRepo();
48951
49086
  const { getSiteById } = useSiteRepo();
49087
+ const { getByOrgId: _getSubscriptionByOrgId } = useSubscriptionRepo();
49088
+ const { countByOrg: _countMemberByOrg } = useMemberRepo();
48952
49089
  function errorByType(type, status) {
48953
49090
  if ((type === "user-invite" /* USER_INVITE */ || type === "member-invite" /* MEMBER_INVITE */ || type === "service-provider-invite" /* SERVICE_PROVIDER_INVITE */ || type === "service-provider-create-org" /* SERVICE_PROVIDER_CREATE_ORG */) && status === "expired" /* EXPIRED */) {
48954
49091
  throw new BadRequestError199(
@@ -49212,6 +49349,30 @@ function useVerificationServiceV2() {
49212
49349
  throw error2;
49213
49350
  }
49214
49351
  }
49352
+ async function createOrganizationInvite({
49353
+ email,
49354
+ metadata
49355
+ }) {
49356
+ const orgId = metadata.org?.toString() ?? "";
49357
+ if (!orgId) {
49358
+ throw new BadRequestError199("Organization is required.");
49359
+ }
49360
+ await getOrgById(orgId);
49361
+ const [subscription, memberCount, pendingInviteCount] = await Promise.all([
49362
+ _getSubscriptionByOrgId(orgId),
49363
+ _countMemberByOrg(orgId),
49364
+ _countPendingOrgInvites(orgId)
49365
+ ]);
49366
+ const maxSeats = subscription?.maxSeats ?? 0;
49367
+ if (!maxSeats) {
49368
+ throw new BadRequestError199("No seats configured for organization.");
49369
+ }
49370
+ const usedSeats = memberCount + pendingInviteCount;
49371
+ if (usedSeats >= maxSeats) {
49372
+ throw new BadRequestError199("No available seats for new invitation.");
49373
+ }
49374
+ return createUserInvite({ email, metadata });
49375
+ }
49215
49376
  async function createForgetPassword(email) {
49216
49377
  const value = {
49217
49378
  type: "forget-password" /* FORGET_PASSWORD */,
@@ -49262,6 +49423,7 @@ function useVerificationServiceV2() {
49262
49423
  signUp,
49263
49424
  verify,
49264
49425
  createUserInvite,
49426
+ createOrganizationInvite,
49265
49427
  createServiceProviderInvite,
49266
49428
  createForgetPassword,
49267
49429
  cancelUserInvitation
@@ -49275,6 +49437,7 @@ function useVerificationControllerV2() {
49275
49437
  const {
49276
49438
  verify: _verify,
49277
49439
  createUserInvite: _createUserInvite,
49440
+ createOrganizationInvite: _createOrganizationInvite,
49278
49441
  createServiceProviderInvite: _createServiceProviderInvite,
49279
49442
  createForgetPassword: _createForgetPassword,
49280
49443
  cancelUserInvitation: _cancelUserInvitation
@@ -49371,6 +49534,44 @@ function useVerificationControllerV2() {
49371
49534
  return;
49372
49535
  }
49373
49536
  }
49537
+ async function createOrganizationInvite(req, res, next) {
49538
+ const schema2 = Joi127.object({
49539
+ email: Joi127.string().email().lowercase().required(),
49540
+ role: Joi127.string().hex().length(24).required(),
49541
+ org: Joi127.string().hex().length(24).required(),
49542
+ app: Joi127.string().optional().allow("", null).default("organization"),
49543
+ name: Joi127.string().optional().allow("", null),
49544
+ siteId: Joi127.string().hex().length(24).optional().allow("", null),
49545
+ siteName: Joi127.string().optional().allow("", null)
49546
+ });
49547
+ const { error, value } = schema2.validate(req.body, { abortEarly: false });
49548
+ if (error) {
49549
+ const messages = error.details.map((d) => d.message).join(", ");
49550
+ logger178.log({ level: "error", message: messages });
49551
+ next(new BadRequestError200(messages));
49552
+ return;
49553
+ }
49554
+ try {
49555
+ const { email, app, role, name, org, siteId, siteName } = value;
49556
+ await _createOrganizationInvite({
49557
+ email,
49558
+ metadata: {
49559
+ app,
49560
+ role,
49561
+ name,
49562
+ org,
49563
+ siteId,
49564
+ siteName
49565
+ }
49566
+ });
49567
+ res.status(201).json({ message: "Successfully invited user." });
49568
+ return;
49569
+ } catch (error2) {
49570
+ logger178.log({ level: "error", message: `${error2.message}` });
49571
+ next(error2);
49572
+ return;
49573
+ }
49574
+ }
49374
49575
  async function createForgetPassword(req, res, next) {
49375
49576
  const schema2 = Joi127.object({
49376
49577
  email: Joi127.string().email().lowercase().required()
@@ -49456,6 +49657,7 @@ function useVerificationControllerV2() {
49456
49657
  return {
49457
49658
  verify,
49458
49659
  createUserInvite,
49660
+ createOrganizationInvite,
49459
49661
  createServiceProviderInvite,
49460
49662
  createForgetPassword,
49461
49663
  getVerifications,