Skip to content
Snippets Groups Projects
Commit bf54277a authored by Hugo SUBTIL's avatar Hugo SUBTIL
Browse files

Merge branch 'dev' into 'recette'

Dev

See merge request web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server!26
parents 37eb2986 dfc99ce9
No related branches found
No related tags found
2 merge requests!27Recette,!26Dev
Showing
with 2716 additions and 323 deletions
......@@ -12,19 +12,39 @@ build:
image: docker:18.09
services:
- docker:18.09-dind
only:
- dev
- rec
- master
stage: build
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" .
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
deploy_dev:
stage: deploy
tags:
- deploy
only:
- dev
script:
- cd /home/mps/ram
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker-compose pull service-ram
- docker-compose up -d service-ram
- docker system prune -a -f
code_analysis:
image: skilldlabs/sonar-scanner:3.4.0
image: skilldlabs/sonar-scanner:4.0.0
services:
- docker:18.09-dind
stage: sonar-analysis
only:
- dev
before_script:
- export NODE_PATH=$NODE_PATH:`npm root -g`
- npm install -g typescript
script:
- >
sonar-scanner
......@@ -35,3 +55,14 @@ code_analysis:
-Dsonar.host.url=${SONAR_URL}
-Dsonar.projectKey=${SONAR_PROJECT_KEY}
-Dsonar.login=${SONAR_TOKEN}
mr:
image: docker:18.09
services:
- docker:18.09-dind
stage: build
only:
- merge_requests
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build .
# Changelog
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.4.0](https://forge.grandlyon.com///compare/v1.3.0...v1.4.0) (2021-02-01)
### Features
* **structures:** add admin delete ([43eb15b](https://forge.grandlyon.com///commit/43eb15b70acfddfb251e02f98abd0840d7eb4567))
* add address search for structure registration ([c4811fb](https://forge.grandlyon.com///commit/c4811fb22dfab9149d94e4b87dcb79570a895f26))
* add APTIC api structure + cron job ([88bc8fd](https://forge.grandlyon.com///commit/88bc8fdc489059fe11fb1ee83b5b5716d9daf7e0))
* add APTIC api structure + cron job ([6605486](https://forge.grandlyon.com///commit/66054863ffda381a5f15d9419e3577717b2c9798))
* add email sending for outdated structures ([20fd741](https://forge.grandlyon.com///commit/20fd741e6c3c9a06ebce3f056f107d28e9cf50f8))
### Bug Fixes
* add trim for opendata request to solve 400 request issue ([2d3b357](https://forge.grandlyon.com///commit/2d3b357965e0a5fa18d0e9207174a9143b1cb9cc))
* configuration logs and bug fix for user registration ([eb8b243](https://forge.grandlyon.com///commit/eb8b24330f0380eecb1cad762c18f1cd8f6ce1b6))
* cron duration ([2f86c0b](https://forge.grandlyon.com///commit/2f86c0bcbf6b52f83ca9f7f5de8a740bda5d135f))
* fix duplication bug from aptic structure ([4838342](https://forge.grandlyon.com///commit/48383420588f4b221dbf920f65e30e8da9def88f))
* merge conflit ([6a4290d](https://forge.grandlyon.com///commit/6a4290df9a0c42134f10b61c7de31d542acfc3fe))
* outdated structure range ([0d2666f](https://forge.grandlyon.com///commit/0d2666fd7ae0922cbf188ee3fd16a570e9192195))
* update conf ([e7070d1](https://forge.grandlyon.com///commit/e7070d130edbf875b8851eec89a4cf75ca8b3689))
* update mailing templates, user model wrong type and aptic structure handling when a structure is updated. ([f1b69ba](https://forge.grandlyon.com///commit/f1b69ba24d961c031b4f54eeaf1cc5b0cbd0a1d8))
* **structure:** remove unecessary sort for search ([2982dfe](https://forge.grandlyon.com///commit/2982dfe3ffa3b15f41f2bea497f16c255063e2c7))
* **structure:** structure id creation ([7b14c80](https://forge.grandlyon.com///commit/7b14c808b8e04a34552e58eb243906b6acd9bbfc))
* unecessary id declaration in model structure ([e788e55](https://forge.grandlyon.com///commit/e788e55e0c63155c5994b39cbc2f37871f2b4398))
## [1.3.0](https://forge.grandlyon.com///compare/v1.2.0...v1.3.0) (2021-01-15)
### Features
* add admin module + add validation for claiming structures ([95ed7ec](https://forge.grandlyon.com///commit/95ed7eca7c099e24aeeb6ffb535e5b59858162fb))
* add new field in structure schema ([b09c65d](https://forge.grandlyon.com///commit/b09c65d4139976d22d20589d0b3f6e62ef996e2f))
* add role guard ([acb79f2](https://forge.grandlyon.com///commit/acb79f25c7a4c7ee447e4409be25682152b3f739))
* add role to jwt ([f446fd9](https://forge.grandlyon.com///commit/f446fd990de074512e1dc8dcfd7bba31e8b0c9e1))
* add sending of email when structure is validate or not by an admin ([6d683b5](https://forge.grandlyon.com///commit/6d683b5f28489c955b9dc9cfb3cf6522b07ef979))
* add structure name in claim validation mail ([3ad4b8c](https://forge.grandlyon.com///commit/3ad4b8cc7c6b111c45814b738184e56350053da1))
* add tcl module ([b3807e2](https://forge.grandlyon.com///commit/b3807e264a53be1717d316cd512f09bb371e454d))
* claim structure ([8f1bc01](https://forge.grandlyon.com///commit/8f1bc01010e3575a5fd53027be7bb9e680e8fc7c))
### Bug Fixes
* mail issue after sen change ([29cdc20](https://forge.grandlyon.com///commit/29cdc20d5e636548665a4f7868dcd2802fe0a4c4))
* structure claim check with bdd ([e0ff4df](https://forge.grandlyon.com///commit/e0ff4df5be560a3e79a563a80b824be80ce62781))
## [1.2.0](https://forge.grandlyon.com///compare/v1.1.0...v1.2.0) (2020-12-18)
### Features
* add comments and TU ([5c0dd46](https://forge.grandlyon.com///commit/5c0dd468d34f11c9e9fea2817a3600267f043043))
* add password cahnge endpoint ([cead66e](https://forge.grandlyon.com///commit/cead66ea129de7d7b38e026e6ee89d6fa2892f5e))
* add password reset ([ffea481](https://forge.grandlyon.com///commit/ffea481f8275c93748c114488c150d8b9ace3edd))
* add tu for password change ([c3eb184](https://forge.grandlyon.com///commit/c3eb184b73169d0c7611298f7e3fb00bde72a21a))
* structure edit + data refacto ([a2a65e8](https://forge.grandlyon.com///commit/a2a65e8a2ed3fb2bb8ea1066945d7b044eee7357))
* update dto definition for swagger ([d7a30ed](https://forge.grandlyon.com///commit/d7a30ed7a0e7e0f74e85dace474152f9a184bfc5))
* **auth:** add expiration date on token ([771bd91](https://forge.grandlyon.com///commit/771bd9165b700eb29cc473723d363997695d7f5f))
* **auth:** add user verification endpoint ([7b1fe8a](https://forge.grandlyon.com///commit/7b1fe8a6db800f0182c372e09c720d17771382a1))
* **auth:** send validation mail ([ccbfe8f](https://forge.grandlyon.com///commit/ccbfe8ffda6db3f55b1ff6263f189ef583df3a61))
* **auth:** update password strength verification, increase security with salt in env variable ([8cf88c0](https://forge.grandlyon.com///commit/8cf88c0eb37975172de43a869e30ae125edcacf3))
* **cicd:** add sonar conf + deploy ([1595281](https://forge.grandlyon.com///commit/1595281e0254bbbc06e89cc0058a0dc58a0e9a16))
* **cicd:** init cicd with build ([7156660](https://forge.grandlyon.com///commit/71566600376fcc43a9aa4b0486853746a6cf31be))
* **config:** update logging and add envconfiguration handling ([2ccc5e8](https://forge.grandlyon.com///commit/2ccc5e86bc34a5afaef901ca3ae1dca80c6294f4))
* **mailer:** add ejs template handling ([2b68810](https://forge.grandlyon.com///commit/2b68810cd5a7915da4370e91ae866020e5482df6))
### Bug Fixes
* **mailer:** update mailer service with new sen api request form ([edd8d04](https://forge.grandlyon.com///commit/edd8d0415224a5f55ef594bf7bd993d0af414b75))
* change token variables ([64d5fd4](https://forge.grandlyon.com///commit/64d5fd4830bfcb55f8226c4184f0851fa6ca7b5b))
* import typo ([cead291](https://forge.grandlyon.com///commit/cead291d4845201d2ebf42ef39ebda9b8299066f))
* route in reset-password mail template ([b9de8c9](https://forge.grandlyon.com///commit/b9de8c935cd2f7ae267292d7df3b560410012127))
* update missing import ([e9c77cb](https://forge.grandlyon.com///commit/e9c77cb64213929ad9a7cf402f00ae59f4a42260))
* **cicd:** add mr validation build + sonar ts ([da070d2](https://forge.grandlyon.com///commit/da070d2aa8a56f70279ff641090ad0df43314abc))
* **cicd:** add mr validation build + sonar ts ([8025ab2](https://forge.grandlyon.com///commit/8025ab2f3abed73f2354bb5254982dc0fb08628e))
* **cicd:** docker build issue ([7732250](https://forge.grandlyon.com///commit/7732250a37b8c1edc9af9509037aebf4f232f466))
* **cicd:** docker-compose version ([0187808](https://forge.grandlyon.com///commit/018780838acc590f5d799828a9a57a689b06f723))
* **cicd:** image build ([78c33c2](https://forge.grandlyon.com///commit/78c33c237b194c5c86e7bdd91f52be221fb63f76))
* **cicd:** image build ([50c1fd1](https://forge.grandlyon.com///commit/50c1fd1108fe50b9e19ebe256753a2284f87a021))
* **TU:** Add unitary testing for auth service ([af44ba0](https://forge.grandlyon.com///commit/af44ba026e4bba564f87ad268ea2bd8ef5a5c566))
* **TU:** fix import issues on TU and add user.service TU ([a0f9456](https://forge.grandlyon.com///commit/a0f94564ef8b04fa10503ec789901e758975888c))
* **TU:** wrong test description ([647da39](https://forge.grandlyon.com///commit/647da394bef7a16febf223220b581f78100b685a))
* build issue because of typo in imports ([fca81cb](https://forge.grandlyon.com///commit/fca81cb4687e141bf311d15e42c6a67e2de5e407))
## 1.1.0 (2020-12-01)
### Features
* add categories endpoint ([b610803](https://forge.grandlyon.com///commit/b6108038843cdaf5099beb369bdd23e98d10f126))
* add count handling ([d918fb7](https://forge.grandlyon.com///commit/d918fb7e8a15061f482359b6e9b4cf8b1e424cea))
* add first working version for structure endpoint ([42b760b](https://forge.grandlyon.com///commit/42b760bc70029b3b19439b34aac38448ed7c65f5))
* add full text search ([609b51b](https://forge.grandlyon.com///commit/609b51b8a40056be18cc2b7fe39674c1db463c48))
* add health check ([0673e49](https://forge.grandlyon.com///commit/0673e49a7a9792e60910e1887ad4dcc56d453750))
* add registration and auth ([99b3c50](https://forge.grandlyon.com///commit/99b3c509f27e7fa2d105431347658957a017dcf0))
* first working version of auth ([8d8ff61](https://forge.grandlyon.com///commit/8d8ff617ea3065b54145502e7e8277c97304ac30))
* parse boolean string to boolean for search filter + Refacto ([1184295](https://forge.grandlyon.com///commit/1184295c0cadf04771fc377b0b6fd09507ceecc4))
* update readme + make coord and address call in backend instead of front ([87ca741](https://forge.grandlyon.com///commit/87ca7411ca6a61c5e23319fa472f8dff10627c8c))
* **docker:** add docker handling for mongo database ([d66af3c](https://forge.grandlyon.com///commit/d66af3c04547e85b222ef73eeee090520edd6d22))
### Bug Fixes
* or instead of and for filter search query ([e135dfb](https://forge.grandlyon.com///commit/e135dfb02db44621f25e08d36bc8475393e62573))
* search issue ([13e5b81](https://forge.grandlyon.com///commit/13e5b816236236ce2bf73a7179f0ea5b51ae6703))
* typo in structure.controller ([d9000b4](https://forge.grandlyon.com///commit/d9000b4d9d98454b8f99148cd8a5e0ed1c32adee))
* update docker-compose ([857a2d5](https://forge.grandlyon.com///commit/857a2d54ca8284778a7963828cfe6a55fcfce1ec))
......@@ -7,11 +7,17 @@ WORKDIR /app
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./
RUN npm install
RUN chgrp -R 0 /app && chmod -R g+rwX /app
RUN npm install --silent
# Bundle app source
COPY . .
COPY tsconfig.build.json .
COPY tsconfig.json .
COPY src src
RUN npm run build
CMD ["sh","-c", "npm run start:prod"]
CMD npm run start:prod
EXPOSE 3000
version: '3.1'
version: '2'
services:
service-ram:
......@@ -42,5 +42,29 @@ services:
ME_CONFIG_BASICAUTH_PASSWORD: ${ME_CONFIG_BASICAUTH_PASSWORD}
ME_CONFIG_MONGODB_SERVER: database-ram
ghost:
image: ghost:latest
restart: always
ports:
- ${GHOST_PORT}:2368
environment:
# see https://docs.ghost.org/docs/config#section-running-ghost-with-config-env-variables
database__client: mysql
database__connection__host: ghost-db
database__connection__user: root
database__connection__password: ${GHOST_DB_PASSWORD}
database__connection__database: ghost
# this url value is just an example, and is likely wrong for your environment!
url: http://localhost:${GHOST_PORT}
ghost-db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${GHOST_DB_PASSWORD}
volumes:
- db-ghost
volumes:
db-ram:
db-ghost:
This diff is collapsed.
{
"name": "ram_server",
"private": true,
"version": "1.0.0",
"version": "1.4.0",
"description": "Nest TypeScript starter repository",
"license": "MIT",
"scripts": {
......@@ -13,6 +13,7 @@
"start:debug": "nodemon --config nodemon-debug.json",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"release": "standard-version",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
......@@ -22,14 +23,28 @@
"dependencies": {
"@nestjs/common": "^7.5.1",
"@nestjs/core": "^7.5.1",
"@nestjs/jwt": "^7.2.0",
"@nestjs/mongoose": "^7.1.0",
"@nestjs/passport": "^7.1.5",
"@nestjs/platform-express": "^7.5.1",
"@nestjs/schedule": "^0.4.1",
"@nestjs/swagger": "^4.7.5",
"@types/bcrypt": "^3.0.0",
"bcrypt": "^5.0.0",
"class-transformer": "^0.3.1",
"class-validator": "^0.12.2",
"dotenv": "^8.2.0",
"ejs": "^3.1.5",
"form-data": "^3.0.0",
"luxon": "^1.25.0",
"mongoose": "^5.10.15",
"passport": "^0.4.1",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^6.6.3",
"standard-version": "^9.0.0",
"swagger-ui-express": "^4.1.5"
},
"devDependencies": {
......@@ -40,6 +55,7 @@
"@types/jest": "^26.0.15",
"@types/mongoose": "^5.10.1",
"@types/node": "^14.14.6",
"@types/passport-local": "^1.0.33",
"@types/supertest": "^2.0.10",
"@typescript-eslint/eslint-plugin": "^4.6.1",
"@typescript-eslint/parser": "^4.6.1",
......
import { Test, TestingModule } from '@nestjs/testing';
import { StructuresController } from './structures.controller';
import { AdminController } from './admin.controller';
describe('StructuresController', () => {
let controller: StructuresController;
describe('AdminController', () => {
let controller: AdminController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [StructuresController],
controllers: [AdminController],
}).compile();
controller = module.get<StructuresController>(StructuresController);
controller = module.get<AdminController>(AdminController);
});
it('should be defined', () => {
......
import { Body } from '@nestjs/common';
import { Controller, Get, Post, UseGuards } from '@nestjs/common';
import { ApiOperation } from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { StructuresService } from '../structures/services/structures.service';
import { Roles } from '../users/decorators/roles.decorator';
import { RolesGuard } from '../users/guards/roles.guard';
import { UsersService } from '../users/users.service';
import { PendingStructureDto } from './dto/pending-structure.dto';
@Controller('admin')
export class AdminController {
constructor(private usersService: UsersService, private structuresService: StructuresService) {}
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@Get('pendingStructures')
@ApiOperation({ description: 'Get pending structre for validation' })
public getPendingAttachments(): Promise<PendingStructureDto[]> {
return this.usersService.getPendingStructures();
}
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@Post('validatePendingStructure')
@ApiOperation({ description: 'Validate structure ownership' })
public async validatePendingStructure(@Body() pendingStructureDto: PendingStructureDto) {
const structure = await this.structuresService.findOne(pendingStructureDto.structureId);
return this.usersService.validatePendingStructure(
pendingStructureDto.userEmail,
pendingStructureDto.structureId,
structure.structureName,
true
);
}
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@Post('rejectPendingStructure')
@ApiOperation({ description: 'Refuse structure ownership' })
public async refusePendingStructure(@Body() pendingStructureDto: PendingStructureDto) {
const structure = await this.structuresService.findOne(pendingStructureDto.structureId);
return this.usersService.validatePendingStructure(
pendingStructureDto.userEmail,
pendingStructureDto.structureId,
structure.structureName,
false
);
}
}
import { Module } from '@nestjs/common';
import { StructuresModule } from '../structures/structures.module';
import { UsersModule } from '../users/users.module';
import { AdminController } from './admin.controller';
import { AdminService } from './admin.service';
@Module({
imports: [UsersModule, StructuresModule],
controllers: [AdminController],
providers: [AdminService],
})
export class AdminModule {}
import { Test, TestingModule } from '@nestjs/testing';
import { StructuresService } from './structures.service';
import { AdminService } from './admin.service';
describe('StructuresService', () => {
let service: StructuresService;
describe('AdminService', () => {
let service: AdminService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [StructuresService],
providers: [AdminService],
}).compile();
service = module.get<StructuresService>(StructuresService);
service = module.get<AdminService>(AdminService);
});
it('should be defined', () => {
......
import { Injectable } from '@nestjs/common';
@Injectable()
export class AdminService {}
import { ApiProperty } from '@nestjs/swagger';
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
export class PendingStructureDto {
@IsNotEmpty()
@IsEmail()
@ApiProperty({ type: String })
readonly userEmail: string;
@IsNotEmpty()
@IsString()
@ApiProperty({ type: String })
readonly structureId: string;
}
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';
describe('AppController', () => {
let app: TestingModule;
beforeAll(async () => {
app = await Test.createTestingModule({
controllers: [AppController],
providers: [AppService],
}).compile();
});
describe('getHello', () => {
it('should return "Hello World!"', () => {
describe('healthcheck', () => {
it('should return "Hello World!"', async () => {
const appController = app.get<AppController>(AppController);
expect(appController.getHello()).toBe('Hello World!');
const result = { status: 'API Online', uptime: 1 };
jest.spyOn(appController, 'healthcheck').mockImplementation(async (): Promise<{ status; uptime }> => result);
expect(await appController.healthcheck()).toBe(result);
});
});
});
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { ScheduleModule } from '@nestjs/schedule';
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 { MailerModule } from './mailer/mailer.module';
import { TclModule } from './tcl/tcl.module';
import { AdminModule } from './admin/admin.module';
import { PostsModule } from './posts/posts.module';
@Module({
imports: [
ConfigurationModule,
MongooseModule.forRoot(
`mongodb://${process.env.MONGO_NON_ROOT_USERNAME}:${process.env.MONGO_NON_ROOT_PASSWORD}@${process.env.MONGO_DB_HOST_AND_PORT}/ram`
),
ScheduleModule.forRoot(),
StructuresModule,
CategoriesModule,
AuthModule,
UsersModule,
MailerModule,
TclModule,
AdminModule,
PostsModule,
],
controllers: [AppController],
})
......
import { JwtModule } from '@nestjs/jwt';
import { getModelToken } from '@nestjs/mongoose';
import { PassportModule } from '@nestjs/passport';
import { Test, TestingModule } from '@nestjs/testing';
import { ConfigurationModule } from '../configuration/configuration.module';
import { MailerModule } from '../mailer/mailer.module';
import { User } from '../users/schemas/user.schema';
import { UsersService } from '../users/users.service';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
describe('AuthController', () => {
let controller: AuthController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
PassportModule,
MailerModule,
ConfigurationModule,
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: { expiresIn: '86400s' }, // 24h validity
}),
],
controllers: [AuthController],
providers: [
AuthService,
UsersService,
{
provide: getModelToken('User'),
useValue: User,
},
],
}).compile();
controller = module.get<AuthController>(AuthController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
import { Controller, Post, Body } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LoginDto } from './login-dto';
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
@Post('login')
async login(@Body() loginDto: LoginDto) {
return this.authService.login(loginDto);
}
}
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './strategy/jwt.strategy';
@Module({
imports: [
UsersModule,
PassportModule,
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: { expiresIn: '86400s' }, // 24h validity
}),
],
providers: [AuthService, JwtStrategy],
controllers: [AuthController],
})
export class AuthModule {}
import { HttpException, HttpStatus } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { getModelToken } from '@nestjs/mongoose';
import { PassportModule } from '@nestjs/passport';
import { Test, TestingModule } from '@nestjs/testing';
import { ConfigurationModule } from '../configuration/configuration.module';
import { MailerModule } from '../mailer/mailer.module';
import { User } from '../users/schemas/user.schema';
import { UsersService } from '../users/users.service';
import { AuthService } from './auth.service';
import { LoginDto } from './login-dto';
describe('AuthService', () => {
let service: AuthService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
PassportModule,
MailerModule,
ConfigurationModule,
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: { expiresIn: '86400s' }, // 24h validity
}),
],
providers: [
AuthService,
UsersService,
{
provide: getModelToken('User'),
useValue: User,
},
],
}).compile();
service = module.get<AuthService>(AuthService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('validateUser', () => {
it('should validateUser', async () => {
const result = {
_id: 'tsfsf6296',
validationToken:
'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42',
emailVerified: false,
email: 'jacques.dupont@mii.com',
role: 0,
};
const loginDto: LoginDto = { email: 'jacques.dupont@mii.com', password: 'test1A!!' }; //NOSONAR
jest.spyOn(service, 'validateUser').mockImplementation(async (): Promise<any> => result);
expect(await service.validateUser(loginDto)).toBe(result);
});
it('should not validateUser', async () => {
const result = null;
const loginDto: LoginDto = { email: 'jacques.dupont@mii.com', password: 'test1A!!' }; //NOSONAR
jest.spyOn(service, 'validateUser').mockImplementation(async (): Promise<any> => result);
expect(await service.validateUser(loginDto)).toBe(result);
});
});
describe('login', () => {
it('should login user jacques.dupont@mii.com', async () => {
const result = { username: ' jacques.dupont@mii.com', token: 'tok3n!1sfq' };
const loginDto: LoginDto = { email: 'jacques.dupont@mii.com', password: 'test1A!!' }; //NOSONAR
jest.spyOn(service, 'validateUser').mockImplementation(async (): Promise<{ username; token }> => result);
expect(await service.validateUser(loginDto)).toBe(result);
});
it('should not login jacques.dupont@mii.com, email not verified', async () => {
const result = new HttpException('Invalid credentials', HttpStatus.UNAUTHORIZED);
const loginDto: LoginDto = { email: 'jacques.dupont@mii.com', password: 'test1A!!' }; //NOSONAR
jest.spyOn(service, 'validateUser').mockImplementation(async (): Promise<any> => result);
expect(await service.validateUser(loginDto)).toBe(result);
});
it('should not login jacques.dupont@mii.com, bad password', async () => {
const result = new HttpException('Invalid credentials', HttpStatus.UNAUTHORIZED);
const loginDto: LoginDto = { email: 'jacques.dupont@mii.com', password: 'test1A!!' }; //NOSONAR
jest.spyOn(service, 'validateUser').mockImplementation(async (): Promise<any> => result);
expect(await service.validateUser(loginDto)).toBe(result);
});
it('should not login jacques.dupont@mii.com, username does not exist', async () => {
const result = new HttpException('Invalid credentials', HttpStatus.UNAUTHORIZED);
const loginDto: LoginDto = { email: 'jacques.dupont@mii.com', password: 'test1A!!' }; //NOSONAR
jest.spyOn(service, 'validateUser').mockImplementation(async (): Promise<any> => result);
expect(await service.validateUser(loginDto)).toBe(result);
});
});
});
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { UsersService } from '../users/users.service';
import { JwtService } from '@nestjs/jwt';
import { LoginDto } from './login-dto';
import { DateTime } from 'luxon';
import { User } from '../users/schemas/user.schema';
@Injectable()
export class AuthService {
constructor(private usersService: UsersService, private jwtService: JwtService) {}
async validateUser(loginDto: LoginDto): Promise<any> {
const user = await this.usersService.findOne(loginDto.email);
if (user) {
return user;
}
return null;
}
async login(loginDto: LoginDto): Promise<{ username; token }> {
// find user in db
const user: User = await this.usersService.findByLogin(loginDto);
if (!user.emailVerified) {
throw new HttpException('Invalid credentials', HttpStatus.UNAUTHORIZED);
}
// generate and sign token
const token = this._createToken(user);
return {
username: user.email,
name: user.name,
surname: user.surname,
...token,
};
}
private _createToken(user: User): any {
const local = DateTime.local().setZone('Europe/Paris');
return {
accessToken: this.jwtService.sign({ email: user.email, role: user.role }),
expiresAt: local.plus({ days: 1 }),
};
}
}
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment