From 66054863ffda381a5f15d9419e3577717b2c9798 Mon Sep 17 00:00:00 2001 From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com> Date: Fri, 18 Dec 2020 17:17:26 +0100 Subject: [PATCH] feat: add APTIC api structure + cron job --- package-lock.json | 37 +++++++++ package.json | 1 + src/app.module.ts | 2 + .../services/aptic-structures.service.ts | 78 +++++++++++++++++++ .../{ => services}/structures.service.ts | 4 +- src/structures/structures.controller.ts | 2 +- src/structures/structures.module.ts | 5 +- template.env | 1 + 8 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 src/structures/services/aptic-structures.service.ts rename src/structures/{ => services}/structures.service.ts (96%) diff --git a/package-lock.json b/package-lock.json index f17f7e9a4..6e30b44fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1394,6 +1394,22 @@ "tslib": "2.0.3" } }, + "@nestjs/schedule": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-0.4.1.tgz", + "integrity": "sha512-pj+zo3DJnoyGQKGguyLn9Nv1KEHZO2vNNGhtrZCIn74GsJL+CkDnd+fpgV85mypaJzjjGRogbMvXUW2UFnJAfg==", + "requires": { + "cron": "1.7.2", + "uuid": "8.3.0" + }, + "dependencies": { + "uuid": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==" + } + } + }, "@nestjs/schematics": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-7.1.3.tgz", @@ -4482,6 +4498,14 @@ "sha.js": "^2.4.8" } }, + "cron": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/cron/-/cron-1.7.2.tgz", + "integrity": "sha512-+SaJ2OfeRvfQqwXQ2kgr0Y5pzBR/lijf5OpnnaruwWnmI799JfWr2jN2ItOV9s3A/+TFOt6mxvKzQq5F0Jp6VQ==", + "requires": { + "moment-timezone": "^0.5.x" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -9796,6 +9820,19 @@ "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==" }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "moment-timezone": { + "version": "0.5.32", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.32.tgz", + "integrity": "sha512-Z8QNyuQHQAmWucp8Knmgei8YNo28aLjJq6Ma+jy1ZSpSk5nyfRT8xgUbSQvD2+2UajISfenndwvFuH3NGS+nvA==", + "requires": { + "moment": ">= 2.9.0" + } + }, "mongodb": { "version": "3.6.3", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.3.tgz", diff --git a/package.json b/package.json index 939149dd3..be649e40e 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@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", diff --git a/src/app.module.ts b/src/app.module.ts index 33d12ac3d..0fdca258b 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,5 +1,6 @@ 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'; @@ -13,6 +14,7 @@ import { MailerModule } from './mailer/mailer.module'; 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, diff --git a/src/structures/services/aptic-structures.service.ts b/src/structures/services/aptic-structures.service.ts new file mode 100644 index 000000000..838a221e8 --- /dev/null +++ b/src/structures/services/aptic-structures.service.ts @@ -0,0 +1,78 @@ +import { HttpException, HttpService, Injectable, HttpStatus } from '@nestjs/common'; +import { Logger } from '@nestjs/common'; +import { Observable } from 'rxjs'; +import { AxiosResponse } from 'axios'; +import { Cron, CronExpression } from '@nestjs/schedule'; +import * as _ from 'lodash'; +import * as https from 'https'; + +@Injectable() +export class ApticStructuresService { + constructor(private readonly httpService: HttpService) {} + + public formatApticStructures(postalCodeData: any[]): any { + // Get all postal code in one array + const postalCodeArray = _.flatten( + postalCodeData.map((data) => { + return data.codesPostaux; + }) + ); + + // Call APTIC Api's + const postalCodePromises = postalCodeArray.map((postalCode) => { + return this.getApticStructures(postalCode).toPromise(); + }); + + Promise.all(postalCodePromises).then((data) => { + const structuresData = _.flatten( + data.map((tmp: { data }) => { + return tmp.data.data; + }) + ); + console.log(structuresData); + //TODO: create structure + //TODO: clean with already existing structures + }); + } + + @Cron(CronExpression.EVERY_MINUTE) + public async getMetopoleMunicipality() { + const req = + 'https://download.data.grandlyon.com/ws/grandlyon/adr_voie_lieu.adrcomgl/all.json?maxfeatures=-1&start=1'; + Logger.log(`Request : ${req}`, 'ApticStructuresService - getMetopoleMunicipality'); + this.httpService.get(encodeURI(req)).subscribe( + (data) => { + const inseeArray = data.data.values.map((municipality) => { + return this.getPostalCodeWithINSEE(municipality.insee).toPromise(); + }); + Promise.all(inseeArray).then((inseData) => { + const postalCodeArray = inseData.map((cpData: { data; config }) => { + return cpData.data; + }); + this.formatApticStructures(postalCodeArray); + }); + }, + (err) => Logger.error(err) + ); + } + + public getPostalCodeWithINSEE(inseeCode: string): Observable<AxiosResponse<any>> { + const req = `https://geo.api.gouv.fr/communes/${inseeCode}?fields=codesPostaux&format=json`; + Logger.log(`Request : ${req}`, 'ApticStructuresService - getMetopoleMunicipality'); + return this.httpService.get(encodeURI(req)); + } + + public getApticStructures(postalCodeData: string): Observable<AxiosResponse<any>> { + const agent = new https.Agent({ + rejectUnauthorized: false, + }); + const req = `https://presence.aptic.fr/postal_code/${postalCodeData}`; + Logger.log(`Request : ${req}`, 'ApticStructuresService'); + return this.httpService.get(req, { + httpsAgent: agent, + headers: { + api_key: process.env.APTIC_TOKEN, + }, + }); + } +} diff --git a/src/structures/structures.service.ts b/src/structures/services/structures.service.ts similarity index 96% rename from src/structures/structures.service.ts rename to src/structures/services/structures.service.ts index 543058c8c..785c6d1aa 100644 --- a/src/structures/structures.service.ts +++ b/src/structures/services/structures.service.ts @@ -3,8 +3,8 @@ import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { Observable } from 'rxjs'; import { AxiosResponse } from 'axios'; -import { CreateStructureDto } from './dto/create-structure.dto'; -import { Structure, StructureDocument } from './schemas/structure.schema'; +import { CreateStructureDto } from '../dto/create-structure.dto'; +import { Structure, StructureDocument } from '../schemas/structure.schema'; import { Logger } from '@nestjs/common'; @Injectable() diff --git a/src/structures/structures.controller.ts b/src/structures/structures.controller.ts index 8026e1747..cb5cd41e7 100644 --- a/src/structures/structures.controller.ts +++ b/src/structures/structures.controller.ts @@ -2,7 +2,7 @@ import { Body, Controller, Get, Param, Post, Query } from '@nestjs/common'; import { CreateStructureDto } from './dto/create-structure.dto'; import { QueryStructure } from './dto/query-structure.dto'; import { Structure } from './schemas/structure.schema'; -import { StructuresService } from './structures.service'; +import { StructuresService } from './services/structures.service'; @Controller('structures') export class StructuresController { diff --git a/src/structures/structures.module.ts b/src/structures/structures.module.ts index 6a82aae92..bd2d9cda6 100644 --- a/src/structures/structures.module.ts +++ b/src/structures/structures.module.ts @@ -3,11 +3,12 @@ import { MongooseModule } from '@nestjs/mongoose'; import { MailerModule } from '../mailer/mailer.module'; import { Structure, StructureSchema } from './schemas/structure.schema'; import { StructuresController } from './structures.controller'; -import { StructuresService } from './structures.service'; +import { StructuresService } from './services/structures.service'; +import { ApticStructuresService } from './services/aptic-structures.service'; @Module({ imports: [MongooseModule.forFeature([{ name: Structure.name, schema: StructureSchema }]), HttpModule, MailerModule], controllers: [StructuresController], - providers: [StructuresService], + providers: [StructuresService, ApticStructuresService], }) export class StructuresModule {} diff --git a/template.env b/template.env index 79db55d3f..4f50e814d 100644 --- a/template.env +++ b/template.env @@ -13,3 +13,4 @@ ME_PORT=<mongo express port> SALT=<Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue> MAIL_URL=<API url> MAIL_TOKEN=<API token> +APTIC_TOKEN=<APTIC API TOKEN> -- GitLab