@internetderdinge/api 1.224.2 → 1.229.1

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 (169) hide show
  1. package/dist/src/accounts/accounts.controller.js +89 -0
  2. package/dist/src/accounts/accounts.route.js +101 -0
  3. package/dist/src/accounts/accounts.schemas.js +12 -0
  4. package/dist/src/accounts/accounts.service.js +65 -0
  5. package/dist/src/accounts/accounts.validation.js +99 -0
  6. package/dist/src/accounts/auth0.service.js +188 -0
  7. package/dist/src/config/config.js +48 -0
  8. package/dist/src/config/logger.js +27 -0
  9. package/dist/src/config/morgan.js +16 -0
  10. package/dist/src/config/passport.cjs +28 -0
  11. package/dist/src/config/roles.js +11 -0
  12. package/dist/src/config/tokens.cjs +10 -0
  13. package/dist/src/devices/devices.controller.js +172 -0
  14. package/dist/src/devices/devices.model.js +94 -0
  15. package/dist/src/devices/devices.route.js +153 -0
  16. package/dist/src/devices/devices.schemas.js +84 -0
  17. package/dist/src/devices/devices.service.js +198 -0
  18. package/dist/src/devices/devices.types.js +1 -0
  19. package/dist/src/devices/devices.validation.js +257 -0
  20. package/dist/src/devicesNotifications/devicesNotifications.controller.js +69 -0
  21. package/dist/src/devicesNotifications/devicesNotifications.model.js +39 -0
  22. package/dist/src/devicesNotifications/devicesNotifications.route.js +124 -0
  23. package/dist/src/devicesNotifications/devicesNotifications.schemas.js +10 -0
  24. package/dist/src/devicesNotifications/devicesNotifications.service.js +181 -0
  25. package/dist/src/devicesNotifications/devicesNotifications.validation.js +46 -0
  26. package/dist/src/email/email.service.js +580 -0
  27. package/dist/src/files/upload.service.js +124 -0
  28. package/dist/src/i18n/i18n.js +38 -0
  29. package/dist/src/i18n/saveMissingLocalJsonBackend.js +53 -0
  30. package/dist/src/i18n/types.js +1 -0
  31. package/dist/src/index.js +48 -0
  32. package/dist/src/iotdevice/iotdevice.controller.js +96 -0
  33. package/dist/src/iotdevice/iotdevice.model.js +17 -0
  34. package/dist/src/iotdevice/iotdevice.route.js +143 -0
  35. package/dist/src/iotdevice/iotdevice.schemas.js +60 -0
  36. package/dist/src/iotdevice/iotdevice.service.js +579 -0
  37. package/dist/src/iotdevice/iotdevice.types.js +1 -0
  38. package/dist/src/iotdevice/iotdevice.validation.js +54 -0
  39. package/dist/src/middlewares/auth.js +75 -0
  40. package/dist/src/middlewares/checkJwt.cjs +17 -0
  41. package/dist/src/middlewares/error.js +36 -0
  42. package/dist/src/middlewares/mongooseValidations/ensureSameOrganization.js +13 -0
  43. package/dist/src/middlewares/rateLimiter.js +7 -0
  44. package/dist/src/middlewares/validate.js +18 -0
  45. package/dist/src/middlewares/validateAction.js +35 -0
  46. package/dist/src/middlewares/validateAdmin.js +18 -0
  47. package/dist/src/middlewares/validateAi.js +16 -0
  48. package/dist/src/middlewares/validateCurrentAuthUser.js +17 -0
  49. package/dist/src/middlewares/validateCurrentUser.js +20 -0
  50. package/dist/src/middlewares/validateDevice.js +98 -0
  51. package/dist/src/middlewares/validateDeviceUserOrganization.js +26 -0
  52. package/dist/src/middlewares/validateOrganization.js +63 -0
  53. package/dist/src/middlewares/validateQuerySearchUserAndOrganization.js +44 -0
  54. package/dist/src/middlewares/validateTokens.js +23 -0
  55. package/dist/src/middlewares/validateUser.js +38 -0
  56. package/dist/src/middlewares/validateZod.js +33 -0
  57. package/dist/src/models/plugins/index.js +4 -0
  58. package/dist/src/models/plugins/paginate.plugin.js +117 -0
  59. package/dist/src/models/plugins/paginateNew.plugin.js +185 -0
  60. package/dist/src/models/plugins/simplePopulate.js +16 -0
  61. package/dist/src/models/plugins/toJSON.plugin.js +35 -0
  62. package/dist/src/organizations/organizations.controller.js +64 -0
  63. package/dist/src/organizations/organizations.model.js +41 -0
  64. package/dist/src/organizations/organizations.route.js +98 -0
  65. package/dist/src/organizations/organizations.schemas.js +7 -0
  66. package/dist/src/organizations/organizations.service.js +59 -0
  67. package/dist/src/organizations/organizations.validation.js +62 -0
  68. package/dist/src/pdf/pdf.controller.js +24 -0
  69. package/dist/src/pdf/pdf.route.js +22 -0
  70. package/dist/src/pdf/pdf.schemas.js +6 -0
  71. package/dist/src/pdf/pdf.service.js +65 -0
  72. package/dist/src/pdf/pdf.validation.js +27 -0
  73. package/dist/src/tokens/tokens.controller.js +60 -0
  74. package/dist/src/tokens/tokens.model.js +18 -0
  75. package/dist/src/tokens/tokens.route.js +52 -0
  76. package/dist/src/tokens/tokens.schemas.js +14 -0
  77. package/dist/src/tokens/tokens.service.js +30 -0
  78. package/dist/src/tokens/tokens.validation.js +9 -0
  79. package/dist/src/types/routeSpec.js +1 -0
  80. package/dist/src/users/users.controller.js +147 -0
  81. package/dist/src/users/users.model.js +50 -0
  82. package/dist/src/users/users.route.js +137 -0
  83. package/dist/src/users/users.schemas.js +69 -0
  84. package/dist/src/users/users.service.js +295 -0
  85. package/dist/src/users/users.types.js +1 -0
  86. package/dist/src/users/users.validation.js +144 -0
  87. package/dist/src/utils/ApiError.js +16 -0
  88. package/dist/src/utils/buildRouterAndDocs.js +72 -0
  89. package/dist/src/utils/catchAsync.js +4 -0
  90. package/dist/src/utils/comparePapers.service.js +32 -0
  91. package/dist/src/utils/deviceUtils.js +63 -0
  92. package/dist/src/utils/filterOptions.js +24 -0
  93. package/dist/src/utils/medicationName.js +10 -0
  94. package/dist/src/utils/pick.js +16 -0
  95. package/dist/src/utils/registerOpenApi.js +28 -0
  96. package/dist/src/utils/urlUtils.js +15 -0
  97. package/dist/src/utils/userName.js +22 -0
  98. package/dist/src/utils/zValidations.js +124 -0
  99. package/dist/src/validations/auth.validation.cjs +53 -0
  100. package/dist/src/validations/custom.validation.js +19 -0
  101. package/dist/src/validations/index.cjs +3 -0
  102. package/package.json +15 -6
  103. package/scripts/release-and-sync-paperless.mjs +135 -0
  104. package/scripts/release-version.mjs +145 -0
  105. package/src/accounts/accounts.controller.ts +1 -0
  106. package/src/accounts/accounts.service.ts +1 -0
  107. package/src/accounts/accounts.validation.ts +6 -3
  108. package/src/accounts/auth0.service.ts +55 -28
  109. package/src/config/config.ts +6 -0
  110. package/src/config/logger.ts +15 -9
  111. package/src/devices/devices.controller.ts +7 -1
  112. package/src/devices/devices.model.ts +4 -1
  113. package/src/devices/devices.schemas.ts +10 -8
  114. package/src/devices/devices.service.ts +2 -1
  115. package/src/devices/devices.types.ts +1 -0
  116. package/src/devices/devices.validation.ts +85 -23
  117. package/src/devicesNotifications/devicesNotifications.controller.ts +57 -28
  118. package/src/devicesNotifications/devicesNotifications.model.ts +20 -12
  119. package/src/devicesNotifications/devicesNotifications.service.ts +35 -17
  120. package/src/files/upload.service.ts +52 -28
  121. package/src/i18n/i18n.ts +2 -2
  122. package/src/i18n/types.ts +1 -0
  123. package/src/index.ts +47 -0
  124. package/src/iotdevice/iotdevice.controller.ts +1 -0
  125. package/src/iotdevice/iotdevice.model.ts +6 -3
  126. package/src/iotdevice/iotdevice.route.ts +85 -76
  127. package/src/iotdevice/iotdevice.service.ts +5 -4
  128. package/src/iotdevice/iotdevice.types.ts +6 -0
  129. package/src/middlewares/auth.ts +2 -8
  130. package/src/middlewares/error.ts +26 -12
  131. package/src/middlewares/mongooseValidations/ensureSameOrganization.ts +4 -3
  132. package/src/middlewares/validateAi.ts +17 -9
  133. package/src/middlewares/validateDevice.ts +1 -0
  134. package/src/middlewares/validateDeviceUserOrganization.ts +1 -0
  135. package/src/middlewares/validateOrganization.ts +1 -1
  136. package/src/middlewares/validateQuerySearchUserAndOrganization.ts +1 -0
  137. package/src/middlewares/validateTokens.ts +2 -1
  138. package/src/middlewares/validateUser.ts +1 -0
  139. package/src/models/plugins/index.ts +5 -4
  140. package/src/models/plugins/paginate.plugin.ts +26 -16
  141. package/src/models/plugins/paginateNew.plugin.ts +33 -21
  142. package/src/models/plugins/simplePopulate.ts +8 -3
  143. package/src/models/plugins/toJSON.plugin.ts +12 -5
  144. package/src/organizations/organizations.controller.ts +1 -2
  145. package/src/organizations/organizations.model.ts +4 -4
  146. package/src/organizations/organizations.route.ts +1 -1
  147. package/src/organizations/organizations.service.ts +15 -6
  148. package/src/pdf/pdf.controller.ts +18 -1
  149. package/src/pdf/pdf.service.ts +25 -16
  150. package/src/tokens/tokens.controller.ts +6 -8
  151. package/src/tokens/tokens.model.ts +3 -1
  152. package/src/tokens/tokens.service.ts +3 -2
  153. package/src/types/express.d.ts +17 -0
  154. package/src/types/mongoose.d.ts +22 -0
  155. package/src/users/users.controller.ts +8 -9
  156. package/src/users/users.model.ts +6 -5
  157. package/src/users/users.route.ts +0 -1
  158. package/src/users/users.service.ts +16 -0
  159. package/src/users/users.types.ts +1 -0
  160. package/src/users/users.validation.ts +6 -2
  161. package/src/utils/ApiError.ts +8 -1
  162. package/src/utils/buildRouterAndDocs.ts +56 -21
  163. package/src/utils/catchAsync.ts +27 -3
  164. package/src/utils/deviceUtils.ts +109 -0
  165. package/src/utils/medicationName.ts +5 -4
  166. package/src/utils/pick.ts +5 -1
  167. package/src/utils/userName.ts +1 -0
  168. package/src/utils/zValidations.ts +78 -26
  169. package/tsconfig.json +13 -4
@@ -1,7 +1,8 @@
1
+ // @ts-nocheck
1
2
  /* eslint-disable no-param-reassign */
2
- import mongoose from 'mongoose';
3
- import type { Schema, Document, Model, PipelineStage } from 'mongoose';
4
- import type { PaginateOptions, QueryResult } from './types';
3
+ import mongoose from "mongoose";
4
+ import type { Schema, Document, Model, PipelineStage } from "mongoose";
5
+ import type { PaginateOptions, QueryResult } from "./paginate.plugin.js";
5
6
 
6
7
  const paginate = (schema: Schema): void => {
7
8
  /**
@@ -14,19 +15,26 @@ const paginate = (schema: Schema): void => {
14
15
  filter: Record<string, any> = {},
15
16
  options: PaginateOptions = {},
16
17
  plugin?: any,
17
- ): Promise<QueryResult> {
18
+ ): Promise<QueryResult<any>> {
18
19
  // Parse sorting options
19
20
  const sort = options.sortBy
20
- ? options.sortBy.split(',').reduce((acc: Record<string, number>, sortOption: string) => {
21
- const [key, order] = sortOption.split(':');
22
- acc[key] = order === 'desc' ? -1 : 1;
23
- return acc;
24
- }, {})
21
+ ? options.sortBy
22
+ .split(",")
23
+ .reduce((acc: Record<string, number>, sortOption: string) => {
24
+ const [key, order] = sortOption.split(":");
25
+ acc[key] = order === "desc" ? -1 : 1;
26
+ return acc;
27
+ }, {})
25
28
  : { createdAt: -1 };
26
29
 
27
30
  const limit =
28
- options.limit && parseInt(options.limit.toString(), 10) > 0 ? parseInt(options.limit.toString(), 10) : 10000;
29
- const page = options.page && parseInt(options.page.toString(), 10) > 0 ? parseInt(options.page.toString(), 10) : 1;
31
+ options.limit && parseInt(options.limit.toString(), 10) > 0
32
+ ? parseInt(options.limit.toString(), 10)
33
+ : 10000;
34
+ const page =
35
+ options.page && parseInt(options.page.toString(), 10) > 0
36
+ ? parseInt(options.page.toString(), 10)
37
+ : 1;
30
38
  const skip = (page - 1) * limit;
31
39
 
32
40
  // Build aggregation pipeline
@@ -38,7 +46,7 @@ const paginate = (schema: Schema): void => {
38
46
 
39
47
  // Helper function to determine if a path is a virtual field
40
48
  const isVirtualField = (path: string): boolean => {
41
- const rootPath = path.split('.')[0];
49
+ const rootPath = path.split(".")[0];
42
50
  return !!schema.virtuals[rootPath];
43
51
  };
44
52
 
@@ -50,14 +58,16 @@ const paginate = (schema: Schema): void => {
50
58
 
51
59
  for (const key in filterObj) {
52
60
  if (filterObj.hasOwnProperty(key)) {
53
- if (key === '$or' || key === '$and') {
61
+ if (key === "$or" || key === "$and") {
54
62
  const mainArray: Record<string, any>[] = [];
55
63
  const virtualArray: Record<string, any>[] = [];
56
64
 
57
65
  filterObj[key].forEach((item: Record<string, any>) => {
58
- const { main: itemMain, virtual: itemVirtual } = separateFilter(item);
66
+ const { main: itemMain, virtual: itemVirtual } =
67
+ separateFilter(item);
59
68
  if (Object.keys(itemMain).length > 0) mainArray.push(itemMain);
60
- if (Object.keys(itemVirtual).length > 0) virtualArray.push(itemVirtual);
69
+ if (Object.keys(itemVirtual).length > 0)
70
+ virtualArray.push(itemVirtual);
61
71
  });
62
72
 
63
73
  if (mainArray.length > 0) main[key] = mainArray;
@@ -87,8 +97,8 @@ const paginate = (schema: Schema): void => {
87
97
 
88
98
  // Handle virtual fields population
89
99
  if (options.populate) {
90
- options.populate.split(',').forEach((populateOption: string) => {
91
- const paths = populateOption.split('.');
100
+ options.populate.split(",").forEach((populateOption: string) => {
101
+ const paths = populateOption.split(".");
92
102
  const localField = paths[0];
93
103
  const virtual = schema.virtuals[localField];
94
104
  if (!virtual) {
@@ -140,7 +150,9 @@ const paginate = (schema: Schema): void => {
140
150
 
141
151
  // Handle fuzzy search (if applicable)
142
152
  if (this.fuzzySearch && options.fuzzySearch) {
143
- throw new Error('Fuzzy search is not supported with aggregation in this paginate function.');
153
+ throw new Error(
154
+ "Fuzzy search is not supported with aggregation in this paginate function.",
155
+ );
144
156
  }
145
157
 
146
158
  // Add sorting, skipping, and limiting stages
@@ -151,7 +163,7 @@ const paginate = (schema: Schema): void => {
151
163
  // Rename root _id to id
152
164
  pipeline.push({
153
165
  $addFields: {
154
- id: '$_id',
166
+ id: "$_id",
155
167
  },
156
168
  });
157
169
  pipeline.push({
@@ -166,7 +178,7 @@ const paginate = (schema: Schema): void => {
166
178
  $facet: {
167
179
  metadata: [
168
180
  {
169
- $count: 'totalResults',
181
+ $count: "totalResults",
170
182
  },
171
183
  ],
172
184
  data: pipeline,
@@ -174,7 +186,7 @@ const paginate = (schema: Schema): void => {
174
186
  },
175
187
  {
176
188
  $addFields: {
177
- totalResults: { $arrayElemAt: ['$metadata.totalResults', 0] },
189
+ totalResults: { $arrayElemAt: ["$metadata.totalResults", 0] },
178
190
  },
179
191
  },
180
192
  ];
@@ -1,10 +1,15 @@
1
1
  function simplePopulate(populate: string): Record<string, any> {
2
2
  let docsPromise: Record<string, any> = {};
3
- populate.split(',').forEach((populateOption) => {
3
+ populate.split(",").forEach((populateOption) => {
4
4
  docsPromise = populateOption
5
- .split('.')
5
+ .split(".")
6
6
  .reverse()
7
- .reduce((a, b) => ({ path: b, populate: a }));
7
+ .reduce<Record<string, any>>((acc, key) => {
8
+ if (Object.keys(acc).length === 0) {
9
+ return { path: key };
10
+ }
11
+ return { path: key, populate: acc };
12
+ }, {});
8
13
  });
9
14
  return docsPromise;
10
15
  }
@@ -6,9 +6,14 @@
6
6
  * - replaces _id with id
7
7
  */
8
8
 
9
- import type { Schema, Document } from 'mongoose';
10
-
11
- const deleteAtPath = (obj: Record<string, any>, path: string[], index: number): void => {
9
+ // @ts-nocheck
10
+ import type { Schema, Document } from "mongoose";
11
+
12
+ const deleteAtPath = (
13
+ obj: Record<string, any>,
14
+ path: string[],
15
+ index: number,
16
+ ): void => {
12
17
  if (index === path.length - 1) {
13
18
  delete obj[path[index]];
14
19
  return;
@@ -17,7 +22,9 @@ const deleteAtPath = (obj: Record<string, any>, path: string[], index: number):
17
22
  };
18
23
 
19
24
  const toJSON = (schema: Schema, timestamps: boolean = false): void => {
20
- let transform: ((doc: Document, ret: Record<string, any>, options: any) => any) | undefined;
25
+ let transform:
26
+ | ((doc: Document, ret: Record<string, any>, options: any) => any)
27
+ | undefined;
21
28
 
22
29
  if (schema.options.toJSON && schema.options.toJSON.transform) {
23
30
  transform = schema.options.toJSON.transform;
@@ -28,7 +35,7 @@ const toJSON = (schema: Schema, timestamps: boolean = false): void => {
28
35
  transform(doc: Document, ret: Record<string, any>, options: any): any {
29
36
  Object.keys(schema.paths).forEach((path) => {
30
37
  if (schema.paths[path].options && schema.paths[path].options.private) {
31
- deleteAtPath(ret, path.split('.'), 0);
38
+ deleteAtPath(ret, path.split("."), 0);
32
39
  }
33
40
  });
34
41
 
@@ -1,5 +1,4 @@
1
- import express from "express";
2
- const { Request, Response } = express;
1
+ import type { Request, Response } from "express";
3
2
  import httpStatus from "http-status";
4
3
  import pick from "../utils/pick.js";
5
4
  import ApiError from "../utils/ApiError.js";
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  import mongoose, { Schema, Document, Model } from "mongoose";
2
3
  import { toJSON, paginate } from "../models/plugins/index.js";
3
4
 
@@ -54,9 +55,8 @@ organizationSchema.plugin(toJSON);
54
55
  organizationSchema.plugin(paginate);
55
56
 
56
57
  // Define the model
57
- const Organization: Model<IOrganization> = mongoose.model<IOrganization>(
58
- "Organization",
59
- organizationSchema,
60
- );
58
+ const Organization: Model<IOrganization> =
59
+ (mongoose.models.Organization as Model<IOrganization>) ||
60
+ mongoose.model<IOrganization>("Organization", organizationSchema);
61
61
 
62
62
  export default Organization;
@@ -31,7 +31,7 @@ export const organizationsRouteSpecs: RouteSpec[] = [
31
31
  path: "/",
32
32
  validate: [auth("manageUsers")],
33
33
  requestSchema: createOrganizationSchema,
34
- responseSchema: {},
34
+ responseSchema: organizationResponseSchema,
35
35
  handler: createOrganization,
36
36
  summary: "Create a new organization",
37
37
  description: "Creates a new organization with the provided details.",
@@ -1,7 +1,9 @@
1
+ // @ts-nocheck
1
2
  import httpStatus from "http-status";
2
3
  import { ObjectId } from "mongoose";
3
4
  import Organization from "./organizations.model.js";
4
- import type { IOrganization, QueryResult } from "./organizations.model.js";
5
+ import type { IOrganization } from "./organizations.model.js";
6
+ import type { QueryResult } from "../models/plugins/paginate.plugin.js";
5
7
  import ApiError from "../utils/ApiError.js";
6
8
 
7
9
  const createOrganization = async (
@@ -13,17 +15,24 @@ const createOrganization = async (
13
15
 
14
16
  const queryOrganizations = async (
15
17
  filter: Record<string, any>,
16
- options: { sortBy?: string; limit?: number; page?: number },
17
- ): Promise<QueryResult> => {
18
+ options: {
19
+ sortBy?: string;
20
+ limit?: number;
21
+ page?: number;
22
+ populate?: string;
23
+ },
24
+ ): Promise<QueryResult<IOrganization>> => {
18
25
  const organizations = await Organization.paginate(filter, options);
19
26
  return organizations;
20
27
  };
21
28
 
22
29
  const queryOrganizationsByUser = async (
23
- organizationsList: Array<{ organization: ObjectId }>,
24
- ): Promise<QueryResult | false> => {
30
+ organizationsList: Array<{ organization?: ObjectId | null }>,
31
+ ): Promise<QueryResult<IOrganization> | false> => {
25
32
  if (!organizationsList) return false;
26
- const organizationIds = organizationsList.map((e) => e.organization);
33
+ const organizationIds = organizationsList
34
+ .map((e) => e.organization)
35
+ .filter((id): id is ObjectId => Boolean(id));
27
36
  const organizations = await Organization.paginate(
28
37
  {
29
38
  _id: { $in: organizationIds },
@@ -1,14 +1,31 @@
1
1
  import httpStatus from "http-status";
2
2
  import catchAsync from "../utils/catchAsync.js";
3
3
  import pdfService from "./pdf.service.js";
4
+ import ApiError from "../utils/ApiError.js";
4
5
 
5
6
  export const generatePdfFromUrl = catchAsync(async (req, res) => {
6
7
  const fileName = "memo-print";
7
8
 
8
9
  const authHeader = req.headers["authorization"];
10
+ if (!authHeader) {
11
+ throw new ApiError(httpStatus.UNAUTHORIZED, "Missing Authorization header");
12
+ }
13
+
9
14
  const token = authHeader.split(" ")[1];
15
+ if (!token) {
16
+ throw new ApiError(httpStatus.UNAUTHORIZED, "Missing bearer token");
17
+ }
18
+
19
+ const urlPath =
20
+ typeof req.query.urlPath === "string" ? req.query.urlPath : undefined;
21
+ if (!urlPath) {
22
+ throw new ApiError(
23
+ httpStatus.BAD_REQUEST,
24
+ "Missing urlPath query parameter",
25
+ );
26
+ }
10
27
 
11
- const result = await pdfService.generatePdfFromUrl({ ...req.query, token });
28
+ const result = await pdfService.generatePdfFromUrl({ urlPath, token });
12
29
 
13
30
  res.status(httpStatus.CREATED).send({ signed: result });
14
31
  });
@@ -1,7 +1,7 @@
1
- import puppeteer from 'puppeteer';
2
- import { v4 as uuidv4 } from 'uuid';
3
- import AWS from 'aws-sdk';
4
- import path from 'path';
1
+ import puppeteer from "puppeteer";
2
+ import { v4 as uuidv4 } from "uuid";
3
+ import AWS from "aws-sdk";
4
+ import path from "path";
5
5
 
6
6
  // Configure AWS SDK
7
7
  const s3 = new AWS.S3({
@@ -11,13 +11,16 @@ const s3 = new AWS.S3({
11
11
  });
12
12
 
13
13
  // Function to upload a file to S3
14
- const uploadBuffer = async (buffer: Buffer, fileName: string): Promise<string> => {
14
+ const uploadBuffer = async (
15
+ buffer: Buffer,
16
+ fileName: string,
17
+ ): Promise<string> => {
15
18
  const params = {
16
19
  Bucket: process.env.AWS_S3_BUCKET_NAME!,
17
20
  Key: fileName,
18
21
  Body: buffer,
19
- ContentType: 'application/pdf',
20
- ACL: 'private',
22
+ ContentType: "application/pdf",
23
+ ACL: "private",
21
24
  };
22
25
 
23
26
  const data = await s3.upload(params).promise();
@@ -32,7 +35,7 @@ const generateSignedUrl = (fileName: string): string => {
32
35
  Expires: 60 * 60, // URL expiration time in seconds
33
36
  };
34
37
 
35
- return s3.getSignedUrl('getObject', params);
38
+ return s3.getSignedUrl("getObject", params);
36
39
  };
37
40
 
38
41
  interface GeneratePdfOptions {
@@ -40,7 +43,10 @@ interface GeneratePdfOptions {
40
43
  token: string;
41
44
  }
42
45
 
43
- const generatePdfFromUrl = async ({ urlPath, token }: GeneratePdfOptions): Promise<string> => {
46
+ const generatePdfFromUrl = async ({
47
+ urlPath,
48
+ token,
49
+ }: GeneratePdfOptions): Promise<string> => {
44
50
  const domain = process.env.FRONTEND_URL!;
45
51
  const browser = await puppeteer.launch({
46
52
  defaultViewport: {
@@ -49,7 +55,7 @@ const generatePdfFromUrl = async ({ urlPath, token }: GeneratePdfOptions): Promi
49
55
  deviceScaleFactor: 1,
50
56
  },
51
57
  executablePath: process.env.CHROME_BIN,
52
- args: ['--no-sandbox'],
58
+ args: ["--no-sandbox"],
53
59
  });
54
60
 
55
61
  const page = await browser.newPage();
@@ -58,22 +64,25 @@ const generatePdfFromUrl = async ({ urlPath, token }: GeneratePdfOptions): Promi
58
64
 
59
65
  // Set the token in local storage
60
66
  await page.evaluate((token) => {
61
- localStorage.setItem('print-token', token);
67
+ localStorage.setItem("print-token", token);
62
68
  }, token);
63
69
 
64
- await page.goto(domain + urlPath, { waitUntil: 'networkidle2' });
70
+ await page.goto(domain + urlPath, { waitUntil: "networkidle2" });
65
71
 
66
- await page.waitForSelector('.pdf-render-complete');
72
+ await page.waitForSelector(".pdf-render-complete");
67
73
 
68
- const pdf = await page.pdf({ format: 'A4', printBackground: true });
74
+ const pdf = await page.pdf({ format: "A4", printBackground: true });
69
75
 
70
76
  await page.evaluate(() => {
71
- localStorage.setItem('print-token', '');
77
+ localStorage.setItem("print-token", "");
72
78
  });
73
79
 
74
80
  await browser.close();
75
81
 
76
- const fileUrl = await uploadBuffer(pdf, `download-${uuidv4()}.pdf`);
82
+ const fileUrl = await uploadBuffer(
83
+ Buffer.from(pdf),
84
+ `download-${uuidv4()}.pdf`,
85
+ );
77
86
 
78
87
  console.log(`File uploaded successfully. File URL: ${fileUrl}`);
79
88
 
@@ -38,16 +38,15 @@ export const createToken = async (
38
38
 
39
39
  // Get a token by ID
40
40
  export const getToken = async (
41
- req: Request,
41
+ req: Request<{ tokenId: string }>,
42
42
  res: Response,
43
43
  next: NextFunction,
44
44
  ): Promise<void> => {
45
45
  try {
46
46
  const token = await tokensService.getTokenById(req.params.tokenId);
47
47
  if (!token) {
48
- return res
49
- .status(httpStatus.NOT_FOUND)
50
- .send({ message: "Token not found" });
48
+ res.status(httpStatus.NOT_FOUND).send({ message: "Token not found" });
49
+ return;
51
50
  }
52
51
  res.send(token);
53
52
  } catch (error) {
@@ -57,16 +56,15 @@ export const getToken = async (
57
56
 
58
57
  // Delete a token by ID
59
58
  export const deleteToken = async (
60
- req: Request,
59
+ req: Request<{ tokenId: string }>,
61
60
  res: Response,
62
61
  next: NextFunction,
63
62
  ): Promise<void> => {
64
63
  try {
65
64
  const token = await tokensService.deleteTokenById(req.params.tokenId);
66
65
  if (!token) {
67
- return res
68
- .status(httpStatus.NOT_FOUND)
69
- .send({ message: "Token not found" });
66
+ res.status(httpStatus.NOT_FOUND).send({ message: "Token not found" });
67
+ return;
70
68
  }
71
69
  res.status(httpStatus.NO_CONTENT).send();
72
70
  } catch (error) {
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  import mongoose, { Schema, Model } from "mongoose";
2
3
  import crypto from "crypto";
3
4
  import { toJSON, paginate } from "../models/plugins/index.js";
@@ -19,6 +20,7 @@ const tokenSchema: Schema = new mongoose.Schema(
19
20
  tokenSchema.plugin(toJSON, true);
20
21
  tokenSchema.plugin(paginate);
21
22
 
22
- const Token: Model<any> = mongoose.model("Token", tokenSchema);
23
+ const Token: Model<any> =
24
+ (mongoose.models.Token as Model<any>) || mongoose.model("Token", tokenSchema);
23
25
 
24
26
  export default Token;
@@ -1,12 +1,13 @@
1
1
  import crypto from "crypto";
2
2
  import type { Document } from "mongoose";
3
3
  import Token from "./tokens.model.js";
4
+ import type { QueryResult } from "../models/plugins/paginate.plugin.js";
4
5
 
5
6
  export const queryTokens = async (
6
7
  filter: Record<string, any>,
7
8
  options: { sortBy?: string; limit?: number; page?: number },
8
- ): Promise<QueryResult> => {
9
- return Token.paginate(filter, options);
9
+ ): Promise<QueryResult<any>> => {
10
+ return (Token as any).paginate(filter, options);
10
11
  };
11
12
 
12
13
  export const createToken = async (
@@ -0,0 +1,17 @@
1
+ declare global {
2
+ namespace Express {
3
+ interface Request {
4
+ auth?: {
5
+ sub: string;
6
+ id?: string;
7
+ tokenId?: string;
8
+ type?: string;
9
+ [key: string]: any;
10
+ };
11
+ currentUser?: any;
12
+ user?: any;
13
+ }
14
+ }
15
+ }
16
+
17
+ export {};
@@ -0,0 +1,22 @@
1
+ declare module "mongoose" {
2
+ const mongoose: any;
3
+ export default mongoose;
4
+
5
+ export type ObjectId = any;
6
+ export type Document = any;
7
+ export type Model<T = any> = any;
8
+ export type Schema<T = any> = any;
9
+ export type Query<T = any> = any;
10
+ export type FilterQuery<T = any> = any;
11
+ export type PaginateOptions = any;
12
+ export type PaginateModel<T = any> = any;
13
+ export type PipelineStage = any;
14
+
15
+ export const Schema: any;
16
+ export const Types: any;
17
+ export function model<T = any>(...args: any[]): Model<T>;
18
+
19
+ export namespace Types {
20
+ type ObjectId = any;
21
+ }
22
+ }
@@ -18,13 +18,13 @@ export const createUser = catchAsync(
18
18
  async (req: AuthRequest<{}, any, {}>, res: Response) => {
19
19
  const { body } = req;
20
20
  if (body.email) {
21
- const auth0user = await auth0Service.getUserIdByEmail(body.email);
21
+ const auth0users = await auth0Service.getUserIdByEmail(body.email);
22
22
  body.status = "invited";
23
23
  body.inviteCode = crypto.randomBytes(48).toString("base64url");
24
24
 
25
- if (auth0user.data[0]) {
25
+ if (auth0users[0]) {
26
26
  const userFound = await userService.getUserByOwner(
27
- auth0user.data[0].user_id,
27
+ auth0users[0].user_id,
28
28
  body.organization,
29
29
  );
30
30
  if (userFound) {
@@ -101,10 +101,8 @@ export const getCurrentUser = catchAsync(
101
101
  req: AuthRequest<{}, any, { organization?: string }>,
102
102
  res: Response,
103
103
  ) => {
104
- const result = await userService.getUserByOwner(
105
- req.auth.sub,
106
- req.query.organization,
107
- );
104
+ const organization = req.query.organization as string;
105
+ const result = await userService.getUserByOwner(req.auth.sub, organization);
108
106
  res.send(result);
109
107
  },
110
108
  );
@@ -181,9 +179,10 @@ export const getInvite = catchAsync(
181
179
  `User not found token: ${authReq.params.inviteCode}`,
182
180
  );
183
181
  }
182
+ const organizationId = String(user.organization);
184
183
  const already = await userService.getUserByOwner(
185
184
  authReq.auth.sub,
186
- user.organization,
185
+ organizationId,
187
186
  );
188
187
  if (already) {
189
188
  throw new ApiError(httpStatus.CONFLICT, "User already in organization");
@@ -222,7 +221,7 @@ export const organizationRemove = catchAsync(
222
221
  export const cleanup = catchAsync(async (_req: Request, res: Response) => {
223
222
  const all = await userService.queryAllCalendars();
224
223
  const filtered = all.filter((e) => e.organizationData === null);
225
- const ids = filtered.map((e) => e._id);
224
+ const ids = filtered.map((e) => String(e._id));
226
225
  const deleted = await userService.deleteMany(ids);
227
226
  res.send({
228
227
  deleted,
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  import mongoose, { Schema, Document, Model, Types } from "mongoose";
2
3
  import validator from "validator";
3
4
  import { toJSON, paginate } from "../models/plugins/index.js";
@@ -9,9 +10,10 @@ export interface IUser {
9
10
  timezone: string;
10
11
  owner?: string;
11
12
  organization?: Types.ObjectId;
13
+ organizationData?: any;
12
14
  inviteCode?: string;
13
15
  email?: string;
14
- role: keyof typeof roles;
16
+ role: (typeof roles)[number];
15
17
  category: string;
16
18
  status?: string;
17
19
  meta?: Record<string, any>;
@@ -83,7 +85,6 @@ userSchema.methods.isPasswordMatch = async function (
83
85
  return false;
84
86
  };
85
87
 
86
- export const User = mongoose.model<IUserDocument, IUserModel>(
87
- "User",
88
- userSchema,
89
- );
88
+ export const User =
89
+ (mongoose.models.User as IUserModel) ||
90
+ mongoose.model<IUserDocument, IUserModel>("User", userSchema);
@@ -108,7 +108,6 @@ export const userRouteSpecs: RouteSpec[] = [
108
108
  privateDocs: true,
109
109
  summary: "Get invite details by code",
110
110
  description: "Retrieves information about a pending invite using its code.",
111
- privateDocs: true,
112
111
  },
113
112
  {
114
113
  method: "post",
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  import httpStatus from "http-status";
2
3
  import type { FilterQuery, PaginateOptions } from "mongoose";
3
4
  import { User } from "./users.model.js";
@@ -315,6 +316,18 @@ export const updateInvite = async (params: {
315
316
  return user;
316
317
  };
317
318
 
319
+ /**
320
+ * Update a user's organization membership (placeholder for legacy callers)
321
+ */
322
+ export const organizationUpdate = async (
323
+ _body: any,
324
+ ): Promise<IUserDocument> => {
325
+ throw new ApiError(
326
+ httpStatus.NOT_IMPLEMENTED,
327
+ "organizationUpdate not implemented",
328
+ );
329
+ };
330
+
318
331
  /**
319
332
  * Remove a user from an organization
320
333
  */
@@ -383,6 +396,7 @@ export default {
383
396
  organizationInvite,
384
397
  getInvite,
385
398
  updateInvite,
399
+ organizationUpdate,
386
400
  organizationRemove,
387
401
  queryUsers,
388
402
  queryAllCalendars,
@@ -391,3 +405,5 @@ export default {
391
405
  populateAuth0User,
392
406
  populateAuth0Users,
393
407
  };
408
+
409
+ export type UserService = typeof import("./users.service");
@@ -0,0 +1 @@
1
+ export type User = any;
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  import { z } from "zod";
2
3
  import { extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi";
3
4
  import { objectId, password } from "../validations/custom.validation.js";
@@ -5,6 +6,7 @@ import {
5
6
  zPagination,
6
7
  zGet,
7
8
  zObjectId,
9
+ zObjectIdFor,
8
10
  zPatchBody,
9
11
  zUpdate,
10
12
  zDelete,
@@ -49,9 +51,11 @@ export const createCurrentUserSchema = createUserSchema;
49
51
  export const queryUsersSchema = {
50
52
  ...zPagination,
51
53
  query: zPagination.query.extend({
52
- organization: zObjectId.optional().openapi({
54
+ organization: zObjectIdFor("organization").openapi({
53
55
  description: "Filter users by organization ObjectId",
54
- example: "60c72b2f9b1e8d001c8e4f3a",
56
+ example:
57
+ process.env.SCHEMA_EXAMPLE_ORGANIZATION_ID ||
58
+ "60c72b2f9b1e8d001c8e4f3a",
55
59
  }),
56
60
  }),
57
61
  };