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
Select Git revision

Target

Select target project
  • web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server
1 result
Select Git revision
Show changes
Showing
with 706 additions and 41 deletions
import { HttpModule, Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { NewsletterService } from './newsletter.service';
import { NewsletterController } from './newsletter.controller';
import { NewsletterSubscription, NewsletterSubscriptionSchema } from './newsletter-subscription.schema';
import { NewsletterController } from './newsletter.controller';
import { NewsletterService } from './newsletter.service';
@Module({
imports: [
MongooseModule.forFeature([{ name: NewsletterSubscription.name, schema: NewsletterSubscriptionSchema }]),
......
import { HttpModule, HttpStatus } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { HttpStatus } from '@nestjs/common';
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { INewsletterSubscription } from './interface/newsletter-subscription.interface';
import { NewsletterSubscription } from './newsletter-subscription.schema';
import { NewsletterService } from './newsletter.service';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const mailchimp = require('@mailchimp/mailchimp_marketing');
jest.mock('@mailchimp/mailchimp_marketing');
describe('NewsletterService', () => {
const OLD_ENV = process.env;
let service: NewsletterService;
const mockNewsletterModel = {
......@@ -17,6 +22,7 @@ describe('NewsletterService', () => {
};
beforeEach(async () => {
jest.resetModules(); // Most important - it clears the cache
const module: TestingModule = await Test.createTestingModule({
imports: [HttpModule],
providers: [
......@@ -29,6 +35,15 @@ describe('NewsletterService', () => {
}).compile();
service = module.get<NewsletterService>(NewsletterService);
process.env = { ...OLD_ENV }; // Make a copy
process.env.MC_LIST_ID = 'abcde';
process.env.MC_API_KEY = 'k3y';
process.env.MC_SERVER = 's3rv3r';
});
afterAll(() => {
process.env = OLD_ENV; // Restore old environment
});
it('should be defined', () => {
......@@ -53,6 +68,7 @@ describe('NewsletterService', () => {
it('it should add a subscription for email test2@test.com', async () => {
const result: INewsletterSubscription = { email: 'test2@test.com' } as INewsletterSubscription;
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' };
mailchimp.lists.addListMember.mockResolvedValueOnce({ email_address: 'test2@test.com' });
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => undefined)
......@@ -62,6 +78,42 @@ describe('NewsletterService', () => {
const subscription = await service.newsletterSubscribe('test2@test.com');
expect(subscription).toEqual({ email: 'test2@test.com' });
});
it('it should return mailchimp 400 issue', async () => {
const result: INewsletterSubscription = { email: 'test2@test.com' } as INewsletterSubscription;
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' };
mailchimp.lists.addListMember.mockRejectedValueOnce({ status: 400 });
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => undefined)
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
mockNewsletterModel.create.mockResolvedValueOnce(_doc);
try {
await service.newsletterSubscribe('test2@test.com');
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Email already exists');
expect(e.status).toEqual(HttpStatus.BAD_REQUEST);
}
});
it('it should return mailchimp 500 issue', async () => {
const result: INewsletterSubscription = { email: 'test2@test.com' } as INewsletterSubscription;
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' };
mailchimp.lists.addListMember.mockRejectedValueOnce({ status: 500 });
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => undefined)
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
mockNewsletterModel.create.mockResolvedValueOnce(_doc);
try {
await service.newsletterSubscribe('test2@test.com');
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Server error');
expect(e.status).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
}
});
});
describe('newsletterUnsubscribe', () => {
it('it should not remove subscription for email test@test.com : does not exist', async () => {
......@@ -134,4 +186,23 @@ describe('NewsletterService', () => {
expect(findOneEmail.length).toBe(2);
});
});
describe('updateNewsletterSubscription', () => {
it('should update existing user subscription', () => {
mailchimp.lists.getListMembersInfo.mockResolvedValueOnce({ total_items: 10 }).mockResolvedValueOnce({
members: [
{ email_address: 'a@a.com', status: 'subscribed' },
{ email_address: 'test@test.com', status: 'unsubscribed' },
{ email_address: 'test2@test.com', status: 'unsubscribed' },
],
});
const result = { email: 'test2@test.com' } as INewsletterSubscription;
const spyer = jest.spyOn(mockNewsletterModel, 'findOne');
// jest.spyOn(service, 'findOne').mockResolvedValueOnce(result).mockResolvedValueOnce(result);
mockNewsletterModel.findOne.mockResolvedValueOnce(result).mockResolvedValueOnce(null);
service.updateNewsletterSubscription();
expect(spyer).toBeCalledTimes(2);
// expect(spyerDelete).toBeCalledTimes(1);
});
});
});
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Cron, CronExpression } from '@nestjs/schedule';
import { Model } from 'mongoose';
import { IMailchimpSubscription } from './interface/mailchimp-subscription';
import { INewsletterSubscription } from './interface/newsletter-subscription.interface';
import { NewsletterSubscription, NewsletterSubscriptionDocument } from './newsletter-subscription.schema';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const mailchimp = require('@mailchimp/mailchimp_marketing');
@Injectable()
export class NewsletterService {
private readonly logger = new Logger(NewsletterService.name);
private LIST_ID = process.env.MC_LIST_ID;
constructor(
@InjectModel(NewsletterSubscription.name) private newsletterSubscriptionModel: Model<INewsletterSubscription>
) {}
) {
// Configure mailchimp client
mailchimp.setConfig({
apiKey: process.env.MC_API_KEY,
server: process.env.MC_SERVER,
});
}
@Cron(CronExpression.EVERY_DAY_AT_3AM)
public async updateNewsletterSubscription(): Promise<void> {
this.logger.debug('updateNewsletterSubscription');
const { total_items } = await mailchimp.lists.getListMembersInfo(this.LIST_ID);
const { members } = await mailchimp.lists.getListMembersInfo(this.LIST_ID, {
fields: ['members.email_address,members.id,members.status'],
count: total_items,
});
const memberToRemove = members.filter((user: IMailchimpSubscription) => user.status !== 'subscribed');
memberToRemove.forEach(async (member: IMailchimpSubscription) => {
const userSubscription = await this.findOne(member.email_address);
if (userSubscription) {
this.logger.log(`Remove subscription ${member.id}`);
userSubscription.deleteOne();
}
});
}
public async newsletterSubscribe(email: string): Promise<NewsletterSubscription> {
this.logger.debug('newsletterSubscribe');
const existingEmail = await this.findOne(email);
if (existingEmail) {
throw new HttpException('Email already exists', HttpStatus.BAD_REQUEST);
}
await this.newsletterSubscriptionModel.create({ email: email });
return this.findOne(email);
try {
const member = await mailchimp.lists.addListMember(this.LIST_ID, {
email_address: email,
status: 'subscribed',
});
await this.newsletterSubscriptionModel.create({ email: email, mailchimpId: member.id });
return this.findOne(email);
} catch (e) {
if (e.status === 400) {
this.logger.error(`Error ${e.status}, user might already exist in mailchimplist`);
throw new HttpException('Email already exists', HttpStatus.BAD_REQUEST);
} else {
this.logger.error(`Mailchimp configuration error`);
throw new HttpException('Server error', HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
public async newsletterUnsubscribe(email: string): Promise<NewsletterSubscription> {
this.logger.debug('newsletterUnsubscribe');
const subscription = await this.findOne(email);
if (!subscription) {
throw new HttpException('Invalid email', HttpStatus.BAD_REQUEST);
}
await mailchimp.lists.setListMember(this.LIST_ID, subscription.mailchimpId, {
email_address: email,
status: 'unsubscribed',
});
return subscription.deleteOne();
}
public async findOne(mail: string): Promise<INewsletterSubscription | undefined> {
this.logger.debug('findOne');
return this.newsletterSubscriptionModel.findOne({ email: mail });
}
public async searchNewsletterSubscription(searchString: string): Promise<NewsletterSubscriptionDocument[]> {
this.logger.debug('searchNewsletterSubscription');
return this.newsletterSubscriptionModel.find({ email: new RegExp(searchString, 'i') });
}
public async countNewsletterSubscriptions(): Promise<number> {
this.logger.debug('countNewsletterSubscriptions');
return this.newsletterSubscriptionModel.countDocuments({});
}
public async findAll(): Promise<NewsletterSubscription[]> {
this.logger.debug('findAll');
return this.newsletterSubscriptionModel.find();
}
}
import { HttpModule, HttpService } from '@nestjs/common';
import { HttpModule, HttpService } from '@nestjs/axios';
import { Test, TestingModule } from '@nestjs/testing';
import { of } from 'rxjs';
import { ConfigurationModule } from '../configuration/configuration.module';
......
import { Controller, Get, HttpService, HttpException, HttpStatus, Logger, Param } from '@nestjs/common';
import { Controller, Get, HttpException, HttpStatus, Logger, Param } from '@nestjs/common';
import { ConfigurationService } from '../configuration/configuration.service';
import { Observable } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { Page } from './schemas/page.schema';
import { rewriteGhostImgUrl } from '../shared/utils';
import { ApiTags } from '@nestjs/swagger';
import { HttpService } from '@nestjs/axios';
@ApiTags('pages')
@Controller('pages')
export class PagesController {
private readonly logger = new Logger(PagesController.name);
......
import { HttpModule, Module } from '@nestjs/common';
import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { PagesController } from './pages.controller';
@Module({
......
......@@ -7,10 +7,18 @@ import { Parameters } from './schemas/parameters.schema';
describe('ParametersController', () => {
let controller: ParametersController;
const parametersServiceMock = {
getParameters: jest.fn(),
setParameterLockdownInfoDisplay: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ParametersService,
{
provide: ParametersService,
useValue: parametersServiceMock,
},
{
provide: getModelToken('Parameters'),
useValue: Parameters,
......@@ -26,18 +34,25 @@ describe('ParametersController', () => {
expect(controller).toBeDefined();
});
it('should get parameters', async () => {
const result = { lockdownInfoDisplay: false };
jest.spyOn(controller, 'getParameters').mockImplementation(async (): Promise<Parameters> => result);
expect(await controller.getParameters()).toBe(result);
it('should call getParameters', async () => {
const spyer = jest.spyOn(parametersServiceMock, 'getParameters');
await controller.getParameters();
expect(spyer).toBeCalledTimes(1);
});
it('should set lockdownInfoDisplay', async () => {
const result = { lockdownInfoDisplay: false };
jest
.spyOn(controller, 'setParameterLockdownInfoDisplay')
.mockImplementation(async (): Promise<Parameters> => result);
const lockdownInfoDisplayValue = { lockdownInfoDisplay: false };
expect(await controller.setParameterLockdownInfoDisplay(lockdownInfoDisplayValue)).toBe(result);
describe('setParameterLockdownInfoDisplay', () => {
const spyer = jest.spyOn(parametersServiceMock, 'setParameterLockdownInfoDisplay');
afterEach(() => spyer.mockClear());
it('should call setParameterLockdownInfoDisplay(false) ', async () => {
await controller.setParameterLockdownInfoDisplay({ lockdownInfoDisplay: false });
expect(spyer).toBeCalledTimes(1);
expect(spyer).toBeCalledWith(false);
});
it('should call setParameterLockdownInfoDisplay(true)', async () => {
await controller.setParameterLockdownInfoDisplay({ lockdownInfoDisplay: true });
expect(spyer).toBeCalledTimes(1);
expect(spyer).toBeCalledWith(true);
});
});
});
import { Body, Controller, Post, Get, UseGuards } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { Roles } from '../users/decorators/roles.decorator';
import { RolesGuard } from '../users/guards/roles.guard';
import { ParametersService } from './parameters.service';
import { Parameters } from './schemas/parameters.schema';
@ApiTags('parameters')
@Controller('parameters')
export class ParametersController {
constructor(private parametersService: ParametersService) {}
@Get()
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
public async getParameters(): Promise<Parameters> {
return this.parametersService.getParameters();
}
......
import { HttpStatus } from '@nestjs/common';
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { mockParametersModel } from '../../test/mock/services/parameters.mock.service';
import { IParameters } from './interface/parameters.interface';
import { ParametersService } from './parameters.service';
import { Parameters } from './schemas/parameters.schema';
describe('ParametersService', () => {
let service: ParametersService;
const parametersModelMock = {
findOne: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ParametersService,
{
provide: getModelToken(Parameters.name),
useValue: mockParametersModel,
useValue: parametersModelMock,
},
],
}).compile();
service = module.get<ParametersService>(ParametersService);
});
afterEach(() => {
jest.clearAllMocks();
});
it('should be defined', () => {
expect(service).toBeDefined();
});
it('should get parameters', async () => {
const result: IParameters = { lockdownInfoDisplay: false } as IParameters;
jest.spyOn(service, 'getParameters').mockImplementation(async (): Promise<Parameters> => result);
expect(await service.getParameters()).toBe(result);
describe('getParameters', () => {
it('should get parameters', async () => {
const spyer = jest.spyOn(parametersModelMock, 'findOne');
parametersModelMock.findOne.mockResolvedValueOnce({ lockdownInfoDisplay: false });
const result = await service.getParameters();
expect(spyer).toBeCalledTimes(1);
expect(result).toEqual({ lockdownInfoDisplay: false });
});
it('should throw error because parameters was not found', async () => {
const spyer = jest.spyOn(parametersModelMock, 'findOne');
parametersModelMock.findOne.mockResolvedValueOnce(null);
try {
await service.getParameters();
expect(true).toBe(false);
} catch (error) {
expect(error.message).toBe('Parameters not found');
expect(error.status).toBe(HttpStatus.NOT_FOUND);
}
expect(spyer).toBeCalledTimes(1);
});
});
it('should set Parameter LockdownInfoDisplay', async () => {
const result: IParameters = { lockdownInfoDisplay: false } as IParameters;
jest.spyOn(service, 'setParameterLockdownInfoDisplay').mockImplementation(async (): Promise<Parameters> => result);
expect(await service.setParameterLockdownInfoDisplay(false)).toBe(result);
describe('setParameters', () => {
it('should set parameters', async () => {
const spyer = jest.spyOn(parametersModelMock, 'findOne');
parametersModelMock.findOne.mockResolvedValueOnce({ lockdownInfoDisplay: false, save: jest.fn() });
const result = await service.setParameterLockdownInfoDisplay(true);
expect(spyer).toBeCalledTimes(1);
expect(result.lockdownInfoDisplay).toEqual(true);
});
it('should throw error because parameters was not found', async () => {
const spyer = jest.spyOn(parametersModelMock, 'findOne');
parametersModelMock.findOne.mockResolvedValueOnce(null);
try {
await service.setParameterLockdownInfoDisplay(true);
expect(true).toBe(false);
} catch (error) {
expect(error.message).toBe('Parameters not found');
expect(error.status).toBe(HttpStatus.NOT_FOUND);
}
expect(spyer).toBeCalledTimes(1);
});
});
});
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { IsNotEmpty, ValidateNested } from 'class-validator';
import { PersonalOfferDto } from './personal-offer.dto';
export class CreatePersonalOfferDto {
@ApiProperty({
description: 'Id of the structure',
type: [String],
})
@IsNotEmpty()
structureId: string;
@ApiProperty({
description: 'Personal offer to create',
type: [String],
})
@ValidateNested({ each: true })
@Type(() => PersonalOfferDto)
personalOffer: PersonalOfferDto;
}
import { ApiProperty } from '@nestjs/swagger';
export class PersonalOfferDto {
/** accompaniments **/
@ApiProperty({
description: 'List of procedures accompaniments',
type: [String],
})
proceduresAccompaniment: string[];
/** trainings **/
@ApiProperty({
description: 'List of base skills trainings',
type: [String],
})
baseSkills: string[];
@ApiProperty({
description: 'List of access right trainings',
type: [String],
})
accessRight: string[];
@ApiProperty({
description: 'List of digital, culture and security trainings',
type: [String],
})
digitalCultureSecurity: string[];
@ApiProperty({
description: 'List of social and profressional trainings',
type: [String],
})
socialAndProfessional: string[];
@ApiProperty({
description: 'List of parenting help trainings',
type: [String],
})
parentingHelp: string[];
}
import { Test, TestingModule } from '@nestjs/testing';
import { PersonalOffersController } from './personal-offers.controller';
import { PersonalOffersService } from './personal-offers.service';
import { PersonalOffersServiceMock } from '../../test/mock/services/personalOffers.mock.service';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { mockJwtAuthGuard } from '../../test/mock/guards/jwt-auth.mock.guard';
import { IsPersonalOfferOwnerGuard } from '../users/guards/isPersonalOfferOwner.guard';
import { mockIsPersonalOfferOwnerGuard } from '../../test/mock/guards/isPersonalOfferOwner.mock.guard';
import {
createPersonalOffersDtoDataMock,
updatePersonalOffersDtoDataMock,
personalOffersDataMock,
} from '../../test/mock/data/personalOffers.mock.data';
import { UsersService } from '../users/services/users.service';
import { UsersServiceMock } from '../../test/mock/services/user.mock.service';
import { StructuresService } from '../structures/services/structures.service';
import { StructuresServiceMock } from '../../test/mock/services/structures.mock.service';
describe('PersonalOffersController', () => {
let controller: PersonalOffersController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [PersonalOffersController],
providers: [
{
provide: PersonalOffersService,
useClass: PersonalOffersServiceMock,
},
{
provide: UsersService,
useClass: UsersServiceMock,
},
{
provide: StructuresService,
useClass: StructuresServiceMock,
},
],
})
.overrideGuard(JwtAuthGuard)
.useValue(mockJwtAuthGuard)
.overrideGuard(IsPersonalOfferOwnerGuard)
.useValue(mockIsPersonalOfferOwnerGuard)
.compile();
controller = module.get<PersonalOffersController>(PersonalOffersController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
describe('find personal offer', () => {
it('should get personal offer', async () => {
expect(await controller.find('1234ba0e2ab5775cfc01ed3e')).toBe(personalOffersDataMock[0]);
});
it('should get personal offer does not exist', async () => {
try {
await controller.find('abcd');
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Personal offer does not exist');
expect(e.status).toBe(404);
}
});
});
describe('create personal offer', () => {
it('should create personal offer for existing user and structure', async () => {
const req = { user: { _id: '6036721022462b001334c4bb' } };
expect(await controller.create(req, createPersonalOffersDtoDataMock[0])).toEqual(personalOffersDataMock[0]);
});
it('should return personal offer already exist in the structure', async () => {
const req = { user: { _id: '6036721022462b001334c4bb' } };
try {
await controller.create(req, createPersonalOffersDtoDataMock[1]);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Personal offer already exist in the structure');
expect(e.status).toBe(400);
}
});
it('should return structure not found for the personal offer attachment', async () => {
const req = { user: { _id: '6036721022462b001334c4bb' } };
try {
await controller.create(req, createPersonalOffersDtoDataMock[2]);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Structure not found for the personal offer attachment');
expect(e.status).toBe(400);
}
});
it('should return user not found for the personal offer attachment', async () => {
const req = { user: { _id: 'unIdQuiExistePasTropTrop' } };
try {
await controller.create(req, createPersonalOffersDtoDataMock[0]);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('User not found for the personal offer attachment');
expect(e.status).toBe(400);
}
});
});
describe('update personal offer', () => {
it('should get updated personal offer', async () => {
expect(await controller.update('2345ba0e2ab5775cfc01ed4d', updatePersonalOffersDtoDataMock[1])).toEqual(
personalOffersDataMock[1]
);
});
it('should get invalid personal offer id', async () => {
try {
await controller.update('abcd', updatePersonalOffersDtoDataMock[1]);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Invalid personal offer id for update');
expect(e.status).toBe(400);
}
});
});
describe('update personal offer', () => {
it('should get deleted personal offer', async () => {
expect(await controller.delete('2345ba0e2ab5775cfc01ed4d')).toEqual(personalOffersDataMock[1]);
});
it('should get invalid personal offer id', async () => {
try {
await controller.delete('abcd');
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Invalid personal offer id for deletion');
expect(e.status).toBe(400);
}
});
});
});
import { Body, Controller, Delete, Get, Param, Post, Put, Request, UseGuards } from '@nestjs/common';
import { ApiBody, ApiParam, ApiTags } from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { StructuresService } from '../structures/services/structures.service';
import { IsPersonalOfferOwnerGuard } from '../users/guards/isPersonalOfferOwner.guard';
import { IUser } from '../users/interfaces/user.interface';
import { UsersService } from '../users/services/users.service';
import { CreatePersonalOfferDto } from './dto/create-personal-offer.dto';
import { PersonalOfferDto } from './dto/personal-offer.dto';
import { PersonalOffersService } from './personal-offers.service';
import { PersonalOfferDocument } from './schemas/personal-offer.schema';
@ApiTags('personnal-offers')
@Controller('personal-offers')
export class PersonalOffersController {
constructor(
private personalOffersService: PersonalOffersService,
private structuresService: StructuresService,
private usersService: UsersService
) {}
/**
* Return personal offer of given id.
* @param id
* @returns {PersonalOffer} Personal offer
*/
@Get(':id')
@ApiParam({ name: 'id', type: String, required: true })
public async find(@Param('id') id: string) {
return this.personalOffersService.findOne(id);
}
/**
* Create and return a personal offer.
* @param createPersonalOfferDto
* @returns {PersonalOffer} created personal offer
*/
@Post()
@ApiBody({ type: CreatePersonalOfferDto, required: true })
@UseGuards(JwtAuthGuard)
public async create(
@Request() req,
@Body() createPersonalOfferDto: CreatePersonalOfferDto
): Promise<PersonalOfferDocument> {
const user: IUser = req.user;
const personalOfferDocument: PersonalOfferDocument = await this.personalOffersService.create(
createPersonalOfferDto
);
await this.structuresService.addPersonalOffer(createPersonalOfferDto.structureId, personalOfferDocument);
await this.usersService.addPersonalOffer(user._id, personalOfferDocument);
return personalOfferDocument;
}
/**
* Update and return a personal offer.
* @param id - id of the personal offer to update
* @param updatePersonalOfferDto - personal offer data to update
* @returns {PersonalOffer} Updated personal offer
*/
@Put(':id')
@ApiParam({ name: 'id', type: String, required: true })
@ApiBody({ type: PersonalOfferDto, required: true })
@UseGuards(JwtAuthGuard, IsPersonalOfferOwnerGuard)
public async update(
@Param('id') id: string,
@Body() updatePersonalOfferDto: PersonalOfferDto
): Promise<PersonalOfferDocument> {
return this.personalOffersService.update(id, updatePersonalOfferDto);
}
/**
* Delete and return a personal offer.
* @param id - id of the personal offer to delete
* @returns {PersonalOffer} Deleted personal offer
*/
@Delete(':id')
@ApiParam({ name: 'id', type: String, required: true })
@UseGuards(JwtAuthGuard, IsPersonalOfferOwnerGuard)
public async delete(@Param('id') id: string): Promise<PersonalOfferDocument> {
return this.personalOffersService.delete(id);
}
}
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { StructuresModule } from '../structures/structures.module';
import { UsersModule } from '../users/users.module';
import { PersonalOffersController } from './personal-offers.controller';
import { PersonalOffersService } from './personal-offers.service';
import { PersonalOffer, PersonalOfferSchema } from './schemas/personal-offer.schema';
@Module({
imports: [
MongooseModule.forFeature([{ name: PersonalOffer.name, schema: PersonalOfferSchema }]),
StructuresModule,
UsersModule,
],
controllers: [PersonalOffersController],
providers: [PersonalOffersService],
})
export class PersonalOffersModule {}
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import {
createPersonalOffersDtoDataMock,
updatePersonalOffersDtoDataMock,
personalOffersDataMock,
} from '../../test/mock/data/personalOffers.mock.data';
import { PersonalOffersService } from './personal-offers.service';
describe('PersonalOffersService', () => {
let service: PersonalOffersService;
const personalOfferModelMock = {
findById: jest.fn(),
create: jest.fn(),
findByIdAndUpdate: jest.fn(),
findByIdAndDelete: jest.fn(),
exec: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
PersonalOffersService,
{
provide: getModelToken('PersonalOffer'),
useValue: personalOfferModelMock,
},
],
}).compile();
service = module.get<PersonalOffersService>(PersonalOffersService);
});
afterEach(async () => {
jest.clearAllMocks();
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('findOne', () => {
it('should return personal offer', async () => {
personalOfferModelMock.findById.mockReturnThis();
personalOfferModelMock.exec.mockResolvedValueOnce(personalOffersDataMock[0]);
expect(await service.findOne('1234ba0e2ab5775cfc01ed3e')).toEqual(personalOffersDataMock[0]);
});
it('should return exception if personal offer is not found for given id', async () => {
personalOfferModelMock.findById.mockReturnThis();
personalOfferModelMock.exec.mockResolvedValueOnce(null);
let error: any;
try {
await service.findOne('abcd');
} catch (e) {
error = e;
}
expect(error.message).toBe('Personal offer does not exist');
expect(error.status).toBe(404);
});
});
describe('create', () => {
it('should create personal offer', async () => {
personalOfferModelMock.create.mockResolvedValueOnce(personalOffersDataMock[0]);
expect(await service.create(createPersonalOffersDtoDataMock[0])).toEqual(personalOffersDataMock[0]);
});
});
describe('update', () => {
it('should update personal offer', async () => {
personalOfferModelMock.findByIdAndUpdate.mockReturnThis();
personalOfferModelMock.exec.mockResolvedValueOnce(personalOffersDataMock[1]);
expect(await service.update('2345ba0e2ab5775cfc01ed4d', updatePersonalOffersDtoDataMock[1])).toEqual(
personalOffersDataMock[1]
);
});
it('should return exception if personal offer is not found for given id', async () => {
personalOfferModelMock.findById.mockReturnThis();
personalOfferModelMock.exec.mockResolvedValueOnce(null);
let error: any;
try {
await service.update('abcd', updatePersonalOffersDtoDataMock[1]);
} catch (e) {
error = e;
}
expect(error.message).toBe('Invalid personal offer id for update');
expect(error.status).toBe(400);
});
});
describe('delete', () => {
it('should update personal offer', async () => {
personalOfferModelMock.findByIdAndDelete.mockReturnThis();
personalOfferModelMock.exec.mockResolvedValueOnce(personalOffersDataMock[0]);
expect(await service.delete('2345ba0e2ab5775cfc01ed4d')).toEqual(personalOffersDataMock[0]);
});
it('should return exception if personal offer is not found for given id', async () => {
personalOfferModelMock.findById.mockReturnThis();
personalOfferModelMock.exec.mockResolvedValueOnce(null);
let error: any;
try {
await service.delete('abcd');
} catch (e) {
error = e;
}
expect(error.message).toBe('Invalid personal offer id for deletion');
expect(error.status).toBe(400);
});
});
});
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { CreatePersonalOfferDto } from './dto/create-personal-offer.dto';
import { PersonalOfferDto } from './dto/personal-offer.dto';
import { PersonalOffer, PersonalOfferDocument } from './schemas/personal-offer.schema';
@Injectable()
export class PersonalOffersService {
constructor(@InjectModel(PersonalOffer.name) private personalOfferModel: Model<PersonalOfferDocument>) {}
public async findOne(id: string): Promise<PersonalOffer> {
const result: PersonalOfferDocument = await this.personalOfferModel.findById(id).exec();
if (!result) {
throw new HttpException('Personal offer does not exist', HttpStatus.NOT_FOUND);
}
return result;
}
public async create(createDto: CreatePersonalOfferDto): Promise<PersonalOfferDocument> {
return this.personalOfferModel.create(createDto.personalOffer);
}
public async update(id: string, updatePersonalOfferDto: PersonalOfferDto): Promise<PersonalOfferDocument> {
const result: PersonalOfferDocument = await this.personalOfferModel
.findByIdAndUpdate(id, updatePersonalOfferDto)
.exec();
if (!result) {
throw new HttpException('Invalid personal offer id for update', HttpStatus.BAD_REQUEST);
}
return result;
}
public async delete(id: string): Promise<PersonalOfferDocument> {
const result: PersonalOfferDocument = await this.personalOfferModel.findByIdAndDelete(id).exec();
if (!result) {
throw new HttpException('Invalid personal offer id for deletion', HttpStatus.BAD_REQUEST);
}
return result;
}
}
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
export type PersonalOfferDocument = PersonalOffer & Document;
@Schema({ timestamps: true })
export class PersonalOffer {
@Prop()
proceduresAccompaniment: string[];
@Prop()
baseSkills: string[];
@Prop()
accessRight: string[];
@Prop()
digitalCultureSecurity: string[];
@Prop()
socialAndProfessional: string[];
@Prop()
parentingHelp: string[];
}
export const PersonalOfferSchema = SchemaFactory.createForClass(PersonalOffer);
import { HttpModule, HttpService } from '@nestjs/common';
import { HttpModule, HttpService } from '@nestjs/axios';
import { Test, TestingModule } from '@nestjs/testing';
import { of } from 'rxjs';
import { ConfigurationModule } from '../configuration/configuration.module';
......
import { Controller, Get, HttpException, HttpService, HttpStatus, Logger, Param, Query } from '@nestjs/common';
import { Controller, Get, HttpException, HttpStatus, Logger, Param, Query } from '@nestjs/common';
import { Observable } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { ApiQuery } from '@nestjs/swagger';
import { ApiQuery, ApiTags } from '@nestjs/swagger';
import { Post } from './schemas/post.schema';
import { PostsService } from './posts.service';
import { Tag } from './schemas/tag.schema';
import { PostWithMeta } from './schemas/postWithMeta.schema';
import { HttpService } from '@nestjs/axios';
@ApiTags('posts')
@Controller('posts')
export class PostsController {
private readonly logger = new Logger(PostsController.name);
......
import { HttpModule, Module } from '@nestjs/common';
import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { PostsController } from './posts.controller';
import { PostsService } from './posts.service';
......