@loomcore/api 0.2.51 → 0.2.52

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.
Files changed (41) hide show
  1. package/dist/__tests__/common-test.utils.d.ts +2 -0
  2. package/dist/__tests__/common-test.utils.js +7 -1
  3. package/dist/__tests__/mongo-db.test-database.js +46 -12
  4. package/dist/__tests__/test-express-app.js +10 -6
  5. package/dist/controllers/api.controller.d.ts +1 -0
  6. package/dist/controllers/api.controller.js +12 -10
  7. package/dist/controllers/auth.controller.js +6 -2
  8. package/dist/controllers/features.controller.js +58 -6
  9. package/dist/controllers/organizations.controller.js +3 -4
  10. package/dist/controllers/query-api.controller.d.ts +1 -0
  11. package/dist/controllers/query-api.controller.js +7 -5
  12. package/dist/controllers/roles.controller.js +58 -6
  13. package/dist/controllers/user-roles.controller.js +58 -6
  14. package/dist/controllers/users.controller.d.ts +4 -1
  15. package/dist/controllers/users.controller.js +87 -11
  16. package/dist/services/authorization.service.js +0 -2
  17. package/dist/services/feature.service.d.ts +1 -2
  18. package/dist/services/feature.service.js +0 -5
  19. package/dist/services/role.service.d.ts +1 -2
  20. package/dist/services/role.service.js +0 -5
  21. package/dist/services/user-role.service.d.ts +1 -2
  22. package/dist/services/user-role.service.js +0 -5
  23. package/dist/services/user.service.d.ts +4 -7
  24. package/dist/services/user.service.js +15 -38
  25. package/dist/utils/auth/authorize-method.util.d.ts +1 -1
  26. package/dist/utils/auth/index.d.ts +0 -6
  27. package/dist/utils/auth/index.js +0 -6
  28. package/dist/utils/auth/reset-password.util.js +5 -3
  29. package/package.json +1 -1
  30. package/dist/utils/auth/assert-admin-or-feature.util.d.ts +0 -2
  31. package/dist/utils/auth/assert-admin-or-feature.util.js +0 -8
  32. package/dist/utils/auth/assert-admin.util.d.ts +0 -2
  33. package/dist/utils/auth/assert-admin.util.js +0 -7
  34. package/dist/utils/auth/assert-owner-or-admin.util.d.ts +0 -2
  35. package/dist/utils/auth/assert-owner-or-admin.util.js +0 -10
  36. package/dist/utils/auth/assert-user-has-feature.util.d.ts +0 -2
  37. package/dist/utils/auth/assert-user-has-feature.util.js +0 -18
  38. package/dist/utils/auth/assert-user-or-admin.util.d.ts +0 -3
  39. package/dist/utils/auth/assert-user-or-admin.util.js +0 -10
  40. package/dist/utils/auth/change-password.util.d.ts +0 -6
  41. package/dist/utils/auth/change-password.util.js +0 -11
@@ -24,6 +24,7 @@ declare function setupTestUsers(): Promise<{
24
24
  declare function deleteTestUser(): Promise<void>;
25
25
  declare function simulateloginWithTestUser(): Promise<string>;
26
26
  declare function getAuthToken(): string;
27
+ declare function getAdminAuthToken(): string;
27
28
  declare function getExpiredAuthToken(): string;
28
29
  declare function verifyToken(token: string): any;
29
30
  export declare class CategoryService extends GenericApiService<ICategory> {
@@ -66,6 +67,7 @@ declare const testUtils: {
66
67
  deleteMetaOrg: typeof deleteMetaOrg;
67
68
  deleteTestUser: typeof deleteTestUser;
68
69
  getAuthToken: typeof getAuthToken;
70
+ getAdminAuthToken: typeof getAdminAuthToken;
69
71
  getExpiredAuthToken: typeof getExpiredAuthToken;
70
72
  getTestMetaOrgRefererUrl: typeof testObjectsModule.getTestMetaOrgRefererUrl;
71
73
  initialize: typeof initialize;
@@ -13,7 +13,7 @@ import { MultiTenantApiService } from '../services/multi-tenant-api.service.js';
13
13
  import { OrganizationService } from '../services/organization.service.js';
14
14
  import { OrganizationDomainService } from '../services/organization-domain.service.js';
15
15
  import * as testObjectsModule from './test-objects.js';
16
- const { getTestMetaOrg, getTestMetaOrgDomain, getTestMetaOrgRefererUrl, getTestOrg, getTestOrgDomain, getTestMetaOrgUser, getTestMetaOrgUserContext, getTestOrgUser, getTestOrgUserContext, setTestOrgId, setTestMetaOrgId, setTestMetaOrgUserId, setTestOrgUserId, TEST_META_ORG_DOMAIN, TEST_ORG_DOMAIN, } = testObjectsModule;
16
+ const { getTestMetaOrg, getTestMetaOrgDomain, getTestMetaOrgRefererUrl, getTestOrg, getTestOrgDomain, getTestMetaOrgAdminUserContext, getTestMetaOrgUser, getTestMetaOrgUserContext, getTestOrgUser, getTestOrgUserContext, setTestOrgId, setTestMetaOrgId, setTestMetaOrgUserId, setTestOrgUserId, TEST_META_ORG_DOMAIN, TEST_ORG_DOMAIN, } = testObjectsModule;
17
17
  import { entityUtils } from '@loomcore/common/utils';
18
18
  import { config, setBaseApiConfig } from '../config/index.js';
19
19
  import { attemptLogin } from '../utils/auth/index.js';
@@ -208,6 +208,11 @@ function getAuthToken() {
208
208
  const token = jwt.sign(userContext, JWT_SECRET, { expiresIn: 3600 });
209
209
  return `Bearer ${token}`;
210
210
  }
211
+ function getAdminAuthToken() {
212
+ const userContext = getTestMetaOrgAdminUserContext();
213
+ const token = jwt.sign(userContext, JWT_SECRET, { expiresIn: 3600 });
214
+ return `Bearer ${token}`;
215
+ }
211
216
  function getExpiredAuthToken() {
212
217
  const userContext = getTestMetaOrgUserContext();
213
218
  const token = jwt.sign(userContext, JWT_SECRET, { expiresIn: -1 });
@@ -407,6 +412,7 @@ const testUtils = {
407
412
  deleteMetaOrg,
408
413
  deleteTestUser,
409
414
  getAuthToken,
415
+ getAdminAuthToken,
410
416
  getExpiredAuthToken,
411
417
  getTestMetaOrgRefererUrl,
412
418
  initialize,
@@ -3,6 +3,35 @@ import { MongoClient, ObjectId } from 'mongodb';
3
3
  import testUtils from './common-test.utils.js';
4
4
  import { initSystemUserContext } from '../config/base-api-config.js';
5
5
  import { MongoDBDatabase } from '../databases/index.js';
6
+ function isPortBindError(error) {
7
+ const code = error?.code;
8
+ const message = error instanceof Error ? error.message : String(error);
9
+ return code === 'EACCES' || code === 'EADDRINUSE' || message.includes('EACCES') || message.includes('EADDRINUSE');
10
+ }
11
+ async function createMongoMemoryServer() {
12
+ const maxAttempts = 5;
13
+ let lastError;
14
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
15
+ try {
16
+ return await MongoMemoryServer.create({
17
+ instance: {
18
+ ip: '127.0.0.1',
19
+ port: 0,
20
+ },
21
+ binary: {
22
+ downloadDir: process.env.HOME ? `${process.env.HOME}/.cache/mongodb-binaries` : undefined,
23
+ },
24
+ });
25
+ }
26
+ catch (error) {
27
+ lastError = error;
28
+ if (!isPortBindError(error) || attempt === maxAttempts) {
29
+ throw error;
30
+ }
31
+ }
32
+ }
33
+ throw lastError;
34
+ }
6
35
  export class TestMongoDatabase {
7
36
  mongoServer = null;
8
37
  mongoClient = null;
@@ -14,22 +43,20 @@ export class TestMongoDatabase {
14
43
  return this.initPromise;
15
44
  }
16
45
  this.initPromise = this._performInit();
17
- return this.initPromise;
46
+ try {
47
+ return await this.initPromise;
48
+ }
49
+ catch (error) {
50
+ this.initPromise = null;
51
+ throw error;
52
+ }
18
53
  }
19
54
  getRandomId() {
20
55
  return new ObjectId().toString();
21
56
  }
22
57
  async _performInit() {
23
58
  if (!this.database) {
24
- this.mongoServer = await MongoMemoryServer.create({
25
- instance: {
26
- ip: '127.0.0.1',
27
- port: 0,
28
- },
29
- binary: {
30
- downloadDir: process.env.HOME ? `${process.env.HOME}/.cache/mongodb-binaries` : undefined,
31
- }
32
- });
59
+ this.mongoServer = await createMongoMemoryServer();
33
60
  const uri = this.mongoServer.getUri();
34
61
  this.mongoClient = await MongoClient.connect(uri);
35
62
  this.mongoDb = this.mongoClient.db();
@@ -57,8 +84,15 @@ export class TestMongoDatabase {
57
84
  }
58
85
  }
59
86
  async cleanup() {
60
- await testUtils.cleanup();
61
- await this.clearCollections();
87
+ if (this.database) {
88
+ await testUtils.cleanup();
89
+ }
90
+ if (this.mongoDb) {
91
+ const collections = await this.mongoDb.collections();
92
+ for (const collection of collections) {
93
+ await collection.deleteMany({});
94
+ }
95
+ }
62
96
  if (this.mongoClient) {
63
97
  await this.mongoClient.close();
64
98
  }
@@ -64,13 +64,17 @@ async function clearCollections() {
64
64
  }
65
65
  }
66
66
  async function cleanup() {
67
- if (testDatabase) {
68
- await testDatabase.cleanup();
67
+ try {
68
+ if (testDatabase) {
69
+ await testDatabase.cleanup();
70
+ }
71
+ }
72
+ finally {
73
+ initPromise = null;
74
+ app = undefined;
75
+ database = undefined;
76
+ testDatabase = undefined;
69
77
  }
70
- initPromise = null;
71
- app = undefined;
72
- database = undefined;
73
- testDatabase = undefined;
74
78
  }
75
79
  export const TestExpressApp = {
76
80
  init,
@@ -11,6 +11,7 @@ export declare abstract class ApiController<T extends IEntity> {
11
11
  protected publicSpec?: IModelSpec;
12
12
  protected idSchema: TSchema;
13
13
  protected constructor(slug: string, app: Application, service: IGenericApiService<T>, resourceName?: string, modelSpec?: IModelSpec, publicSpec?: IModelSpec);
14
+ protected authorize(method: string): import("express").RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
14
15
  mapRoutes(app: Application): void;
15
16
  protected validate(entity: any, isPartial?: boolean): void;
16
17
  protected validateMany(entities: any[], isPartial?: boolean): void;
@@ -26,17 +26,19 @@ export class ApiController {
26
26
  this.publicSpec = publicSpec;
27
27
  }
28
28
  }
29
+ authorize(method) {
30
+ return authorizeMethod(this, method);
31
+ }
29
32
  mapRoutes(app) {
30
- const authorize = (method) => authorizeMethod(this, method);
31
- app.get(`/api/${this.slug}`, authorize('get'), this.get.bind(this));
32
- app.get(`/api/${this.slug}/all`, authorize('getAll'), this.getAll.bind(this));
33
- app.get(`/api/${this.slug}/count`, authorize('getCount'), this.getCount.bind(this));
34
- app.get(`/api/${this.slug}/:id`, authorize('getById'), this.getById.bind(this));
35
- app.post(`/api/${this.slug}`, authorize('create'), this.create.bind(this));
36
- app.patch(`/api/${this.slug}/batch`, authorize('batchUpdate'), this.batchUpdate.bind(this));
37
- app.put(`/api/${this.slug}/:id`, authorize('fullUpdateById'), this.fullUpdateById.bind(this));
38
- app.patch(`/api/${this.slug}/:id`, authorize('partialUpdateById'), this.partialUpdateById.bind(this));
39
- app.delete(`/api/${this.slug}/:id`, authorize('deleteById'), this.deleteById.bind(this));
33
+ app.get(`/api/${this.slug}`, this.authorize('get'), this.get.bind(this));
34
+ app.get(`/api/${this.slug}/all`, this.authorize('getAll'), this.getAll.bind(this));
35
+ app.get(`/api/${this.slug}/count`, this.authorize('getCount'), this.getCount.bind(this));
36
+ app.get(`/api/${this.slug}/:id`, this.authorize('getById'), this.getById.bind(this));
37
+ app.post(`/api/${this.slug}`, this.authorize('create'), this.create.bind(this));
38
+ app.patch(`/api/${this.slug}/batch`, this.authorize('batchUpdate'), this.batchUpdate.bind(this));
39
+ app.put(`/api/${this.slug}/:id`, this.authorize('fullUpdateById'), this.fullUpdateById.bind(this));
40
+ app.patch(`/api/${this.slug}/:id`, this.authorize('partialUpdateById'), this.partialUpdateById.bind(this));
41
+ app.delete(`/api/${this.slug}/:id`, this.authorize('deleteById'), this.deleteById.bind(this));
40
42
  }
41
43
  validate(entity, isPartial = false) {
42
44
  const validationErrors = this.service.validate(entity, isPartial);
@@ -37,7 +37,7 @@ import { entityUtils } from '@loomcore/common/utils';
37
37
  import { config } from '../config/base-api-config.js';
38
38
  import { BadRequestError, UnauthenticatedError } from '../errors/index.js';
39
39
  import { OrganizationService, UserService } from '../services/index.js';
40
- import { attemptLogin, authorizeMethod, changePassword, createLoginResponseSpec, getAndSetDeviceIdCookie, getDeviceIdFromCookie, requestTokenUsingRefreshToken, resetPassword, sendResetPasswordEmail, } from '../utils/auth/index.js';
40
+ import { attemptLogin, authorizeMethod, createLoginResponseSpec, getAndSetDeviceIdCookie, getDeviceIdFromCookie, requestTokenUsingRefreshToken, resetPassword, sendResetPasswordEmail, } from '../utils/auth/index.js';
41
41
  import { apiUtils } from '../utils/index.js';
42
42
  import { Authorize } from '../decorators/authorize.decorator.js';
43
43
  let AuthController = (() => {
@@ -135,7 +135,11 @@ let AuthController = (() => {
135
135
  const password = req.body?.password;
136
136
  const validationErrors = entityUtils.validate(this.userSpec, { password: password }, true, passwordValidator);
137
137
  entityUtils.handleValidationResult(validationErrors, 'AuthController.changePassword');
138
- const updateResult = await changePassword(this.database, userContext, userContext.user._id, password, this.userService);
138
+ await this.userService.changePassword(userContext, userContext.user._id, password);
139
+ const updateResult = {
140
+ success: true,
141
+ count: 1,
142
+ };
139
143
  apiUtils.apiResponse(res, 200, { data: updateResult });
140
144
  }
141
145
  async forgotPassword(req, res) {
@@ -1,9 +1,61 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
1
35
  import { FeatureModelSpec } from '@loomcore/common/models';
36
+ import { Authorize } from '../decorators/authorize.decorator.js';
2
37
  import { FeatureService } from '../services/feature.service.js';
3
38
  import { ApiController } from './api.controller.js';
4
- export class FeaturesController extends ApiController {
5
- constructor(app, database) {
6
- const featureService = new FeatureService(database);
7
- super('features', app, featureService, 'feature', FeatureModelSpec);
8
- }
9
- }
39
+ let FeaturesController = (() => {
40
+ let _classDecorators = [Authorize('admin')];
41
+ let _classDescriptor;
42
+ let _classExtraInitializers = [];
43
+ let _classThis;
44
+ let _classSuper = ApiController;
45
+ var FeaturesController = class extends _classSuper {
46
+ static { _classThis = this; }
47
+ static {
48
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
49
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
50
+ FeaturesController = _classThis = _classDescriptor.value;
51
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
52
+ __runInitializers(_classThis, _classExtraInitializers);
53
+ }
54
+ constructor(app, database) {
55
+ const featureService = new FeatureService(database);
56
+ super('features', app, featureService, 'feature', FeatureModelSpec);
57
+ }
58
+ };
59
+ return FeaturesController = _classThis;
60
+ })();
61
+ export { FeaturesController };
@@ -34,7 +34,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
34
34
  };
35
35
  import { BadRequestError } from '../errors/index.js';
36
36
  import { OrganizationService } from '../services/index.js';
37
- import { apiUtils, authorizeMethod } from '../utils/index.js';
37
+ import { apiUtils } from '../utils/index.js';
38
38
  import { ApiController } from './api.controller.js';
39
39
  import { Authorize } from '../decorators/authorize.decorator.js';
40
40
  let OrganizationsController = (() => {
@@ -60,9 +60,8 @@ let OrganizationsController = (() => {
60
60
  }
61
61
  mapRoutes(app) {
62
62
  super.mapRoutes(app);
63
- const authorize = (method) => authorizeMethod(this, method);
64
- app.get(`/api/${this.slug}/get-by-name/:name`, authorize('getByName'), this.getByName.bind(this));
65
- app.get(`/api/${this.slug}/get-by-code/:code`, authorize('getByCode'), this.getByCode.bind(this));
63
+ app.get(`/api/${this.slug}/get-by-name/:name`, this.authorize('getByName'), this.getByName.bind(this));
64
+ app.get(`/api/${this.slug}/get-by-code/:code`, this.authorize('getByCode'), this.getByCode.bind(this));
66
65
  }
67
66
  async getByName(req, res, next) {
68
67
  const { name } = req.params;
@@ -11,6 +11,7 @@ export declare abstract class QueryApiController<T extends IEntity> {
11
11
  protected publicSpec?: IModelSpec;
12
12
  protected idSchema: TSchema;
13
13
  protected constructor(slug: string, app: Application, service: IGenericQueryService<T>, resourceName?: string, modelSpec?: IModelSpec, publicSpec?: IModelSpec);
14
+ protected authorize(method: string): import("express").RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
14
15
  mapRoutes(app: Application): void;
15
16
  getAll(req: Request, res: Response, next: NextFunction): Promise<void>;
16
17
  get(req: Request, res: Response, next: NextFunction): Promise<void>;
@@ -20,12 +20,14 @@ export class QueryApiController {
20
20
  this.idSchema = getIdSchema();
21
21
  this.mapRoutes(app);
22
22
  }
23
+ authorize(method) {
24
+ return authorizeMethod(this, method);
25
+ }
23
26
  mapRoutes(app) {
24
- const authorize = (method) => authorizeMethod(this, method);
25
- app.get(`/api/${this.slug}`, authorize('get'), this.get.bind(this));
26
- app.get(`/api/${this.slug}/all`, authorize('getAll'), this.getAll.bind(this));
27
- app.get(`/api/${this.slug}/count`, authorize('getCount'), this.getCount.bind(this));
28
- app.get(`/api/${this.slug}/:id`, authorize('getById'), this.getById.bind(this));
27
+ app.get(`/api/${this.slug}`, this.authorize('get'), this.get.bind(this));
28
+ app.get(`/api/${this.slug}/all`, this.authorize('getAll'), this.getAll.bind(this));
29
+ app.get(`/api/${this.slug}/count`, this.authorize('getCount'), this.getCount.bind(this));
30
+ app.get(`/api/${this.slug}/:id`, this.authorize('getById'), this.getById.bind(this));
29
31
  }
30
32
  async getAll(req, res, next) {
31
33
  res.set('Content-Type', 'application/json');
@@ -1,9 +1,61 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
1
35
  import { RoleModelSpec } from '@loomcore/common/models';
36
+ import { Authorize } from '../decorators/authorize.decorator.js';
2
37
  import { RoleService } from '../services/role.service.js';
3
38
  import { ApiController } from './api.controller.js';
4
- export class RolesController extends ApiController {
5
- constructor(app, database) {
6
- const roleService = new RoleService(database);
7
- super('roles', app, roleService, 'role', RoleModelSpec);
8
- }
9
- }
39
+ let RolesController = (() => {
40
+ let _classDecorators = [Authorize('admin')];
41
+ let _classDescriptor;
42
+ let _classExtraInitializers = [];
43
+ let _classThis;
44
+ let _classSuper = ApiController;
45
+ var RolesController = class extends _classSuper {
46
+ static { _classThis = this; }
47
+ static {
48
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
49
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
50
+ RolesController = _classThis = _classDescriptor.value;
51
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
52
+ __runInitializers(_classThis, _classExtraInitializers);
53
+ }
54
+ constructor(app, database) {
55
+ const roleService = new RoleService(database);
56
+ super('roles', app, roleService, 'role', RoleModelSpec);
57
+ }
58
+ };
59
+ return RolesController = _classThis;
60
+ })();
61
+ export { RolesController };
@@ -1,9 +1,61 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
1
35
  import { UserRoleModelSpec } from '@loomcore/common/models';
36
+ import { Authorize } from '../decorators/authorize.decorator.js';
2
37
  import { UserRoleService } from '../services/user-role.service.js';
3
38
  import { ApiController } from './api.controller.js';
4
- export class UserRolesController extends ApiController {
5
- constructor(app, database) {
6
- const userRoleService = new UserRoleService(database);
7
- super('user-roles', app, userRoleService, 'user-role', UserRoleModelSpec);
8
- }
9
- }
39
+ let UserRolesController = (() => {
40
+ let _classDecorators = [Authorize('admin')];
41
+ let _classDescriptor;
42
+ let _classExtraInitializers = [];
43
+ let _classThis;
44
+ let _classSuper = ApiController;
45
+ var UserRolesController = class extends _classSuper {
46
+ static { _classThis = this; }
47
+ static {
48
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
49
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
50
+ UserRolesController = _classThis = _classDescriptor.value;
51
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
52
+ __runInitializers(_classThis, _classExtraInitializers);
53
+ }
54
+ constructor(app, database) {
55
+ const userRoleService = new UserRoleService(database);
56
+ super('user-roles', app, userRoleService, 'user-role', UserRoleModelSpec);
57
+ }
58
+ };
59
+ return UserRolesController = _classThis;
60
+ })();
61
+ export { UserRolesController };
@@ -1,5 +1,5 @@
1
1
  import { type IModelSpec, type IUser } from '@loomcore/common/models';
2
- import type { Application } from 'express';
2
+ import type { Application, Request, Response } from 'express';
3
3
  import type { IDatabase } from '../databases/models/index.js';
4
4
  import { UserService } from '../services/index.js';
5
5
  import { ApiController } from './api.controller.js';
@@ -11,4 +11,7 @@ export interface UsersControllerOptions {
11
11
  export declare class UsersController extends ApiController<IUser> {
12
12
  userService: UserService;
13
13
  constructor(app: Application, database: IDatabase, options?: UsersControllerOptions);
14
+ mapRoutes(app: Application): void;
15
+ getSelf(req: Request, res: Response): Promise<void>;
16
+ partialUpdateSelf(req: Request, res: Response): Promise<void>;
14
17
  }
@@ -1,14 +1,90 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
1
35
  import { PublicUserSpec, UserSpec, } from '@loomcore/common/models';
36
+ import { Authorize } from '../decorators/authorize.decorator.js';
2
37
  import { UserService } from '../services/index.js';
38
+ import { apiUtils } from '../utils/index.js';
3
39
  import { ApiController } from './api.controller.js';
4
- export class UsersController extends ApiController {
5
- userService;
6
- constructor(app, database, options = {
7
- userService: new UserService(database),
8
- userSpec: UserSpec,
9
- publicUserSpec: PublicUserSpec,
10
- }) {
11
- super('users', app, options.userService, 'user', options.userSpec, options.publicUserSpec);
12
- this.userService = options.userService;
13
- }
14
- }
40
+ let UsersController = (() => {
41
+ let _classDecorators = [Authorize('admin')];
42
+ let _classDescriptor;
43
+ let _classExtraInitializers = [];
44
+ let _classThis;
45
+ let _classSuper = ApiController;
46
+ let _instanceExtraInitializers = [];
47
+ let _getSelf_decorators;
48
+ let _partialUpdateSelf_decorators;
49
+ var UsersController = class extends _classSuper {
50
+ static { _classThis = this; }
51
+ static {
52
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
53
+ _getSelf_decorators = [Authorize()];
54
+ _partialUpdateSelf_decorators = [Authorize()];
55
+ __esDecorate(this, null, _getSelf_decorators, { kind: "method", name: "getSelf", static: false, private: false, access: { has: obj => "getSelf" in obj, get: obj => obj.getSelf }, metadata: _metadata }, null, _instanceExtraInitializers);
56
+ __esDecorate(this, null, _partialUpdateSelf_decorators, { kind: "method", name: "partialUpdateSelf", static: false, private: false, access: { has: obj => "partialUpdateSelf" in obj, get: obj => obj.partialUpdateSelf }, metadata: _metadata }, null, _instanceExtraInitializers);
57
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
58
+ UsersController = _classThis = _classDescriptor.value;
59
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
60
+ __runInitializers(_classThis, _classExtraInitializers);
61
+ }
62
+ userService = __runInitializers(this, _instanceExtraInitializers);
63
+ constructor(app, database, options = {
64
+ userService: new UserService(database),
65
+ userSpec: UserSpec,
66
+ publicUserSpec: PublicUserSpec,
67
+ }) {
68
+ super('users', app, options.userService, 'user', options.userSpec, options.publicUserSpec);
69
+ this.userService = options.userService;
70
+ }
71
+ mapRoutes(app) {
72
+ app.get(`/api/${this.slug}/me`, this.authorize('getSelf'), this.getSelf.bind(this));
73
+ app.patch(`/api/${this.slug}/me`, this.authorize('partialUpdateSelf'), this.partialUpdateSelf.bind(this));
74
+ super.mapRoutes(app);
75
+ }
76
+ async getSelf(req, res) {
77
+ res.set('Content-Type', 'application/json');
78
+ const user = await this.userService.getById(req.userContext, req.userContext.user._id);
79
+ apiUtils.apiResponse(res, 200, { data: user }, this.modelSpec, this.publicSpec);
80
+ }
81
+ async partialUpdateSelf(req, res) {
82
+ res.set('Content-Type', 'application/json');
83
+ this.validate(req.body, true);
84
+ const user = await this.userService.partialUpdateById(req.userContext, req.userContext.user._id, req.body);
85
+ apiUtils.apiResponse(res, 200, { data: user }, this.modelSpec, this.publicSpec);
86
+ }
87
+ };
88
+ return UsersController = _classThis;
89
+ })();
90
+ export { UsersController };
@@ -1,5 +1,4 @@
1
1
  import { AuthorizationModelSpec, getSystemUserContext, } from '@loomcore/common/models';
2
- import { assertUserHasFeature } from '../utils/index.js';
3
2
  import { FeatureService } from './feature.service.js';
4
3
  import { MultiTenantApiService } from './multi-tenant-api.service.js';
5
4
  import { UserRoleService } from './user-role.service.js';
@@ -12,7 +11,6 @@ export class AuthorizationService extends MultiTenantApiService {
12
11
  this.featuresService = new FeatureService(database);
13
12
  }
14
13
  async preProcessEntity(userContext, entity, isCreate, allowId = true) {
15
- assertUserHasFeature(userContext, ['admin', 'system', 'authorizations']);
16
14
  return super.preProcessEntity(userContext, entity, isCreate, allowId);
17
15
  }
18
16
  async getUserContextFeatures(user) {
@@ -1,7 +1,6 @@
1
- import { IFeature, IUserContext } from '@loomcore/common/models';
1
+ import { IFeature } from '@loomcore/common/models';
2
2
  import { IDatabase } from '../databases/index.js';
3
3
  import { MultiTenantApiService } from './multi-tenant-api.service.js';
4
4
  export declare class FeatureService extends MultiTenantApiService<IFeature> {
5
5
  constructor(database: IDatabase);
6
- preProcessEntity(userContext: IUserContext, entity: Partial<IFeature>, isCreate: boolean, allowId?: boolean): Promise<Partial<IFeature>>;
7
6
  }
@@ -1,12 +1,7 @@
1
1
  import { FeatureModelSpec } from '@loomcore/common/models';
2
2
  import { MultiTenantApiService } from './multi-tenant-api.service.js';
3
- import { assertUserHasFeature } from '../utils/index.js';
4
3
  export class FeatureService extends MultiTenantApiService {
5
4
  constructor(database) {
6
5
  super(database, 'features', 'feature', FeatureModelSpec);
7
6
  }
8
- async preProcessEntity(userContext, entity, isCreate, allowId = true) {
9
- assertUserHasFeature(userContext, ['admin', 'system', 'features']);
10
- return super.preProcessEntity(userContext, entity, isCreate, allowId);
11
- }
12
7
  }
@@ -1,7 +1,6 @@
1
- import { IRole, IUserContext } from '@loomcore/common/models';
1
+ import { IRole } from '@loomcore/common/models';
2
2
  import { IDatabase } from '../databases/index.js';
3
3
  import { MultiTenantApiService } from './multi-tenant-api.service.js';
4
4
  export declare class RoleService extends MultiTenantApiService<IRole> {
5
5
  constructor(database: IDatabase);
6
- preProcessEntity(userContext: IUserContext, entity: Partial<IRole>, isCreate: boolean, allowId?: boolean): Promise<Partial<IRole>>;
7
6
  }
@@ -1,12 +1,7 @@
1
1
  import { RoleModelSpec } from '@loomcore/common/models';
2
2
  import { MultiTenantApiService } from './multi-tenant-api.service.js';
3
- import { assertUserHasFeature } from '../utils/index.js';
4
3
  export class RoleService extends MultiTenantApiService {
5
4
  constructor(database) {
6
5
  super(database, 'roles', 'role', RoleModelSpec);
7
6
  }
8
- async preProcessEntity(userContext, entity, isCreate, allowId = true) {
9
- assertUserHasFeature(userContext, ['admin', 'system', 'roles']);
10
- return super.preProcessEntity(userContext, entity, isCreate, allowId);
11
- }
12
7
  }
@@ -1,7 +1,6 @@
1
- import { IUserContext, IUserRole } from '@loomcore/common/models';
1
+ import { IUserRole } from '@loomcore/common/models';
2
2
  import { IDatabase } from '../databases/index.js';
3
3
  import { MultiTenantApiService } from './multi-tenant-api.service.js';
4
4
  export declare class UserRoleService extends MultiTenantApiService<IUserRole> {
5
5
  constructor(database: IDatabase);
6
- preProcessEntity(userContext: IUserContext, entity: Partial<IUserRole>, isCreate: boolean, allowId?: boolean): Promise<Partial<IUserRole>>;
7
6
  }
@@ -1,12 +1,7 @@
1
1
  import { UserRoleModelSpec } from '@loomcore/common/models';
2
2
  import { MultiTenantApiService } from './multi-tenant-api.service.js';
3
- import { assertUserHasFeature } from '../utils/index.js';
4
3
  export class UserRoleService extends MultiTenantApiService {
5
4
  constructor(database) {
6
5
  super(database, 'userRoles', 'userRole', UserRoleModelSpec);
7
6
  }
8
- async preProcessEntity(userContext, entity, isCreate, allowId = true) {
9
- assertUserHasFeature(userContext, ['admin', 'system', 'user-roles']);
10
- return super.preProcessEntity(userContext, entity, isCreate, allowId);
11
- }
12
7
  }
@@ -1,17 +1,14 @@
1
- import { type IModelSpec, type IPagedResult, type IQueryOptions, type IUser, type IUserContext } from '@loomcore/common/models';
1
+ import { type IModelSpec, type IQueryOptions, type IUser, type IUserContext } from '@loomcore/common/models';
2
2
  import type { AppIdType } from '@loomcore/common/types';
3
3
  import type { IDatabase } from '../databases/models/index.js';
4
4
  import { MultiTenantApiService } from './multi-tenant-api.service.js';
5
5
  export declare class UserService extends MultiTenantApiService<IUser> {
6
6
  constructor(database: IDatabase, modelSpec?: IModelSpec);
7
- getById(userContext: IUserContext, id: AppIdType): Promise<IUser>;
8
- get(userContext: IUserContext, queryOptions?: IQueryOptions): Promise<IPagedResult<IUser>>;
9
- getAll(userContext: IUserContext): Promise<IUser[]>;
10
- getCount(userContext: IUserContext): Promise<number>;
11
7
  fullUpdateById(_userContext: IUserContext, _id: AppIdType, _entity: IUser): Promise<IUser>;
12
8
  update(userContext: IUserContext, queryObject: IQueryOptions, entity: Partial<IUser>): Promise<IUser[]>;
13
9
  batchUpdate(userContext: IUserContext, entities: Partial<IUser>[]): Promise<IUser[]>;
14
- partialUpdateById(userContext: IUserContext, id: AppIdType, entity: Partial<IUser>, allowPasswordUpdate?: boolean): Promise<IUser>;
15
- private assertPasswordUpdateAllowed;
10
+ partialUpdateById(userContext: IUserContext, id: AppIdType, entity: Partial<IUser>): Promise<IUser>;
11
+ changePassword(userContext: IUserContext, id: AppIdType, password: string): Promise<IUser>;
16
12
  preProcessEntity(userContext: IUserContext, entity: Partial<IUser>, isCreate: boolean, allowId?: boolean): Promise<Partial<IUser>>;
13
+ private assertPasswordNotPresent;
17
14
  }
@@ -1,6 +1,5 @@
1
1
  import { UserSpec, } from '@loomcore/common/models';
2
2
  import { BadRequestError, ServerError } from '../errors/index.js';
3
- import { assertAdmin, assertUserOrAdmin, isAdmin, } from '../utils/auth/index.js';
4
3
  import { passwordUtils } from '../utils/password.utils.js';
5
4
  import { MultiTenantApiService } from './multi-tenant-api.service.js';
6
5
  import moment from 'moment';
@@ -8,58 +7,31 @@ export class UserService extends MultiTenantApiService {
8
7
  constructor(database, modelSpec = UserSpec) {
9
8
  super(database, 'users', 'user', modelSpec);
10
9
  }
11
- async getById(userContext, id) {
12
- assertUserOrAdmin(userContext, id);
13
- return super.getById(userContext, id);
14
- }
15
- async get(userContext, queryOptions) {
16
- assertAdmin(userContext);
17
- return super.get(userContext, queryOptions);
18
- }
19
- async getAll(userContext) {
20
- assertAdmin(userContext);
21
- return super.getAll(userContext);
22
- }
23
- async getCount(userContext) {
24
- assertAdmin(userContext);
25
- return super.getCount(userContext);
26
- }
27
10
  async fullUpdateById(_userContext, _id, _entity) {
28
11
  throw new ServerError('User full update is not allowed.');
29
12
  }
30
13
  async update(userContext, queryObject, entity) {
31
- assertAdmin(userContext);
32
- this.assertPasswordUpdateAllowed(userContext, null, entity, false);
14
+ this.assertPasswordNotPresent(entity);
33
15
  return super.update(userContext, queryObject, entity);
34
16
  }
35
17
  async batchUpdate(userContext, entities) {
36
- assertAdmin(userContext);
37
18
  for (const entity of entities) {
38
- this.assertPasswordUpdateAllowed(userContext, null, entity, false);
19
+ this.assertPasswordNotPresent(entity);
39
20
  }
40
21
  return super.batchUpdate(userContext, entities);
41
22
  }
42
- async partialUpdateById(userContext, id, entity, allowPasswordUpdate = false) {
43
- assertUserOrAdmin(userContext, id);
44
- this.assertPasswordUpdateAllowed(userContext, id, entity, allowPasswordUpdate);
23
+ async partialUpdateById(userContext, id, entity) {
24
+ this.assertPasswordNotPresent(entity);
45
25
  return super.partialUpdateById(userContext, id, entity);
46
26
  }
47
- assertPasswordUpdateAllowed(userContext, id, entity, allowPasswordUpdate) {
48
- if (!('password' in entity)) {
49
- return;
50
- }
51
- if (!entity.password) {
27
+ async changePassword(userContext, id, password) {
28
+ if (!password) {
52
29
  throw new BadRequestError('Password cannot be empty.');
53
30
  }
54
- if (!allowPasswordUpdate) {
55
- throw new ServerError('Use auth change password endpoint to update password.');
56
- }
57
- if (isAdmin(userContext)) {
58
- return;
59
- }
60
- if (userContext.user._id !== id) {
61
- throw new ServerError('You can only update your own password.');
62
- }
31
+ const updates = {
32
+ password: password,
33
+ };
34
+ return super.partialUpdateById(userContext, id, updates);
63
35
  }
64
36
  async preProcessEntity(userContext, entity, isCreate, allowId = false) {
65
37
  const preparedEntity = await super.preProcessEntity(userContext, entity, isCreate, allowId);
@@ -74,4 +46,9 @@ export class UserService extends MultiTenantApiService {
74
46
  }
75
47
  return preparedEntity;
76
48
  }
49
+ assertPasswordNotPresent(entity) {
50
+ if ('password' in entity) {
51
+ throw new BadRequestError('Cannot update user with password present on the entity.');
52
+ }
53
+ }
77
54
  }
@@ -1,2 +1,2 @@
1
1
  import { RequestHandler } from 'express';
2
- export declare function authorizeMethod<T extends object>(instance: T, methodName: Extract<keyof T, string>): RequestHandler;
2
+ export declare function authorizeMethod(instance: object, methodName: string): RequestHandler;
@@ -1,11 +1,5 @@
1
- export * from './assert-admin.util.js';
2
- export * from './assert-admin-or-feature.util.js';
3
- export * from './assert-owner-or-admin.util.js';
4
- export * from './assert-user-or-admin.util.js';
5
1
  export * from './attempt-login.util.js';
6
2
  export * from './auth-user-specs.util.js';
7
- export * from './assert-user-has-feature.util.js';
8
- export * from './change-password.util.js';
9
3
  export * from './create-new-refresh-token.util.js';
10
4
  export * from './create-new-tokens.util.js';
11
5
  export * from './generate-device-id.util.js';
@@ -1,11 +1,5 @@
1
- export * from './assert-admin.util.js';
2
- export * from './assert-admin-or-feature.util.js';
3
- export * from './assert-owner-or-admin.util.js';
4
- export * from './assert-user-or-admin.util.js';
5
1
  export * from './attempt-login.util.js';
6
2
  export * from './auth-user-specs.util.js';
7
- export * from './assert-user-has-feature.util.js';
8
- export * from './change-password.util.js';
9
3
  export * from './create-new-refresh-token.util.js';
10
4
  export * from './create-new-tokens.util.js';
11
5
  export * from './generate-device-id.util.js';
@@ -3,7 +3,6 @@ import { entityUtils } from '@loomcore/common/utils';
3
3
  import { BadRequestError, ServerError } from '../../errors/index.js';
4
4
  import { PasswordResetTokenService } from '../../services/password-reset-token.service.js';
5
5
  import { UserService } from '../../services/user.service.js';
6
- import { changePassword } from './change-password.util.js';
7
6
  export async function resetPassword(database, email, passwordResetToken, password, organization, userService = new UserService(database), userSpec = UserSpec) {
8
7
  const validationErrors = entityUtils.validate(userSpec, { password: password }, true, passwordValidator);
9
8
  entityUtils.handleValidationResult(validationErrors, 'AuthService.resetPassword');
@@ -26,9 +25,12 @@ export async function resetPassword(database, email, passwordResetToken, passwor
26
25
  if (!user) {
27
26
  throw new ServerError(`Unable to retrieve user for email: ${lowerCaseEmail}`);
28
27
  }
29
- const result = await changePassword(database, systemUserContext, user._id, password, userService);
28
+ const result = await userService.changePassword(systemUserContext, user._id, password);
30
29
  console.log(`password changed using forgot-password for email: ${lowerCaseEmail}`);
31
30
  await passwordResetTokenService.deleteById(systemUserContext, retrievedPasswordResetToken._id);
32
31
  console.log(`passwordResetToken deleted for email: ${lowerCaseEmail}`);
33
- return result;
32
+ return {
33
+ success: true,
34
+ count: 1,
35
+ };
34
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loomcore/api",
3
- "version": "0.2.51",
3
+ "version": "0.2.52",
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": {
@@ -1,2 +0,0 @@
1
- import type { IUserContext } from '@loomcore/common/models';
2
- export declare function assertAdminOrFeature(userContext: IUserContext, features: string[], requireAll?: boolean): void;
@@ -1,8 +0,0 @@
1
- import { isAdmin } from './is-admin.util.js';
2
- import { assertUserHasFeature } from './assert-user-has-feature.util.js';
3
- export function assertAdminOrFeature(userContext, features, requireAll = false) {
4
- if (isAdmin(userContext)) {
5
- return;
6
- }
7
- assertUserHasFeature(userContext, features, requireAll);
8
- }
@@ -1,2 +0,0 @@
1
- import type { IUserContext } from '@loomcore/common/models';
2
- export declare function assertAdmin(userContext: IUserContext): void;
@@ -1,7 +0,0 @@
1
- import { UnauthorizedError } from '../../errors/index.js';
2
- import { isAdmin } from './is-admin.util.js';
3
- export function assertAdmin(userContext) {
4
- if (!isAdmin(userContext)) {
5
- throw new UnauthorizedError();
6
- }
7
- }
@@ -1,2 +0,0 @@
1
- import type { IAuditable, IUserContext } from '@loomcore/common/models';
2
- export declare function assertOwnerOrAdmin(userContext: IUserContext, auditable: IAuditable): void;
@@ -1,10 +0,0 @@
1
- import { UnauthorizedError } from '../../errors/index.js';
2
- import { isAdmin } from './is-admin.util.js';
3
- export function assertOwnerOrAdmin(userContext, auditable) {
4
- if (isAdmin(userContext)) {
5
- return;
6
- }
7
- if (userContext.user._id !== auditable._createdBy) {
8
- throw new UnauthorizedError();
9
- }
10
- }
@@ -1,2 +0,0 @@
1
- import { IUserContext } from '@loomcore/common/models';
2
- export declare function assertUserHasFeature(userContext: IUserContext, features: string[], requireAll?: boolean): void;
@@ -1,18 +0,0 @@
1
- import { UnauthorizedError } from '../../errors/index.js';
2
- export function assertUserHasFeature(userContext, features, requireAll = false) {
3
- if (features.length === 0) {
4
- return;
5
- }
6
- const missingFeatures = features.filter(feature => !userContext.features.includes(feature));
7
- if (requireAll) {
8
- if (missingFeatures.length > 0) {
9
- throw new UnauthorizedError(missingFeatures);
10
- }
11
- }
12
- else {
13
- if (missingFeatures.length === features.length) {
14
- throw new UnauthorizedError(missingFeatures);
15
- }
16
- }
17
- return;
18
- }
@@ -1,3 +0,0 @@
1
- import type { IUserContext } from '@loomcore/common/models';
2
- import type { AppIdType } from '@loomcore/common/types';
3
- export declare function assertUserOrAdmin(userContext: IUserContext, userId: AppIdType): void;
@@ -1,10 +0,0 @@
1
- import { UnauthorizedError } from '../../errors/index.js';
2
- import { isAdmin } from './is-admin.util.js';
3
- export function assertUserOrAdmin(userContext, userId) {
4
- if (isAdmin(userContext)) {
5
- return;
6
- }
7
- if (userContext.user._id !== userId) {
8
- throw new UnauthorizedError();
9
- }
10
- }
@@ -1,6 +0,0 @@
1
- import { type IUserContext } from '@loomcore/common/models';
2
- import type { IDatabase } from '../../databases/models/index.js';
3
- import type { UpdateResult } from '../../databases/models/update-result.js';
4
- import { UserService } from '../../services/user.service.js';
5
- import { AppIdType } from '@loomcore/common/types';
6
- export declare function changePassword(database: IDatabase, userContext: IUserContext, userId: AppIdType, password: string, userService?: UserService): Promise<UpdateResult>;
@@ -1,11 +0,0 @@
1
- import { UserService } from '../../services/user.service.js';
2
- export async function changePassword(database, userContext, userId, password, userService = new UserService(database)) {
3
- const updates = {
4
- password: password,
5
- };
6
- await userService.partialUpdateById(userContext, userId, updates, true);
7
- return {
8
- success: true,
9
- count: 1,
10
- };
11
- }