@loomcore/api 0.0.58 → 0.1.0
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/LICENSE +201 -0
- package/README.md +50 -0
- package/dist/__tests__/common-test.utils.d.ts +29 -60
- package/dist/__tests__/common-test.utils.js +88 -166
- package/dist/__tests__/index.d.ts +6 -0
- package/dist/__tests__/index.js +6 -0
- package/dist/__tests__/models/category.model.d.ts +8 -0
- package/dist/__tests__/models/category.model.js +6 -0
- package/dist/__tests__/models/mongo-test-entity.model.d.ts +11 -0
- package/dist/__tests__/models/mongo-test-entity.model.js +13 -0
- package/dist/__tests__/models/product.model.d.ts +17 -0
- package/dist/__tests__/models/product.model.js +10 -0
- package/dist/__tests__/models/test-entity.model.d.ts +11 -0
- package/dist/__tests__/models/test-entity.model.js +10 -0
- package/dist/__tests__/models/test-item.model.d.ts +12 -0
- package/dist/__tests__/models/test-item.model.js +9 -0
- package/dist/__tests__/mongo-db.test-database.d.ts +15 -0
- package/dist/__tests__/mongo-db.test-database.js +74 -0
- package/dist/__tests__/postgres-test-migrations/001-create-test-entities-table.migration.d.ts +11 -0
- package/dist/__tests__/postgres-test-migrations/001-create-test-entities-table.migration.js +59 -0
- package/dist/__tests__/postgres-test-migrations/002-create-categories-table.migration.d.ts +11 -0
- package/dist/__tests__/postgres-test-migrations/002-create-categories-table.migration.js +52 -0
- package/dist/__tests__/postgres-test-migrations/003-create-products-table.migration.d.ts +11 -0
- package/dist/__tests__/postgres-test-migrations/003-create-products-table.migration.js +62 -0
- package/dist/__tests__/postgres-test-migrations/004-create-test-users-table.migration.d.ts +11 -0
- package/dist/__tests__/postgres-test-migrations/004-create-test-users-table.migration.js +66 -0
- package/dist/__tests__/postgres-test-migrations/005-create-test-items-table.migration.d.ts +11 -0
- package/dist/__tests__/postgres-test-migrations/005-create-test-items-table.migration.js +50 -0
- package/dist/__tests__/postgres-test-migrations/run-test-migrations.d.ts +2 -0
- package/dist/__tests__/postgres-test-migrations/run-test-migrations.js +22 -0
- package/dist/__tests__/postgres.test-database.d.ts +13 -0
- package/dist/__tests__/postgres.test-database.js +85 -0
- package/dist/__tests__/test-database.interface.d.ts +7 -0
- package/dist/__tests__/test-express-app.d.ts +9 -7
- package/dist/__tests__/test-express-app.js +38 -48
- package/dist/__tests__/test-mongo-db.d.ts +14 -0
- package/dist/__tests__/test-mongo-db.js +81 -0
- package/dist/__tests__/test-objects.d.ts +23 -0
- package/dist/__tests__/test-objects.js +45 -0
- package/dist/__tests__/test-user.d.ts +3 -0
- package/dist/__tests__/test-user.js +16 -0
- package/dist/config/base-api-config.d.ts +2 -2
- package/dist/config/base-api-config.js +2 -2
- package/dist/controllers/api.controller.d.ts +1 -5
- package/dist/controllers/api.controller.js +4 -11
- package/dist/controllers/auth.controller.d.ts +2 -2
- package/dist/controllers/auth.controller.js +4 -5
- package/dist/controllers/organizations.controller.d.ts +2 -2
- package/dist/controllers/organizations.controller.js +4 -4
- package/dist/controllers/users.controller.d.ts +2 -2
- package/dist/controllers/users.controller.js +2 -2
- package/dist/databases/index.d.ts +1 -0
- package/dist/databases/index.js +1 -0
- package/dist/databases/models/constants.d.ts +1 -0
- package/dist/databases/models/constants.js +1 -0
- package/dist/databases/models/database.d.ts +3 -0
- package/dist/databases/models/database.interface.d.ts +28 -0
- package/dist/databases/models/delete-result.d.ts +5 -0
- package/dist/databases/models/delete-result.js +8 -0
- package/dist/databases/models/index.d.ts +5 -0
- package/dist/databases/models/index.js +5 -0
- package/dist/databases/models/update-result.d.ts +5 -0
- package/dist/databases/models/update-result.js +8 -0
- package/dist/databases/mongo-db/commands/batch-update.command.d.ts +3 -0
- package/dist/databases/mongo-db/commands/batch-update.command.js +41 -0
- package/dist/databases/mongo-db/commands/create-many.command.d.ts +5 -0
- package/dist/databases/mongo-db/commands/create-many.command.js +17 -0
- package/dist/databases/mongo-db/commands/create.command.d.ts +5 -0
- package/dist/databases/mongo-db/commands/create.command.js +17 -0
- package/dist/databases/mongo-db/commands/delete-by-id.command.d.ts +3 -0
- package/dist/databases/mongo-db/commands/delete-by-id.command.js +9 -0
- package/dist/databases/mongo-db/commands/delete-many.command.d.ts +4 -0
- package/dist/databases/mongo-db/commands/delete-many.command.js +9 -0
- package/dist/databases/mongo-db/commands/full-updateby-id.command.d.ts +3 -0
- package/dist/databases/mongo-db/commands/full-updateby-id.command.js +21 -0
- package/dist/databases/mongo-db/commands/index.d.ts +8 -0
- package/dist/databases/mongo-db/commands/index.js +8 -0
- package/dist/databases/mongo-db/commands/mongo-batch-update.command.d.ts +4 -0
- package/dist/databases/mongo-db/commands/mongo-batch-update.command.js +41 -0
- package/dist/databases/mongo-db/commands/mongo-create-many.command.d.ts +5 -0
- package/dist/databases/mongo-db/commands/mongo-create-many.command.js +17 -0
- package/dist/databases/mongo-db/commands/mongo-create.command.d.ts +5 -0
- package/dist/databases/mongo-db/commands/mongo-create.command.js +17 -0
- package/dist/databases/mongo-db/commands/mongo-delete-by-id.command.d.ts +3 -0
- package/dist/databases/mongo-db/commands/mongo-delete-by-id.command.js +14 -0
- package/dist/databases/mongo-db/commands/mongo-delete-many.command.d.ts +4 -0
- package/dist/databases/mongo-db/commands/mongo-delete-many.command.js +9 -0
- package/dist/databases/mongo-db/commands/mongo-full-updateby-id.command.d.ts +3 -0
- package/dist/databases/mongo-db/commands/mongo-full-updateby-id.command.js +25 -0
- package/dist/databases/mongo-db/commands/mongo-partial-update-by-id.command.d.ts +3 -0
- package/dist/databases/mongo-db/commands/mongo-partial-update-by-id.command.js +25 -0
- package/dist/databases/mongo-db/commands/mongo-update.command.d.ts +4 -0
- package/dist/databases/mongo-db/commands/mongo-update.command.js +19 -0
- package/dist/databases/mongo-db/commands/partial-update-by-id.command.d.ts +3 -0
- package/dist/databases/mongo-db/commands/partial-update-by-id.command.js +21 -0
- package/dist/databases/mongo-db/commands/update.command.d.ts +4 -0
- package/dist/databases/mongo-db/commands/update.command.js +19 -0
- package/dist/databases/mongo-db/index.d.ts +4 -0
- package/dist/databases/mongo-db/index.js +4 -0
- package/dist/databases/mongo-db/models/no-sql-pipeline.d.ts +15 -0
- package/dist/databases/mongo-db/models/no-sql-pipeline.interface.d.ts +11 -0
- package/dist/databases/mongo-db/models/no-sql-pipeline.js +43 -0
- package/dist/databases/mongo-db/mongo-db.database.d.ts +32 -0
- package/dist/databases/mongo-db/mongo-db.database.js +65 -0
- package/dist/databases/mongo-db/queries/find-one.query.d.ts +3 -0
- package/dist/databases/mongo-db/queries/find-one.query.js +9 -0
- package/dist/databases/mongo-db/queries/find.query.d.ts +3 -0
- package/dist/databases/mongo-db/queries/find.query.js +9 -0
- package/dist/databases/mongo-db/queries/get-all.query.d.ts +3 -0
- package/dist/databases/mongo-db/queries/get-all.query.js +17 -0
- package/dist/databases/mongo-db/queries/get-by-id.query.d.ts +3 -0
- package/dist/databases/mongo-db/queries/get-by-id.query.js +20 -0
- package/dist/databases/mongo-db/queries/get-count.query.d.ts +2 -0
- package/dist/databases/mongo-db/queries/get-count.query.js +5 -0
- package/dist/databases/mongo-db/queries/get.query.d.ts +4 -0
- package/dist/databases/mongo-db/queries/get.query.js +14 -0
- package/dist/databases/mongo-db/queries/index.d.ts +6 -0
- package/dist/databases/mongo-db/queries/index.js +6 -0
- package/dist/databases/mongo-db/queries/mongo-find-one.query.d.ts +3 -0
- package/dist/databases/mongo-db/queries/mongo-find-one.query.js +9 -0
- package/dist/databases/mongo-db/queries/mongo-find.query.d.ts +3 -0
- package/dist/databases/mongo-db/queries/mongo-find.query.js +9 -0
- package/dist/databases/mongo-db/queries/mongo-get-all.query.d.ts +3 -0
- package/dist/databases/mongo-db/queries/mongo-get-all.query.js +17 -0
- package/dist/databases/mongo-db/queries/mongo-get-by-id.query.d.ts +4 -0
- package/dist/databases/mongo-db/queries/mongo-get-by-id.query.js +17 -0
- package/dist/databases/mongo-db/queries/mongo-get-count.query.d.ts +2 -0
- package/dist/databases/mongo-db/queries/mongo-get-count.query.js +5 -0
- package/dist/databases/mongo-db/queries/mongo-get.query.d.ts +4 -0
- package/dist/databases/mongo-db/queries/mongo-get.query.js +14 -0
- package/dist/databases/mongo-db/utils/build-find-options.util.d.ts +3 -0
- package/dist/databases/mongo-db/utils/build-find-options.util.js +15 -0
- package/dist/databases/mongo-db/utils/build-no-sql-match.util.d.ts +3 -0
- package/dist/databases/mongo-db/utils/build-no-sql-match.util.js +59 -0
- package/dist/databases/mongo-db/utils/convert-object-ids-to-strings.util.d.ts +1 -0
- package/dist/databases/mongo-db/utils/convert-object-ids-to-strings.util.js +32 -0
- package/dist/databases/mongo-db/utils/convert-operations-to-pipeline.util.d.ts +3 -0
- package/dist/databases/mongo-db/utils/convert-operations-to-pipeline.util.js +68 -0
- package/dist/databases/mongo-db/utils/convert-query-options-to-pipeline.util.d.ts +3 -0
- package/dist/databases/mongo-db/utils/convert-query-options-to-pipeline.util.js +31 -0
- package/dist/databases/mongo-db/utils/convert-strings-to-object-ids.util.d.ts +3 -0
- package/dist/databases/mongo-db/utils/convert-strings-to-object-ids.util.js +72 -0
- package/dist/databases/mongo-db/utils/index.d.ts +7 -0
- package/dist/databases/mongo-db/utils/index.js +7 -0
- package/dist/databases/operations/join.operation.d.ts +7 -0
- package/dist/databases/operations/join.operation.js +12 -0
- package/dist/databases/operations/operation.d.ts +2 -0
- package/dist/databases/postgres/commands/postgres-batch-update.command.d.ts +4 -0
- package/dist/databases/postgres/commands/postgres-batch-update.command.js +56 -0
- package/dist/databases/postgres/commands/postgres-create-many.command.d.ts +6 -0
- package/dist/databases/postgres/commands/postgres-create-many.command.js +63 -0
- package/dist/databases/postgres/commands/postgres-create.command.d.ts +6 -0
- package/dist/databases/postgres/commands/postgres-create.command.js +29 -0
- package/dist/databases/postgres/commands/postgres-delete-by-id.command.d.ts +3 -0
- package/dist/databases/postgres/commands/postgres-delete-by-id.command.js +6 -0
- package/dist/databases/postgres/commands/postgres-delete-many.command.d.ts +4 -0
- package/dist/databases/postgres/commands/postgres-delete-many.command.js +13 -0
- package/dist/databases/postgres/commands/postgres-full-update-by-id.command.d.ts +4 -0
- package/dist/databases/postgres/commands/postgres-full-update-by-id.command.js +72 -0
- package/dist/databases/postgres/commands/postgres-partial-update-by-id.command.d.ts +4 -0
- package/dist/databases/postgres/commands/postgres-partial-update-by-id.command.js +42 -0
- package/dist/databases/postgres/commands/postgres-update.command.d.ts +5 -0
- package/dist/databases/postgres/commands/postgres-update.command.js +48 -0
- package/dist/databases/postgres/migrations/001-create-migrations-table.migration.d.ts +11 -0
- package/dist/databases/postgres/migrations/001-create-migrations-table.migration.js +52 -0
- package/dist/databases/postgres/migrations/002-create-organizations-table.migration.d.ts +11 -0
- package/dist/databases/postgres/migrations/002-create-organizations-table.migration.js +55 -0
- package/dist/databases/postgres/migrations/003-create-users-table.migration.d.ts +11 -0
- package/dist/databases/postgres/migrations/003-create-users-table.migration.js +65 -0
- package/dist/databases/postgres/migrations/004-create-refresh-token-table.migration.d.ts +11 -0
- package/dist/databases/postgres/migrations/004-create-refresh-token-table.migration.js +57 -0
- package/dist/databases/postgres/migrations/index.d.ts +3 -0
- package/dist/databases/postgres/migrations/index.js +3 -0
- package/dist/databases/postgres/migrations/migration.d.ts +6 -0
- package/dist/databases/postgres/migrations/migration.interface.d.ts +6 -0
- package/dist/databases/postgres/migrations/migration.interface.js +1 -0
- package/dist/databases/postgres/migrations/migration.js +14 -0
- package/dist/databases/postgres/migrations/runMigrations.d.ts +2 -0
- package/dist/databases/postgres/migrations/runMigrations.js +20 -0
- package/dist/databases/postgres/migrations/setup-for-auth.migration.d.ts +2 -0
- package/dist/databases/postgres/migrations/setup-for-auth.migration.js +18 -0
- package/dist/databases/postgres/migrations/setup-for-multitenant.migration.d.ts +2 -0
- package/dist/databases/postgres/migrations/setup-for-multitenant.migration.js +16 -0
- package/dist/databases/postgres/postgres.database.d.ts +31 -0
- package/dist/databases/postgres/postgres.database.js +69 -0
- package/dist/databases/postgres/queries/postgres-find-one.query.d.ts +3 -0
- package/dist/databases/postgres/queries/postgres-find-one.query.js +13 -0
- package/dist/databases/postgres/queries/postgres-find.query.d.ts +3 -0
- package/dist/databases/postgres/queries/postgres-find.query.js +11 -0
- package/dist/databases/postgres/queries/postgres-get-all.query.d.ts +3 -0
- package/dist/databases/postgres/queries/postgres-get-all.query.js +14 -0
- package/dist/databases/postgres/queries/postgres-get-by-id.query.d.ts +4 -0
- package/dist/databases/postgres/queries/postgres-get-by-id.query.js +26 -0
- package/dist/databases/postgres/queries/postgres-get-count.query.d.ts +2 -0
- package/dist/databases/postgres/queries/postgres-get-count.query.js +4 -0
- package/dist/databases/postgres/queries/postgres-get.query.d.ts +4 -0
- package/dist/databases/postgres/queries/postgres-get.query.js +26 -0
- package/dist/databases/postgres/utils/build-count-query.d.ts +3 -0
- package/dist/databases/postgres/utils/build-count-query.js +7 -0
- package/dist/databases/postgres/utils/build-join-clauses.d.ts +2 -0
- package/dist/databases/postgres/utils/build-join-clauses.js +12 -0
- package/dist/databases/postgres/utils/build-order-by-clause.d.ts +2 -0
- package/dist/databases/postgres/utils/build-order-by-clause.js +8 -0
- package/dist/databases/postgres/utils/build-pagination-clause.d.ts +2 -0
- package/dist/databases/postgres/utils/build-pagination-clause.js +9 -0
- package/dist/databases/postgres/utils/build-select-clause.d.ts +3 -0
- package/dist/databases/postgres/utils/build-select-clause.js +28 -0
- package/dist/databases/postgres/utils/build-where-clause.d.ts +5 -0
- package/dist/databases/postgres/utils/build-where-clause.js +50 -0
- package/dist/databases/postgres/utils/columns-and-values-from-entity.d.ts +5 -0
- package/dist/databases/postgres/utils/columns-and-values-from-entity.js +9 -0
- package/dist/databases/postgres/utils/convert-null-to-undefined.util.d.ts +2 -0
- package/dist/databases/postgres/utils/convert-null-to-undefined.util.js +70 -0
- package/dist/databases/postgres/utils/transform-join-results.d.ts +2 -0
- package/dist/databases/postgres/utils/transform-join-results.js +33 -0
- package/dist/databases/utils/database-to-idatabase.util.d.ts +3 -0
- package/dist/databases/utils/database-to-idatabase.util.js +14 -0
- package/dist/databases/utils/get-property-schema.util.d.ts +2 -0
- package/dist/databases/utils/get-property-schema.util.js +15 -0
- package/dist/databases/utils/index.d.ts +1 -0
- package/dist/databases/utils/index.js +1 -0
- package/dist/models/base-api-config.interface.d.ts +3 -2
- package/dist/models/index.d.ts +1 -1
- package/dist/models/index.js +1 -1
- package/dist/models/refresh-token.d.ts +9 -0
- package/dist/models/refresh-token.js +2 -0
- package/dist/models/refresh-token.model.d.ts +18 -0
- package/dist/models/refresh-token.model.js +13 -0
- package/dist/models/refresh-token.spec.d.ts +1 -0
- package/dist/models/refresh-token.spec.js +12 -0
- package/dist/services/auth.service.d.ts +11 -18
- package/dist/services/auth.service.js +29 -50
- package/dist/services/generic-api-service/generic-api-service.interface.d.ts +29 -0
- package/dist/services/generic-api-service/generic-api-service.interface.js +1 -0
- package/dist/services/generic-api-service/generic-api.service.d.ts +37 -0
- package/dist/services/generic-api-service/generic-api.service.js +178 -0
- package/dist/services/index.d.ts +2 -2
- package/dist/services/index.js +2 -2
- package/dist/services/multi-tenant-api.service.d.ts +9 -6
- package/dist/services/multi-tenant-api.service.js +10 -23
- package/dist/services/organization.service.d.ts +5 -5
- package/dist/services/organization.service.js +9 -6
- package/dist/services/password-reset-token.service.d.ts +3 -3
- package/dist/services/password-reset-token.service.js +5 -5
- package/dist/services/tenant-query-decorator.d.ts +1 -1
- package/dist/services/tenant-query-decorator.js +1 -1
- package/dist/services/user.service.d.ts +4 -6
- package/dist/services/user.service.js +4 -10
- package/dist/services/utils/audit-for-create.util.d.ts +2 -0
- package/dist/services/utils/audit-for-create.util.js +9 -0
- package/dist/services/utils/audit-for-update.util.d.ts +2 -0
- package/dist/services/utils/audit-for-update.util.js +7 -0
- package/dist/services/utils/strip-sender-provided-system-properties.util.d.ts +2 -0
- package/dist/services/utils/strip-sender-provided-system-properties.util.js +15 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/utils/api.utils.js +2 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/sql.db.utils.d.ts +14 -0
- package/dist/utils/sql.db.utils.js +94 -0
- package/package.json +4 -2
- package/dist/services/generic-api-service.interface.d.ts +0 -27
- package/dist/services/generic-api.service.d.ts +0 -50
- package/dist/services/generic-api.service.js +0 -424
- package/dist/utils/db.utils.d.ts +0 -27
- package/dist/utils/db.utils.js +0 -323
- /package/dist/{controllers/api-controller.utils.d.ts → __tests__/test-database.interface.js} +0 -0
- /package/dist/{controllers/api-controller.utils.js → databases/models/database.interface.js} +0 -0
- /package/dist/{models/types/index.d.ts → databases/models/database.js} +0 -0
- /package/dist/{models/types/index.js → databases/mongo-db/models/no-sql-pipeline.interface.js} +0 -0
- /package/dist/{services/generic-api-service.interface.js → databases/operations/operation.js} +0 -0
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { Db, UpdateResult } from 'mongodb';
|
|
2
1
|
import { Request, Response } from 'express';
|
|
3
2
|
import { IUserContext, IUser, ITokenResponse, ILoginResponse } from '@loomcore/common/models';
|
|
4
|
-
import { GenericApiService } from './generic-api.service.js';
|
|
3
|
+
import { GenericApiService } from './generic-api-service/generic-api.service.js';
|
|
4
|
+
import { UpdateResult } from '../databases/models/update-result.js';
|
|
5
|
+
import { IRefreshToken } from '../models/refresh-token.model.js';
|
|
6
|
+
import { IDatabase } from '../databases/models/index.js';
|
|
5
7
|
export declare class AuthService extends GenericApiService<IUser> {
|
|
6
|
-
private
|
|
8
|
+
private refreshTokenService;
|
|
7
9
|
private passwordResetTokenService;
|
|
8
10
|
private emailService;
|
|
9
|
-
constructor(
|
|
11
|
+
constructor(database: IDatabase);
|
|
10
12
|
attemptLogin(req: Request, res: Response, email: string, password: string): Promise<ILoginResponse | null>;
|
|
11
13
|
logUserIn(userContext: IUserContext, deviceId: string): Promise<{
|
|
12
14
|
tokens: {
|
|
@@ -20,25 +22,18 @@ export declare class AuthService extends GenericApiService<IUser> {
|
|
|
20
22
|
getUserByEmail(email: string): Promise<IUser | null>;
|
|
21
23
|
createUser(userContext: IUserContext, user: IUser): Promise<IUser | null>;
|
|
22
24
|
requestTokenUsingRefreshToken(req: Request): Promise<ITokenResponse | null>;
|
|
23
|
-
changeLoggedInUsersPassword(userContext: IUserContext, body: any): Promise<UpdateResult
|
|
25
|
+
changeLoggedInUsersPassword(userContext: IUserContext, body: any): Promise<UpdateResult>;
|
|
24
26
|
changePassword(userContext: IUserContext, queryObject: any, password: string): Promise<UpdateResult>;
|
|
25
27
|
createNewTokens(userId: string, deviceId: string, refreshTokenExpiresOn: number): Promise<{
|
|
26
28
|
accessToken: string;
|
|
27
29
|
refreshToken: any;
|
|
28
30
|
expiresOn: number;
|
|
29
31
|
} | null>;
|
|
30
|
-
getActiveRefreshToken(refreshToken: string, deviceId: string): Promise<
|
|
31
|
-
createNewRefreshToken(userId: string, deviceId: string, existingExpiresOn?: number | null): Promise<
|
|
32
|
-
token: string;
|
|
33
|
-
deviceId: string;
|
|
34
|
-
userId: string;
|
|
35
|
-
expiresOn: number;
|
|
36
|
-
created: Date;
|
|
37
|
-
createdBy: string;
|
|
38
|
-
} | null>;
|
|
32
|
+
getActiveRefreshToken(userContext: IUserContext, refreshToken: string, deviceId: string): Promise<IRefreshToken | null>;
|
|
33
|
+
createNewRefreshToken(userId: string, deviceId: string, existingExpiresOn?: number | null, orgId?: string): Promise<IRefreshToken | null>;
|
|
39
34
|
sendResetPasswordEmail(emailAddress: string): Promise<void>;
|
|
40
35
|
resetPassword(email: string, passwordResetToken: string, password: string): Promise<UpdateResult>;
|
|
41
|
-
deleteRefreshTokensForDevice(deviceId: string): Promise<import("
|
|
36
|
+
deleteRefreshTokensForDevice(deviceId: string): Promise<import("../databases/models/delete-result.js").DeleteResult>;
|
|
42
37
|
generateJwt(payload: any): string;
|
|
43
38
|
generateRefreshToken(): string;
|
|
44
39
|
generateDeviceId(): string;
|
|
@@ -47,8 +42,6 @@ export declare class AuthService extends GenericApiService<IUser> {
|
|
|
47
42
|
getExpiresOnFromSeconds(expiresInSeconds: number): number;
|
|
48
43
|
getExpiresOnFromMinutes(expiresInMinutes: number): number;
|
|
49
44
|
getExpiresOnFromDays(expiresInDays: number): number;
|
|
50
|
-
|
|
51
|
-
transformList(users: IUser[]): IUser[];
|
|
52
|
-
transformSingle(user: IUser): IUser;
|
|
45
|
+
preprocessEntity(userContext: IUserContext, entity: Partial<IUser>, isCreate: boolean, allowId: boolean): Promise<Partial<IUser>>;
|
|
53
46
|
private updateLastLoggedIn;
|
|
54
47
|
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { ObjectId } from 'mongodb';
|
|
2
1
|
import moment from 'moment';
|
|
3
2
|
import crypto from 'crypto';
|
|
4
3
|
import { EmptyUserContext, passwordValidator, UserSpec, getSystemUserContext } from '@loomcore/common/models';
|
|
5
4
|
import { entityUtils } from '@loomcore/common/utils';
|
|
6
5
|
import { BadRequestError, ServerError } from '../errors/index.js';
|
|
7
6
|
import { JwtService, EmailService } from './index.js';
|
|
8
|
-
import { GenericApiService } from './generic-api.service.js';
|
|
7
|
+
import { GenericApiService } from './generic-api-service/generic-api.service.js';
|
|
9
8
|
import { PasswordResetTokenService } from './password-reset-token.service.js';
|
|
10
9
|
import { passwordUtils } from '../utils/index.js';
|
|
11
10
|
import { config } from '../config/index.js';
|
|
11
|
+
import { refreshTokenModelSpec } from '../models/refresh-token.model.js';
|
|
12
12
|
export class AuthService extends GenericApiService {
|
|
13
|
-
|
|
13
|
+
refreshTokenService;
|
|
14
14
|
passwordResetTokenService;
|
|
15
15
|
emailService;
|
|
16
|
-
constructor(
|
|
17
|
-
super(
|
|
18
|
-
this.
|
|
19
|
-
this.passwordResetTokenService = new PasswordResetTokenService(
|
|
16
|
+
constructor(database) {
|
|
17
|
+
super(database, 'users', 'user', UserSpec);
|
|
18
|
+
this.refreshTokenService = new GenericApiService(database, 'refreshTokens', 'refreshToken', refreshTokenModelSpec);
|
|
19
|
+
this.passwordResetTokenService = new PasswordResetTokenService(database);
|
|
20
20
|
this.emailService = new EmailService();
|
|
21
21
|
}
|
|
22
22
|
async attemptLogin(req, res, email, password) {
|
|
@@ -40,7 +40,7 @@ export class AuthService extends GenericApiService {
|
|
|
40
40
|
async logUserIn(userContext, deviceId) {
|
|
41
41
|
const payload = userContext;
|
|
42
42
|
const accessToken = this.generateJwt(payload);
|
|
43
|
-
const refreshTokenObject = await this.createNewRefreshToken(userContext.user._id
|
|
43
|
+
const refreshTokenObject = await this.createNewRefreshToken(userContext.user._id, deviceId, null, userContext._orgId);
|
|
44
44
|
const accessTokenExpiresOn = this.getExpiresOnFromSeconds(config.auth.jwtExpirationInSeconds);
|
|
45
45
|
let loginResponse = null;
|
|
46
46
|
if (refreshTokenObject) {
|
|
@@ -51,20 +51,17 @@ export class AuthService extends GenericApiService {
|
|
|
51
51
|
};
|
|
52
52
|
this.updateLastLoggedIn(userContext.user._id)
|
|
53
53
|
.catch(err => console.log(`Error updating lastLoggedIn: ${err}`));
|
|
54
|
-
userContext.user = this.
|
|
54
|
+
userContext.user = this.postprocessEntity(userContext, userContext.user);
|
|
55
55
|
loginResponse = { tokens: tokenResponse, userContext };
|
|
56
56
|
}
|
|
57
57
|
return loginResponse;
|
|
58
58
|
}
|
|
59
59
|
async getUserById(id) {
|
|
60
|
-
|
|
61
|
-
throw new BadRequestError('id is not a valid ObjectId');
|
|
62
|
-
}
|
|
63
|
-
const user = await this.findOne(EmptyUserContext, { _id: new ObjectId(id) });
|
|
60
|
+
const user = await this.findOne(EmptyUserContext, { filters: { _id: { eq: id } } });
|
|
64
61
|
return user;
|
|
65
62
|
}
|
|
66
63
|
async getUserByEmail(email) {
|
|
67
|
-
const user = await this.findOne(EmptyUserContext, { email: email.toLowerCase() });
|
|
64
|
+
const user = await this.findOne(EmptyUserContext, { filters: { email: { eq: email.toLowerCase() } } });
|
|
68
65
|
return user;
|
|
69
66
|
}
|
|
70
67
|
async createUser(userContext, user) {
|
|
@@ -75,9 +72,9 @@ export class AuthService extends GenericApiService {
|
|
|
75
72
|
const refreshToken = req.query.refreshToken;
|
|
76
73
|
const deviceId = this.getDeviceIdFromCookie(req);
|
|
77
74
|
let tokens = null;
|
|
78
|
-
if (refreshToken && typeof refreshToken === 'string' && deviceId) {
|
|
75
|
+
if (refreshToken && typeof refreshToken === 'string' && deviceId && typeof deviceId === 'string') {
|
|
79
76
|
let userId = null;
|
|
80
|
-
const activeRefreshToken = await this.getActiveRefreshToken(refreshToken, deviceId);
|
|
77
|
+
const activeRefreshToken = await this.getActiveRefreshToken(EmptyUserContext, refreshToken, deviceId);
|
|
81
78
|
if (activeRefreshToken) {
|
|
82
79
|
userId = activeRefreshToken.userId;
|
|
83
80
|
if (userId) {
|
|
@@ -88,36 +85,31 @@ export class AuthService extends GenericApiService {
|
|
|
88
85
|
return tokens;
|
|
89
86
|
}
|
|
90
87
|
async changeLoggedInUsersPassword(userContext, body) {
|
|
91
|
-
const queryObject = { _id:
|
|
88
|
+
const queryObject = { _id: userContext.user._id };
|
|
92
89
|
const result = await this.changePassword(userContext, queryObject, body.password);
|
|
93
90
|
return result;
|
|
94
91
|
}
|
|
95
92
|
async changePassword(userContext, queryObject, password) {
|
|
96
|
-
const
|
|
97
|
-
const updates = { password: hashedPassword, _lastPasswordChange: moment().utc().toDate() };
|
|
93
|
+
const updates = { password: password, _lastPasswordChange: moment().utc().toDate() };
|
|
98
94
|
const updatedUsers = await super.update(userContext, queryObject, updates);
|
|
99
95
|
const result = {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
upsertedId: null,
|
|
103
|
-
upsertedCount: 0,
|
|
104
|
-
matchedCount: updatedUsers.length
|
|
96
|
+
success: true,
|
|
97
|
+
count: updatedUsers.length,
|
|
105
98
|
};
|
|
106
99
|
return result;
|
|
107
100
|
}
|
|
108
101
|
async createNewTokens(userId, deviceId, refreshTokenExpiresOn) {
|
|
109
102
|
let createdRefreshTokenObject = null;
|
|
110
|
-
const
|
|
111
|
-
|
|
103
|
+
const user = await this.getUserById(userId);
|
|
104
|
+
const newRefreshToken = await this.createNewRefreshToken(userId, deviceId, refreshTokenExpiresOn, user?._orgId);
|
|
112
105
|
if (newRefreshToken) {
|
|
113
106
|
createdRefreshTokenObject = newRefreshToken;
|
|
114
|
-
user = await this.getUserById(userId);
|
|
115
107
|
}
|
|
116
108
|
let tokenResponse = null;
|
|
117
109
|
if (user && createdRefreshTokenObject) {
|
|
118
110
|
const payload = {
|
|
119
111
|
user: user,
|
|
120
|
-
_orgId: user._orgId
|
|
112
|
+
_orgId: user._orgId
|
|
121
113
|
};
|
|
122
114
|
const accessToken = this.generateJwt(payload);
|
|
123
115
|
const accessTokenExpiresOn = this.getExpiresOnFromSeconds(config.auth.jwtExpirationInSeconds);
|
|
@@ -129,8 +121,8 @@ export class AuthService extends GenericApiService {
|
|
|
129
121
|
}
|
|
130
122
|
return tokenResponse;
|
|
131
123
|
}
|
|
132
|
-
async getActiveRefreshToken(refreshToken, deviceId) {
|
|
133
|
-
const refreshTokenResult = await this.
|
|
124
|
+
async getActiveRefreshToken(userContext, refreshToken, deviceId) {
|
|
125
|
+
const refreshTokenResult = await this.refreshTokenService.findOne(userContext, { filters: { token: { eq: refreshToken }, deviceId: { eq: deviceId } } });
|
|
134
126
|
let activeRefreshToken = null;
|
|
135
127
|
if (refreshTokenResult) {
|
|
136
128
|
const now = Date.now();
|
|
@@ -141,9 +133,10 @@ export class AuthService extends GenericApiService {
|
|
|
141
133
|
}
|
|
142
134
|
return activeRefreshToken;
|
|
143
135
|
}
|
|
144
|
-
async createNewRefreshToken(userId, deviceId, existingExpiresOn = null) {
|
|
136
|
+
async createNewRefreshToken(userId, deviceId, existingExpiresOn = null, orgId) {
|
|
145
137
|
const expiresOn = existingExpiresOn ? existingExpiresOn : this.getExpiresOnFromDays(config.auth.refreshTokenExpirationInDays);
|
|
146
138
|
const newRefreshToken = {
|
|
139
|
+
_orgId: orgId,
|
|
147
140
|
token: this.generateRefreshToken(),
|
|
148
141
|
deviceId,
|
|
149
142
|
userId,
|
|
@@ -152,12 +145,8 @@ export class AuthService extends GenericApiService {
|
|
|
152
145
|
createdBy: userId
|
|
153
146
|
};
|
|
154
147
|
const deleteResult = await this.deleteRefreshTokensForDevice(deviceId);
|
|
155
|
-
const insertResult = await this.
|
|
156
|
-
|
|
157
|
-
if (insertResult.insertedId) {
|
|
158
|
-
tokenResult = newRefreshToken;
|
|
159
|
-
}
|
|
160
|
-
return tokenResult;
|
|
148
|
+
const insertResult = await this.refreshTokenService.create(EmptyUserContext, newRefreshToken);
|
|
149
|
+
return insertResult;
|
|
161
150
|
}
|
|
162
151
|
async sendResetPasswordEmail(emailAddress) {
|
|
163
152
|
const expiresOn = this.getExpiresOnFromMinutes(config.auth.passwordResetTokenExpirationInMinutes);
|
|
@@ -190,7 +179,7 @@ export class AuthService extends GenericApiService {
|
|
|
190
179
|
return result;
|
|
191
180
|
}
|
|
192
181
|
deleteRefreshTokensForDevice(deviceId) {
|
|
193
|
-
return this.
|
|
182
|
+
return this.refreshTokenService.deleteMany(EmptyUserContext, { filters: { deviceId: { eq: deviceId } } });
|
|
194
183
|
}
|
|
195
184
|
generateJwt(payload) {
|
|
196
185
|
if (payload._orgId !== undefined) {
|
|
@@ -242,7 +231,7 @@ export class AuthService extends GenericApiService {
|
|
|
242
231
|
getExpiresOnFromDays(expiresInDays) {
|
|
243
232
|
return Date.now() + expiresInDays * 24 * 60 * 60 * 1000;
|
|
244
233
|
}
|
|
245
|
-
async
|
|
234
|
+
async preprocessEntity(userContext, entity, isCreate, allowId) {
|
|
246
235
|
if (entity.email) {
|
|
247
236
|
entity.email = entity.email.toLowerCase();
|
|
248
237
|
}
|
|
@@ -253,26 +242,16 @@ export class AuthService extends GenericApiService {
|
|
|
253
242
|
if (isCreate && !entity.roles) {
|
|
254
243
|
entity.roles = ["user"];
|
|
255
244
|
}
|
|
256
|
-
const preparedEntity = await super.
|
|
245
|
+
const preparedEntity = await super.preprocessEntity(userContext, entity, isCreate, allowId);
|
|
257
246
|
return preparedEntity;
|
|
258
247
|
}
|
|
259
|
-
transformList(users) {
|
|
260
|
-
return super.transformList(users);
|
|
261
|
-
}
|
|
262
|
-
transformSingle(user) {
|
|
263
|
-
return super.transformSingle(user);
|
|
264
|
-
}
|
|
265
248
|
async updateLastLoggedIn(userId) {
|
|
266
249
|
try {
|
|
267
|
-
if (!entityUtils.isValidObjectId(userId)) {
|
|
268
|
-
throw new BadRequestError('userId is not a valid ObjectId');
|
|
269
|
-
}
|
|
270
250
|
const updates = { _lastLoggedIn: moment().utc().toDate() };
|
|
271
251
|
const systemUserContext = getSystemUserContext();
|
|
272
252
|
await this.partialUpdateById(systemUserContext, userId, updates);
|
|
273
253
|
}
|
|
274
254
|
catch (error) {
|
|
275
|
-
console.log(`Failed to update lastLoggedIn for user ${userId}: ${error}`);
|
|
276
255
|
}
|
|
277
256
|
}
|
|
278
257
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ValueError } from '@sinclair/typebox/errors';
|
|
2
|
+
import { IUserContext, IEntity, IPagedResult, IQueryOptions } from '@loomcore/common/models';
|
|
3
|
+
import { DeleteResult } from '../../databases/models/delete-result.js';
|
|
4
|
+
import { Operation } from '../../databases/operations/operation.js';
|
|
5
|
+
export interface IGenericApiService<T extends IEntity> {
|
|
6
|
+
validate(doc: any, isPartial?: boolean): ValueError[] | null;
|
|
7
|
+
validateMany(docs: any[], isPartial?: boolean): ValueError[] | null;
|
|
8
|
+
prepareQuery(userContext: IUserContext | undefined, queryObject: IQueryOptions, operations: Operation[]): {
|
|
9
|
+
queryObject: IQueryOptions;
|
|
10
|
+
operations: Operation[];
|
|
11
|
+
};
|
|
12
|
+
preprocessEntity(userContext: IUserContext, entity: Partial<T>, isCreate: boolean, allowId: boolean): Promise<Partial<T>>;
|
|
13
|
+
postprocessEntity(userContext: IUserContext, entity: T): T;
|
|
14
|
+
getAll(userContext: IUserContext): Promise<T[]>;
|
|
15
|
+
get(userContext: IUserContext, queryOptions: IQueryOptions): Promise<IPagedResult<T>>;
|
|
16
|
+
getById(userContext: IUserContext, id: string): Promise<T>;
|
|
17
|
+
getCount(userContext: IUserContext): Promise<number>;
|
|
18
|
+
create(userContext: IUserContext, entity: Partial<T>): Promise<T | null>;
|
|
19
|
+
createMany(userContext: IUserContext, entities: Partial<T>[]): Promise<T[]>;
|
|
20
|
+
batchUpdate(userContext: IUserContext, entities: Partial<T>[]): Promise<T[]>;
|
|
21
|
+
fullUpdateById(userContext: IUserContext, id: string, entity: T): Promise<T>;
|
|
22
|
+
partialUpdateById(userContext: IUserContext, id: string, entity: Partial<T>): Promise<T>;
|
|
23
|
+
partialUpdateByIdWithoutPreAndPostProcessing(userContext: IUserContext, id: string, entity: T): Promise<T>;
|
|
24
|
+
update(userContext: IUserContext, queryObject: IQueryOptions, entity: Partial<T>): Promise<T[]>;
|
|
25
|
+
deleteById(userContext: IUserContext, id: string): Promise<DeleteResult>;
|
|
26
|
+
deleteMany(userContext: IUserContext, queryObject: IQueryOptions): Promise<DeleteResult>;
|
|
27
|
+
find(userContext: IUserContext, queryObject: IQueryOptions, options?: any): Promise<T[]>;
|
|
28
|
+
findOne(userContext: IUserContext, queryObject: IQueryOptions, options?: any): Promise<T | null>;
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ValueError } from '@sinclair/typebox/errors';
|
|
2
|
+
import { IUserContext, IEntity, IQueryOptions, IPagedResult, IModelSpec } from '@loomcore/common/models';
|
|
3
|
+
import { IGenericApiService } from './generic-api-service.interface.js';
|
|
4
|
+
import { Operation } from '../../databases/operations/operation.js';
|
|
5
|
+
import { DeleteResult } from '../../databases/models/delete-result.js';
|
|
6
|
+
import { IDatabase } from '../../databases/models/index.js';
|
|
7
|
+
export declare class GenericApiService<T extends IEntity> implements IGenericApiService<T> {
|
|
8
|
+
protected database: IDatabase;
|
|
9
|
+
protected pluralResourceName: string;
|
|
10
|
+
protected singularResourceName: string;
|
|
11
|
+
protected modelSpec: IModelSpec;
|
|
12
|
+
constructor(database: IDatabase, pluralResourceName: string, singularResourceName: string, modelSpec: IModelSpec);
|
|
13
|
+
getAll(userContext: IUserContext): Promise<T[]>;
|
|
14
|
+
prepareQuery(userContext: IUserContext | undefined, queryObject: IQueryOptions, operations: Operation[]): {
|
|
15
|
+
queryObject: IQueryOptions;
|
|
16
|
+
operations: Operation[];
|
|
17
|
+
};
|
|
18
|
+
validate(doc: any, isPartial?: boolean): ValueError[] | null;
|
|
19
|
+
validateMany(docs: any[], isPartial?: boolean): ValueError[] | null;
|
|
20
|
+
preprocessEntity(userContext: IUserContext, entity: Partial<T>, isCreate: boolean, allowId?: boolean): Promise<Partial<T>>;
|
|
21
|
+
postprocessEntity(userContext: IUserContext, entity: T): T;
|
|
22
|
+
get(userContext: IUserContext, queryOptions?: IQueryOptions): Promise<IPagedResult<T>>;
|
|
23
|
+
protected prepareQueryOptions(userContext: IUserContext | undefined, queryOptions: IQueryOptions): IQueryOptions;
|
|
24
|
+
getById(userContext: IUserContext, id: string): Promise<T>;
|
|
25
|
+
getCount(userContext: IUserContext): Promise<number>;
|
|
26
|
+
create(userContext: IUserContext, entity: Partial<T>): Promise<T | null>;
|
|
27
|
+
createMany(userContext: IUserContext, entities: Partial<T>[]): Promise<T[]>;
|
|
28
|
+
batchUpdate(userContext: IUserContext, entities: Partial<T>[]): Promise<T[]>;
|
|
29
|
+
fullUpdateById(userContext: IUserContext, id: string, entity: T): Promise<T>;
|
|
30
|
+
partialUpdateById(userContext: IUserContext, id: string, entity: Partial<T>): Promise<T>;
|
|
31
|
+
partialUpdateByIdWithoutPreAndPostProcessing(userContext: IUserContext, id: string, entity: Partial<T>): Promise<T>;
|
|
32
|
+
update(userContext: IUserContext, queryObject: IQueryOptions, entity: Partial<T>): Promise<T[]>;
|
|
33
|
+
deleteById(userContext: IUserContext, id: string): Promise<DeleteResult>;
|
|
34
|
+
deleteMany(userContext: IUserContext, queryObject: IQueryOptions): Promise<DeleteResult>;
|
|
35
|
+
find(userContext: IUserContext, queryObject: IQueryOptions): Promise<T[]>;
|
|
36
|
+
findOne(userContext: IUserContext, queryObject: IQueryOptions): Promise<T | null>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import { DefaultQueryOptions } from '@loomcore/common/models';
|
|
3
|
+
import { entityUtils } from '@loomcore/common/utils';
|
|
4
|
+
import { stripSenderProvidedSystemProperties } from '../utils/strip-sender-provided-system-properties.util.js';
|
|
5
|
+
import { auditForCreate } from '../utils/audit-for-create.util.js';
|
|
6
|
+
import { auditForUpdate } from '../utils/audit-for-update.util.js';
|
|
7
|
+
import { IdNotFoundError, ServerError } from '../../errors/index.js';
|
|
8
|
+
export class GenericApiService {
|
|
9
|
+
database;
|
|
10
|
+
pluralResourceName;
|
|
11
|
+
singularResourceName;
|
|
12
|
+
modelSpec;
|
|
13
|
+
constructor(database, pluralResourceName, singularResourceName, modelSpec) {
|
|
14
|
+
this.pluralResourceName = pluralResourceName;
|
|
15
|
+
this.singularResourceName = singularResourceName;
|
|
16
|
+
this.modelSpec = modelSpec;
|
|
17
|
+
this.database = database;
|
|
18
|
+
}
|
|
19
|
+
async getAll(userContext) {
|
|
20
|
+
const { operations } = this.prepareQuery(userContext, {}, []);
|
|
21
|
+
const entities = await this.database.getAll(operations, this.pluralResourceName);
|
|
22
|
+
return entities.map(entity => this.postprocessEntity(userContext, entity));
|
|
23
|
+
}
|
|
24
|
+
prepareQuery(userContext, queryObject, operations) {
|
|
25
|
+
return { queryObject, operations };
|
|
26
|
+
}
|
|
27
|
+
validate(doc, isPartial = false) {
|
|
28
|
+
const validator = isPartial ? this.modelSpec.partialValidator : this.modelSpec.validator;
|
|
29
|
+
return entityUtils.validate(validator, doc);
|
|
30
|
+
}
|
|
31
|
+
validateMany(docs, isPartial = false) {
|
|
32
|
+
const validator = isPartial ? this.modelSpec.partialValidator : this.modelSpec.validator;
|
|
33
|
+
let allErrors = [];
|
|
34
|
+
for (const doc of docs) {
|
|
35
|
+
const errors = entityUtils.validate(validator, doc);
|
|
36
|
+
if (errors && errors.length > 0) {
|
|
37
|
+
allErrors.push(...errors);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return allErrors.length > 0 ? allErrors : null;
|
|
41
|
+
}
|
|
42
|
+
async preprocessEntity(userContext, entity, isCreate, allowId = true) {
|
|
43
|
+
let preparedEntity = _.clone(entity);
|
|
44
|
+
stripSenderProvidedSystemProperties(userContext, preparedEntity, allowId);
|
|
45
|
+
if (this.modelSpec.isAuditable) {
|
|
46
|
+
if (isCreate) {
|
|
47
|
+
auditForCreate(userContext, preparedEntity);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
auditForUpdate(userContext, preparedEntity);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (!this.modelSpec?.fullSchema) {
|
|
54
|
+
throw new ServerError(`Cannot prepare entity: No model specification with schema provided for ${this.pluralResourceName}`);
|
|
55
|
+
}
|
|
56
|
+
let cleanedEntity = preparedEntity;
|
|
57
|
+
if (this.modelSpec) {
|
|
58
|
+
cleanedEntity = this.modelSpec.decode(preparedEntity);
|
|
59
|
+
}
|
|
60
|
+
preparedEntity = this.database.preprocessEntity(cleanedEntity, this.modelSpec.fullSchema);
|
|
61
|
+
return preparedEntity;
|
|
62
|
+
}
|
|
63
|
+
postprocessEntity(userContext, entity) {
|
|
64
|
+
return this.database.postprocessEntity(entity, this.modelSpec.fullSchema);
|
|
65
|
+
}
|
|
66
|
+
async get(userContext, queryOptions = { ...DefaultQueryOptions }) {
|
|
67
|
+
const preparedOptions = this.prepareQueryOptions(userContext, queryOptions);
|
|
68
|
+
const { operations } = this.prepareQuery(userContext, {}, []);
|
|
69
|
+
const pagedResult = await this.database.get(operations, preparedOptions, this.modelSpec, this.pluralResourceName);
|
|
70
|
+
const transformedEntities = (pagedResult.entities || []).map(entity => this.postprocessEntity(userContext, entity));
|
|
71
|
+
return {
|
|
72
|
+
...pagedResult,
|
|
73
|
+
entities: transformedEntities
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
prepareQueryOptions(userContext, queryOptions) {
|
|
77
|
+
return queryOptions;
|
|
78
|
+
}
|
|
79
|
+
async getById(userContext, id) {
|
|
80
|
+
const { operations, queryObject } = this.prepareQuery(userContext, {}, []);
|
|
81
|
+
const entity = await this.database.getById(operations, queryObject, id, this.pluralResourceName);
|
|
82
|
+
if (!entity) {
|
|
83
|
+
throw new IdNotFoundError();
|
|
84
|
+
}
|
|
85
|
+
return this.postprocessEntity(userContext, entity);
|
|
86
|
+
}
|
|
87
|
+
async getCount(userContext) {
|
|
88
|
+
this.prepareQuery(userContext, {}, []);
|
|
89
|
+
return await this.database.getCount(this.pluralResourceName);
|
|
90
|
+
}
|
|
91
|
+
async create(userContext, entity) {
|
|
92
|
+
let createdEntity = null;
|
|
93
|
+
const preparedEntity = await this.preprocessEntity(userContext, entity, true, true);
|
|
94
|
+
const insertResult = await this.database.create(preparedEntity, this.pluralResourceName);
|
|
95
|
+
if (insertResult.insertedId) {
|
|
96
|
+
createdEntity = this.postprocessEntity(userContext, insertResult.entity);
|
|
97
|
+
}
|
|
98
|
+
return createdEntity;
|
|
99
|
+
}
|
|
100
|
+
async createMany(userContext, entities) {
|
|
101
|
+
let createdEntities = [];
|
|
102
|
+
if (entities.length) {
|
|
103
|
+
const preparedEntities = await Promise.all(entities.map(entity => this.preprocessEntity(userContext, entity, true, true)));
|
|
104
|
+
const insertResult = await this.database.createMany(preparedEntities, this.pluralResourceName);
|
|
105
|
+
if (insertResult.insertedIds) {
|
|
106
|
+
createdEntities = insertResult.entities.map(entity => this.postprocessEntity(userContext, entity));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return createdEntities;
|
|
110
|
+
}
|
|
111
|
+
async batchUpdate(userContext, entities) {
|
|
112
|
+
if (!entities || entities.length === 0) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
const preparedEntities = await Promise.all(entities.map(entity => this.preprocessEntity(userContext, entity, false, true)));
|
|
116
|
+
const { queryObject, operations } = this.prepareQuery(userContext, {}, []);
|
|
117
|
+
const rawUpdatedEntities = await this.database.batchUpdate(preparedEntities, operations, queryObject, this.pluralResourceName);
|
|
118
|
+
const updatedEntities = rawUpdatedEntities.map(entity => this.postprocessEntity(userContext, entity));
|
|
119
|
+
return updatedEntities;
|
|
120
|
+
}
|
|
121
|
+
async fullUpdateById(userContext, id, entity) {
|
|
122
|
+
const { operations, queryObject } = this.prepareQuery(userContext, {}, []);
|
|
123
|
+
const existingEntity = await this.database.getById(operations, queryObject, id, this.pluralResourceName);
|
|
124
|
+
if (!existingEntity) {
|
|
125
|
+
throw new IdNotFoundError();
|
|
126
|
+
}
|
|
127
|
+
const auditProperties = {
|
|
128
|
+
_created: existingEntity._created,
|
|
129
|
+
_createdBy: existingEntity._createdBy,
|
|
130
|
+
};
|
|
131
|
+
const preparedEntity = await this.preprocessEntity(userContext, entity, false, true);
|
|
132
|
+
Object.assign(preparedEntity, auditProperties);
|
|
133
|
+
const rawUpdatedEntity = await this.database.fullUpdateById(operations, id, preparedEntity, this.pluralResourceName);
|
|
134
|
+
const updatedEntity = this.postprocessEntity(userContext, rawUpdatedEntity);
|
|
135
|
+
return updatedEntity;
|
|
136
|
+
}
|
|
137
|
+
async partialUpdateById(userContext, id, entity) {
|
|
138
|
+
const { operations } = this.prepareQuery(userContext, {}, []);
|
|
139
|
+
const preparedEntity = await this.preprocessEntity(userContext, entity, false, true);
|
|
140
|
+
const rawUpdatedEntity = await this.database.partialUpdateById(operations, id, preparedEntity, this.pluralResourceName);
|
|
141
|
+
const updatedEntity = this.postprocessEntity(userContext, rawUpdatedEntity);
|
|
142
|
+
return updatedEntity;
|
|
143
|
+
}
|
|
144
|
+
async partialUpdateByIdWithoutPreAndPostProcessing(userContext, id, entity) {
|
|
145
|
+
const preparedEntity = this.database.preprocessEntity(entity, this.modelSpec.fullSchema);
|
|
146
|
+
const rawUpdatedEntity = await this.database.partialUpdateById([], id, preparedEntity, this.pluralResourceName);
|
|
147
|
+
return this.database.postprocessEntity(rawUpdatedEntity, this.modelSpec.fullSchema);
|
|
148
|
+
}
|
|
149
|
+
async update(userContext, queryObject, entity) {
|
|
150
|
+
const { queryObject: preparedQuery, operations } = this.prepareQuery(userContext, queryObject, []);
|
|
151
|
+
const preparedEntity = await this.preprocessEntity(userContext, entity, false, true);
|
|
152
|
+
const rawUpdatedEntities = await this.database.update(preparedQuery, preparedEntity, operations, this.pluralResourceName);
|
|
153
|
+
const updatedEntities = rawUpdatedEntities.map(entity => this.postprocessEntity(userContext, entity));
|
|
154
|
+
return updatedEntities;
|
|
155
|
+
}
|
|
156
|
+
async deleteById(userContext, id) {
|
|
157
|
+
const deleteResult = await this.database.deleteById(id, this.pluralResourceName);
|
|
158
|
+
if (deleteResult.count <= 0) {
|
|
159
|
+
throw new IdNotFoundError();
|
|
160
|
+
}
|
|
161
|
+
return deleteResult;
|
|
162
|
+
}
|
|
163
|
+
async deleteMany(userContext, queryObject) {
|
|
164
|
+
const { queryObject: preparedQuery, operations } = this.prepareQuery(userContext, queryObject, []);
|
|
165
|
+
const deleteResult = await this.database.deleteMany(preparedQuery, this.pluralResourceName);
|
|
166
|
+
return deleteResult;
|
|
167
|
+
}
|
|
168
|
+
async find(userContext, queryObject) {
|
|
169
|
+
const { queryObject: preparedQuery, operations } = this.prepareQuery(userContext, queryObject, []);
|
|
170
|
+
const rawEntities = await this.database.find(preparedQuery, this.pluralResourceName);
|
|
171
|
+
return rawEntities.map(entity => this.postprocessEntity(userContext, entity));
|
|
172
|
+
}
|
|
173
|
+
async findOne(userContext, queryObject) {
|
|
174
|
+
const { queryObject: preparedQuery, operations } = this.prepareQuery(userContext, queryObject, []);
|
|
175
|
+
const rawEntity = await this.database.findOne(preparedQuery, this.pluralResourceName);
|
|
176
|
+
return rawEntity ? this.postprocessEntity(userContext, rawEntity) : null;
|
|
177
|
+
}
|
|
178
|
+
}
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './auth.service.js';
|
|
2
2
|
export * from './email.service.js';
|
|
3
|
-
export * from './generic-api.service.js';
|
|
4
|
-
export * from './generic-api-service.interface.js';
|
|
3
|
+
export * from './generic-api-service/generic-api.service.js';
|
|
4
|
+
export * from './generic-api-service/generic-api-service.interface.js';
|
|
5
5
|
export * from './jwt.service.js';
|
|
6
6
|
export * from './multi-tenant-api.service.js';
|
|
7
7
|
export * from './organization.service.js';
|
package/dist/services/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './auth.service.js';
|
|
2
2
|
export * from './email.service.js';
|
|
3
|
-
export * from './generic-api.service.js';
|
|
4
|
-
export * from './generic-api-service.interface.js';
|
|
3
|
+
export * from './generic-api-service/generic-api.service.js';
|
|
4
|
+
export * from './generic-api-service/generic-api-service.interface.js';
|
|
5
5
|
export * from './jwt.service.js';
|
|
6
6
|
export * from './multi-tenant-api.service.js';
|
|
7
7
|
export * from './organization.service.js';
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { Db } from 'mongodb';
|
|
2
1
|
import { IUserContext, IEntity, IQueryOptions, IModelSpec } from '@loomcore/common/models';
|
|
3
|
-
import {
|
|
2
|
+
import { Operation } from '../databases/operations/operation.js';
|
|
3
|
+
import { GenericApiService } from './generic-api-service/generic-api.service.js';
|
|
4
|
+
import { IDatabase } from '../databases/models/index.js';
|
|
4
5
|
export declare class MultiTenantApiService<T extends IEntity> extends GenericApiService<T> {
|
|
5
6
|
private tenantDecorator?;
|
|
6
|
-
constructor(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
constructor(database: IDatabase, pluralResourceName: string, singularResourceName: string, modelSpec: IModelSpec);
|
|
8
|
+
prepareQuery(userContext: IUserContext, queryOptions: IQueryOptions, operations: Operation[]): {
|
|
9
|
+
queryObject: IQueryOptions;
|
|
10
|
+
operations: Operation[];
|
|
11
|
+
};
|
|
12
|
+
preprocessEntity(userContext: IUserContext, entity: Partial<T>, isCreate: boolean, allowId?: boolean): Promise<Partial<T>>;
|
|
10
13
|
}
|
|
@@ -1,46 +1,33 @@
|
|
|
1
|
-
import { GenericApiService } from './generic-api.service.js';
|
|
2
1
|
import { TenantQueryDecorator } from './tenant-query-decorator.js';
|
|
3
2
|
import { BadRequestError } from '../errors/bad-request.error.js';
|
|
4
3
|
import { config } from '../config/base-api-config.js';
|
|
4
|
+
import { GenericApiService } from './generic-api-service/generic-api.service.js';
|
|
5
5
|
export class MultiTenantApiService extends GenericApiService {
|
|
6
6
|
tenantDecorator;
|
|
7
|
-
constructor(
|
|
8
|
-
super(
|
|
7
|
+
constructor(database, pluralResourceName, singularResourceName, modelSpec) {
|
|
8
|
+
super(database, pluralResourceName, singularResourceName, modelSpec);
|
|
9
9
|
if (config?.app?.isMultiTenant) {
|
|
10
10
|
this.tenantDecorator = new TenantQueryDecorator();
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
prepareQuery(userContext,
|
|
13
|
+
prepareQuery(userContext, queryOptions, operations) {
|
|
14
14
|
if (!config?.app?.isMultiTenant) {
|
|
15
|
-
return super.prepareQuery(userContext,
|
|
15
|
+
return super.prepareQuery(userContext, queryOptions, operations);
|
|
16
16
|
}
|
|
17
17
|
if (!userContext || !userContext._orgId) {
|
|
18
18
|
throw new BadRequestError('A valid userContext was not provided to MultiTenantApiService.prepareQuery');
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
const queryObject = this.tenantDecorator.applyTenantToQuery(userContext, queryOptions, this.pluralResourceName);
|
|
21
|
+
return { queryObject, operations };
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
-
console.log('--- MultiTenantApiService.prepareQueryOptions ---');
|
|
24
|
-
console.log('Initial queryOptions.filters:', JSON.stringify(queryOptions.filters, null, 2));
|
|
23
|
+
async preprocessEntity(userContext, entity, isCreate, allowId = false) {
|
|
25
24
|
if (!config?.app?.isMultiTenant) {
|
|
26
|
-
return super.
|
|
27
|
-
}
|
|
28
|
-
if (!userContext || !userContext._orgId) {
|
|
29
|
-
throw new BadRequestError('A valid userContext was not provided to MultiTenantApiService.prepareQueryOptions');
|
|
30
|
-
}
|
|
31
|
-
const newQueryOptions = this.tenantDecorator.applyTenantToQueryOptions(userContext, queryOptions, this.pluralResourceName);
|
|
32
|
-
console.log('Final queryOptions.filters:', JSON.stringify(newQueryOptions.filters, null, 2));
|
|
33
|
-
console.log('-------------------------------------------------');
|
|
34
|
-
return newQueryOptions;
|
|
35
|
-
}
|
|
36
|
-
async prepareEntity(userContext, entity, isCreate, allowId = false) {
|
|
37
|
-
if (!config?.app?.isMultiTenant) {
|
|
38
|
-
return super.prepareEntity(userContext, entity, isCreate, allowId);
|
|
25
|
+
return super.preprocessEntity(userContext, entity, isCreate, allowId);
|
|
39
26
|
}
|
|
40
27
|
if (!userContext || !userContext._orgId) {
|
|
41
28
|
throw new BadRequestError('A valid userContext was not provided to MultiTenantApiService.prepareEntity');
|
|
42
29
|
}
|
|
43
|
-
const preparedEntity = await super.
|
|
30
|
+
const preparedEntity = await super.preprocessEntity(userContext, entity, isCreate, allowId);
|
|
44
31
|
const orgIdField = this.tenantDecorator.getOrgIdField();
|
|
45
32
|
preparedEntity[orgIdField] = userContext._orgId;
|
|
46
33
|
return preparedEntity;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { GenericApiService } from './generic-api.service.js';
|
|
1
|
+
import { GenericApiService } from './generic-api-service/generic-api.service.js';
|
|
3
2
|
import { IOrganization, IUserContext } from '@loomcore/common/models';
|
|
3
|
+
import { IDatabase } from '../databases/models/database.interface.js';
|
|
4
4
|
export declare class OrganizationService extends GenericApiService<IOrganization> {
|
|
5
|
-
constructor(
|
|
6
|
-
getAuthTokenByRepoCode(userContext: IUserContext, orgId: string): Promise<string | null
|
|
5
|
+
constructor(database: IDatabase);
|
|
6
|
+
getAuthTokenByRepoCode(userContext: IUserContext, orgId: string): Promise<string | null>;
|
|
7
7
|
validateRepoAuthToken(userContext: IUserContext, orgCode: string, authToken: string): Promise<string | null>;
|
|
8
|
-
getMetaOrg(userContext: IUserContext): Promise<IOrganization>;
|
|
8
|
+
getMetaOrg(userContext: IUserContext): Promise<IOrganization | null>;
|
|
9
9
|
}
|