@loomcore/api 0.2.4 → 0.2.6
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/__tests__/common-test.utils.d.ts +12 -12
- package/dist/__tests__/common-test.utils.js +94 -101
- package/dist/__tests__/postgres.test-database.d.ts +2 -2
- package/dist/__tests__/postgres.test-database.js +16 -15
- package/dist/__tests__/test-objects.d.ts +1 -6
- package/dist/__tests__/test-objects.js +34 -73
- package/dist/config/base-api-config.d.ts +2 -2
- package/dist/config/base-api-config.js +17 -10
- package/dist/controllers/auth.controller.d.ts +3 -5
- package/dist/controllers/auth.controller.js +22 -26
- package/dist/controllers/index.d.ts +10 -11
- package/dist/controllers/index.js +10 -11
- package/dist/databases/mongo-db/migrations/mongo-initial-schema.d.ts +2 -2
- package/dist/databases/mongo-db/migrations/mongo-initial-schema.js +185 -128
- package/dist/services/auth.service.d.ts +8 -9
- package/dist/services/auth.service.js +66 -82
- package/dist/services/email.service.js +5 -5
- package/dist/services/jwt.service.js +2 -2
- package/dist/services/multi-tenant-api.service.d.ts +4 -4
- package/dist/services/multi-tenant-api.service.js +8 -8
- package/dist/services/organization.service.d.ts +4 -4
- package/dist/services/organization.service.js +12 -8
- package/dist/services/password-reset-token.service.d.ts +4 -4
- package/dist/services/password-reset-token.service.js +13 -9
- package/dist/services/tenant-query-decorator.d.ts +1 -1
- package/dist/services/tenant-query-decorator.js +17 -11
- package/dist/services/user.service.d.ts +6 -6
- package/dist/services/user.service.js +7 -7
- package/dist/services/utils/audit-for-create.util.d.ts +1 -1
- package/dist/services/utils/audit-for-update.util.d.ts +1 -1
- package/dist/services/utils/audit-for-update.util.js +0 -1
- package/dist/services/utils/getUserContextAuthorizations.util.d.ts +2 -2
- package/dist/services/utils/strip-sender-provided-system-properties.util.d.ts +1 -1
- package/dist/services/utils/strip-sender-provided-system-properties.util.js +5 -3
- package/package.json +5 -2
- package/dist/controllers/persons.controller.d.ts +0 -8
- package/dist/controllers/persons.controller.js +0 -18
- package/dist/services/person.service.d.ts +0 -6
- package/dist/services/person.service.js +0 -7
|
@@ -1,133 +1,94 @@
|
|
|
1
|
-
export let TEST_META_ORG_ID =
|
|
2
|
-
export let TEST_META_ORG_USER_ID =
|
|
3
|
-
export let TEST_META_ORG_USER_PERSON_ID = '69261672f48fb7bf76e54dfc';
|
|
1
|
+
export let TEST_META_ORG_ID = "69261691f936c45f85da24d0";
|
|
2
|
+
export let TEST_META_ORG_USER_ID = "69261672f48fb7bf76e54dfb";
|
|
4
3
|
export function setTestMetaOrgId(metaOrgId) {
|
|
5
4
|
TEST_META_ORG_ID = metaOrgId;
|
|
6
5
|
}
|
|
7
6
|
export function setTestMetaOrgUserId(userId) {
|
|
8
7
|
TEST_META_ORG_USER_ID = userId;
|
|
9
8
|
}
|
|
10
|
-
export
|
|
11
|
-
TEST_META_ORG_USER_PERSON_ID = personId;
|
|
12
|
-
}
|
|
13
|
-
export const TEST_META_ORG_USER_PASSWORD = 'test-meta-org-user-password';
|
|
9
|
+
export const TEST_META_ORG_USER_PASSWORD = "test-meta-org-user-password";
|
|
14
10
|
export function getTestMetaOrg() {
|
|
15
11
|
return {
|
|
16
12
|
_id: TEST_META_ORG_ID,
|
|
17
|
-
name:
|
|
18
|
-
code:
|
|
13
|
+
name: "Test Meta Organization",
|
|
14
|
+
code: "test-meta-org",
|
|
19
15
|
status: 1,
|
|
20
16
|
isMetaOrg: true,
|
|
21
17
|
_created: new Date(),
|
|
22
|
-
_createdBy:
|
|
18
|
+
_createdBy: "system",
|
|
23
19
|
};
|
|
24
20
|
}
|
|
25
|
-
;
|
|
26
21
|
export function getTestMetaOrgUser() {
|
|
27
22
|
return {
|
|
28
23
|
_id: TEST_META_ORG_USER_ID,
|
|
29
24
|
_orgId: getTestMetaOrg()._id,
|
|
30
|
-
externalId:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
displayName: 'Test User',
|
|
25
|
+
externalId: "test-meta-org-user-external-id",
|
|
26
|
+
email: "test@example.com",
|
|
27
|
+
displayName: "Test User",
|
|
34
28
|
password: TEST_META_ORG_USER_PASSWORD,
|
|
35
29
|
_created: new Date(),
|
|
36
|
-
_createdBy:
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
export function getTestMetaOrgUserPerson() {
|
|
40
|
-
const person = {
|
|
41
|
-
_id: TEST_META_ORG_USER_PERSON_ID,
|
|
42
|
-
_orgId: getTestMetaOrg()._id,
|
|
43
|
-
externalId: 'test-meta-org-user-person-external-id',
|
|
44
|
-
firstName: 'Test',
|
|
45
|
-
lastName: 'User',
|
|
46
|
-
isAgent: false,
|
|
47
|
-
isClient: false,
|
|
48
|
-
isEmployee: false,
|
|
49
|
-
_created: new Date(),
|
|
50
|
-
_createdBy: 'system',
|
|
30
|
+
_createdBy: "system",
|
|
51
31
|
};
|
|
52
|
-
return person;
|
|
53
32
|
}
|
|
54
33
|
export function getTestMetaOrgUserContext() {
|
|
55
34
|
return {
|
|
56
35
|
user: getTestMetaOrgUser(),
|
|
57
36
|
organization: getTestMetaOrg(),
|
|
58
|
-
authorizations: [
|
|
59
|
-
|
|
37
|
+
authorizations: [
|
|
38
|
+
{
|
|
39
|
+
_id: "6939c54e57a1c6576a40c590",
|
|
60
40
|
_orgId: getTestMetaOrg()._id,
|
|
61
|
-
role:
|
|
62
|
-
feature:
|
|
41
|
+
role: "metaorgUser",
|
|
42
|
+
feature: "metaorgUser",
|
|
63
43
|
config: {},
|
|
64
|
-
}
|
|
44
|
+
},
|
|
45
|
+
],
|
|
65
46
|
};
|
|
66
47
|
}
|
|
67
|
-
;
|
|
68
|
-
let
|
|
69
|
-
let TEST_ORG_USER_ID = '6926167d06c0073a778a1250';
|
|
70
|
-
let TEST_ORG_USER_PERSON_ID = '6926167d06c0073a778a1251';
|
|
48
|
+
let TEST_ORG_ID = "6926167d06c0073a778a124f";
|
|
49
|
+
let TEST_ORG_USER_ID = "6926167d06c0073a778a1250";
|
|
71
50
|
export function setTestOrgId(orgId) {
|
|
72
51
|
TEST_ORG_ID = orgId;
|
|
73
52
|
}
|
|
74
53
|
export function setTestOrgUserId(userId) {
|
|
75
54
|
TEST_ORG_USER_ID = userId;
|
|
76
55
|
}
|
|
77
|
-
export function setTestOrgUserPersonId(personId) {
|
|
78
|
-
TEST_ORG_USER_PERSON_ID = personId;
|
|
79
|
-
}
|
|
80
56
|
export function getTestOrg() {
|
|
81
57
|
return {
|
|
82
58
|
_id: TEST_ORG_ID,
|
|
83
|
-
name:
|
|
84
|
-
code:
|
|
59
|
+
name: "Test Organization",
|
|
60
|
+
code: "test-org",
|
|
85
61
|
status: 1,
|
|
86
62
|
isMetaOrg: false,
|
|
87
63
|
_created: new Date(),
|
|
88
|
-
_createdBy:
|
|
64
|
+
_createdBy: "system",
|
|
89
65
|
};
|
|
90
66
|
}
|
|
91
|
-
;
|
|
92
|
-
export const TEST_ORG_USER_PASSWORD = 'test-org-user-password';
|
|
67
|
+
export const TEST_ORG_USER_PASSWORD = "test-org-user-password";
|
|
93
68
|
export function getTestOrgUser() {
|
|
94
69
|
return {
|
|
95
70
|
_id: TEST_ORG_USER_ID,
|
|
96
71
|
_orgId: getTestOrg()._id,
|
|
97
|
-
externalId:
|
|
98
|
-
email:
|
|
99
|
-
|
|
100
|
-
displayName: 'Test User',
|
|
72
|
+
externalId: "test-org-user-external-id",
|
|
73
|
+
email: "test-org-user@example.com",
|
|
74
|
+
displayName: "Test User",
|
|
101
75
|
password: TEST_ORG_USER_PASSWORD,
|
|
102
76
|
_created: new Date(),
|
|
103
|
-
_createdBy:
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
export function getTestOrgUserPerson() {
|
|
107
|
-
return {
|
|
108
|
-
_id: TEST_ORG_USER_PERSON_ID,
|
|
109
|
-
_orgId: getTestOrg()._id,
|
|
110
|
-
externalId: 'test-org-user-person-external-id',
|
|
111
|
-
firstName: 'Test',
|
|
112
|
-
lastName: 'User',
|
|
113
|
-
isAgent: false,
|
|
114
|
-
isClient: false,
|
|
115
|
-
isEmployee: false,
|
|
116
|
-
_created: new Date(),
|
|
117
|
-
_createdBy: 'system',
|
|
77
|
+
_createdBy: "system",
|
|
118
78
|
};
|
|
119
79
|
}
|
|
120
80
|
export function getTestOrgUserContext() {
|
|
121
81
|
return {
|
|
122
82
|
user: getTestOrgUser(),
|
|
123
83
|
organization: getTestOrg(),
|
|
124
|
-
authorizations: [
|
|
125
|
-
|
|
84
|
+
authorizations: [
|
|
85
|
+
{
|
|
86
|
+
_id: "6939c54e57a1c6576a40c591",
|
|
126
87
|
_orgId: getTestOrg()._id,
|
|
127
|
-
role:
|
|
128
|
-
feature:
|
|
88
|
+
role: "testOrgUser",
|
|
89
|
+
feature: "testOrgUser",
|
|
129
90
|
config: {},
|
|
130
|
-
}
|
|
91
|
+
},
|
|
92
|
+
],
|
|
131
93
|
};
|
|
132
94
|
}
|
|
133
|
-
;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { IDatabase } from "../databases/models/index.js";
|
|
2
|
+
import { IBaseApiConfig } from "../models/index.js";
|
|
3
3
|
export declare let config: IBaseApiConfig;
|
|
4
4
|
export declare function setBaseApiConfig(theConfig: IBaseApiConfig): void;
|
|
5
5
|
export declare function initSystemUserContext(database: IDatabase): Promise<void>;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import { EmptyUserContext, initializeSystemUserContext } from
|
|
1
|
+
import { EmptyUserContext, initializeSystemUserContext, } from "@loomcore/common/models";
|
|
2
2
|
export let config;
|
|
3
3
|
let isConfigSet = false;
|
|
4
4
|
let isSystemUserContextSet = false;
|
|
5
5
|
const BASE_API_CONFIG_KEYS = [
|
|
6
|
-
|
|
6
|
+
"app",
|
|
7
|
+
"auth",
|
|
8
|
+
"database",
|
|
9
|
+
"debug",
|
|
10
|
+
"email",
|
|
11
|
+
"env",
|
|
12
|
+
"network",
|
|
13
|
+
"thirdPartyClients",
|
|
7
14
|
];
|
|
8
15
|
function copyOnlySpecifiedConfigProperties(obj, allowedKeys) {
|
|
9
16
|
const result = {};
|
|
@@ -19,29 +26,29 @@ export function setBaseApiConfig(theConfig) {
|
|
|
19
26
|
config = copyOnlySpecifiedConfigProperties(theConfig, BASE_API_CONFIG_KEYS);
|
|
20
27
|
isConfigSet = true;
|
|
21
28
|
}
|
|
22
|
-
else if (config.env !==
|
|
23
|
-
console.warn(
|
|
29
|
+
else if (config.env !== "test") {
|
|
30
|
+
console.warn("BaseApiConfig data has already been set. Ignoring subsequent calls to setBaseApiConfig.");
|
|
24
31
|
}
|
|
25
32
|
}
|
|
26
33
|
export async function initSystemUserContext(database) {
|
|
27
34
|
if (!isConfigSet) {
|
|
28
|
-
throw new Error(
|
|
35
|
+
throw new Error("BaseApiConfig has not been set. Call setBaseApiConfig first.");
|
|
29
36
|
}
|
|
30
37
|
if (!isSystemUserContextSet) {
|
|
31
|
-
const systemEmail = config.email?.systemEmailAddress ||
|
|
38
|
+
const systemEmail = config.email?.systemEmailAddress || "system@example.com";
|
|
32
39
|
let metaOrg = undefined;
|
|
33
40
|
if (config.app.isMultiTenant) {
|
|
34
|
-
const { OrganizationService } = await import(
|
|
41
|
+
const { OrganizationService } = await import("../services/organization.service.js");
|
|
35
42
|
const organizationService = new OrganizationService(database);
|
|
36
43
|
metaOrg = await organizationService.getMetaOrg(EmptyUserContext);
|
|
37
44
|
if (!metaOrg) {
|
|
38
|
-
throw new Error(
|
|
45
|
+
throw new Error("Meta organization not found. Please create an organization with isMetaOrg=true before starting the API.");
|
|
39
46
|
}
|
|
40
47
|
}
|
|
41
48
|
initializeSystemUserContext(systemEmail, metaOrg);
|
|
42
49
|
isSystemUserContextSet = true;
|
|
43
50
|
}
|
|
44
|
-
else if (config.env !==
|
|
45
|
-
console.warn(
|
|
51
|
+
else if (config.env !== "test") {
|
|
52
|
+
console.warn("SystemUserContext has already been set. Ignoring subsequent calls to initSystemUserContext.");
|
|
46
53
|
}
|
|
47
54
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { Application, Request, Response
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { PersonService } from '../services/person.service.js';
|
|
1
|
+
import type { Application, NextFunction, Request, Response } from "express";
|
|
2
|
+
import type { IDatabase } from "../databases/models/index.js";
|
|
3
|
+
import { AuthService } from "../services/index.js";
|
|
5
4
|
export declare class AuthController {
|
|
6
5
|
authService: AuthService;
|
|
7
|
-
personService: PersonService;
|
|
8
6
|
constructor(app: Application, database: IDatabase);
|
|
9
7
|
mapRoutes(app: Application): void;
|
|
10
8
|
login(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import { LoginResponseSpec,
|
|
2
|
-
import { entityUtils } from
|
|
3
|
-
import { BadRequestError, UnauthenticatedError } from
|
|
4
|
-
import {
|
|
5
|
-
import { AuthService } from
|
|
6
|
-
import {
|
|
7
|
-
import { PersonService } from '../services/person.service.js';
|
|
1
|
+
import { LoginResponseSpec, PublicUserContextSpec, PublicUserSpec, passwordValidator, TokenResponseSpec, UserSpec, } from "@loomcore/common/models";
|
|
2
|
+
import { entityUtils } from "@loomcore/common/utils";
|
|
3
|
+
import { BadRequestError, UnauthenticatedError } from "../errors/index.js";
|
|
4
|
+
import { isAuthorized } from "../middleware/index.js";
|
|
5
|
+
import { AuthService } from "../services/index.js";
|
|
6
|
+
import { apiUtils } from "../utils/index.js";
|
|
8
7
|
export class AuthController {
|
|
9
8
|
authService;
|
|
10
|
-
personService;
|
|
11
9
|
constructor(app, database) {
|
|
12
10
|
this.authService = new AuthService(database);
|
|
13
|
-
this.personService = new PersonService(database);
|
|
14
11
|
this.mapRoutes(app);
|
|
15
12
|
}
|
|
16
13
|
mapRoutes(app) {
|
|
@@ -24,29 +21,25 @@ export class AuthController {
|
|
|
24
21
|
}
|
|
25
22
|
async login(req, res, next) {
|
|
26
23
|
const { email, password } = req.body;
|
|
27
|
-
res.set(
|
|
24
|
+
res.set("Content-Type", "application/json");
|
|
28
25
|
const loginResponse = await this.authService.attemptLogin(req, res, email, password);
|
|
29
26
|
apiUtils.apiResponse(res, 200, { data: loginResponse }, LoginResponseSpec);
|
|
30
27
|
}
|
|
31
28
|
async registerUser(req, res) {
|
|
32
29
|
const userContext = req.userContext;
|
|
33
30
|
if (!userContext) {
|
|
34
|
-
throw new BadRequestError(
|
|
31
|
+
throw new BadRequestError("Missing required fields: userContext is required.");
|
|
35
32
|
}
|
|
36
33
|
const body = req.body;
|
|
37
|
-
|
|
38
|
-
entityUtils.handleValidationResult(validationErrors,
|
|
39
|
-
|
|
40
|
-
validationErrors = this.personService.validate(body.person);
|
|
41
|
-
entityUtils.handleValidationResult(validationErrors, 'AuthController.registerUser');
|
|
42
|
-
}
|
|
43
|
-
const user = await this.authService.createUser(userContext, body.user, body.person);
|
|
34
|
+
const validationErrors = this.authService.validate(body.user);
|
|
35
|
+
entityUtils.handleValidationResult(validationErrors, "AuthController.registerUser");
|
|
36
|
+
const user = await this.authService.createUser(userContext, body.user);
|
|
44
37
|
apiUtils.apiResponse(res, 201, { data: user || undefined }, UserSpec, PublicUserSpec);
|
|
45
38
|
}
|
|
46
39
|
async requestTokenUsingRefreshToken(req, res, next) {
|
|
47
40
|
const refreshToken = req.query.refreshToken;
|
|
48
|
-
if (!refreshToken || typeof refreshToken !==
|
|
49
|
-
throw new BadRequestError(
|
|
41
|
+
if (!refreshToken || typeof refreshToken !== "string") {
|
|
42
|
+
throw new BadRequestError("Missing required fields: refreshToken is required.");
|
|
50
43
|
}
|
|
51
44
|
const deviceId = this.authService.getDeviceIdFromCookie(req);
|
|
52
45
|
const tokens = await this.authService.requestTokenUsingRefreshToken(refreshToken, deviceId);
|
|
@@ -62,23 +55,26 @@ export class AuthController {
|
|
|
62
55
|
apiUtils.apiResponse(res, 200, { data: userContext }, PublicUserContextSpec);
|
|
63
56
|
}
|
|
64
57
|
afterAuth(req, res, loginResponse) {
|
|
65
|
-
console.log(
|
|
58
|
+
console.log("in afterAuth");
|
|
66
59
|
}
|
|
67
60
|
async changePassword(req, res) {
|
|
68
61
|
const userContext = req.userContext;
|
|
62
|
+
if (!userContext) {
|
|
63
|
+
throw new BadRequestError("Missing required fields: userContext is required.");
|
|
64
|
+
}
|
|
69
65
|
const body = req.body;
|
|
70
66
|
const validationErrors = entityUtils.validate(UserSpec, { password: body.password }, true, passwordValidator);
|
|
71
|
-
entityUtils.handleValidationResult(validationErrors,
|
|
67
|
+
entityUtils.handleValidationResult(validationErrors, "AuthController.changePassword");
|
|
72
68
|
const updateResult = await this.authService.changeLoggedInUsersPassword(userContext, body);
|
|
73
69
|
apiUtils.apiResponse(res, 200, { data: updateResult });
|
|
74
70
|
}
|
|
75
71
|
async forgotPassword(req, res) {
|
|
76
72
|
const email = req.body?.email;
|
|
77
|
-
let referer = req.get(
|
|
73
|
+
let referer = req.get("referer") || req.headers.referer;
|
|
78
74
|
if (!referer) {
|
|
79
|
-
throw new BadRequestError(
|
|
75
|
+
throw new BadRequestError("Missing required fields: referer is required.");
|
|
80
76
|
}
|
|
81
|
-
referer = referer.replace(/\/$/,
|
|
77
|
+
referer = referer.replace(/\/$/, "");
|
|
82
78
|
const user = await this.authService.getUserByEmail(email);
|
|
83
79
|
if (user) {
|
|
84
80
|
await this.authService.sendResetPasswordEmail(email, referer);
|
|
@@ -88,7 +84,7 @@ export class AuthController {
|
|
|
88
84
|
async resetPassword(req, res) {
|
|
89
85
|
const { email, token, password } = req.body;
|
|
90
86
|
if (!email || !token || !password) {
|
|
91
|
-
throw new BadRequestError(
|
|
87
|
+
throw new BadRequestError("Missing required fields: email, token, and password are required.");
|
|
92
88
|
}
|
|
93
89
|
const response = await this.authService.resetPassword(email, token, password);
|
|
94
90
|
apiUtils.apiResponse(res, 200, { data: response });
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
11
|
-
export * from './types.js';
|
|
1
|
+
export * from "./api.controller.js";
|
|
2
|
+
export * from "./auth.controller.js";
|
|
3
|
+
export * from "./authorizations.controller.js";
|
|
4
|
+
export * from "./features.controller.js";
|
|
5
|
+
export * from "./organizations.controller.js";
|
|
6
|
+
export * from "./query-api.controller.js";
|
|
7
|
+
export * from "./roles.controller.js";
|
|
8
|
+
export * from "./types.js";
|
|
9
|
+
export * from "./user-roles.controller.js";
|
|
10
|
+
export * from "./users.controller.js";
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
11
|
-
export * from './types.js';
|
|
1
|
+
export * from "./api.controller.js";
|
|
2
|
+
export * from "./auth.controller.js";
|
|
3
|
+
export * from "./authorizations.controller.js";
|
|
4
|
+
export * from "./features.controller.js";
|
|
5
|
+
export * from "./organizations.controller.js";
|
|
6
|
+
export * from "./query-api.controller.js";
|
|
7
|
+
export * from "./roles.controller.js";
|
|
8
|
+
export * from "./types.js";
|
|
9
|
+
export * from "./user-roles.controller.js";
|
|
10
|
+
export * from "./users.controller.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Db } from
|
|
2
|
-
import { IInitialDbMigrationConfig } from
|
|
1
|
+
import { Db } from "mongodb";
|
|
2
|
+
import { IInitialDbMigrationConfig } from "../../../models/initial-database-config.interface.js";
|
|
3
3
|
export interface ISyntheticMigration {
|
|
4
4
|
name: string;
|
|
5
5
|
up: (context: {
|