Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server
1 result
Show changes
Showing
with 1568 additions and 79 deletions
import { HttpModule } from '@nestjs/common';
import { HttpModule, HttpStatus } from '@nestjs/common';
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { Types } from 'mongoose';
import { ConfigurationModule } from '../../configuration/configuration.module';
import { CreateJobDto } from '../dto/create-job.dto';
import { Job } from '../schemas/job.schema';
import { User } from '../schemas/user.schema';
import { JobsService } from '../services/jobs.service';
import { UsersService } from '../services/users.service';
import { JobsController } from './jobs.controller';
describe('JobsController', () => {
......@@ -15,6 +17,19 @@ describe('JobsController', () => {
findAll: jest.fn(),
findByName: jest.fn(),
create: jest.fn(),
findOne: jest.fn(),
deleteOneId: jest.fn(),
findAllUnvalidated: jest.fn(),
createJobFromAdmin: jest.fn(),
validate: jest.fn(),
update: jest.fn(),
mergeJob: jest.fn(),
deleteInvalidJob: jest.fn(),
};
const userServiceMock = {
populateJobswithUsers: jest.fn(),
isJobLinkedtoUser: jest.fn(),
};
beforeEach(async () => {
......@@ -25,10 +40,18 @@ describe('JobsController', () => {
provide: JobsService,
useValue: jobServiceMock,
},
{
provide: UsersService,
useValue: userServiceMock,
},
{
provide: getModelToken('Job'),
useValue: Job,
},
{
provide: getModelToken('User'),
useValue: User,
},
],
controllers: [JobsController],
}).compile();
......@@ -65,6 +88,7 @@ describe('JobsController', () => {
it('should create job `Dev`', async () => {
const newJob: CreateJobDto = {
name: 'Dev',
hasPersonalOffer: false,
};
const newCreatedJob: Job = {
name: 'Dev',
......@@ -73,12 +97,14 @@ describe('JobsController', () => {
};
jobServiceMock.findByName.mockResolvedValueOnce(null);
jobServiceMock.create.mockResolvedValueOnce(newCreatedJob);
const createReply = await controller.createJob(newJob);
const req = { user: { _id: '6036721022462b001334c4bb' } };
const createReply = await controller.createJob(req, newJob);
expect(createReply).toEqual(newCreatedJob);
});
it('should throw error on already existing job `Dev`', async () => {
const newJob: CreateJobDto = {
name: 'Dev',
hasPersonalOffer: false,
};
jobServiceMock.findByName.mockResolvedValueOnce({
_id: Types.ObjectId('6231aefe76598527c8d0b5a7'),
......@@ -87,7 +113,8 @@ describe('JobsController', () => {
hasPersonalOffer: false,
});
try {
await controller.createJob(newJob);
const req = { user: { _id: '6036721022462b001334c4bb' } };
await controller.createJob(req, newJob);
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Job already exist');
......@@ -95,4 +122,159 @@ describe('JobsController', () => {
}
});
});
describe('Create Job', () => {
it('should create a job', async () => {
jobServiceMock.findByName.mockResolvedValueOnce(null);
jobServiceMock.create.mockResolvedValueOnce({
_id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
name: 'Dev',
validated: true,
});
const req = { user: { _id: '6036721022462b001334c4bb', role: 0 } };
const reply = await controller.createJob(req, { name: 'Dev', hasPersonalOffer: true });
expect(reply).toBeTruthy();
});
it('should not create if job already exists', async () => {
jobServiceMock.findByName.mockResolvedValueOnce({
_id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
name: 'Dev',
validated: true,
});
const req = { user: { _id: '6036721022462b001334c4bb', role: 0 } };
try {
await controller.createJob(req, { name: 'Dev', hasPersonalOffer: true });
} catch (e) {
expect(e.message).toBe('Job already exist');
expect(e.status).toBe(HttpStatus.UNPROCESSABLE_ENTITY);
}
});
it('should call create with send notification to true if admin', async () => {
jobServiceMock.findByName.mockResolvedValueOnce(null);
jobServiceMock.create.mockResolvedValueOnce({
_id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
name: 'Dev',
validated: true,
});
const req = { user: { _id: '6036721022462b001334c4bb', role: 1 } };
const job = { name: 'Dev', hasPersonalOffer: true };
const reply = await controller.createJob(req, job);
expect(reply).toBeTruthy();
expect(jobServiceMock.create).toHaveBeenCalledWith(job, true, true, false);
});
});
describe('Validate Job', () => {
it('should validate a given job', async () => {
jobServiceMock.validate.mockResolvedValueOnce({
_id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
name: 'Dev',
validated: true,
});
expect(await controller.validateJob({ id: '6231aefe76598527c8d0b5bc' })).toBeTruthy();
});
});
describe('Get Jobs', () => {
it('should call all validated jobs and populate them with users attached to it', async () => {
const spyer = jest.spyOn(userServiceMock, 'populateJobswithUsers');
jobServiceMock.findAll.mockResolvedValueOnce([
{
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Dev',
validated: true,
},
{
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Scrum',
validated: true,
},
]);
await controller.findValidatedJobs();
expect(jobServiceMock.findAll.mock.calls.length).toBe(2);
expect(spyer.mock.calls.length).toBe(1);
});
it('should call all unvalidated jobs and populate them with users attached to it', async () => {
const spyer = jest.spyOn(userServiceMock, 'populateJobswithUsers');
jobServiceMock.findAllUnvalidated.mockResolvedValueOnce([
{
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Dev',
validated: false,
},
{
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Scrum',
validated: false,
},
]);
await controller.findUnvalidatedJobs();
expect(jobServiceMock.findAllUnvalidated.mock.calls.length).toBe(1);
expect(spyer.mock.calls.length).toBe(2);
});
});
describe('Edit Job', () => {
it('should update job', async () => {
jobServiceMock.update.mockResolvedValueOnce({
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'DevMod',
validated: true,
});
expect(
await controller.updateJob('6231aefe76598527c8d0b5bc', { name: 'DevMod', hasPersonalOffer: false })
).toBeTruthy();
});
it('should delete an unvalidated job and replace all its occurence with a chosen validated job', async () => {
jobServiceMock.mergeJob.mockResolvedValueOnce({
_id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
name: 'Dev',
validated: true,
});
jobServiceMock.deleteInvalidJob.mockResolvedValueOnce({
n: 1,
ok: 1,
deletedCount: 1,
});
const reply = await controller.mergeJob({
sourceJobId: '6231aefe76598527c8d0b5ba',
targetJobId: '6231aefe76598527c8d0b5bc',
});
expect(reply).toBeTruthy();
});
});
describe('Delete Job', () => {
jobServiceMock.deleteOneId.mockResolvedValueOnce({
n: 1,
ok: 1,
deletedCount: 1,
});
it('should delete job', async () => {
jobServiceMock.findOne.mockResolvedValueOnce({
_id: Types.ObjectId('6231aefe76598527c8d0b5ba'),
name: 'Dev',
validated: true,
});
userServiceMock.isJobLinkedtoUser.mockResolvedValueOnce(false);
const reply = await controller.deleteJob({ id: '6231aefe76598527c8d0b5ba' });
expect(reply).toBeTruthy();
});
it('should not delete job if a user is linked', async () => {
jobServiceMock.findOne.mockResolvedValueOnce({
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Dev',
validated: true,
});
userServiceMock.isJobLinkedtoUser.mockResolvedValueOnce(true);
try {
await controller.deleteJob({ id: '6231aefe76598527c8d0b5bc' });
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('Cannot delete job. It has user(s) attached to it.');
expect(e.status).toEqual(HttpStatus.FORBIDDEN);
}
});
});
});
import { Body, Controller, Get, HttpException, HttpStatus, Logger, Post } from '@nestjs/common';
import { ApiParam } from '@nestjs/swagger';
import { CreateEmployerDto } from '../dto/create-employer.dto';
import {
Body,
Controller,
Delete,
Get,
HttpException,
HttpStatus,
Logger,
Param,
Post,
Put,
Request,
UseGuards,
} from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger';
import { MergeJobDto } from '../../admin/dto/merge-job.dto';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { hasAdminRole } from '../../shared/utils';
import { Roles } from '../decorators/roles.decorator';
import { CreateJobDto } from '../dto/create-job.dto';
import { RolesGuard } from '../guards/roles.guard';
import { IJob } from '../interfaces/job.interface';
import { Job } from '../schemas/job.schema';
import { JobsService } from '../services/jobs.service';
import { UsersService } from '../services/users.service';
@ApiTags('jobs')
@Controller('jobs')
export class JobsController {
private readonly logger = new Logger(JobsController.name);
constructor(private jobsService: JobsService) {}
constructor(private jobsService: JobsService, private usersService: UsersService) {}
/**
* Return every jobs
......@@ -22,18 +42,95 @@ export class JobsController {
/**
* Create a new job
* @param job {CreateEmployerDto}
* @param job {CreateJobDto}
* @returns {Job}
*/
@Post()
@UseGuards(JwtAuthGuard)
@ApiBearerAuth('JWT')
@ApiParam({ name: 'job', type: CreateJobDto, required: true })
public async createJob(@Body() job: CreateEmployerDto): Promise<Job> {
public async createJob(@Request() req, @Body() job: CreateJobDto): Promise<Job> {
this.logger.debug(`createJob: ${job.name}`);
const existingJob = await this.jobsService.findByName(job.name);
if (existingJob) {
this.logger.warn(`Job already exist: ${job.name}`);
throw new HttpException('Job already exist', HttpStatus.UNPROCESSABLE_ENTITY);
}
// if user is admin, do not send notification
if (hasAdminRole(req.user)) {
return this.jobsService.create(job, true, job.hasPersonalOffer, false);
}
return this.jobsService.create(job);
}
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiBearerAuth('JWT')
@Roles('admin')
@Get('validated')
@ApiOperation({ description: 'Get validated jobs populated with users attached to it' })
public async findValidatedJobs() {
return this.jobsService.findAll().then(async (jobs: IJob[]) => {
return this.usersService.populateJobswithUsers(jobs);
});
}
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiBearerAuth('JWT')
@Roles('admin')
@Get('unvalidated')
@ApiOperation({ description: 'Get unvalidated jobs populated with users attached to it' })
public async findUnvalidatedJobs() {
return this.jobsService.findAllUnvalidated().then(async (jobs: IJob[]) => {
return this.usersService.populateJobswithUsers(jobs);
});
}
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiBearerAuth('JWT')
@Roles('admin')
@Post('validate/:id')
@ApiParam({ name: 'id', type: String, required: true })
@ApiOperation({ description: 'Validate job' })
public async validateJob(@Param() params) {
return this.jobsService.validate(params.id);
}
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiBearerAuth('JWT')
@Roles('admin')
@Put('merge')
public async mergeJob(@Body() mergeJob: MergeJobDto) {
this.logger.debug('mergeJob');
return this.jobsService.mergeJob(mergeJob);
}
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiBearerAuth('JWT')
@Roles('admin')
@Put(':id')
public async updateJob(@Param('id') id: string, @Body() body: CreateJobDto) {
this.logger.debug('updateJob');
return this.jobsService.update(id, body);
}
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@Delete(':id')
@ApiBearerAuth('JWT')
@ApiParam({ name: 'id', type: String, required: true })
public async deleteJob(@Param() params) {
// look for job
const researchedJob = await this.jobsService.findOne(params.id);
// look for any relations within user collection, reject action if found
if (researchedJob !== null) {
const isJobLinked = await this.usersService.isJobLinkedtoUser(researchedJob._id);
if (!isJobLinked) {
return this.jobsService.deleteOneId(params.id);
} else {
throw new HttpException('Cannot delete job. It has user(s) attached to it.', HttpStatus.FORBIDDEN);
}
} else {
throw new HttpException('Job does not exists', HttpStatus.NOT_FOUND);
}
}
}
import { HttpModule } from '@nestjs/common';
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { Types } from 'mongoose';
import { CategoriesFormationsServiceMock } from '../../../test/mock/services/categoriesFormations.mock.service';
import { CategoriesFormationsService } from '../../categories/services/categories-formations.service';
import { ConfigurationModule } from '../../configuration/configuration.module';
import { MailerService } from '../../mailer/mailer.service';
import { ParametersService } from '../../parameters/parameters.service';
import { Parameters } from '../../parameters/schemas/parameters.schema';
import { SearchModule } from '../../search/search.module';
import { Structure } from '../../structures/schemas/structure.schema';
import { StructuresService } from '../../structures/services/structures.service';
import { StructuresSearchService } from '../../structures/services/structures-search.service';
import { StructuresService } from '../../structures/services/structures.service';
import { TempUser } from '../../temp-user/temp-user.schema';
import { TempUserService } from '../../temp-user/temp-user.service';
import { ProfileDto } from '../dto/profile.dto';
import { UpdateDetailsDto } from '../dto/update-details.dto';
import { User } from '../schemas/user.schema';
import { UsersController } from './users.controller';
import { UsersService } from '../services/users.service';
import { CategoriesFormationsService } from '../../categories/services/categories-formations.service';
import { CategoriesFormationsServiceMock } from '../../../test/mock/services/categoriesFormations.mock.service';
import { EmployerService } from '../services/employer.service';
import { JobsService } from '../services/jobs.service';
import { ProfileDto } from '../dto/profile.dto';
import { Types } from 'mongoose';
import { UsersService } from '../services/users.service';
import { UsersController } from './users.controller';
describe('UsersController', () => {
let controller: UsersController;
......@@ -33,6 +36,7 @@ describe('UsersController', () => {
const userServiceMock = {
updateUserProfile: jest.fn(),
findOne: jest.fn(),
updateUserDetails: jest.fn(),
};
beforeEach(async () => {
......@@ -44,6 +48,7 @@ describe('UsersController', () => {
StructuresSearchService,
MailerService,
TempUserService,
ParametersService,
{
provide: UsersService,
useValue: userServiceMock,
......@@ -72,6 +77,10 @@ describe('UsersController', () => {
provide: getModelToken('User'),
useValue: User,
},
{
provide: getModelToken('Parameters'),
useValue: Parameters,
},
],
controllers: [UsersController],
}).compile();
......@@ -154,6 +163,40 @@ describe('UsersController', () => {
job: Types.ObjectId('6231aefe76598527c8d0b5be'),
});
const reply = await controller.setProfile({ user: { _id: '36', email: 'a@a.com' } }, profile);
console.log(reply);
expect(reply).toBeTruthy();
});
});
describe('update details', () => {
it('should update details', async () => {
const newDetails: UpdateDetailsDto = {
name: 'Jean',
surname: 'Jacque',
phone: '0605040302',
};
userServiceMock.updateUserDetails.mockResolvedValueOnce({
_id: Types.ObjectId('620e4ffa72389045b02ac854'),
structuresLink: [Types.ObjectId('620e5236f25755550cb86dfd')],
structureOutdatedMailSent: [],
pendingStructuresLink: [Types.ObjectId('61e926192ac971550065e275')],
phone: '06 06 06 06 06',
newEmail: null,
changeEmailToken: null,
role: 1,
resetPasswordToken: null,
surname: 'ADMIN',
name: 'Admin',
validationToken: null,
emailVerified: true,
email: 'admin@admin.com',
password: '$2a$12$vLQjJ9zAWyUwiXLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
__v: 11,
employer: Types.ObjectId('6231aefe76598527c8d0b5a7'),
job: Types.ObjectId('6231aefe76598527c8d0b5be'),
});
const reply = await controller.updateDetails({ user: { _id: '36', email: 'a@a.com' } }, newDetails);
console.log(reply);
expect(reply).toBeTruthy();
});
});
......
......@@ -13,7 +13,7 @@ import {
Request,
UseGuards,
} from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { PasswordChangeDto } from '../dto/change-password.dto';
import { EmailChangeDto } from '../dto/change-email.dto';
......@@ -29,6 +29,10 @@ import { ProfileDto } from '../dto/profile.dto';
import { EmployerService } from '../services/employer.service';
import { JobsService } from '../services/jobs.service';
import { IUser } from '../interfaces/user.interface';
import { UpdateDetailsDto } from '../dto/update-details.dto';
import { User } from '../schemas/user.schema';
import { DescriptionDto } from '../dto/description.dto';
@ApiTags('users')
@Controller('users')
export class UsersController {
private readonly logger = new Logger(UsersController.name);
......@@ -53,7 +57,7 @@ export class UsersController {
@UseGuards(JwtAuthGuard)
@ApiBearerAuth('JWT')
@ApiOperation({ description: 'Set user profile' })
@ApiOperation({ description: 'Set user profile with employer and job' })
@ApiResponse({ status: HttpStatus.OK, description: 'Return user profil' })
@ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'Job does not exist' })
@ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'Employer does not exist' })
......@@ -74,6 +78,19 @@ export class UsersController {
return this.usersService.findOne(req.user.email);
}
@UseGuards(JwtAuthGuard)
@ApiBearerAuth('JWT')
@ApiOperation({ description: 'Updates name, surname and phone number of a user' })
@ApiBody({ type: UpdateDetailsDto })
@ApiResponse({ status: HttpStatus.CREATED, description: 'Return user profil' })
@ApiResponse({ status: HttpStatus.NOT_FOUND, description: 'User not found' })
@ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'Missing parametter' })
@Post('details')
public async updateDetails(@Request() req, @Body() details: UpdateDetailsDto): Promise<User | HttpException> {
this.logger.debug('updateProfile details');
return this.usersService.updateUserDetails(req.user._id, details);
}
@Post()
@ApiResponse({ status: 201, description: 'User created' })
public async create(@Body() createUserDto: CreateUserDto) {
......@@ -127,7 +144,7 @@ export class UsersController {
@Post('change-email')
@ApiResponse({ status: 201, description: 'Email confirmation send' })
@ApiResponse({ status: 401, description: 'Invalid Email' })
public async changeEmail(@Request() req, @Body() emailChangeDto: EmailChangeDto) {
public async changeEmail(@Request() _req, @Body() emailChangeDto: EmailChangeDto) {
return this.usersService.changeUserEmail(emailChangeDto);
}
......@@ -135,7 +152,7 @@ export class UsersController {
@Post('verify-change-email')
@ApiResponse({ status: 201, description: 'Email changed' })
@ApiResponse({ status: 401, description: 'Invalid Token' })
public async verifyAndUpdateEmail(@Request() req, @Query('token') token: string) {
public async verifyAndUpdateEmail(@Request() _req, @Query('token') token: string) {
return this.usersService.verifyAndUpdateUserEmail(token);
}
......@@ -152,7 +169,7 @@ export class UsersController {
}
@Post('verify-exist-user')
public async verifyUserExist(@Request() req, @Body() email: { newMail: string }) {
public async verifyUserExist(@Request() _req, @Body() email: { newMail: string }) {
return this.usersService.verifyUserExist(email.newMail);
}
......@@ -175,4 +192,15 @@ export class UsersController {
public async dataConsentValidation(@Request() req): Promise<Structure[]> {
return this.structureService.getAllDataConsentPendingStructures(req.user);
}
@ApiResponse({ status: HttpStatus.CREATED, description: 'Description updated' })
@ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: 'Unauthorized' })
@UseGuards(JwtAuthGuard)
@ApiBearerAuth('JWT')
@ApiOperation({ description: 'Updates description of a user' })
@ApiBody({ type: DescriptionDto })
@Post('description')
public async updateDescription(@Req() req, @Body() body: DescriptionDto): Promise<User> {
return this.usersService.updateDescription(req.user._id, body);
}
}
import { IsNotEmpty, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsString } from 'class-validator';
export class CreateEmployerDto {
@ApiProperty({ type: String, example: 'PIMMS Vaise' })
......
import { IsNotEmpty, IsString } from 'class-validator';
import { IsBoolean, IsNotEmpty, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateJobDto {
......@@ -6,4 +6,8 @@ export class CreateJobDto {
@IsNotEmpty()
@IsString()
readonly name: string;
@ApiProperty({ type: Boolean, example: false })
@IsNotEmpty()
@IsBoolean()
readonly hasPersonalOffer: boolean;
}
import { ApiProperty } from '@nestjs/swagger';
import { IsString, MaxLength } from 'class-validator';
export class DescriptionDto {
@IsString()
@MaxLength(500)
@ApiProperty({ example: 'Some information about me...' })
description: string;
}
import { Prop } from '@nestjs/mongoose';
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
export class UpdateDetailsDto {
@IsString()
@Prop({ required: true })
@ApiProperty({ example: 'Jean' })
name: string;
@IsString()
@Prop({ required: true })
@ApiProperty({ example: 'Dupont' })
surname: string;
@IsString()
@Prop({ required: true })
@ApiProperty({ example: '0601020304' })
phone: string;
}
import { Document } from 'mongoose';
import { Employer } from '../schemas/employer.schema';
export type IEmployer = Employer & Document;
import { Document } from 'mongoose';
import { Job } from '../schemas/job.schema';
export type IJob = Job & Document;
......@@ -57,6 +57,9 @@ export class User {
@Prop({ type: Types.ObjectId, ref: 'Job' })
job: Job;
@Prop({ required: false })
description?: string;
}
export const UserSchema = SchemaFactory.createForClass(User);
......@@ -47,13 +47,22 @@ describe('EmployerSearchService Search cases', () => {
await service.dropIndex();
await service.createEmployerIndex();
await Promise.all(employers.map((employer: any) => service.indexEmployer(employer)));
await new Promise((r) => setTimeout(r, 1500));
});
it('should be defined', () => {
// wait for the new structures to be indexed before search
await service.refreshIndexStructure();
await new Promise((r) => setTimeout(r, 2000));
}, 10000);
it('should be defined', async () => {
// await new Promise((r) => setTimeout(r, 9000));
expect(service).toBeDefined();
});
// it('should index structures', async () => {
// // but we still need to wait the refresh to be done
// await new Promise((r) => setTimeout(r, 2000));
// }, 10000);
it('should find CARSAT', async () => {
const res = await service.search('CARSAT');
expect(res[0].name).toBe('CARSAT');
......
import { HttpModule, HttpStatus } from '@nestjs/common';
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { AxiosResponse } from 'axios';
import { Types } from 'mongoose';
import { ConfigurationModule } from '../../configuration/configuration.module';
import { MailerService } from '../../mailer/mailer.service';
import { CreateEmployerDto } from '../dto/create-employer.dto';
import { EmployerDocument } from '../schemas/employer.schema';
import { User } from '../schemas/user.schema';
import { EmployerSearchService } from './employer-search.service';
import { EmployerService } from './employer.service';
import { UsersService } from './users.service';
describe('EmployerService', () => {
let service: EmployerService;
let mailer: MailerService;
const mockEmployerSearchService = {
indexEmployer: jest.fn(),
......@@ -20,13 +26,18 @@ describe('EmployerService', () => {
const mockEmployerModel = {
create: jest.fn(),
findOne: jest.fn(),
findById: jest.fn(),
deleteOne: jest.fn(),
find: jest.fn(() => mockEmployerModel),
sort: jest.fn(() => mockEmployerModel),
};
const mockUserService = {
replaceEmployers: jest.fn(),
getAdmins: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [ConfigurationModule],
imports: [ConfigurationModule, HttpModule],
providers: [
EmployerService,
{
......@@ -37,9 +48,19 @@ describe('EmployerService', () => {
provide: getModelToken('Employer'),
useValue: mockEmployerModel,
},
{
provide: UsersService,
useValue: mockUserService,
},
{
provide: getModelToken('User'),
useValue: User,
},
MailerService,
],
}).compile();
service = module.get<EmployerService>(EmployerService);
mailer = module.get<MailerService>(MailerService);
});
it('should be defined', () => {
......@@ -62,35 +83,118 @@ describe('EmployerService', () => {
const reply = await service.findAll();
expect(reply.length).toBe(2);
});
it('findByName', async () => {
mockEmployerModel.findOne.mockResolvedValue({
it('findOne', async () => {
mockEmployerModel.findById.mockResolvedValueOnce({
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Sopra',
validated: true,
});
const reply = await service.findByName('Sopra');
const reply = await service.findOne('6231aefe76598527c8d0b5bc');
expect(reply).toBeTruthy();
});
it('findAllValidated', async () => {
mockEmployerModel.find.mockResolvedValueOnce([
{
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Sopra',
validated: true,
},
]);
const reply = await service.findAllValidated();
expect(reply.length).toBe(1);
});
it('create', async () => {
mockEmployerModel.create.mockResolvedValue({
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Sopra',
validated: true,
});
it('findAllUnvalidated', async () => {
mockEmployerModel.find.mockResolvedValueOnce([
{
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Sopra',
validated: false,
},
]);
const reply = await service.findAllValidated();
expect(reply.length).toBe(1);
});
it('finds all unvalidated employers', async () => {
mockEmployerModel.find.mockResolvedValueOnce([
{
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Metro',
validated: false,
},
]);
const reply = await service.findAllUnvalidated();
expect(reply[0].validated).toBeFalsy;
});
it('finds all validated employers', async () => {
mockEmployerModel.find.mockResolvedValueOnce([
{
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Metro',
validated: true,
},
{
_id: Types.ObjectId('6231aefe76598527c8d0b5b2'),
name: 'Sopra',
validated: true,
},
]);
const reply = await service.findAllUnvalidated();
expect(reply.length).toBe(2);
});
it('findByName', async () => {
mockEmployerModel.findOne.mockResolvedValue({
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Sopra',
validated: true,
});
const createJob: CreateEmployerDto = {
name: 'Sopra',
};
const reply = await service.create(createJob);
const reply = await service.findByName('Sopra');
expect(reply).toBeTruthy();
});
describe('createEmployer', () => {
it('create', async () => {
mockEmployerModel.create.mockResolvedValue({
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Sopra',
validated: false,
});
mockEmployerModel.findOne.mockResolvedValue({
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Sopra',
validated: false,
});
const createEmployer: CreateEmployerDto = {
name: 'Sopra',
};
jest.spyOn(service, 'sendAdminCreateNotification').mockResolvedValueOnce();
const reply = await service.create(createEmployer);
expect(reply).toBeTruthy();
expect(service.sendAdminCreateNotification).toBeCalledTimes(1);
});
it('should create validated employer and not send email to admins', async () => {
mockEmployerModel.create.mockResolvedValue({
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Sopra',
validated: false,
});
mockEmployerModel.findOne.mockResolvedValue({
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Sopra',
validated: false,
});
const createEmployer: CreateEmployerDto = {
name: 'Sopra',
};
const reply = await service.create(createEmployer, true, false);
expect(reply).toBeTruthy();
});
});
it('delete', async () => {
mockEmployerModel.findOne.mockResolvedValueOnce({
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
......@@ -145,4 +249,218 @@ describe('EmployerService', () => {
expect(reply.length).toBe(2);
});
});
describe('mergeEmployer', () => {
it('should delete source employer', async () => {
const reply = {
_id: Types.ObjectId('623aed68c5d45b6fbbaa7e61'),
name: 'Metro',
validated: true,
};
mockEmployerModel.findById
.mockResolvedValueOnce({
_id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
name: 'Sopra',
validated: false,
})
.mockResolvedValueOnce(reply);
jest.spyOn(service, 'deleteInvalidEmployer').mockRejectedValueOnce({});
mockUserService.replaceEmployers.mockResolvedValueOnce(null);
expect(
await service.mergeEmployer({
sourceEmployerId: '623aed68c5d45b6fbbaa7e60',
targetEmployerId: '623aed68c5d45b6fbbaa7e61',
})
).toEqual(reply);
});
it('should delete source employer', async () => {
mockEmployerModel.findById.mockResolvedValueOnce(null).mockResolvedValueOnce(null);
jest.spyOn(service, 'deleteInvalidEmployer').mockRejectedValueOnce({});
mockUserService.replaceEmployers.mockResolvedValueOnce(null);
try {
await service.mergeEmployer({
sourceEmployerId: '623aed68c5d45b6fbbaa7e60',
targetEmployerId: '623aed68c5d45b6fbbaa7e61',
});
} catch (e) {
expect(e.message).toBe('Cannot operate on employer.');
expect(e.status).toBe(HttpStatus.NOT_FOUND);
}
});
});
describe('sendAdminCreateNotification', () => {
it('should sendAdminCreateNotification', async () => {
const employer = {
_id: Types.ObjectId('6231aefe76598527c8d0b5bc'),
name: 'Metro',
validated: true,
};
const result: AxiosResponse = {
data: {
status: 200,
content: {
success: true,
response: [7010],
},
},
status: 200,
statusText: 'OK',
headers: {},
config: {},
};
jest.spyOn(mailer, 'send').mockResolvedValueOnce(result);
const spyer = jest.spyOn(mailer, 'send');
mockUserService.getAdmins.mockResolvedValueOnce([
{
_id: '6231aefe76598527c8d0b5bc',
validationToken:
'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
emailVerified: true,
email: 'admin@admin.com',
password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
role: 0,
name: 'admin',
surname: 'admin',
personalOffers: [],
},
]);
await service.sendAdminCreateNotification(
employer as EmployerDocument,
'adminEmployerCreate.ejs',
'adminEmployerCreate.json'
);
expect(spyer.mock.calls.length).toBe(1);
});
});
describe('validate', () => {
it('should validate employer', async () => {
mockEmployerModel.findById.mockResolvedValueOnce({
_id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
name: 'Sopra',
validated: false,
save: jest.fn().mockResolvedValueOnce(null),
});
const employer = await service.validate('623aed68c5d45b6fbbaa7e60');
expect(employer.validated).toBe(true);
});
it('should throw exception', async () => {
mockEmployerModel.findById.mockResolvedValueOnce(null);
try {
await service.validate('623aed68c5d45b6fbbaa7e60');
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Cannot validate employer. It might have been already validate');
expect(e.status).toBe(HttpStatus.NOT_FOUND);
}
});
});
describe('update', () => {
it('should update employer', async () => {
mockEmployerModel.findById.mockResolvedValueOnce({
_id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
name: 'Sopraaa',
validated: false,
save: jest.fn().mockResolvedValueOnce(null),
});
const employer = await service.update('623aed68c5d45b6fbbaa7e60', { name: 'Sopra' });
expect(employer.name).toBe('Sopra');
});
it('should throw exception', async () => {
mockEmployerModel.findById.mockResolvedValueOnce(null);
try {
await service.update('623aed68c5d45b6fbbaa7e60', { name: 'Sopra' });
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Cannot edit employer. It was not found in database.');
expect(e.status).toBe(HttpStatus.NOT_FOUND);
}
});
});
describe('deleteInvalidEmployer', () => {
it('should delete invalid employer', async () => {
mockEmployerModel.findById.mockResolvedValueOnce({
_id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
name: 'Sopra',
validated: false,
save: jest.fn().mockResolvedValueOnce(null),
});
mockEmployerSearchService.deleteIndex.mockResolvedValueOnce(null);
mockEmployerModel.deleteOne.mockResolvedValueOnce({
_id: Types.ObjectId('623aed68c5d45b6fbbaa7e60'),
name: 'Sopra',
validated: false,
save: jest.fn().mockResolvedValueOnce(null),
});
await service.deleteInvalidEmployer('6231aefe76598527c8d0b5bc');
expect(mockEmployerSearchService.deleteIndex).toBeCalled();
expect(mockEmployerModel.deleteOne).toBeCalled();
});
});
describe('deleteOneId', () => {
it('should delete ', async () => {
mockEmployerModel.findOne.mockResolvedValueOnce({
_id: '6231aefe76598527c8d0b5bc',
validationToken:
'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
emailVerified: true,
email: 'admin@admin.com',
password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
role: 0,
name: 'admin',
surname: 'admin',
personalOffers: [],
deleteOne: jest.fn().mockResolvedValueOnce({
_id: '6231aefe76598527c8d0b5bc',
validationToken:
'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
emailVerified: true,
email: 'admin@admin.com',
password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
role: 0,
name: 'admin',
surname: 'admin',
personalOffers: [],
}),
});
expect(await service.deleteOneId('6231aefe76598527c8d0b5bc')).toStrictEqual({
_id: '6231aefe76598527c8d0b5bc',
validationToken:
'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
emailVerified: true,
email: 'admin@admin.com',
password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
role: 0,
name: 'admin',
surname: 'admin',
personalOffers: [],
});
});
it('should throw an error ', async () => {
mockEmployerModel.findOne.mockResolvedValueOnce(null);
try {
expect(await service.deleteOneId('6231aefe76598527c8d0b5bc')).toStrictEqual({
_id: '6231aefe76598527c8d0b5bc',
validationToken:
'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
emailVerified: true,
email: 'admin@admin.com',
password: '$2a$12$vLQjJ9zAWyUwiFLeQDa6w.XzrlgPBhw.2GWrjog/yuEjIaZnQwmZu',
role: 0,
name: 'admin',
surname: 'admin',
personalOffers: [],
});
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Invalid employer id');
expect(e.status).toBe(HttpStatus.BAD_REQUEST);
}
});
});
});
import { Injectable, Logger } from '@nestjs/common';
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model, Query } from 'mongoose';
import * as ejs from 'ejs';
import { Model, Query, Types } from 'mongoose';
import { MergeEmployerDto } from '../../admin/dto/merge-employer.dto';
import { MailerService } from '../../mailer/mailer.service';
import { CreateEmployerDto } from '../dto/create-employer.dto';
import { IEmployer } from '../interfaces/employer.interface';
import { Employer, EmployerDocument } from '../schemas/employer.schema';
import { EmployerSearchService } from './employer-search.service';
import { UsersService } from './users.service';
@Injectable()
export class EmployerService {
......@@ -11,6 +16,8 @@ export class EmployerService {
constructor(
@InjectModel(Employer.name) private employerModel: Model<EmployerDocument>,
private readonly userService: UsersService,
private readonly mailerService: MailerService,
private readonly employerSearchService: EmployerSearchService
) {}
......@@ -19,19 +26,124 @@ export class EmployerService {
return this.employerModel.find().sort({ name: 1 });
}
public async findOne(idParam: string): Promise<EmployerDocument> {
this.logger.debug('findOne');
return await this.employerModel.findById(Types.ObjectId(idParam));
}
public async findAllUnvalidated(): Promise<Employer[]> {
this.logger.debug('findAllUnvalidated');
return this.employerModel.find({ validated: false });
}
public async findAllValidated(): Promise<IEmployer[]> {
this.logger.debug(`findAllValidated`);
return this.employerModel.find({ validated: true });
}
public async findByName(name: string): Promise<EmployerDocument> {
this.logger.debug('findByName');
return this.employerModel.findOne({ name });
}
public async create(employer: CreateEmployerDto, validated = false): Promise<Employer> {
public async create(employer: CreateEmployerDto, validated = false, sendAdminNotification = true): Promise<Employer> {
this.logger.debug(`createEmployer: ${employer.name}`);
await this.employerModel.create({ name: employer.name, validated: validated });
await this.employerModel.create({ name: employer.name, validated });
const document = await this.findByName(employer.name);
this.employerSearchService.indexEmployer(document);
if (sendAdminNotification) {
this.sendAdminCreateNotification(
document,
this.mailerService.config.templates.adminEmployerCreate.ejs,
this.mailerService.config.templates.adminEmployerCreate.json
);
}
return document;
}
public async sendAdminCreateNotification(
employer: EmployerDocument,
templateLocation: any,
jsonConfigLocation: any
): Promise<void> {
const config = this.mailerService.config;
const ejsPath = this.mailerService.getTemplateLocation(templateLocation);
const jsonConfig = this.mailerService.loadJsonConfig(jsonConfigLocation);
const html = await ejs.renderFile(ejsPath, {
config,
employerName: employer ? employer.name : '',
});
const admins = await this.userService.getAdmins();
admins.forEach((admin) => {
this.mailerService.send(admin.email, jsonConfig.subject, html);
});
}
public async validate(employerId: string): Promise<Employer> {
this.logger.debug(`validateEmployer: ${employerId}`);
const employer = await this.employerModel.findById(Types.ObjectId(employerId));
if (employer) {
employer.validated = true;
employer.save();
return employer;
} else {
throw new HttpException('Cannot validate employer. It might have been already validate', HttpStatus.NOT_FOUND);
}
}
public async update(employerId: string, newEmployer: CreateEmployerDto): Promise<Employer> {
this.logger.debug(`editEmployer: ${employerId}`);
const employer = await this.employerModel.findById(Types.ObjectId(employerId));
if (employer) {
employer.name = newEmployer.name;
employer.save();
return employer;
} else {
throw new HttpException('Cannot edit employer. It was not found in database.', HttpStatus.NOT_FOUND);
}
}
public async mergeEmployer({
sourceEmployerId,
targetEmployerId,
}: MergeEmployerDto): Promise<Employer | HttpException> {
this.logger.debug(`mergeEmployer: ${sourceEmployerId} into ${targetEmployerId}`);
const sourceEmployer = await this.employerModel.findById(Types.ObjectId(sourceEmployerId));
const targetEmployer = await this.employerModel.findById(Types.ObjectId(targetEmployerId));
if (targetEmployer && sourceEmployer) {
this.userService.replaceEmployers(sourceEmployer, targetEmployer);
if (!sourceEmployer.validated) {
this.deleteInvalidEmployer(sourceEmployerId);
}
return targetEmployer;
} else {
throw new HttpException('Cannot operate on employer.', HttpStatus.NOT_FOUND);
}
}
public async deleteInvalidEmployer(
id: string
): Promise<
Query<{
ok?: number;
n?: number;
deletedCount?: number;
}>
> {
this.logger.debug(`deleteInvalidEmployer: ${id}`);
const document = await this.employerModel.findById(Types.ObjectId(id));
this.employerSearchService.deleteIndex(document, document._id);
return this.employerModel.deleteOne({ _id: id });
}
public async deleteOneId(id: string): Promise<Employer> {
const employer = await this.employerModel.findOne({ _id: id });
if (!employer) {
throw new HttpException('Invalid employer id', HttpStatus.BAD_REQUEST);
}
return employer.deleteOne();
}
public async deleteByName(
name: string
): Promise<
......
This diff is collapsed.
import { Injectable, Logger } from '@nestjs/common';
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import * as ejs from 'ejs';
import { Model, Query, Types } from 'mongoose';
import { MergeJobDto } from '../../admin/dto/merge-job.dto';
import { MailerService } from '../../mailer/mailer.service';
import { CreateJobDto } from '../dto/create-job.dto';
import { IJob } from '../interfaces/job.interface';
import { Job, JobDocument } from '../schemas/job.schema';
import { UsersService } from './users.service';
@Injectable()
export class JobsService {
private readonly logger = new Logger(JobsService.name);
constructor(@InjectModel(Job.name) private jobModel: Model<JobDocument>) {}
constructor(
@InjectModel(Job.name) private jobModel: Model<JobDocument>,
private readonly userService: UsersService,
private readonly mailerService: MailerService
) {}
public async findAll(filterValidetedJobs = true): Promise<Job[]> {
this.logger.debug(`findAll with filterValidetedJobs: ${filterValidetedJobs}`);
if (!filterValidetedJobs) {
public async findAll(filterValidatedJobs = true): Promise<IJob[]> {
this.logger.debug(`findAll with filterValidetedJobs: ${filterValidatedJobs}`);
if (!filterValidatedJobs) {
return this.jobModel.find();
} else {
return this.jobModel.find({ validated: true });
......@@ -24,8 +33,115 @@ export class JobsService {
return this.jobModel.findOne({ name });
}
public async create(job: CreateJobDto, validated = false, hasPersonalOffer = true): Promise<Job> {
this.logger.debug(`createJob: ${job.name}`);
return this.jobModel.create({ name: job.name, validated, hasPersonalOffer });
public async findOne(idParam: string): Promise<JobDocument> {
this.logger.debug('findOne');
return this.jobModel.findById(Types.ObjectId(idParam));
}
public async findAllUnvalidated(): Promise<IJob[]> {
this.logger.debug('findAllUnvalidated');
return this.jobModel.find({ validated: false });
}
public async create(
job: CreateJobDto,
validated = false,
hasPersonalOffer = false,
sendNotification = true
): Promise<Job> {
this.logger.debug(`createJob: ${job.name} | notificationSending ${sendNotification}`);
const result = this.jobModel
.create({ name: job.name, validated, hasPersonalOffer })
.then(async (postCreate: JobDocument) => {
if (sendNotification) {
this.sendAdminCreateNotification(
postCreate,
this.mailerService.config.templates.adminJobCreate.ejs,
this.mailerService.config.templates.adminJobCreate.json
);
}
return postCreate;
});
return result;
}
public async sendAdminCreateNotification(
job: JobDocument,
templateLocation: any,
jsonConfigLocation: any
): Promise<void> {
const config = this.mailerService.config;
const ejsPath = this.mailerService.getTemplateLocation(templateLocation);
const jsonConfig = this.mailerService.loadJsonConfig(jsonConfigLocation);
const html = await ejs.renderFile(ejsPath, {
config,
jobName: job ? job.name : '',
});
const admins = await this.userService.getAdmins();
admins.forEach((admin) => {
this.mailerService.send(admin.email, jsonConfig.subject, html);
});
}
public async validate(jobId: string): Promise<Job> {
this.logger.debug(`validateJob: ${jobId}`);
const job = await this.jobModel.findById(Types.ObjectId(jobId));
if (job) {
job.validated = true;
job.save();
return job;
} else {
throw new HttpException('Cannot validate job. It might have been already validate', HttpStatus.NOT_FOUND);
}
}
public async mergeJob({ sourceJobId, targetJobId }: MergeJobDto): Promise<Job | HttpException> {
this.logger.debug(`mergeJob: ${sourceJobId} into ${targetJobId}`);
const sourceJob = await this.jobModel.findById(Types.ObjectId(sourceJobId));
const targetJob = await this.jobModel.findById(Types.ObjectId(targetJobId));
if (targetJob && sourceJob) {
this.logger.debug(`Both jobs : ${sourceJob}, ${targetJob}`);
this.userService.replaceJobs(sourceJob, targetJob);
if (!sourceJob.validated) {
this.deleteInvalidJob(sourceJobId);
}
return targetJob;
} else {
throw new HttpException('Cannot operate on job.', HttpStatus.NOT_FOUND);
}
}
public async deleteInvalidJob(
id: string
): Promise<
Query<{
ok?: number;
n?: number;
deletedCount?: number;
}>
> {
this.logger.debug(`deleteInvalidJob: ${id}`);
return this.jobModel.deleteOne({ _id: id });
}
public async deleteOneId(id: string): Promise<Job> {
const job = await this.jobModel.findOne({ _id: id });
if (!job) {
throw new HttpException('Invalid job id', HttpStatus.BAD_REQUEST);
}
return job.deleteOne();
}
public async update(jobId: string, newJob: CreateJobDto): Promise<Job> {
this.logger.debug(`editJob: ${jobId}`);
const job = await this.jobModel.findById(Types.ObjectId(jobId));
if (job) {
job.name = newJob.name;
job.hasPersonalOffer = newJob.hasPersonalOffer;
job.save();
return job;
} else {
throw new HttpException('Cannot edit job. It was not found in database.', HttpStatus.NOT_FOUND);
}
}
}
......@@ -6,7 +6,8 @@ import * as bcrypt from 'bcrypt';
import { personalOffersDataMock } from '../../../test/mock/data/personalOffers.mock.data';
import { PersonalOfferDocument } from '../../personal-offers/schemas/personal-offer.schema';
import { usersMockData } from '../../../test/mock/data/users.mock.data';
import { userDetails, usersMockData } from '../../../test/mock/data/users.mock.data';
import { employersMockData } from '../../../test/mock/data/employers.mock.data';
import { LoginDto } from '../../auth/login-dto';
import { ConfigurationModule } from '../../configuration/configuration.module';
import { MailerModule } from '../../mailer/mailer.module';
......@@ -14,11 +15,25 @@ import { EmailChangeDto } from '../dto/change-email.dto';
import { CreateUserDto } from '../dto/create-user.dto';
import { User } from '../schemas/user.schema';
import { IUser } from '../interfaces/user.interface';
import { UpdateDetailsDto } from '../dto/update-details.dto';
import { DescriptionDto } from '../dto/description.dto';
function hashPassword() {
return bcrypt.hashSync(process.env.USER_PWD, process.env.SALT);
}
const mockUserModel = {
create: jest.fn(),
findOne: jest.fn(),
findById: jest.fn(),
deleteOne: jest.fn(),
updateMany: jest.fn(),
exec: jest.fn(),
find: jest.fn(() => mockUserModel),
sort: jest.fn(() => mockUserModel),
findByIdAndUpdate: jest.fn(),
};
describe('UsersService', () => {
let service: UsersService;
......@@ -29,7 +44,7 @@ describe('UsersService', () => {
UsersService,
{
provide: getModelToken('User'),
useValue: User,
useValue: mockUserModel,
},
],
}).compile();
......@@ -405,4 +420,70 @@ describe('UsersService', () => {
}
});
});
describe('getStructureOwnersDetails', () => {
const userDetailsMock: IUser[] = userDetails as IUser[];
it('should get Structure Owners Details', async () => {
jest.spyOn(service, 'getStructureOwnersDetails').mockResolvedValue(userDetails);
expect(await service.getStructureOwnersDetails('627b85aea0466f0f132e1599', null)).toEqual(userDetailsMock);
});
});
describe('user employer', () => {
it('should replace employer with a new one', async () => {
const spyer = jest.spyOn(mockUserModel, 'updateMany');
mockUserModel.updateMany.mockReturnThis();
mockUserModel.exec.mockResolvedValueOnce([usersMockData[0]]);
await service.replaceEmployers(employersMockData[0], employersMockData[1]);
expect(spyer).toBeCalledTimes(1);
});
it('should return true if a user is linked to a given employer', async () => {});
it('should fetch users attached to a given employer', async () => {});
it('should populate an employer with a list of attached users', async () => {});
it("should update user's employer ", async () => {});
});
describe('user job', () => {
it('should replace job with a new one', async () => {});
it('should return true if a user is linked to a given job', async () => {});
it('should fetch users attached to a given job', async () => {});
it('should populate an job with a list of attached users', async () => {});
it("should update user's job ", async () => {});
});
describe('updateDetails', () => {
it('should update user details', async () => {
const user = usersMockData[0];
const detailsDto: UpdateDetailsDto = { name: 'Michel', surname: 'Chelmi', phone: '0601020304' };
mockUserModel.findByIdAndUpdate.mockResolvedValueOnce({ ...user, ...detailsDto });
const updatedUser = await service.updateUserDetails('', { name: '', surname: '', phone: '' });
expect(updatedUser.name).toBe(detailsDto.name);
expect(updatedUser.surname).toBe(detailsDto.surname);
expect(updatedUser.phone).toBe(detailsDto.phone);
});
it('should not found a user', async () => {
const response = new HttpException('User not found', HttpStatus.BAD_REQUEST);
mockUserModel.findByIdAndUpdate.mockResolvedValueOnce(response);
const query = await service.updateUserDetails('', { name: '', surname: '', phone: '' });
expect(query).toBe(response);
});
});
describe('updateDescription', () => {
it('should update user description', async () => {
const user = usersMockData[0];
const updatedDescription: DescriptionDto = { description: 'hello friend' };
mockUserModel.findByIdAndUpdate.mockResolvedValueOnce({ ...user, ...updatedDescription });
const updatedUser = await service.updateDescription('', { description: '' });
expect(updatedUser.description).toBe(updatedDescription.description);
});
it('should not found a user', async () => {
const response = new HttpException('User not found', HttpStatus.BAD_REQUEST);
mockUserModel.findByIdAndUpdate.mockResolvedValueOnce(response);
const query = await service.updateDescription('', { description: '' });
expect(query).toBe(response);
});
});
});
This diff is collapsed.
import { IEmployer } from '../../../src/users/interfaces/employer.interface';
export const employersMockData: IEmployer[] = [
{
_id: '6036721022462b001334c4ba',
name: 'Metro',
validated: true,
} as any,
{
_id: '6036721022462b001334c4bb',
name: 'Sopra',
validated: true,
} as any,
] as IEmployer[];
......@@ -56,3 +56,21 @@ export const usersMockData: IUser[] = [
save: jest.fn(),
} as any,
] as IUser[];
export const userDetails: IUser[] = [
{
_id: '627b85aea0466f0f132e1599',
surname: 'ADMIN',
name: 'Admin',
email: 'admin@admin.com',
employer: {
name: 'CAF',
validated: true,
},
job: {
hasPersonalOffer: true,
name: 'CNFS',
validated: true,
},
},
] as IUser[];