Skip to content
Commits on Source (14)
stages:
- quality
- test
- sonar-analysis
- build
- deploy
......@@ -38,10 +38,8 @@ build_branch:
DOCKER_DRIVER: overlay2
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
stage: build
except:
- master
- rec
- dev
only:
- merge_requests
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull -t "$CI_REGISTRY_IMAGE/feat:$CI_COMMIT_REF_SLUG" --build-arg conf=prod .
......@@ -104,39 +102,54 @@ test:
- dev
- merge_requests
# code_analysis:
# image: registry.forge.grandlyon.com/apoyen2/sonnar-scanner-gl:master
# services:
# - docker:18.09-dind
# stage: sonar-analysis
# only:
# - dev
# - merge_requests
# before_script:
# - export NODE_PATH=$NODE_PATH:`npm root -g`
# - npm install -g typescript
# script:
# - >
# sonar-scanner
# -Dsonar.projectName=${SONAR_PROJECT_KEY}
# -Dsonar.projectVersion=1.0
# -Dsonar.sourceEncoding=UTF-8
# -Dsonar.projectBaseDir=.
# -Dsonar.host.url=${SONAR_URL}
# -Dsonar.projectKey=${SONAR_PROJECT_KEY}
# -Dsonar.exclusions=scripts/**,**/*mock.*.ts,**/*spec.ts
# -Dsonar.login=${SONAR_TOKEN}
# -Dsonar.qualitygate.wait=true
mr:
sonarqube:
stage: quality
only:
- dev
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/sonarsource/sonar-scanner-cli:4
variables:
DOCKER_TLS_CERTDIR: ''
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
stage: build
SONAR_USER_HOME: '${CI_PROJECT_DIR}/.sonar' # Defines the location of the analysis task cache
GIT_DEPTH: '0' # T
cache:
key: '${CI_JOB_NAME}'
paths:
- .sonar/cache
script:
- >
sonar-scanner
-Dsonar.projectName=${SONAR_PROJECT_KEY}
-Dsonar.projectVersion=1.0
-Dsonar.sourceEncoding=UTF-8
-Dsonar.projectBaseDir=.
-Dsonar.host.url=${SONAR_URL}
-Dsonar.projectKey=${SONAR_PROJECT_KEY}
-Dsonar.login=${SONAR_TOKEN}
-Dsonar.cpd.exclusions=test/**,scripts/**,src/**/*.spec.ts*
-Dsonar.exclusions=test/**,scripts/**,src/**/*.spec.ts*,src/migrations/scripts/**
-Dsonar.qualitygate.wait=true
sonarqube-mr:
stage: quality
only:
- merge_requests
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/sonarsource/sonar-scanner-cli:4
variables:
SONAR_USER_HOME: '${CI_PROJECT_DIR}/.sonar' # Defines the location of the analysis task cache
GIT_DEPTH: '0' # T
cache:
key: '${CI_JOB_NAME}'
paths:
- .sonar/cache
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build .
- >
sonar-scanner
-Dsonar.projectName=${SONAR_PROJECT_KEY}
-Dsonar.projectVersion=1.0
-Dsonar.sourceEncoding=UTF-8
-Dsonar.projectBaseDir=.
-Dsonar.host.url=${SONAR_URL}
-Dsonar.projectKey=${SONAR_PROJECT_KEY}
-Dsonar.login=${SONAR_MR_TOKEN}
-Dsonar.cpd.exclusions=test/**,scripts/**,src/**/*.spec.ts*
-Dsonar.exclusions=test/**,scripts/**,src/**/*.spec.ts*,src/migrations/scripts/**
-Dsonar.qualitygate.wait=true
/title [Scope] Description
### Résumé du problème
_Donnez une description briève du problème._
### Les étapes pour reproduire le bug
_Listez les étapes qui vous permettent de reproduire ce bug, cette étape est très importante._
### Décrivez le comportement du bug ?
### Quel serez le comportement attendu ?
### Logs et/ou screenshots
### Possible fixes
/label ~"type::bug"
## What does this MR do and why?
_Describe in detail what your merge request does and why._
| :warning: Keep an up to date checklist based on your icescrum tasks during all the draft phase to help any other developer who would take the job after you to finish it. |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
## Screenshots or screen recordings
_These are strongly recommended to assist reviewers and reduce the time to merge your change._
## How to set up and validate locally (or on alpha)
_List all steps to set up and validate the changes on local environment._
## MR acceptance checklist
_To be completed by the chosen reviewer._
<!---
Using checklists improves quality in software engineering and other jobs such as with surgeons and airline pilots.
More reading on checklists can be found in the "Checklist Manifesto": http://atulgawande.com/book/the-checklist-manifesto/
"It is common to misconceive how checklists function in complex lines of work. They are not comprehensive how-to guides, whether for building a skyscraper or getting a plane out of trouble. They are quick and simple tools aimed to buttress the skills of expert professionals." - Gawande, Atul. The Checklist Manifesto
--->
### Quality
- [ ] Confirmed
1. For the code that this change impacts, I believe that the automated tests validate functionality that is highly important to users. If the existing automated tests do not cover this functionality, I have added the necessary additional tests or I have added an issue to describe the automation testing gap and linked it to this MR.
1. I have made sure that the sonar quality coverage is up to standards.
1. I have considered the impact of this change on the front-end, back-end, and database portions of the system where appropriate and applied.
1. I have tested this MR in all supported browsers or determined that this testing is not needed.
1. I have confirmed that this change is backwards compatible across updates (migrate up needs a migrate down), or I have decided that this does not apply.
### Performance, reliability and availability
- [ ] Confirmed
1. I am confident that this MR does not harm performance, or I have asked a reviewer to help assess the performance impact.
1. I have considered the scalability risk based on future predicted growth.
### Documentation
- [ ] Confirmed
1. I have prepared a squash commit to feed the changelog linked to the current milestone.
1. I have added/updated documentation (also updated if the changes feature a deprecation) or I have decided that documentation changes are not needed for this MR.
### Security
- [ ] Confirmed
1. I have confirmed that if this MR does not contains any sensitive informations hidden in the changes.
### Deployment
- [ ] Confirmed
1. When featured on a self-data project release, i have made sure my app version in the manifest and package.json is incremented and any relative changes to the permissions are clearly written and transmitted to Cozy.
......@@ -2,6 +2,21 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [1.17.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v1.16.0...v1.17.0) (2022-05-30)
### Features
* **admin:** now display last update date next to structure names ([01d5665](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/01d56659ebd323105dcfa46a9bbb929e482fc05c))
* **digital helps:** rename "Accompagnement CAF" to "CAF" ([90e106f](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/90e106f572ea52d990a67b49f00fe434965cc083))
* **structures:** add MaisonFranceService to structure types ([cfea72c](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/cfea72c594dbb9ccef2382337494be3c3b979c5a))
### Bug Fixes
* Resolve "Join validation issue for admin" and refactor of string to date for structure updatedAt and createdAt ([df74738](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/df747380f58b5f093265c185b357e666792c04a9))
* sonar ([a222df2](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/a222df249f85d780e31f24e79d52431f4eada6b4))
## [1.16.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v1.15.1...v1.16.0) (2022-03-18)
......
{
"name": "ram_server",
"version": "1.16.0",
"version": "1.17.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......
{
"name": "ram_server",
"private": true,
"version": "1.16.0",
"version": "1.17.0",
"description": "Nest TypeScript starter repository",
"license": "MIT",
"scripts": {
......
......@@ -135,7 +135,7 @@ module.exports = {
accessModality: ['accesLibre', 'surRdv'],
freeWorkShop: false,
createdAt: '2020-11-16T10:19:00.000Z',
updatedAt: 'Mon May 10 2021 08:45:50 GMT+0000 (Coordinated Universal Time)',
updatedAt: '2020-12-16T10:19:00.000Z',
structureName: 'Pôle emploi (Vénissieux)',
description: "Espace informatique en libre service le matin Sur RDV l'après-midi, réservation d'un poste",
lockdownActivity: "Espace libre accès le matin RDV l'après-midi, résercation d'un poste",
......@@ -791,8 +791,8 @@ module.exports = {
street: 'Avenue Général Frère',
commune: 'Lyon',
},
createdAt: 'Thu Jan 20 2022 10:06:20 GMT+0100 (heure normale d’Europe centrale)',
updatedAt: 'Thu Jan 20 2022 10:06:20 GMT+0100 (heure normale d’Europe centrale)',
createdAt: '2020-11-13T14:13:00.000Z',
updatedAt: '2022-04-13T14:13:00.000Z',
dataShareConsentDate: null,
__v: 0,
},
......@@ -828,9 +828,9 @@ module.exports = {
street: 'Rue Neuve',
commune: 'Fleurieu-sur-Saône',
},
createdAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)',
updatedAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)',
dataShareConsentDate: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)',
createdAt: '2022-01-13T14:13:00.000Z',
updatedAt: '2022-02-13T14:13:00.000Z',
dataShareConsentDate: '2022-01-13T14:13:00.000Z',
__v: 0,
},
],
......
import { HttpModule } from '@nestjs/common';
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { mockJwtAuthGuard } from '../../test/mock/guards/jwt-auth.mock.guard';
import { mockRoleGuard } from '../../test/mock/guards/role.mock.guard';
import { NewsletterServiceMock } from '../../test/mock/services/newsletter.mock.service';
import { StructuresServiceMock } from '../../test/mock/services/structures.mock.service';
import { UsersServiceMock } from '../../test/mock/services/user.mock.service';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { ConfigurationModule } from '../configuration/configuration.module';
import { MailerService } from '../mailer/mailer.service';
import { NewsletterSubscription } from '../newsletter/newsletter-subscription.schema';
import { NewsletterService } from '../newsletter/newsletter.service';
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 { RolesGuard } from '../users/guards/roles.guard';
import { User } from '../users/schemas/user.schema';
import { UsersService } from '../users/users.service';
import { AdminController } from './admin.controller';
import { mockJwtAuthGuard } from '../../test/mock/guards/jwt-auth.mock.guard';
import { mockRoleGuard } from '../../test/mock/guards/role.mock.guard';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../users/guards/roles.guard';
import { UsersServiceMock } from '../../test/mock/services/user.mock.service';
import { StructuresServiceMock } from '../../test/mock/services/structures.mock.service';
import { NewsletterServiceMock } from '../../test/mock/services/newsletter.mock.service';
import { AdminService } from './admin.service';
describe('AdminController', () => {
let controller: AdminController;
......@@ -39,6 +40,10 @@ describe('AdminController', () => {
provide: NewsletterService,
useClass: NewsletterServiceMock,
},
{
provide: AdminService,
useClass: AdminService,
},
StructuresSearchService,
MailerService,
{
......@@ -71,7 +76,7 @@ describe('AdminController', () => {
it('should get pending attachments', async () => {
expect((await controller.getPendingAttachments()).length).toBe(2);
expect(Object.keys((await controller.getPendingAttachments())[0]).length).toBe(3);
expect(Object.keys((await controller.getPendingAttachments())[0]).length).toBe(5);
});
describe('Pending structures validation', () => {
......@@ -80,9 +85,11 @@ describe('AdminController', () => {
structureId: '6093ba0e2ab5775cfc01ed3e',
structureName: 'test',
userEmail: 'jean.paul@mii.com',
createdAt: new Date('2021-02-02T10:07:48.000Z'),
updatedAt: new Date('2021-03-02T10:07:48.000Z'),
};
expect((await controller.validatePendingStructure(pendingStructureTest)).length).toBe(2);
expect(Object.keys((await controller.validatePendingStructure(pendingStructureTest))[0]).length).toBe(3);
expect(Object.keys((await controller.validatePendingStructure(pendingStructureTest))[0]).length).toBe(5);
});
it('should get structure does not exist', async () => {
......@@ -90,6 +97,8 @@ describe('AdminController', () => {
structureId: '1093ba0e2ab5775cfc01z2ki',
structureName: 'test',
userEmail: 'jean.paul@mii.com',
createdAt: new Date('2021-02-02T10:07:48.000Z'),
updatedAt: new Date('2021-03-02T10:07:48.000Z'),
};
try {
await controller.validatePendingStructure(pendingStructureTest);
......@@ -106,9 +115,11 @@ describe('AdminController', () => {
structureId: '6093ba0e2ab5775cfc01ed3e',
structureName: 'test',
userEmail: 'jean.paul@mii.com',
createdAt: new Date('2021-02-02T10:07:48.000Z'),
updatedAt: new Date('2021-03-02T10:07:48.000Z'),
};
expect((await controller.refusePendingStructure(pendingStructureTest)).length).toBe(2);
expect(Object.keys((await controller.refusePendingStructure(pendingStructureTest))[0]).length).toBe(3);
expect(Object.keys((await controller.refusePendingStructure(pendingStructureTest))[0]).length).toBe(5);
});
it('should get structure does not exist', async () => {
......@@ -116,6 +127,8 @@ describe('AdminController', () => {
structureId: '1093ba0e2ab5775cfc01z2ki',
structureName: 'test',
userEmail: 'jean.paul@mii.com',
createdAt: new Date('2021-02-02T10:07:48.000Z'),
updatedAt: new Date('2021-03-02T10:07:48.000Z'),
};
try {
await controller.refusePendingStructure(pendingStructureTest);
......
import { ApiOperation, ApiParam } from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import {
Body,
Delete,
Param,
Controller,
Delete,
Get,
Post,
UseGuards,
HttpStatus,
HttpException,
HttpStatus,
Logger,
Param,
Post,
UseGuards,
} from '@nestjs/common';
import { ApiOperation, ApiParam } from '@nestjs/swagger';
import { validate } from 'class-validator';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { NewsletterSubscription } from '../newsletter/newsletter-subscription.schema';
import { NewsletterService } from '../newsletter/newsletter.service';
import { Structure } from '../structures/schemas/structure.schema';
import { StructuresService } from '../structures/services/structures.service';
import { Roles } from '../users/decorators/roles.decorator';
import { RolesGuard } from '../users/guards/roles.guard';
import { IUser } from '../users/interfaces/user.interface';
import { UsersService } from '../users/users.service';
import { AdminService } from './admin.service';
import { PendingStructureDto } from './dto/pending-structure.dto';
import { validate } from 'class-validator';
import { Structure } from '../structures/schemas/structure.schema';
import { IUser } from '../users/interfaces/user.interface';
@Controller('admin')
export class AdminController {
......@@ -29,7 +30,8 @@ export class AdminController {
constructor(
private usersService: UsersService,
private structuresService: StructuresService,
private newsletterService: NewsletterService
private newsletterService: NewsletterService,
private adminService: AdminService
) {}
@UseGuards(JwtAuthGuard, RolesGuard)
......@@ -40,7 +42,10 @@ export class AdminController {
const pendingStructure = await this.usersService.getPendingStructures();
return Promise.all(
pendingStructure.map(async (structure) => {
structure.structureName = (await this.structuresService.findOne(structure.structureId)).structureName;
const structureDocument = await this.structuresService.findOne(structure.structureId);
structure.structureName = structureDocument.structureName;
structure.createdAt = structureDocument.createdAt;
structure.updatedAt = structureDocument.updatedAt;
return structure;
})
);
......@@ -51,11 +56,30 @@ export class AdminController {
@Get('adminStructuresList')
@ApiOperation({ description: 'Get pending structre for validation' })
public async getAdminStructuresList(): Promise<any> {
this.logger.debug('getAdminStructuresList');
const structuresList = { claimed: [], inClaim: [], toClaim: [], incomplete: [] };
structuresList.inClaim = await this.getPendingAttachments();
structuresList.toClaim = (await this.structuresService.findAllUnclaimed()).filter(
(demand) => !structuresList.inClaim.find((elem) => elem.structureId == demand.structureId)
);
const inClaimStructures = await this.getPendingAttachments();
structuresList.inClaim = inClaimStructures.map((structure) => {
const lastUpdateDate = this.adminService.getLastUpdateDate(structure);
return {
structureId: structure.structureId,
structureName: structure.structureName,
updatedAt: lastUpdateDate,
isOutdated: this.adminService.isDateOutdated(lastUpdateDate, 6),
};
});
const toClaimStructures = await this.structuresService.findAllUnclaimed();
structuresList.toClaim = toClaimStructures
.filter((demand) => !structuresList.inClaim.find((elem) => elem.structureId == demand.structureId))
.map((structure) => {
const lastUpdateDate = this.adminService.getLastUpdateDate(structure);
return {
structureId: structure.structureId,
structureName: structure.structureName,
updatedAt: lastUpdateDate,
isOutdated: this.adminService.isDateOutdated(lastUpdateDate, 6),
};
});
const allStructures = await this.structuresService.findAll();
structuresList.claimed = allStructures
.filter(
......@@ -64,14 +88,26 @@ export class AdminController {
!structuresList.toClaim.find((elem) => elem.structureId == demand.id)
)
.map((structure) => {
return { structureId: structure.id, structureName: structure.structureName };
const lastUpdateDate = this.adminService.getLastUpdateDate(structure);
return {
structureId: structure.id,
structureName: structure.structureName,
updatedAt: lastUpdateDate,
isOutdated: this.adminService.isDateOutdated(lastUpdateDate, 6),
};
});
structuresList.incomplete = await Promise.all(
allStructures.map(async (struct) => {
const validity = await validate(new Structure(struct));
if (validity.length > 0) {
this.logger.debug(`getAdminStructuresList - validation failed. errors: ${validity.toString()}`);
return { structureId: struct.id, structureName: struct.structureName };
const lastUpdateDate = this.adminService.getLastUpdateDate(struct);
return {
structureId: struct.id,
structureName: struct.structureName,
updatedAt: lastUpdateDate,
isOutdated: this.adminService.isDateOutdated(lastUpdateDate, 6),
};
} else {
this.logger.debug('getAdminStructuresList - validation succeed');
return null;
......
import { Injectable } from '@nestjs/common';
import { DateTime, Interval } from 'luxon';
import { Structure } from '../structures/schemas/structure.schema';
import { PendingStructureDto } from './dto/pending-structure.dto';
import { UnclaimedStructureDto } from './dto/unclaimed-structure-dto';
@Injectable()
export class AdminService {}
export class AdminService {
public isDateOutdated(date: DateTime, nbMonths: number): boolean {
const today = DateTime.local().setZone('utc', { keepLocalTime: true });
return Interval.fromDateTimes(date, today).length('months') > nbMonths;
}
public getLastUpdateDate(structure: Structure | UnclaimedStructureDto | PendingStructureDto): DateTime {
return structure.updatedAt ? structure.updatedAt : structure.createdAt;
}
}
......@@ -16,4 +16,10 @@ export class PendingStructureDto {
@IsString()
@ApiProperty({ type: String })
structureName: string;
@ApiProperty({ type: Date })
updatedAt: Date;
@ApiProperty({ type: Date })
createdAt: Date;
}
......@@ -11,4 +11,10 @@ export class UnclaimedStructureDto {
@IsString()
@ApiProperty({ type: String })
structureName: string;
@ApiProperty({ type: String })
updatedAt: string;
@ApiProperty({ type: String })
createdAt: string;
}
......@@ -15,6 +15,7 @@ import { PagesModule } from './pages/pages.module';
import { TempUserModule } from './temp-user/temp-user.module';
import { NewsletterModule } from './newsletter/newsletter.module';
import { ContactModule } from './contact/contact.module';
import { ParametersModule } from './parameters/parameters.module';
@Module({
imports: [
ConfigurationModule,
......@@ -34,6 +35,7 @@ import { ContactModule } from './contact/contact.module';
TempUserModule,
NewsletterModule,
ContactModule,
ParametersModule,
],
controllers: [AppController],
})
......
......@@ -6,7 +6,7 @@ import * as sanitizeHtml from 'sanitize-html';
@Injectable()
export class ContactService {
constructor(private readonly mailerService: MailerService) {}
constructor(private readonly mailerService: MailerService) {}
public async sendMessage(contactMessage: ContactMessage): Promise<any> {
const config = this.mailerService.config;
......@@ -19,8 +19,8 @@ export class ContactService {
email: sanitizeHtml(contactMessage.email),
phone: sanitizeHtml(contactMessage.phone),
subject: sanitizeHtml(contactMessage.subject),
message: sanitizeHtml(contactMessage.message).replace(/\n/g, "<br />"),
message: sanitizeHtml(contactMessage.message).replace(/\n/g, '<br />'),
});
return this.mailerService.send(process.env.MAIL_CONTACT, jsonConfig.subject, html);
}
}
\ No newline at end of file
}
import { Db } from 'mongodb';
import { getDb } from '../migrations-utils/db';
export const up = async () => {
const db: Db = await getDb();
await db.collection('parameters').insertOne({ lockdownInfoDisplay: true });
};
export const down = async () => {
const db: Db = await getDb();
db.collection('parameters').drop();
};
import { Db } from 'mongodb';
import { getDb } from '../migrations-utils/db';
export const up = async () => {
const db: Db = await getDb();
await db
.collection('categoriesaccompagnements')
.updateOne(
{ id: 'proceduresAccompaniment', 'modules.id': 'accompagnantCaf' },
{ $set: { 'modules.$.text': 'CAF' } }
);
console.log(
'Updated done: "Accompagnement CAF" to "CAF" from collection "categoriesAccompanements" with document id "proceduresAccompaniment"'
);
};
export const down = async () => {
const db: Db = await getDb();
await db
.collection('categoriesaccompagnements')
.updateOne(
{ id: 'proceduresAccompaniment', 'modules.id': 'accompagnantCaf' },
{ $set: { 'modules.$.text': 'Accompagnement CAF' } }
);
console.log(
'Downgraded "CAF" to "Accompagnement CAF" from collection "categoriesAccompanements" with document id "proceduresAccompaniment"'
);
};
import { Db } from 'mongodb';
import { getDb } from '../migrations-utils/db';
export const up = async () => {
const db: Db = await getDb();
await db.collection('structuretype').updateOne({ name: 'Publique' }, { $push: { values: 'MaisonFranceService' } });
console.log('Updated : MaisonFranceService added to "Publique" document in "StructureType" collection');
};
export const down = async () => {
const db: Db = await getDb();
await db.collection('structuretype').updateOne({ name: 'Publique' }, { $pull: { values: 'MaisonFranceService' } });
console.log('Downgraded : MaisonFranceService removed from "Publique" document in "StructureType" collection');
};
import { Document } from 'mongoose';
export interface IParameters extends Document {
lockdownInfoDisplay: boolean;
}
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { ParametersController } from './parameters.controller';
import { ParametersService } from './parameters.service';
import { Parameters } from './schemas/parameters.schema';
describe('ParametersController', () => {
let controller: ParametersController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ParametersService,
{
provide: getModelToken('Parameters'),
useValue: Parameters,
},
],
controllers: [ParametersController],
}).compile();
controller = module.get<ParametersController>(ParametersController);
});
it('should be defined', async () => {
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 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);
});
});
import { Body, Controller, Post, Get, UseGuards } from '@nestjs/common';
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';
@Controller('parameters')
export class ParametersController {
constructor(private parametersService: ParametersService) {}
@Get()
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
public async getParameters(): Promise<Parameters> {
return this.parametersService.getParameters();
}
@Post()
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
public async setParameterLockdownInfoDisplay(@Body() data: { lockdownInfoDisplay: boolean }): Promise<Parameters> {
return this.parametersService.setParameterLockdownInfoDisplay(data.lockdownInfoDisplay);
}
}