@loomcore/api 0.1.78 → 0.1.79
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/README.md +1 -1
- package/dist/__tests__/common-test.utils.js +5 -3
- package/dist/__tests__/postgres.test-database.js +2 -2
- package/dist/__tests__/test-objects.d.ts +6 -1
- package/dist/__tests__/test-objects.js +50 -4
- package/dist/controllers/auth.controller.d.ts +2 -0
- package/dist/controllers/auth.controller.js +9 -4
- package/dist/databases/mongo-db/migrations/mongo-initial-schema.js +23 -5
- package/dist/databases/operations/__tests__/models/{agent.model.d.ts → test-agent.model.d.ts} +5 -5
- package/dist/databases/operations/__tests__/models/test-agent.model.js +8 -0
- package/dist/databases/operations/__tests__/models/{client-report.model.d.ts → test-client-report.model.d.ts} +9 -9
- package/dist/databases/operations/__tests__/models/test-client-report.model.js +11 -0
- package/dist/databases/operations/__tests__/models/test-district.model.d.ts +12 -0
- package/dist/databases/operations/__tests__/models/{district.model.js → test-district.model.js} +2 -2
- package/dist/databases/operations/__tests__/models/{email-address.model.d.ts → test-email-address.model.d.ts} +3 -3
- package/dist/databases/operations/__tests__/models/{email-address.model.js → test-email-address.model.js} +2 -2
- package/dist/databases/operations/__tests__/models/{person.model.d.ts → test-person.model.d.ts} +9 -9
- package/dist/databases/operations/__tests__/models/test-person.model.js +12 -0
- package/dist/databases/operations/__tests__/models/{phone-number.model.d.ts → test-phone-number.model.d.ts} +3 -3
- package/dist/databases/operations/__tests__/models/{phone-number.model.js → test-phone-number.model.js} +2 -2
- package/dist/databases/operations/__tests__/models/{policy.model.d.ts → test-policy.model.d.ts} +7 -7
- package/dist/databases/operations/__tests__/models/test-policy.model.js +12 -0
- package/dist/databases/operations/__tests__/models/{premium.model.d.ts → test-premium.model.d.ts} +3 -3
- package/dist/databases/operations/__tests__/models/{premium.model.js → test-premium.model.js} +2 -2
- package/dist/databases/operations/__tests__/models/test-school.model.d.ts +12 -0
- package/dist/databases/operations/__tests__/models/{school.model.js → test-school.model.js} +2 -2
- package/dist/databases/operations/__tests__/models/test-state.model.d.ts +8 -0
- package/dist/databases/operations/__tests__/models/test-state.model.js +6 -0
- package/dist/databases/postgres/migrations/postgres-initial-schema.js +54 -16
- package/dist/services/auth.service.d.ts +3 -2
- package/dist/services/auth.service.js +15 -1
- package/dist/services/person.service.d.ts +6 -0
- package/dist/services/person.service.js +7 -0
- package/package.json +3 -3
- package/dist/databases/operations/__tests__/models/agent.model.js +0 -8
- package/dist/databases/operations/__tests__/models/client-report.model.js +0 -11
- package/dist/databases/operations/__tests__/models/district.model.d.ts +0 -12
- package/dist/databases/operations/__tests__/models/person.model.js +0 -12
- package/dist/databases/operations/__tests__/models/policy.model.js +0 -12
- package/dist/databases/operations/__tests__/models/school.model.d.ts +0 -12
- package/dist/databases/operations/__tests__/models/state.model.d.ts +0 -8
- package/dist/databases/operations/__tests__/models/state.model.js +0 -6
package/README.md
CHANGED
|
@@ -63,7 +63,7 @@ The test suite supports two modes for PostgreSQL testing:
|
|
|
63
63
|
npm run test:db:stop
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
The container uses port `
|
|
66
|
+
The container uses port `5444` to avoid conflicts with local PostgreSQL instances. Set `USE_REAL_POSTGRES=true` to use the container instead of pg-mem.
|
|
67
67
|
|
|
68
68
|
## Example Usage
|
|
69
69
|
|
|
@@ -17,7 +17,7 @@ import { CategorySpec } from './models/category.model.js';
|
|
|
17
17
|
import { ProductSpec } from './models/product.model.js';
|
|
18
18
|
import { setBaseApiConfig, config } from '../config/index.js';
|
|
19
19
|
import { entityUtils } from '@loomcore/common/utils';
|
|
20
|
-
import { getTestOrgUser } from './test-objects.js';
|
|
20
|
+
import { getTestMetaOrgUserPerson, getTestOrgUser, getTestOrgUserPerson, setTestMetaOrgUserPersonId, setTestOrgUserPersonId } from './test-objects.js';
|
|
21
21
|
import { TestEmailClient } from './test-email-client.js';
|
|
22
22
|
let deviceIdCookie;
|
|
23
23
|
let authService;
|
|
@@ -110,13 +110,15 @@ async function createTestUsers() {
|
|
|
110
110
|
else {
|
|
111
111
|
setTestOrgId(existingTestOrg._id);
|
|
112
112
|
}
|
|
113
|
-
const createdTestOrgUser = await authService.createUser(getTestOrgUserContext(), getTestOrgUser());
|
|
114
|
-
const createdMetaOrgUser = await authService.createUser(getTestMetaOrgUserContext(), getTestMetaOrgUser());
|
|
113
|
+
const createdTestOrgUser = await authService.createUser(getTestOrgUserContext(), getTestOrgUser(), getTestOrgUserPerson());
|
|
114
|
+
const createdMetaOrgUser = await authService.createUser(getTestMetaOrgUserContext(), getTestMetaOrgUser(), getTestMetaOrgUserPerson());
|
|
115
115
|
if (!createdTestOrgUser || !createdMetaOrgUser) {
|
|
116
116
|
throw new Error('Failed to create test user');
|
|
117
117
|
}
|
|
118
118
|
setTestMetaOrgUserId(createdMetaOrgUser._id);
|
|
119
|
+
setTestMetaOrgUserPersonId(createdMetaOrgUser.personId);
|
|
119
120
|
setTestOrgUserId(createdTestOrgUser._id);
|
|
121
|
+
setTestOrgUserPersonId(createdTestOrgUser.personId);
|
|
120
122
|
return { metaOrgUser: createdMetaOrgUser, testOrgUser: createdTestOrgUser };
|
|
121
123
|
}
|
|
122
124
|
catch (error) {
|
|
@@ -25,7 +25,7 @@ export class TestPostgresDatabase {
|
|
|
25
25
|
let postgresClient;
|
|
26
26
|
let pool;
|
|
27
27
|
if (USE_REAL_POSTGRES) {
|
|
28
|
-
const connectionString = `postgresql://test-user:test-password@localhost:
|
|
28
|
+
const connectionString = `postgresql://test-user:test-password@localhost:5444/test-db`;
|
|
29
29
|
postgresClient = new Client({
|
|
30
30
|
connectionString,
|
|
31
31
|
connectionTimeoutMillis: 5000,
|
|
@@ -43,7 +43,7 @@ export class TestPostgresDatabase {
|
|
|
43
43
|
`3. Try: docker ps (to verify Docker access)\n` +
|
|
44
44
|
`Original error: ${errorMessage}`);
|
|
45
45
|
}
|
|
46
|
-
throw new Error(`Failed to connect to PostgreSQL test container at localhost:
|
|
46
|
+
throw new Error(`Failed to connect to PostgreSQL test container at localhost:5444.\n` +
|
|
47
47
|
`Make sure the container is running: npm run test:db:start\n` +
|
|
48
48
|
`Check container status: docker ps | grep postgres-test\n` +
|
|
49
49
|
`View container logs: npm run test:db:logs\n` +
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
import { IOrganization, IUserContext, IUser } from "@loomcore/common/models";
|
|
1
|
+
import { IOrganization, IUserContext, IUser, IPersonModel } 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;
|
|
4
5
|
export declare function setTestMetaOrgId(metaOrgId: string | number): void;
|
|
5
6
|
export declare function setTestMetaOrgUserId(userId: string | number): void;
|
|
7
|
+
export declare function setTestMetaOrgUserPersonId(personId: string | number): void;
|
|
6
8
|
export declare const TEST_META_ORG_USER_PASSWORD = "test-meta-org-user-password";
|
|
7
9
|
export declare function getTestMetaOrg(): IOrganization;
|
|
8
10
|
export declare function getTestMetaOrgUser(): IUser;
|
|
11
|
+
export declare function getTestMetaOrgUserPerson(): IPersonModel;
|
|
9
12
|
export declare function getTestMetaOrgUserContext(): IUserContext;
|
|
10
13
|
export declare function setTestOrgId(orgId: string | number): void;
|
|
11
14
|
export declare function setTestOrgUserId(userId: string | number): void;
|
|
15
|
+
export declare function setTestOrgUserPersonId(personId: string | number): void;
|
|
12
16
|
export declare function getTestOrg(): IOrganization;
|
|
13
17
|
export declare const TEST_ORG_USER_PASSWORD = "test-org-user-password";
|
|
14
18
|
export declare function getTestOrgUser(): IUser;
|
|
19
|
+
export declare function getTestOrgUserPerson(): IPersonModel;
|
|
15
20
|
export declare function getTestOrgUserContext(): IUserContext;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
export let TEST_META_ORG_ID = '69261691f936c45f85da24d0';
|
|
2
2
|
export let TEST_META_ORG_USER_ID = '69261672f48fb7bf76e54dfb';
|
|
3
|
+
export let TEST_META_ORG_USER_PERSON_ID = '69261672f48fb7bf76e54dfc';
|
|
3
4
|
export function setTestMetaOrgId(metaOrgId) {
|
|
4
5
|
TEST_META_ORG_ID = metaOrgId;
|
|
5
6
|
}
|
|
6
7
|
export function setTestMetaOrgUserId(userId) {
|
|
7
8
|
TEST_META_ORG_USER_ID = userId;
|
|
8
9
|
}
|
|
10
|
+
export function setTestMetaOrgUserPersonId(personId) {
|
|
11
|
+
TEST_META_ORG_USER_PERSON_ID = personId;
|
|
12
|
+
}
|
|
9
13
|
export const TEST_META_ORG_USER_PASSWORD = 'test-meta-org-user-password';
|
|
10
14
|
export function getTestMetaOrg() {
|
|
11
15
|
return {
|
|
@@ -25,9 +29,9 @@ export function getTestMetaOrgUser() {
|
|
|
25
29
|
return {
|
|
26
30
|
_id: TEST_META_ORG_USER_ID,
|
|
27
31
|
_orgId: getTestMetaOrg()._id,
|
|
32
|
+
externalId: 'test-meta-org-user-external-id',
|
|
33
|
+
personId: TEST_META_ORG_USER_PERSON_ID,
|
|
28
34
|
email: 'test@example.com',
|
|
29
|
-
firstName: 'Test',
|
|
30
|
-
lastName: 'User',
|
|
31
35
|
displayName: 'Test User',
|
|
32
36
|
password: TEST_META_ORG_USER_PASSWORD,
|
|
33
37
|
_created: new Date(),
|
|
@@ -36,6 +40,25 @@ export function getTestMetaOrgUser() {
|
|
|
36
40
|
_updatedBy: 'system',
|
|
37
41
|
};
|
|
38
42
|
}
|
|
43
|
+
export function getTestMetaOrgUserPerson() {
|
|
44
|
+
return {
|
|
45
|
+
_id: TEST_META_ORG_USER_PERSON_ID,
|
|
46
|
+
_orgId: getTestMetaOrg()._id,
|
|
47
|
+
externalId: 'test-meta-org-user-person-external-id',
|
|
48
|
+
middleName: null,
|
|
49
|
+
firstName: 'Test',
|
|
50
|
+
lastName: 'User',
|
|
51
|
+
isAgent: false,
|
|
52
|
+
isClient: false,
|
|
53
|
+
isEmployee: false,
|
|
54
|
+
dateOfBirth: null,
|
|
55
|
+
extendedTypes: 0,
|
|
56
|
+
_created: new Date(),
|
|
57
|
+
_createdBy: 'system',
|
|
58
|
+
_updated: new Date(),
|
|
59
|
+
_updatedBy: 'system',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
39
62
|
export function getTestMetaOrgUserContext() {
|
|
40
63
|
return {
|
|
41
64
|
user: getTestMetaOrgUser(),
|
|
@@ -52,12 +75,16 @@ export function getTestMetaOrgUserContext() {
|
|
|
52
75
|
;
|
|
53
76
|
let TEST_ORG_ID = '6926167d06c0073a778a124f';
|
|
54
77
|
let TEST_ORG_USER_ID = '6926167d06c0073a778a1250';
|
|
78
|
+
let TEST_ORG_USER_PERSON_ID = '6926167d06c0073a778a1251';
|
|
55
79
|
export function setTestOrgId(orgId) {
|
|
56
80
|
TEST_ORG_ID = orgId;
|
|
57
81
|
}
|
|
58
82
|
export function setTestOrgUserId(userId) {
|
|
59
83
|
TEST_ORG_USER_ID = userId;
|
|
60
84
|
}
|
|
85
|
+
export function setTestOrgUserPersonId(personId) {
|
|
86
|
+
TEST_ORG_USER_PERSON_ID = personId;
|
|
87
|
+
}
|
|
61
88
|
export function getTestOrg() {
|
|
62
89
|
return {
|
|
63
90
|
_id: TEST_ORG_ID,
|
|
@@ -77,9 +104,9 @@ export function getTestOrgUser() {
|
|
|
77
104
|
return {
|
|
78
105
|
_id: TEST_ORG_USER_ID,
|
|
79
106
|
_orgId: getTestOrg()._id,
|
|
107
|
+
externalId: 'test-org-user-external-id',
|
|
80
108
|
email: 'test-org-user@example.com',
|
|
81
|
-
|
|
82
|
-
lastName: 'User',
|
|
109
|
+
personId: TEST_ORG_USER_PERSON_ID,
|
|
83
110
|
displayName: 'Test User',
|
|
84
111
|
password: TEST_ORG_USER_PASSWORD,
|
|
85
112
|
_created: new Date(),
|
|
@@ -88,6 +115,25 @@ export function getTestOrgUser() {
|
|
|
88
115
|
_updatedBy: 'system',
|
|
89
116
|
};
|
|
90
117
|
}
|
|
118
|
+
export function getTestOrgUserPerson() {
|
|
119
|
+
return {
|
|
120
|
+
_id: TEST_ORG_USER_PERSON_ID,
|
|
121
|
+
_orgId: getTestOrg()._id,
|
|
122
|
+
externalId: 'test-org-user-person-external-id',
|
|
123
|
+
middleName: null,
|
|
124
|
+
firstName: 'Test',
|
|
125
|
+
lastName: 'User',
|
|
126
|
+
isAgent: false,
|
|
127
|
+
isClient: false,
|
|
128
|
+
isEmployee: false,
|
|
129
|
+
dateOfBirth: null,
|
|
130
|
+
extendedTypes: 0,
|
|
131
|
+
_created: new Date(),
|
|
132
|
+
_createdBy: 'system',
|
|
133
|
+
_updated: new Date(),
|
|
134
|
+
_updatedBy: 'system',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
91
137
|
export function getTestOrgUserContext() {
|
|
92
138
|
return {
|
|
93
139
|
user: getTestOrgUser(),
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Application, Request, Response, NextFunction } from 'express';
|
|
2
2
|
import { AuthService } from '../services/index.js';
|
|
3
3
|
import { IDatabase } from '../databases/models/index.js';
|
|
4
|
+
import { PersonService } from '../services/person.service.js';
|
|
4
5
|
export declare class AuthController {
|
|
5
6
|
authService: AuthService;
|
|
7
|
+
personService: PersonService;
|
|
6
8
|
constructor(app: Application, database: IDatabase);
|
|
7
9
|
mapRoutes(app: Application): void;
|
|
8
10
|
login(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
@@ -4,10 +4,13 @@ import { BadRequestError, UnauthenticatedError } from '../errors/index.js';
|
|
|
4
4
|
import { apiUtils } from '../utils/index.js';
|
|
5
5
|
import { AuthService } from '../services/index.js';
|
|
6
6
|
import { isAuthorized } from '../middleware/index.js';
|
|
7
|
+
import { PersonService } from '../services/person.service.js';
|
|
7
8
|
export class AuthController {
|
|
8
9
|
authService;
|
|
10
|
+
personService;
|
|
9
11
|
constructor(app, database) {
|
|
10
12
|
this.authService = new AuthService(database);
|
|
13
|
+
this.personService = new PersonService(database);
|
|
11
14
|
this.mapRoutes(app);
|
|
12
15
|
}
|
|
13
16
|
mapRoutes(app) {
|
|
@@ -27,13 +30,15 @@ export class AuthController {
|
|
|
27
30
|
}
|
|
28
31
|
async registerUser(req, res) {
|
|
29
32
|
const userContext = req.userContext;
|
|
30
|
-
const body = req.body;
|
|
31
|
-
const validationErrors = this.authService.validate(body);
|
|
32
|
-
entityUtils.handleValidationResult(validationErrors, 'AuthController.registerUser');
|
|
33
33
|
if (!userContext) {
|
|
34
34
|
throw new BadRequestError('Missing required fields: userContext is required.');
|
|
35
35
|
}
|
|
36
|
-
const
|
|
36
|
+
const body = req.body;
|
|
37
|
+
let validationErrors = this.authService.validate(body.user);
|
|
38
|
+
entityUtils.handleValidationResult(validationErrors, 'AuthController.registerUser');
|
|
39
|
+
validationErrors = this.personService.validate(body.person);
|
|
40
|
+
entityUtils.handleValidationResult(validationErrors, 'AuthController.registerUser');
|
|
41
|
+
const user = await this.authService.createUser(userContext, body.user, body.person);
|
|
37
42
|
apiUtils.apiResponse(res, 201, { data: user || undefined }, UserSpec, PublicUserSpec);
|
|
38
43
|
}
|
|
39
44
|
async requestTokenUsingRefreshToken(req, res, next) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
-
import { initializeSystemUserContext, EmptyUserContext, getSystemUserContext, isSystemUserContextInitialized } from '@loomcore/common/models';
|
|
2
|
+
import { initializeSystemUserContext, EmptyUserContext, getSystemUserContext, isSystemUserContextInitialized, personModelSpec } from '@loomcore/common/models';
|
|
3
3
|
import { MongoDBDatabase } from '../mongo-db.database.js';
|
|
4
|
-
import { AuthService, OrganizationService } from '../../../services/index.js';
|
|
4
|
+
import { AuthService, GenericApiService, OrganizationService } from '../../../services/index.js';
|
|
5
5
|
export const getMongoInitialSchema = (config) => {
|
|
6
6
|
const migrations = [];
|
|
7
7
|
const isMultiTenant = config.app.isMultiTenant;
|
|
@@ -167,6 +167,7 @@ export const getMongoInitialSchema = (config) => {
|
|
|
167
167
|
up: async ({ context: db }) => {
|
|
168
168
|
const database = new MongoDBDatabase(db);
|
|
169
169
|
const authService = new AuthService(database);
|
|
170
|
+
const personService = new GenericApiService(database, 'persons', 'person', personModelSpec);
|
|
170
171
|
if (!isSystemUserContextInitialized()) {
|
|
171
172
|
const errorMessage = isMultiTenant
|
|
172
173
|
? 'SystemUserContext has not been initialized. The meta-org migration (00000000000008_data-meta-org) should have run before this migration. ' +
|
|
@@ -178,15 +179,32 @@ export const getMongoInitialSchema = (config) => {
|
|
|
178
179
|
}
|
|
179
180
|
const systemUserContext = getSystemUserContext();
|
|
180
181
|
const _id = randomUUID().toString();
|
|
182
|
+
const personId = randomUUID().toString();
|
|
183
|
+
const person = {
|
|
184
|
+
_id: personId,
|
|
185
|
+
_orgId: systemUserContext.organization?._id,
|
|
186
|
+
externalId: 'admin-user-person-external-id',
|
|
187
|
+
middleName: null,
|
|
188
|
+
firstName: 'Admin',
|
|
189
|
+
lastName: 'User',
|
|
190
|
+
isAgent: false,
|
|
191
|
+
isClient: false,
|
|
192
|
+
isEmployee: false,
|
|
193
|
+
dateOfBirth: null,
|
|
194
|
+
extendedTypes: 0,
|
|
195
|
+
_created: new Date(),
|
|
196
|
+
_createdBy: 'system',
|
|
197
|
+
_updated: new Date(),
|
|
198
|
+
_updatedBy: 'system'
|
|
199
|
+
};
|
|
181
200
|
await authService.createUser(systemUserContext, {
|
|
182
201
|
_id: _id,
|
|
183
202
|
_orgId: systemUserContext.organization?._id,
|
|
203
|
+
externalId: 'admin-user-external-id',
|
|
184
204
|
email: config.auth?.adminUser?.email,
|
|
185
205
|
password: config.auth?.adminUser?.password,
|
|
186
|
-
firstName: 'Admin',
|
|
187
|
-
lastName: 'User',
|
|
188
206
|
displayName: 'Admin User',
|
|
189
|
-
});
|
|
207
|
+
}, person);
|
|
190
208
|
},
|
|
191
209
|
down: async ({ context: db }) => {
|
|
192
210
|
if (!config.auth?.adminUser?.email)
|
package/dist/databases/operations/__tests__/models/{agent.model.d.ts → test-agent.model.d.ts}
RENAMED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
-
import {
|
|
3
|
-
export interface
|
|
2
|
+
import { ITestPersonModel } from "./test-person.model.js";
|
|
3
|
+
export interface ITestAgentModel extends IEntity, IAuditable {
|
|
4
4
|
person_id: number;
|
|
5
|
-
agent_person?:
|
|
5
|
+
agent_person?: ITestPersonModel;
|
|
6
6
|
}
|
|
7
|
-
export declare const
|
|
7
|
+
export declare const testAgentSchema: import("@sinclair/typebox").TObject<{
|
|
8
8
|
person_id: import("@sinclair/typebox").TNumber;
|
|
9
9
|
agent_person: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
10
10
|
first_name: import("@sinclair/typebox").TString;
|
|
@@ -22,4 +22,4 @@ export declare const agentSchema: import("@sinclair/typebox").TObject<{
|
|
|
22
22
|
}>>;
|
|
23
23
|
}>>;
|
|
24
24
|
}>;
|
|
25
|
-
export declare const
|
|
25
|
+
export declare const testAgentModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { entityUtils } from "@loomcore/common/utils";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { testPersonSchema } from "./test-person.model.js";
|
|
4
|
+
export const testAgentSchema = Type.Object({
|
|
5
|
+
person_id: Type.Number(),
|
|
6
|
+
agent_person: Type.Optional(testPersonSchema),
|
|
7
|
+
});
|
|
8
|
+
export const testAgentModelSpec = entityUtils.getModelSpec(testAgentSchema, { isAuditable: true });
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { ITestPersonModel } from "./test-person.model.js";
|
|
2
|
+
import { ITestAgentModel } from "./test-agent.model.js";
|
|
3
|
+
import { ITestPolicyModel } from "./test-policy.model.js";
|
|
4
4
|
import type { IAuditable, IEntity } from "@loomcore/common/models";
|
|
5
|
-
export interface
|
|
6
|
-
client_person:
|
|
7
|
-
agent?:
|
|
8
|
-
client_policies?:
|
|
5
|
+
export interface ITestClientReportsModel extends IEntity, IAuditable {
|
|
6
|
+
client_person: ITestPersonModel;
|
|
7
|
+
agent?: ITestAgentModel;
|
|
8
|
+
client_policies?: ITestPolicyModel[];
|
|
9
9
|
}
|
|
10
|
-
export declare const
|
|
10
|
+
export declare const testClientReportsSchema: import("@sinclair/typebox").TObject<{
|
|
11
11
|
client_person: import("@sinclair/typebox").TObject<{
|
|
12
12
|
first_name: import("@sinclair/typebox").TString;
|
|
13
13
|
middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
@@ -70,4 +70,4 @@ export declare const clientReportsSchema: import("@sinclair/typebox").TObject<{
|
|
|
70
70
|
}>>>;
|
|
71
71
|
}>>>;
|
|
72
72
|
}>;
|
|
73
|
-
export declare const
|
|
73
|
+
export declare const testClientReportsModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { testPersonSchema } from "./test-person.model.js";
|
|
2
|
+
import { testAgentSchema } from "./test-agent.model.js";
|
|
3
|
+
import { testPolicySchema } from "./test-policy.model.js";
|
|
4
|
+
import { entityUtils } from "@loomcore/common/utils";
|
|
5
|
+
import { Type } from "@sinclair/typebox";
|
|
6
|
+
export const testClientReportsSchema = Type.Object({
|
|
7
|
+
client_person: testPersonSchema,
|
|
8
|
+
agent: Type.Optional(testAgentSchema),
|
|
9
|
+
client_policies: Type.Optional(Type.Array(testPolicySchema))
|
|
10
|
+
});
|
|
11
|
+
export const testClientReportsModelSpec = entityUtils.getModelSpec(testClientReportsSchema, { isAuditable: true });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
+
import { ITestStateModel } from "./test-state.model.js";
|
|
3
|
+
export interface ITestDistrictModel extends IEntity, IAuditable {
|
|
4
|
+
name: string;
|
|
5
|
+
state_id: number;
|
|
6
|
+
state?: ITestStateModel;
|
|
7
|
+
}
|
|
8
|
+
export declare const testDistrictSchema: import("@sinclair/typebox").TObject<{
|
|
9
|
+
name: import("@sinclair/typebox").TString;
|
|
10
|
+
state_id: import("@sinclair/typebox").TNumber;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const testDistrictModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
package/dist/databases/operations/__tests__/models/{district.model.js → test-district.model.js}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { entityUtils } from "@loomcore/common/utils";
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
|
-
export const
|
|
3
|
+
export const testDistrictSchema = Type.Object({
|
|
4
4
|
name: Type.String(),
|
|
5
5
|
state_id: Type.Number(),
|
|
6
6
|
});
|
|
7
|
-
export const
|
|
7
|
+
export const testDistrictModelSpec = entityUtils.getModelSpec(testDistrictSchema, { isAuditable: true });
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
-
export interface
|
|
2
|
+
export interface ITestEmailAddressModel extends IEntity, IAuditable {
|
|
3
3
|
person_id: number;
|
|
4
4
|
email_address: string;
|
|
5
5
|
is_default: boolean;
|
|
6
6
|
}
|
|
7
|
-
export declare const
|
|
7
|
+
export declare const testEmailAddressSchema: import("@sinclair/typebox").TObject<{
|
|
8
8
|
person_id: import("@sinclair/typebox").TNumber;
|
|
9
9
|
email_address: import("@sinclair/typebox").TString;
|
|
10
10
|
is_default: import("@sinclair/typebox").TBoolean;
|
|
11
11
|
}>;
|
|
12
|
-
export declare const
|
|
12
|
+
export declare const testEmailAddressModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { entityUtils } from "@loomcore/common/utils";
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
|
-
export const
|
|
3
|
+
export const testEmailAddressSchema = Type.Object({
|
|
4
4
|
person_id: Type.Number(),
|
|
5
5
|
email_address: Type.String(),
|
|
6
6
|
is_default: Type.Boolean(),
|
|
7
7
|
});
|
|
8
|
-
export const
|
|
8
|
+
export const testEmailAddressModelSpec = entityUtils.getModelSpec(testEmailAddressSchema);
|
package/dist/databases/operations/__tests__/models/{person.model.d.ts → test-person.model.d.ts}
RENAMED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
export interface
|
|
2
|
+
import { ITestEmailAddressModel } from "./test-email-address.model.js";
|
|
3
|
+
import { ITestPhoneNumberModel } from "./test-phone-number.model.js";
|
|
4
|
+
import { ITestSchoolModel } from "./test-school.model.js";
|
|
5
|
+
export interface ITestPersonModel extends IEntity, IAuditable {
|
|
6
6
|
first_name: string;
|
|
7
7
|
middle_name: string | null;
|
|
8
8
|
last_name: string;
|
|
9
|
-
client_email_addresses:
|
|
10
|
-
client_phone_numbers:
|
|
11
|
-
school?:
|
|
9
|
+
client_email_addresses: ITestEmailAddressModel[];
|
|
10
|
+
client_phone_numbers: ITestPhoneNumberModel[];
|
|
11
|
+
school?: ITestSchoolModel;
|
|
12
12
|
}
|
|
13
|
-
export declare const
|
|
13
|
+
export declare const testPersonSchema: import("@sinclair/typebox").TObject<{
|
|
14
14
|
first_name: import("@sinclair/typebox").TString;
|
|
15
15
|
middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
16
16
|
last_name: import("@sinclair/typebox").TString;
|
|
@@ -25,4 +25,4 @@ export declare const personSchema: import("@sinclair/typebox").TObject<{
|
|
|
25
25
|
is_default: import("@sinclair/typebox").TBoolean;
|
|
26
26
|
}>>;
|
|
27
27
|
}>;
|
|
28
|
-
export declare const
|
|
28
|
+
export declare const testPersonModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { entityUtils } from "@loomcore/common/utils";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { testEmailAddressSchema } from "./test-email-address.model.js";
|
|
4
|
+
import { testPhoneNumberSchema } from "./test-phone-number.model.js";
|
|
5
|
+
export const testPersonSchema = Type.Object({
|
|
6
|
+
first_name: Type.String(),
|
|
7
|
+
middle_name: Type.Optional(Type.String()),
|
|
8
|
+
last_name: Type.String(),
|
|
9
|
+
client_phone_numbers: Type.Array(testPhoneNumberSchema),
|
|
10
|
+
client_email_addresses: Type.Array(testEmailAddressSchema),
|
|
11
|
+
});
|
|
12
|
+
export const testPersonModelSpec = entityUtils.getModelSpec(testPersonSchema, { isAuditable: true });
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
-
export interface
|
|
2
|
+
export interface ITestPhoneNumberModel extends IEntity, IAuditable {
|
|
3
3
|
phone_number: string;
|
|
4
4
|
phone_number_type: string;
|
|
5
5
|
is_default: boolean;
|
|
6
6
|
}
|
|
7
|
-
export declare const
|
|
7
|
+
export declare const testPhoneNumberSchema: import("@sinclair/typebox").TObject<{
|
|
8
8
|
phone_number: import("@sinclair/typebox").TString;
|
|
9
9
|
phone_number_type: import("@sinclair/typebox").TString;
|
|
10
10
|
is_default: import("@sinclair/typebox").TBoolean;
|
|
11
11
|
}>;
|
|
12
|
-
export declare const
|
|
12
|
+
export declare const testPhoneNumberModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { entityUtils } from "@loomcore/common/utils";
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
|
-
export const
|
|
3
|
+
export const testPhoneNumberSchema = Type.Object({
|
|
4
4
|
phone_number: Type.String(),
|
|
5
5
|
phone_number_type: Type.String(),
|
|
6
6
|
is_default: Type.Boolean(),
|
|
7
7
|
});
|
|
8
|
-
export const
|
|
8
|
+
export const testPhoneNumberModelSpec = entityUtils.getModelSpec(testPhoneNumberSchema, { isAuditable: true });
|
package/dist/databases/operations/__tests__/models/{policy.model.d.ts → test-policy.model.d.ts}
RENAMED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
export interface
|
|
2
|
+
import { ITestAgentModel } from "./test-agent.model.js";
|
|
3
|
+
import { ITestPremiumModel } from "./test-premium.model.js";
|
|
4
|
+
export interface ITestPolicyModel extends IEntity, IAuditable {
|
|
5
5
|
client_id: number;
|
|
6
6
|
amount: number;
|
|
7
7
|
frequency: string;
|
|
8
|
-
agents?:
|
|
9
|
-
policy_premiums?:
|
|
8
|
+
agents?: ITestAgentModel[];
|
|
9
|
+
policy_premiums?: ITestPremiumModel[];
|
|
10
10
|
}
|
|
11
|
-
export declare const
|
|
11
|
+
export declare const testPolicySchema: import("@sinclair/typebox").TObject<{
|
|
12
12
|
client_id: import("@sinclair/typebox").TNumber;
|
|
13
13
|
amount: import("@sinclair/typebox").TNumber;
|
|
14
14
|
frequency: import("@sinclair/typebox").TString;
|
|
@@ -36,4 +36,4 @@ export declare const policySchema: import("@sinclair/typebox").TObject<{
|
|
|
36
36
|
date: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TDate, import("@sinclair/typebox").TString]>;
|
|
37
37
|
}>>>;
|
|
38
38
|
}>;
|
|
39
|
-
export declare const
|
|
39
|
+
export declare const testPolicyModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { entityUtils } from "@loomcore/common/utils";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { testAgentSchema } from "./test-agent.model.js";
|
|
4
|
+
import { testPremiumSchema } from "./test-premium.model.js";
|
|
5
|
+
export const testPolicySchema = Type.Object({
|
|
6
|
+
client_id: Type.Number(),
|
|
7
|
+
amount: Type.Number(),
|
|
8
|
+
frequency: Type.String(),
|
|
9
|
+
agents: Type.Optional(Type.Array(testAgentSchema)),
|
|
10
|
+
policy_premiums: Type.Optional(Type.Array(testPremiumSchema))
|
|
11
|
+
});
|
|
12
|
+
export const testPolicyModelSpec = entityUtils.getModelSpec(testPolicySchema, { isAuditable: true });
|
package/dist/databases/operations/__tests__/models/{premium.model.d.ts → test-premium.model.d.ts}
RENAMED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
-
export interface
|
|
2
|
+
export interface ITestPremiumModel extends IEntity, IAuditable {
|
|
3
3
|
policy_id: number;
|
|
4
4
|
amount: number;
|
|
5
5
|
date: Date | string;
|
|
6
6
|
}
|
|
7
|
-
export declare const
|
|
7
|
+
export declare const testPremiumSchema: import("@sinclair/typebox").TObject<{
|
|
8
8
|
policy_id: import("@sinclair/typebox").TNumber;
|
|
9
9
|
amount: import("@sinclair/typebox").TNumber;
|
|
10
10
|
date: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TDate, import("@sinclair/typebox").TString]>;
|
|
11
11
|
}>;
|
|
12
|
-
export declare const
|
|
12
|
+
export declare const testPremiumModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
package/dist/databases/operations/__tests__/models/{premium.model.js → test-premium.model.js}
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { entityUtils } from "@loomcore/common/utils";
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
|
-
export const
|
|
3
|
+
export const testPremiumSchema = Type.Object({
|
|
4
4
|
policy_id: Type.Number(),
|
|
5
5
|
amount: Type.Number(),
|
|
6
6
|
date: Type.Union([Type.Date(), Type.String()])
|
|
7
7
|
});
|
|
8
|
-
export const
|
|
8
|
+
export const testPremiumModelSpec = entityUtils.getModelSpec(testPremiumSchema, { isAuditable: true });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
+
import { ITestDistrictModel } from "./test-district.model.js";
|
|
3
|
+
export interface ITestSchoolModel extends IEntity, IAuditable {
|
|
4
|
+
name: string;
|
|
5
|
+
district_id: number;
|
|
6
|
+
district?: ITestDistrictModel;
|
|
7
|
+
}
|
|
8
|
+
export declare const testSchoolSchema: import("@sinclair/typebox").TObject<{
|
|
9
|
+
name: import("@sinclair/typebox").TString;
|
|
10
|
+
district_id: import("@sinclair/typebox").TNumber;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const testSchoolModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { entityUtils } from "@loomcore/common/utils";
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
|
-
export const
|
|
3
|
+
export const testSchoolSchema = Type.Object({
|
|
4
4
|
name: Type.String(),
|
|
5
5
|
district_id: Type.Number(),
|
|
6
6
|
});
|
|
7
|
-
export const
|
|
7
|
+
export const testSchoolModelSpec = entityUtils.getModelSpec(testSchoolSchema, { isAuditable: true });
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
+
export interface ITestStateModel extends IEntity, IAuditable {
|
|
3
|
+
name: string;
|
|
4
|
+
}
|
|
5
|
+
export declare const testStateSchema: import("@sinclair/typebox").TObject<{
|
|
6
|
+
name: import("@sinclair/typebox").TString;
|
|
7
|
+
}>;
|
|
8
|
+
export declare const testStateModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { entityUtils } from "@loomcore/common/utils";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
export const testStateSchema = Type.Object({
|
|
4
|
+
name: Type.String(),
|
|
5
|
+
});
|
|
6
|
+
export const testStateModelSpec = entityUtils.getModelSpec(testStateSchema, { isAuditable: true });
|
|
@@ -43,21 +43,54 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
43
43
|
}
|
|
44
44
|
if (isAuthEnabled)
|
|
45
45
|
migrations.push({
|
|
46
|
-
name: '00000000000002_schema-
|
|
46
|
+
name: '00000000000002_schema-persons',
|
|
47
47
|
up: async ({ context: pool }) => {
|
|
48
48
|
const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
|
|
49
|
-
|
|
49
|
+
await pool.query(`
|
|
50
|
+
CREATE TABLE IF NOT EXISTS "persons" (
|
|
51
|
+
"_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
52
|
+
${orgColumnDef}
|
|
53
|
+
"externalId" VARCHAR(255) UNIQUE,
|
|
54
|
+
"firstName" VARCHAR(255) NOT NULL,
|
|
55
|
+
"middleName" VARCHAR(255),
|
|
56
|
+
"lastName" VARCHAR(255) NOT NULL,
|
|
57
|
+
"dateOfBirth" DATE,
|
|
58
|
+
"isAgent" BOOLEAN NOT NULL DEFAULT FALSE,
|
|
59
|
+
"isClient" BOOLEAN NOT NULL DEFAULT FALSE,
|
|
60
|
+
"isEmployee" BOOLEAN NOT NULL DEFAULT FALSE,
|
|
61
|
+
"extendedTypes" INTEGER NOT NULL DEFAULT 0,
|
|
62
|
+
"_created" TIMESTAMPTZ NOT NULL,
|
|
63
|
+
"_createdBy" INTEGER NOT NULL,
|
|
64
|
+
"_updated" TIMESTAMPTZ NOT NULL,
|
|
65
|
+
"_updatedBy" INTEGER NOT NULL,
|
|
66
|
+
"_deleted" TIMESTAMPTZ,
|
|
67
|
+
"_deletedBy" INTEGER
|
|
68
|
+
)
|
|
69
|
+
`);
|
|
70
|
+
},
|
|
71
|
+
down: async ({ context: pool }) => {
|
|
72
|
+
await pool.query('DROP TABLE IF EXISTS "persons"');
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
if (isAuthEnabled)
|
|
76
|
+
migrations.push({
|
|
77
|
+
name: '00000000000003_schema-users',
|
|
78
|
+
up: async ({ context: pool }) => {
|
|
79
|
+
const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
|
|
80
|
+
let uniqueConstraint = isMultiTenant
|
|
50
81
|
? 'CONSTRAINT "uk_users_email" UNIQUE ("_orgId", "email")'
|
|
51
82
|
: 'CONSTRAINT "uk_users_email" UNIQUE ("email")';
|
|
83
|
+
uniqueConstraint += `,
|
|
84
|
+
CONSTRAINT "fk_users_personId" FOREIGN KEY("personId") REFERENCES "persons"("_id") ON DELETE CASCADE`;
|
|
52
85
|
await pool.query(`
|
|
53
86
|
CREATE TABLE IF NOT EXISTS "users" (
|
|
54
87
|
"_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
55
88
|
${orgColumnDef}
|
|
89
|
+
"externalId" VARCHAR(255) UNIQUE,
|
|
56
90
|
"email" VARCHAR(255) NOT NULL,
|
|
57
|
-
"firstName" VARCHAR(255),
|
|
58
|
-
"lastName" VARCHAR(255),
|
|
59
91
|
"displayName" VARCHAR(255),
|
|
60
92
|
"password" VARCHAR(255) NOT NULL,
|
|
93
|
+
"personId" INTEGER UNIQUE,
|
|
61
94
|
"_lastLoggedIn" TIMESTAMPTZ,
|
|
62
95
|
"_lastPasswordChange" TIMESTAMPTZ,
|
|
63
96
|
"_created" TIMESTAMPTZ NOT NULL,
|
|
@@ -76,7 +109,7 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
76
109
|
});
|
|
77
110
|
if (isAuthEnabled)
|
|
78
111
|
migrations.push({
|
|
79
|
-
name: '
|
|
112
|
+
name: '00000000000004_schema-refresh-tokens',
|
|
80
113
|
up: async ({ context: pool }) => {
|
|
81
114
|
const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
|
|
82
115
|
await pool.query(`
|
|
@@ -99,7 +132,7 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
99
132
|
});
|
|
100
133
|
if (isAuthEnabled)
|
|
101
134
|
migrations.push({
|
|
102
|
-
name: '
|
|
135
|
+
name: '00000000000005_schema-password-reset-tokens',
|
|
103
136
|
up: async ({ context: pool }) => {
|
|
104
137
|
const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
|
|
105
138
|
const uniqueConstraint = isMultiTenant
|
|
@@ -128,7 +161,7 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
128
161
|
});
|
|
129
162
|
if (isAuthEnabled)
|
|
130
163
|
migrations.push({
|
|
131
|
-
name: '
|
|
164
|
+
name: '00000000000006_schema-roles',
|
|
132
165
|
up: async ({ context: pool }) => {
|
|
133
166
|
const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
|
|
134
167
|
const uniqueConstraint = isMultiTenant
|
|
@@ -150,7 +183,7 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
150
183
|
});
|
|
151
184
|
if (isAuthEnabled)
|
|
152
185
|
migrations.push({
|
|
153
|
-
name: '
|
|
186
|
+
name: '00000000000007_schema-user-roles',
|
|
154
187
|
up: async ({ context: pool }) => {
|
|
155
188
|
const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
|
|
156
189
|
const uniqueConstraint = isMultiTenant
|
|
@@ -180,7 +213,7 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
180
213
|
});
|
|
181
214
|
if (isAuthEnabled)
|
|
182
215
|
migrations.push({
|
|
183
|
-
name: '
|
|
216
|
+
name: '00000000000008_schema-features',
|
|
184
217
|
up: async ({ context: pool }) => {
|
|
185
218
|
const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
|
|
186
219
|
const uniqueConstraint = isMultiTenant
|
|
@@ -202,7 +235,7 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
202
235
|
});
|
|
203
236
|
if (isAuthEnabled)
|
|
204
237
|
migrations.push({
|
|
205
|
-
name: '
|
|
238
|
+
name: '00000000000009_schema-authorizations',
|
|
206
239
|
up: async ({ context: pool }) => {
|
|
207
240
|
const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
|
|
208
241
|
const uniqueConstraint = isMultiTenant
|
|
@@ -235,7 +268,7 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
235
268
|
});
|
|
236
269
|
if (isMultiTenant) {
|
|
237
270
|
migrations.push({
|
|
238
|
-
name: '
|
|
271
|
+
name: '00000000000010_data-meta-org',
|
|
239
272
|
up: async ({ context: pool }) => {
|
|
240
273
|
const result = await pool.query(`
|
|
241
274
|
INSERT INTO "organizations" ("name", "code", "status", "isMetaOrg", "_created", "_createdBy", "_updated", "_updatedBy")
|
|
@@ -254,7 +287,7 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
254
287
|
}
|
|
255
288
|
if (isAuthEnabled) {
|
|
256
289
|
migrations.push({
|
|
257
|
-
name: '
|
|
290
|
+
name: '00000000000011_data-admin-user',
|
|
258
291
|
up: async ({ context: pool }) => {
|
|
259
292
|
const client = await pool.connect();
|
|
260
293
|
try {
|
|
@@ -273,14 +306,19 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
273
306
|
const userData = {
|
|
274
307
|
email: config.auth?.adminUser?.email,
|
|
275
308
|
password: config.auth?.adminUser?.password,
|
|
276
|
-
firstName: 'Admin',
|
|
277
|
-
lastName: 'User',
|
|
278
309
|
displayName: 'Admin User',
|
|
279
310
|
};
|
|
280
311
|
if (isMultiTenant && systemUserContext.organization?._id) {
|
|
281
312
|
userData._orgId = systemUserContext.organization._id;
|
|
282
313
|
}
|
|
283
|
-
|
|
314
|
+
const personData = {
|
|
315
|
+
firstName: 'Admin',
|
|
316
|
+
lastName: 'User',
|
|
317
|
+
};
|
|
318
|
+
if (isMultiTenant && systemUserContext.organization?._id) {
|
|
319
|
+
personData._orgId = systemUserContext.organization._id;
|
|
320
|
+
}
|
|
321
|
+
await authService.createUser(systemUserContext, userData, personData);
|
|
284
322
|
}
|
|
285
323
|
finally {
|
|
286
324
|
client.release();
|
|
@@ -295,7 +333,7 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
295
333
|
}
|
|
296
334
|
if (config.auth) {
|
|
297
335
|
migrations.push({
|
|
298
|
-
name: '
|
|
336
|
+
name: '00000000000012_data-admin-authorizations',
|
|
299
337
|
up: async ({ context: pool }) => {
|
|
300
338
|
const client = await pool.connect();
|
|
301
339
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Request, Response } from 'express';
|
|
2
|
-
import { IUserContext, ITokenResponse, ILoginResponse, IUser } from '@loomcore/common/models';
|
|
2
|
+
import { IUserContext, ITokenResponse, ILoginResponse, IUser, IPersonModel } from '@loomcore/common/models';
|
|
3
3
|
import type { AppIdType } from '@loomcore/common/types';
|
|
4
4
|
import { MultiTenantApiService } from './multi-tenant-api.service.js';
|
|
5
5
|
import { UpdateResult } from '../databases/models/update-result.js';
|
|
@@ -11,6 +11,7 @@ export declare class AuthService extends MultiTenantApiService<IUser> {
|
|
|
11
11
|
private emailService;
|
|
12
12
|
private organizationService;
|
|
13
13
|
private authConfig;
|
|
14
|
+
private personService;
|
|
14
15
|
constructor(database: IDatabase);
|
|
15
16
|
attemptLogin(req: Request, res: Response, email: string, password: string): Promise<ILoginResponse | null>;
|
|
16
17
|
logUserIn(userContext: IUserContext, deviceId: string): Promise<{
|
|
@@ -22,7 +23,7 @@ export declare class AuthService extends MultiTenantApiService<IUser> {
|
|
|
22
23
|
userContext: IUserContext;
|
|
23
24
|
} | null>;
|
|
24
25
|
getUserByEmail(email: string): Promise<IUser | null>;
|
|
25
|
-
createUser(userContext: IUserContext, user: Partial<IUser>): Promise<IUser | null>;
|
|
26
|
+
createUser(userContext: IUserContext, user: Partial<IUser>, person: Partial<IPersonModel>): Promise<IUser | null>;
|
|
26
27
|
requestTokenUsingRefreshToken(refreshToken: string, deviceId: string): Promise<ITokenResponse | null>;
|
|
27
28
|
changeLoggedInUsersPassword(userContext: IUserContext, body: any): Promise<UpdateResult>;
|
|
28
29
|
changePassword(userContext: IUserContext, queryObject: any, password: string): Promise<UpdateResult>;
|
|
@@ -12,18 +12,21 @@ import { passwordUtils } from '../utils/index.js';
|
|
|
12
12
|
import { config } from '../config/index.js';
|
|
13
13
|
import { refreshTokenModelSpec } from '../models/refresh-token.model.js';
|
|
14
14
|
import { getUserContextAuthorizations } from './utils/getUserContextAuthorizations.util.js';
|
|
15
|
+
import { PersonService } from './person.service.js';
|
|
15
16
|
export class AuthService extends MultiTenantApiService {
|
|
16
17
|
refreshTokenService;
|
|
17
18
|
passwordResetTokenService;
|
|
18
19
|
emailService;
|
|
19
20
|
organizationService;
|
|
20
21
|
authConfig;
|
|
22
|
+
personService;
|
|
21
23
|
constructor(database) {
|
|
22
24
|
super(database, 'users', 'user', UserSpec);
|
|
23
25
|
this.refreshTokenService = new GenericApiService(database, 'refresh_tokens', 'refresh_token', refreshTokenModelSpec);
|
|
24
26
|
this.passwordResetTokenService = new PasswordResetTokenService(database);
|
|
25
27
|
this.emailService = new EmailService();
|
|
26
28
|
this.organizationService = new OrganizationService(database);
|
|
29
|
+
this.personService = new PersonService(database);
|
|
27
30
|
if (!config.auth) {
|
|
28
31
|
throw new ServerError('Auth configuration is not set');
|
|
29
32
|
}
|
|
@@ -77,7 +80,7 @@ export class AuthService extends MultiTenantApiService {
|
|
|
77
80
|
}
|
|
78
81
|
return this.database.postProcessEntity(rawUser, this.modelSpec.fullSchema);
|
|
79
82
|
}
|
|
80
|
-
async createUser(userContext, user) {
|
|
83
|
+
async createUser(userContext, user, person) {
|
|
81
84
|
if (userContext.user._id === 'system') {
|
|
82
85
|
if (config.app.isMultiTenant && userContext.organization?._id !== user._orgId) {
|
|
83
86
|
throw new BadRequestError('User is not authorized to create a user in this organization');
|
|
@@ -95,6 +98,17 @@ export class AuthService extends MultiTenantApiService {
|
|
|
95
98
|
throw new BadRequestError('A user with this email address already exists');
|
|
96
99
|
}
|
|
97
100
|
}
|
|
101
|
+
let personId = user.personId;
|
|
102
|
+
if (personId && person) {
|
|
103
|
+
const updatePersonResult = await this.personService.partialUpdateById(userContext, personId, person);
|
|
104
|
+
}
|
|
105
|
+
if (!personId) {
|
|
106
|
+
const newPerson = await this.personService.create(userContext, person);
|
|
107
|
+
if (newPerson) {
|
|
108
|
+
personId = newPerson._id;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
user.personId = personId;
|
|
98
112
|
return await this.create(userContext, user);
|
|
99
113
|
}
|
|
100
114
|
async requestTokenUsingRefreshToken(refreshToken, deviceId) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { IPersonModel } from "@loomcore/common/models";
|
|
2
|
+
import { IDatabase } from "../databases/index.js";
|
|
3
|
+
import { GenericApiService } from "./generic-api-service/generic-api.service.js";
|
|
4
|
+
export declare class PersonService extends GenericApiService<IPersonModel> {
|
|
5
|
+
constructor(database: IDatabase);
|
|
6
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { personModelSpec } from "@loomcore/common/models";
|
|
2
|
+
import { GenericApiService } from "./generic-api-service/generic-api.service.js";
|
|
3
|
+
export class PersonService extends GenericApiService {
|
|
4
|
+
constructor(database) {
|
|
5
|
+
super(database, 'persons', 'person', personModelSpec);
|
|
6
|
+
}
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loomcore/api",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.79",
|
|
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": {
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"qs": "^6.14.1"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@loomcore/common": "^0.0.
|
|
60
|
+
"@loomcore/common": "^0.0.46",
|
|
61
61
|
"@sinclair/typebox": "0.34.33",
|
|
62
62
|
"cookie-parser": "^1.4.6",
|
|
63
63
|
"cors": "^2.8.5",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"cross-env": "^7.0.3",
|
|
83
83
|
"mongodb-memory-server": "^9.3.0",
|
|
84
84
|
"npm-run-all": "^4.1.5",
|
|
85
|
-
"pg-mem": "^3.0.
|
|
85
|
+
"pg-mem": "^3.0.12",
|
|
86
86
|
"rxjs": "^7.8.0",
|
|
87
87
|
"supertest": "^7.1.0",
|
|
88
88
|
"typescript": "^5.8.3",
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { entityUtils } from "@loomcore/common/utils";
|
|
2
|
-
import { Type } from "@sinclair/typebox";
|
|
3
|
-
import { personSchema } from "./person.model.js";
|
|
4
|
-
export const agentSchema = Type.Object({
|
|
5
|
-
person_id: Type.Number(),
|
|
6
|
-
agent_person: Type.Optional(personSchema),
|
|
7
|
-
});
|
|
8
|
-
export const agentModelSpec = entityUtils.getModelSpec(agentSchema, { isAuditable: true });
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { personSchema } from "./person.model.js";
|
|
2
|
-
import { agentSchema } from "./agent.model.js";
|
|
3
|
-
import { policySchema } from "./policy.model.js";
|
|
4
|
-
import { entityUtils } from "@loomcore/common/utils";
|
|
5
|
-
import { Type } from "@sinclair/typebox";
|
|
6
|
-
export const clientReportsSchema = Type.Object({
|
|
7
|
-
client_person: personSchema,
|
|
8
|
-
agent: Type.Optional(agentSchema),
|
|
9
|
-
client_policies: Type.Optional(Type.Array(policySchema))
|
|
10
|
-
});
|
|
11
|
-
export const clientReportsModelSpec = entityUtils.getModelSpec(clientReportsSchema, { isAuditable: true });
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
-
import { IStateModel } from "./state.model.js";
|
|
3
|
-
export interface IDistrictModel extends IEntity, IAuditable {
|
|
4
|
-
name: string;
|
|
5
|
-
state_id: number;
|
|
6
|
-
state?: IStateModel;
|
|
7
|
-
}
|
|
8
|
-
export declare const districtSchema: import("@sinclair/typebox").TObject<{
|
|
9
|
-
name: import("@sinclair/typebox").TString;
|
|
10
|
-
state_id: import("@sinclair/typebox").TNumber;
|
|
11
|
-
}>;
|
|
12
|
-
export declare const districtModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { entityUtils } from "@loomcore/common/utils";
|
|
2
|
-
import { Type } from "@sinclair/typebox";
|
|
3
|
-
import { emailAddressSchema } from "./email-address.model.js";
|
|
4
|
-
import { phoneNumberSchema } from "./phone-number.model.js";
|
|
5
|
-
export const personSchema = Type.Object({
|
|
6
|
-
first_name: Type.String(),
|
|
7
|
-
middle_name: Type.Optional(Type.String()),
|
|
8
|
-
last_name: Type.String(),
|
|
9
|
-
client_phone_numbers: Type.Array(phoneNumberSchema),
|
|
10
|
-
client_email_addresses: Type.Array(emailAddressSchema),
|
|
11
|
-
});
|
|
12
|
-
export const personModelSpec = entityUtils.getModelSpec(personSchema, { isAuditable: true });
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { entityUtils } from "@loomcore/common/utils";
|
|
2
|
-
import { Type } from "@sinclair/typebox";
|
|
3
|
-
import { agentSchema } from "./agent.model.js";
|
|
4
|
-
import { premiumSchema } from "./premium.model.js";
|
|
5
|
-
export const policySchema = Type.Object({
|
|
6
|
-
client_id: Type.Number(),
|
|
7
|
-
amount: Type.Number(),
|
|
8
|
-
frequency: Type.String(),
|
|
9
|
-
agents: Type.Optional(Type.Array(agentSchema)),
|
|
10
|
-
policy_premiums: Type.Optional(Type.Array(premiumSchema))
|
|
11
|
-
});
|
|
12
|
-
export const policyModelSpec = entityUtils.getModelSpec(policySchema, { isAuditable: true });
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
-
import { IDistrictModel } from "./district.model.js";
|
|
3
|
-
export interface ISchoolModel extends IEntity, IAuditable {
|
|
4
|
-
name: string;
|
|
5
|
-
district_id: number;
|
|
6
|
-
district?: IDistrictModel;
|
|
7
|
-
}
|
|
8
|
-
export declare const schoolSchema: import("@sinclair/typebox").TObject<{
|
|
9
|
-
name: import("@sinclair/typebox").TString;
|
|
10
|
-
district_id: import("@sinclair/typebox").TNumber;
|
|
11
|
-
}>;
|
|
12
|
-
export declare const schoolModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
|
-
export interface IStateModel extends IEntity, IAuditable {
|
|
3
|
-
name: string;
|
|
4
|
-
}
|
|
5
|
-
export declare const stateSchema: import("@sinclair/typebox").TObject<{
|
|
6
|
-
name: import("@sinclair/typebox").TString;
|
|
7
|
-
}>;
|
|
8
|
-
export declare const stateModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
|