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
Commits on Source (19)
Showing
with 512 additions and 105 deletions
......@@ -2,6 +2,28 @@
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.
## [2.0.0-beta2](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v2.0.0-beta1.1...v2.0.0-beta2) (2022-05-24)
### Features
* **admin:** administration panel for jobs and employers ([7ed53e7](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/7ed53e756546b424248f004cf7af9da558a1a434))
* **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))
* **edit-profile:** edit profile page ([23bde5d](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/23bde5dbcd50620fc946c7663518040b92ee8c48))
* **structure:** Get more info about structure owner details ([08f9c75](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/08f9c7539af7dc93d25fb7c97f8320b95f62b618))
* **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
* auth issue with reading env var ([f46b600](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/f46b6003f87ad808a15bf174ff22059b9c9c52f3))
* **dependencies:** update minor version to fix vulnerabilities ([629eeab](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/629eeabd8e3f7ddbdf503027059ad69282a2f925))
* **deps:** update dependency class-validator to ^0.13.0 ([95f7189](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/95f71895ff46ea8bfb2f98f55e4753159a504239))
* elastic unit test ([641e484](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/641e4849ccf324efaa64ba0e164753709361b2d2))
* 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))
## [2.0.0-beta1.1](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v2.0.0-beta1...v2.0.0-beta1.1) (2022-04-04)
......
This diff is collapsed.
{
"name": "ram_server",
"private": true,
"version": "2.0.0-beta1.1",
"version": "2.0.0-beta2",
"description": "Nest TypeScript starter repository",
"license": "MIT",
"scripts": {
......@@ -42,7 +42,7 @@
"@types/bcrypt": "^3.0.0",
"bcrypt": "^5.0.1",
"class-transformer": "^0.3.1",
"class-validator": "^0.12.2",
"class-validator": "^0.13.0",
"dotenv": "^8.2.0",
"ejs": "^3.1.7",
"form-data": "^3.0.0",
......@@ -63,7 +63,7 @@
"@compodoc/compodoc": "^1.1.16",
"@golevelup/ts-jest": "^0.3.2",
"@nestjs/cli": "^7.5.1",
"@nestjs/schematics": "^7.1.3",
"@nestjs/schematics": "^8.0.0",
"@nestjs/testing": "^7.5.1",
"@types/express": "^4.17.8",
"@types/jest": "^26.0.15",
......
......@@ -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,
},
],
......
......@@ -23,6 +23,7 @@ import { EmployerService } from '../users/services/employer.service';
import { JobsService } from '../users/services/jobs.service';
import { UsersService } from '../users/services/users.service';
import { AdminController } from './admin.controller';
import { AdminService } from './admin.service';
describe('AdminController', () => {
let controller: AdminController;
......@@ -78,6 +79,10 @@ describe('AdminController', () => {
provide: NewsletterService,
useClass: NewsletterServiceMock,
},
{
provide: AdminService,
useClass: AdminService,
},
StructuresSearchService,
MailerService,
{
......@@ -123,7 +128,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(4);
expect(Object.keys((await controller.getPendingAttachments())[0]).length).toBe(5);
});
describe('Pending structures validation', () => {
......@@ -132,10 +137,11 @@ describe('AdminController', () => {
structureId: '6093ba0e2ab5775cfc01ed3e',
structureName: 'test',
userEmail: 'jean.paul@mii.com',
updatedAt: '2021-03-02T10:07:48.000Z',
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(4);
expect(Object.keys((await controller.validatePendingStructure(pendingStructureTest))[0]).length).toBe(5);
});
it('should get structure does not exist', async () => {
......@@ -143,7 +149,8 @@ describe('AdminController', () => {
structureId: '1093ba0e2ab5775cfc01z2ki',
structureName: 'test',
userEmail: 'jean.paul@mii.com',
updatedAt: '2021-03-02T10:07:48.000Z',
createdAt: new Date('2021-02-02T10:07:48.000Z'),
updatedAt: new Date('2021-03-02T10:07:48.000Z'),
};
try {
await controller.validatePendingStructure(pendingStructureTest);
......@@ -160,10 +167,11 @@ describe('AdminController', () => {
structureId: '6093ba0e2ab5775cfc01ed3e',
structureName: 'test',
userEmail: 'jean.paul@mii.com',
updatedAt: '2021-03-02T10:07:48.000Z',
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(4);
expect(Object.keys((await controller.refusePendingStructure(pendingStructureTest))[0]).length).toBe(5);
});
it('should get structure does not exist', async () => {
......@@ -171,7 +179,8 @@ describe('AdminController', () => {
structureId: '1093ba0e2ab5775cfc01z2ki',
structureName: 'test',
userEmail: 'jean.paul@mii.com',
updatedAt: '2021-03-02T10:07:48.000Z',
createdAt: new Date('2021-02-02T10:07:48.000Z'),
updatedAt: new Date('2021-03-02T10:07:48.000Z'),
};
try {
await controller.refusePendingStructure(pendingStructureTest);
......
......@@ -11,9 +11,8 @@ import {
Put,
UseGuards,
} from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';
import { ApiBearerAuth, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
import { validate } from 'class-validator';
import { DateTime, Interval } from 'luxon';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { NewsletterSubscription } from '../newsletter/newsletter-subscription.schema';
import { NewsletterService } from '../newsletter/newsletter.service';
......@@ -25,10 +24,12 @@ import { IUser } from '../users/interfaces/user.interface';
import { EmployerService } from '../users/services/employer.service';
import { JobsService } from '../users/services/jobs.service';
import { UsersService } from '../users/services/users.service';
import { AdminService } from './admin.service';
import { PendingStructureDto } from './dto/pending-structure.dto';
import { SetUserEmployerDto } from './dto/set-user-employer.dto';
import { SetUserJobDto } from './dto/set-user-job.dto';
@ApiTags('admin')
@Controller('admin')
export class AdminController {
private readonly logger = new Logger(AdminController.name);
......@@ -37,7 +38,8 @@ export class AdminController {
private structuresService: StructuresService,
private jobsService: JobsService,
private employerService: EmployerService,
private newsletterService: NewsletterService
private newsletterService: NewsletterService,
private adminService: AdminService
) {}
@UseGuards(JwtAuthGuard, RolesGuard)
......@@ -50,6 +52,7 @@ export class AdminController {
pendingStructure.map(async (structure) => {
const structureDocument = await this.structuresService.findOne(structure.structureId);
structure.structureName = structureDocument.structureName;
structure.createdAt = structureDocument.createdAt;
structure.updatedAt = structureDocument.updatedAt;
return structure;
})
......@@ -61,26 +64,28 @@ export class AdminController {
@Get('adminStructuresList')
@ApiOperation({ description: 'Get pending structures for validation' })
public async getAdminStructuresList(): Promise<any> {
this.logger.debug('getAdminStructuresList');
const structuresList = { claimed: [], inClaim: [], toClaim: [], incomplete: [] };
const today = DateTime.local().setZone('utc', { keepLocalTime: true });
const inClaimStructures = await this.getPendingAttachments();
structuresList.inClaim = inClaimStructures.map((structure) => {
const lastUpdateDate = this.adminService.getLastUpdateDate(structure);
return {
structureId: structure.structureId,
structureName: structure.structureName,
updatedAt: structure.updatedAt,
isOutdated: Interval.fromDateTimes(DateTime.fromISO(structure.updatedAt), today).length('months') > 6,
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: structure.updatedAt,
isOutdated: Interval.fromDateTimes(DateTime.fromISO(structure.updatedAt), today).length('months') > 6,
updatedAt: lastUpdateDate,
isOutdated: this.adminService.isDateOutdated(lastUpdateDate, 6),
};
});
const allStructures = await this.structuresService.findAll();
......@@ -91,11 +96,12 @@ export class AdminController {
!structuresList.toClaim.find((elem) => elem.structureId == demand.id)
)
.map((structure) => {
const lastUpdateDate = this.adminService.getLastUpdateDate(structure);
return {
structureId: structure.id,
structureName: structure.structureName,
updatedAt: structure.updatedAt,
isOutdated: Interval.fromDateTimes(DateTime.fromISO(structure.updatedAt), today).length('months') > 6,
updatedAt: lastUpdateDate,
isOutdated: this.adminService.isDateOutdated(lastUpdateDate, 6),
};
});
structuresList.incomplete = await Promise.all(
......@@ -103,12 +109,12 @@ export class AdminController {
const validity = await validate(new Structure(struct));
if (validity.length > 0) {
this.logger.debug(`getAdminStructuresList - validation failed. errors: ${validity.toString()}`);
const lastUpdateDate = this.adminService.getLastUpdateDate(struct);
return {
structureId: struct.id,
structureName: struct.structureName,
updatedAt: struct.updatedAt,
isOutdated: Interval.fromDateTimes(DateTime.fromISO(struct.updatedAt), today).length('months') > 6,
updatedAt: lastUpdateDate,
isOutdated: this.adminService.isDateOutdated(lastUpdateDate, 6),
};
} else {
this.logger.debug('getAdminStructuresList - validation succeed');
......
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;
}
}
import { ApiProperty } from '@nestjs/swagger';
import { IsDate, IsEmail, IsMongoId, IsNotEmpty, IsString } from 'class-validator';
import { IsEmail, IsMongoId, IsNotEmpty, IsString } from 'class-validator';
export class PendingStructureDto {
@IsNotEmpty()
......@@ -17,8 +17,9 @@ export class PendingStructureDto {
@ApiProperty({ type: String })
structureName: string;
@IsNotEmpty()
@IsDate()
@ApiProperty({ type: String })
updatedAt: string;
@ApiProperty({ type: Date })
updatedAt: Date;
@ApiProperty({ type: Date })
createdAt: Date;
}
import { ApiProperty } from '@nestjs/swagger';
import { IsDate, IsNotEmpty, IsString } from 'class-validator';
import { IsNotEmpty, IsString } from 'class-validator';
export class UnclaimedStructureDto {
@IsNotEmpty()
......@@ -12,8 +12,9 @@ export class UnclaimedStructureDto {
@ApiProperty({ type: String })
structureName: string;
@IsNotEmpty()
@IsDate()
@ApiProperty({ type: String })
updatedAt: string;
updatedAt: Date;
@ApiProperty({ type: String })
createdAt: Date;
}
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { ScheduleModule } from '@nestjs/schedule';
import { AdminModule } from './admin/admin.module';
import { AppController } from './app.controller';
import { StructuresModule } from './structures/structures.module';
import { ConfigurationModule } from './configuration/configuration.module';
import { CategoriesModule } from './categories/categories.module';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
import { CategoriesModule } from './categories/categories.module';
import { ConfigurationModule } from './configuration/configuration.module';
import { ContactModule } from './contact/contact.module';
import { MailerModule } from './mailer/mailer.module';
import { TclModule } from './tcl/tcl.module';
import { AdminModule } from './admin/admin.module';
import { PostsModule } from './posts/posts.module';
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 { PagesModule } from './pages/pages.module';
import { ParametersModule } from './parameters/parameters.module';
import { PersonalOffersModule } from './personal-offers/personal-offers.module';
import { PostsModule } from './posts/posts.module';
import { StructuresModule } from './structures/structures.module';
import { TclModule } from './tcl/tcl.module';
import { TempUserModule } from './temp-user/temp-user.module';
import { UsersModule } from './users/users.module';
@Module({
imports: [
ConfigurationModule,
......@@ -36,6 +37,7 @@ import { PersonalOffersModule } from './personal-offers/personal-offers.module';
NewsletterModule,
ContactModule,
PersonalOffersModule,
ParametersModule,
],
controllers: [AppController],
})
......
import { Controller, Post, Body } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AuthService } from './auth.service';
import { LoginDto } from './login-dto';
@ApiTags('auth')
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
......
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import * as dotenv from 'dotenv';
import { UsersModule } from '../users/users.module';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { JwtStrategy } from './strategy/jwt.strategy';
dotenv.config();
@Module({
imports: [
......
......@@ -5,7 +5,9 @@ import { CategoriesAccompagnement } from '../schemas/categoriesAccompagnement.sc
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { Roles } from '../../users/decorators/roles.decorator';
import { RolesGuard } from '../../users/guards/roles.guard';
import { ApiTags } from '@nestjs/swagger';
@ApiTags('categories')
@Controller('categories/categoriesAccompagnement')
export class CategoriesAccompagnementController {
constructor(private readonly categoriesAccompagnementService: CategoriesAccompagnementService) {}
......
......@@ -5,7 +5,9 @@ import { CategoriesFormations } from '../schemas/categoriesFormations.schema';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { Roles } from '../../users/decorators/roles.decorator';
import { RolesGuard } from '../../users/guards/roles.guard';
import { ApiTags } from '@nestjs/swagger';
@ApiTags('categories')
@Controller('categories/categoriesFormations')
export class CategoriesFormationsController {
constructor(private readonly categoriesFormationsService: CategoriesFormationsService) {}
......
......@@ -5,7 +5,9 @@ import { CategoriesOthers } from '../schemas/categoriesOthers.schema';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { Roles } from '../../users/decorators/roles.decorator';
import { RolesGuard } from '../../users/guards/roles.guard';
import { ApiTags } from '@nestjs/swagger';
@ApiTags('categories')
@Controller('categories/categoriesOthers')
export class CategoriesOthersController {
constructor(private readonly categoriesOthersService: CategoriesOthersService) {}
......
import { Body, Controller, Post } from '@nestjs/common';
import { ContactMessage } from './schemas/contact-message.schema';
import { ContactService } from './contact.service';
import { ApiTags } from '@nestjs/swagger';
@ApiTags('contact')
@Controller('contact')
export class ContactController {
constructor(private contactService: ContactService) {}
......
......@@ -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('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 { Body, Controller, Post } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { NewsletterService } from './newsletter.service';
@ApiTags('newsletter')
@Controller('newsletter')
export class NewsletterController {
constructor(private newsletterService: NewsletterService) {}
......