@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.
- 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 +17 -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 +67 -0
- package/dist/src/utils/urlUtils.js +15 -0
- package/dist/src/utils/userName.js +22 -0
- package/dist/src/utils/zValidations.js +143 -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/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +97 -80
- package/scripts/release-and-sync-paperless.mjs +137 -0
- package/src/accounts/accounts.controller.ts +1 -0
- package/src/accounts/accounts.service.ts +1 -0
- package/src/accounts/accounts.validation.ts +8 -5
- 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 +11 -9
- package/src/devices/devices.service.ts +1 -0
- package/src/devices/devices.types.ts +1 -0
- package/src/devices/devices.validation.ts +93 -32
- 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 +1 -1
- 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 +4 -3
- 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/middlewares/validateZod.ts +5 -5
- 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/organizations/organizations.validation.ts +1 -1
- 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 +57 -22
- package/src/utils/catchAsync.ts +27 -3
- package/src/utils/medicationName.ts +5 -4
- package/src/utils/pick.ts +5 -1
- package/src/utils/registerOpenApi.ts +75 -24
- package/src/utils/userName.ts +1 -0
- package/src/utils/zValidations.ts +98 -27
- package/tsconfig.json +13 -4
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
let deviceList = null;
|
|
4
|
+
const parseDeviceList = (value) => {
|
|
5
|
+
if (!Array.isArray(value)) {
|
|
6
|
+
throw new Error("Device list must be an array.");
|
|
7
|
+
}
|
|
8
|
+
return value;
|
|
9
|
+
};
|
|
10
|
+
const loadDeviceListFromFile = (listPath) => {
|
|
11
|
+
const absolutePath = path.resolve(listPath);
|
|
12
|
+
const raw = readFileSync(absolutePath, "utf8");
|
|
13
|
+
const parsed = JSON.parse(raw);
|
|
14
|
+
return parseDeviceList(parsed);
|
|
15
|
+
};
|
|
16
|
+
export const initDeviceList = (options = {}) => {
|
|
17
|
+
if (options.list) {
|
|
18
|
+
deviceList = options.list;
|
|
19
|
+
return deviceList;
|
|
20
|
+
}
|
|
21
|
+
if (options.listPath) {
|
|
22
|
+
deviceList = loadDeviceListFromFile(options.listPath);
|
|
23
|
+
return deviceList;
|
|
24
|
+
}
|
|
25
|
+
throw new Error("initDeviceList requires list or listPath.");
|
|
26
|
+
};
|
|
27
|
+
const ensureDeviceList = () => {
|
|
28
|
+
if (!deviceList) {
|
|
29
|
+
throw new Error("deviceList is not initialized. Call initDeviceList(...) before using device utilities.");
|
|
30
|
+
}
|
|
31
|
+
return deviceList;
|
|
32
|
+
};
|
|
33
|
+
export { deviceList as default };
|
|
34
|
+
export function deviceByKind(device) {
|
|
35
|
+
const list = ensureDeviceList();
|
|
36
|
+
const result = list.find((e) => e.id === device);
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
export function deviceByDeviceName(deviceName) {
|
|
40
|
+
if (!deviceName)
|
|
41
|
+
return false;
|
|
42
|
+
const list = ensureDeviceList();
|
|
43
|
+
const result = list.find((e) => {
|
|
44
|
+
if (!e.deviceNameDetection)
|
|
45
|
+
return false;
|
|
46
|
+
return deviceName.startsWith(e.deviceNameDetection);
|
|
47
|
+
});
|
|
48
|
+
if (!result)
|
|
49
|
+
return false;
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns true if the device kind has the given feature
|
|
54
|
+
*/
|
|
55
|
+
export function deviceKindHasFeature(feature, kind) {
|
|
56
|
+
if (!kind)
|
|
57
|
+
return false;
|
|
58
|
+
const list = ensureDeviceList();
|
|
59
|
+
const result = list.find((e) => e.id === kind);
|
|
60
|
+
if (!result)
|
|
61
|
+
return false;
|
|
62
|
+
return result.features.includes(feature);
|
|
63
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import mongoose from 'mongoose';
|
|
2
|
+
const { ObjectId } = mongoose.Types;
|
|
3
|
+
const filterOptions = (query, filter, options) => {
|
|
4
|
+
let filterAlt = filter;
|
|
5
|
+
if (query.search && mongoose.isValidObjectId(query.search)) {
|
|
6
|
+
const idList = options.objectIds.map((e) => ({
|
|
7
|
+
[e]: new ObjectId(query.search),
|
|
8
|
+
}));
|
|
9
|
+
filterAlt = {
|
|
10
|
+
$and: [filter, { $or: idList }],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
else if (query.search) {
|
|
14
|
+
const regexp = new RegExp(query.search, 'i');
|
|
15
|
+
const searchList = options.search.map((e) => ({
|
|
16
|
+
[e]: { $regex: regexp },
|
|
17
|
+
}));
|
|
18
|
+
filterAlt = {
|
|
19
|
+
$and: [filter, { $or: searchList }],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return filterAlt;
|
|
23
|
+
};
|
|
24
|
+
export { filterOptions };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import i18n from "../i18n/i18n";
|
|
3
|
+
export const medicationName = (entry, lng) => {
|
|
4
|
+
const name = entry.medicationData?.Kurzname
|
|
5
|
+
? entry.medicationData.Kurzname
|
|
6
|
+
: entry.localMedicationData?.meta?.name
|
|
7
|
+
? entry.localMedicationData.meta.name.replace(/ .*/, "")
|
|
8
|
+
: i18n.t("A medication", { lng });
|
|
9
|
+
return name;
|
|
10
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create an object composed of the picked object properties
|
|
3
|
+
* @param {Record<string, any>} object - The source object
|
|
4
|
+
* @param {string[]} keys - The keys to pick
|
|
5
|
+
* @returns {Partial<Record<string, any>>} - The new object with picked properties
|
|
6
|
+
*/
|
|
7
|
+
// @ts-nocheck
|
|
8
|
+
const pick = (object, keys) => {
|
|
9
|
+
return keys.reduce((obj, key) => {
|
|
10
|
+
if (object && Object.prototype.hasOwnProperty.call(object, key)) {
|
|
11
|
+
obj[key] = object[key];
|
|
12
|
+
}
|
|
13
|
+
return obj;
|
|
14
|
+
}, {});
|
|
15
|
+
};
|
|
16
|
+
export default pick;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { OpenAPIRegistry } from "@asteasolutions/zod-to-openapi";
|
|
2
|
+
import { extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
extendZodWithOpenApi(z);
|
|
5
|
+
export const registry = new OpenAPIRegistry();
|
|
6
|
+
// add Bearer JWT auth
|
|
7
|
+
export const bearerAuth = registry.registerComponent("securitySchemes", "bearerAuth", {
|
|
8
|
+
type: "http",
|
|
9
|
+
scheme: "bearer",
|
|
10
|
+
bearerFormat: "JWT",
|
|
11
|
+
description: "JWT Bearer authentication",
|
|
12
|
+
});
|
|
13
|
+
export const xApiKey = registry.registerComponent("securitySchemes", "x-api-key", {
|
|
14
|
+
type: "apiKey",
|
|
15
|
+
in: "header",
|
|
16
|
+
name: "x-api-key",
|
|
17
|
+
description: "API key for authentication",
|
|
18
|
+
});
|
|
19
|
+
const UserSchema = z
|
|
20
|
+
.object({
|
|
21
|
+
id: z.string().openapi({ example: "1212121" }),
|
|
22
|
+
name: z.string().openapi({ example: "John Doe" }),
|
|
23
|
+
age: z.number().openapi({ example: 42 }),
|
|
24
|
+
})
|
|
25
|
+
.openapi("User");
|
|
26
|
+
registry.registerPath({
|
|
27
|
+
method: "get",
|
|
28
|
+
path: "/usersnnn/{id}",
|
|
29
|
+
summary: "Get a single user",
|
|
30
|
+
request: {
|
|
31
|
+
params: z.object({ id: z.string() }),
|
|
32
|
+
},
|
|
33
|
+
responses: {
|
|
34
|
+
200: {
|
|
35
|
+
description: "Object with user data.",
|
|
36
|
+
content: {
|
|
37
|
+
"application/json": {
|
|
38
|
+
schema: UserSchema,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
registry.registerPath({
|
|
45
|
+
method: "get",
|
|
46
|
+
path: "/users/{id}",
|
|
47
|
+
description: "Get user data by its id",
|
|
48
|
+
summary: "Get a single user",
|
|
49
|
+
request: {
|
|
50
|
+
params: z.object({
|
|
51
|
+
id: z.string().openapi({ example: "1212121" }),
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
responses: {
|
|
55
|
+
200: {
|
|
56
|
+
description: "Object with user data.",
|
|
57
|
+
content: {
|
|
58
|
+
"application/json": {
|
|
59
|
+
schema: UserSchema,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
204: {
|
|
64
|
+
description: "No content - successful operation",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const resolvePossiblyRelativeUrl = (maybeUrl, baseUrl) => {
|
|
2
|
+
if (!maybeUrl)
|
|
3
|
+
return null;
|
|
4
|
+
if (maybeUrl.startsWith('http'))
|
|
5
|
+
return maybeUrl;
|
|
6
|
+
if (baseUrl && baseUrl.startsWith('http')) {
|
|
7
|
+
try {
|
|
8
|
+
return new URL(maybeUrl, baseUrl).toString();
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return maybeUrl;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return maybeUrl;
|
|
15
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { getUserById } from "../accounts/auth0.service";
|
|
3
|
+
const generateUserName = async (patient) => {
|
|
4
|
+
if (patient.owner) {
|
|
5
|
+
const auth0UserById = await getUserById(patient.owner);
|
|
6
|
+
patient.auth0User = auth0UserById.data;
|
|
7
|
+
}
|
|
8
|
+
if (patient?.auth0User?.app_metadata?.first_name) {
|
|
9
|
+
return `${patient.auth0User.app_metadata.first_name} ${patient.auth0User.app_metadata.last_name}`;
|
|
10
|
+
}
|
|
11
|
+
if (patient?.auth0User?.family_name) {
|
|
12
|
+
return `${patient.auth0User.given_name} ${patient.auth0User.family_name}`;
|
|
13
|
+
}
|
|
14
|
+
if (patient && patient?.auth0User) {
|
|
15
|
+
return patient.auth0User.name;
|
|
16
|
+
}
|
|
17
|
+
if (patient && (patient.meta?.firstName || patient.meta?.lastName)) {
|
|
18
|
+
return `${patient.meta?.firstName}${patient.meta?.firstName ? " " : ""}${patient.meta?.lastName}`;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
};
|
|
22
|
+
export default generateUserName;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import mongoose from "mongoose";
|
|
4
|
+
export const zPagination = {
|
|
5
|
+
query: z.object({
|
|
6
|
+
name: z
|
|
7
|
+
.string()
|
|
8
|
+
.openapi({
|
|
9
|
+
example: "John",
|
|
10
|
+
description: "Name to filter by",
|
|
11
|
+
param: { name: "name", in: "query" },
|
|
12
|
+
})
|
|
13
|
+
.optional(),
|
|
14
|
+
role: z
|
|
15
|
+
.string()
|
|
16
|
+
.openapi({
|
|
17
|
+
example: "admin",
|
|
18
|
+
description: "Role to filter by",
|
|
19
|
+
param: { name: "role", in: "query" },
|
|
20
|
+
})
|
|
21
|
+
.optional(),
|
|
22
|
+
sortBy: z
|
|
23
|
+
.string()
|
|
24
|
+
.openapi({
|
|
25
|
+
example: "createdAt",
|
|
26
|
+
description: "Field to sort by",
|
|
27
|
+
param: { name: "sortBy", in: "query" },
|
|
28
|
+
})
|
|
29
|
+
.optional(),
|
|
30
|
+
search: z
|
|
31
|
+
.string()
|
|
32
|
+
.openapi({
|
|
33
|
+
example: process.env.SCHEMA_EXAMPLE_SEARCH || "",
|
|
34
|
+
description: "Search term to filter results",
|
|
35
|
+
param: { name: "search", in: "query" },
|
|
36
|
+
})
|
|
37
|
+
.optional(),
|
|
38
|
+
limit: z.coerce
|
|
39
|
+
.number()
|
|
40
|
+
.openapi({
|
|
41
|
+
example: 10,
|
|
42
|
+
description: "Number of items per page",
|
|
43
|
+
param: { name: "limit", in: "query" },
|
|
44
|
+
})
|
|
45
|
+
.int()
|
|
46
|
+
.min(1)
|
|
47
|
+
.max(100000)
|
|
48
|
+
.optional(),
|
|
49
|
+
offset: z.coerce
|
|
50
|
+
.number() // was z.int()
|
|
51
|
+
.openapi({
|
|
52
|
+
example: 0,
|
|
53
|
+
description: "Offset for pagination, used to skip a number of items",
|
|
54
|
+
param: { name: "offset", in: "query" },
|
|
55
|
+
})
|
|
56
|
+
.int()
|
|
57
|
+
.min(0)
|
|
58
|
+
.max(100000)
|
|
59
|
+
.optional(),
|
|
60
|
+
page: z.coerce
|
|
61
|
+
.number()
|
|
62
|
+
.int()
|
|
63
|
+
.openapi({
|
|
64
|
+
example: 1,
|
|
65
|
+
description: "Page number for pagination",
|
|
66
|
+
param: { name: "page", in: "query" },
|
|
67
|
+
})
|
|
68
|
+
.min(1)
|
|
69
|
+
.max(100000)
|
|
70
|
+
.optional(),
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
73
|
+
export const zPaginationResponse = () => z.object({
|
|
74
|
+
results: z.array(z.unknown()), // Replace with your specific item schema
|
|
75
|
+
totalResults: z
|
|
76
|
+
.number()
|
|
77
|
+
.openapi({ example: 100, description: "Total number of items" }),
|
|
78
|
+
totalPages: z
|
|
79
|
+
.number()
|
|
80
|
+
.openapi({ example: 10, description: "Total number of pages" }),
|
|
81
|
+
page: z
|
|
82
|
+
.number()
|
|
83
|
+
.openapi({ example: 1, description: "Current page number" }),
|
|
84
|
+
limit: z
|
|
85
|
+
.number()
|
|
86
|
+
.openapi({ example: 10, description: "Number of items per page" }),
|
|
87
|
+
});
|
|
88
|
+
const defaultObjectIdExample = "682fd0d7d4a6325d9d45b86d";
|
|
89
|
+
const exampleDefaults = {
|
|
90
|
+
organization: "682fd0d7d4a6325d9d45b86e",
|
|
91
|
+
user: defaultObjectIdExample,
|
|
92
|
+
device: "682fd0d7d4a6325d9d45b86f",
|
|
93
|
+
paper: "682fd0d7d4a6325d9d45b870",
|
|
94
|
+
};
|
|
95
|
+
const objectIdExampleOverrides = {
|
|
96
|
+
organizationId: process.env.SCHEMA_EXAMPLE_ORGANIZATION_ID || exampleDefaults.organization,
|
|
97
|
+
organization: process.env.SCHEMA_EXAMPLE_ORGANIZATION_ID || exampleDefaults.organization,
|
|
98
|
+
userId: process.env.SCHEMA_EXAMPLE_USER_ID || exampleDefaults.user,
|
|
99
|
+
deviceId: process.env.SCHEMA_EXAMPLE_DEVICE_ID || exampleDefaults.device,
|
|
100
|
+
device: process.env.SCHEMA_EXAMPLE_DEVICE_ID || exampleDefaults.device,
|
|
101
|
+
paperId: process.env.SCHEMA_EXAMPLE_PAPER_ID || exampleDefaults.paper,
|
|
102
|
+
paper: process.env.SCHEMA_EXAMPLE_PAPER_ID || exampleDefaults.paper,
|
|
103
|
+
patient: process.env.SCHEMA_EXAMPLE_USER_ID || exampleDefaults.user,
|
|
104
|
+
accountId: process.env.SCHEMA_EXAMPLE_ACCOUNT_ID,
|
|
105
|
+
tokenId: process.env.SCHEMA_EXAMPLE_TOKEN_ID,
|
|
106
|
+
};
|
|
107
|
+
export const zObjectIdFor = (paramName) => {
|
|
108
|
+
const example = paramName ? objectIdExampleOverrides[paramName] : undefined;
|
|
109
|
+
const exampleValue = example || defaultObjectIdExample;
|
|
110
|
+
return z
|
|
111
|
+
.string()
|
|
112
|
+
.refine((val) => {
|
|
113
|
+
if (process.env.SCHEMA_STRICT_EXAMPLES === "true" && example) {
|
|
114
|
+
return val === example;
|
|
115
|
+
}
|
|
116
|
+
return mongoose.Types.ObjectId.isValid(val);
|
|
117
|
+
})
|
|
118
|
+
.openapi({
|
|
119
|
+
example: exampleValue,
|
|
120
|
+
description: "A valid MongoDB ObjectId",
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
export const zGet = (id) => ({
|
|
124
|
+
params: z.object({
|
|
125
|
+
[id]: zObjectIdFor(id),
|
|
126
|
+
}),
|
|
127
|
+
});
|
|
128
|
+
export function zPatchBody(shape, message = "At least one field must be provided for update") {
|
|
129
|
+
// assume user passed in already-optional vals
|
|
130
|
+
return z.object(shape); // .refine((o) => Object.keys(o).length > 0, { message });
|
|
131
|
+
}
|
|
132
|
+
export const zUpdate = (id) => ({
|
|
133
|
+
params: z.object({
|
|
134
|
+
[id]: zObjectIdFor(id),
|
|
135
|
+
}),
|
|
136
|
+
});
|
|
137
|
+
export const zDelete = (id) => ({
|
|
138
|
+
params: z.object({
|
|
139
|
+
[id]: zObjectIdFor(id),
|
|
140
|
+
}),
|
|
141
|
+
});
|
|
142
|
+
export const zObjectId = zObjectIdFor();
|
|
143
|
+
export const zDate = () => z.string().pipe(z.coerce.date());
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const Joi = require('joi');
|
|
3
|
+
const { password } = require('./custom.validation.ts');
|
|
4
|
+
const register = {
|
|
5
|
+
body: Joi.object().keys({
|
|
6
|
+
email: Joi.string().required().email(),
|
|
7
|
+
password: Joi.string().required().custom(password),
|
|
8
|
+
name: Joi.string().required(),
|
|
9
|
+
}),
|
|
10
|
+
};
|
|
11
|
+
const login = {
|
|
12
|
+
body: Joi.object().keys({
|
|
13
|
+
email: Joi.string().required(),
|
|
14
|
+
password: Joi.string().required(),
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
const logout = {
|
|
18
|
+
body: Joi.object().keys({
|
|
19
|
+
refreshToken: Joi.string().required(),
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
const refreshTokens = {
|
|
23
|
+
body: Joi.object().keys({
|
|
24
|
+
refreshToken: Joi.string().required(),
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
const forgotPassword = {
|
|
28
|
+
body: Joi.object().keys({
|
|
29
|
+
email: Joi.string().email().required(),
|
|
30
|
+
}),
|
|
31
|
+
};
|
|
32
|
+
const resetPassword = {
|
|
33
|
+
query: Joi.object().keys({
|
|
34
|
+
token: Joi.string().required(),
|
|
35
|
+
}),
|
|
36
|
+
body: Joi.object().keys({
|
|
37
|
+
password: Joi.string().required().custom(password),
|
|
38
|
+
}),
|
|
39
|
+
};
|
|
40
|
+
const verifyEmail = {
|
|
41
|
+
query: Joi.object().keys({
|
|
42
|
+
token: Joi.string().required(),
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
module.exports = {
|
|
46
|
+
register,
|
|
47
|
+
login,
|
|
48
|
+
logout,
|
|
49
|
+
refreshTokens,
|
|
50
|
+
forgotPassword,
|
|
51
|
+
resetPassword,
|
|
52
|
+
verifyEmail,
|
|
53
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
// Can be anything starting with nrf- or epd7, or epd- followed by a number
|
|
3
|
+
export const deviceId = () => z.string().regex(/^(?:nrf-.*|epd7.*|epd-\d+)$/, {
|
|
4
|
+
message: 'must start with "nrf-", "epd7" or "epd-" followed by a number',
|
|
5
|
+
});
|
|
6
|
+
export const objectId = () => z.string().regex(/^[0-9a-fA-F]{24}$/, {
|
|
7
|
+
message: 'must be a valid mongo id',
|
|
8
|
+
});
|
|
9
|
+
export const password = () => z
|
|
10
|
+
.string()
|
|
11
|
+
.min(8, 'password must be at least 8 characters')
|
|
12
|
+
.refine((val) => /\d/.test(val) && /[a-zA-Z]/.test(val), {
|
|
13
|
+
message: 'password must contain at least 1 letter and 1 number',
|
|
14
|
+
});
|
|
15
|
+
export default {
|
|
16
|
+
deviceId,
|
|
17
|
+
objectId,
|
|
18
|
+
password,
|
|
19
|
+
};
|