Merge pull request #509 from Hexastack/fix/permission-and-role-ts-strict-null-check

Fix: permission and role ts strict null check
This commit is contained in:
Med Marrouchi 2025-01-03 16:10:43 +01:00 committed by GitHub
commit 4974fb4bc8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 62 additions and 51 deletions

View File

@ -24,7 +24,11 @@ import { ModelRepository } from '../repositories/model.repository';
import { PermissionRepository } from '../repositories/permission.repository'; import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository'; import { RoleRepository } from '../repositories/role.repository';
import { Model, ModelModel } from '../schemas/model.schema'; import { Model, ModelModel } from '../schemas/model.schema';
import { Permission, PermissionModel } from '../schemas/permission.schema'; import {
Permission,
PermissionFull,
PermissionModel,
} from '../schemas/permission.schema';
import { Role, RoleModel } from '../schemas/role.schema'; import { Role, RoleModel } from '../schemas/role.schema';
import { ModelService } from '../services/model.service'; import { ModelService } from '../services/model.service';
import { PermissionService } from '../services/permission.service'; import { PermissionService } from '../services/permission.service';
@ -79,11 +83,11 @@ describe('PermissionController', () => {
permissionModuleRef.get<PermissionService>(PermissionService); permissionModuleRef.get<PermissionService>(PermissionService);
allPermissions = await permissionService.findAll(); allPermissions = await permissionService.findAll();
adminRole = await roleService.findOne({ name: 'admin' }); adminRole = (await roleService.findOne({ name: 'admin' })) as Role;
contentModel = await modelService.findOne({ name: 'Content' }); contentModel = (await modelService.findOne({ name: 'Content' })) as Model;
createPermission = await permissionService.findOne({ createPermission = (await permissionService.findOne({
action: Action.CREATE, action: Action.CREATE,
}); })) as Permission;
}); });
afterAll(closeInMongodConnection); afterAll(closeInMongodConnection);
@ -110,16 +114,16 @@ describe('PermissionController', () => {
...currPermission, ...currPermission,
role: allRoles.find((role) => { role: allRoles.find((role) => {
return role.id === currPermission.role; return role.id === currPermission.role;
}), }) as Role,
model: allModels.find((model) => { model: allModels.find((model) => {
return model.id === currPermission.model; return model.id === currPermission.model;
}), }) as Model,
}); });
return acc; return acc;
}, },
[], [] as PermissionFull[],
); );
expect(result).toEqualPayload(permissionsWithRolesAndModels); expect(result).toEqualPayload(permissionsWithRolesAndModels);

View File

@ -92,13 +92,16 @@ export class PermissionController extends BaseController<
@CsrfCheck(true) @CsrfCheck(true)
@Post() @Post()
async create(@Body() permission: PermissionCreateDto) { async create(@Body() permission: PermissionCreateDto) {
this.validate({ const role = await this.roleService.findOne(permission.role);
dto: permission, if (!role) {
allowedIds: { throw new NotFoundException('Unable to find role');
role: (await this.roleService.findOne(permission.role))?.id, }
model: (await this.modelService.findOne(permission.model))?.id, const model = await this.modelService.findOne(permission.model);
},
}); if (!model) {
throw new NotFoundException('Unable to find model');
}
return await this.permissionService.create(permission); return await this.permissionService.create(permission);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
@ -30,7 +30,7 @@ import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository'; import { RoleRepository } from '../repositories/role.repository';
import { UserRepository } from '../repositories/user.repository'; import { UserRepository } from '../repositories/user.repository';
import { PermissionModel } from '../schemas/permission.schema'; import { PermissionModel } from '../schemas/permission.schema';
import { Role, RoleModel } from '../schemas/role.schema'; import { Role, RoleFull, RoleModel } from '../schemas/role.schema';
import { UserModel } from '../schemas/user.schema'; import { UserModel } from '../schemas/user.schema';
import { PermissionService } from '../services/permission.service'; import { PermissionService } from '../services/permission.service';
import { RoleService } from '../services/role.service'; import { RoleService } from '../services/role.service';
@ -83,8 +83,8 @@ describe('RoleController', () => {
roleService = module.get<RoleService>(RoleService); roleService = module.get<RoleService>(RoleService);
permissionService = module.get<PermissionService>(PermissionService); permissionService = module.get<PermissionService>(PermissionService);
userService = module.get<UserService>(UserService); userService = module.get<UserService>(UserService);
roleAdmin = await roleService.findOne({ name: 'admin' }); roleAdmin = (await roleService.findOne({ name: 'admin' })) as Role;
rolePublic = await roleService.findOne({ name: 'public' }); rolePublic = (await roleService.findOne({ name: 'public' })) as Role;
}); });
afterAll(async () => { afterAll(async () => {
@ -126,7 +126,7 @@ describe('RoleController', () => {
acc.push(roleWithPermissionsAndUsers); acc.push(roleWithPermissionsAndUsers);
return acc; return acc;
}, []); }, [] as RoleFull[]);
expect(roleService.findAndPopulate).toHaveBeenCalledWith({}, pageQuery); expect(roleService.findAndPopulate).toHaveBeenCalledWith({}, pageQuery);
expect(result).toEqualPayload(rolesWithPermissionsAndUsers); expect(result).toEqualPayload(rolesWithPermissionsAndUsers);
@ -136,10 +136,10 @@ describe('RoleController', () => {
describe('findOne', () => { describe('findOne', () => {
it('should find one role', async () => { it('should find one role', async () => {
jest.spyOn(roleService, 'findOne'); jest.spyOn(roleService, 'findOne');
const result = await roleController.findOne(roleAdmin.id, []); const result = (await roleController.findOne(roleAdmin.id, [])) as Role;
expect(roleService.findOne).toHaveBeenCalledWith(roleAdmin.id); expect(roleService.findOne).toHaveBeenCalledWith(roleAdmin.id);
expect(result).toEqualPayload( expect(result).toEqualPayload(
roleFixtures.find((role) => role.name === 'admin'), roleFixtures.find((role) => role.name === 'admin') as Role,
); );
}); });

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
@ -23,9 +23,13 @@ import {
import { ModelRepository } from '../repositories/model.repository'; import { ModelRepository } from '../repositories/model.repository';
import { PermissionRepository } from '../repositories/permission.repository'; import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository'; import { RoleRepository } from '../repositories/role.repository';
import { ModelModel } from '../schemas/model.schema'; import { ModelModel, Model as ModelSchema } from '../schemas/model.schema';
import { Permission, PermissionModel } from '../schemas/permission.schema'; import {
import { RoleModel } from '../schemas/role.schema'; Permission,
PermissionFull,
PermissionModel,
} from '../schemas/permission.schema';
import { Role, RoleModel } from '../schemas/role.schema';
import { Action } from '../types/action.type'; import { Action } from '../types/action.type';
describe('PermissionRepository', () => { describe('PermissionRepository', () => {
@ -56,12 +60,12 @@ describe('PermissionRepository', () => {
permissionModel = module.get<Model<Permission>>( permissionModel = module.get<Model<Permission>>(
getModelToken('Permission'), getModelToken('Permission'),
); );
permission = await permissionRepository.findOne({ permission = (await permissionRepository.findOne({
action: Action.CREATE, action: Action.CREATE,
}); })) as Permission;
permissionToDelete = await permissionRepository.findOne({ permissionToDelete = (await permissionRepository.findOne({
action: Action.UPDATE, action: Action.UPDATE,
}); })) as Permission;
}); });
afterAll(async () => { afterAll(async () => {
@ -104,16 +108,16 @@ describe('PermissionRepository', () => {
...currPermission, ...currPermission,
role: allRoles.find((role) => { role: allRoles.find((role) => {
return role.id === currPermission.role; return role.id === currPermission.role;
}), }) as Role,
model: allModels.find((model) => { model: allModels.find((model) => {
return model.id === currPermission.model; return model.id === currPermission.model;
}), }) as ModelSchema,
}); });
return acc; return acc;
}, },
[], [] as PermissionFull[],
); );
expect(permissionModel.find).toHaveBeenCalledWith({}, undefined); expect(permissionModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(permissionsWithRolesAndModels); expect(result).toEqualPayload(permissionsWithRolesAndModels);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
@ -22,7 +22,7 @@ import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository'; import { RoleRepository } from '../repositories/role.repository';
import { UserRepository } from '../repositories/user.repository'; import { UserRepository } from '../repositories/user.repository';
import { PermissionModel } from '../schemas/permission.schema'; import { PermissionModel } from '../schemas/permission.schema';
import { Role, RoleModel } from '../schemas/role.schema'; import { Role, RoleFull, RoleModel } from '../schemas/role.schema';
import { User, UserModel } from '../schemas/user.schema'; import { User, UserModel } from '../schemas/user.schema';
import { roleFixtures } from './../../utils/test/fixtures/role'; import { roleFixtures } from './../../utils/test/fixtures/role';
@ -54,13 +54,13 @@ describe('RoleRepository', () => {
permissionRepository = permissionRepository =
module.get<PermissionRepository>(PermissionRepository); module.get<PermissionRepository>(PermissionRepository);
roleModel = module.get<Model<Role>>(getModelToken('Role')); roleModel = module.get<Model<Role>>(getModelToken('Role'));
role = await roleRepository.findOne({ name: 'admin' }); role = (await roleRepository.findOne({ name: 'admin' })) as Role;
users = (await userRepository.findAll()).filter((user) => users = (await userRepository.findAll()).filter((user) =>
user.roles.includes(role.id), user.roles.includes(role.id),
); );
roleToDelete = await roleRepository.findOne({ roleToDelete = (await roleRepository.findOne({
name: 'manager', name: 'manager',
}); })) as Role;
}); });
afterAll(async () => { afterAll(async () => {
@ -104,7 +104,7 @@ describe('RoleRepository', () => {
}; };
acc.push(roleWithPermissionsAndUsers); acc.push(roleWithPermissionsAndUsers);
return acc; return acc;
}, []); }, [] as RoleFull[]);
expect(roleModel.find).toHaveBeenCalledWith({}, undefined); expect(roleModel.find).toHaveBeenCalledWith({}, undefined);
expect(result).toEqualPayload(rolesWithPermissionsAndUsers); expect(result).toEqualPayload(rolesWithPermissionsAndUsers);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
@ -24,13 +24,13 @@ import {
import { ModelRepository } from '../repositories/model.repository'; import { ModelRepository } from '../repositories/model.repository';
import { PermissionRepository } from '../repositories/permission.repository'; import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository'; import { RoleRepository } from '../repositories/role.repository';
import { ModelModel } from '../schemas/model.schema'; import { ModelModel, Model as ModelSchema } from '../schemas/model.schema';
import { import {
Permission, Permission,
PermissionFull, PermissionFull,
PermissionModel, PermissionModel,
} from '../schemas/permission.schema'; } from '../schemas/permission.schema';
import { RoleModel } from '../schemas/role.schema'; import { Role, RoleModel } from '../schemas/role.schema';
import { Action } from '../types/action.type'; import { Action } from '../types/action.type';
import { PermissionService } from './permission.service'; import { PermissionService } from './permission.service';
@ -70,9 +70,9 @@ describe('PermissionService', () => {
modelRepository = module.get<ModelRepository>(ModelRepository); modelRepository = module.get<ModelRepository>(ModelRepository);
permissionRepository = permissionRepository =
module.get<PermissionRepository>(PermissionRepository); module.get<PermissionRepository>(PermissionRepository);
permission = await permissionRepository.findOne({ permission = (await permissionRepository.findOne({
action: Action.CREATE, action: Action.CREATE,
}); })) as Permission;
}); });
afterAll(async () => { afterAll(async () => {
@ -112,16 +112,16 @@ describe('PermissionService', () => {
...currPermission, ...currPermission,
role: allRoles.find((role) => { role: allRoles.find((role) => {
return role.id === currPermission.role; return role.id === currPermission.role;
}), }) as Role,
model: allModels.find((model) => { model: allModels.find((model) => {
return model.id === currPermission.model; return model.id === currPermission.model;
}), }) as ModelSchema,
}); });
return acc; return acc;
}, },
[], [] as PermissionFull[],
); );
expect(permissionRepository.findAllAndPopulate).toHaveBeenCalled(); expect(permissionRepository.findAllAndPopulate).toHaveBeenCalled();
expect(result).toEqualPayload(permissionsWithRolesAndModels); expect(result).toEqualPayload(permissionsWithRolesAndModels);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
@ -21,7 +21,7 @@ import { PermissionRepository } from '../repositories/permission.repository';
import { RoleRepository } from '../repositories/role.repository'; import { RoleRepository } from '../repositories/role.repository';
import { UserRepository } from '../repositories/user.repository'; import { UserRepository } from '../repositories/user.repository';
import { Permission, PermissionModel } from '../schemas/permission.schema'; import { Permission, PermissionModel } from '../schemas/permission.schema';
import { Role, RoleModel } from '../schemas/role.schema'; import { Role, RoleFull, RoleModel } from '../schemas/role.schema';
import { User, UserModel } from '../schemas/user.schema'; import { User, UserModel } from '../schemas/user.schema';
import { roleFixtures } from './../../utils/test/fixtures/role'; import { roleFixtures } from './../../utils/test/fixtures/role';
@ -55,7 +55,7 @@ describe('RoleService', () => {
userRepository = module.get<UserRepository>(UserRepository); userRepository = module.get<UserRepository>(UserRepository);
permissionRepository = permissionRepository =
module.get<PermissionRepository>(PermissionRepository); module.get<PermissionRepository>(PermissionRepository);
role = await roleRepository.findOne({ name: 'admin' }); role = (await roleRepository.findOne({ name: 'admin' })) as Role;
users = (await userRepository.findAll()).filter((user) => users = (await userRepository.findAll()).filter((user) =>
user.roles.includes(role.id), user.roles.includes(role.id),
); );
@ -105,7 +105,7 @@ describe('RoleService', () => {
}; };
acc.push(roleWithPermissionsAndUsers); acc.push(roleWithPermissionsAndUsers);
return acc; return acc;
}, []); }, [] as RoleFull[]);
expect(roleRepository.findPageAndPopulate).toHaveBeenCalledWith( expect(roleRepository.findPageAndPopulate).toHaveBeenCalledWith(
{}, {},