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 (23)
Showing
with 559 additions and 39 deletions
...@@ -4,10 +4,23 @@ stages: ...@@ -4,10 +4,23 @@ stages:
- build - build
- deploy - deploy
default:
services:
- name: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09-dind
alias: docker
- name: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/elasticsearch:7.16.2
alias: elasticsearch
command: ['bin/elasticsearch', '-Expack.security.enabled=false', '-Ediscovery.type=single-node']
variables:
DEPENDENCY_PROXY: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/
build: build:
variables:
DOCKER_TLS_CERTDIR: ''
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09 image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- docker:18.09-dind
only: only:
- dev - dev
- rec - rec
...@@ -18,6 +31,38 @@ build: ...@@ -18,6 +31,38 @@ build:
- docker build --pull -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" . - docker build --pull -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" .
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
build_branch:
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
except:
- master
- rec
- dev
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 .
- docker push "$CI_REGISTRY_IMAGE/feat:$CI_COMMIT_REF_SLUG"
build-release:
variables:
DOCKER_TLS_CERTDIR: ''
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/:18.09-dind
stage: build
only:
- tags
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull -t "$CI_REGISTRY_IMAGE/tags:$CI_COMMIT_TAG" --build-arg conf=prod .
- docker push "$CI_REGISTRY_IMAGE/tags:$CI_COMMIT_TAG"
deploy_dev: deploy_dev:
stage: deploy stage: deploy
tags: tags:
...@@ -37,10 +82,6 @@ deploy_dev: ...@@ -37,10 +82,6 @@ deploy_dev:
test: test:
stage: test stage: test
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/node:14.15.4 image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/node:14.15.4
services:
- name: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/elasticsearch:7.16.2
alias: elasticsearch
command: ['bin/elasticsearch', '-Expack.security.enabled=false', '-Ediscovery.type=single-node']
before_script: before_script:
- export GHOST_HOST_AND_PORT=http://localhost:2368 - export GHOST_HOST_AND_PORT=http://localhost:2368
- export GHOST_ADMIN_API_KEY=60142bc9e33940000156bccc:6217742e2671e322612e89cac9bab61fcd01822709fe5d8f5e6a5b3e54d5e6bb - export GHOST_ADMIN_API_KEY=60142bc9e33940000156bccc:6217742e2671e322612e89cac9bab61fcd01822709fe5d8f5e6a5b3e54d5e6bb
...@@ -84,9 +125,11 @@ test: ...@@ -84,9 +125,11 @@ test:
# -Dsonar.qualitygate.wait=true # -Dsonar.qualitygate.wait=true
mr: mr:
variables:
DOCKER_TLS_CERTDIR: ''
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09 image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- docker:18.09-dind
stage: build stage: build
only: only:
- merge_requests - merge_requests
......
...@@ -2,6 +2,54 @@ ...@@ -2,6 +2,54 @@
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. 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.15.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v1.13.0...v1.15.0) (2022-02-21)
### Features
* **cicd:** add variables for mr job ([59a5b63](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/59a5b63541a8a46ed1fba87732a85191a31c7c5f))
* **cicd:** rework on automation. Add feature and tag build. Better handling of dependencie proxy ([bae2362](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/bae236298040d7d660876c8b0d4edae0d64d202b))
* **logger:** restrict logging for production ([1fb3c7f](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/1fb3c7f2a4b534e90fa7d9439390c0aa1a17e31d))
* **orientation-form:** structure search apply global filters ([63b6464](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/63b6464e5c9216f2638f38e28bb4ce15b5e012b4))
* **post:** add docker persistent storage for ghost files ([b634839](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/b634839efb922f97dbb134d9d00750673dee47a5))
* **searchResults:** Add descriptions to pages created with script ([14402a4](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/14402a4e890fe4719787f8ab975466dca0174877))
### Bug Fixes
* **cicd:** fix deploy issue after variables adding ([555631c](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/555631cec956e765f615614afab5b4af636fe15e))
* **cicd:** fix test issue ([8933076](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/89330762025de43dc81da08b99ea79736fe53138))
* **cicd:** issue on testing pipeline after variable adding ([365e973](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/365e9736d4684465e1dc0f14aace7f6a22b54ff6))
* **cicd:** update .gitlab-ci ([5d56874](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/5d56874e20e66e6b14f8a701bd5784c7e443eacd))
* **cicd:** update variables ([ee769e8](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/ee769e8a219d2ca2ee60fdd2681d503fb7c3a8e5))
* **cicd:** variable usage was making deploy job fail ([dd1d187](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/dd1d187e2667e35500536e22c13815eb4697f4c5))
* solve incomplete creation of ghost elements in init script ([3dce694](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/3dce694654056011e459a4e18d7397c778e5aaa0))
* update index create root url ([404a625](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/404a62594e2567ecbc661a2e6b80c4385246cd27))
## [1.14.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v1.13.0...v1.14.0) (2022-02-21)
### Features
* **cicd:** add variables for mr job ([59a5b63](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/59a5b63541a8a46ed1fba87732a85191a31c7c5f))
* **cicd:** rework on automation. Add feature and tag build. Better handling of dependencie proxy ([bae2362](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/bae236298040d7d660876c8b0d4edae0d64d202b))
* **logger:** restrict logging for production ([1fb3c7f](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/1fb3c7f2a4b534e90fa7d9439390c0aa1a17e31d))
* **orientation-form:** structure search apply global filters ([63b6464](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/63b6464e5c9216f2638f38e28bb4ce15b5e012b4))
* **post:** add docker persistent storage for ghost files ([b634839](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/b634839efb922f97dbb134d9d00750673dee47a5))
* **searchResults:** Add descriptions to pages created with script ([14402a4](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/14402a4e890fe4719787f8ab975466dca0174877))
### Bug Fixes
* **cicd:** fix deploy issue after variables adding ([555631c](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/555631cec956e765f615614afab5b4af636fe15e))
* **cicd:** fix test issue ([8933076](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/89330762025de43dc81da08b99ea79736fe53138))
* **cicd:** issue on testing pipeline after variable adding ([365e973](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/365e9736d4684465e1dc0f14aace7f6a22b54ff6))
* **cicd:** update .gitlab-ci ([5d56874](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/5d56874e20e66e6b14f8a701bd5784c7e443eacd))
* **cicd:** update variables ([ee769e8](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/ee769e8a219d2ca2ee60fdd2681d503fb7c3a8e5))
* **cicd:** variable usage was making deploy job fail ([dd1d187](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/dd1d187e2667e35500536e22c13815eb4697f4c5))
* solve incomplete creation of ghost elements in init script ([3dce694](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/3dce694654056011e459a4e18d7397c778e5aaa0))
* update index create root url ([404a625](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/404a62594e2567ecbc661a2e6b80c4385246cd27))
## [1.13.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v1.12.0...v1.13.0) (2022-02-07) ## [1.13.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v1.12.0...v1.13.0) (2022-02-07)
......
...@@ -78,6 +78,8 @@ services: ...@@ -78,6 +78,8 @@ services:
database__connection__database: ghost database__connection__database: ghost
# this url value is just an example, and is likely wrong for your environment! # this url value is just an example, and is likely wrong for your environment!
url: http://localhost:${GHOST_PORT} url: http://localhost:${GHOST_PORT}
volumes:
- ghost-content:/var/lib/ghost/content
ghost-db: ghost-db:
image: mysql:5.7 image: mysql:5.7
...@@ -126,6 +128,8 @@ volumes: ...@@ -126,6 +128,8 @@ volumes:
driver: local driver: local
db-elastic: db-elastic:
driver: local driver: local
ghost-content:
driver: local
networks: networks:
backend: backend:
......
{ {
"name": "ram_server", "name": "ram_server",
"version": "1.13.0", "version": "1.15.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
......
{ {
"name": "ram_server", "name": "ram_server",
"private": true, "private": true,
"version": "1.13.0", "version": "1.15.0",
"description": "Nest TypeScript starter repository", "description": "Nest TypeScript starter repository",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
"twitter_title": null, "twitter_title": null,
"twitter_description": null, "twitter_description": null,
"meta_title": null, "meta_title": null,
"meta_description": null, "meta_description": "Découvrez ce qu'est Rés'IN, le Réseau des acteurs de l'inclusion numérique de la Métropole de Lyon",
"frontmatter": null "frontmatter": null
}, },
{ {
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
"twitter_title": null, "twitter_title": null,
"twitter_description": null, "twitter_description": null,
"meta_title": null, "meta_title": null,
"meta_description": null, "meta_description": "Retrouvez tous les détails de l'Acessibilité sur Rés'IN, le Réseau des acteurs de l'inclusion numérique de la Métropole de Lyon.",
"frontmatter": null "frontmatter": null
} }
] ]
...@@ -70,6 +70,8 @@ async function createTags(deleteOnly) { ...@@ -70,6 +70,8 @@ async function createTags(deleteOnly) {
await deleteTags(existingTags).then(() => { await deleteTags(existingTags).then(() => {
console.log('-- Tags dropped --'); console.log('-- Tags dropped --');
}); });
// wait complete deletion of tags or else slugs are messed up when re created before proper deletion
await new Promise((r) => setTimeout(r, 1000));
} else { } else {
console.log('-- No tag to drop --'); console.log('-- No tag to drop --');
} }
...@@ -85,6 +87,8 @@ async function createTags(deleteOnly) { ...@@ -85,6 +87,8 @@ async function createTags(deleteOnly) {
}) })
.catch((error) => console.error(error)); .catch((error) => console.error(error));
}); });
// wait complete creation of tags, if not posts are missing tags not yet created
await new Promise((r) => setTimeout(r, 1000));
} }
}) })
.catch((error) => console.error(error)); .catch((error) => console.error(error));
...@@ -142,6 +146,8 @@ async function createPosts(deleteOnly) { ...@@ -142,6 +146,8 @@ async function createPosts(deleteOnly) {
await deletePosts(existingPosts).then(() => { await deletePosts(existingPosts).then(() => {
console.log('-- Posts dropped --'); console.log('-- Posts dropped --');
}); });
// wait complete deletion of post or else slugs are messed up when re created before proper deletion
await new Promise((r) => setTimeout(r, 1000));
} else { } else {
console.log('-- No posts to drop --'); console.log('-- No posts to drop --');
} }
...@@ -161,6 +167,8 @@ async function createPosts(deleteOnly) { ...@@ -161,6 +167,8 @@ async function createPosts(deleteOnly) {
}) })
.catch((error) => console.error(error)); .catch((error) => console.error(error));
}); });
// wait complete creation of posts
await new Promise((r) => setTimeout(r, 1000));
} }
}) })
.catch((error) => console.error(error)); .catch((error) => console.error(error));
...@@ -181,8 +189,8 @@ async function createPages(deleteOnly) { ...@@ -181,8 +189,8 @@ async function createPages(deleteOnly) {
} else { } else {
console.log('-- No pages to drop --'); console.log('-- No pages to drop --');
} }
// wait complete delete of pages, if not page slugs are appended by _2 // wait complete deletion of pages, if not new pages slugs are appended with '_2'
await new Promise((r) => setTimeout(r, 1000)); await new Promise((r) => setTimeout(r, 2000));
// Creating new pages // Creating new pages
if (!deleteOnly) { if (!deleteOnly) {
...@@ -199,6 +207,8 @@ async function createPages(deleteOnly) { ...@@ -199,6 +207,8 @@ async function createPages(deleteOnly) {
}) })
.catch((error) => console.error(error)); .catch((error) => console.error(error));
}); });
// wait complete creation of pages
await new Promise((r) => setTimeout(r, 1000));
} }
}) })
.catch((error) => console.error(error)); .catch((error) => console.error(error));
......
...@@ -3,7 +3,7 @@ const path = require('path'); ...@@ -3,7 +3,7 @@ const path = require('path');
require('dotenv').config({ path: path.resolve(__dirname, '../.env') }); require('dotenv').config({ path: path.resolve(__dirname, '../.env') });
axios axios
.post('http://localhost:3000/auth/login', { .post('http://localhost:3000/api/auth/login', {
email: 'admin@admin.com', email: 'admin@admin.com',
password: process.env.USER_PWD, password: process.env.USER_PWD,
}) })
...@@ -12,7 +12,7 @@ axios ...@@ -12,7 +12,7 @@ axios
headers: { Authorization: `Bearer ${res.data.accessToken}` }, headers: { Authorization: `Bearer ${res.data.accessToken}` },
}; };
axios axios
.post('http://localhost:3000/structures/resetSearchIndex', {}, config) .post('http://localhost:3000/api/structures/resetSearchIndex', {}, config)
.then((res) => { .then((res) => {
console.log(`statusCode: ${res.status}`); console.log(`statusCode: ${res.status}`);
}) })
......
...@@ -19,4 +19,7 @@ export class CategoriesFormationsService { ...@@ -19,4 +19,7 @@ export class CategoriesFormationsService {
public findOne(categoryId: string): Promise<CategoriesFormations> { public findOne(categoryId: string): Promise<CategoriesFormations> {
return this.structureModel.findOne({ id: categoryId }).select({ 'modules.id': 1 }).exec(); return this.structureModel.findOne({ id: categoryId }).select({ 'modules.id': 1 }).exec();
} }
public findOneComplete(categoryId: string): Promise<CategoriesFormations> {
return this.structureModel.findOne({ id: categoryId }).exec();
}
} }
...@@ -4,7 +4,10 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; ...@@ -4,7 +4,10 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create(AppModule); const app = await NestFactory.create(AppModule, {
logger:
process.env.NODE_ENV === 'production' ? ['error', 'warn', 'log'] : ['log', 'debug', 'error', 'verbose', 'warn'],
});
app.useGlobalPipes(new ValidationPipe()); app.useGlobalPipes(new ValidationPipe());
const options = new DocumentBuilder() const options = new DocumentBuilder()
.setTitle(`Res'in`) .setTitle(`Res'in`)
......
import { Db } from 'mongodb';
import { getDb } from '../migrations-utils/db';
export const up = async () => {
const db: Db = await getDb();
const cursor = db.collection('categoriesformations').find({});
let document;
while ((document = await cursor.next())) {
if (document.id == 'baseSkills') {
const newDoc = {
surname: 'ordinateur, smartphone, internet',
name: 'Compétences de base',
};
await db.collection('categoriesformations').updateOne({ _id: document._id }, [{ $set: newDoc }]);
} else if (document.id == 'accessRight') {
const newDoc = {
surname: 'Pôle emploi, CAF',
name: 'Accès aux droits',
};
await db.collection('categoriesformations').updateOne({ _id: document._id }, [{ $set: newDoc }]);
} else if (document.id == 'parentingHelp') {
const newDoc = {
surname: 'temps d’écran, scolarité',
name: 'Aide à la parentalité',
};
await db.collection('categoriesformations').updateOne({ _id: document._id }, [{ $set: newDoc }]);
} else if (document.id == 'socialAndProfessional') {
const newDoc = {
surname: 'CV, tableur',
name: 'Insertion professionnelle',
};
await db.collection('categoriesformations').updateOne({ _id: document._id }, [{ $set: newDoc }]);
} else if (document.id == 'digitalCultureSecurity') {
const newDoc = {
surname: 'réseaux sociaux, visio',
name: 'Culture numérique',
};
await db.collection('categoriesformations').updateOne({ _id: document._id }, [{ $set: newDoc }]);
}
}
console.log(`Update done`);
};
export const down = async () => {
const db: Db = await getDb();
const cursor = db.collection('categoriesformations').find({});
let document;
while ((document = await cursor.next())) {
if (document.id == 'socialAndProfessional') {
const newDoc = {
surname: null,
name: 'Insertion sociale et professionnelle',
};
await db.collection('categoriesformations').updateOne({ _id: document._id }, [{ $set: newDoc }]);
} else if (document.id == 'baseSkills') {
const newDoc = {
surname: null,
name: 'Les compétences de base',
};
await db.collection('categoriesformations').updateOne({ _id: document._id }, [{ $set: newDoc }]);
} else if (document.id == 'parentingHelp') {
const newDoc = {
surname: null,
name: 'Aide à la parentalité',
};
await db.collection('categoriesformations').updateOne({ _id: document._id }, [{ $set: newDoc }]);
} else if (document.id == 'digitalCultureSecurity') {
const newDoc = {
surname: null,
name: 'Culture et sécurité numérique',
};
await db.collection('categoriesformations').updateOne({ _id: document._id }, [{ $set: newDoc }]);
} else if (document.id == 'accessRight') {
const newDoc = {
surname: null,
name: 'Accès aux droits',
};
await db.collection('categoriesformations').updateOne({ _id: document._id }, [{ $set: newDoc }]);
}
}
console.log(`Update done`);
};
import { HttpModule, HttpStatus } from '@nestjs/common'; import { HttpModule } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config'; import { ConfigModule } from '@nestjs/config';
import { ElasticsearchService } from '@nestjs/elasticsearch';
import { getModelToken } from '@nestjs/mongoose'; import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { CategoriesFormationsServiceMock } from '../../../test/mock/services/categoriesFormations.mock.service';
import { UsersServiceMock } from '../../../test/mock/services/user.mock.service'; import { UsersServiceMock } from '../../../test/mock/services/user.mock.service';
import { CategoriesFormationsService } from '../../categories/services/categories-formations.service';
import { ConfigurationService } from '../../configuration/configuration.service'; import { ConfigurationService } from '../../configuration/configuration.service';
import { MailerModule } from '../../mailer/mailer.module'; import { MailerModule } from '../../mailer/mailer.module';
import { MailerService } from '../../mailer/mailer.service';
import { SearchModule } from '../../search/search.module'; import { SearchModule } from '../../search/search.module';
import { UsersService } from '../../users/users.service'; import { UsersService } from '../../users/users.service';
import { structureDto } from '../dto/structure.dto'; import { structureDto } from '../dto/structure.dto';
import { Structure } from '../schemas/structure.schema'; import { Structure, StructureDocument } from '../schemas/structure.schema';
import { StructuresSearchService } from './structures-search.service'; import { StructuresSearchService } from './structures-search.service';
import { StructuresService } from './structures.service'; import { StructuresService } from './structures.service';
describe('StructuresService', () => { describe('StructuresService', () => {
...@@ -25,17 +25,210 @@ describe('StructuresService', () => { ...@@ -25,17 +25,210 @@ describe('StructuresService', () => {
find: jest.fn(), find: jest.fn(),
}; };
const structuresSearchServiceMock = {
search: jest.fn().mockReturnValue([
{
_id: '6903ba0e2ab5775cfc01ed4d',
structureId: '6903ba0e2ab5775cfc01ed4d',
structureType: null,
digitalCultureSecurity: ['2', '5', '9', '28', '34', '39', '42', '51', '52', '54', '65', '96', '97', '98'],
parentingHelp: ['3', '22', '82', '94'],
socialAndProfessional: ['6', '20', '66', '67', '68', '69', '124', '125', '127'],
accessRight: ['84', '85', '86', '87', '88', '89', '93', '95'],
baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: ['cpam', 'impots', 'carsat', 'poleEmploi'],
publics: ['toutPublic'],
labelsQualifications: ['passNumerique', 'espacePublicNumeriqueepn'],
accessModality: ['accesLibre', 'telephoneVisio', 'surRdv'],
freeWorkShop: false,
createdAt: '2020-11-16T09:30:00.000Z',
updatedAt: '2021-04-12T08:48:00.000Z',
structureName: "L'Atelier Numérique",
description:
"L'Atelier Numérique est l'Espace Public Numérique des Centres Sociaux de Rillieux-la-Pape, ayant pour mission la médiation numérique pour toutes et tous.",
lockdownActivity:
'accesLibres, permanences numériques téléphoniques, cours et ateliers à distance, formations professionnelles.',
contactPhone: '',
contactMail: '',
website: '',
facebook: null,
twitter: null,
instagram: null,
pmrAccess: true,
exceptionalClosures: '',
jaccompagneLesUsagersDansLeursDemarchesEnLigne: true,
publicsAccompaniment: [],
autresAccompagnements: '',
nbComputers: 16,
nbPrinters: 1,
nbTablets: 1,
nbNumericTerminal: 1,
hours: {
monday: {
open: true,
time: [
{
closing: '12:30',
opening: '9:00',
},
{
closing: '17:00',
opening: '13:30',
},
],
},
tuesday: {
open: true,
time: [
{
closing: '12:30',
opening: '9:00',
},
{
closing: '17:00',
opening: '13:30',
},
],
},
wednesday: {
open: true,
time: [
{
closing: '12:30',
opening: '9:00',
},
{
closing: '17:00',
opening: '13:30',
},
],
},
thursday: {
open: true,
time: [
{
closing: '12:30',
opening: '9:00',
},
{
closing: '17:00',
opening: '13:30',
},
],
},
friday: {
open: true,
time: [
{
closing: '12:30',
opening: '9:00',
},
],
},
saturday: {
open: false,
time: [],
},
sunday: {
open: false,
time: [],
},
},
__v: 0,
address: {
numero: '30 bis',
street: 'Avenue Leclerc',
commune: 'Rillieux-la-Pape',
},
coord: [4.9036773, 45.8142196],
accountVerified: true,
linkedin: null,
nbScanners: 1,
otherDescription: null,
},
]),
};
const mockCategoriesFormationsService = {
findOneComplete: jest.fn().mockReturnValue({
_id: '5fbb934180a5c257dc0161f6',
modules: [
{
id: '260',
display_id: '260',
display_name: 'Modules APTIC - n°260',
digest: 'Maitrise de l’environnement d’un ordinateur (clavier, souris)',
text: 'Maitrise de l’environnement d’un ordinateur (clavier, souris)',
},
{
id: '1',
display_id: '1',
display_name: 'Modules APTIC - n°1',
digest: 'Composantes et facettes de l’identité numérique',
text: 'Composantes et facettes de l’identité numérique',
},
{
id: '11',
display_id: '11',
display_name: 'Modules APTIC - n°11',
digest: 'Internet : fonctionnement et outils de navigation web',
text: 'Internet : fonctionnement et outils de navigation web',
},
{
id: '38',
display_id: '38',
display_name: 'Modules APTIC - n°38',
digest: 'Le smartphone : principes de fonctionnement',
text: 'Le smartphone : principes de fonctionnement',
},
{
id: '48',
display_id: '48',
display_name: 'Modules APTIC - n°48',
digest: 'Internet : envoyer, recevoir, gérer ses emails',
text: 'Internet : envoyer, recevoir, gérer ses emails',
},
{
id: '74',
display_id: '74',
display_name: 'Modules APTIC - n°74',
digest: 'Smartphones et Tablettes sous Androïd',
text: 'Smartphones et Tablettes sous Androïd',
},
{
id: '77',
display_id: '77',
display_name: 'Modules APTIC - n°77',
digest: "Smartphone : Les principaux gestes pour l'écran tactile",
text: "Smartphone : Les principaux gestes pour l'écran tactile",
},
],
name: 'Les compétences de base',
id: 'baseSkills',
__v: 0,
}),
};
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
imports: [HttpModule, MailerModule, SearchModule, ConfigModule], imports: [HttpModule, MailerModule, SearchModule, ConfigModule],
providers: [ providers: [
StructuresService, StructuresService,
ConfigurationService, ConfigurationService,
StructuresSearchService, {
provide: StructuresSearchService,
useValue: structuresSearchServiceMock,
},
CategoriesFormationsService,
{ {
provide: getModelToken(Structure.name), provide: getModelToken(Structure.name),
useValue: mockStructureModel, useValue: mockStructureModel,
}, },
{
provide: CategoriesFormationsService,
useValue: mockCategoriesFormationsService,
},
{ {
provide: UsersService, provide: UsersService,
useClass: UsersServiceMock, useClass: UsersServiceMock,
...@@ -56,11 +249,92 @@ describe('StructuresService', () => { ...@@ -56,11 +249,92 @@ describe('StructuresService', () => {
expect(res).toBeTruthy(); expect(res).toBeTruthy();
}); });
it('should searchForStructures', () => { describe('should searchForStructures', () => {
let res = service.searchForStructures('a', [{ nbPrinters: '1' }]); jest.setTimeout(30000);
expect(res).toBeTruthy(); mockStructureModel.find.mockReturnThis();
res = service.searchForStructures('a'); mockStructureModel.exec.mockResolvedValue([
expect(res).toBeTruthy(); {
_id: '6903ba0e2ab5775cfc01ed4d',
structureId: '6903ba0e2ab5775cfc01ed4d',
structureType: null,
digitalCultureSecurity: ['2', '5', '9', '28', '34', '39', '42', '51', '52', '54', '65', '96', '97', '98'],
parentingHelp: ['3', '22', '82', '94'],
socialAndProfessional: ['6', '20', '66', '67', '68', '69', '124', '125', '127'],
accessRight: ['84', '85', '86', '87', '88', '89', '93', '95'],
baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: ['cpam', 'impots', 'carsat', 'poleEmploi'],
publics: ['toutPublic'],
labelsQualifications: ['passNumerique', 'espacePublicNumeriqueepn'],
accessModality: ['accesLibre', 'telephoneVisio', 'surRdv'],
freeWorkShop: false,
createdAt: '2020-11-16T09:30:00.000Z',
updatedAt: '2021-04-12T08:48:00.000Z',
structureName: "L'Atelier Numérique",
description:
"L'Atelier Numérique est l'Espace Public Numérique des Centres Sociaux de Rillieux-la-Pape, ayant pour mission la médiation numérique pour toutes et tous.",
lockdownActivity:
'accesLibres, permanences numériques téléphoniques, cours et ateliers à distance, formations professionnelles.',
contactPhone: '',
contactMail: '',
website: '',
facebook: null,
twitter: null,
instagram: null,
pmrAccess: true,
exceptionalClosures: '',
jaccompagneLesUsagersDansLeursDemarchesEnLigne: true,
publicsAccompaniment: [],
autresAccompagnements: '',
nbComputers: 16,
nbPrinters: 1,
nbTablets: 1,
nbNumericTerminal: 1,
hours: {
monday: {
open: true,
time: [
{
closing: '12:30',
opening: '9:00',
},
{
closing: '17:00',
opening: '13:30',
},
],
},
},
__v: 0,
address: {
numero: '30 bis',
street: 'Avenue Leclerc',
commune: 'Rillieux-la-Pape',
},
coord: [4.9036773, 45.8142196],
accountVerified: true,
linkedin: null,
nbScanners: 1,
otherDescription: null,
},
]);
it('should find 1 structure', async () => {
const res = await service.searchForStructures('a', [{ nbPrinters: '1' }]);
expect(res.length).toBe(1);
});
it('should find 1 structure', async () => {
const res = await service.searchForStructures('a', [{ nbPrinters: '1' }, { '': 'baseSkills' }]);
expect(res.length).toBe(1);
});
it('should find 1 structure', async () => {
const res = await service.searchForStructures('a', [{ '': 'baseSkills' }]);
expect(res.length).toBe(1);
});
it('should find 1 structure', async () => {
const res = await service.searchForStructures('a');
expect(res.length).toBe(1);
});
}); });
it('should create structure', () => { it('should create structure', () => {
......
...@@ -22,6 +22,7 @@ import { CategoriesFormations } from '../../categories/schemas/categoriesFormati ...@@ -22,6 +22,7 @@ import { CategoriesFormations } from '../../categories/schemas/categoriesFormati
import { CategoriesOthers } from '../../categories/schemas/categoriesOthers.schema'; import { CategoriesOthers } from '../../categories/schemas/categoriesOthers.schema';
import { UnclaimedStructureDto } from '../../admin/dto/unclaimed-structure-dto'; import { UnclaimedStructureDto } from '../../admin/dto/unclaimed-structure-dto';
import { depRegex } from '../common/regex'; import { depRegex } from '../common/regex';
import { CategoriesFormationsService } from '../../categories/services/categories-formations.service';
@Injectable() @Injectable()
export class StructuresService { export class StructuresService {
...@@ -30,6 +31,7 @@ export class StructuresService { ...@@ -30,6 +31,7 @@ export class StructuresService {
private readonly userService: UsersService, private readonly userService: UsersService,
private readonly mailerService: MailerService, private readonly mailerService: MailerService,
private structuresSearchService: StructuresSearchService, private structuresSearchService: StructuresSearchService,
private categoriesFormationsService: CategoriesFormationsService,
@InjectModel(Structure.name) private structureModel: Model<StructureDocument> @InjectModel(Structure.name) private structureModel: Model<StructureDocument>
) {} ) {}
...@@ -40,22 +42,57 @@ export class StructuresService { ...@@ -40,22 +42,57 @@ export class StructuresService {
return this.populateES(); return this.populateES();
} }
public fillFilters(filters: Array<any>): Promise<{}[]>[] {
return filters?.map(async (elem) => {
const key = Object.keys(elem)[0];
const modules = (await this.categoriesFormationsService.findOneComplete(elem[key])).modules;
return modules.map((module) => {
return { [elem[key]]: module.id };
});
});
}
async searchForStructures(text: string, filters?: Array<any>): Promise<StructureDocument[]> { async searchForStructures(text: string, filters?: Array<any>): Promise<StructureDocument[]> {
const results = await this.structuresSearchService.search(text); const results = await this.structuresSearchService.search(text);
const ids = results.map((result) => result.structureId); const ids = results.map((result) => result.structureId);
let multipleFilters = filters ? filters.filter((elem) => Object.keys(elem)[0].length == 0) : null;
filters = filters?.filter((elem) => Object.keys(elem)[0].length != 0);
if (multipleFilters) {
const filtersArrays = await Promise.all(this.fillFilters(multipleFilters));
multipleFilters = [].concat.apply([], filtersArrays);
}
if (!ids.length) { if (!ids.length) {
return []; return [];
} }
//we match ids from Elasticsearch with ids from mongoDB (and filters) and sort the result according to ElasticSearch order. //we match ids from Elasticsearch with ids from mongoDB (and filters) and sort the result according to ElasticSearch order.
if (filters.length > 0) { if (filters?.length > 0 && multipleFilters?.length == 0) {
return (
await this.structureModel
.find({
_id: { $in: ids },
$and: [...this.parseFilter(filters), { deletedAt: { $exists: false }, accountVerified: true }],
})
.exec()
).sort((a, b) => ids.indexOf(a.id) - ids.indexOf(b.id));
} else if (filters?.length > 0 && multipleFilters?.length > 0) {
return ( return (
await this.structureModel await this.structureModel
.find({ .find({
_id: { $in: ids }, _id: { $in: ids },
$or: [...this.parseFilter(multipleFilters)],
$and: [...this.parseFilter(filters), { deletedAt: { $exists: false }, accountVerified: true }], $and: [...this.parseFilter(filters), { deletedAt: { $exists: false }, accountVerified: true }],
}) })
.exec() .exec()
).sort((a, b) => ids.indexOf(a.id) - ids.indexOf(b.id)); ).sort((a, b) => ids.indexOf(a.id) - ids.indexOf(b.id));
} else if (filters?.length == 0 && multipleFilters?.length > 0) {
return (
await this.structureModel
.find({
_id: { $in: ids },
$or: [...this.parseFilter(multipleFilters), { deletedAt: { $exists: false }, accountVerified: true }],
})
.exec()
).sort((a, b) => ids.indexOf(a.id) - ids.indexOf(b.id));
} else { } else {
return ( return (
await this.structureModel await this.structureModel
......
...@@ -12,6 +12,9 @@ import { TempUserService } from '../temp-user/temp-user.service'; ...@@ -12,6 +12,9 @@ import { TempUserService } from '../temp-user/temp-user.service';
import { User } from './schemas/user.schema'; import { User } from './schemas/user.schema';
import { UsersController } from './users.controller'; import { UsersController } from './users.controller';
import { UsersService } from './users.service'; import { UsersService } from './users.service';
import { CategoriesFormationsService } from '../categories/services/categories-formations.service';
import { CategoriesModule } from '../categories/categories.module';
import { CategoriesFormationsServiceMock } from '../../test/mock/services/categoriesFormations.mock.service';
describe('UsersController', () => { describe('UsersController', () => {
let controller: UsersController; let controller: UsersController;
...@@ -25,6 +28,10 @@ describe('UsersController', () => { ...@@ -25,6 +28,10 @@ describe('UsersController', () => {
StructuresSearchService, StructuresSearchService,
MailerService, MailerService,
TempUserService, TempUserService,
{
provide: CategoriesFormationsService,
useValue: CategoriesFormationsServiceMock,
},
{ {
provide: getModelToken('TempUser'), provide: getModelToken('TempUser'),
useValue: TempUser, useValue: TempUser,
......
...@@ -10,6 +10,7 @@ export class StructuresForSearchServiceMock { ...@@ -10,6 +10,7 @@ export class StructuresForSearchServiceMock {
street: 'Avenue Edouard Aynard', street: 'Avenue Edouard Aynard',
commune: 'Écully', commune: 'Écully',
}, },
nbPrinters: 1,
description: description:
'Nous sommes une équipe de 6 personnes accompagnant les usagers dans leur démarche de découverte des outils numériques, mettant à disposition sous forme de prêt des liseuses et du livre numérique et organisant des ateliers individuels de prise en main des outils numériques et tentant de répondre aux questions des usages sur des sujets divers.', 'Nous sommes une équipe de 6 personnes accompagnant les usagers dans leur démarche de découverte des outils numériques, mettant à disposition sous forme de prêt des liseuses et du livre numérique et organisant des ateliers individuels de prise en main des outils numériques et tentant de répondre aux questions des usages sur des sujets divers.',
}, },
...@@ -22,6 +23,7 @@ export class StructuresForSearchServiceMock { ...@@ -22,6 +23,7 @@ export class StructuresForSearchServiceMock {
street: " Place de l'Abbe Launay", street: " Place de l'Abbe Launay",
commune: 'Grézieu-la-Varenne', commune: 'Grézieu-la-Varenne',
}, },
nbPrinters: 1,
description: null, description: null,
}, },
{ {
...@@ -33,6 +35,7 @@ export class StructuresForSearchServiceMock { ...@@ -33,6 +35,7 @@ export class StructuresForSearchServiceMock {
street: 'Place de la Mairie', street: 'Place de la Mairie',
commune: 'La Tour-de-Salvagny', commune: 'La Tour-de-Salvagny',
}, },
nbPrinters: 1,
description: null, description: null,
}, },
{ {
...@@ -44,6 +47,7 @@ export class StructuresForSearchServiceMock { ...@@ -44,6 +47,7 @@ export class StructuresForSearchServiceMock {
street: 'Chemin Jean-Marie Vianney', street: 'Chemin Jean-Marie Vianney',
commune: 'Écully', commune: 'Écully',
}, },
nbPrinters: 1,
description: null, description: null,
}, },
{ {
...@@ -56,6 +60,9 @@ export class StructuresForSearchServiceMock { ...@@ -56,6 +60,9 @@ export class StructuresForSearchServiceMock {
commune: 'Oullins', commune: 'Oullins',
}, },
description: null, description: null,
nbPrinters: 1,
baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
}, },
]; ];
} }
......
...@@ -214,6 +214,7 @@ export class StructuresServiceMock { ...@@ -214,6 +214,7 @@ export class StructuresServiceMock {
socialAndProfessional: ['6', '20', '66', '67', '68', '69', '124', '125', '127'], socialAndProfessional: ['6', '20', '66', '67', '68', '69', '124', '125', '127'],
accessRight: ['84', '85', '86', '87', '88', '89', '93', '95'], accessRight: ['84', '85', '86', '87', '88', '89', '93', '95'],
baseSkills: ['260', '1', '11', '38', '48', '74', '77'], baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: ['cpam', 'impots', 'carsat', 'poleEmploi'], proceduresAccompaniment: ['cpam', 'impots', 'carsat', 'poleEmploi'],
publics: ['toutPublic'], publics: ['toutPublic'],
labelsQualifications: ['passNumerique', 'espacePublicNumeriqueepn'], labelsQualifications: ['passNumerique', 'espacePublicNumeriqueepn'],
...@@ -237,7 +238,6 @@ export class StructuresServiceMock { ...@@ -237,7 +238,6 @@ export class StructuresServiceMock {
jaccompagneLesUsagersDansLeursDemarchesEnLigne: true, jaccompagneLesUsagersDansLeursDemarchesEnLigne: true,
publicsAccompaniment: [], publicsAccompaniment: [],
autresAccompagnements: '', autresAccompagnements: '',
equipmentsAndServices: ['ordinateurs', 'tablettes'],
nbComputers: 16, nbComputers: 16,
nbPrinters: 1, nbPrinters: 1,
nbTablets: 1, nbTablets: 1,
...@@ -335,12 +335,12 @@ export class StructuresServiceMock { ...@@ -335,12 +335,12 @@ export class StructuresServiceMock {
{ {
_id: '6093ba0e2ab5775cfc01abce', _id: '6093ba0e2ab5775cfc01abce',
coord: [4.8498155, 45.7514817], coord: [4.8498155, 45.7514817],
equipmentsAndServices: ['wifiEnAccesLibre'],
digitalCultureSecurity: [], digitalCultureSecurity: [],
parentingHelp: [], parentingHelp: [],
socialAndProfessional: [], socialAndProfessional: [],
accessRight: [], accessRight: [],
baseSkills: [], baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: [], proceduresAccompaniment: [],
publicsAccompaniment: [], publicsAccompaniment: [],
publics: ['adultes'], publics: ['adultes'],
...@@ -409,12 +409,12 @@ export class StructuresServiceMock { ...@@ -409,12 +409,12 @@ export class StructuresServiceMock {
{ {
_id: '6093ba0e2ab5775cfc01fffe', _id: '6093ba0e2ab5775cfc01fffe',
coord: [4.8498155, 45.7514817], coord: [4.8498155, 45.7514817],
equipmentsAndServices: ['wifiEnAccesLibre'],
digitalCultureSecurity: [], digitalCultureSecurity: [],
parentingHelp: [], parentingHelp: [],
socialAndProfessional: [], socialAndProfessional: [],
accessRight: [], accessRight: [],
baseSkills: [], baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: [], proceduresAccompaniment: [],
publicsAccompaniment: [], publicsAccompaniment: [],
publics: ['adultes'], publics: ['adultes'],
...@@ -562,12 +562,12 @@ export class StructuresServiceMock { ...@@ -562,12 +562,12 @@ export class StructuresServiceMock {
{ {
_id: '6093ba0e2ab5775cfc01ffff', _id: '6093ba0e2ab5775cfc01ffff',
coord: [4.8498155, 45.7514817], coord: [4.8498155, 45.7514817],
equipmentsAndServices: ['wifiEnAccesLibre'],
digitalCultureSecurity: [], digitalCultureSecurity: [],
parentingHelp: [], parentingHelp: [],
socialAndProfessional: [], socialAndProfessional: [],
accessRight: [], accessRight: [],
baseSkills: [], baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: [], proceduresAccompaniment: [],
publicsAccompaniment: [], publicsAccompaniment: [],
publics: ['adultes'], publics: ['adultes'],
...@@ -715,12 +715,12 @@ export class StructuresServiceMock { ...@@ -715,12 +715,12 @@ export class StructuresServiceMock {
{ {
_id: '6093ba0e2ab5775cfc01ffff', _id: '6093ba0e2ab5775cfc01ffff',
coord: [4.8498155, 45.7514817], coord: [4.8498155, 45.7514817],
equipmentsAndServices: ['wifiEnAccesLibre'],
digitalCultureSecurity: [], digitalCultureSecurity: [],
parentingHelp: [], parentingHelp: [],
socialAndProfessional: [], socialAndProfessional: [],
accessRight: [], accessRight: [],
baseSkills: [], baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: [], proceduresAccompaniment: [],
publicsAccompaniment: [], publicsAccompaniment: [],
publics: ['adultes'], publics: ['adultes'],
...@@ -793,12 +793,12 @@ export class StructuresServiceMock { ...@@ -793,12 +793,12 @@ export class StructuresServiceMock {
return { return {
_id: '6093ba0e2ab5775cfc01ed3e', _id: '6093ba0e2ab5775cfc01ed3e',
coord: [4.8498155, 45.7514817], coord: [4.8498155, 45.7514817],
equipmentsAndServices: ['wifiEnAccesLibre'],
digitalCultureSecurity: [], digitalCultureSecurity: [],
parentingHelp: [], parentingHelp: [],
socialAndProfessional: [], socialAndProfessional: [],
accessRight: [], accessRight: [],
baseSkills: [], baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: [], proceduresAccompaniment: [],
publicsAccompaniment: [], publicsAccompaniment: [],
publics: ['adultes'], publics: ['adultes'],
......