@loomcore/api 0.2.35 → 0.2.37
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/databases/migrations/migration-runner.js +4 -2
- package/dist/databases/mongo-db/migrations/mongo-initial-schema.js +26 -26
- package/dist/databases/postgres/postgres.database.js +15 -15
- package/dist/databases/postgres/utils/build-join-clauses.js +3 -1
- package/dist/databases/postgres/utils/build-select-clause.js +8 -4
- package/dist/databases/postgres/utils/convert-keys.util.d.ts +1 -0
- package/dist/databases/postgres/utils/convert-keys.util.js +3 -0
- package/dist/databases/postgres/utils/does-table-exist.util.js +3 -1
- package/dist/databases/postgres/utils/index.d.ts +1 -0
- package/dist/databases/postgres/utils/index.js +1 -0
- package/dist/services/organization-domain.service.js +1 -1
- package/dist/services/password-reset-token.service.js +1 -1
- package/dist/services/refresh-token.service.js +1 -1
- package/dist/services/user-roles.service.js +1 -1
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import { Pool } from 'pg';
|
|
|
3
3
|
import { MongoClient } from 'mongodb';
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import path from 'path';
|
|
6
|
+
import { pathToFileURL } from 'node:url';
|
|
6
7
|
import { buildMongoUrl } from '../mongo-db/utils/build-mongo-url.util.js';
|
|
7
8
|
import { buildPostgresUrl } from '../postgres/utils/build-postgres-url.util.js';
|
|
8
9
|
import { getPostgresInitialSchema } from '../postgres/migrations/postgres-initial-schema.js';
|
|
@@ -144,14 +145,15 @@ export class MigrationRunner {
|
|
|
144
145
|
};
|
|
145
146
|
}
|
|
146
147
|
else {
|
|
148
|
+
const importUrl = pathToFileURL(fullPath).href;
|
|
147
149
|
return {
|
|
148
150
|
name: f,
|
|
149
151
|
up: async () => {
|
|
150
|
-
const mod = await import(
|
|
152
|
+
const mod = await import(importUrl);
|
|
151
153
|
await mod.up({ context });
|
|
152
154
|
},
|
|
153
155
|
down: async () => {
|
|
154
|
-
const mod = await import(
|
|
156
|
+
const mod = await import(importUrl);
|
|
155
157
|
await mod.down({ context });
|
|
156
158
|
}
|
|
157
159
|
};
|
|
@@ -29,16 +29,16 @@ export const getMongoInitialSchema = (dbConfig) => {
|
|
|
29
29
|
migrations.push({
|
|
30
30
|
name: "00000000000001_schema-organizations-domains",
|
|
31
31
|
up: async ({ context: db }) => {
|
|
32
|
-
await db.createCollection("
|
|
32
|
+
await db.createCollection("organizationDomains");
|
|
33
33
|
await db
|
|
34
|
-
.collection("
|
|
34
|
+
.collection("organizationDomains")
|
|
35
35
|
.createIndex({ domain: 1 }, { unique: true });
|
|
36
36
|
await db
|
|
37
|
-
.collection("
|
|
37
|
+
.collection("organizationDomains")
|
|
38
38
|
.createIndex({ organizationId: 1 });
|
|
39
39
|
},
|
|
40
40
|
down: async ({ context: db }) => {
|
|
41
|
-
await db.collection("
|
|
41
|
+
await db.collection("organizationDomains").drop();
|
|
42
42
|
},
|
|
43
43
|
});
|
|
44
44
|
}
|
|
@@ -70,41 +70,41 @@ export const getMongoInitialSchema = (dbConfig) => {
|
|
|
70
70
|
migrations.push({
|
|
71
71
|
name: "00000000000003_schema-refresh-tokens",
|
|
72
72
|
up: async ({ context: db }) => {
|
|
73
|
-
await db.createCollection("
|
|
73
|
+
await db.createCollection("refreshTokens");
|
|
74
74
|
await db
|
|
75
|
-
.collection("
|
|
75
|
+
.collection("refreshTokens")
|
|
76
76
|
.createIndex({ token: 1 }, { unique: true });
|
|
77
|
-
await db.collection("
|
|
78
|
-
await db.collection("
|
|
77
|
+
await db.collection("refreshTokens").createIndex({ userId: 1 });
|
|
78
|
+
await db.collection("refreshTokens").createIndex({ deviceId: 1 });
|
|
79
79
|
if (isMultiTenant) {
|
|
80
|
-
await db.collection("
|
|
80
|
+
await db.collection("refreshTokens").createIndex({ _orgId: 1 });
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
down: async ({ context: db }) => {
|
|
84
|
-
await db.collection("
|
|
84
|
+
await db.collection("refreshTokens").drop();
|
|
85
85
|
},
|
|
86
86
|
});
|
|
87
87
|
if (isAuthEnabled)
|
|
88
88
|
migrations.push({
|
|
89
89
|
name: "00000000000004_schema-password-reset-tokens",
|
|
90
90
|
up: async ({ context: db }) => {
|
|
91
|
-
await db.createCollection("
|
|
91
|
+
await db.createCollection("passwordResetTokens");
|
|
92
92
|
if (isMultiTenant) {
|
|
93
93
|
await db
|
|
94
|
-
.collection("
|
|
94
|
+
.collection("passwordResetTokens")
|
|
95
95
|
.createIndex({ _orgId: 1, email: 1 }, { unique: true });
|
|
96
96
|
await db
|
|
97
|
-
.collection("
|
|
97
|
+
.collection("passwordResetTokens")
|
|
98
98
|
.createIndex({ _orgId: 1 });
|
|
99
99
|
}
|
|
100
100
|
else {
|
|
101
101
|
await db
|
|
102
|
-
.collection("
|
|
102
|
+
.collection("passwordResetTokens")
|
|
103
103
|
.createIndex({ email: 1 }, { unique: true });
|
|
104
104
|
}
|
|
105
105
|
},
|
|
106
106
|
down: async ({ context: db }) => {
|
|
107
|
-
await db.collection("
|
|
107
|
+
await db.collection("passwordResetTokens").drop();
|
|
108
108
|
},
|
|
109
109
|
});
|
|
110
110
|
if (isAuthEnabled)
|
|
@@ -132,23 +132,23 @@ export const getMongoInitialSchema = (dbConfig) => {
|
|
|
132
132
|
migrations.push({
|
|
133
133
|
name: "00000000000006_schema-user-roles",
|
|
134
134
|
up: async ({ context: db }) => {
|
|
135
|
-
await db.createCollection("
|
|
135
|
+
await db.createCollection("userRoles");
|
|
136
136
|
if (isMultiTenant) {
|
|
137
137
|
await db
|
|
138
|
-
.collection("
|
|
138
|
+
.collection("userRoles")
|
|
139
139
|
.createIndex({ _orgId: 1, userId: 1, roleId: 1 }, { unique: true });
|
|
140
|
-
await db.collection("
|
|
140
|
+
await db.collection("userRoles").createIndex({ _orgId: 1 });
|
|
141
141
|
}
|
|
142
142
|
else {
|
|
143
143
|
await db
|
|
144
|
-
.collection("
|
|
144
|
+
.collection("userRoles")
|
|
145
145
|
.createIndex({ userId: 1, roleId: 1 }, { unique: true });
|
|
146
146
|
}
|
|
147
|
-
await db.collection("
|
|
148
|
-
await db.collection("
|
|
147
|
+
await db.collection("userRoles").createIndex({ userId: 1 });
|
|
148
|
+
await db.collection("userRoles").createIndex({ roleId: 1 });
|
|
149
149
|
},
|
|
150
150
|
down: async ({ context: db }) => {
|
|
151
|
-
await db.collection("
|
|
151
|
+
await db.collection("userRoles").drop();
|
|
152
152
|
},
|
|
153
153
|
});
|
|
154
154
|
if (isAuthEnabled)
|
|
@@ -222,7 +222,7 @@ export const getMongoInitialSchema = (dbConfig) => {
|
|
|
222
222
|
};
|
|
223
223
|
const metaOrgDomains = dbConfig.multiTenant.metaOrgDomains ?? [];
|
|
224
224
|
if (metaOrgDomains.length > 0) {
|
|
225
|
-
await db.collection("
|
|
225
|
+
await db.collection("organizationDomains").insertMany(metaOrgDomains.map((domain) => ({
|
|
226
226
|
organizationId: metaOrg._id,
|
|
227
227
|
domain,
|
|
228
228
|
_created: new Date(),
|
|
@@ -234,7 +234,7 @@ export const getMongoInitialSchema = (dbConfig) => {
|
|
|
234
234
|
initializeSystemUserContext(dbConfig.email?.systemEmailAddress || "system@example.com", metaOrg);
|
|
235
235
|
},
|
|
236
236
|
down: async ({ context: db }) => {
|
|
237
|
-
await db.collection("
|
|
237
|
+
await db.collection("organizationDomains").deleteMany({});
|
|
238
238
|
await db.collection("organizations").deleteMany({ isMetaOrg: true });
|
|
239
239
|
},
|
|
240
240
|
});
|
|
@@ -299,7 +299,7 @@ export const getMongoInitialSchema = (dbConfig) => {
|
|
|
299
299
|
...orgDoc,
|
|
300
300
|
name: "admin",
|
|
301
301
|
});
|
|
302
|
-
await db.collection("
|
|
302
|
+
await db.collection("userRoles").insertOne({
|
|
303
303
|
...orgDoc,
|
|
304
304
|
userId: adminUser._id,
|
|
305
305
|
roleId: roleResult.insertedId,
|
|
@@ -355,7 +355,7 @@ export const getMongoInitialSchema = (dbConfig) => {
|
|
|
355
355
|
.collection("features")
|
|
356
356
|
.deleteMany({ ...orgFilter, name: "admin" });
|
|
357
357
|
if (adminRole) {
|
|
358
|
-
await db.collection("
|
|
358
|
+
await db.collection("userRoles").deleteMany({
|
|
359
359
|
...orgFilter,
|
|
360
360
|
roleId: adminRole._id,
|
|
361
361
|
});
|
|
@@ -12,7 +12,7 @@ import { get as getQuery } from "./queries/postgres-get.query.js";
|
|
|
12
12
|
import { getAll as getAllQuery } from "./queries/postgres-get-all.query.js";
|
|
13
13
|
import { getById as getByIdQuery } from "./queries/postgres-get-by-id.query.js";
|
|
14
14
|
import { getCount as getCountQuery } from "./queries/postgres-get-count.query.js";
|
|
15
|
-
import { convertKeysToCamelCase, convertKeysToSnakeCase, } from "./utils/convert-keys.util.js";
|
|
15
|
+
import { convertKeysToCamelCase, convertKeysToSnakeCase, toPostgresStoreName, } from "./utils/convert-keys.util.js";
|
|
16
16
|
import { convertNullToUndefined } from "./utils/convert-null-to-undefined.util.js";
|
|
17
17
|
export class PostgresDatabase {
|
|
18
18
|
connection;
|
|
@@ -36,45 +36,45 @@ export class PostgresDatabase {
|
|
|
36
36
|
return convertKeysToCamelCase(withNullsConverted);
|
|
37
37
|
}
|
|
38
38
|
async getAll(operations, pluralResourceName) {
|
|
39
|
-
return getAllQuery(this.connection, operations, pluralResourceName);
|
|
39
|
+
return getAllQuery(this.connection, operations, toPostgresStoreName(pluralResourceName));
|
|
40
40
|
}
|
|
41
41
|
async get(operations, queryOptions, modelSpec, pluralResourceName) {
|
|
42
|
-
return getQuery(this.connection, operations, queryOptions, pluralResourceName);
|
|
42
|
+
return getQuery(this.connection, operations, queryOptions, toPostgresStoreName(pluralResourceName));
|
|
43
43
|
}
|
|
44
44
|
async getById(operations, queryObject, id, pluralResourceName) {
|
|
45
|
-
return getByIdQuery(this.connection, operations, queryObject, id, pluralResourceName);
|
|
45
|
+
return getByIdQuery(this.connection, operations, queryObject, id, toPostgresStoreName(pluralResourceName));
|
|
46
46
|
}
|
|
47
47
|
async getCount(pluralResourceName) {
|
|
48
|
-
return getCountQuery(this.connection, pluralResourceName);
|
|
48
|
+
return getCountQuery(this.connection, toPostgresStoreName(pluralResourceName));
|
|
49
49
|
}
|
|
50
50
|
async create(entity, pluralResourceName) {
|
|
51
|
-
return createCommand(this.connection, pluralResourceName, entity);
|
|
51
|
+
return createCommand(this.connection, toPostgresStoreName(pluralResourceName), entity);
|
|
52
52
|
}
|
|
53
53
|
async createMany(entities, pluralResourceName) {
|
|
54
|
-
return createManyCommand(this.connection, pluralResourceName, entities);
|
|
54
|
+
return createManyCommand(this.connection, toPostgresStoreName(pluralResourceName), entities);
|
|
55
55
|
}
|
|
56
56
|
async batchUpdate(entities, operations, queryObject, pluralResourceName) {
|
|
57
|
-
return batchUpdateCommand(this.connection, entities, operations, queryObject, pluralResourceName);
|
|
57
|
+
return batchUpdateCommand(this.connection, entities, operations, queryObject, toPostgresStoreName(pluralResourceName));
|
|
58
58
|
}
|
|
59
59
|
async fullUpdateById(operations, id, entity, pluralResourceName) {
|
|
60
|
-
return fullUpdateByIdCommand(this.connection, operations, id, entity, pluralResourceName);
|
|
60
|
+
return fullUpdateByIdCommand(this.connection, operations, id, entity, toPostgresStoreName(pluralResourceName));
|
|
61
61
|
}
|
|
62
62
|
async partialUpdateById(operations, id, entity, pluralResourceName) {
|
|
63
|
-
return partialUpdateByIdCommand(this.connection, operations, id, entity, pluralResourceName);
|
|
63
|
+
return partialUpdateByIdCommand(this.connection, operations, id, entity, toPostgresStoreName(pluralResourceName));
|
|
64
64
|
}
|
|
65
65
|
async update(queryObject, entity, operations, pluralResourceName) {
|
|
66
|
-
return updateCommand(this.connection, queryObject, entity, operations, pluralResourceName);
|
|
66
|
+
return updateCommand(this.connection, queryObject, entity, operations, toPostgresStoreName(pluralResourceName));
|
|
67
67
|
}
|
|
68
68
|
async deleteById(id, pluralResourceName) {
|
|
69
|
-
return deleteByIdCommand(this.connection, id, pluralResourceName);
|
|
69
|
+
return deleteByIdCommand(this.connection, id, toPostgresStoreName(pluralResourceName));
|
|
70
70
|
}
|
|
71
71
|
async deleteMany(queryObject, pluralResourceName) {
|
|
72
|
-
return deleteManyCommand(this.connection, queryObject, pluralResourceName);
|
|
72
|
+
return deleteManyCommand(this.connection, queryObject, toPostgresStoreName(pluralResourceName));
|
|
73
73
|
}
|
|
74
74
|
async find(queryObject, pluralResourceName) {
|
|
75
|
-
return findQuery(this.connection, queryObject, pluralResourceName);
|
|
75
|
+
return findQuery(this.connection, queryObject, toPostgresStoreName(pluralResourceName));
|
|
76
76
|
}
|
|
77
77
|
async findOne(queryObject, pluralResourceName) {
|
|
78
|
-
return findOneQuery(this.connection, queryObject, pluralResourceName);
|
|
78
|
+
return findOneQuery(this.connection, queryObject, toPostgresStoreName(pluralResourceName));
|
|
79
79
|
}
|
|
80
80
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LeftJoin } from "../../operations/left-join.operation.js";
|
|
2
2
|
import { InnerJoin } from "../../operations/inner-join.operation.js";
|
|
3
3
|
import { LeftJoinMany } from "../../operations/left-join-many.operation.js";
|
|
4
|
+
import { toPostgresStoreName } from "./convert-keys.util.js";
|
|
4
5
|
function getParentAlias(localField) {
|
|
5
6
|
if (!localField.includes('.'))
|
|
6
7
|
return null;
|
|
@@ -45,7 +46,8 @@ export function buildJoinClauses(operations, mainTableName, options) {
|
|
|
45
46
|
else {
|
|
46
47
|
leftSide = mainTableName ? `"${mainTableName}"."${operation.localField}"` : `"${operation.localField}"`;
|
|
47
48
|
}
|
|
48
|
-
|
|
49
|
+
const fromTable = toPostgresStoreName(operation.from);
|
|
50
|
+
joinClauses.push(`${joinType} "${fromTable}" AS "${operation.as}" ON ${leftSide} = "${operation.as}"."${operation.foreignField}"`);
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
return joinClauses.join(' ');
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { LeftJoin } from '../../operations/left-join.operation.js';
|
|
2
2
|
import { InnerJoin } from '../../operations/inner-join.operation.js';
|
|
3
3
|
import { LeftJoinMany } from '../../operations/left-join-many.operation.js';
|
|
4
|
+
import { toPostgresStoreName } from './convert-keys.util.js';
|
|
4
5
|
const PK = '_id';
|
|
5
6
|
export async function getTableColumns(client, tableName) {
|
|
7
|
+
const storeName = toPostgresStoreName(tableName);
|
|
6
8
|
const result = await client.query(`
|
|
7
9
|
SELECT column_name
|
|
8
10
|
FROM information_schema.columns
|
|
9
11
|
WHERE table_schema = current_schema()
|
|
10
12
|
AND table_name = $1
|
|
11
13
|
ORDER BY ordinal_position
|
|
12
|
-
`, [
|
|
14
|
+
`, [storeName]);
|
|
13
15
|
return result.rows.map(row => row.column_name);
|
|
14
16
|
}
|
|
15
17
|
function getParentAlias(localField) {
|
|
@@ -93,19 +95,21 @@ async function buildManyValue(client, op, operations, mainTableName, parentAlias
|
|
|
93
95
|
if (throughJoin) {
|
|
94
96
|
const throughAlias = throughJoin.as;
|
|
95
97
|
const linkColumn = op.localField.split('.')[1];
|
|
96
|
-
|
|
98
|
+
const throughFrom = toPostgresStoreName(throughJoin.from);
|
|
99
|
+
const opFrom = toPostgresStoreName(op.from);
|
|
100
|
+
fromClause = `"${throughFrom}" AS "${throughAlias}" INNER JOIN "${opFrom}" AS "${alias}" ON "${throughAlias}"."${linkColumn}" = "${alias}"."${op.foreignField}"`;
|
|
97
101
|
const throughParentRef = buildParentRef(throughJoin.localField, mainTableName);
|
|
98
102
|
whereClause = `"${throughAlias}"."${throughJoin.foreignField}" = ${throughParentRef}`;
|
|
99
103
|
}
|
|
100
104
|
else {
|
|
101
|
-
fromClause = `"${op.from}" AS "${alias}"`;
|
|
105
|
+
fromClause = `"${toPostgresStoreName(op.from)}" AS "${alias}"`;
|
|
102
106
|
whereClause = `"${alias}"."${op.foreignField}" = ${parentRef}`;
|
|
103
107
|
}
|
|
104
108
|
const throughAliasesUsedBySiblings = getThroughAliasesUsedBySiblings(childOps);
|
|
105
109
|
const oneToOneChildren = childOps.filter(c => c instanceof LeftJoin || c instanceof InnerJoin);
|
|
106
110
|
for (const child of oneToOneChildren) {
|
|
107
111
|
const leftCol = child.localField.includes('.') ? child.localField.split('.')[1] : child.localField;
|
|
108
|
-
fromClause += ` LEFT JOIN "${child.from}" AS "${child.as}" ON "${alias}"."${leftCol}" = "${child.as}"."${child.foreignField}"`;
|
|
112
|
+
fromClause += ` LEFT JOIN "${toPostgresStoreName(child.from)}" AS "${child.as}" ON "${alias}"."${leftCol}" = "${child.as}"."${child.foreignField}"`;
|
|
109
113
|
}
|
|
110
114
|
const itemEntries = columns.map(col => ({
|
|
111
115
|
key: col,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare function toSnakeCase(str: string): string;
|
|
2
|
+
export declare function toPostgresStoreName(logicalResourceName: string): string;
|
|
2
3
|
export declare function toCamelCase(str: string): string;
|
|
3
4
|
export declare function convertKeysToSnakeCase<T>(obj: T): T;
|
|
4
5
|
export declare function convertKeysToCamelCase<T>(obj: T): T;
|
|
@@ -7,6 +7,9 @@ export function toSnakeCase(str) {
|
|
|
7
7
|
.replace(/^_|_$/g, '');
|
|
8
8
|
return result;
|
|
9
9
|
}
|
|
10
|
+
export function toPostgresStoreName(logicalResourceName) {
|
|
11
|
+
return toSnakeCase(logicalResourceName);
|
|
12
|
+
}
|
|
10
13
|
export function toCamelCase(str) {
|
|
11
14
|
return str.split(/[-_]+/)
|
|
12
15
|
.map((word, index) => {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { toPostgresStoreName } from "./convert-keys.util.js";
|
|
1
2
|
export async function doesTableExist(client, tableName) {
|
|
3
|
+
const storeName = toPostgresStoreName(tableName);
|
|
2
4
|
const result = await client.query(`
|
|
3
5
|
SELECT EXISTS (
|
|
4
6
|
SELECT 1 FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = $1
|
|
5
7
|
)
|
|
6
|
-
`, [
|
|
8
|
+
`, [storeName]);
|
|
7
9
|
return result.rows[0].exists;
|
|
8
10
|
}
|
|
@@ -3,4 +3,5 @@ export * from './does-table-exist.util.js';
|
|
|
3
3
|
export * from './build-where-clause.js';
|
|
4
4
|
export * from './build-pagination-clause.js';
|
|
5
5
|
export * from './build-order-by-clause.js';
|
|
6
|
+
export * from './convert-keys.util.js';
|
|
6
7
|
export * from './convert-null-to-undefined.util.js';
|
|
@@ -3,4 +3,5 @@ export * from './does-table-exist.util.js';
|
|
|
3
3
|
export * from './build-where-clause.js';
|
|
4
4
|
export * from './build-pagination-clause.js';
|
|
5
5
|
export * from './build-order-by-clause.js';
|
|
6
|
+
export * from './convert-keys.util.js';
|
|
6
7
|
export * from './convert-null-to-undefined.util.js';
|
|
@@ -2,6 +2,6 @@ import { OrganizationDomainSpec, } from "@loomcore/common/models";
|
|
|
2
2
|
import { GenericApiService } from "./generic-api-service/generic-api.service.js";
|
|
3
3
|
export class OrganizationDomainService extends GenericApiService {
|
|
4
4
|
constructor(database) {
|
|
5
|
-
super(database, "
|
|
5
|
+
super(database, "organizationDomains", "organizationDomain", OrganizationDomainSpec);
|
|
6
6
|
}
|
|
7
7
|
}
|
|
@@ -3,7 +3,7 @@ import { PasswordResetTokenSpec, } from "@loomcore/common/models";
|
|
|
3
3
|
import { MultiTenantApiService } from "./multi-tenant-api.service.js";
|
|
4
4
|
export class PasswordResetTokenService extends MultiTenantApiService {
|
|
5
5
|
constructor(database) {
|
|
6
|
-
super(database, "
|
|
6
|
+
super(database, "passwordResetTokens", "passwordResetToken", PasswordResetTokenSpec);
|
|
7
7
|
}
|
|
8
8
|
async createPasswordResetToken(userContext, email, expiresOn) {
|
|
9
9
|
const lowerCaseEmail = email.toLowerCase();
|
|
@@ -2,6 +2,6 @@ import { refreshTokenModelSpec } from "@loomcore/common/models";
|
|
|
2
2
|
import { MultiTenantApiService } from "./multi-tenant-api.service.js";
|
|
3
3
|
export class RefreshTokenService extends MultiTenantApiService {
|
|
4
4
|
constructor(database) {
|
|
5
|
-
super(database, "
|
|
5
|
+
super(database, "refreshTokens", "refreshToken", refreshTokenModelSpec);
|
|
6
6
|
}
|
|
7
7
|
}
|
|
@@ -3,7 +3,7 @@ import { MultiTenantApiService } from "./multi-tenant-api.service.js";
|
|
|
3
3
|
import { assertUserHasFeature } from "../utils/index.js";
|
|
4
4
|
export class UserRolesService extends MultiTenantApiService {
|
|
5
5
|
constructor(database) {
|
|
6
|
-
super(database, "
|
|
6
|
+
super(database, "userRoles", "userRole", UserRoleModelSpec);
|
|
7
7
|
}
|
|
8
8
|
async preProcessEntity(userContext, entity, isCreate, allowId = true) {
|
|
9
9
|
assertUserHasFeature(userContext, ['admin', 'system', 'user-roles']);
|