diff --git a/libs/common/src/constants/permissions-mapping.ts b/libs/common/src/constants/permissions-mapping.ts new file mode 100644 index 0000000..a9db542 --- /dev/null +++ b/libs/common/src/constants/permissions-mapping.ts @@ -0,0 +1,43 @@ +export const PermissionMapping = { + DEVICE_MANAGEMENT: { + DEVICE: ['SINGLE_CONTROL', 'VIEW', 'DELETE', 'UPDATE', 'BATCH_CONTROL'], + FIRMWARE: ['CONTROL', 'VIEW'], + }, + COMMUNITY_MANAGEMENT: { + COMMUNITY: ['VIEW', 'ADD', 'UPDATE', 'DELETE'], + }, + SPACE_MANAGEMENT: { + SPACE: [ + 'VIEW', + 'ADD', + 'UPDATE', + 'DELETE', + 'MODULE_ADD', + 'ASSIGN_USER_TO_SPACE', + 'DELETE_USER_FROM_SPACE', + ], + SUBSPACE: [ + 'VIEW', + 'ADD', + 'UPDATE', + 'DELETE', + 'ASSIGN_DEVICE_TO_SUBSPACE', + 'DELETE_DEVICE_FROM_SUBSPACE', + ], + }, + DEVICE_WIZARD: { + DEVICE_WIZARD: ['VIEW_DEVICE_WIZARD'], + SPACE_DEVICE: ['VIEW_DEVICE_IN_SPACE', 'ASSIGN_DEVICE_TO_SPACE'], + SUBSPACE_DEVICE: ['VIEW_DEVICE_IN_SUBSPACE', 'UPDATE_DEVICE_IN_SUBSPACE'], + }, + AUTOMATION_MANAGEMENT: { + AUTOMATION: ['VIEW', 'ADD', 'UPDATE', 'DELETE', 'CONTROL'], + SCENES: ['VIEW', 'ADD', 'UPDATE', 'DELETE', 'CONTROL'], + }, + VISITOR_PASSWORD_MANAGEMENT: { + VISITOR_PASSWORD: ['VIEW', 'ADD', 'UPDATE', 'DELETE'], + }, + USER_MANAGEMENT: { + USER: ['ADD'], + }, +}; diff --git a/libs/common/src/constants/role-permissions.ts b/libs/common/src/constants/role-permissions.ts new file mode 100644 index 0000000..ed61e5d --- /dev/null +++ b/libs/common/src/constants/role-permissions.ts @@ -0,0 +1,130 @@ +import { RoleType } from './role.type.enum'; + +export const RolePermissions = { + [RoleType.SUPER_ADMIN]: [ + 'DEVICE_SINGLE_CONTROL', + 'DEVICE_VIEW', + 'DEVICE_DELETE', + 'DEVICE_UPDATE', + 'DEVICE_BATCH_CONTROL', + 'COMMUNITY_VIEW', + 'COMMUNITY_ADD', + 'COMMUNITY_UPDATE', + 'COMMUNITY_DELETE', + 'FIRMWARE_CONTROL', + 'SPACE_VIEW', + 'SPACE_ADD', + 'SPACE_UPDATE', + 'SPACE_DELETE', + 'SPACE_MODULE_ADD', + 'ASSIGN_USER_TO_SPACE', + 'DELETE_USER_FROM_SPACE', + 'SUBSPACE_VIEW', + 'SUBSPACE_ADD', + 'SUBSPACE_UPDATE', + 'SUBSPACE_DELETE', + 'ASSIGN_DEVICE_TO_SUBSPACE', + 'DELETE_DEVICE_FROM_SUBSPACE', + 'VIEW_DEVICE_WIZARD', + 'VIEW_DEVICE_IN_SUBSPACE', + 'VIEW_DEVICE_IN_SPACE', + 'UPDATE_DEVICE_IN_SUBSPACE', + 'ASSIGN_DEVICE_TO_SPACE', + 'AUTOMATION_VIEW', + 'AUTOMATION_ADD', + 'AUTOMATION_UPDATE', + 'AUTOMATION_DELETE', + 'AUTOMATION_CONTROL', + 'SCENES_VIEW', + 'SCENES_ADD', + 'SCENES_UPDATE', + 'SCENES_DELETE', + 'SCENES_CONTROL', + 'VISITOR_PASSWORD_VIEW', + 'VISITOR_PASSWORD_ADD', + 'USER_ADD', + ], + [RoleType.ADMIN]: [ + 'DEVICE_SINGLE_CONTROL', + 'DEVICE_VIEW', + 'DEVICE_DELETE', + 'DEVICE_UPDATE', + 'DEVICE_BATCH_CONTROL', + 'COMMUNITY_VIEW', + 'COMMUNITY_ADD', + 'COMMUNITY_UPDATE', + 'COMMUNITY_DELETE', + 'FIRMWARE_CONTROL', + 'SPACE_VIEW', + 'SPACE_ADD', + 'SPACE_UPDATE', + 'SPACE_DELETE', + 'SPACE_MODULE_ADD', + 'ASSIGN_USER_TO_SPACE', + 'DELETE_USER_FROM_SPACE', + 'SUBSPACE_VIEW', + 'SUBSPACE_ADD', + 'SUBSPACE_UPDATE', + 'SUBSPACE_DELETE', + 'ASSIGN_DEVICE_TO_SUBSPACE', + 'DELETE_DEVICE_FROM_SUBSPACE', + 'VIEW_DEVICE_WIZARD', + 'VIEW_DEVICE_IN_SUBSPACE', + 'VIEW_DEVICE_IN_SPACE', + 'UPDATE_DEVICE_IN_SUBSPACE', + 'ASSIGN_DEVICE_TO_SPACE', + 'AUTOMATION_VIEW', + 'AUTOMATION_ADD', + 'AUTOMATION_UPDATE', + 'AUTOMATION_DELETE', + 'AUTOMATION_CONTROL', + 'SCENES_VIEW', + 'SCENES_ADD', + 'SCENES_UPDATE', + 'SCENES_DELETE', + 'SCENES_CONTROL', + 'VISITOR_PASSWORD_VIEW', + 'VISITOR_PASSWORD_ADD', + 'USER_ADD', + ], + [RoleType.SPACE_MEMBER]: [ + 'DEVICE_SINGLE_CONTROL', + 'DEVICE_VIEW', + 'SPACE_VIEW', + 'SUBSPACE_VIEW', + 'VIEW_DEVICE_WIZARD', + 'VIEW_DEVICE_IN_SUBSPACE', + 'VIEW_DEVICE_IN_SPACE', + 'AUTOMATION_VIEW', + 'AUTOMATION_CONTROL', + 'SCENES_VIEW', + 'SCENES_CONTROL', + 'VISITOR_PASSWORD_VIEW', + ], + [RoleType.SPACE_OWNER]: [ + 'DEVICE_SINGLE_CONTROL', + 'DEVICE_VIEW', + 'FIRMWARE_CONTROL', + 'FIRMWARE_VIEW', + 'SPACE_VIEW', + 'SPACE_MEMBER_ADD', + 'SUBSPACE_VIEW', + 'SUBSPACE_ADD', + 'SUBSPACE_UPDATE', + 'SUBSPACE_DELETE', + 'AUTOMATION_VIEW', + 'AUTOMATION_ADD', + 'AUTOMATION_UPDATE', + 'AUTOMATION_DELETE', + 'AUTOMATION_CONTROL', + 'SCENES_VIEW', + 'SCENES_ADD', + 'SCENES_UPDATE', + 'SCENES_DELETE', + 'SCENES_CONTROL', + 'VISITOR_PASSWORD_VIEW', + 'VISITOR_PASSWORD_ADD', + 'VISITOR_PASSWORD_UPDATE', + 'VISITOR_PASSWORD_DELETE', + ], +}; diff --git a/libs/common/src/database/database.module.ts b/libs/common/src/database/database.module.ts index 44fd854..eeabcd4 100644 --- a/libs/common/src/database/database.module.ts +++ b/libs/common/src/database/database.module.ts @@ -15,7 +15,6 @@ import { } from '../modules/space/entities'; import { UserSpaceEntity } from '../modules/user/entities'; import { DeviceUserPermissionEntity } from '../modules/device/entities'; -import { UserRoleEntity } from '../modules/user/entities'; import { RoleTypeEntity } from '../modules/role-type/entities'; import { UserNotificationEntity } from '../modules/user/entities'; import { DeviceNotificationEntity } from '../modules/device/entities'; @@ -34,6 +33,10 @@ import { SpaceProductModelEntity, SubspaceModelEntity, } from '../modules/space-model/entities'; +import { + InviteUserEntity, + InviteUserSpaceEntity, +} from '../modules/Invite-user/entities'; @Module({ imports: [ TypeOrmModule.forRootAsync({ @@ -63,7 +66,6 @@ import { SpaceProductEntity, UserSpaceEntity, DeviceUserPermissionEntity, - UserRoleEntity, RoleTypeEntity, UserNotificationEntity, DeviceNotificationEntity, @@ -78,6 +80,8 @@ import { SpaceProductModelEntity, SpaceProductItemModelEntity, SubspaceModelEntity, + InviteUserEntity, + InviteUserSpaceEntity, ], namingStrategy: new SnakeNamingStrategy(), synchronize: Boolean(JSON.parse(configService.get('DB_SYNC'))), diff --git a/libs/common/src/modules/project/entities/project.entity.ts b/libs/common/src/modules/project/entities/project.entity.ts index f7213a2..01fba17 100644 --- a/libs/common/src/modules/project/entities/project.entity.ts +++ b/libs/common/src/modules/project/entities/project.entity.ts @@ -3,6 +3,7 @@ import { AbstractEntity } from '../../abstract/entities/abstract.entity'; import { ProjectDto } from '../dtos'; import { CommunityEntity } from '../../community/entities'; import { SpaceModelEntity } from '../../space-model'; +import { UserEntity } from '../../user/entities'; @Entity({ name: 'project' }) @Unique(['name']) @@ -28,6 +29,9 @@ export class ProjectEntity extends AbstractEntity { @OneToMany(() => CommunityEntity, (community) => community.project) communities: CommunityEntity[]; + @OneToMany(() => UserEntity, (user) => user.project) + public users: UserEntity[]; + constructor(partial: Partial) { super(); Object.assign(this, partial); diff --git a/libs/common/src/modules/role-type/entities/role.type.entity.ts b/libs/common/src/modules/role-type/entities/role.type.entity.ts index 10f30bd..b7289a3 100644 --- a/libs/common/src/modules/role-type/entities/role.type.entity.ts +++ b/libs/common/src/modules/role-type/entities/role.type.entity.ts @@ -2,7 +2,8 @@ import { Column, Entity, OneToMany, Unique } from 'typeorm'; import { AbstractEntity } from '../../abstract/entities/abstract.entity'; import { RoleTypeDto } from '../dtos/role.type.dto'; import { RoleType } from '@app/common/constants/role.type.enum'; -import { UserRoleEntity } from '../../user/entities'; +import { UserEntity } from '../../user/entities'; +import { InviteUserEntity } from '../../Invite-user/entities'; @Entity({ name: 'role-type' }) @Unique(['type']) @@ -12,10 +13,14 @@ export class RoleTypeEntity extends AbstractEntity { enum: Object.values(RoleType), }) type: string; - @OneToMany(() => UserRoleEntity, (role) => role.roleType, { + @OneToMany(() => UserEntity, (inviteUser) => inviteUser.roleType, { nullable: true, }) - roles: UserRoleEntity[]; + users: UserEntity[]; + @OneToMany(() => InviteUserEntity, (inviteUser) => inviteUser.roleType, { + nullable: true, + }) + invitedUsers: InviteUserEntity[]; constructor(partial: Partial) { super(); Object.assign(this, partial); diff --git a/libs/common/src/modules/user/user.repository.module.ts b/libs/common/src/modules/user/user.repository.module.ts index 11cefe0..e7f7d3e 100644 --- a/libs/common/src/modules/user/user.repository.module.ts +++ b/libs/common/src/modules/user/user.repository.module.ts @@ -4,7 +4,6 @@ import { UserEntity, UserNotificationEntity, UserOtpEntity, - UserRoleEntity, UserSpaceEntity, } from './entities'; @@ -17,7 +16,6 @@ import { UserEntity, UserNotificationEntity, UserOtpEntity, - UserRoleEntity, UserSpaceEntity, ]), ], diff --git a/src/app.module.ts b/src/app.module.ts index ac06b84..3606c0a 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -7,7 +7,6 @@ import { GroupModule } from './group/group.module'; import { DeviceModule } from './device/device.module'; import { UserDevicePermissionModule } from './user-device-permission/user-device-permission.module'; import { CommunityModule } from './community/community.module'; -import { RoleModule } from './role/role.module'; import { SeederModule } from '@app/common/seed/seeder.module'; import { UserNotificationModule } from './user-notification/user-notification.module'; import { DeviceMessagesSubscriptionModule } from './device-messages/device-messages.module'; @@ -24,6 +23,8 @@ import { SpaceModule } from './space/space.module'; import { ProductModule } from './product'; import { ProjectModule } from './project'; import { SpaceModelModule } from './space-model'; +import { InviteUserModule } from './invite-user/invite-user.module'; +import { PermissionModule } from './permission/permission.module'; @Module({ imports: [ ConfigModule.forRoot({ @@ -31,7 +32,7 @@ import { SpaceModelModule } from './space-model'; }), AuthenticationModule, UserModule, - RoleModule, + InviteUserModule, CommunityModule, SpaceModule, @@ -51,6 +52,7 @@ import { SpaceModelModule } from './space-model'; ScheduleModule, ProductModule, ProjectModule, + PermissionModule, ], providers: [ { diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 66d335d..4af4688 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -6,10 +6,7 @@ import { UserAuthController } from './controllers'; import { UserAuthService } from './services'; import { UserRepository } from '@app/common/modules/user/repositories'; import { UserSessionRepository } from '@app/common/modules/session/repositories/session.repository'; -import { - UserRoleRepository, - UserOtpRepository, -} from '@app/common/modules/user/repositories'; +import { UserOtpRepository } from '@app/common/modules/user/repositories'; import { RoleTypeRepository } from '@app/common/modules/role-type/repositories'; @Module({ @@ -20,7 +17,6 @@ import { RoleTypeRepository } from '@app/common/modules/role-type/repositories'; UserRepository, UserSessionRepository, UserOtpRepository, - UserRoleRepository, RoleTypeRepository, ], exports: [UserAuthService], diff --git a/src/auth/services/user-auth.service.ts b/src/auth/services/user-auth.service.ts index 80be3c2..b9b3ed3 100644 --- a/src/auth/services/user-auth.service.ts +++ b/src/auth/services/user-auth.service.ts @@ -134,13 +134,12 @@ export class UserAuthService { isLoggedOut: false, }), ]); + const res = await this.authService.login({ email: user.email, userId: user.uuid, uuid: user.uuid, - roles: user?.roles?.map((role) => { - return { uuid: role.uuid, type: role.roleType.type }; - }), + role: user.roleType, sessionId: session[1].uuid, }); return res; diff --git a/src/decorators/permissions.decorator.ts b/src/decorators/permissions.decorator.ts new file mode 100644 index 0000000..ad21bf4 --- /dev/null +++ b/src/decorators/permissions.decorator.ts @@ -0,0 +1,4 @@ +import { SetMetadata } from '@nestjs/common'; + +export const Permissions = (...permissions: string[]) => + SetMetadata('permissions', permissions); diff --git a/src/guards/permissions.guard.ts b/src/guards/permissions.guard.ts new file mode 100644 index 0000000..4075943 --- /dev/null +++ b/src/guards/permissions.guard.ts @@ -0,0 +1,44 @@ +import { Injectable, ExecutionContext } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; +import { Reflector } from '@nestjs/core'; +import { RolePermissions } from '@app/common/constants/role-permissions'; +import { RoleType } from '@app/common/constants/role.type.enum'; + +@Injectable() +export class PermissionsGuard extends AuthGuard('jwt') { + constructor(private reflector: Reflector) { + super(); + } + + async canActivate(context: ExecutionContext): Promise { + // First, run the AuthGuard logic to validate the JWT + const isAuthenticated = await super.canActivate(context); + if (!isAuthenticated) { + return false; + } + + // Authorization logic + const requiredPermissions = this.reflector.get( + 'permissions', + context.getHandler(), + ); + + if (!requiredPermissions) { + return true; // Allow if no permissions are specified + } + + const request = context.switchToHttp().getRequest(); + const user = request.user; // User is now available after AuthGuard + console.log('user', user); + + const userRole = user?.role.type as RoleType; + if (!userRole || !RolePermissions[userRole]) { + return false; // Deny if role or permissions are missing + } + + const userPermissions = RolePermissions[userRole]; + + // Check if the user has the required permissions + return requiredPermissions.every((perm) => userPermissions.includes(perm)); + } +} diff --git a/src/invite-user/controllers/index.ts b/src/invite-user/controllers/index.ts new file mode 100644 index 0000000..045b43b --- /dev/null +++ b/src/invite-user/controllers/index.ts @@ -0,0 +1 @@ +export * from './invite-user.controller'; diff --git a/src/invite-user/controllers/invite-user.controller.ts b/src/invite-user/controllers/invite-user.controller.ts new file mode 100644 index 0000000..7c25450 --- /dev/null +++ b/src/invite-user/controllers/invite-user.controller.ts @@ -0,0 +1,34 @@ +import { InviteUserService } from '../services/invite-user.service'; +import { Body, Controller, Post, UseGuards } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; +import { AddUserInvitationDto } from '../dtos/add.invite-user.dto'; +import { ControllerRoute } from '@app/common/constants/controller-route'; +import { BaseResponseDto } from '@app/common/dto/base.response.dto'; +import { PermissionsGuard } from 'src/guards/permissions.guard'; +import { Permissions } from 'src/decorators/permissions.decorator'; + +@ApiTags('Invite User Module') +@Controller({ + version: '1', + path: ControllerRoute.INVITE_USER.ROUTE, +}) +export class InviteUserController { + constructor(private readonly inviteUserService: InviteUserService) {} + + @ApiBearerAuth() + @UseGuards(PermissionsGuard) + @Permissions('USER_ADD') + @Post() + @ApiOperation({ + summary: ControllerRoute.INVITE_USER.ACTIONS.CREATE_USER_INVITATION_SUMMARY, + description: + ControllerRoute.INVITE_USER.ACTIONS.CREATE_USER_INVITATION_DESCRIPTION, + }) + async createUserInvitation( + @Body() addUserInvitationDto: AddUserInvitationDto, + ): Promise { + return await this.inviteUserService.createUserInvitation( + addUserInvitationDto, + ); + } +} diff --git a/src/invite-user/dtos/add.invite-user.dto.ts b/src/invite-user/dtos/add.invite-user.dto.ts new file mode 100644 index 0000000..e47758d --- /dev/null +++ b/src/invite-user/dtos/add.invite-user.dto.ts @@ -0,0 +1,75 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { + ArrayMinSize, + IsArray, + IsNotEmpty, + IsOptional, + IsString, +} from 'class-validator'; + +export class AddUserInvitationDto { + @ApiProperty({ + description: 'The first name of the user', + example: 'John', + required: true, + }) + @IsString() + @IsNotEmpty() + public firstName: string; + + @ApiProperty({ + description: 'The last name of the user', + example: 'Doe', + required: true, + }) + @IsString() + @IsNotEmpty() + public lastName: string; + + @ApiProperty({ + description: 'The email of the user', + example: 'OqM9A@example.com', + required: true, + }) + @IsString() + @IsNotEmpty() + public email: string; + + @ApiProperty({ + description: 'The job title of the user', + example: 'Software Engineer', + required: true, + }) + @IsString() + @IsNotEmpty() + public jobTitle: string; + + @ApiProperty({ + description: 'The phone number of the user', + example: '+1234567890', + required: true, + }) + @IsString() + @IsOptional() + public phoneNumber?: string; + + @ApiProperty({ + description: 'The role uuid of the user', + example: 'd290f1ee-6c54-4b01-90e6-d701748f0851', + required: true, + }) + @IsString() + @IsNotEmpty() + public roleUuid: string; + @ApiProperty({ + description: 'The array of space UUIDs (at least one required)', + example: ['b5f3c9d2-58b7-4377-b3f7-60acb711d5d9'], + required: true, + }) + @IsArray() + @ArrayMinSize(1) + public spaceUuids: string[]; + constructor(dto: Partial) { + Object.assign(this, dto); + } +} diff --git a/src/invite-user/dtos/index.ts b/src/invite-user/dtos/index.ts new file mode 100644 index 0000000..6cdec2a --- /dev/null +++ b/src/invite-user/dtos/index.ts @@ -0,0 +1 @@ +export * from './add.invite-user.dto'; diff --git a/src/invite-user/invite-user.module.ts b/src/invite-user/invite-user.module.ts new file mode 100644 index 0000000..d7a19b6 --- /dev/null +++ b/src/invite-user/invite-user.module.ts @@ -0,0 +1,23 @@ +import { Module } from '@nestjs/common'; +import { InviteUserService } from './services/invite-user.service'; +import { InviteUserController } from './controllers/invite-user.controller'; +import { ConfigModule } from '@nestjs/config'; +import { + InviteUserRepository, + InviteUserSpaceRepository, +} from '@app/common/modules/Invite-user/repositories'; +import { UserRepository } from '@app/common/modules/user/repositories'; +import { InviteUserRepositoryModule } from '@app/common/modules/Invite-user/Invite-user.repository.module'; + +@Module({ + imports: [ConfigModule, InviteUserRepositoryModule], + controllers: [InviteUserController], + providers: [ + InviteUserService, + InviteUserRepository, + UserRepository, + InviteUserSpaceRepository, + ], + exports: [InviteUserService], +}) +export class InviteUserModule {} diff --git a/src/invite-user/services/index.ts b/src/invite-user/services/index.ts new file mode 100644 index 0000000..024e5a5 --- /dev/null +++ b/src/invite-user/services/index.ts @@ -0,0 +1 @@ +export * from './invite-user.service'; diff --git a/src/permission/controllers/index.ts b/src/permission/controllers/index.ts new file mode 100644 index 0000000..e78a8bd --- /dev/null +++ b/src/permission/controllers/index.ts @@ -0,0 +1 @@ +export * from './permission.controller'; diff --git a/src/permission/controllers/permission.controller.ts b/src/permission/controllers/permission.controller.ts new file mode 100644 index 0000000..9b07db2 --- /dev/null +++ b/src/permission/controllers/permission.controller.ts @@ -0,0 +1,24 @@ +import { Controller, Get, Param } from '@nestjs/common'; +import { ApiTags, ApiOperation } from '@nestjs/swagger'; +import { ControllerRoute } from '@app/common/constants/controller-route'; +import { EnableDisableStatusEnum } from '@app/common/constants/days.enum'; +import { PermissionService } from '../services'; + +@ApiTags('Permission Module') +@Controller({ + version: EnableDisableStatusEnum.ENABLED, + path: ControllerRoute.PERMISSION.ROUTE, +}) +export class PermissionController { + constructor(private readonly permissionService: PermissionService) {} + + @Get(':roleUuid') + @ApiOperation({ + summary: ControllerRoute.PERMISSION.ACTIONS.GET_PERMISSION_BY_ROLE_SUMMARY, + description: + ControllerRoute.PERMISSION.ACTIONS.GET_PERMISSION_BY_ROLE_DESCRIPTION, + }) + async getPermissionsByRole(@Param('roleUuid') roleUuid: string) { + return await this.permissionService.getPermissionsByRole(roleUuid); + } +} diff --git a/src/permission/permission.module.ts b/src/permission/permission.module.ts new file mode 100644 index 0000000..8c74871 --- /dev/null +++ b/src/permission/permission.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { CommonModule } from '@app/common'; +import { PermissionController } from './controllers'; +import { PermissionService } from './services'; +import { RoleTypeRepository } from '@app/common/modules/role-type/repositories'; + +@Module({ + imports: [ConfigModule, CommonModule], + controllers: [PermissionController], + providers: [PermissionService, RoleTypeRepository], + exports: [PermissionService], +}) +export class PermissionModule {} diff --git a/src/permission/services/index.ts b/src/permission/services/index.ts new file mode 100644 index 0000000..89f3aec --- /dev/null +++ b/src/permission/services/index.ts @@ -0,0 +1 @@ +export * from './permission.service'; diff --git a/src/permission/services/permission.service.ts b/src/permission/services/permission.service.ts new file mode 100644 index 0000000..33c5f18 --- /dev/null +++ b/src/permission/services/permission.service.ts @@ -0,0 +1,52 @@ +import { PermissionMapping } from '@app/common/constants/permissions-mapping'; +import { RolePermissions } from '@app/common/constants/role-permissions'; +import { RoleType } from '@app/common/constants/role.type.enum'; +import { RoleTypeRepository } from '@app/common/modules/role-type/repositories'; +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; + +@Injectable() +export class PermissionService { + constructor(private readonly roleTypeRepository: RoleTypeRepository) {} + + async getPermissionsByRole(roleUuid: string) { + try { + const role = await this.roleTypeRepository.findOne({ + where: { + uuid: roleUuid, + }, + }); + + if (!role) { + throw new HttpException('Role not found', HttpStatus.NOT_FOUND); + } + + const permissions = this.mapPermissions(role.type.toString() as RoleType); + return permissions; + } catch (err) { + throw new HttpException( + err.message || 'Internal Server Error', + err.status || HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + mapPermissions(role: RoleType): any[] { + const rolePermissions = RolePermissions[role]; // Permissions for the role + + const mappedPermissions = Object.entries(PermissionMapping).map( + ([title, subOptions]) => ({ + title, + subOptions: Object.entries(subOptions).map( + ([subTitle, permissions]) => ({ + title: subTitle, + subOptions: permissions.map((permission) => ({ + title: permission, + isChecked: rolePermissions.includes(`${subTitle}_${permission}`), // Check if the role has the permission + })), + }), + ), + }), + ); + + return mappedPermissions; + } +}