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:
- build
- 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:
variables:
DOCKER_TLS_CERTDIR: ''
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- docker:18.09-dind
only:
- dev
- rec
......@@ -18,6 +31,38 @@ build:
- docker build --pull -t "$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:
stage: deploy
tags:
......@@ -37,10 +82,6 @@ deploy_dev:
test:
stage: test
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:
- export GHOST_HOST_AND_PORT=http://localhost:2368
- export GHOST_ADMIN_API_KEY=60142bc9e33940000156bccc:6217742e2671e322612e89cac9bab61fcd01822709fe5d8f5e6a5b3e54d5e6bb
......@@ -84,9 +125,11 @@ test:
# -Dsonar.qualitygate.wait=true
mr:
variables:
DOCKER_TLS_CERTDIR: ''
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- docker:18.09-dind
stage: build
only:
- merge_requests
......
......@@ -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.
## [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)
......
......@@ -78,6 +78,8 @@ services:
database__connection__database: ghost
# this url value is just an example, and is likely wrong for your environment!
url: http://localhost:${GHOST_PORT}
volumes:
- ghost-content:/var/lib/ghost/content
ghost-db:
image: mysql:5.7
......@@ -126,6 +128,8 @@ volumes:
driver: local
db-elastic:
driver: local
ghost-content:
driver: local
networks:
backend:
......
{
"name": "ram_server",
"version": "1.13.0",
"version": "1.15.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......
{
"name": "ram_server",
"private": true,
"version": "1.13.0",
"version": "1.15.0",
"description": "Nest TypeScript starter repository",
"license": "MIT",
"scripts": {
......
......@@ -26,7 +26,7 @@
"twitter_title": null,
"twitter_description": 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
},
{
......@@ -55,7 +55,7 @@
"twitter_title": null,
"twitter_description": 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
}
]
......@@ -70,6 +70,8 @@ async function createTags(deleteOnly) {
await deleteTags(existingTags).then(() => {
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 {
console.log('-- No tag to drop --');
}
......@@ -85,6 +87,8 @@ async function createTags(deleteOnly) {
})
.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));
......@@ -142,6 +146,8 @@ async function createPosts(deleteOnly) {
await deletePosts(existingPosts).then(() => {
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 {
console.log('-- No posts to drop --');
}
......@@ -161,6 +167,8 @@ async function createPosts(deleteOnly) {
})
.catch((error) => console.error(error));
});
// wait complete creation of posts
await new Promise((r) => setTimeout(r, 1000));
}
})
.catch((error) => console.error(error));
......@@ -181,8 +189,8 @@ async function createPages(deleteOnly) {
} else {
console.log('-- No pages to drop --');
}
// wait complete delete of pages, if not page slugs are appended by _2
await new Promise((r) => setTimeout(r, 1000));
// wait complete deletion of pages, if not new pages slugs are appended with '_2'
await new Promise((r) => setTimeout(r, 2000));
// Creating new pages
if (!deleteOnly) {
......@@ -199,6 +207,8 @@ async function createPages(deleteOnly) {
})
.catch((error) => console.error(error));
});
// wait complete creation of pages
await new Promise((r) => setTimeout(r, 1000));
}
})
.catch((error) => console.error(error));
......
......@@ -3,7 +3,7 @@ const path = require('path');
require('dotenv').config({ path: path.resolve(__dirname, '../.env') });
axios
.post('http://localhost:3000/auth/login', {
.post('http://localhost:3000/api/auth/login', {
email: 'admin@admin.com',
password: process.env.USER_PWD,
})
......@@ -12,7 +12,7 @@ axios
headers: { Authorization: `Bearer ${res.data.accessToken}` },
};
axios
.post('http://localhost:3000/structures/resetSearchIndex', {}, config)
.post('http://localhost:3000/api/structures/resetSearchIndex', {}, config)
.then((res) => {
console.log(`statusCode: ${res.status}`);
})
......
......@@ -19,4 +19,7 @@ export class CategoriesFormationsService {
public findOne(categoryId: string): Promise<CategoriesFormations> {
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';
import { AppModule } from './app.module';
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());
const options = new DocumentBuilder()
.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 { ElasticsearchService } from '@nestjs/elasticsearch';
import { getModelToken } from '@nestjs/mongoose';
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 { CategoriesFormationsService } from '../../categories/services/categories-formations.service';
import { ConfigurationService } from '../../configuration/configuration.service';
import { MailerModule } from '../../mailer/mailer.module';
import { MailerService } from '../../mailer/mailer.service';
import { SearchModule } from '../../search/search.module';
import { UsersService } from '../../users/users.service';
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 { StructuresService } from './structures.service';
describe('StructuresService', () => {
......@@ -25,17 +25,210 @@ describe('StructuresService', () => {
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 () => {
const module: TestingModule = await Test.createTestingModule({
imports: [HttpModule, MailerModule, SearchModule, ConfigModule],
providers: [
StructuresService,
ConfigurationService,
StructuresSearchService,
{
provide: StructuresSearchService,
useValue: structuresSearchServiceMock,
},
CategoriesFormationsService,
{
provide: getModelToken(Structure.name),
useValue: mockStructureModel,
},
{
provide: CategoriesFormationsService,
useValue: mockCategoriesFormationsService,
},
{
provide: UsersService,
useClass: UsersServiceMock,
......@@ -56,11 +249,92 @@ describe('StructuresService', () => {
expect(res).toBeTruthy();
});
it('should searchForStructures', () => {
let res = service.searchForStructures('a', [{ nbPrinters: '1' }]);
expect(res).toBeTruthy();
res = service.searchForStructures('a');
expect(res).toBeTruthy();
describe('should searchForStructures', () => {
jest.setTimeout(30000);
mockStructureModel.find.mockReturnThis();
mockStructureModel.exec.mockResolvedValue([
{
_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', () => {
......
......@@ -22,6 +22,7 @@ import { CategoriesFormations } from '../../categories/schemas/categoriesFormati
import { CategoriesOthers } from '../../categories/schemas/categoriesOthers.schema';
import { UnclaimedStructureDto } from '../../admin/dto/unclaimed-structure-dto';
import { depRegex } from '../common/regex';
import { CategoriesFormationsService } from '../../categories/services/categories-formations.service';
@Injectable()
export class StructuresService {
......@@ -30,6 +31,7 @@ export class StructuresService {
private readonly userService: UsersService,
private readonly mailerService: MailerService,
private structuresSearchService: StructuresSearchService,
private categoriesFormationsService: CategoriesFormationsService,
@InjectModel(Structure.name) private structureModel: Model<StructureDocument>
) {}
......@@ -40,22 +42,57 @@ export class StructuresService {
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[]> {
const results = await this.structuresSearchService.search(text);
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) {
return [];
}
//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 (
await this.structureModel
.find({
_id: { $in: ids },
$or: [...this.parseFilter(multipleFilters)],
$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 (
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 {
return (
await this.structureModel
......
......@@ -12,6 +12,9 @@ import { TempUserService } from '../temp-user/temp-user.service';
import { User } from './schemas/user.schema';
import { UsersController } from './users.controller';
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', () => {
let controller: UsersController;
......@@ -25,6 +28,10 @@ describe('UsersController', () => {
StructuresSearchService,
MailerService,
TempUserService,
{
provide: CategoriesFormationsService,
useValue: CategoriesFormationsServiceMock,
},
{
provide: getModelToken('TempUser'),
useValue: TempUser,
......
......@@ -10,6 +10,7 @@ export class StructuresForSearchServiceMock {
street: 'Avenue Edouard Aynard',
commune: 'Écully',
},
nbPrinters: 1,
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.',
},
......@@ -22,6 +23,7 @@ export class StructuresForSearchServiceMock {
street: " Place de l'Abbe Launay",
commune: 'Grézieu-la-Varenne',
},
nbPrinters: 1,
description: null,
},
{
......@@ -33,6 +35,7 @@ export class StructuresForSearchServiceMock {
street: 'Place de la Mairie',
commune: 'La Tour-de-Salvagny',
},
nbPrinters: 1,
description: null,
},
{
......@@ -44,6 +47,7 @@ export class StructuresForSearchServiceMock {
street: 'Chemin Jean-Marie Vianney',
commune: 'Écully',
},
nbPrinters: 1,
description: null,
},
{
......@@ -56,6 +60,9 @@ export class StructuresForSearchServiceMock {
commune: 'Oullins',
},
description: null,
nbPrinters: 1,
baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
},
];
}
......
......@@ -214,6 +214,7 @@ export class StructuresServiceMock {
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'],
......@@ -237,7 +238,6 @@ export class StructuresServiceMock {
jaccompagneLesUsagersDansLeursDemarchesEnLigne: true,
publicsAccompaniment: [],
autresAccompagnements: '',
equipmentsAndServices: ['ordinateurs', 'tablettes'],
nbComputers: 16,
nbPrinters: 1,
nbTablets: 1,
......@@ -335,12 +335,12 @@ export class StructuresServiceMock {
{
_id: '6093ba0e2ab5775cfc01abce',
coord: [4.8498155, 45.7514817],
equipmentsAndServices: ['wifiEnAccesLibre'],
digitalCultureSecurity: [],
parentingHelp: [],
socialAndProfessional: [],
accessRight: [],
baseSkills: [],
baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: [],
publicsAccompaniment: [],
publics: ['adultes'],
......@@ -409,12 +409,12 @@ export class StructuresServiceMock {
{
_id: '6093ba0e2ab5775cfc01fffe',
coord: [4.8498155, 45.7514817],
equipmentsAndServices: ['wifiEnAccesLibre'],
digitalCultureSecurity: [],
parentingHelp: [],
socialAndProfessional: [],
accessRight: [],
baseSkills: [],
baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: [],
publicsAccompaniment: [],
publics: ['adultes'],
......@@ -562,12 +562,12 @@ export class StructuresServiceMock {
{
_id: '6093ba0e2ab5775cfc01ffff',
coord: [4.8498155, 45.7514817],
equipmentsAndServices: ['wifiEnAccesLibre'],
digitalCultureSecurity: [],
parentingHelp: [],
socialAndProfessional: [],
accessRight: [],
baseSkills: [],
baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: [],
publicsAccompaniment: [],
publics: ['adultes'],
......@@ -715,12 +715,12 @@ export class StructuresServiceMock {
{
_id: '6093ba0e2ab5775cfc01ffff',
coord: [4.8498155, 45.7514817],
equipmentsAndServices: ['wifiEnAccesLibre'],
digitalCultureSecurity: [],
parentingHelp: [],
socialAndProfessional: [],
accessRight: [],
baseSkills: [],
baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: [],
publicsAccompaniment: [],
publics: ['adultes'],
......@@ -793,12 +793,12 @@ export class StructuresServiceMock {
return {
_id: '6093ba0e2ab5775cfc01ed3e',
coord: [4.8498155, 45.7514817],
equipmentsAndServices: ['wifiEnAccesLibre'],
digitalCultureSecurity: [],
parentingHelp: [],
socialAndProfessional: [],
accessRight: [],
baseSkills: [],
baseSkills: ['260', '1', '11', '38', '48', '74', '77'],
equipmentsAndServices: ['ordinateurs', 'imprimantes'],
proceduresAccompaniment: [],
publicsAccompaniment: [],
publics: ['adultes'],
......