This commit is contained in:
@@ -7,6 +7,7 @@ import { SSOClientService } from "./sso-client.service";
|
|||||||
import { TokensService } from "./tokens.service";
|
import { TokensService } from "./tokens.service";
|
||||||
import { AuthMessage } from "../../../common/enums/message.enum";
|
import { AuthMessage } from "../../../common/enums/message.enum";
|
||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
|
import { getPermissionsFromRoles } from "../../users/utils/role-permissions.util";
|
||||||
import { ITokenPayload } from "../interfaces/IToken-payload";
|
import { ITokenPayload } from "../interfaces/IToken-payload";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -46,7 +47,7 @@ export class SSOService {
|
|||||||
const payload: ITokenPayload = {
|
const payload: ITokenPayload = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
permissions: getPermissionsFromRoles(user.roles),
|
||||||
audience: clientId,
|
audience: clientId,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -105,7 +106,7 @@ export class SSOService {
|
|||||||
const payload: ITokenPayload = {
|
const payload: ITokenPayload = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
permissions: getPermissionsFromRoles(user.roles),
|
||||||
audience: clientId,
|
audience: clientId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { DataSource, QueryRunner } from "typeorm";
|
|||||||
import { AuthMessage } from "../../../common/enums/message.enum";
|
import { AuthMessage } from "../../../common/enums/message.enum";
|
||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
import { RefreshTokensRepository } from "../../users/repositories/refresh-token.repository";
|
import { RefreshTokensRepository } from "../../users/repositories/refresh-token.repository";
|
||||||
|
import { getPermissionsFromRoles } from "../../users/utils/role-permissions.util";
|
||||||
import { ITokenPayload } from "../interfaces/IToken-payload";
|
import { ITokenPayload } from "../interfaces/IToken-payload";
|
||||||
import { ResellerType } from "../DTO/verify-reseller-otp.dto";
|
import { ResellerType } from "../DTO/verify-reseller-otp.dto";
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ export class TokensService {
|
|||||||
{
|
{
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
permissions: getPermissionsFromRoles(user.roles),
|
||||||
},
|
},
|
||||||
queryRunner,
|
queryRunner,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||||
import { IsEmail, IsMobilePhone, IsNotEmpty, IsOptional, IsString, IsUUID, IsUrl, Length, MinLength } from "class-validator";
|
import { ArrayNotEmpty, IsArray, IsEmail, IsMobilePhone, IsNotEmpty, IsOptional, IsString, IsUUID, IsUrl, Length, MinLength } from "class-validator";
|
||||||
|
|
||||||
import { AdminMessage, AuthMessage } from "../../../common/enums/message.enum";
|
import { AdminMessage, AuthMessage } from "../../../common/enums/message.enum";
|
||||||
|
|
||||||
@@ -22,9 +22,11 @@ export class CreateAdminDto {
|
|||||||
phone: string;
|
phone: string;
|
||||||
|
|
||||||
@IsNotEmpty({ message: AdminMessage.ROLE_REQUIRED })
|
@IsNotEmpty({ message: AdminMessage.ROLE_REQUIRED })
|
||||||
@IsUUID("4", { message: AdminMessage.ROLE_ID_SHOULD_BE_UUID })
|
@IsArray({ message: AdminMessage.ROLE_REQUIRED })
|
||||||
@ApiProperty({ description: "Role id", example: "123e4567-e89b-12d3-a456-426614174000" })
|
@ArrayNotEmpty({ message: AdminMessage.ROLE_REQUIRED })
|
||||||
roleId: string;
|
@IsUUID("4", { each: true, message: AdminMessage.ROLE_ID_SHOULD_BE_UUID })
|
||||||
|
@ApiProperty({ description: "Role ids", example: ["123e4567-e89b-12d3-a456-426614174000"], type: [String] })
|
||||||
|
roleIds: string[];
|
||||||
|
|
||||||
@IsNotEmpty({ message: AuthMessage.FIRST_NAME_NOT_EMPTY })
|
@IsNotEmpty({ message: AuthMessage.FIRST_NAME_NOT_EMPTY })
|
||||||
@IsString({ message: AuthMessage.FIRST_NAME_NOT_EMPTY })
|
@IsString({ message: AuthMessage.FIRST_NAME_NOT_EMPTY })
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { RoleEnum } from "../enums/role.enum";
|
|||||||
import { PermissionsRepository } from "../repositories/permissions.repository";
|
import { PermissionsRepository } from "../repositories/permissions.repository";
|
||||||
import { RoleRepository } from "../repositories/roles.repository";
|
import { RoleRepository } from "../repositories/roles.repository";
|
||||||
import { UserRepository } from "../repositories/users.repository";
|
import { UserRepository } from "../repositories/users.repository";
|
||||||
|
import { getPermissionEntitiesFromRoles } from "../utils/role-permissions.util";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AdminsService {
|
export class AdminsService {
|
||||||
@@ -43,22 +44,22 @@ export class AdminsService {
|
|||||||
const existPhone = await queryRunner.manager.findOneBy(this.userRepository.target, { phone: createDto.phone });
|
const existPhone = await queryRunner.manager.findOneBy(this.userRepository.target, { phone: createDto.phone });
|
||||||
if (existPhone) throw new BadRequestException(UserMessage.PHONE_EXIST);
|
if (existPhone) throw new BadRequestException(UserMessage.PHONE_EXIST);
|
||||||
|
|
||||||
const role = await queryRunner.manager.findOne(this.rolesRepository.target, {
|
const roles = await queryRunner.manager.find(this.rolesRepository.target, {
|
||||||
where: { id: createDto.roleId },
|
where: { id: In(createDto.roleIds), isAdmin: true },
|
||||||
relations: { permissions: true },
|
relations: { permissions: true },
|
||||||
});
|
});
|
||||||
if (!role) throw new BadRequestException(AdsMessage.ROLE_NOT_FOUND);
|
if (roles.length !== createDto.roleIds.length) throw new BadRequestException(AdsMessage.ROLE_NOT_FOUND);
|
||||||
|
|
||||||
if (createDto.password !== createDto.repeatPassword) throw new BadRequestException(AdminMessage.PASSWORD_NOT_MATCH);
|
if (createDto.password !== createDto.repeatPassword) throw new BadRequestException(AdminMessage.PASSWORD_NOT_MATCH);
|
||||||
|
|
||||||
const hashedPassword = await this.passwordService.hashPassword(createDto.password);
|
const hashedPassword = await this.passwordService.hashPassword(createDto.password);
|
||||||
const userName = slugify(`${createDto.firstName} ${Date.now().toString().slice(-5)}`, { lower: true, trim: true });
|
const userName = slugify(`${createDto.firstName} ${Date.now().toString().slice(-5)}`, { lower: true, trim: true });
|
||||||
|
|
||||||
await queryRunner.manager.save(this.rolesRepository.target, role);
|
const { roleIds: _roleIds, repeatPassword: _repeatPassword, ...adminData } = createDto;
|
||||||
|
|
||||||
const adminUser = queryRunner.manager.create(this.userRepository.target, {
|
const adminUser = queryRunner.manager.create(this.userRepository.target, {
|
||||||
...createDto,
|
...adminData,
|
||||||
roles: [role],
|
roles,
|
||||||
password: hashedPassword,
|
password: hashedPassword,
|
||||||
userName,
|
userName,
|
||||||
});
|
});
|
||||||
@@ -75,7 +76,7 @@ export class AdminsService {
|
|||||||
userAgent: userIpAndHeaders.headers["user-agent"],
|
userAgent: userIpAndHeaders.headers["user-agent"],
|
||||||
actionDescription: `Admin created new admin: ${createDto.email}`,
|
actionDescription: `Admin created new admin: ${createDto.email}`,
|
||||||
metadata: {
|
metadata: {
|
||||||
roleId: createDto.roleId,
|
roleIds: createDto.roleIds,
|
||||||
createdBy: "admin",
|
createdBy: "admin",
|
||||||
email: createDto.email,
|
email: createDto.email,
|
||||||
phone: createDto.phone,
|
phone: createDto.phone,
|
||||||
@@ -118,16 +119,14 @@ export class AdminsService {
|
|||||||
if (existPhone) throw new BadRequestException(UserMessage.PHONE_EXIST);
|
if (existPhone) throw new BadRequestException(UserMessage.PHONE_EXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateDto.roleId) {
|
if (updateDto.roleIds?.length) {
|
||||||
const role = await queryRunner.manager.findOne(this.rolesRepository.target, {
|
const roles = await queryRunner.manager.find(this.rolesRepository.target, {
|
||||||
where: { id: updateDto.roleId },
|
where: { id: In(updateDto.roleIds), isAdmin: true },
|
||||||
relations: { permissions: true },
|
relations: { permissions: true },
|
||||||
});
|
});
|
||||||
if (!role) throw new BadRequestException(AdsMessage.ROLE_NOT_FOUND);
|
if (roles.length !== updateDto.roleIds.length) throw new BadRequestException(AdsMessage.ROLE_NOT_FOUND);
|
||||||
|
|
||||||
await queryRunner.manager.save(this.rolesRepository.target, role);
|
admin.roles = roles;
|
||||||
|
|
||||||
admin.roles = [role];
|
|
||||||
|
|
||||||
await queryRunner.manager.save(this.userRepository.target, admin);
|
await queryRunner.manager.save(this.userRepository.target, admin);
|
||||||
}
|
}
|
||||||
@@ -138,7 +137,8 @@ export class AdminsService {
|
|||||||
admin.password = await this.passwordService.hashPassword(updateDto.password);
|
admin.password = await this.passwordService.hashPassword(updateDto.password);
|
||||||
}
|
}
|
||||||
|
|
||||||
await queryRunner.manager.save(this.userRepository.target, { ...admin, ...updateDto, password: admin.password });
|
const { roleIds: _roleIds, repeatPassword: _repeatPassword, ...updateData } = updateDto;
|
||||||
|
await queryRunner.manager.save(this.userRepository.target, { ...admin, ...updateData, password: admin.password });
|
||||||
|
|
||||||
await queryRunner.commitTransaction();
|
await queryRunner.commitTransaction();
|
||||||
await this.accessLogService.logUpdate("User", admin.id, UserType.ADMIN, {
|
await this.accessLogService.logUpdate("User", admin.id, UserType.ADMIN, {
|
||||||
@@ -150,7 +150,7 @@ export class AdminsService {
|
|||||||
userType: UserType.ADMIN,
|
userType: UserType.ADMIN,
|
||||||
actionDescription: `Admin updated admin: ${admin.email}`,
|
actionDescription: `Admin updated admin: ${admin.email}`,
|
||||||
metadata: {
|
metadata: {
|
||||||
roleId: updateDto.roleId,
|
roleIds: updateDto.roleIds,
|
||||||
},
|
},
|
||||||
oldValues: JSON.stringify({ ...admin }),
|
oldValues: JSON.stringify({ ...admin }),
|
||||||
newValues: JSON.stringify({ ...updateDto }),
|
newValues: JSON.stringify({ ...updateDto }),
|
||||||
@@ -169,7 +169,7 @@ export class AdminsService {
|
|||||||
/************************************************************ */
|
/************************************************************ */
|
||||||
|
|
||||||
async deleteAdmin(id: string, userIpAndHeaders: IUserIpAndHeaders) {
|
async deleteAdmin(id: string, userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
const admin = await this.userRepository.findOne({ where: { id, roles: { isAdmin: true } } });
|
const admin = await this.userRepository.findOne({ where: { id, roles: { isAdmin: true } }, relations: { roles: true } });
|
||||||
if (!admin) throw new BadRequestException(AdminMessage.ADMIN_NOT_FOUND);
|
if (!admin) throw new BadRequestException(AdminMessage.ADMIN_NOT_FOUND);
|
||||||
|
|
||||||
await this.userRepository.softDelete(id);
|
await this.userRepository.softDelete(id);
|
||||||
@@ -182,7 +182,7 @@ export class AdminsService {
|
|||||||
userAgent: userIpAndHeaders.headers["user-agent"],
|
userAgent: userIpAndHeaders.headers["user-agent"],
|
||||||
actionDescription: `Admin deleted admin: ${admin.email}`,
|
actionDescription: `Admin deleted admin: ${admin.email}`,
|
||||||
metadata: {
|
metadata: {
|
||||||
roleId: admin.roles[0].id,
|
roleIds: admin.roles.map((role) => role.id),
|
||||||
email: admin.email,
|
email: admin.email,
|
||||||
phone: admin.phone,
|
phone: admin.phone,
|
||||||
},
|
},
|
||||||
@@ -303,7 +303,7 @@ export class AdminsService {
|
|||||||
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
permissions: user.roles[0].permissions,
|
permissions: getPermissionEntitiesFromRoles(user.roles),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/************************************************************ */
|
/************************************************************ */
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "../../../.."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../../../../../danak-admin"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { PermissionEnum } from "../enums/permission.enum";
|
||||||
|
import { Role } from "../entities/role.entity";
|
||||||
|
import { Permission } from "../entities/permission.entity";
|
||||||
|
|
||||||
|
export function getPermissionsFromRoles(roles: Role[]): PermissionEnum[] {
|
||||||
|
return [...new Set(roles.flatMap((role) => (role?.permissions?.length ? role.permissions.map((permission) => permission.name) : [])))];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPermissionEntitiesFromRoles(roles: Role[]): Permission[] {
|
||||||
|
const permissionsById = new Map<string, Permission>();
|
||||||
|
|
||||||
|
for (const role of roles) {
|
||||||
|
for (const permission of role?.permissions ?? []) {
|
||||||
|
permissionsById.set(permission.id, permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...permissionsById.values()];
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user