mirror of
https://github.com/hexastack/hexabot
synced 2025-01-22 18:45:57 +00:00
fix: apply strict null checks updates to the User Module
This commit is contained in:
parent
8326c8c121
commit
816db9817a
@ -60,7 +60,7 @@ describe('AuthController', () => {
|
|||||||
let invitationService: InvitationService;
|
let invitationService: InvitationService;
|
||||||
let roleService: RoleService;
|
let roleService: RoleService;
|
||||||
let jwtService: JwtService;
|
let jwtService: JwtService;
|
||||||
let role: Role;
|
let role: Role | null;
|
||||||
let baseUser: UserCreateDto;
|
let baseUser: UserCreateDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
@ -136,7 +136,7 @@ describe('AuthController', () => {
|
|||||||
username: 'test',
|
username: 'test',
|
||||||
first_name: 'test',
|
first_name: 'test',
|
||||||
last_name: 'test',
|
last_name: 'test',
|
||||||
roles: [role.id],
|
roles: [role!.id],
|
||||||
};
|
};
|
||||||
await invitationService.create(baseUser);
|
await invitationService.create(baseUser);
|
||||||
});
|
});
|
||||||
|
@ -87,7 +87,7 @@ export class LocalAuthController extends BaseAuthController {
|
|||||||
logger: LoggerService,
|
logger: LoggerService,
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly validateAccountService: ValidateAccountService,
|
private readonly validateAccountService: ValidateAccountService,
|
||||||
private readonly invitationService?: InvitationService,
|
private readonly invitationService: InvitationService,
|
||||||
) {
|
) {
|
||||||
super(logger);
|
super(logger);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ 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 { UserRepository } from '../repositories/user.repository';
|
import { UserRepository } from '../repositories/user.repository';
|
||||||
import { ModelModel } from '../schemas/model.schema';
|
import { ModelFull, ModelModel } from '../schemas/model.schema';
|
||||||
import { PermissionModel } from '../schemas/permission.schema';
|
import { PermissionModel } from '../schemas/permission.schema';
|
||||||
import { RoleModel } from '../schemas/role.schema';
|
import { RoleModel } from '../schemas/role.schema';
|
||||||
import { UserModel } from '../schemas/user.schema';
|
import { UserModel } from '../schemas/user.schema';
|
||||||
@ -104,11 +104,12 @@ describe('ModelController', () => {
|
|||||||
|
|
||||||
it('should find models, and for each model populate the corresponding permissions', async () => {
|
it('should find models, and for each model populate the corresponding permissions', async () => {
|
||||||
jest.spyOn(modelService, 'findAndPopulate');
|
jest.spyOn(modelService, 'findAndPopulate');
|
||||||
const allRoles = await modelService.findAll();
|
const allModels = await modelService.findAll();
|
||||||
const allPermissions = await permissionService.findAll();
|
const allPermissions = await permissionService.findAll();
|
||||||
const result = await modelController.find(['permissions'], {});
|
const result = await modelController.find(['permissions'], {});
|
||||||
|
|
||||||
const modelsWithPermissionsAndUsers = allRoles.reduce((acc, currRole) => {
|
const modelsWithPermissionsAndUsers = allModels.reduce(
|
||||||
|
(acc, currRole) => {
|
||||||
const modelWithPermissionsAndUsers = {
|
const modelWithPermissionsAndUsers = {
|
||||||
...currRole,
|
...currRole,
|
||||||
permissions: allPermissions.filter((currPermission) => {
|
permissions: allPermissions.filter((currPermission) => {
|
||||||
@ -118,7 +119,9 @@ describe('ModelController', () => {
|
|||||||
|
|
||||||
acc.push(modelWithPermissionsAndUsers);
|
acc.push(modelWithPermissionsAndUsers);
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
},
|
||||||
|
[] as ModelFull[],
|
||||||
|
);
|
||||||
|
|
||||||
expect(modelService.findAndPopulate).toHaveBeenCalledWith({});
|
expect(modelService.findAndPopulate).toHaveBeenCalledWith({});
|
||||||
expect(result).toEqualPayload(modelsWithPermissionsAndUsers);
|
expect(result).toEqualPayload(modelsWithPermissionsAndUsers);
|
||||||
|
@ -47,7 +47,7 @@ import { UserRepository } from '../repositories/user.repository';
|
|||||||
import { InvitationModel } from '../schemas/invitation.schema';
|
import { InvitationModel } from '../schemas/invitation.schema';
|
||||||
import { PermissionModel } from '../schemas/permission.schema';
|
import { PermissionModel } from '../schemas/permission.schema';
|
||||||
import { Role, RoleModel } from '../schemas/role.schema';
|
import { Role, RoleModel } from '../schemas/role.schema';
|
||||||
import { User, UserModel } from '../schemas/user.schema';
|
import { User, UserFull, UserModel } from '../schemas/user.schema';
|
||||||
import { PasswordResetService } from '../services/passwordReset.service';
|
import { PasswordResetService } from '../services/passwordReset.service';
|
||||||
import { PermissionService } from '../services/permission.service';
|
import { PermissionService } from '../services/permission.service';
|
||||||
import { RoleService } from '../services/role.service';
|
import { RoleService } from '../services/role.service';
|
||||||
@ -63,9 +63,9 @@ describe('UserController', () => {
|
|||||||
let roleService: RoleService;
|
let roleService: RoleService;
|
||||||
let invitationService: InvitationService;
|
let invitationService: InvitationService;
|
||||||
let notFoundId: string;
|
let notFoundId: string;
|
||||||
let role: Role;
|
let role: Role | null;
|
||||||
let roles: Role[];
|
let roles: Role[];
|
||||||
let user: User;
|
let user: User | null;
|
||||||
let passwordResetService: PasswordResetService;
|
let passwordResetService: PasswordResetService;
|
||||||
let jwtService: JwtService;
|
let jwtService: JwtService;
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
@ -157,12 +157,12 @@ describe('UserController', () => {
|
|||||||
describe('findOne', () => {
|
describe('findOne', () => {
|
||||||
it('should find one user and populate its roles', async () => {
|
it('should find one user and populate its roles', async () => {
|
||||||
jest.spyOn(userService, 'findOneAndPopulate');
|
jest.spyOn(userService, 'findOneAndPopulate');
|
||||||
const result = await userController.findOne(user.id, ['roles']);
|
const result = await userController.findOne(user!.id, ['roles']);
|
||||||
expect(userService.findOneAndPopulate).toHaveBeenCalledWith(user.id);
|
expect(userService.findOneAndPopulate).toHaveBeenCalledWith(user!.id);
|
||||||
expect(result).toEqualPayload(
|
expect(result).toEqualPayload(
|
||||||
{
|
{
|
||||||
...userFixtures.find(({ username }) => username === 'admin'),
|
...userFixtures.find(({ username }) => username === 'admin'),
|
||||||
roles: roles.filter(({ id }) => user.roles.includes(id)),
|
roles: roles.filter(({ id }) => user!.roles.includes(id)),
|
||||||
},
|
},
|
||||||
[...IGNORED_FIELDS, 'password', 'provider'],
|
[...IGNORED_FIELDS, 'password', 'provider'],
|
||||||
);
|
);
|
||||||
@ -176,13 +176,17 @@ describe('UserController', () => {
|
|||||||
jest.spyOn(userService, 'findPageAndPopulate');
|
jest.spyOn(userService, 'findPageAndPopulate');
|
||||||
const result = await userService.findPageAndPopulate({}, pageQuery);
|
const result = await userService.findPageAndPopulate({}, pageQuery);
|
||||||
|
|
||||||
const usersWithRoles = userFixtures.reduce((acc, currUser) => {
|
const usersWithRoles = userFixtures.reduce(
|
||||||
|
(acc, currUser) => {
|
||||||
acc.push({
|
acc.push({
|
||||||
...currUser,
|
...currUser,
|
||||||
roles: roles.filter(({ id }) => user.roles.includes(id)),
|
roles: roles.filter(({ id }) => user?.roles?.includes(id)),
|
||||||
|
avatar: null,
|
||||||
});
|
});
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
},
|
||||||
|
[] as Omit<UserFull, 'id' | 'createdAt' | 'updatedAt'>[],
|
||||||
|
);
|
||||||
|
|
||||||
expect(userService.findPageAndPopulate).toHaveBeenCalledWith(
|
expect(userService.findPageAndPopulate).toHaveBeenCalledWith(
|
||||||
{},
|
{},
|
||||||
@ -205,7 +209,7 @@ describe('UserController', () => {
|
|||||||
last_name: 'testUser',
|
last_name: 'testUser',
|
||||||
email: 'test@test.test',
|
email: 'test@test.test',
|
||||||
password: 'test',
|
password: 'test',
|
||||||
roles: [role.id],
|
roles: [role!.id],
|
||||||
};
|
};
|
||||||
const result = await userController.create(userDto);
|
const result = await userController.create(userDto);
|
||||||
expect(userService.create).toHaveBeenCalledWith(userDto);
|
expect(userService.create).toHaveBeenCalledWith(userDto);
|
||||||
@ -224,16 +228,16 @@ describe('UserController', () => {
|
|||||||
it('should return updated user', async () => {
|
it('should return updated user', async () => {
|
||||||
jest.spyOn(userService, 'updateOne');
|
jest.spyOn(userService, 'updateOne');
|
||||||
const result = await userController.updateOne(
|
const result = await userController.updateOne(
|
||||||
{ user: { id: user.id } } as any,
|
{ user: { id: user!.id } } as any,
|
||||||
user.id,
|
user!.id,
|
||||||
updateDto,
|
updateDto,
|
||||||
);
|
);
|
||||||
expect(userService.updateOne).toHaveBeenCalledWith(user.id, updateDto);
|
expect(userService.updateOne).toHaveBeenCalledWith(user!.id, updateDto);
|
||||||
expect(result).toEqualPayload(
|
expect(result).toEqualPayload(
|
||||||
{
|
{
|
||||||
...userFixtures.find(({ username }) => username === 'admin'),
|
...userFixtures.find(({ username }) => username === 'admin'),
|
||||||
...updateDto,
|
...updateDto,
|
||||||
roles: user.roles,
|
roles: user!.roles,
|
||||||
},
|
},
|
||||||
[...IGNORED_FIELDS, 'password', 'provider'],
|
[...IGNORED_FIELDS, 'password', 'provider'],
|
||||||
);
|
);
|
||||||
@ -243,44 +247,43 @@ describe('UserController', () => {
|
|||||||
describe('updateStateAndRoles', () => {
|
describe('updateStateAndRoles', () => {
|
||||||
it('should return updated user', async () => {
|
it('should return updated user', async () => {
|
||||||
const updateDto: UserUpdateStateAndRolesDto = {
|
const updateDto: UserUpdateStateAndRolesDto = {
|
||||||
roles: [role.id],
|
roles: [role!.id],
|
||||||
};
|
};
|
||||||
jest.spyOn(userService, 'updateOne');
|
jest.spyOn(userService, 'updateOne');
|
||||||
const result = await userController.updateStateAndRoles(
|
const result = await userController.updateStateAndRoles(
|
||||||
user.id,
|
user!.id,
|
||||||
updateDto,
|
updateDto,
|
||||||
{
|
{
|
||||||
passport: {
|
passport: {
|
||||||
user: { id: user.id },
|
user: { id: user!.id },
|
||||||
},
|
},
|
||||||
} as ExpressSession,
|
} as ExpressSession,
|
||||||
);
|
);
|
||||||
expect(userService.updateOne).toHaveBeenCalledWith(user.id, updateDto);
|
expect(userService.updateOne).toHaveBeenCalledWith(user!.id, updateDto);
|
||||||
expect(result).toEqualPayload(
|
expect(result).toEqualPayload(
|
||||||
{
|
{
|
||||||
...userFixtures.find(({ username }) => username === 'admin'),
|
...userFixtures.find(({ username }) => username === 'admin'),
|
||||||
...updateDto,
|
...updateDto,
|
||||||
},
|
},
|
||||||
|
|
||||||
[...IGNORED_FIELDS, 'first_name', 'password', 'provider'],
|
[...IGNORED_FIELDS, 'first_name', 'password', 'provider'],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return updated user after adding an extra role', async () => {
|
it('should return updated user after adding an extra role', async () => {
|
||||||
const updateDto: UserUpdateStateAndRolesDto = {
|
const updateDto: UserUpdateStateAndRolesDto = {
|
||||||
roles: [role.id, roles[1].id],
|
roles: [role!.id, roles[1].id],
|
||||||
};
|
};
|
||||||
jest.spyOn(userService, 'updateOne');
|
jest.spyOn(userService, 'updateOne');
|
||||||
const result = await userController.updateStateAndRoles(
|
const result = await userController.updateStateAndRoles(
|
||||||
user.id,
|
user!.id,
|
||||||
updateDto,
|
updateDto,
|
||||||
{
|
{
|
||||||
passport: {
|
passport: {
|
||||||
user: { id: user.id },
|
user: { id: user!.id },
|
||||||
},
|
},
|
||||||
} as ExpressSession,
|
} as ExpressSession,
|
||||||
);
|
);
|
||||||
expect(userService.updateOne).toHaveBeenCalledWith(user.id, updateDto);
|
expect(userService.updateOne).toHaveBeenCalledWith(user!.id, updateDto);
|
||||||
expect(result).toEqualPayload(
|
expect(result).toEqualPayload(
|
||||||
{
|
{
|
||||||
...userFixtures.find(({ username }) => username === 'admin'),
|
...userFixtures.find(({ username }) => username === 'admin'),
|
||||||
@ -296,9 +299,9 @@ describe('UserController', () => {
|
|||||||
state: false,
|
state: false,
|
||||||
};
|
};
|
||||||
await expect(
|
await expect(
|
||||||
userController.updateStateAndRoles(user.id, updateDto, {
|
userController.updateStateAndRoles(user!.id, updateDto, {
|
||||||
passport: {
|
passport: {
|
||||||
user: { id: user.id },
|
user: { id: user!.id },
|
||||||
},
|
},
|
||||||
} as ExpressSession),
|
} as ExpressSession),
|
||||||
).rejects.toThrow(ForbiddenException);
|
).rejects.toThrow(ForbiddenException);
|
||||||
@ -309,9 +312,9 @@ describe('UserController', () => {
|
|||||||
roles: [],
|
roles: [],
|
||||||
};
|
};
|
||||||
await expect(
|
await expect(
|
||||||
userController.updateStateAndRoles(user.id, updateDto, {
|
userController.updateStateAndRoles(user!.id, updateDto, {
|
||||||
passport: {
|
passport: {
|
||||||
user: { id: user.id },
|
user: { id: user!.id },
|
||||||
},
|
},
|
||||||
} as ExpressSession),
|
} as ExpressSession),
|
||||||
).rejects.toThrow(ForbiddenException);
|
).rejects.toThrow(ForbiddenException);
|
||||||
@ -343,8 +346,8 @@ describe('UserController', () => {
|
|||||||
|
|
||||||
describe('deleteOne', () => {
|
describe('deleteOne', () => {
|
||||||
it('should delete user by id', async () => {
|
it('should delete user by id', async () => {
|
||||||
const result = await userController.deleteOne(user.id);
|
const result = await userController.deleteOne(user!.id);
|
||||||
notFoundId = user.id;
|
notFoundId = user!.id;
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
acknowledged: true,
|
acknowledged: true,
|
||||||
deletedCount: 1,
|
deletedCount: 1,
|
||||||
|
@ -142,12 +142,12 @@ export class ReadOnlyUserController extends BaseController<
|
|||||||
);
|
);
|
||||||
const currentPermissions = await this.permissionService.findAndPopulate({
|
const currentPermissions = await this.permissionService.findAndPopulate({
|
||||||
role: {
|
role: {
|
||||||
$in: currentUser.roles.map(({ id }) => id),
|
$in: currentUser?.roles.map(({ id }) => id),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
roles: currentUser.roles,
|
roles: currentUser?.roles,
|
||||||
permissions: currentPermissions.map((permission) => {
|
permissions: currentPermissions.map((permission) => {
|
||||||
if (permission.model) {
|
if (permission.model) {
|
||||||
return {
|
return {
|
||||||
@ -248,7 +248,9 @@ export class ReadWriteUserController extends ReadOnlyUserController {
|
|||||||
roles: (await this.roleService.findAll())
|
roles: (await this.roleService.findAll())
|
||||||
.filter((role) => user.roles.includes(role.id))
|
.filter((role) => user.roles.includes(role.id))
|
||||||
.map((role) => role.id),
|
.map((role) => role.id),
|
||||||
avatar: (await this.attachmentService.findOne(user.avatar))?.id,
|
avatar: user.avatar
|
||||||
|
? (await this.attachmentService.findOne(user.avatar))?.id
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return await this.userService.create(user);
|
return await this.userService.create(user);
|
||||||
@ -285,7 +287,7 @@ export class ReadWriteUserController extends ReadOnlyUserController {
|
|||||||
@Body() userUpdate: UserEditProfileDto,
|
@Body() userUpdate: UserEditProfileDto,
|
||||||
@UploadedFile() avatarFile?: Express.Multer.File,
|
@UploadedFile() avatarFile?: Express.Multer.File,
|
||||||
) {
|
) {
|
||||||
if (!('id' in req.user && req.user.id) || req.user.id !== id) {
|
if (!(req.user && 'id' in req.user && req.user.id) || req.user.id !== id) {
|
||||||
throw new ForbiddenException();
|
throw new ForbiddenException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,18 +341,20 @@ export class ReadWriteUserController extends ReadOnlyUserController {
|
|||||||
@Body() body: UserUpdateStateAndRolesDto,
|
@Body() body: UserUpdateStateAndRolesDto,
|
||||||
@Session() session: ExpressSession,
|
@Session() session: ExpressSession,
|
||||||
) {
|
) {
|
||||||
const oldRoles = (await this.userService.findOne(id)).roles;
|
const oldRoles = (await this.userService.findOne(id))?.roles;
|
||||||
const newRoles = body.roles;
|
const newRoles = body.roles;
|
||||||
const { id: adminRoleId } = await this.roleService.findOne({
|
const { id: adminRoleId } =
|
||||||
|
(await this.roleService.findOne({
|
||||||
name: 'admin',
|
name: 'admin',
|
||||||
});
|
})) || {};
|
||||||
if (id === session.passport?.user?.id && body.state === false) {
|
if (id === session.passport?.user?.id && body.state === false) {
|
||||||
throw new ForbiddenException('Your account state is protected');
|
throw new ForbiddenException('Your account state is protected');
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
|
adminRoleId &&
|
||||||
session?.passport?.user?.id === id &&
|
session?.passport?.user?.id === id &&
|
||||||
oldRoles.includes(adminRoleId) &&
|
oldRoles?.includes(adminRoleId) &&
|
||||||
!newRoles.includes(adminRoleId)
|
!newRoles?.includes(adminRoleId)
|
||||||
) {
|
) {
|
||||||
throw new ForbiddenException('Admin privileges are protected');
|
throw new ForbiddenException('Admin privileges are protected');
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,11 @@ import {
|
|||||||
rootMongooseTestModule,
|
rootMongooseTestModule,
|
||||||
} from '@/utils/test/test';
|
} from '@/utils/test/test';
|
||||||
|
|
||||||
import { Invitation, InvitationModel } from '../schemas/invitation.schema';
|
import {
|
||||||
|
Invitation,
|
||||||
|
InvitationFull,
|
||||||
|
InvitationModel,
|
||||||
|
} from '../schemas/invitation.schema';
|
||||||
import { PermissionModel } from '../schemas/permission.schema';
|
import { PermissionModel } from '../schemas/permission.schema';
|
||||||
import { RoleModel } from '../schemas/role.schema';
|
import { RoleModel } from '../schemas/role.schema';
|
||||||
|
|
||||||
@ -79,10 +83,10 @@ describe('InvitationRepository', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const result = await invitationRepository.findOneAndPopulate(
|
const result = await invitationRepository.findOneAndPopulate(
|
||||||
invitation.id,
|
invitation!.id,
|
||||||
);
|
);
|
||||||
expect(invitationModel.findById).toHaveBeenCalledWith(
|
expect(invitationModel.findById).toHaveBeenCalledWith(
|
||||||
invitation.id,
|
invitation!.id,
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
expect(result).toEqualPayload({
|
expect(result).toEqualPayload({
|
||||||
@ -111,7 +115,7 @@ describe('InvitationRepository', () => {
|
|||||||
roles: allRoles.filter((role) => currInv.roles.includes(role.id)),
|
roles: allRoles.filter((role) => currInv.roles.includes(role.id)),
|
||||||
});
|
});
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, [] as InvitationFull[]);
|
||||||
|
|
||||||
expect(invitationModel.find).toHaveBeenCalledWith({}, undefined);
|
expect(invitationModel.find).toHaveBeenCalledWith({}, undefined);
|
||||||
expect(result).toEqualPayload(invitationsWithRoles);
|
expect(result).toEqualPayload(invitationsWithRoles);
|
||||||
|
@ -20,7 +20,7 @@ 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 { ModelModel } from '../schemas/model.schema';
|
import { ModelFull, ModelModel } from '../schemas/model.schema';
|
||||||
import { Permission, PermissionModel } from '../schemas/permission.schema';
|
import { Permission, PermissionModel } from '../schemas/permission.schema';
|
||||||
|
|
||||||
import { Model as ModelType } from './../schemas/model.schema';
|
import { Model as ModelType } from './../schemas/model.schema';
|
||||||
@ -29,7 +29,7 @@ describe('ModelRepository', () => {
|
|||||||
let modelRepository: ModelRepository;
|
let modelRepository: ModelRepository;
|
||||||
let permissionRepository: PermissionRepository;
|
let permissionRepository: PermissionRepository;
|
||||||
let modelModel: Model<ModelType>;
|
let modelModel: Model<ModelType>;
|
||||||
let model: ModelType;
|
let model: ModelType | null;
|
||||||
let permissions: Permission[];
|
let permissions: Permission[];
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
@ -45,7 +45,7 @@ describe('ModelRepository', () => {
|
|||||||
modelRepository = module.get<ModelRepository>(ModelRepository);
|
modelRepository = module.get<ModelRepository>(ModelRepository);
|
||||||
modelModel = module.get<Model<ModelType>>(getModelToken('Model'));
|
modelModel = module.get<Model<ModelType>>(getModelToken('Model'));
|
||||||
model = await modelRepository.findOne({ name: 'ContentType' });
|
model = await modelRepository.findOne({ name: 'ContentType' });
|
||||||
permissions = await permissionRepository.find({ model: model.id });
|
permissions = await permissionRepository.find({ model: model!.id });
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(closeInMongodConnection);
|
afterAll(closeInMongodConnection);
|
||||||
@ -55,8 +55,8 @@ describe('ModelRepository', () => {
|
|||||||
describe('findOneAndPopulate', () => {
|
describe('findOneAndPopulate', () => {
|
||||||
it('should find a model and populate its permissions', async () => {
|
it('should find a model and populate its permissions', async () => {
|
||||||
jest.spyOn(modelModel, 'findById');
|
jest.spyOn(modelModel, 'findById');
|
||||||
const result = await modelRepository.findOneAndPopulate(model.id);
|
const result = await modelRepository.findOneAndPopulate(model!.id);
|
||||||
expect(modelModel.findById).toHaveBeenCalledWith(model.id, undefined);
|
expect(modelModel.findById).toHaveBeenCalledWith(model!.id, undefined);
|
||||||
expect(result).toEqualPayload({
|
expect(result).toEqualPayload({
|
||||||
...modelFixtures.find(({ name }) => name === 'ContentType'),
|
...modelFixtures.find(({ name }) => name === 'ContentType'),
|
||||||
permissions,
|
permissions,
|
||||||
@ -73,12 +73,12 @@ describe('ModelRepository', () => {
|
|||||||
const modelsWithPermissions = allModels.reduce((acc, currModel) => {
|
const modelsWithPermissions = allModels.reduce((acc, currModel) => {
|
||||||
acc.push({
|
acc.push({
|
||||||
...currModel,
|
...currModel,
|
||||||
permissions: allPermissions.filter((permission) => {
|
permissions: allPermissions.filter(
|
||||||
return permission.model === currModel.id;
|
(permission) => permission.model === currModel.id,
|
||||||
}),
|
),
|
||||||
});
|
});
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, [] as ModelFull[]);
|
||||||
expect(modelModel.find).toHaveBeenCalledWith({}, undefined);
|
expect(modelModel.find).toHaveBeenCalledWith({}, undefined);
|
||||||
expect(result).toEqualPayload(modelsWithPermissions);
|
expect(result).toEqualPayload(modelsWithPermissions);
|
||||||
});
|
});
|
||||||
|
@ -28,13 +28,13 @@ 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, RoleModel } from '../schemas/role.schema';
|
||||||
import { User, UserModel } from '../schemas/user.schema';
|
import { User, UserFull, UserModel } from '../schemas/user.schema';
|
||||||
|
|
||||||
describe('UserRepository', () => {
|
describe('UserRepository', () => {
|
||||||
let roleRepository: RoleRepository;
|
let roleRepository: RoleRepository;
|
||||||
let userRepository: UserRepository;
|
let userRepository: UserRepository;
|
||||||
let userModel: Model<User>;
|
let userModel: Model<User>;
|
||||||
let user: User;
|
let user: User | null;
|
||||||
let allRoles: Role[];
|
let allRoles: Role[];
|
||||||
|
|
||||||
const FIELDS_TO_IGNORE: string[] = [
|
const FIELDS_TO_IGNORE: string[] = [
|
||||||
@ -90,12 +90,12 @@ describe('UserRepository', () => {
|
|||||||
describe('findOneAndPopulate', () => {
|
describe('findOneAndPopulate', () => {
|
||||||
it('should find one user and populate its role', async () => {
|
it('should find one user and populate its role', async () => {
|
||||||
jest.spyOn(userModel, 'findById');
|
jest.spyOn(userModel, 'findById');
|
||||||
const result = await userRepository.findOneAndPopulate(user.id);
|
const result = await userRepository.findOneAndPopulate(user!.id);
|
||||||
expect(userModel.findById).toHaveBeenCalledWith(user.id, undefined);
|
expect(userModel.findById).toHaveBeenCalledWith(user!.id, undefined);
|
||||||
expect(result).toEqualPayload(
|
expect(result).toEqualPayload(
|
||||||
{
|
{
|
||||||
...userFixtures.find(({ username }) => username === 'admin'),
|
...userFixtures.find(({ username }) => username === 'admin'),
|
||||||
roles: allRoles.filter(({ id }) => user.roles.includes(id)),
|
roles: allRoles.filter(({ id }) => user!.roles.includes(id)),
|
||||||
},
|
},
|
||||||
FIELDS_TO_IGNORE,
|
FIELDS_TO_IGNORE,
|
||||||
);
|
);
|
||||||
@ -113,10 +113,11 @@ describe('UserRepository', () => {
|
|||||||
const usersWithRoles = allUsers.reduce((acc, currUser) => {
|
const usersWithRoles = allUsers.reduce((acc, currUser) => {
|
||||||
acc.push({
|
acc.push({
|
||||||
...currUser,
|
...currUser,
|
||||||
roles: allRoles.filter(({ id }) => user.roles.includes(id)),
|
roles: allRoles.filter(({ id }) => user?.roles.includes(id)),
|
||||||
|
avatar: null,
|
||||||
});
|
});
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, [] as UserFull[]);
|
||||||
|
|
||||||
expect(userModel.find).toHaveBeenCalledWith({}, undefined);
|
expect(userModel.find).toHaveBeenCalledWith({}, undefined);
|
||||||
expect(result).toEqualPayload(usersWithRoles);
|
expect(result).toEqualPayload(usersWithRoles);
|
||||||
|
@ -112,7 +112,7 @@ export class User extends UserStub {
|
|||||||
roles: string[];
|
roles: string[];
|
||||||
|
|
||||||
@Transform(({ obj }) => obj.avatar?.toString() || null)
|
@Transform(({ obj }) => obj.avatar?.toString() || null)
|
||||||
avatar?: string;
|
avatar?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema({ timestamps: true })
|
@Schema({ timestamps: true })
|
||||||
|
@ -82,7 +82,7 @@ describe('AuthService', () => {
|
|||||||
{},
|
{},
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
expect(result.id).toBe(user.id);
|
expect(result!.id).toBe(user!.id);
|
||||||
});
|
});
|
||||||
it('should not validate user if the provided password is incorrect', async () => {
|
it('should not validate user if the provided password is incorrect', async () => {
|
||||||
const result = await authService.validateUser(
|
const result = await authService.validateUser(
|
||||||
|
@ -150,7 +150,7 @@ describe('InvitationService', () => {
|
|||||||
const role = await roleRepository.findOne({});
|
const role = await roleRepository.findOne({});
|
||||||
const newInvitation: InvitationCreateDto = {
|
const newInvitation: InvitationCreateDto = {
|
||||||
email: 'test@testland.tst',
|
email: 'test@testland.tst',
|
||||||
roles: [role.id.toString()],
|
roles: [role!.id.toString()],
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.spyOn(invitationRepository, 'create');
|
jest.spyOn(invitationRepository, 'create');
|
||||||
|
@ -19,7 +19,7 @@ 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 { Model, ModelModel } from '../schemas/model.schema';
|
import { Model, ModelFull, ModelModel } from '../schemas/model.schema';
|
||||||
import { Permission, PermissionModel } from '../schemas/permission.schema';
|
import { Permission, PermissionModel } from '../schemas/permission.schema';
|
||||||
|
|
||||||
import { ModelService } from './model.service';
|
import { ModelService } from './model.service';
|
||||||
@ -28,7 +28,7 @@ describe('ModelService', () => {
|
|||||||
let modelService: ModelService;
|
let modelService: ModelService;
|
||||||
let modelRepository: ModelRepository;
|
let modelRepository: ModelRepository;
|
||||||
let permissionRepository: PermissionRepository;
|
let permissionRepository: PermissionRepository;
|
||||||
let model: Model;
|
let model: Model | null;
|
||||||
let permissions: Permission[];
|
let permissions: Permission[];
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
@ -49,7 +49,7 @@ describe('ModelService', () => {
|
|||||||
module.get<PermissionRepository>(PermissionRepository);
|
module.get<PermissionRepository>(PermissionRepository);
|
||||||
modelRepository = module.get<ModelRepository>(ModelRepository);
|
modelRepository = module.get<ModelRepository>(ModelRepository);
|
||||||
model = await modelRepository.findOne({ name: 'ContentType' });
|
model = await modelRepository.findOne({ name: 'ContentType' });
|
||||||
permissions = await permissionRepository.find({ model: model.id });
|
permissions = await permissionRepository.find({ model: model!.id });
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(closeInMongodConnection);
|
afterAll(closeInMongodConnection);
|
||||||
@ -58,7 +58,7 @@ describe('ModelService', () => {
|
|||||||
|
|
||||||
describe('findOneAndPopulate', () => {
|
describe('findOneAndPopulate', () => {
|
||||||
it('should find a model and populate its permissions', async () => {
|
it('should find a model and populate its permissions', async () => {
|
||||||
const result = await modelService.findOneAndPopulate(model.id);
|
const result = await modelService.findOneAndPopulate(model!.id);
|
||||||
expect(result).toEqualPayload({
|
expect(result).toEqualPayload({
|
||||||
...modelFixtures.find(({ name }) => name === 'ContentType'),
|
...modelFixtures.find(({ name }) => name === 'ContentType'),
|
||||||
permissions,
|
permissions,
|
||||||
@ -74,12 +74,12 @@ describe('ModelService', () => {
|
|||||||
const modelsWithPermissions = models.reduce((acc, currModel) => {
|
const modelsWithPermissions = models.reduce((acc, currModel) => {
|
||||||
acc.push({
|
acc.push({
|
||||||
...currModel,
|
...currModel,
|
||||||
permissions: permissions.filter((permission) => {
|
permissions: permissions.filter(
|
||||||
return permission.model === currModel.id;
|
(permission) => permission.model === currModel.id,
|
||||||
}),
|
),
|
||||||
});
|
});
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, [] as ModelFull[]);
|
||||||
expect(modelRepository.findAndPopulate).toHaveBeenCalledWith(
|
expect(modelRepository.findAndPopulate).toHaveBeenCalledWith(
|
||||||
{},
|
{},
|
||||||
undefined,
|
undefined,
|
||||||
|
@ -103,16 +103,15 @@ describe('PasswordResetService', () => {
|
|||||||
}).compile();
|
}).compile();
|
||||||
passwordResetService =
|
passwordResetService =
|
||||||
module.get<PasswordResetService>(PasswordResetService);
|
module.get<PasswordResetService>(PasswordResetService);
|
||||||
|
|
||||||
mailerService = module.get<MailerService>(MailerService);
|
mailerService = module.get<MailerService>(MailerService);
|
||||||
jwtService = module.get<JwtService>(JwtService);
|
jwtService = module.get<JwtService>(JwtService);
|
||||||
userModel = module.get<Model<User>>(getModelToken('User'));
|
userModel = module.get<Model<User>>(getModelToken('User'));
|
||||||
});
|
});
|
||||||
afterAll(async () => {
|
|
||||||
await closeInMongodConnection();
|
afterAll(closeInMongodConnection);
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(jest.clearAllMocks);
|
afterEach(jest.clearAllMocks);
|
||||||
|
|
||||||
describe('requestReset', () => {
|
describe('requestReset', () => {
|
||||||
it('should send an email with a token', async () => {
|
it('should send an email with a token', async () => {
|
||||||
const sendMailSpy = jest.spyOn(mailerService, 'sendMail');
|
const sendMailSpy = jest.spyOn(mailerService, 'sendMail');
|
||||||
@ -152,8 +151,8 @@ describe('PasswordResetService', () => {
|
|||||||
expect(verifySpy).toHaveBeenCalled();
|
expect(verifySpy).toHaveBeenCalled();
|
||||||
|
|
||||||
const user = await userModel.findOne({ email: users[0].email });
|
const user = await userModel.findOne({ email: users[0].email });
|
||||||
expect(user.resetToken).toBeNull();
|
expect(user!.resetToken).toBeNull();
|
||||||
expect(compareSync('newPassword', user.password)).toBeTruthy();
|
expect(compareSync('newPassword', user!.password)).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -29,7 +29,7 @@ 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, RoleModel } from '../schemas/role.schema';
|
||||||
import { User, UserModel } from '../schemas/user.schema';
|
import { User, UserFull, UserModel } from '../schemas/user.schema';
|
||||||
|
|
||||||
import { PermissionService } from './permission.service';
|
import { PermissionService } from './permission.service';
|
||||||
import { RoleService } from './role.service';
|
import { RoleService } from './role.service';
|
||||||
@ -39,7 +39,7 @@ describe('UserService', () => {
|
|||||||
let userService: UserService;
|
let userService: UserService;
|
||||||
let roleRepository: RoleRepository;
|
let roleRepository: RoleRepository;
|
||||||
let userRepository: UserRepository;
|
let userRepository: UserRepository;
|
||||||
let user: User;
|
let user: User | null;
|
||||||
let allRoles: Role[];
|
let allRoles: Role[];
|
||||||
const FIELDS_TO_IGNORE: string[] = [
|
const FIELDS_TO_IGNORE: string[] = [
|
||||||
...IGNORED_TEST_FIELDS,
|
...IGNORED_TEST_FIELDS,
|
||||||
@ -99,15 +99,15 @@ describe('UserService', () => {
|
|||||||
describe('findOneAndPopulate', () => {
|
describe('findOneAndPopulate', () => {
|
||||||
it('should find one user and populate its role', async () => {
|
it('should find one user and populate its role', async () => {
|
||||||
jest.spyOn(userRepository, 'findOneAndPopulate');
|
jest.spyOn(userRepository, 'findOneAndPopulate');
|
||||||
const result = await userService.findOneAndPopulate(user.id);
|
const result = await userService.findOneAndPopulate(user!.id);
|
||||||
expect(userRepository.findOneAndPopulate).toHaveBeenCalledWith(
|
expect(userRepository.findOneAndPopulate).toHaveBeenCalledWith(
|
||||||
user.id,
|
user!.id,
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
expect(result).toEqualPayload(
|
expect(result).toEqualPayload(
|
||||||
{
|
{
|
||||||
...userFixtures.find(({ username }) => username === 'admin'),
|
...userFixtures.find(({ username }) => username === 'admin'),
|
||||||
roles: allRoles.filter(({ id }) => user.roles.includes(id)),
|
roles: allRoles.filter(({ id }) => user!.roles.includes(id)),
|
||||||
},
|
},
|
||||||
FIELDS_TO_IGNORE,
|
FIELDS_TO_IGNORE,
|
||||||
);
|
);
|
||||||
@ -120,13 +120,17 @@ describe('UserService', () => {
|
|||||||
jest.spyOn(userRepository, 'findPageAndPopulate');
|
jest.spyOn(userRepository, 'findPageAndPopulate');
|
||||||
const allUsers = await userRepository.findAll();
|
const allUsers = await userRepository.findAll();
|
||||||
const result = await userService.findPageAndPopulate({}, pageQuery);
|
const result = await userService.findPageAndPopulate({}, pageQuery);
|
||||||
const usersWithRoles = allUsers.reduce((acc, currUser) => {
|
const usersWithRoles = allUsers.reduce(
|
||||||
|
(acc, { avatar: _avatar, roles: _roles, ...rest }) => {
|
||||||
acc.push({
|
acc.push({
|
||||||
...currUser,
|
...rest,
|
||||||
roles: allRoles.filter(({ id }) => user.roles.includes(id)),
|
roles: allRoles.filter(({ id }) => user?.roles?.includes(id)),
|
||||||
|
avatar: null,
|
||||||
});
|
});
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
},
|
||||||
|
[] as UserFull[],
|
||||||
|
);
|
||||||
|
|
||||||
expect(userRepository.findPageAndPopulate).toHaveBeenCalledWith(
|
expect(userRepository.findPageAndPopulate).toHaveBeenCalledWith(
|
||||||
{},
|
{},
|
||||||
|
@ -55,7 +55,7 @@ export type RecursivePartial<T> = {
|
|||||||
: T[P];
|
: T[P];
|
||||||
};
|
};
|
||||||
//base controller validator types
|
//base controller validator types
|
||||||
type TAllowedKeys<T, TStub, TValue = string[]> = {
|
type TAllowedKeys<T, TStub, TValue = (string | null | undefined)[]> = {
|
||||||
[key in keyof Record<
|
[key in keyof Record<
|
||||||
TFilterKeysOfType<
|
TFilterKeysOfType<
|
||||||
TFilterPopulateFields<TFilterKeysOfNeverType<T>, TStub>,
|
TFilterPopulateFields<TFilterKeysOfNeverType<T>, TStub>,
|
||||||
@ -69,13 +69,17 @@ export type TValidateProps<T, TStub> = {
|
|||||||
dto:
|
dto:
|
||||||
| Partial<TAllowedKeys<T, TStub>>
|
| Partial<TAllowedKeys<T, TStub>>
|
||||||
| Partial<TAllowedKeys<T, TStub, string>>;
|
| Partial<TAllowedKeys<T, TStub, string>>;
|
||||||
allowedIds: Partial<TAllowedKeys<T, TStub> & TAllowedKeys<T, TStub, string>>;
|
allowedIds: TAllowedKeys<T, TStub> &
|
||||||
|
TAllowedKeys<T, TStub, string | null | undefined>;
|
||||||
};
|
};
|
||||||
|
|
||||||
//populate types
|
//populate types
|
||||||
export type TFilterPopulateFields<T, TStub> = Omit<
|
export type TFilterPopulateFields<T, TStub> = Omit<
|
||||||
T,
|
T,
|
||||||
TFilterKeysOfType<TStub, string | number | boolean | object>
|
TFilterKeysOfType<
|
||||||
|
TStub,
|
||||||
|
null | undefined | string | number | boolean | object
|
||||||
|
>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//search filter types
|
//search filter types
|
||||||
|
Loading…
Reference in New Issue
Block a user