mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-11-26 09:54:55 +00:00
Merge pull request #32 from SyncrowIOT/SP-196-be-handle-super-admin-migration
Sp 196 be handle super admin migration
This commit is contained in:
@ -1,2 +1,3 @@
|
|||||||
import emailConfig from './email.config';
|
import emailConfig from './email.config';
|
||||||
export default [emailConfig];
|
import superAdminConfig from './super.admin.config';
|
||||||
|
export default [emailConfig, superAdminConfig];
|
||||||
|
|||||||
9
libs/common/src/config/super.admin.config.ts
Normal file
9
libs/common/src/config/super.admin.config.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { registerAs } from '@nestjs/config';
|
||||||
|
|
||||||
|
export default registerAs(
|
||||||
|
'super-admin',
|
||||||
|
(): Record<string, any> => ({
|
||||||
|
SUPER_ADMIN_EMAIL: process.env.SUPER_ADMIN_EMAIL,
|
||||||
|
SUPER_ADMIN_PASSWORD: process.env.SUPER_ADMIN_PASSWORD,
|
||||||
|
}),
|
||||||
|
);
|
||||||
@ -1,4 +1,5 @@
|
|||||||
export enum RoleType {
|
export enum RoleType {
|
||||||
USER = 'USER',
|
SUPER_ADMIN = 'SUPER_ADMIN',
|
||||||
ADMIN = 'ADMIN',
|
ADMIN = 'ADMIN',
|
||||||
|
USER = 'USER',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,30 @@
|
|||||||
import { Global, Module } from '@nestjs/common';
|
import { Global, Module } from '@nestjs/common';
|
||||||
import { HelperHashService } from './services';
|
import { HelperHashService } from './services';
|
||||||
|
import { UserRepository } from '../modules/user/repositories';
|
||||||
|
import { UserRepositoryModule } from '../modules/user/user.repository.module';
|
||||||
|
import { UserRoleRepository } from '../modules/user-role/repositories';
|
||||||
|
import { UserRoleRepositoryModule } from '../modules/user-role/user.role.repository.module';
|
||||||
|
import { RoleTypeRepository } from '../modules/role-type/repositories';
|
||||||
|
import { RoleTypeRepositoryModule } from '../modules/role-type/role.type.repository.module';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { SuperAdminService } from './services/super.admin.sarvice';
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
providers: [HelperHashService],
|
providers: [
|
||||||
exports: [HelperHashService],
|
HelperHashService,
|
||||||
|
SuperAdminService,
|
||||||
|
UserRepository,
|
||||||
|
UserRoleRepository,
|
||||||
|
RoleTypeRepository,
|
||||||
|
],
|
||||||
|
exports: [HelperHashService, SuperAdminService],
|
||||||
controllers: [],
|
controllers: [],
|
||||||
imports: [],
|
imports: [
|
||||||
|
ConfigModule.forRoot(),
|
||||||
|
UserRepositoryModule,
|
||||||
|
UserRoleRepositoryModule,
|
||||||
|
RoleTypeRepositoryModule,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class HelperModule {}
|
export class HelperModule {}
|
||||||
|
|||||||
72
libs/common/src/helper/services/super.admin.sarvice.ts
Normal file
72
libs/common/src/helper/services/super.admin.sarvice.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { HelperHashService } from './helper.hash.service';
|
||||||
|
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-role/repositories';
|
||||||
|
import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class SuperAdminService {
|
||||||
|
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 } },
|
||||||
|
relations: ['roleType'],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (superAdminData.length <= 0) {
|
||||||
|
// Create the super admin user if not found
|
||||||
|
console.log('Creating super admin user...');
|
||||||
|
|
||||||
|
await this.createSuperAdmin();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error while checking super admin:', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async getRoleUuidByRoleType(roleType: string) {
|
||||||
|
const role = await this.roleTypeRepository.findOne({
|
||||||
|
where: { type: roleType },
|
||||||
|
});
|
||||||
|
|
||||||
|
return role.uuid;
|
||||||
|
}
|
||||||
|
private async createSuperAdmin(): Promise<void> {
|
||||||
|
const salt = this.helperHashService.randomSalt(10); // Hash the password using bcrypt
|
||||||
|
const hashedPassword = await this.helperHashService.bcrypt(
|
||||||
|
this.configService.get<string>('super-admin.SUPER_ADMIN_PASSWORD'),
|
||||||
|
salt,
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
const user = 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) {
|
||||||
|
console.error('Error while creating super admin:', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,11 @@
|
|||||||
import { Column, Entity, OneToMany } from 'typeorm';
|
import { Column, Entity, OneToMany, Unique } from 'typeorm';
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
import { RoleTypeDto } from '../dtos/role.type.dto';
|
import { RoleTypeDto } from '../dtos/role.type.dto';
|
||||||
import { RoleType } from '@app/common/constants/role.type.enum';
|
import { RoleType } from '@app/common/constants/role.type.enum';
|
||||||
import { UserRoleEntity } from '../../user-role/entities';
|
import { UserRoleEntity } from '../../user-role/entities';
|
||||||
|
|
||||||
@Entity({ name: 'role-type' })
|
@Entity({ name: 'role-type' })
|
||||||
|
@Unique(['type'])
|
||||||
export class RoleTypeEntity extends AbstractEntity<RoleTypeDto> {
|
export class RoleTypeEntity extends AbstractEntity<RoleTypeDto> {
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { Entity, ManyToOne } from 'typeorm';
|
import { Entity, ManyToOne, Unique } from 'typeorm';
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
import { UserRoleDto } from '../dtos';
|
import { UserRoleDto } from '../dtos';
|
||||||
import { UserEntity } from '../../user/entities';
|
import { UserEntity } from '../../user/entities';
|
||||||
import { RoleTypeEntity } from '../../role-type/entities';
|
import { RoleTypeEntity } from '../../role-type/entities';
|
||||||
|
|
||||||
@Entity({ name: 'user-role' })
|
@Entity({ name: 'user-role' })
|
||||||
|
@Unique(['user', 'roleType'])
|
||||||
export class UserRoleEntity extends AbstractEntity<UserRoleDto> {
|
export class UserRoleEntity extends AbstractEntity<UserRoleDto> {
|
||||||
@ManyToOne(() => UserEntity, (user) => user.role, {
|
@ManyToOne(() => UserEntity, (user) => user.role, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import { ResponseMessage } from '../../../libs/common/src/response/response.deco
|
|||||||
import { UserLoginDto } from '../dtos/user-login.dto';
|
import { UserLoginDto } from '../dtos/user-login.dto';
|
||||||
import { ForgetPasswordDto, UserOtpDto, VerifyOtpDto } from '../dtos';
|
import { ForgetPasswordDto, UserOtpDto, VerifyOtpDto } from '../dtos';
|
||||||
import { RefreshTokenGuard } from '@app/common/guards/jwt-refresh.auth.guard';
|
import { RefreshTokenGuard } from '@app/common/guards/jwt-refresh.auth.guard';
|
||||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.guard';
|
||||||
|
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: '1',
|
||||||
@ -52,7 +52,7 @@ export class UserAuthController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard)
|
@UseGuards(SuperAdminRoleGuard)
|
||||||
@Delete('user/delete/:id')
|
@Delete('user/delete/:id')
|
||||||
async userDelete(@Param('id') id: string) {
|
async userDelete(@Param('id') id: string) {
|
||||||
await this.userAuthService.deleteUser(id);
|
await this.userAuthService.deleteUser(id);
|
||||||
@ -98,7 +98,7 @@ export class UserAuthController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard)
|
@UseGuards(SuperAdminRoleGuard)
|
||||||
@Get('user/list')
|
@Get('user/list')
|
||||||
async userList() {
|
async userList() {
|
||||||
const userList = await this.userAuthService.userList();
|
const userList = await this.userAuthService.userList();
|
||||||
|
|||||||
@ -4,10 +4,13 @@ import { AuthGuard } from '@nestjs/passport';
|
|||||||
|
|
||||||
export class AdminRoleGuard extends AuthGuard('jwt') {
|
export class AdminRoleGuard extends AuthGuard('jwt') {
|
||||||
handleRequest(err, user) {
|
handleRequest(err, user) {
|
||||||
const isAdmin = user.roles.some((role) => role.type === RoleType.ADMIN);
|
|
||||||
if (err || !user) {
|
if (err || !user) {
|
||||||
throw err || new UnauthorizedException();
|
throw err || new UnauthorizedException();
|
||||||
} else {
|
} else {
|
||||||
|
const isAdmin = user.roles.some(
|
||||||
|
(role) =>
|
||||||
|
role.type === RoleType.SUPER_ADMIN || role.type === RoleType.ADMIN,
|
||||||
|
);
|
||||||
if (!isAdmin) {
|
if (!isAdmin) {
|
||||||
throw new BadRequestException('Only admin role can access this route');
|
throw new BadRequestException('Only admin role can access this route');
|
||||||
}
|
}
|
||||||
|
|||||||
21
src/guards/super.admin.role.guard.ts
Normal file
21
src/guards/super.admin.role.guard.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { RoleType } from '@app/common/constants/role.type.enum';
|
||||||
|
import { BadRequestException, UnauthorizedException } from '@nestjs/common';
|
||||||
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
|
|
||||||
|
export class SuperAdminRoleGuard extends AuthGuard('jwt') {
|
||||||
|
handleRequest(err, user) {
|
||||||
|
if (err || !user) {
|
||||||
|
throw err || new UnauthorizedException();
|
||||||
|
} else {
|
||||||
|
const isSuperAdmin = user.roles.some(
|
||||||
|
(role) => role.type === RoleType.SUPER_ADMIN,
|
||||||
|
);
|
||||||
|
if (!isSuperAdmin) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
'Only super admin role can access this route',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,12 +4,15 @@ import { AuthGuard } from '@nestjs/passport';
|
|||||||
|
|
||||||
export class UserRoleGuard extends AuthGuard('jwt') {
|
export class UserRoleGuard extends AuthGuard('jwt') {
|
||||||
handleRequest(err, user) {
|
handleRequest(err, user) {
|
||||||
const isUserOrAdmin = user.roles.some(
|
|
||||||
(role) => role.type === RoleType.ADMIN || role.type === RoleType.USER,
|
|
||||||
);
|
|
||||||
if (err || !user) {
|
if (err || !user) {
|
||||||
throw err || new UnauthorizedException();
|
throw err || new UnauthorizedException();
|
||||||
} else {
|
} else {
|
||||||
|
const isUserOrAdmin = user.roles.some(
|
||||||
|
(role) =>
|
||||||
|
role.type === RoleType.SUPER_ADMIN ||
|
||||||
|
role.type === RoleType.ADMIN ||
|
||||||
|
role.type === RoleType.USER,
|
||||||
|
);
|
||||||
if (!isUserOrAdmin) {
|
if (!isUserOrAdmin) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
'Only admin or user role can access this route',
|
'Only admin or user role can access this route',
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import rateLimit from 'express-rate-limit';
|
|||||||
import helmet from 'helmet';
|
import helmet from 'helmet';
|
||||||
import { setupSwaggerAuthentication } from '../libs/common/src/util/user-auth.swagger.utils';
|
import { setupSwaggerAuthentication } from '../libs/common/src/util/user-auth.swagger.utils';
|
||||||
import { ValidationPipe } from '@nestjs/common';
|
import { ValidationPipe } from '@nestjs/common';
|
||||||
|
import { SuperAdminService } from '@app/common/helper/services/super.admin.sarvice';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AuthModule);
|
const app = await NestFactory.create(AuthModule);
|
||||||
@ -33,6 +34,9 @@ async function bootstrap() {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
// Create super admin user
|
||||||
|
const superAdminService = app.get(SuperAdminService);
|
||||||
|
await superAdminService.createSuperAdminIfNotFound();
|
||||||
|
|
||||||
await app.listen(process.env.PORT || 4000);
|
await app.listen(process.env.PORT || 4000);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {
|
|||||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||||
import { RoleService } from '../services/role.service';
|
import { RoleService } from '../services/role.service';
|
||||||
import { UserRoleEditDto } from '../dtos';
|
import { UserRoleEditDto } from '../dtos';
|
||||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.guard';
|
||||||
|
|
||||||
@ApiTags('Role Module')
|
@ApiTags('Role Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
@ -21,7 +21,7 @@ import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
|||||||
export class RoleController {
|
export class RoleController {
|
||||||
constructor(private readonly roleService: RoleService) {}
|
constructor(private readonly roleService: RoleService) {}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard)
|
@UseGuards(SuperAdminRoleGuard)
|
||||||
@Get('types')
|
@Get('types')
|
||||||
async fetchRoleTypes() {
|
async fetchRoleTypes() {
|
||||||
try {
|
try {
|
||||||
@ -36,7 +36,7 @@ export class RoleController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard)
|
@UseGuards(SuperAdminRoleGuard)
|
||||||
@Put('edit/user/:userUuid')
|
@Put('edit/user/:userUuid')
|
||||||
async editUserRoleType(
|
async editUserRoleType(
|
||||||
@Param('userUuid') userUuid: string,
|
@Param('userUuid') userUuid: string,
|
||||||
|
|||||||
@ -1,13 +1,16 @@
|
|||||||
import { RoleType } from '@app/common/constants/role.type.enum';
|
import { RoleType } from '@app/common/constants/role.type.enum';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { IsEnum } from 'class-validator';
|
import { IsEnum, IsIn } from 'class-validator';
|
||||||
|
|
||||||
export class UserRoleEditDto {
|
export class UserRoleEditDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'role type',
|
description: 'Role type (USER or ADMIN)',
|
||||||
enum: RoleType,
|
enum: [RoleType.USER, RoleType.ADMIN],
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
@IsEnum(RoleType)
|
@IsEnum(RoleType)
|
||||||
|
@IsIn([RoleType.USER, RoleType.ADMIN], {
|
||||||
|
message: 'roleType must be one of the following values: USER, ADMIN',
|
||||||
|
})
|
||||||
roleType: RoleType;
|
roleType: RoleType;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user