@drax/identity-back 0.0.8 → 0.0.10
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/errors/BadCredentialsError.js +10 -0
- package/dist/errors/UnauthorizedError.js +10 -0
- package/dist/factory/RoleServiceFactory.js +16 -3
- package/dist/factory/UserServiceFactory.js +17 -3
- package/dist/graphql/resolvers/role.resolvers.js +98 -11
- package/dist/graphql/resolvers/user.resolvers.js +134 -15
- package/dist/graphql/types/role.graphql +6 -4
- package/dist/graphql/types/user.graphql +36 -9
- package/dist/i18n/messages/validation-i18n.js +21 -0
- package/dist/index.js +22 -7
- package/dist/interfaces/IID.js +1 -0
- package/dist/interfaces/IJwtUser.js +1 -0
- package/dist/middleware/jwtMiddleware.js +19 -0
- package/dist/middleware/rbacMiddleware.js +36 -0
- package/dist/models/RoleModel.js +0 -8
- package/dist/models/UserModel.js +1 -2
- package/dist/permissions/IdentityPermissions.js +16 -0
- package/dist/rbac/Rbac.js +20 -0
- package/dist/repository/mongo/RoleMongoRepository.js +41 -0
- package/dist/repository/mongo/UserMongoRepository.js +82 -0
- package/dist/repository/sqlite/RoleSqliteRepository.js +115 -0
- package/dist/repository/sqlite/UserSqliteRepository.js +157 -0
- package/dist/routes/RoleRoutes.js +145 -0
- package/dist/routes/UserRoutes.js +199 -0
- package/dist/routes/authRoutes.js +12 -4
- package/dist/services/AuthService.js +0 -15
- package/dist/services/PermissionService.js +19 -0
- package/dist/services/RoleService.js +48 -16
- package/dist/services/UserService.js +82 -23
- package/dist/utils/AuthUtils.js +20 -6
- package/dist/utils/DbSetupUtils.js +28 -0
- package/dist/zod/RoleZod.js +8 -0
- package/dist/zod/UserZod.js +18 -0
- package/package.json +17 -10
- package/src/errors/BadCredentialsError.ts +13 -0
- package/src/errors/UnauthorizedError.ts +13 -0
- package/src/factory/RoleServiceFactory.ts +20 -3
- package/src/factory/UserServiceFactory.ts +20 -3
- package/src/graphql/resolvers/role.resolvers.ts +92 -11
- package/src/graphql/resolvers/user.resolvers.ts +128 -15
- package/src/graphql/types/role.graphql +6 -4
- package/src/graphql/types/user.graphql +36 -9
- package/src/index.ts +50 -10
- package/src/interfaces/IID.ts +5 -0
- package/src/interfaces/IJwtUser.ts +7 -0
- package/src/interfaces/IRole.ts +15 -5
- package/src/interfaces/IRoleRepository.ts +8 -5
- package/src/interfaces/IUser.ts +30 -6
- package/src/interfaces/IUserGroup.ts +2 -1
- package/src/interfaces/IUserRepository.ts +11 -6
- package/src/middleware/jwtMiddleware.ts +22 -0
- package/src/middleware/rbacMiddleware.ts +40 -0
- package/src/models/RoleModel.ts +0 -9
- package/src/models/UserModel.ts +1 -2
- package/src/permissions/IdentityPermissions.ts +20 -0
- package/src/rbac/Rbac.ts +31 -0
- package/src/repository/mongo/RoleMongoRepository.ts +57 -0
- package/src/repository/mongo/UserMongoRepository.ts +104 -0
- package/src/repository/sqlite/RoleSqliteRepository.ts +151 -0
- package/src/repository/sqlite/UserSqliteRepository.ts +194 -0
- package/src/routes/RoleRoutes.ts +141 -0
- package/src/routes/UserRoutes.ts +198 -0
- package/src/services/PermissionService.ts +26 -0
- package/src/services/RoleService.ts +46 -21
- package/src/services/UserService.ts +86 -28
- package/src/utils/AuthUtils.ts +22 -7
- package/src/utils/DbSetupUtils.ts +39 -0
- package/src/zod/RoleZod.ts +14 -0
- package/src/zod/UserZod.ts +26 -0
- package/test/data-json/roles/admin-role.json +1 -1
- package/test/data-obj/roles/{admin-role.ts → admin-mongo-role.ts} +2 -1
- package/test/data-obj/roles/admin-sqlite-role.ts +9 -0
- package/test/data-obj/roles/operator-sqlite-role.ts +9 -0
- package/test/data-obj/users/root-mongo-user.ts +15 -0
- package/test/data-obj/users/root-sqlite-user.ts +16 -0
- package/test/{initializers → db}/MongoInMemory.ts +2 -1
- package/test/initializers/RoleMongoInitializer.ts +15 -0
- package/test/initializers/RoleSqliteInitializer.ts +18 -0
- package/test/repository/{role-repository.test.ts → mongo/role-mongo-repository.test.ts} +14 -24
- package/test/repository/mongo/user-mongo-repository.test.ts +121 -0
- package/test/repository/sqlite/role-sqlite-repository.test.ts +70 -0
- package/test/repository/sqlite/user-sqlite-repository.test.ts +126 -0
- package/test/service/mock-service.test.ts +3 -3
- package/test/service/role-service.test.ts +5 -5
- package/test/service/user-service.test.ts +42 -15
- package/test.db +0 -0
- package/tsconfig.json +16 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/types/errors/BadCredentialsError.d.ts +6 -0
- package/types/errors/BadCredentialsError.d.ts.map +1 -0
- package/types/errors/UnauthorizedError.d.ts +6 -0
- package/types/errors/UnauthorizedError.d.ts.map +1 -0
- package/types/factory/RoleServiceFactory.d.ts +2 -2
- package/types/factory/RoleServiceFactory.d.ts.map +1 -1
- package/types/factory/UserServiceFactory.d.ts +2 -2
- package/types/factory/UserServiceFactory.d.ts.map +1 -1
- package/types/graphql/resolvers/role.resolvers.d.ts +24 -7
- package/types/graphql/resolvers/role.resolvers.d.ts.map +1 -1
- package/types/graphql/resolvers/user.resolvers.d.ts +38 -7
- package/types/graphql/resolvers/user.resolvers.d.ts.map +1 -1
- package/types/i18n/messages/validation-i18n.d.ts +4 -0
- package/types/i18n/messages/validation-i18n.d.ts.map +1 -0
- package/types/index.d.ts +21 -5
- package/types/index.d.ts.map +1 -1
- package/types/interfaces/IID.d.ts +6 -0
- package/types/interfaces/IID.d.ts.map +1 -0
- package/types/interfaces/IJwtUser.d.ts +7 -0
- package/types/interfaces/IJwtUser.d.ts.map +1 -0
- package/types/interfaces/IRole.d.ts +13 -6
- package/types/interfaces/IRole.d.ts.map +1 -1
- package/types/interfaces/IRoleRepository.d.ts +8 -4
- package/types/interfaces/IRoleRepository.d.ts.map +1 -1
- package/types/interfaces/IUser.d.ts +29 -8
- package/types/interfaces/IUser.d.ts.map +1 -1
- package/types/interfaces/IUserGroup.d.ts +3 -2
- package/types/interfaces/IUserGroup.d.ts.map +1 -1
- package/types/interfaces/IUserRepository.d.ts +10 -6
- package/types/interfaces/IUserRepository.d.ts.map +1 -1
- package/types/middleware/jwtMiddleware.d.ts +4 -0
- package/types/middleware/jwtMiddleware.d.ts.map +1 -0
- package/types/middleware/rbacMiddleware.d.ts +4 -0
- package/types/middleware/rbacMiddleware.d.ts.map +1 -0
- package/types/models/RoleModel.d.ts +8 -8
- package/types/models/RoleModel.d.ts.map +1 -1
- package/types/models/UserGroupModel.d.ts +8 -8
- package/types/models/UserGroupModel.d.ts.map +1 -1
- package/types/models/UserModel.d.ts +8 -8
- package/types/models/UserModel.d.ts.map +1 -1
- package/types/permissions/IdentityPermissions.d.ts +16 -0
- package/types/permissions/IdentityPermissions.d.ts.map +1 -0
- package/types/rbac/Rbac.d.ts +12 -0
- package/types/rbac/Rbac.d.ts.map +1 -0
- package/types/repository/mongo/RoleMongoRepository.d.ts +14 -0
- package/types/repository/mongo/RoleMongoRepository.d.ts.map +1 -0
- package/types/repository/mongo/UserMongoRepository.d.ts +18 -0
- package/types/repository/mongo/UserMongoRepository.d.ts.map +1 -0
- package/types/repository/sqlite/RoleSqliteRepository.d.ts +19 -0
- package/types/repository/sqlite/RoleSqliteRepository.d.ts.map +1 -0
- package/types/repository/sqlite/UserSqliteRepository.d.ts +24 -0
- package/types/repository/sqlite/UserSqliteRepository.d.ts.map +1 -0
- package/types/routes/RoleRoutes.d.ts +4 -0
- package/types/routes/RoleRoutes.d.ts.map +1 -0
- package/types/routes/UserRoutes.d.ts +4 -0
- package/types/routes/UserRoutes.d.ts.map +1 -0
- package/types/routes/authRoutes.d.ts.map +1 -1
- package/types/services/AuthService.d.ts +0 -3
- package/types/services/AuthService.d.ts.map +1 -1
- package/types/services/PermissionService.d.ts +9 -0
- package/types/services/PermissionService.d.ts.map +1 -0
- package/types/services/RoleService.d.ts +6 -8
- package/types/services/RoleService.d.ts.map +1 -1
- package/types/services/UserService.d.ts +13 -11
- package/types/services/UserService.d.ts.map +1 -1
- package/types/utils/AuthUtils.d.ts +5 -2
- package/types/utils/AuthUtils.d.ts.map +1 -1
- package/types/utils/DbSetupUtils.d.ts +10 -0
- package/types/utils/DbSetupUtils.d.ts.map +1 -0
- package/types/zod/RoleZod.d.ts +10 -0
- package/types/zod/RoleZod.d.ts.map +1 -0
- package/types/zod/UserZod.d.ts +53 -0
- package/types/zod/UserZod.d.ts.map +1 -0
- package/dist/factory/AuthServiceFactory.js +0 -8
- package/dist/graphql/resolvers/auth.resolvers.js +0 -16
- package/dist/graphql/types/auth.graphql +0 -12
- package/dist/repository/RoleRepository.js +0 -29
- package/dist/repository/UserRepository.js +0 -33
- package/src/factory/AuthServiceFactory.ts +0 -10
- package/src/graphql/resolvers/auth.resolvers.ts +0 -20
- package/src/graphql/types/auth.graphql +0 -12
- package/src/repository/RoleRepository.ts +0 -42
- package/src/repository/UserRepository.ts +0 -47
- package/src/routes/authRoutes.ts +0 -22
- package/src/services/AuthService.ts +0 -29
- package/test/data-obj/users/root-user.ts +0 -15
- package/test/initializers/MongoInMemory.mjs +0 -34
- package/test/initializers/RoleInitializer.mjs +0 -11
- package/test/initializers/RoleInitializer.ts +0 -15
- package/test/repository/user-repository.test.ts +0 -54
- package/types/factory/AuthServiceFactory.d.ts +0 -4
- package/types/factory/AuthServiceFactory.d.ts.map +0 -1
- package/types/graphql/resolvers/auth.resolvers.d.ts +0 -12
- package/types/graphql/resolvers/auth.resolvers.d.ts.map +0 -1
- package/types/repository/RoleRepository.d.ts +0 -41
- package/types/repository/RoleRepository.d.ts.map +0 -1
- package/types/repository/UserRepository.d.ts +0 -40
- package/types/repository/UserRepository.d.ts.map +0 -1
- package/types/routes/AuthRoutes.d.ts +0 -3
- package/types/routes/AuthRoutes.d.ts.map +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { RoleModel } from "../../models/RoleModel.js";
|
|
2
|
+
class RoleMongoRepository {
|
|
3
|
+
async create(roleData) {
|
|
4
|
+
const role = new RoleModel(roleData);
|
|
5
|
+
await role.save();
|
|
6
|
+
return role;
|
|
7
|
+
}
|
|
8
|
+
async update(id, roleData) {
|
|
9
|
+
const role = await RoleModel.findOneAndUpdate({ _id: id }, roleData, { new: true }).exec();
|
|
10
|
+
return role;
|
|
11
|
+
}
|
|
12
|
+
async delete(id) {
|
|
13
|
+
const result = await RoleModel.deleteOne(id).exec();
|
|
14
|
+
return result.deletedCount == 1;
|
|
15
|
+
}
|
|
16
|
+
async findById(id) {
|
|
17
|
+
const role = await RoleModel.findById(id).exec();
|
|
18
|
+
return role;
|
|
19
|
+
}
|
|
20
|
+
async fetchAll() {
|
|
21
|
+
const roles = await RoleModel.find().exec();
|
|
22
|
+
return roles;
|
|
23
|
+
}
|
|
24
|
+
async paginate(page = 1, limit = 5, search) {
|
|
25
|
+
const query = {};
|
|
26
|
+
if (search) {
|
|
27
|
+
query['$or'] = [
|
|
28
|
+
{ name: new RegExp(search, 'i') },
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
const options = { page, limit };
|
|
32
|
+
const roles = await RoleModel.paginate(query, options);
|
|
33
|
+
return {
|
|
34
|
+
page: page,
|
|
35
|
+
limit: limit,
|
|
36
|
+
total: roles.totalDocs,
|
|
37
|
+
items: roles.docs
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export default RoleMongoRepository;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { UserModel } from "../../models/UserModel.js";
|
|
2
|
+
import { mongoose, MongooseErrorToValidationError, MongoServerErrorToValidationError, ValidationError } from "@drax/common-back";
|
|
3
|
+
import { MongoServerError } from "mongodb";
|
|
4
|
+
import RoleMongoRepository from "./RoleMongoRepository.js";
|
|
5
|
+
class UserMongoRepository {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.roleRepository = new RoleMongoRepository();
|
|
8
|
+
}
|
|
9
|
+
async create(userData) {
|
|
10
|
+
try {
|
|
11
|
+
if (!await this.roleRepository.findById(userData.role)) {
|
|
12
|
+
throw new ValidationError([{ field: 'role', reason: 'validation.notfound', value: userData.role }]);
|
|
13
|
+
}
|
|
14
|
+
const user = new UserModel(userData);
|
|
15
|
+
await user.save();
|
|
16
|
+
await user.populate('role');
|
|
17
|
+
return user;
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
if (e instanceof mongoose.Error.ValidationError) {
|
|
21
|
+
throw MongooseErrorToValidationError(e);
|
|
22
|
+
}
|
|
23
|
+
throw e;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async update(id, userData) {
|
|
27
|
+
try {
|
|
28
|
+
const user = await UserModel.findOneAndUpdate({ _id: id }, userData, { new: true }).populate('role').exec();
|
|
29
|
+
return user;
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
if (e instanceof mongoose.Error.ValidationError) {
|
|
33
|
+
throw MongooseErrorToValidationError(e);
|
|
34
|
+
}
|
|
35
|
+
if (e instanceof MongoServerError || e.name === 'MongoServerError') {
|
|
36
|
+
throw MongoServerErrorToValidationError(e);
|
|
37
|
+
}
|
|
38
|
+
throw e;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async delete(id) {
|
|
42
|
+
const result = await UserModel.deleteOne({ _id: id }).exec();
|
|
43
|
+
return result.deletedCount == 1;
|
|
44
|
+
}
|
|
45
|
+
async findById(id) {
|
|
46
|
+
const user = await UserModel.findById(id).populate('role').exec();
|
|
47
|
+
return user;
|
|
48
|
+
}
|
|
49
|
+
async findByUsername(username) {
|
|
50
|
+
const user = await UserModel.findOne({ username: username }).populate('role').exec();
|
|
51
|
+
return user;
|
|
52
|
+
}
|
|
53
|
+
async paginate(page = 1, limit = 5, search) {
|
|
54
|
+
const query = {};
|
|
55
|
+
if (search) {
|
|
56
|
+
query['$or'] = [
|
|
57
|
+
{ username: new RegExp(search, 'i') },
|
|
58
|
+
{ email: new RegExp(search, 'i') },
|
|
59
|
+
{ name: new RegExp(search, 'i') },
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
const options = { populate: ['role'], page: page, limit: limit };
|
|
63
|
+
const userPaginated = await UserModel.paginate(query, options);
|
|
64
|
+
return {
|
|
65
|
+
page: page,
|
|
66
|
+
limit: limit,
|
|
67
|
+
total: userPaginated.totalDocs,
|
|
68
|
+
items: userPaginated.docs
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async changePassword(id, password) {
|
|
72
|
+
try {
|
|
73
|
+
await UserModel.findOneAndUpdate({ _id: id }, { password }).exec();
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
console.error(e);
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export default UserMongoRepository;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import sqlite from "better-sqlite3";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { SqliteErrorToValidationError } from "@drax/common-back";
|
|
4
|
+
const roleTableSQL = `
|
|
5
|
+
CREATE TABLE IF NOT EXISTS roles
|
|
6
|
+
(
|
|
7
|
+
id TEXT PRIMARY KEY,
|
|
8
|
+
name TEXT,
|
|
9
|
+
permissions TEXT,
|
|
10
|
+
readonly INTEGER,
|
|
11
|
+
childRoles TEXT
|
|
12
|
+
|
|
13
|
+
);
|
|
14
|
+
`;
|
|
15
|
+
class RoleSqliteRepository {
|
|
16
|
+
constructor(DATABASE, verbose = false) {
|
|
17
|
+
this.db = new sqlite(DATABASE, { verbose: verbose ? console.log : null });
|
|
18
|
+
}
|
|
19
|
+
table() {
|
|
20
|
+
this.db.exec(roleTableSQL);
|
|
21
|
+
}
|
|
22
|
+
normalizeData(roleData) {
|
|
23
|
+
roleData.readonly = roleData.readonly ? 1 : 0;
|
|
24
|
+
if (roleData.permissions && Array.isArray(roleData.permissions)) {
|
|
25
|
+
roleData.permissions = roleData.permissions.join(",");
|
|
26
|
+
}
|
|
27
|
+
if (roleData.childRoles && Array.isArray(roleData.childRoles)) {
|
|
28
|
+
roleData.childRoles = roleData.childRoles.join(",");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async create(roleData) {
|
|
32
|
+
try {
|
|
33
|
+
if (!roleData.id) {
|
|
34
|
+
roleData.id = randomUUID();
|
|
35
|
+
}
|
|
36
|
+
this.normalizeData(roleData);
|
|
37
|
+
const fields = Object.keys(roleData)
|
|
38
|
+
.map(field => `${field}`)
|
|
39
|
+
.join(', ');
|
|
40
|
+
const values = Object.keys(roleData)
|
|
41
|
+
.map(field => `@${field}`)
|
|
42
|
+
.join(', ');
|
|
43
|
+
/* console.log("fields", fields)
|
|
44
|
+
console.log("values",values)
|
|
45
|
+
console.log("userData",roleData)*/
|
|
46
|
+
const stmt = this.db.prepare(`INSERT INTO roles (${fields}) VALUES (${values})`);
|
|
47
|
+
stmt.run(roleData);
|
|
48
|
+
return this.findById(roleData.id);
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
console.log(e);
|
|
52
|
+
throw SqliteErrorToValidationError(e, roleData);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async findById(id) {
|
|
56
|
+
const role = this.db.prepare('SELECT * FROM roles WHERE id = ?').get(id);
|
|
57
|
+
if (role) {
|
|
58
|
+
role.permissions = role.permissions ? role.permissions.split(",") : [];
|
|
59
|
+
return role;
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
async update(id, roleData) {
|
|
64
|
+
try {
|
|
65
|
+
this.normalizeData(roleData);
|
|
66
|
+
const setClauses = Object.keys(roleData)
|
|
67
|
+
.map(field => `${field} = @${field}`)
|
|
68
|
+
.join(', ');
|
|
69
|
+
roleData.id = id;
|
|
70
|
+
const stmt = this.db.prepare(`UPDATE roles SET ${setClauses} WHERE id = @id `);
|
|
71
|
+
stmt.run(roleData);
|
|
72
|
+
return this.findById(id);
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
console.log(e);
|
|
76
|
+
throw SqliteErrorToValidationError(e, roleData);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async delete(id) {
|
|
80
|
+
const stmt = this.db.prepare('DELETE FROM roles WHERE id = ?');
|
|
81
|
+
stmt.run(id);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
async deleteAll() {
|
|
85
|
+
const stmt = this.db.prepare('DELETE FROM roles');
|
|
86
|
+
stmt.run();
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
async fetchAll() {
|
|
90
|
+
const roles = this.db.prepare('SELECT * FROM roles').all();
|
|
91
|
+
for (const role of roles) {
|
|
92
|
+
role.permissions = role.permissions ? role.permissions.split(",") : [];
|
|
93
|
+
}
|
|
94
|
+
return roles;
|
|
95
|
+
}
|
|
96
|
+
async paginate(page = 1, limit = 5, search = "") {
|
|
97
|
+
const offset = page > 1 ? (page - 1) * limit : 0;
|
|
98
|
+
let where;
|
|
99
|
+
if (search) {
|
|
100
|
+
where = ` WHERE name LIKE '%${search}%'`;
|
|
101
|
+
}
|
|
102
|
+
const rCount = this.db.prepare('SELECT COUNT(*) as count FROM roles' + where).get();
|
|
103
|
+
const roles = this.db.prepare('SELECT * FROM roles LIMIT ? OFFSET ?' + where).all([limit, offset]);
|
|
104
|
+
for (const role of roles) {
|
|
105
|
+
role.permissions = role.permissions ? role.permissions.split(",") : [];
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
page: page,
|
|
109
|
+
limit: limit,
|
|
110
|
+
total: rCount.count,
|
|
111
|
+
items: roles
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export default RoleSqliteRepository;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import sqlite from "better-sqlite3";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { SqliteErrorToValidationError, ValidationError } from "@drax/common-back";
|
|
4
|
+
import RoleSqliteRepository from "./RoleSqliteRepository.js";
|
|
5
|
+
const userTableSQL = `
|
|
6
|
+
CREATE TABLE IF NOT EXISTS users
|
|
7
|
+
(
|
|
8
|
+
id
|
|
9
|
+
TEXT
|
|
10
|
+
PRIMARY
|
|
11
|
+
KEY,
|
|
12
|
+
name
|
|
13
|
+
TEXT,
|
|
14
|
+
username
|
|
15
|
+
TEXT
|
|
16
|
+
UNIQUE,
|
|
17
|
+
active
|
|
18
|
+
INTEGER,
|
|
19
|
+
password
|
|
20
|
+
TEXT,
|
|
21
|
+
email
|
|
22
|
+
TEXT
|
|
23
|
+
UNIQUE,
|
|
24
|
+
phone
|
|
25
|
+
TEXT,
|
|
26
|
+
role
|
|
27
|
+
TEXT,
|
|
28
|
+
groups
|
|
29
|
+
TEXT,
|
|
30
|
+
avatar
|
|
31
|
+
TEXT
|
|
32
|
+
);
|
|
33
|
+
`;
|
|
34
|
+
class UserSqliteRepository {
|
|
35
|
+
constructor(DATABASE, verbose = false) {
|
|
36
|
+
this.db = new sqlite(DATABASE, { verbose: verbose ? console.log : null });
|
|
37
|
+
this.roleRepository = new RoleSqliteRepository(DATABASE, verbose);
|
|
38
|
+
}
|
|
39
|
+
table() {
|
|
40
|
+
this.db.exec(userTableSQL);
|
|
41
|
+
}
|
|
42
|
+
normalizeData(userData) {
|
|
43
|
+
if (userData.groups && Array.isArray(userData.groups)) {
|
|
44
|
+
userData.groups = userData.groups.join(",");
|
|
45
|
+
}
|
|
46
|
+
userData.active = userData.active ? 1 : 0;
|
|
47
|
+
}
|
|
48
|
+
async create(userData) {
|
|
49
|
+
if (!userData.id) {
|
|
50
|
+
userData.id = randomUUID();
|
|
51
|
+
}
|
|
52
|
+
if (!await this.findRoleById(userData.role)) {
|
|
53
|
+
throw new ValidationError([{ field: 'role', reason: 'validation.notfound', value: userData.role }]);
|
|
54
|
+
}
|
|
55
|
+
this.normalizeData(userData);
|
|
56
|
+
try {
|
|
57
|
+
const fields = Object.keys(userData)
|
|
58
|
+
.map(field => `${field}`)
|
|
59
|
+
.join(', ');
|
|
60
|
+
const values = Object.keys(userData)
|
|
61
|
+
.map(field => `@${field}`)
|
|
62
|
+
.join(', ');
|
|
63
|
+
/*console.log("fields", fields)
|
|
64
|
+
console.log("values",values)
|
|
65
|
+
console.log("userData",userData)*/
|
|
66
|
+
const stmt = this.db.prepare(`INSERT INTO users (${fields})
|
|
67
|
+
VALUES (${values})`);
|
|
68
|
+
stmt.run(userData);
|
|
69
|
+
return this.findById(userData.id);
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
throw SqliteErrorToValidationError(e, userData);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async update(id, userData) {
|
|
76
|
+
try {
|
|
77
|
+
if (!await this.findRoleById(userData.role)) {
|
|
78
|
+
throw new ValidationError([{ field: 'role', reason: 'validation.notfound', value: userData.role }]);
|
|
79
|
+
}
|
|
80
|
+
this.normalizeData(userData);
|
|
81
|
+
const setClauses = Object.keys(userData)
|
|
82
|
+
.map(field => `${field} = @${field}`)
|
|
83
|
+
.join(', ');
|
|
84
|
+
userData.id = id;
|
|
85
|
+
const stmt = this.db.prepare(`UPDATE users
|
|
86
|
+
SET ${setClauses}
|
|
87
|
+
WHERE id = @id `);
|
|
88
|
+
stmt.run(userData);
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
throw SqliteErrorToValidationError(e, userData);
|
|
92
|
+
}
|
|
93
|
+
return this.findById(id);
|
|
94
|
+
}
|
|
95
|
+
async delete(id) {
|
|
96
|
+
const stmt = this.db.prepare('DELETE FROM users WHERE id = ?');
|
|
97
|
+
stmt.run(id);
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
async deleteAll() {
|
|
101
|
+
const stmt = this.db.prepare('DELETE FROM users');
|
|
102
|
+
stmt.run();
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
async findById(id) {
|
|
106
|
+
const user = this.db.prepare('SELECT * FROM users WHERE id = ?').get(id);
|
|
107
|
+
if (!user) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
user.role = await this.findRoleById(user.role);
|
|
111
|
+
return user;
|
|
112
|
+
}
|
|
113
|
+
async findByUsername(username) {
|
|
114
|
+
const user = this.db.prepare('SELECT * FROM users WHERE username = ?').get(username);
|
|
115
|
+
if (!user) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
user.role = await this.findRoleById(user.role);
|
|
119
|
+
return user;
|
|
120
|
+
}
|
|
121
|
+
async paginate(page = 1, limit = 5, search) {
|
|
122
|
+
const offset = page > 1 ? (page - 1) * limit : 0;
|
|
123
|
+
let where;
|
|
124
|
+
if (search) {
|
|
125
|
+
where = ` WHERE name LIKE '%${search}%' OR username LIKE '%${search}%'`;
|
|
126
|
+
}
|
|
127
|
+
const rCount = this.db.prepare('SELECT COUNT(*) as count FROM users' + where).get();
|
|
128
|
+
const users = this.db.prepare('SELECT * FROM users LIMIT ? OFFSET ?' + where).all([limit, offset]);
|
|
129
|
+
for (const user of users) {
|
|
130
|
+
let role = await this.findRoleById(user.role);
|
|
131
|
+
if (role) {
|
|
132
|
+
user.role = role;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
user.role = null;
|
|
136
|
+
}
|
|
137
|
+
user.active = user.active === 1;
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
page: page,
|
|
141
|
+
limit: limit,
|
|
142
|
+
total: rCount.count,
|
|
143
|
+
items: users
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
async findRoleById(id) {
|
|
147
|
+
return await this.roleRepository.findById(id);
|
|
148
|
+
}
|
|
149
|
+
async changePassword(id, password) {
|
|
150
|
+
const stmt = this.db.prepare(`UPDATE users
|
|
151
|
+
SET password = @password
|
|
152
|
+
WHERE id = @id `);
|
|
153
|
+
stmt.run({ id: id, password: password });
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export default UserSqliteRepository;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { ValidationError } from "@drax/common-back";
|
|
2
|
+
import RoleServiceFactory from "../factory/RoleServiceFactory.js";
|
|
3
|
+
import { IdentityPermissions } from "../permissions/IdentityPermissions.js";
|
|
4
|
+
import { PermissionService } from "../services/PermissionService.js";
|
|
5
|
+
import UnauthorizedError from "../errors/UnauthorizedError.js";
|
|
6
|
+
const roleService = RoleServiceFactory;
|
|
7
|
+
async function RoleRoutes(fastify, options) {
|
|
8
|
+
fastify.get('/api/permissions', async (request, reply) => {
|
|
9
|
+
try {
|
|
10
|
+
request.rbac.assertPermission(IdentityPermissions.PermissionsRole);
|
|
11
|
+
let permissions = PermissionService.getPermissions();
|
|
12
|
+
return permissions;
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
console.error(e);
|
|
16
|
+
if (e instanceof UnauthorizedError) {
|
|
17
|
+
reply.statusCode = e.statusCode;
|
|
18
|
+
reply.send({ error: e.message });
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
reply.statusCode = 500;
|
|
22
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
fastify.get('/api/roles/all', async (request, reply) => {
|
|
27
|
+
try {
|
|
28
|
+
request.rbac.assertPermission(IdentityPermissions.ViewRole);
|
|
29
|
+
let roles = await roleService.fetchAll();
|
|
30
|
+
return roles;
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
console.error(e);
|
|
34
|
+
if (e instanceof ValidationError) {
|
|
35
|
+
reply.statusCode = e.statusCode;
|
|
36
|
+
reply.send({ error: e.message, inputErrors: e.errors });
|
|
37
|
+
}
|
|
38
|
+
else if (e instanceof UnauthorizedError) {
|
|
39
|
+
reply.statusCode = e.statusCode;
|
|
40
|
+
reply.send({ error: e.message });
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
reply.statusCode = 500;
|
|
44
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
fastify.get('/api/roles', async (request, reply) => {
|
|
49
|
+
try {
|
|
50
|
+
request.rbac.assertPermission(IdentityPermissions.ViewRole);
|
|
51
|
+
const page = request.query.page;
|
|
52
|
+
const limit = request.query.limit;
|
|
53
|
+
const search = request.query.search;
|
|
54
|
+
let paginateResult = await roleService.paginate(page, limit, search);
|
|
55
|
+
return paginateResult;
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
console.error(e);
|
|
59
|
+
if (e instanceof ValidationError) {
|
|
60
|
+
reply.statusCode = e.statusCode;
|
|
61
|
+
reply.send({ error: e.message, inputErrors: e.errors });
|
|
62
|
+
}
|
|
63
|
+
else if (e instanceof UnauthorizedError) {
|
|
64
|
+
reply.statusCode = e.statusCode;
|
|
65
|
+
reply.send({ error: e.message });
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
reply.statusCode = 500;
|
|
69
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
fastify.post('/api/roles', async (request, reply) => {
|
|
74
|
+
try {
|
|
75
|
+
request.rbac.assertPermission(IdentityPermissions.CreateRole);
|
|
76
|
+
const payload = request.body;
|
|
77
|
+
let role = await roleService.create(payload);
|
|
78
|
+
return role;
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
console.error(e);
|
|
82
|
+
if (e instanceof ValidationError) {
|
|
83
|
+
reply.statusCode = e.statusCode;
|
|
84
|
+
reply.send({ error: e.message, inputErrors: e.errors });
|
|
85
|
+
}
|
|
86
|
+
else if (e instanceof UnauthorizedError) {
|
|
87
|
+
reply.statusCode = e.statusCode;
|
|
88
|
+
reply.send({ error: e.message });
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
reply.statusCode = 500;
|
|
92
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
fastify.put('/api/roles/:id', async (request, reply) => {
|
|
97
|
+
try {
|
|
98
|
+
request.rbac.assertPermission(IdentityPermissions.UpdateRole);
|
|
99
|
+
const id = request.params.id;
|
|
100
|
+
const payload = request.body;
|
|
101
|
+
let role = await roleService.update(id, payload);
|
|
102
|
+
return role;
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
console.error(e);
|
|
106
|
+
if (e instanceof ValidationError) {
|
|
107
|
+
reply.statusCode = e.statusCode;
|
|
108
|
+
reply.send({ error: e.message, inputErrors: e.errors });
|
|
109
|
+
}
|
|
110
|
+
else if (e instanceof UnauthorizedError) {
|
|
111
|
+
reply.statusCode = e.statusCode;
|
|
112
|
+
reply.send({ error: e.message });
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
reply.statusCode = 500;
|
|
116
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
fastify.delete('/api/roles/:id', async (request, reply) => {
|
|
121
|
+
try {
|
|
122
|
+
request.rbac.assertPermission(IdentityPermissions.DeleteRole);
|
|
123
|
+
const id = request.params.id;
|
|
124
|
+
let r = await roleService.delete(id);
|
|
125
|
+
return r;
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
console.error(e);
|
|
129
|
+
if (e instanceof ValidationError) {
|
|
130
|
+
reply.statusCode = e.statusCode;
|
|
131
|
+
reply.send({ error: e.message, inputErrors: e.errors });
|
|
132
|
+
}
|
|
133
|
+
else if (e instanceof UnauthorizedError) {
|
|
134
|
+
reply.statusCode = e.statusCode;
|
|
135
|
+
reply.send({ error: e.message });
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
reply.statusCode = 500;
|
|
139
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
export default RoleRoutes;
|
|
145
|
+
export { RoleRoutes };
|