@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.
- package/dist/__tests__/common-test.utils.d.ts +2 -0
- package/dist/__tests__/common-test.utils.js +7 -1
- package/dist/__tests__/mongo-db.test-database.js +46 -12
- package/dist/__tests__/test-express-app.js +10 -6
- package/dist/controllers/api.controller.d.ts +1 -0
- package/dist/controllers/api.controller.js +12 -10
- package/dist/controllers/auth.controller.js +6 -2
- package/dist/controllers/features.controller.js +58 -6
- package/dist/controllers/organizations.controller.js +3 -4
- package/dist/controllers/query-api.controller.d.ts +1 -0
- package/dist/controllers/query-api.controller.js +7 -5
- package/dist/controllers/roles.controller.js +58 -6
- package/dist/controllers/user-roles.controller.js +58 -6
- package/dist/controllers/users.controller.d.ts +4 -1
- package/dist/controllers/users.controller.js +87 -11
- package/dist/services/authorization.service.js +0 -2
- package/dist/services/feature.service.d.ts +1 -2
- package/dist/services/feature.service.js +0 -5
- package/dist/services/role.service.d.ts +1 -2
- package/dist/services/role.service.js +0 -5
- package/dist/services/user-role.service.d.ts +1 -2
- package/dist/services/user-role.service.js +0 -5
- package/dist/services/user.service.d.ts +4 -7
- package/dist/services/user.service.js +15 -38
- package/dist/utils/auth/authorize-method.util.d.ts +1 -1
- package/dist/utils/auth/index.d.ts +0 -6
- package/dist/utils/auth/index.js +0 -6
- package/dist/utils/auth/reset-password.util.js +5 -3
- package/package.json +1 -1
- package/dist/utils/auth/assert-admin-or-feature.util.d.ts +0 -2
- package/dist/utils/auth/assert-admin-or-feature.util.js +0 -8
- package/dist/utils/auth/assert-admin.util.d.ts +0 -2
- package/dist/utils/auth/assert-admin.util.js +0 -7
- package/dist/utils/auth/assert-owner-or-admin.util.d.ts +0 -2
- package/dist/utils/auth/assert-owner-or-admin.util.js +0 -10
- package/dist/utils/auth/assert-user-has-feature.util.d.ts +0 -2
- package/dist/utils/auth/assert-user-has-feature.util.js +0 -18
- package/dist/utils/auth/assert-user-or-admin.util.d.ts +0 -3
- package/dist/utils/auth/assert-user-or-admin.util.js +0 -10
- package/dist/utils/auth/change-password.util.d.ts +0 -6
- 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
|
-
|
|
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
|
|
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
|
-
|
|
61
|
-
|
|
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
|
-
|
|
68
|
-
|
|
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
|
-
|
|
31
|
-
app.get(`/api/${this.slug}`, authorize('
|
|
32
|
-
app.get(`/api/${this.slug}/
|
|
33
|
-
app.get(`/api/${this.slug}
|
|
34
|
-
app.
|
|
35
|
-
app.
|
|
36
|
-
app.
|
|
37
|
-
app.
|
|
38
|
-
app.
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
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
|
-
|
|
64
|
-
app.get(`/api/${this.slug}/get-by-
|
|
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
|
-
|
|
25
|
-
app.get(`/api/${this.slug}`, authorize('
|
|
26
|
-
app.get(`/api/${this.slug}/
|
|
27
|
-
app.get(`/api/${this.slug}
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
15
|
-
|
|
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
|
-
|
|
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.
|
|
19
|
+
this.assertPasswordNotPresent(entity);
|
|
39
20
|
}
|
|
40
21
|
return super.batchUpdate(userContext, entities);
|
|
41
22
|
}
|
|
42
|
-
async partialUpdateById(userContext, id, entity
|
|
43
|
-
|
|
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
|
-
|
|
48
|
-
if (!
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
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
|
|
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';
|
package/dist/utils/auth/index.js
CHANGED
|
@@ -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(
|
|
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
|
|
32
|
+
return {
|
|
33
|
+
success: true,
|
|
34
|
+
count: 1,
|
|
35
|
+
};
|
|
34
36
|
}
|
package/package.json
CHANGED
|
@@ -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,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,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,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
|
-
}
|