@loomcore/api 0.2.5 → 0.2.7
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 +4 -4
- package/dist/__tests__/common-test.utils.js +2 -15
- package/dist/__tests__/test-objects.d.ts +1 -6
- package/dist/__tests__/test-objects.js +34 -73
- 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/services/auth.service.d.ts +2 -3
- package/dist/services/auth.service.js +8 -37
- 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
|
@@ -5,10 +5,10 @@ import { IDatabase } from "../databases/models/index.js";
|
|
|
5
5
|
import { Operation } from "../databases/operations/operation.js";
|
|
6
6
|
import { GenericApiService } from "../services/index.js";
|
|
7
7
|
import { MultiTenantApiService } from "../services/multi-tenant-api.service.js";
|
|
8
|
-
import { DbType } from "../databases/db-type.type.js";
|
|
9
|
-
import { ICategory } from "./models/category.model.js";
|
|
10
|
-
import { IProduct } from "./models/product.model.js";
|
|
11
|
-
import { IProductWithCategory } from "./models/product-with-category.model.js";
|
|
8
|
+
import type { DbType } from "../databases/db-type.type.js";
|
|
9
|
+
import { type ICategory } from "./models/category.model.js";
|
|
10
|
+
import { type IProduct } from "./models/product.model.js";
|
|
11
|
+
import { type IProductWithCategory } from "./models/product-with-category.model.js";
|
|
12
12
|
declare function initialize(database: IDatabase): void;
|
|
13
13
|
declare function getRandomId(): string;
|
|
14
14
|
declare function isMongoDatabase(database: IDatabase): boolean;
|
|
@@ -16,24 +16,21 @@ import * as testObjectsModule from "./test-objects.js";
|
|
|
16
16
|
const { getTestMetaOrg, getTestOrg, getTestMetaOrgUser, getTestMetaOrgUserContext, getTestOrgUserContext, setTestOrgId, setTestMetaOrgId, setTestMetaOrgUserId, setTestOrgUserId, } = testObjectsModule;
|
|
17
17
|
import { entityUtils } from "@loomcore/common/utils";
|
|
18
18
|
import { config, setBaseApiConfig } from "../config/index.js";
|
|
19
|
-
import { PersonService } from "../services/person.service.js";
|
|
20
19
|
import { apiUtils } from "../utils/index.js";
|
|
21
20
|
import { CategorySpec } from "./models/category.model.js";
|
|
22
21
|
import { ProductSpec } from "./models/product.model.js";
|
|
23
22
|
import { ProductWithCategoryPublicSpec, ProductWithCategorySpec, } from "./models/product-with-category.model.js";
|
|
24
23
|
import { TestEmailClient } from "./test-email-client.js";
|
|
25
|
-
import {
|
|
24
|
+
import { getTestOrgUser } from "./test-objects.js";
|
|
26
25
|
let deviceIdCookie;
|
|
27
26
|
let authService;
|
|
28
27
|
let organizationService;
|
|
29
|
-
let personService;
|
|
30
28
|
const JWT_SECRET = "test-secret";
|
|
31
29
|
const newUser1Email = "one@test.com";
|
|
32
30
|
const newUser1Password = "testone";
|
|
33
31
|
const constDeviceIdCookie = crypto.randomBytes(16).toString("hex");
|
|
34
32
|
function initialize(database) {
|
|
35
33
|
authService = new AuthService(database);
|
|
36
|
-
personService = new PersonService(database);
|
|
37
34
|
organizationService = new OrganizationService(database);
|
|
38
35
|
deviceIdCookie = constDeviceIdCookie;
|
|
39
36
|
}
|
|
@@ -98,7 +95,7 @@ async function setupTestUsers() {
|
|
|
98
95
|
}
|
|
99
96
|
}
|
|
100
97
|
async function createTestUsers() {
|
|
101
|
-
if (!authService || !organizationService
|
|
98
|
+
if (!authService || !organizationService) {
|
|
102
99
|
throw new Error("Database not initialized. Call initialize() first.");
|
|
103
100
|
}
|
|
104
101
|
try {
|
|
@@ -118,16 +115,6 @@ async function createTestUsers() {
|
|
|
118
115
|
else {
|
|
119
116
|
setTestOrgId(existingTestOrg._id);
|
|
120
117
|
}
|
|
121
|
-
const createdTestOrgUserPerson = await personService.create(getTestOrgUserContext(), getTestOrgUserPerson());
|
|
122
|
-
if (!createdTestOrgUserPerson) {
|
|
123
|
-
throw new Error("Failed to create test organization user person");
|
|
124
|
-
}
|
|
125
|
-
setTestOrgUserPersonId(createdTestOrgUserPerson._id);
|
|
126
|
-
const createdMetaOrgUserPerson = await personService.create(getTestMetaOrgUserContext(), getTestMetaOrgUserPerson());
|
|
127
|
-
if (!createdMetaOrgUserPerson) {
|
|
128
|
-
throw new Error("Failed to create meta organization user person");
|
|
129
|
-
}
|
|
130
|
-
setTestMetaOrgUserPersonId(createdMetaOrgUserPerson._id);
|
|
131
118
|
const createdTestOrgUser = await authService.createUser(getTestOrgUserContext(), getTestOrgUser());
|
|
132
119
|
const createdMetaOrgUser = await authService.createUser(getTestMetaOrgUserContext(), getTestMetaOrgUser());
|
|
133
120
|
if (!createdTestOrgUser || !createdMetaOrgUser) {
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
import { IOrganization,
|
|
1
|
+
import type { IOrganization, IUser, IUserContext } from "@loomcore/common/models";
|
|
2
2
|
export declare let TEST_META_ORG_ID: string | number;
|
|
3
3
|
export declare let TEST_META_ORG_USER_ID: string | number;
|
|
4
|
-
export declare let TEST_META_ORG_USER_PERSON_ID: string | number;
|
|
5
4
|
export declare function setTestMetaOrgId(metaOrgId: string | number): void;
|
|
6
5
|
export declare function setTestMetaOrgUserId(userId: string | number): void;
|
|
7
|
-
export declare function setTestMetaOrgUserPersonId(personId: string | number): void;
|
|
8
6
|
export declare const TEST_META_ORG_USER_PASSWORD = "test-meta-org-user-password";
|
|
9
7
|
export declare function getTestMetaOrg(): IOrganization;
|
|
10
8
|
export declare function getTestMetaOrgUser(): IUser;
|
|
11
|
-
export declare function getTestMetaOrgUserPerson(): IPersonModel;
|
|
12
9
|
export declare function getTestMetaOrgUserContext(): IUserContext;
|
|
13
10
|
export declare function setTestOrgId(orgId: string | number): void;
|
|
14
11
|
export declare function setTestOrgUserId(userId: string | number): void;
|
|
15
|
-
export declare function setTestOrgUserPersonId(personId: string | number): void;
|
|
16
12
|
export declare function getTestOrg(): IOrganization;
|
|
17
13
|
export declare const TEST_ORG_USER_PASSWORD = "test-org-user-password";
|
|
18
14
|
export declare function getTestOrgUser(): IUser;
|
|
19
|
-
export declare function getTestOrgUserPerson(): IPersonModel;
|
|
20
15
|
export declare function getTestOrgUserContext(): IUserContext;
|
|
@@ -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,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,4 +1,4 @@
|
|
|
1
|
-
import { type ILoginResponse, type
|
|
1
|
+
import { type ILoginResponse, type ITokenResponse, type IUser, type IUserContext } from "@loomcore/common/models";
|
|
2
2
|
import type { AppIdType } from "@loomcore/common/types";
|
|
3
3
|
import type { Request, Response } from "express";
|
|
4
4
|
import type { IDatabase } from "../databases/models/index.js";
|
|
@@ -11,7 +11,6 @@ export declare class AuthService extends MultiTenantApiService<IUser> {
|
|
|
11
11
|
private emailService;
|
|
12
12
|
private organizationService;
|
|
13
13
|
private authConfig;
|
|
14
|
-
private personService;
|
|
15
14
|
constructor(database: IDatabase);
|
|
16
15
|
attemptLogin(req: Request, res: Response, email: string, password: string): Promise<ILoginResponse | null>;
|
|
17
16
|
logUserIn(userContext: IUserContext, deviceId: string): Promise<{
|
|
@@ -23,7 +22,7 @@ export declare class AuthService extends MultiTenantApiService<IUser> {
|
|
|
23
22
|
userContext: IUserContext;
|
|
24
23
|
} | null>;
|
|
25
24
|
getUserByEmail(email: string): Promise<IUser | null>;
|
|
26
|
-
createUser(userContext: IUserContext, user: Partial<IUser
|
|
25
|
+
createUser(userContext: IUserContext, user: Partial<IUser>): Promise<IUser | null>;
|
|
27
26
|
requestTokenUsingRefreshToken(refreshToken: string, deviceId: string): Promise<ITokenResponse | null>;
|
|
28
27
|
changeLoggedInUsersPassword(userContext: IUserContext, body: any): Promise<UpdateResult>;
|
|
29
28
|
changePassword(userContext: IUserContext, queryObject: any, password: string): Promise<UpdateResult>;
|
|
@@ -10,7 +10,6 @@ import { EmailService, JwtService } from "./index.js";
|
|
|
10
10
|
import { MultiTenantApiService } from "./multi-tenant-api.service.js";
|
|
11
11
|
import { OrganizationService } from "./organization.service.js";
|
|
12
12
|
import { PasswordResetTokenService } from "./password-reset-token.service.js";
|
|
13
|
-
import { PersonService } from "./person.service.js";
|
|
14
13
|
import { getUserContextAuthorizations } from "./utils/getUserContextAuthorizations.util.js";
|
|
15
14
|
export class AuthService extends MultiTenantApiService {
|
|
16
15
|
refreshTokenService;
|
|
@@ -18,14 +17,12 @@ export class AuthService extends MultiTenantApiService {
|
|
|
18
17
|
emailService;
|
|
19
18
|
organizationService;
|
|
20
19
|
authConfig;
|
|
21
|
-
personService;
|
|
22
20
|
constructor(database) {
|
|
23
21
|
super(database, "users", "user", UserSpec);
|
|
24
22
|
this.refreshTokenService = new MultiTenantApiService(database, "refresh_tokens", "refresh_token", refreshTokenModelSpec);
|
|
25
23
|
this.passwordResetTokenService = new PasswordResetTokenService(database);
|
|
26
24
|
this.emailService = new EmailService();
|
|
27
25
|
this.organizationService = new OrganizationService(database);
|
|
28
|
-
this.personService = new PersonService(database);
|
|
29
26
|
if (!config.auth) {
|
|
30
27
|
throw new ServerError("Auth configuration is not set");
|
|
31
28
|
}
|
|
@@ -42,13 +39,9 @@ export class AuthService extends MultiTenantApiService {
|
|
|
42
39
|
if (!passwordsMatch) {
|
|
43
40
|
throw new BadRequestError("Invalid Credentials");
|
|
44
41
|
}
|
|
45
|
-
const person = await this.personService.findOne(getSystemUserContext(), {
|
|
46
|
-
filters: { _id: { eq: user.personId } },
|
|
47
|
-
});
|
|
48
42
|
const authorizations = await getUserContextAuthorizations(this.database, user);
|
|
49
43
|
const userContext = {
|
|
50
44
|
user: user,
|
|
51
|
-
person: person ?? undefined,
|
|
52
45
|
organization: organization ?? undefined,
|
|
53
46
|
authorizations: authorizations,
|
|
54
47
|
};
|
|
@@ -82,7 +75,7 @@ export class AuthService extends MultiTenantApiService {
|
|
|
82
75
|
}
|
|
83
76
|
return this.database.postProcessEntity(rawUser, this.modelSpec.fullSchema);
|
|
84
77
|
}
|
|
85
|
-
async createUser(userContext, user
|
|
78
|
+
async createUser(userContext, user) {
|
|
86
79
|
if (userContext.user._id === "system") {
|
|
87
80
|
if (config.app.isMultiTenant &&
|
|
88
81
|
userContext.organization?._id !== user._orgId) {
|
|
@@ -103,20 +96,6 @@ export class AuthService extends MultiTenantApiService {
|
|
|
103
96
|
throw new BadRequestError("A user with this email address already exists");
|
|
104
97
|
}
|
|
105
98
|
}
|
|
106
|
-
let personId = user.personId;
|
|
107
|
-
if (personId && person) {
|
|
108
|
-
await this.personService.partialUpdateById(userContext, personId, person);
|
|
109
|
-
}
|
|
110
|
-
if (!personId && person) {
|
|
111
|
-
const newPerson = await this.personService.create(userContext, person);
|
|
112
|
-
if (newPerson) {
|
|
113
|
-
personId = newPerson._id;
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
throw new ServerError("authService.createUser: Failed to create person");
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
user.personId = personId;
|
|
120
99
|
return await this.create(userContext, user);
|
|
121
100
|
}
|
|
122
101
|
async requestTokenUsingRefreshToken(refreshToken, deviceId) {
|
|
@@ -125,23 +104,13 @@ export class AuthService extends MultiTenantApiService {
|
|
|
125
104
|
if (activeRefreshToken) {
|
|
126
105
|
const systemUserContext = getSystemUserContext();
|
|
127
106
|
const user = await this.getById(systemUserContext, activeRefreshToken.userId);
|
|
128
|
-
const person = await this.personService.findOne(systemUserContext, {
|
|
129
|
-
filters: { _id: { eq: user?.personId } },
|
|
130
|
-
});
|
|
131
107
|
const organization = await this.organizationService.findOne(EmptyUserContext, { filters: { _id: { eq: user?._orgId } } });
|
|
132
108
|
const authorizations = await getUserContextAuthorizations(this.database, user);
|
|
133
|
-
|
|
109
|
+
const userContext = {
|
|
134
110
|
user: user,
|
|
135
|
-
person: person ?? undefined,
|
|
136
111
|
organization: organization ?? undefined,
|
|
137
112
|
authorizations: authorizations,
|
|
138
113
|
};
|
|
139
|
-
if (user.personId) {
|
|
140
|
-
const person = await this.personService.getById(systemUserContext, user.personId);
|
|
141
|
-
if (person) {
|
|
142
|
-
userContext.person = person;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
114
|
tokens = await this.createNewTokens(userContext, activeRefreshToken);
|
|
146
115
|
}
|
|
147
116
|
return tokens;
|
|
@@ -197,7 +166,7 @@ export class AuthService extends MultiTenantApiService {
|
|
|
197
166
|
created: moment().utc().toDate(),
|
|
198
167
|
createdBy: userId,
|
|
199
168
|
};
|
|
200
|
-
|
|
169
|
+
await this.deleteRefreshTokensForDevice(deviceId);
|
|
201
170
|
const insertResult = await this.refreshTokenService.create(getSystemUserContext(), newRefreshToken);
|
|
202
171
|
return insertResult;
|
|
203
172
|
}
|
|
@@ -271,7 +240,7 @@ export class AuthService extends MultiTenantApiService {
|
|
|
271
240
|
return deviceId;
|
|
272
241
|
}
|
|
273
242
|
getDeviceIdFromCookie(req) {
|
|
274
|
-
return req.cookies
|
|
243
|
+
return req.cookies.deviceId;
|
|
275
244
|
}
|
|
276
245
|
getExpiresOnFromSeconds(expiresInSeconds) {
|
|
277
246
|
return Date.now() + expiresInSeconds * 1000;
|
|
@@ -284,7 +253,7 @@ export class AuthService extends MultiTenantApiService {
|
|
|
284
253
|
}
|
|
285
254
|
async preProcessEntity(userContext, entity, isCreate, allowId) {
|
|
286
255
|
if (entity.email) {
|
|
287
|
-
entity.email = entity.email
|
|
256
|
+
entity.email = entity.email?.toLowerCase();
|
|
288
257
|
}
|
|
289
258
|
if (entity.password) {
|
|
290
259
|
const hash = await passwordUtils.hashPassword(entity.password);
|
|
@@ -301,6 +270,8 @@ export class AuthService extends MultiTenantApiService {
|
|
|
301
270
|
const systemUserContext = getSystemUserContext();
|
|
302
271
|
await this.partialUpdateById(systemUserContext, userId, updates);
|
|
303
272
|
}
|
|
304
|
-
catch (error) {
|
|
273
|
+
catch (error) {
|
|
274
|
+
console.error(`Error updating lastLoggedIn: ${error}`);
|
|
275
|
+
}
|
|
305
276
|
}
|
|
306
277
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loomcore/api",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Loom Core Api - An opinionated Node.js api using Typescript, Express, and MongoDb or PostgreSQL",
|
|
6
6
|
"scripts": {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"qs": "^6.15.2"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@loomcore/common": "^0.0.
|
|
61
|
+
"@loomcore/common": "^0.0.72",
|
|
62
62
|
"@sinclair/typebox": "0.34.33",
|
|
63
63
|
"cookie-parser": "^1.4.6",
|
|
64
64
|
"cors": "^2.8.5",
|
|
@@ -87,5 +87,8 @@
|
|
|
87
87
|
"typescript": "^5.8.3",
|
|
88
88
|
"vite": "^6.2.5",
|
|
89
89
|
"vitest": "^3.0.9"
|
|
90
|
+
},
|
|
91
|
+
"overrides": {
|
|
92
|
+
"ajv": "^8.18.0"
|
|
90
93
|
}
|
|
91
94
|
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { IPersonModel } from "@loomcore/common/models";
|
|
2
|
-
import { ApiController } from "./api.controller.js";
|
|
3
|
-
import { Application } from "express";
|
|
4
|
-
import { IDatabase } from "../databases/models/index.js";
|
|
5
|
-
export declare class PersonsController extends ApiController<IPersonModel> {
|
|
6
|
-
constructor(app: Application, database: IDatabase);
|
|
7
|
-
mapRoutes(app: Application): void;
|
|
8
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { ApiController } from "./api.controller.js";
|
|
2
|
-
import { isAuthorized } from "../middleware/is-authorized.js";
|
|
3
|
-
import { PersonService } from "../services/person.service.js";
|
|
4
|
-
export class PersonsController extends ApiController {
|
|
5
|
-
constructor(app, database) {
|
|
6
|
-
const personService = new PersonService(database);
|
|
7
|
-
super('persons', app, personService);
|
|
8
|
-
}
|
|
9
|
-
mapRoutes(app) {
|
|
10
|
-
super.mapRoutes(app);
|
|
11
|
-
app.get('/api/persons', isAuthorized(), this.get.bind(this));
|
|
12
|
-
app.get('/api/persons/:id', isAuthorized(), this.getById.bind(this));
|
|
13
|
-
app.post('/api/persons', isAuthorized(), this.create.bind(this));
|
|
14
|
-
app.put('/api/persons/:id', isAuthorized(), this.fullUpdateById.bind(this));
|
|
15
|
-
app.patch('/api/persons/:id', isAuthorized(), this.partialUpdateById.bind(this));
|
|
16
|
-
app.delete('/api/persons/:id', isAuthorized(), this.deleteById.bind(this));
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type IPersonModel } from "@loomcore/common/models";
|
|
2
|
-
import type { IDatabase } from "../databases/models/index.js";
|
|
3
|
-
import { MultiTenantApiService } from "./multi-tenant-api.service.js";
|
|
4
|
-
export declare class PersonService extends MultiTenantApiService<IPersonModel> {
|
|
5
|
-
constructor(database: IDatabase);
|
|
6
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { personModelSpec } from "@loomcore/common/models";
|
|
2
|
-
import { MultiTenantApiService } from "./multi-tenant-api.service.js";
|
|
3
|
-
export class PersonService extends MultiTenantApiService {
|
|
4
|
-
constructor(database) {
|
|
5
|
-
super(database, "persons", "person", personModelSpec);
|
|
6
|
-
}
|
|
7
|
-
}
|