From de84113066c27d88922285bd431b4968cf565a68 Mon Sep 17 00:00:00 2001 From: Joseph Ditton Date: Fri, 7 Jan 2022 10:19:34 -0700 Subject: [PATCH] adds context id to role and role helpers --- .../1641570023672-AddContextIdToUserRole.ts | 18 +++++++++ server/entities/user_role.entity.ts | 3 ++ server/providers/services/users.service.ts | 38 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 server/database/migrations/1641570023672-AddContextIdToUserRole.ts diff --git a/server/database/migrations/1641570023672-AddContextIdToUserRole.ts b/server/database/migrations/1641570023672-AddContextIdToUserRole.ts new file mode 100644 index 0000000..921c679 --- /dev/null +++ b/server/database/migrations/1641570023672-AddContextIdToUserRole.ts @@ -0,0 +1,18 @@ +import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; + +export class AddContextIdToUserRole1641570023672 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.addColumn( + 'user_role', + new TableColumn({ + name: 'contextId', + type: 'text', + default: "'root'", // default values must include single quotes for text + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropColumn('user_role', 'contextId'); + } +} diff --git a/server/entities/user_role.entity.ts b/server/entities/user_role.entity.ts index e680a3a..230a7ec 100644 --- a/server/entities/user_role.entity.ts +++ b/server/entities/user_role.entity.ts @@ -13,6 +13,9 @@ export class UserRole { @Column() userId: number; + @Column() + contextId: string; + @ManyToOne(() => Role, (role) => role.userRoles) role: Role; diff --git a/server/providers/services/users.service.ts b/server/providers/services/users.service.ts index c3ee086..2bb752a 100644 --- a/server/providers/services/users.service.ts +++ b/server/providers/services/users.service.ts @@ -3,12 +3,19 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import * as bcrypt from 'bcrypt'; import { User } from '../../entities/user.entity'; +import { Role, RoleKey } from 'server/entities/role.entity'; +import { UserRole } from 'server/entities/user_role.entity'; +import { intersection, isEmpty } from 'lodash'; @Injectable() export class UsersService { constructor( @InjectRepository(User) private usersRespository: Repository, + @InjectRepository(UserRole) + private userRolesRepository: Repository, + @InjectRepository(Role) + private rolesRepository: Repository, ) {} findAll(relations: string[] = []) { @@ -33,4 +40,35 @@ export class UsersService { const verified: boolean = await bcrypt.compare(password, user.passwordHash); return { verified, user: verified ? user : null }; } + + addUserToRoleInContext(userId: number, contextId: string, ...roleKeys: RoleKey[]) { + return Promise.all( + roleKeys.map(async (key) => { + const role = await this.rolesRepository.findOne({ key }); + const userRole = new UserRole(); + userRole.userId = userId; + userRole.contextId = contextId; + userRole.role = role; + await this.userRolesRepository.save(userRole); + }), + ); + } + + addUserToRootRole(userId: number, ...roleKeys: RoleKey[]) { + return this.addUserToRoleInContext(userId, 'root', ...roleKeys); + } + + // if multiple roles are passed then will return true if user has any of the listed roles. + async hasRoleInContext(userId: number, contextId: string, ...roleKeys: RoleKey[]) { + const userRoles = await this.userRolesRepository.find({ + where: { userId, contextId }, + relations: ['role'], + }); + const usersRoleKeys = userRoles.map((userRole) => userRole.role.key); + return !isEmpty(intersection(roleKeys, usersRoleKeys)); + } + + async hasRootRole(userId: number, ...roleKeys: RoleKey[]) { + return this.hasRoleInContext(userId, 'root', ...roleKeys); + } }