@internetderdinge/api 1.229.0 → 1.229.2

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 (171) 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 +17 -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 +67 -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 +143 -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/dist/tsconfig.tsbuildinfo +1 -0
  103. package/package.json +97 -80
  104. package/scripts/release-and-sync-paperless.mjs +137 -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 +8 -5
  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 +11 -9
  114. package/src/devices/devices.service.ts +1 -0
  115. package/src/devices/devices.types.ts +1 -0
  116. package/src/devices/devices.validation.ts +93 -32
  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 +1 -1
  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 +4 -3
  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/middlewares/validateZod.ts +5 -5
  140. package/src/models/plugins/index.ts +5 -4
  141. package/src/models/plugins/paginate.plugin.ts +26 -16
  142. package/src/models/plugins/paginateNew.plugin.ts +33 -21
  143. package/src/models/plugins/simplePopulate.ts +8 -3
  144. package/src/models/plugins/toJSON.plugin.ts +12 -5
  145. package/src/organizations/organizations.controller.ts +1 -2
  146. package/src/organizations/organizations.model.ts +4 -4
  147. package/src/organizations/organizations.route.ts +1 -1
  148. package/src/organizations/organizations.service.ts +15 -6
  149. package/src/organizations/organizations.validation.ts +1 -1
  150. package/src/pdf/pdf.controller.ts +18 -1
  151. package/src/pdf/pdf.service.ts +25 -16
  152. package/src/tokens/tokens.controller.ts +6 -8
  153. package/src/tokens/tokens.model.ts +3 -1
  154. package/src/tokens/tokens.service.ts +3 -2
  155. package/src/types/express.d.ts +17 -0
  156. package/src/types/mongoose.d.ts +22 -0
  157. package/src/users/users.controller.ts +8 -9
  158. package/src/users/users.model.ts +6 -5
  159. package/src/users/users.route.ts +0 -1
  160. package/src/users/users.service.ts +16 -0
  161. package/src/users/users.types.ts +1 -0
  162. package/src/users/users.validation.ts +6 -2
  163. package/src/utils/ApiError.ts +8 -1
  164. package/src/utils/buildRouterAndDocs.ts +57 -22
  165. package/src/utils/catchAsync.ts +27 -3
  166. package/src/utils/medicationName.ts +5 -4
  167. package/src/utils/pick.ts +5 -1
  168. package/src/utils/registerOpenApi.ts +75 -24
  169. package/src/utils/userName.ts +1 -0
  170. package/src/utils/zValidations.ts +98 -27
  171. package/tsconfig.json +13 -4
@@ -0,0 +1,185 @@
1
+ // @ts-nocheck
2
+ /* eslint-disable no-param-reassign */
3
+ import mongoose from "mongoose";
4
+ const paginate = (schema) => {
5
+ /**
6
+ * Query for documents with pagination
7
+ * @param {Object} [filter] - Mongo filter
8
+ * @param {PaginateOptions} [options] - Query options
9
+ * @returns {Promise<QueryResult>}
10
+ */
11
+ schema.statics.paginate = async function (filter = {}, options = {}, plugin) {
12
+ // Parse sorting options
13
+ const sort = options.sortBy
14
+ ? options.sortBy
15
+ .split(",")
16
+ .reduce((acc, sortOption) => {
17
+ const [key, order] = sortOption.split(":");
18
+ acc[key] = order === "desc" ? -1 : 1;
19
+ return acc;
20
+ }, {})
21
+ : { createdAt: -1 };
22
+ const limit = options.limit && parseInt(options.limit.toString(), 10) > 0
23
+ ? parseInt(options.limit.toString(), 10)
24
+ : 10000;
25
+ const page = options.page && parseInt(options.page.toString(), 10) > 0
26
+ ? parseInt(options.page.toString(), 10)
27
+ : 1;
28
+ const skip = (page - 1) * limit;
29
+ // Build aggregation pipeline
30
+ const pipeline = [];
31
+ let mainMatch = {};
32
+ let virtualMatch = {};
33
+ let hasVirtualFields = false;
34
+ // Helper function to determine if a path is a virtual field
35
+ const isVirtualField = (path) => {
36
+ const rootPath = path.split(".")[0];
37
+ return !!schema.virtuals[rootPath];
38
+ };
39
+ // Separate filter into main collection fields and virtual fields
40
+ if (filter) {
41
+ const separateFilter = (filterObj) => {
42
+ const main = {};
43
+ const virtual = {};
44
+ for (const key in filterObj) {
45
+ if (filterObj.hasOwnProperty(key)) {
46
+ if (key === "$or" || key === "$and") {
47
+ const mainArray = [];
48
+ const virtualArray = [];
49
+ filterObj[key].forEach((item) => {
50
+ const { main: itemMain, virtual: itemVirtual } = separateFilter(item);
51
+ if (Object.keys(itemMain).length > 0)
52
+ mainArray.push(itemMain);
53
+ if (Object.keys(itemVirtual).length > 0)
54
+ virtualArray.push(itemVirtual);
55
+ });
56
+ if (mainArray.length > 0)
57
+ main[key] = mainArray;
58
+ if (virtualArray.length > 0)
59
+ virtual[key] = virtualArray;
60
+ }
61
+ else {
62
+ if (isVirtualField(key)) {
63
+ virtual[key] = filterObj[key];
64
+ hasVirtualFields = true;
65
+ }
66
+ else {
67
+ main[key] = filterObj[key];
68
+ }
69
+ }
70
+ }
71
+ }
72
+ return { main, virtual };
73
+ };
74
+ const { main, virtual } = separateFilter(filter);
75
+ mainMatch = main;
76
+ virtualMatch = virtual;
77
+ }
78
+ // Add main collection $match stage
79
+ if (Object.keys(mainMatch).length > 0) {
80
+ pipeline.push({ $match: mainMatch });
81
+ }
82
+ // Handle virtual fields population
83
+ if (options.populate) {
84
+ options.populate.split(",").forEach((populateOption) => {
85
+ const paths = populateOption.split(".");
86
+ const localField = paths[0];
87
+ const virtual = schema.virtuals[localField];
88
+ if (!virtual) {
89
+ throw new Error(`Cannot populate unknown field: ${localField}`);
90
+ }
91
+ const refModel = virtual.options.ref;
92
+ const localFieldOption = virtual.options.localField;
93
+ const foreignFieldOption = virtual.options.foreignField;
94
+ const asField = localField;
95
+ const lookupStage = {
96
+ $lookup: {
97
+ from: mongoose.model(refModel).collection.name,
98
+ localField: localFieldOption,
99
+ foreignField: foreignFieldOption,
100
+ as: asField,
101
+ },
102
+ };
103
+ pipeline.push(lookupStage);
104
+ if (virtual.options.justOne) {
105
+ pipeline.push({
106
+ $unwind: {
107
+ path: `$${asField}`,
108
+ preserveNullAndEmptyArrays: true,
109
+ },
110
+ });
111
+ }
112
+ // Add $addFields stage to rename nested _id to id in populated documents
113
+ pipeline.push({
114
+ $addFields: {
115
+ [`${asField}.id`]: `$${asField}._id`,
116
+ },
117
+ });
118
+ pipeline.push({
119
+ $project: {
120
+ [`${asField}._id`]: 0,
121
+ },
122
+ });
123
+ });
124
+ }
125
+ // Add virtual fields $match stage
126
+ if (hasVirtualFields && Object.keys(virtualMatch).length > 0) {
127
+ pipeline.push({ $match: virtualMatch });
128
+ }
129
+ // Handle fuzzy search (if applicable)
130
+ if (this.fuzzySearch && options.fuzzySearch) {
131
+ throw new Error("Fuzzy search is not supported with aggregation in this paginate function.");
132
+ }
133
+ // Add sorting, skipping, and limiting stages
134
+ pipeline.push({ $sort: sort });
135
+ pipeline.push({ $skip: skip });
136
+ pipeline.push({ $limit: limit });
137
+ // Rename root _id to id
138
+ pipeline.push({
139
+ $addFields: {
140
+ id: "$_id",
141
+ },
142
+ });
143
+ pipeline.push({
144
+ $project: {
145
+ _id: 0,
146
+ },
147
+ });
148
+ // Use $facet to get both the results and the total count
149
+ const facetPipeline = [
150
+ {
151
+ $facet: {
152
+ metadata: [
153
+ {
154
+ $count: "totalResults",
155
+ },
156
+ ],
157
+ data: pipeline,
158
+ },
159
+ },
160
+ {
161
+ $addFields: {
162
+ totalResults: { $arrayElemAt: ["$metadata.totalResults", 0] },
163
+ },
164
+ },
165
+ ];
166
+ // Execute the aggregation pipeline
167
+ const aggResult = await this.aggregate(facetPipeline).exec();
168
+ // Extract results and total count
169
+ let totalResults = 0;
170
+ let results = [];
171
+ if (aggResult && aggResult.length > 0) {
172
+ totalResults = aggResult[0].totalResults || 0;
173
+ results = aggResult[0].data || [];
174
+ }
175
+ const totalPages = Math.ceil(totalResults / limit) || 1;
176
+ return {
177
+ results,
178
+ page,
179
+ limit,
180
+ totalPages,
181
+ totalResults,
182
+ };
183
+ };
184
+ };
185
+ export default paginate;
@@ -0,0 +1,16 @@
1
+ function simplePopulate(populate) {
2
+ let docsPromise = {};
3
+ populate.split(",").forEach((populateOption) => {
4
+ docsPromise = populateOption
5
+ .split(".")
6
+ .reverse()
7
+ .reduce((acc, key) => {
8
+ if (Object.keys(acc).length === 0) {
9
+ return { path: key };
10
+ }
11
+ return { path: key, populate: acc };
12
+ }, {});
13
+ });
14
+ return docsPromise;
15
+ }
16
+ export default simplePopulate;
@@ -0,0 +1,35 @@
1
+ /* eslint-disable no-param-reassign */
2
+ const deleteAtPath = (obj, path, index) => {
3
+ if (index === path.length - 1) {
4
+ delete obj[path[index]];
5
+ return;
6
+ }
7
+ deleteAtPath(obj[path[index]], path, index + 1);
8
+ };
9
+ const toJSON = (schema, timestamps = false) => {
10
+ let transform;
11
+ if (schema.options.toJSON && schema.options.toJSON.transform) {
12
+ transform = schema.options.toJSON.transform;
13
+ }
14
+ schema.options.toJSON = {
15
+ ...schema.options.toJSON,
16
+ transform(doc, ret, options) {
17
+ Object.keys(schema.paths).forEach((path) => {
18
+ if (schema.paths[path].options && schema.paths[path].options.private) {
19
+ deleteAtPath(ret, path.split("."), 0);
20
+ }
21
+ });
22
+ ret.id = ret._id.toString();
23
+ delete ret._id;
24
+ delete ret.__v;
25
+ if (!timestamps) {
26
+ delete ret.createdAt;
27
+ delete ret.updatedAt;
28
+ }
29
+ if (transform) {
30
+ return transform(doc, ret, options);
31
+ }
32
+ },
33
+ };
34
+ };
35
+ export default toJSON;
@@ -0,0 +1,64 @@
1
+ import httpStatus from "http-status";
2
+ import pick from "../utils/pick.js";
3
+ import ApiError from "../utils/ApiError.js";
4
+ import catchAsync from "../utils/catchAsync.js";
5
+ import usersService from "../users/users.service";
6
+ import organizationsService, { deleteOrganizationById, } from "./organizations.service.js";
7
+ import mongoose from "mongoose";
8
+ import { filterOptions } from "../utils/filterOptions.js";
9
+ const ObjectId = mongoose.Types.ObjectId;
10
+ export const createOrganization = catchAsync(async (req, res) => {
11
+ const organization = await organizationsService.createOrganization(req.body);
12
+ const user = await usersService.createUser({
13
+ organization: organization._id,
14
+ owner: res.req.auth.sub,
15
+ role: "admin",
16
+ category: "relative",
17
+ status: "accept",
18
+ });
19
+ res.status(httpStatus.CREATED).send(organization);
20
+ });
21
+ export const getOrganizations = catchAsync(async (req, res) => {
22
+ const filter = pick(req.query, ["name", "kind"]);
23
+ const options = pick(req.query, ["sortBy", "limit", "page"]);
24
+ console.log("getOrganizations", req.query, filter, options);
25
+ const filteredOptions = filterOptions(req.query, filter, {
26
+ objectIds: ["_id", "patient"],
27
+ search: ["name", "kind"],
28
+ });
29
+ const optionsPopulate = {
30
+ ...options,
31
+ // fuzzySearch: req.query.search ? { search: req.query.search, fields: ['name', 'kind'] } : undefined,
32
+ populate: "usersData,devicesData",
33
+ };
34
+ const result = await organizationsService.queryOrganizations(filteredOptions, optionsPopulate);
35
+ res.send(result);
36
+ });
37
+ export const queryOrganizationsByUser = catchAsync(async (req, res) => {
38
+ const users = await usersService.getUsersByOwner(res.req.auth.sub);
39
+ const result = await organizationsService.queryOrganizationsByUser(users);
40
+ res.send(result);
41
+ });
42
+ export const getOrganizationById = catchAsync(async (req, res) => {
43
+ const organization = await organizationsService.getOrganizationById(req.params.organizationId);
44
+ if (!organization) {
45
+ throw new ApiError(httpStatus.NOT_FOUND, "Organization not found");
46
+ }
47
+ res.send(organization);
48
+ });
49
+ export const updateOrganization = catchAsync(async (req, res) => {
50
+ const user = await organizationsService.updateOrganizationById(req.params.organizationId, req.body);
51
+ res.send(user);
52
+ });
53
+ export const deleteOrganization = catchAsync(async (req, res) => {
54
+ const entry = await deleteOrganizationById(req.params.organizationId);
55
+ res.send(entry);
56
+ });
57
+ export default {
58
+ createOrganization,
59
+ getOrganizations,
60
+ queryOrganizationsByUser,
61
+ getOrganizationById,
62
+ updateOrganization,
63
+ deleteOrganization,
64
+ };
@@ -0,0 +1,41 @@
1
+ // @ts-nocheck
2
+ import mongoose, { Schema } from "mongoose";
3
+ import { toJSON, paginate } from "../models/plugins/index.js";
4
+ // Define the schema
5
+ const organizationSchema = new Schema({
6
+ name: {
7
+ type: String,
8
+ trim: true,
9
+ // required: true,
10
+ },
11
+ meta: { type: Object },
12
+ kind: { type: String },
13
+ }, {
14
+ timestamps: true,
15
+ toObject: {
16
+ virtuals: true,
17
+ },
18
+ toJSON: {
19
+ virtuals: true,
20
+ },
21
+ });
22
+ // Virtuals
23
+ organizationSchema.virtual("usersData", {
24
+ ref: "User",
25
+ localField: "_id",
26
+ foreignField: "organization",
27
+ justOne: false,
28
+ });
29
+ organizationSchema.virtual("devicesData", {
30
+ ref: "Device",
31
+ localField: "_id",
32
+ foreignField: "organization",
33
+ justOne: false,
34
+ });
35
+ // Add plugins
36
+ organizationSchema.plugin(toJSON);
37
+ organizationSchema.plugin(paginate);
38
+ // Define the model
39
+ const Organization = mongoose.models.Organization ||
40
+ mongoose.model("Organization", organizationSchema);
41
+ export default Organization;
@@ -0,0 +1,98 @@
1
+ import { Router } from "express";
2
+ import buildRouterAndDocs from "../utils/buildRouterAndDocs.js";
3
+ import { createOrganizationSchema, updateOrganizationSchema, getOrganizationByIdSchema, queryOrganizationsSchema, } from "./organizations.validation.js";
4
+ import { organizationResponseSchema } from "./organizations.schemas.js";
5
+ import { createOrganization, getOrganizations, queryOrganizationsByUser, getOrganizationById, updateOrganization, deleteOrganization, } from "./organizations.controller.js";
6
+ import auth from "../middlewares/auth.js";
7
+ import { validateAdmin } from "../middlewares/validateAdmin.js";
8
+ import { validateOrganization } from "../middlewares/validateOrganization.js";
9
+ import { validateOrganizationDelete, validateOrganizationUpdate, } from "../middlewares/validateAction.js";
10
+ export const organizationsRouteSpecs = [
11
+ {
12
+ method: "post",
13
+ path: "/",
14
+ validate: [auth("manageUsers")],
15
+ requestSchema: createOrganizationSchema,
16
+ responseSchema: organizationResponseSchema,
17
+ handler: createOrganization,
18
+ summary: "Create a new organization",
19
+ description: "Creates a new organization with the provided details.",
20
+ },
21
+ {
22
+ method: "get",
23
+ path: "/",
24
+ validate: [auth("getUsers")],
25
+ requestSchema: {},
26
+ responseSchema: organizationResponseSchema.array(),
27
+ handler: queryOrganizationsByUser,
28
+ summary: "Get all organizations",
29
+ description: "Retrieves all organizations accessible to the current user.",
30
+ },
31
+ {
32
+ method: "get",
33
+ path: "/all",
34
+ validate: [auth("getUsers"), validateAdmin],
35
+ requestSchema: queryOrganizationsSchema,
36
+ responseSchema: organizationResponseSchema.array(),
37
+ handler: getOrganizations,
38
+ summary: "Get all organizations",
39
+ description: "Retrieves all organizations in the system.",
40
+ },
41
+ {
42
+ method: "get",
43
+ path: "/:organizationId",
44
+ validate: [auth("getUsers"), validateOrganization],
45
+ requestSchema: getOrganizationByIdSchema,
46
+ responseSchema: organizationResponseSchema,
47
+ handler: getOrganizationById,
48
+ summary: "Get an organization by ID",
49
+ description: "Retrieves the details of a specific organization by its ID.",
50
+ },
51
+ {
52
+ method: "patch",
53
+ path: "/:organizationId",
54
+ validate: [
55
+ auth("manageUsers"),
56
+ validateOrganization,
57
+ validateOrganizationUpdate,
58
+ ],
59
+ requestSchema: updateOrganizationSchema,
60
+ responseSchema: organizationResponseSchema,
61
+ handler: updateOrganization,
62
+ summary: "Update an organization by ID",
63
+ description: "Updates the details of a specific organization by its ID.",
64
+ },
65
+ {
66
+ method: "post",
67
+ path: "/:organizationId",
68
+ validate: [
69
+ auth("manageUsers"),
70
+ validateOrganization,
71
+ validateOrganizationUpdate,
72
+ ],
73
+ requestSchema: updateOrganizationSchema,
74
+ responseSchema: organizationResponseSchema,
75
+ handler: updateOrganization,
76
+ summary: "Update an organization by ID",
77
+ description: "Updates the details of a specific organization by its ID.",
78
+ },
79
+ {
80
+ method: "delete",
81
+ path: "/:organizationId",
82
+ validate: [
83
+ auth("manageUsers"),
84
+ validateOrganization,
85
+ validateOrganizationDelete,
86
+ ],
87
+ requestSchema: getOrganizationByIdSchema,
88
+ responseSchema: organizationResponseSchema,
89
+ handler: deleteOrganization,
90
+ summary: "Delete an organization by ID",
91
+ description: "Deletes a specific organization by its ID.",
92
+ },
93
+ ];
94
+ const router = Router();
95
+ buildRouterAndDocs(router, organizationsRouteSpecs, "/organizations", [
96
+ "Organizations",
97
+ ]);
98
+ export default router;
@@ -0,0 +1,7 @@
1
+ import { z } from 'zod';
2
+ export const organizationResponseSchema = z.object({
3
+ id: z.string(),
4
+ name: z.string(),
5
+ email: z.string().email(),
6
+ kind: z.string().optional(),
7
+ });
@@ -0,0 +1,59 @@
1
+ // @ts-nocheck
2
+ import httpStatus from "http-status";
3
+ import Organization from "./organizations.model.js";
4
+ import ApiError from "../utils/ApiError.js";
5
+ const createOrganization = async (organizationBody) => {
6
+ const organization = await Organization.create(organizationBody);
7
+ return organization;
8
+ };
9
+ const queryOrganizations = async (filter, options) => {
10
+ const organizations = await Organization.paginate(filter, options);
11
+ return organizations;
12
+ };
13
+ const queryOrganizationsByUser = async (organizationsList) => {
14
+ if (!organizationsList)
15
+ return false;
16
+ const organizationIds = organizationsList
17
+ .map((e) => e.organization)
18
+ .filter((id) => Boolean(id));
19
+ const organizations = await Organization.paginate({
20
+ _id: { $in: organizationIds },
21
+ }, {});
22
+ return organizations;
23
+ };
24
+ export const getOrganizationById = async (id) => {
25
+ return Organization.findById(id);
26
+ };
27
+ export const getOrganizationByEmail = async (email) => {
28
+ return Organization.findOne({ email });
29
+ };
30
+ const updateOrganizationById = async (organizationId, updateBody) => {
31
+ const organization = await getOrganizationById(organizationId);
32
+ if (!organization) {
33
+ throw new ApiError(httpStatus.NOT_FOUND, "Organization not found");
34
+ }
35
+ // Legacy: Remove organization field if present in updateBody
36
+ if ("organization" in updateBody) {
37
+ delete updateBody.organization;
38
+ }
39
+ Object.assign(organization, updateBody);
40
+ await organization.save();
41
+ return organization;
42
+ };
43
+ export const deleteOrganizationById = async (organizationId) => {
44
+ const organization = await getOrganizationById(organizationId);
45
+ if (!organization) {
46
+ throw new ApiError(httpStatus.NOT_FOUND, "Organization not found");
47
+ }
48
+ await organization.deleteOne();
49
+ return organization;
50
+ };
51
+ export default {
52
+ createOrganization,
53
+ queryOrganizations,
54
+ getOrganizationById,
55
+ queryOrganizationsByUser,
56
+ getOrganizationByEmail,
57
+ updateOrganizationById,
58
+ deleteOrganizationById,
59
+ };
@@ -0,0 +1,62 @@
1
+ import { extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi";
2
+ import { z } from "zod";
3
+ import { zPagination, zGet, zObjectId, zUpdate, zDelete, } from "../utils/zValidations.js";
4
+ extendZodWithOpenApi(z);
5
+ export const createOrganizationSchema = {
6
+ body: z.object({
7
+ /* name: z.string().openapi({
8
+ example: 'Acme Inc.',
9
+ description: 'The name of the organization',
10
+ }),
11
+ email: z.string().email().openapi({
12
+ example: 'contact@acme.com',
13
+ description: 'Contact email for the organization',
14
+ }), */
15
+ kind: z.string().openapi({
16
+ example: "private",
17
+ description: "The type or category of the organization",
18
+ }),
19
+ }),
20
+ };
21
+ export const queryOrganizationsSchema = zPagination;
22
+ export const getOrganizationByIdSchema = zGet("organizationId");
23
+ export const updateOrganizationSchema = {
24
+ ...zUpdate("organizationId"),
25
+ body: z.object({
26
+ name: z
27
+ .string()
28
+ .openapi({
29
+ example: "Acme Inc.",
30
+ description: "The name of the organization",
31
+ })
32
+ .optional(),
33
+ organization: zObjectId, // Legacy field, to be removed later
34
+ kind: z
35
+ .string()
36
+ .openapi({
37
+ example: "private",
38
+ description: "The type or category of the organization",
39
+ })
40
+ .optional(),
41
+ meta: z
42
+ .record(z.string(), z.any())
43
+ .openapi({
44
+ example: { key: "value" },
45
+ description: "Additional metadata for the entry",
46
+ })
47
+ .optional(),
48
+ }),
49
+ //...zUpdate('organizationId'),
50
+ /* body: z.object({
51
+ meta: z.any,
52
+ /* organization: zObjectId,
53
+ kind: z
54
+ .string()
55
+ .openapi({
56
+ example: 'private',
57
+ description: 'The type or category of the organization',
58
+ })
59
+ .optional(),
60
+ }),*/
61
+ };
62
+ export const deleteOrganizationSchema = zDelete("organizationId");
@@ -0,0 +1,24 @@
1
+ import httpStatus from "http-status";
2
+ import catchAsync from "../utils/catchAsync.js";
3
+ import pdfService from "./pdf.service.js";
4
+ import ApiError from "../utils/ApiError.js";
5
+ export const generatePdfFromUrl = catchAsync(async (req, res) => {
6
+ const fileName = "memo-print";
7
+ const authHeader = req.headers["authorization"];
8
+ if (!authHeader) {
9
+ throw new ApiError(httpStatus.UNAUTHORIZED, "Missing Authorization header");
10
+ }
11
+ const token = authHeader.split(" ")[1];
12
+ if (!token) {
13
+ throw new ApiError(httpStatus.UNAUTHORIZED, "Missing bearer token");
14
+ }
15
+ const urlPath = typeof req.query.urlPath === "string" ? req.query.urlPath : undefined;
16
+ if (!urlPath) {
17
+ throw new ApiError(httpStatus.BAD_REQUEST, "Missing urlPath query parameter");
18
+ }
19
+ const result = await pdfService.generatePdfFromUrl({ urlPath, token });
20
+ res.status(httpStatus.CREATED).send({ signed: result });
21
+ });
22
+ export default {
23
+ generatePdfFromUrl,
24
+ };
@@ -0,0 +1,22 @@
1
+ import { Router } from "express";
2
+ import buildRouterAndDocs from "../utils/buildRouterAndDocs.js";
3
+ import { generatePdfSchema } from "./pdf.validation.js";
4
+ import { pdfResponseSchema } from "./pdf.schemas.js";
5
+ import { generatePdfFromUrl } from "./pdf.controller.js";
6
+ import auth from "../middlewares/auth.js";
7
+ export const pdfRouteSpecs = [
8
+ {
9
+ method: "get",
10
+ path: "/",
11
+ validate: [auth("manageUsers")],
12
+ requestSchema: generatePdfSchema,
13
+ responseSchema: pdfResponseSchema,
14
+ handler: generatePdfFromUrl,
15
+ summary: "Generate a PDF from a provided URL",
16
+ description: "This endpoint allows users to generate a PDF document from a specified URL.",
17
+ memoOnly: true,
18
+ },
19
+ ];
20
+ const router = Router();
21
+ buildRouterAndDocs(router, pdfRouteSpecs, "/pdf", ["PDF"]);
22
+ export default router;
@@ -0,0 +1,6 @@
1
+ import { z } from 'zod';
2
+ export const pdfResponseSchema = z.object({
3
+ url: z.string().url(),
4
+ filename: z.string(),
5
+ size: z.number(),
6
+ });