@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.
- package/dist/src/accounts/accounts.controller.js +89 -0
- package/dist/src/accounts/accounts.route.js +101 -0
- package/dist/src/accounts/accounts.schemas.js +12 -0
- package/dist/src/accounts/accounts.service.js +65 -0
- package/dist/src/accounts/accounts.validation.js +99 -0
- package/dist/src/accounts/auth0.service.js +188 -0
- package/dist/src/config/config.js +48 -0
- package/dist/src/config/logger.js +27 -0
- package/dist/src/config/morgan.js +16 -0
- package/dist/src/config/passport.cjs +28 -0
- package/dist/src/config/roles.js +11 -0
- package/dist/src/config/tokens.cjs +10 -0
- package/dist/src/devices/devices.controller.js +172 -0
- package/dist/src/devices/devices.model.js +94 -0
- package/dist/src/devices/devices.route.js +153 -0
- package/dist/src/devices/devices.schemas.js +84 -0
- package/dist/src/devices/devices.service.js +198 -0
- package/dist/src/devices/devices.types.js +1 -0
- package/dist/src/devices/devices.validation.js +257 -0
- package/dist/src/devicesNotifications/devicesNotifications.controller.js +69 -0
- package/dist/src/devicesNotifications/devicesNotifications.model.js +39 -0
- package/dist/src/devicesNotifications/devicesNotifications.route.js +124 -0
- package/dist/src/devicesNotifications/devicesNotifications.schemas.js +10 -0
- package/dist/src/devicesNotifications/devicesNotifications.service.js +181 -0
- package/dist/src/devicesNotifications/devicesNotifications.validation.js +46 -0
- package/dist/src/email/email.service.js +580 -0
- package/dist/src/files/upload.service.js +124 -0
- package/dist/src/i18n/i18n.js +38 -0
- package/dist/src/i18n/saveMissingLocalJsonBackend.js +53 -0
- package/dist/src/i18n/types.js +1 -0
- package/dist/src/index.js +48 -0
- package/dist/src/iotdevice/iotdevice.controller.js +96 -0
- package/dist/src/iotdevice/iotdevice.model.js +17 -0
- package/dist/src/iotdevice/iotdevice.route.js +143 -0
- package/dist/src/iotdevice/iotdevice.schemas.js +60 -0
- package/dist/src/iotdevice/iotdevice.service.js +579 -0
- package/dist/src/iotdevice/iotdevice.types.js +1 -0
- package/dist/src/iotdevice/iotdevice.validation.js +54 -0
- package/dist/src/middlewares/auth.js +75 -0
- package/dist/src/middlewares/checkJwt.cjs +17 -0
- package/dist/src/middlewares/error.js +36 -0
- package/dist/src/middlewares/mongooseValidations/ensureSameOrganization.js +13 -0
- package/dist/src/middlewares/rateLimiter.js +7 -0
- package/dist/src/middlewares/validate.js +18 -0
- package/dist/src/middlewares/validateAction.js +35 -0
- package/dist/src/middlewares/validateAdmin.js +18 -0
- package/dist/src/middlewares/validateAi.js +16 -0
- package/dist/src/middlewares/validateCurrentAuthUser.js +17 -0
- package/dist/src/middlewares/validateCurrentUser.js +20 -0
- package/dist/src/middlewares/validateDevice.js +98 -0
- package/dist/src/middlewares/validateDeviceUserOrganization.js +26 -0
- package/dist/src/middlewares/validateOrganization.js +63 -0
- package/dist/src/middlewares/validateQuerySearchUserAndOrganization.js +44 -0
- package/dist/src/middlewares/validateTokens.js +23 -0
- package/dist/src/middlewares/validateUser.js +38 -0
- package/dist/src/middlewares/validateZod.js +33 -0
- package/dist/src/models/plugins/index.js +4 -0
- package/dist/src/models/plugins/paginate.plugin.js +117 -0
- package/dist/src/models/plugins/paginateNew.plugin.js +185 -0
- package/dist/src/models/plugins/simplePopulate.js +16 -0
- package/dist/src/models/plugins/toJSON.plugin.js +35 -0
- package/dist/src/organizations/organizations.controller.js +64 -0
- package/dist/src/organizations/organizations.model.js +41 -0
- package/dist/src/organizations/organizations.route.js +98 -0
- package/dist/src/organizations/organizations.schemas.js +7 -0
- package/dist/src/organizations/organizations.service.js +59 -0
- package/dist/src/organizations/organizations.validation.js +62 -0
- package/dist/src/pdf/pdf.controller.js +24 -0
- package/dist/src/pdf/pdf.route.js +22 -0
- package/dist/src/pdf/pdf.schemas.js +6 -0
- package/dist/src/pdf/pdf.service.js +65 -0
- package/dist/src/pdf/pdf.validation.js +27 -0
- package/dist/src/tokens/tokens.controller.js +60 -0
- package/dist/src/tokens/tokens.model.js +18 -0
- package/dist/src/tokens/tokens.route.js +52 -0
- package/dist/src/tokens/tokens.schemas.js +14 -0
- package/dist/src/tokens/tokens.service.js +30 -0
- package/dist/src/tokens/tokens.validation.js +9 -0
- package/dist/src/types/routeSpec.js +1 -0
- package/dist/src/users/users.controller.js +147 -0
- package/dist/src/users/users.model.js +50 -0
- package/dist/src/users/users.route.js +137 -0
- package/dist/src/users/users.schemas.js +69 -0
- package/dist/src/users/users.service.js +295 -0
- package/dist/src/users/users.types.js +1 -0
- package/dist/src/users/users.validation.js +144 -0
- package/dist/src/utils/ApiError.js +16 -0
- package/dist/src/utils/buildRouterAndDocs.js +72 -0
- package/dist/src/utils/catchAsync.js +4 -0
- package/dist/src/utils/comparePapers.service.js +32 -0
- package/dist/src/utils/deviceUtils.js +63 -0
- package/dist/src/utils/filterOptions.js +24 -0
- package/dist/src/utils/medicationName.js +10 -0
- package/dist/src/utils/pick.js +16 -0
- package/dist/src/utils/registerOpenApi.js +28 -0
- package/dist/src/utils/urlUtils.js +15 -0
- package/dist/src/utils/userName.js +22 -0
- package/dist/src/utils/zValidations.js +124 -0
- package/dist/src/validations/auth.validation.cjs +53 -0
- package/dist/src/validations/custom.validation.js +19 -0
- package/dist/src/validations/index.cjs +3 -0
- package/package.json +15 -6
- package/scripts/release-and-sync-paperless.mjs +135 -0
- package/scripts/release-version.mjs +145 -0
- package/src/accounts/accounts.controller.ts +1 -0
- package/src/accounts/accounts.service.ts +1 -0
- package/src/accounts/accounts.validation.ts +6 -3
- package/src/accounts/auth0.service.ts +55 -28
- package/src/config/config.ts +6 -0
- package/src/config/logger.ts +15 -9
- package/src/devices/devices.controller.ts +7 -1
- package/src/devices/devices.model.ts +4 -1
- package/src/devices/devices.schemas.ts +10 -8
- package/src/devices/devices.service.ts +2 -1
- package/src/devices/devices.types.ts +1 -0
- package/src/devices/devices.validation.ts +85 -23
- package/src/devicesNotifications/devicesNotifications.controller.ts +57 -28
- package/src/devicesNotifications/devicesNotifications.model.ts +20 -12
- package/src/devicesNotifications/devicesNotifications.service.ts +35 -17
- package/src/files/upload.service.ts +52 -28
- package/src/i18n/i18n.ts +2 -2
- package/src/i18n/types.ts +1 -0
- package/src/index.ts +47 -0
- package/src/iotdevice/iotdevice.controller.ts +1 -0
- package/src/iotdevice/iotdevice.model.ts +6 -3
- package/src/iotdevice/iotdevice.route.ts +85 -76
- package/src/iotdevice/iotdevice.service.ts +5 -4
- package/src/iotdevice/iotdevice.types.ts +6 -0
- package/src/middlewares/auth.ts +2 -8
- package/src/middlewares/error.ts +26 -12
- package/src/middlewares/mongooseValidations/ensureSameOrganization.ts +4 -3
- package/src/middlewares/validateAi.ts +17 -9
- package/src/middlewares/validateDevice.ts +1 -0
- package/src/middlewares/validateDeviceUserOrganization.ts +1 -0
- package/src/middlewares/validateOrganization.ts +1 -1
- package/src/middlewares/validateQuerySearchUserAndOrganization.ts +1 -0
- package/src/middlewares/validateTokens.ts +2 -1
- package/src/middlewares/validateUser.ts +1 -0
- package/src/models/plugins/index.ts +5 -4
- package/src/models/plugins/paginate.plugin.ts +26 -16
- package/src/models/plugins/paginateNew.plugin.ts +33 -21
- package/src/models/plugins/simplePopulate.ts +8 -3
- package/src/models/plugins/toJSON.plugin.ts +12 -5
- package/src/organizations/organizations.controller.ts +1 -2
- package/src/organizations/organizations.model.ts +4 -4
- package/src/organizations/organizations.route.ts +1 -1
- package/src/organizations/organizations.service.ts +15 -6
- package/src/pdf/pdf.controller.ts +18 -1
- package/src/pdf/pdf.service.ts +25 -16
- package/src/tokens/tokens.controller.ts +6 -8
- package/src/tokens/tokens.model.ts +3 -1
- package/src/tokens/tokens.service.ts +3 -2
- package/src/types/express.d.ts +17 -0
- package/src/types/mongoose.d.ts +22 -0
- package/src/users/users.controller.ts +8 -9
- package/src/users/users.model.ts +6 -5
- package/src/users/users.route.ts +0 -1
- package/src/users/users.service.ts +16 -0
- package/src/users/users.types.ts +1 -0
- package/src/users/users.validation.ts +6 -2
- package/src/utils/ApiError.ts +8 -1
- package/src/utils/buildRouterAndDocs.ts +56 -21
- package/src/utils/catchAsync.ts +27 -3
- package/src/utils/deviceUtils.ts +109 -0
- package/src/utils/medicationName.ts +5 -4
- package/src/utils/pick.ts +5 -1
- package/src/utils/userName.ts +1 -0
- package/src/utils/zValidations.ts +78 -26
- package/tsconfig.json +13 -4
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
/* eslint-disable no-param-reassign */
|
|
2
|
-
import mongoose from
|
|
3
|
-
import type { Schema, Document, Model, PipelineStage } from
|
|
4
|
-
import type { PaginateOptions, QueryResult } from
|
|
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
|
|
21
|
-
|
|
22
|
-
acc
|
|
23
|
-
|
|
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
|
|
29
|
-
|
|
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(
|
|
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 ===
|
|
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 } =
|
|
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)
|
|
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(
|
|
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(
|
|
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:
|
|
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:
|
|
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: [
|
|
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(
|
|
3
|
+
populate.split(",").forEach((populateOption) => {
|
|
4
4
|
docsPromise = populateOption
|
|
5
|
-
.split(
|
|
5
|
+
.split(".")
|
|
6
6
|
.reverse()
|
|
7
|
-
.reduce((
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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:
|
|
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(
|
|
38
|
+
deleteAtPath(ret, path.split("."), 0);
|
|
32
39
|
}
|
|
33
40
|
});
|
|
34
41
|
|
|
@@ -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> =
|
|
58
|
-
|
|
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
|
|
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: {
|
|
17
|
-
|
|
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
|
|
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
|
|
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({
|
|
28
|
+
const result = await pdfService.generatePdfFromUrl({ urlPath, token });
|
|
12
29
|
|
|
13
30
|
res.status(httpStatus.CREATED).send({ signed: result });
|
|
14
31
|
});
|
package/src/pdf/pdf.service.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import puppeteer from
|
|
2
|
-
import { v4 as uuidv4 } from
|
|
3
|
-
import AWS from
|
|
4
|
-
import path from
|
|
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 (
|
|
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:
|
|
20
|
-
ACL:
|
|
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(
|
|
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 ({
|
|
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: [
|
|
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(
|
|
67
|
+
localStorage.setItem("print-token", token);
|
|
62
68
|
}, token);
|
|
63
69
|
|
|
64
|
-
await page.goto(domain + urlPath, { waitUntil:
|
|
70
|
+
await page.goto(domain + urlPath, { waitUntil: "networkidle2" });
|
|
65
71
|
|
|
66
|
-
await page.waitForSelector(
|
|
72
|
+
await page.waitForSelector(".pdf-render-complete");
|
|
67
73
|
|
|
68
|
-
const pdf = await page.pdf({ format:
|
|
74
|
+
const pdf = await page.pdf({ format: "A4", printBackground: true });
|
|
69
75
|
|
|
70
76
|
await page.evaluate(() => {
|
|
71
|
-
localStorage.setItem(
|
|
77
|
+
localStorage.setItem("print-token", "");
|
|
72
78
|
});
|
|
73
79
|
|
|
74
80
|
await browser.close();
|
|
75
81
|
|
|
76
|
-
const fileUrl = await uploadBuffer(
|
|
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
|
-
|
|
49
|
-
|
|
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
|
-
|
|
68
|
-
|
|
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> =
|
|
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,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
|
|
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 (
|
|
25
|
+
if (auth0users[0]) {
|
|
26
26
|
const userFound = await userService.getUserByOwner(
|
|
27
|
-
|
|
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
|
|
105
|
-
|
|
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
|
-
|
|
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,
|
package/src/users/users.model.ts
CHANGED
|
@@ -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:
|
|
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 =
|
|
87
|
-
|
|
88
|
-
userSchema
|
|
89
|
-
);
|
|
88
|
+
export const User =
|
|
89
|
+
(mongoose.models.User as IUserModel) ||
|
|
90
|
+
mongoose.model<IUserDocument, IUserModel>("User", userSchema);
|
package/src/users/users.route.ts
CHANGED
|
@@ -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:
|
|
54
|
+
organization: zObjectIdFor("organization").openapi({
|
|
53
55
|
description: "Filter users by organization ObjectId",
|
|
54
|
-
example:
|
|
56
|
+
example:
|
|
57
|
+
process.env.SCHEMA_EXAMPLE_ORGANIZATION_ID ||
|
|
58
|
+
"60c72b2f9b1e8d001c8e4f3a",
|
|
55
59
|
}),
|
|
56
60
|
}),
|
|
57
61
|
};
|