Refactor user role handling to use single role object

This commit is contained in:
faris Aljohari
2024-12-16 00:16:24 -06:00
parent 37d016ea43
commit 852299a273
13 changed files with 43 additions and 96 deletions

View File

@ -4,5 +4,5 @@ export class AuthInterface {
uuid: string;
sessionId: string;
id: number;
roles?: string[];
role?: object;
}

View File

@ -39,7 +39,7 @@ export class AuthService {
}
: undefined,
},
relations: ['roles.roleType'],
relations: ['roleType'],
});
if (!user.isUserVerified) {
@ -85,9 +85,8 @@ export class AuthService {
email: user.email,
userId: user.userId,
uuid: user.uuid,
type: user.type,
sessionId: user.sessionId,
roles: user?.roles,
role: user?.role,
googleCode: user.googleCode,
};
if (payload.googleCode) {

View File

@ -31,7 +31,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
userUuid: payload.uuid,
uuid: payload.uuid,
sessionId: payload.sessionId,
roles: payload?.roles,
role: payload?.role,
};
} else {
throw new BadRequestException('Unauthorized');

View File

@ -34,7 +34,7 @@ export class RefreshTokenStrategy extends PassportStrategy(
userUuid: payload.uuid,
uuid: payload.uuid,
sessionId: payload.sessionId,
roles: payload?.roles,
role: payload?.role,
};
} else {
throw new BadRequestException('Unauthorized');

View File

@ -1,4 +1,6 @@
export enum RoleType {
SUPER_ADMIN = 'SUPER_ADMIN',
ADMIN = 'ADMIN',
SPACE_OWNER = 'SPACE_OWNER',
SPACE_MEMBER = 'SPACE_MEMBER',
}

View File

@ -19,7 +19,12 @@ export class RoleTypeSeeder {
if (!roleTypeNames.includes(RoleType.ADMIN)) {
missingRoleTypes.push(RoleType.ADMIN);
}
if (!roleTypeNames.includes(RoleType.SPACE_OWNER)) {
missingRoleTypes.push(RoleType.SPACE_OWNER);
}
if (!roleTypeNames.includes(RoleType.SPACE_MEMBER)) {
missingRoleTypes.push(RoleType.SPACE_MEMBER);
}
if (missingRoleTypes.length > 0) {
await this.addRoleTypeData(missingRoleTypes);
}

View File

@ -1,7 +1,6 @@
import { Injectable } from '@nestjs/common';
import { UserRepository } from '@app/common/modules/user/repositories';
import { RoleType } from '@app/common/constants/role.type.enum';
import { UserRoleRepository } from '@app/common/modules/user/repositories';
import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
import { ConfigService } from '@nestjs/config';
import { HelperHashService } from '../../helper/services';
@ -11,19 +10,23 @@ export class SuperAdminSeeder {
constructor(
private readonly configService: ConfigService,
private readonly userRepository: UserRepository,
private readonly userRoleRepository: UserRoleRepository,
private readonly roleTypeRepository: RoleTypeRepository,
private readonly helperHashService: HelperHashService,
) {}
async createSuperAdminIfNotFound(): Promise<void> {
try {
const superAdminData = await this.userRoleRepository.find({
where: { roleType: { type: RoleType.SUPER_ADMIN } },
const superAdmin = await this.userRepository.findOne({
where: {
roleType: { type: RoleType.SUPER_ADMIN },
email: this.configService.get<string>(
'super-admin.SUPER_ADMIN_EMAIL',
),
},
relations: ['roleType'],
});
if (superAdminData.length <= 0) {
if (!superAdmin) {
// Create the super admin user if not found
console.log('Creating super admin user...');
@ -48,20 +51,16 @@ export class SuperAdminSeeder {
salt,
);
try {
const user = await this.userRepository.save({
const defaultUserRoleUuid = await this.getRoleUuidByRoleType(
RoleType.SUPER_ADMIN,
);
await this.userRepository.save({
email: this.configService.get<string>('super-admin.SUPER_ADMIN_EMAIL'),
password: hashedPassword,
firstName: 'Super',
lastName: 'Admin',
isUserVerified: true,
isActive: true,
});
const defaultUserRoleUuid = await this.getRoleUuidByRoleType(
RoleType.SUPER_ADMIN,
);
await this.userRoleRepository.save({
user: { uuid: user.uuid },
roleType: { uuid: defaultUserRoleUuid },
});
} catch (err) {

View File

@ -7,11 +7,12 @@ export class AdminRoleGuard extends AuthGuard('jwt') {
if (err || !user) {
throw err || new UnauthorizedException();
} else {
const isAdmin = user.roles.some(
(role) =>
role.type === RoleType.SUPER_ADMIN || role.type === RoleType.ADMIN,
);
if (!isAdmin) {
if (
!(
user.role.type === RoleType.ADMIN ||
user.role.type === RoleType.SUPER_ADMIN
)
) {
throw new BadRequestException('Only admin role can access this route');
}
}

View File

@ -20,10 +20,10 @@ export class CommunityPermissionGuard implements CanActivate {
if (
user &&
user.roles &&
user.roles.some(
(role) =>
role.type === RoleType.ADMIN || role.type === RoleType.SUPER_ADMIN,
user.role &&
!(
user.role.type === RoleType.ADMIN ||
user.role.type === RoleType.SUPER_ADMIN
)
) {
return true;

View File

@ -7,10 +7,7 @@ export class SuperAdminRoleGuard extends AuthGuard('jwt') {
if (err || !user) {
throw err || new UnauthorizedException();
} else {
const isSuperAdmin = user.roles.some(
(role) => role.type === RoleType.SUPER_ADMIN,
);
if (!isSuperAdmin) {
if (!(user.role.type === RoleType.SUPER_ADMIN)) {
throw new BadRequestException(
'Only super admin role can access this route',
);

View File

@ -36,19 +36,4 @@ export class RoleController {
data: roleTypes,
};
}
@ApiBearerAuth()
@UseGuards(SuperAdminRoleGuard)
@Post()
@ApiOperation({
summary: ControllerRoute.ROLE.ACTIONS.ADD_USER_ROLE_SUMMARY,
description: ControllerRoute.ROLE.ACTIONS.ADD_USER_ROLE_DESCRIPTION,
})
async addUserRoleType(@Body() addUserRoleDto: AddUserRoleDto) {
await this.roleService.addUserRoleType(addUserRoleDto);
return {
statusCode: HttpStatus.OK,
message: 'User Role Added Successfully',
};
}
}

View File

@ -7,7 +7,6 @@ import { RoleController } from './controllers/role.controller';
import { DeviceUserPermissionRepository } from '@app/common/modules/device/repositories';
import { PermissionTypeRepository } from '@app/common/modules/permission/repositories';
import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
import { UserRoleRepository } from '@app/common/modules/user/repositories';
@Module({
imports: [ConfigModule, DeviceRepositoryModule],
@ -18,7 +17,6 @@ import { UserRoleRepository } from '@app/common/modules/user/repositories';
DeviceRepository,
RoleService,
RoleTypeRepository,
UserRoleRepository,
],
exports: [RoleService],
})

View File

@ -1,55 +1,16 @@
import { Injectable } from '@nestjs/common';
import { RoleTypeRepository } from './../../../libs/common/src/modules/role-type/repositories/role.type.repository';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { AddUserRoleDto } from '../dtos/role.add.dto';
import { UserRoleRepository } from '@app/common/modules/user/repositories';
import { QueryFailedError } from 'typeorm';
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
import { RoleType } from '@app/common/constants/role.type.enum';
@Injectable()
export class RoleService {
constructor(
private readonly roleTypeRepository: RoleTypeRepository,
private readonly userRoleRepository: UserRoleRepository,
) {}
async addUserRoleType(addUserRoleDto: AddUserRoleDto) {
try {
const roleType = await this.fetchRoleByType(addUserRoleDto.roleType);
if (roleType.uuid) {
return await this.userRoleRepository.save({
user: { uuid: addUserRoleDto.userUuid },
roleType: { uuid: roleType.uuid },
});
}
} catch (error) {
if (
error instanceof QueryFailedError &&
error.driverError.code === CommonErrorCodes.DUPLICATE_ENTITY
) {
// Postgres unique constraint violation error code
throw new HttpException(
'This role already exists for this user',
HttpStatus.CONFLICT,
);
}
throw new HttpException(
error.message || 'Internal Server Error',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
constructor(private readonly roleTypeRepository: RoleTypeRepository) {}
async fetchRoleTypes() {
const roleTypes = await this.roleTypeRepository.find();
return roleTypes;
}
private async fetchRoleByType(roleType: string) {
return await this.roleTypeRepository.findOne({
where: {
type: roleType,
},
});
const roles = roleTypes.filter(
(roleType) => roleType.type !== RoleType.SUPER_ADMIN,
);
return roles;
}
}