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 (15)
Showing
with 387 additions and 45 deletions
...@@ -2,6 +2,25 @@ ...@@ -2,6 +2,25 @@
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.11.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v1.10.0...v1.11.0) (2022-01-12)
### Features
* add structure and user information on structure claim ([92e0099](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/92e00990779c3149057cb51decbd262c40600e34))
* **aptic-structures:** send mail when structure is created via aptic ([afdae30](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/afdae30a9c657c7fbfc17fbd2a229daa82d8d543))
* **dev:** add auto import of images in ghost at init ([a9cec09](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/a9cec09e3be83728c9725190d9e07e3597b3356a))
* migrate null values to 0 for equipments ([f0b382c](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/f0b382ce2cfd45a8a4f19ca661b1e97d1f5371e8))
* **TU:** add various TU ([9f82093](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/9f82093997d66c3a3469f21fa1eb7bfca2310e04))
### Bug Fixes
* mail spelling ([7af3cd8](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/7af3cd86cbaa14af316c98896e4ea87660742a04))
* mail spelling and typo ([b2ff1e3](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/b2ff1e3bdbaaa7a32640a3cdafa0323fe339884d))
* **post:** post image broken links ([a50f133](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/a50f1334871e81e5f9d5e64d46c19d55a4a854ef))
* **post:** rollback of unecesary localconf protection remove ([8d6056a](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/commit/8d6056af95b41626ee589000416d51d67eb49380))
## [1.10.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v1.9.1...v1.10.0) (2021-12-22) ## [1.10.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server/compare/v1.9.1...v1.10.0) (2021-12-22)
......
...@@ -2,7 +2,7 @@ version: '2' ...@@ -2,7 +2,7 @@ version: '2'
services: services:
service-ram: service-ram:
image: registry.forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server:master image: registry.forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server:dev
ports: ports:
- ${SERVICE_API_BIND_PORT}:3000 - ${SERVICE_API_BIND_PORT}:3000
extra_hosts: extra_hosts:
...@@ -87,7 +87,7 @@ services: ...@@ -87,7 +87,7 @@ services:
- db-ghost:/var/lib/mysql - db-ghost:/var/lib/mysql
es01: es01:
image: elasticsearch:7.6.1 image: elasticsearch:7.16.2
restart: unless-stopped restart: unless-stopped
environment: environment:
node.name: es01 node.name: es01
......
{ {
"name": "ram_server", "name": "ram_server",
"version": "1.10.0", "version": "1.11.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
...@@ -4448,6 +4448,12 @@ ...@@ -4448,6 +4448,12 @@
"integrity": "sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA==", "integrity": "sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA==",
"dev": true "dev": true
}, },
"@golevelup/ts-jest": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@golevelup/ts-jest/-/ts-jest-0.3.2.tgz",
"integrity": "sha512-hv+j/vau2oj5CuhY1CrTs48Qu+ZVXpm/56OzKcL2KVN8+yc0ZIMbvTIld1wbrT1RrvAuwfDmUM2s3aSy7veuwg==",
"dev": true
},
"@hutson/parse-repository-url": { "@hutson/parse-repository-url": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz",
......
{ {
"name": "ram_server", "name": "ram_server",
"private": true, "private": true,
"version": "1.10.0", "version": "1.11.0",
"description": "Nest TypeScript starter repository", "description": "Nest TypeScript starter repository",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
}, },
"devDependencies": { "devDependencies": {
"@compodoc/compodoc": "^1.1.16", "@compodoc/compodoc": "^1.1.16",
"@golevelup/ts-jest": "^0.3.2",
"@nestjs/cli": "^7.5.1", "@nestjs/cli": "^7.5.1",
"@nestjs/schematics": "^7.1.3", "@nestjs/schematics": "^7.1.3",
"@nestjs/testing": "^7.5.1", "@nestjs/testing": "^7.5.1",
......
...@@ -227,7 +227,7 @@ ...@@ -227,7 +227,7 @@
"slug": "le-reseau-de-mediation-numerique-metropolitain-quest-ce-que-cest", "slug": "le-reseau-de-mediation-numerique-metropolitain-quest-ce-que-cest",
"mobiledoc": "{\"version\":\"0.3.1\",\"atoms\":[],\"cards\":[],\"markups\":[],\"sections\":[[1,\"p\",[[0,[],0,\"La Métropole s’est engagée depuis plusieurs mois maintenant dans la mise en place d’un réseau des acteurs de la méditation numérique.\"]]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]]]}", "mobiledoc": "{\"version\":\"0.3.1\",\"atoms\":[],\"cards\":[],\"markups\":[],\"sections\":[[1,\"p\",[[0,[],0,\"La Métropole s’est engagée depuis plusieurs mois maintenant dans la mise en place d’un réseau des acteurs de la méditation numérique.\"]]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]]]}",
"comment_id": "603f6835adff2300014659ee", "comment_id": "603f6835adff2300014659ee",
"feature_image": "http://localhost:2368/content/images/2021/03/folder.png", "feature_image": "scripts/data/folder.png",
"featured": false, "featured": false,
"status": "published", "status": "published",
"visibility": "public", "visibility": "public",
...@@ -349,7 +349,7 @@ ...@@ -349,7 +349,7 @@
"slug": "une-plateforme-daccompagnement-nationale", "slug": "une-plateforme-daccompagnement-nationale",
"mobiledoc": "{\"version\":\"0.3.1\",\"atoms\":[],\"cards\":[],\"markups\":[],\"sections\":[[1,\"p\",[[0,[],0,\"Le site solidarite-numerique.fr développé par la Mednum en partenariat avec le secrétariat d’État a la culture.\"]]],[1,\"p\",[]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]]]}", "mobiledoc": "{\"version\":\"0.3.1\",\"atoms\":[],\"cards\":[],\"markups\":[],\"sections\":[[1,\"p\",[[0,[],0,\"Le site solidarite-numerique.fr développé par la Mednum en partenariat avec le secrétariat d’État a la culture.\"]]],[1,\"p\",[]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]],[1,\"p\",[[0,[],0,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"]]]]}",
"comment_id": "603f67d9adff2300014659e0", "comment_id": "603f67d9adff2300014659e0",
"feature_image": "http://localhost:2368/content/images/2021/03/etude.png", "feature_image": "scripts/data/etude.png",
"featured": false, "featured": false,
"status": "published", "status": "published",
"visibility": "public", "visibility": "public",
...@@ -571,7 +571,7 @@ ...@@ -571,7 +571,7 @@
"slug": "the-editor", "slug": "the-editor",
"mobiledoc": "{\"version\":\"0.3.1\",\"atoms\":[],\"cards\":[],\"markups\":[[\"a\",[\"href\",\"https://resin.grandlyon.com/home\"]]],\"sections\":[[1,\"p\",[]],[1,\"p\",[[0,[],0,\"Prévus pour se dérouler sur la métropole cette année, les deux événements Superdemain et Numérique en Commun[s] ont dû évidemment repenser l'organisation de cette édition 2020, année si particulière.\"]]],[1,\"p\",[[0,[],0,\"Les formations des professionnels prévus en présentiel sont annulées en raison du confinement. Mais une troisième vague de parcours en ligne est ouverte jusqu'au 13 novembre.\"]]],[1,\"p\",[[0,[0],1,\"Inscriptions\"]]],[1,\"p\",[[0,[],0,\"Les super-shows (conférences) sont maintenus en format 100% distancielPlus d'infos\"]]],[1,\"p\",[[0,[],0,\"Également prévu sur la métropole de Lyon, l'évènement Numérique en Commun[s], évènement national autour du numérique et ses enjeux a lui aussi basculé en 100% distanciel.\"]]],[1,\"p\",[[0,[],0,\"Au programme : 2h30 d'échanges le 17 novembre prochain avec de nombreux intervenants nationaux et 9 parcours en ligne à destination des professionnels, agents de collectivités ou élus sur des sujets d'actualités : inclusion numérique, communs, impact environnemental du numérique...\"]]],[1,\"p\",[[0,[0],1,\"Informations et inscription\"]]],[1,\"p\",[]]]}", "mobiledoc": "{\"version\":\"0.3.1\",\"atoms\":[],\"cards\":[],\"markups\":[[\"a\",[\"href\",\"https://resin.grandlyon.com/home\"]]],\"sections\":[[1,\"p\",[]],[1,\"p\",[[0,[],0,\"Prévus pour se dérouler sur la métropole cette année, les deux événements Superdemain et Numérique en Commun[s] ont dû évidemment repenser l'organisation de cette édition 2020, année si particulière.\"]]],[1,\"p\",[[0,[],0,\"Les formations des professionnels prévus en présentiel sont annulées en raison du confinement. Mais une troisième vague de parcours en ligne est ouverte jusqu'au 13 novembre.\"]]],[1,\"p\",[[0,[0],1,\"Inscriptions\"]]],[1,\"p\",[[0,[],0,\"Les super-shows (conférences) sont maintenus en format 100% distancielPlus d'infos\"]]],[1,\"p\",[[0,[],0,\"Également prévu sur la métropole de Lyon, l'évènement Numérique en Commun[s], évènement national autour du numérique et ses enjeux a lui aussi basculé en 100% distanciel.\"]]],[1,\"p\",[[0,[],0,\"Au programme : 2h30 d'échanges le 17 novembre prochain avec de nombreux intervenants nationaux et 9 parcours en ligne à destination des professionnels, agents de collectivités ou élus sur des sujets d'actualités : inclusion numérique, communs, impact environnemental du numérique...\"]]],[1,\"p\",[[0,[0],1,\"Informations et inscription\"]]],[1,\"p\",[]]]}",
"comment_id": "601425dc7775f400017ea02d", "comment_id": "601425dc7775f400017ea02d",
"feature_image": "http://localhost:2368/content/images/2021/03/nec-1.png", "feature_image": "scripts/data/nec.png",
"featured": false, "featured": false,
"status": "published", "status": "published",
"visibility": "public", "visibility": "public",
...@@ -793,7 +793,7 @@ ...@@ -793,7 +793,7 @@
"slug": "admin-settings", "slug": "admin-settings",
"mobiledoc": "{\"version\":\"0.3.1\",\"atoms\":[[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}]],\"cards\":[[\"image\",{\"src\":\"https://static.ghost.org/v1.0.0/images/private.png\"}]],\"markups\":[[\"em\"],[\"strong\"],[\"a\",[\"href\",\"https://ghost.org/pricing/\"]],[\"a\",[\"href\",\"http://localhost:2368/organising-content/\"]]],\"sections\":[[1,\"h2\",[[0,[],0,\"Make your site private\"]]],[1,\"p\",[[0,[],0,\"Le centre socio-culturel la Carnière situé à Saint-Priest possède un important pôle numérique.\"]]],[10,0],[1,\"p\",[[0,[],0,\"Ghost will give you a short, randomly generated pass-phrase which you can share with anyone who needs access to the site while you're working on it. While this setting is enabled, all search engine optimisation features will be switched off to help keep your site under the radar.\"]]],[1,\"p\",[[0,[],0,\"Do remember though, this is \"],[0,[0],1,\"not\"],[0,[],0,\" secure authentication. You shouldn't rely on this feature for protecting important private data. It's just a simple, shared pass-phrase for some very basic privacy.\"]]],[1,\"h2\",[[0,[],0,\"Invite your team \"]]],[1,\"p\",[[0,[],0,\"Ghost has a number of different user roles for your team:\"]]],[1,\"p\",[[0,[1],1,\"Contributors\"],[1,[],0,0],[0,[],0,\"This is the base user level in Ghost. Contributors can create and edit their own draft posts, but they are unable to edit drafts of others or publish posts. Contributors are \"],[0,[1],1,\"untrusted\"],[0,[],0,\" users with the most basic access to your publication.\"]]],[1,\"p\",[[0,[1],1,\"Authors\"],[1,[],0,1],[0,[],0,\"Authors are the 2nd user level in Ghost. Authors can write, edit and publish their own posts. Authors are \"],[0,[1],1,\"trusted\"],[0,[],0,\" users. If you don't trust users to be allowed to publish their own posts, they should be set as Contributors.\"]]],[1,\"p\",[[0,[1],1,\"Editors\"],[1,[],0,2],[0,[],0,\"Editors are the 3rd user level in Ghost. Editors can do everything that an Author can do, but they can also edit and publish the posts of others - as well as their own. Editors can also invite new Contributors & Authors to the site.\"]]],[1,\"p\",[[0,[1],1,\"Administrators\"],[1,[],0,3],[0,[],0,\"The top user level in Ghost is Administrator. Again, administrators can do everything that Authors and Editors can do, but they can also edit all site settings and data, not just content. Additionally, administrators have full access to invite, manage or remove any other user of the site.\"],[1,[],0,4],[1,[],0,5],[0,[1],1,\"The Owner\"],[1,[],0,6],[0,[],0,\"There is only ever one owner of a Ghost site. The owner is a special user which has all the same permissions as an Administrator, but with two exceptions: The Owner can never be deleted. And in some circumstances the owner will have access to additional special settings if applicable. For example: billing details, if using \"],[0,[2,1],2,\"Ghost(Pro)\"],[0,[],0,\".\"]]],[1,\"blockquote\",[[0,[0],1,\"It's a good idea to ask all of your users to fill out their user profiles, including bio and social links. These will populate rich structured data for posts and generally create more opportunities for themes to fully populate their design.\"]]],[1,\"h2\",[[0,[],0,\"Next: Organising content\"]]],[1,\"p\",[[0,[],0,\"Find out how to \"],[0,[3],1,\"organise your content\"],[0,[],0,\" with sensible tags and authors, or for more advanced configurations, how to create custom content structures using dynamic routing.\"]]]]}", "mobiledoc": "{\"version\":\"0.3.1\",\"atoms\":[[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}],[\"soft-return\",\"\",{}]],\"cards\":[[\"image\",{\"src\":\"https://static.ghost.org/v1.0.0/images/private.png\"}]],\"markups\":[[\"em\"],[\"strong\"],[\"a\",[\"href\",\"https://ghost.org/pricing/\"]],[\"a\",[\"href\",\"http://localhost:2368/organising-content/\"]]],\"sections\":[[1,\"h2\",[[0,[],0,\"Make your site private\"]]],[1,\"p\",[[0,[],0,\"Le centre socio-culturel la Carnière situé à Saint-Priest possède un important pôle numérique.\"]]],[10,0],[1,\"p\",[[0,[],0,\"Ghost will give you a short, randomly generated pass-phrase which you can share with anyone who needs access to the site while you're working on it. While this setting is enabled, all search engine optimisation features will be switched off to help keep your site under the radar.\"]]],[1,\"p\",[[0,[],0,\"Do remember though, this is \"],[0,[0],1,\"not\"],[0,[],0,\" secure authentication. You shouldn't rely on this feature for protecting important private data. It's just a simple, shared pass-phrase for some very basic privacy.\"]]],[1,\"h2\",[[0,[],0,\"Invite your team \"]]],[1,\"p\",[[0,[],0,\"Ghost has a number of different user roles for your team:\"]]],[1,\"p\",[[0,[1],1,\"Contributors\"],[1,[],0,0],[0,[],0,\"This is the base user level in Ghost. Contributors can create and edit their own draft posts, but they are unable to edit drafts of others or publish posts. Contributors are \"],[0,[1],1,\"untrusted\"],[0,[],0,\" users with the most basic access to your publication.\"]]],[1,\"p\",[[0,[1],1,\"Authors\"],[1,[],0,1],[0,[],0,\"Authors are the 2nd user level in Ghost. Authors can write, edit and publish their own posts. Authors are \"],[0,[1],1,\"trusted\"],[0,[],0,\" users. If you don't trust users to be allowed to publish their own posts, they should be set as Contributors.\"]]],[1,\"p\",[[0,[1],1,\"Editors\"],[1,[],0,2],[0,[],0,\"Editors are the 3rd user level in Ghost. Editors can do everything that an Author can do, but they can also edit and publish the posts of others - as well as their own. Editors can also invite new Contributors & Authors to the site.\"]]],[1,\"p\",[[0,[1],1,\"Administrators\"],[1,[],0,3],[0,[],0,\"The top user level in Ghost is Administrator. Again, administrators can do everything that Authors and Editors can do, but they can also edit all site settings and data, not just content. Additionally, administrators have full access to invite, manage or remove any other user of the site.\"],[1,[],0,4],[1,[],0,5],[0,[1],1,\"The Owner\"],[1,[],0,6],[0,[],0,\"There is only ever one owner of a Ghost site. The owner is a special user which has all the same permissions as an Administrator, but with two exceptions: The Owner can never be deleted. And in some circumstances the owner will have access to additional special settings if applicable. For example: billing details, if using \"],[0,[2,1],2,\"Ghost(Pro)\"],[0,[],0,\".\"]]],[1,\"blockquote\",[[0,[0],1,\"It's a good idea to ask all of your users to fill out their user profiles, including bio and social links. These will populate rich structured data for posts and generally create more opportunities for themes to fully populate their design.\"]]],[1,\"h2\",[[0,[],0,\"Next: Organising content\"]]],[1,\"p\",[[0,[],0,\"Find out how to \"],[0,[3],1,\"organise your content\"],[0,[],0,\" with sensible tags and authors, or for more advanced configurations, how to create custom content structures using dynamic routing.\"]]]]}",
"comment_id": "601425dc7775f400017ea029", "comment_id": "601425dc7775f400017ea029",
"feature_image": "http://localhost:2368/content/images/2021/03/la_carniere.png", "feature_image": "scripts/data/la_carniere.png",
"featured": false, "featured": false,
"status": "published", "status": "published",
"visibility": "public", "visibility": "public",
......
...@@ -100,8 +100,23 @@ function processImagesInHTML(html) { ...@@ -100,8 +100,23 @@ function processImagesInHTML(html) {
}); });
} }
async function uploadPostImage(imagePath)
{
let imagePromise = api.images.upload({
ref: imagePath,
file: path.resolve(imagePath)
});
return Promise.resolve(imagePromise).then((url) => {
return url.url;
}).catch((error) => {
console.error(error);
return null
})
}
async function createPosts(deleteOnly) { async function createPosts(deleteOnly) {
// Get existing posts
api.posts api.posts
.browse({ limit: 'all' }) .browse({ limit: 'all' })
.then(async (existingPosts) => { .then(async (existingPosts) => {
...@@ -120,7 +135,11 @@ async function createPosts(deleteOnly) { ...@@ -120,7 +135,11 @@ async function createPosts(deleteOnly) {
// Creating new posts // Creating new posts
if (!deleteOnly) { if (!deleteOnly) {
console.log('-- Creating ' + postsData.length + ' posts --'); console.log('-- Creating ' + postsData.length + ' posts --');
_.forEach(postsData, (post) => { _.forEach(postsData, async (post) => {
//upload de l'image en featured_image
if (post.feature_image) {
post.feature_image = await uploadPostImage(post.feature_image);
}
api.posts api.posts
.add(post, { source: 'html' }) .add(post, { source: 'html' })
.then((res) => { .then((res) => {
......
...@@ -183,6 +183,6 @@ export class AdminController { ...@@ -183,6 +183,6 @@ export class AdminController {
@Delete('newsletterSubscription/:email') @Delete('newsletterSubscription/:email')
@ApiParam({ name: 'email', type: String, required: true }) @ApiParam({ name: 'email', type: String, required: true })
public async unsubscribeUserFromNewsletter(@Param() params): Promise<NewsletterSubscription> { public async unsubscribeUserFromNewsletter(@Param() params): Promise<NewsletterSubscription> {
return this.newsletterService.deleteOneEmail(params.email); return this.newsletterService.newsletterUnsubscribe(params.email);
} }
} }
import { getModelToken } from '@nestjs/mongoose'; import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { CategoriesAccompagnement } from '../schemas/categoriesAccompagnement.schema'; import { CreateCategoriesAccompagnement } from '../dto/create-categoriesAccompagnement.dto';
import { CategoriesAccompagnementService } from './categories-accompagnement.service'; import { CategoriesAccompagnementService } from './categories-accompagnement.service';
describe('CategoriesAccompagnementService', () => { describe('CategoriesAccompagnementService', () => {
let service: CategoriesAccompagnementService; let service: CategoriesAccompagnementService;
const mockCategoriesAccompagnementModel = {
create: jest.fn(),
find: jest.fn(),
};
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
imports: [], imports: [],
...@@ -13,7 +18,7 @@ describe('CategoriesAccompagnementService', () => { ...@@ -13,7 +18,7 @@ describe('CategoriesAccompagnementService', () => {
CategoriesAccompagnementService, CategoriesAccompagnementService,
{ {
provide: getModelToken('CategoriesAccompagnement'), provide: getModelToken('CategoriesAccompagnement'),
useValue: CategoriesAccompagnement, useValue: mockCategoriesAccompagnementModel,
}, },
], ],
}).compile(); }).compile();
...@@ -24,4 +29,20 @@ describe('CategoriesAccompagnementService', () => { ...@@ -24,4 +29,20 @@ describe('CategoriesAccompagnementService', () => {
it('should be defined', () => { it('should be defined', () => {
expect(service).toBeDefined(); expect(service).toBeDefined();
}); });
it('should create categorie accompagnement', async () => {
const data: CreateCategoriesAccompagnement = { name: 'test', modules: [{ id: 'Test', text: 'Text du test' }] };
const _doc = { _id: '5fbb92ef80a5c257dc0161f2', ...data };
mockCategoriesAccompagnementModel.create.mockResolvedValueOnce(_doc);
expect(await service.create(data)).toEqual(_doc);
});
it('should findAll structures', async () => {
const data: CreateCategoriesAccompagnement[] = [
{ name: 'test', modules: [{ id: 'Test', text: 'Text du test' }] },
{ name: 'test2', modules: [{ id: 'Test2', text: 'Text du test test 2' }] },
];
mockCategoriesAccompagnementModel.find.mockResolvedValueOnce(data);
expect(await service.findAll()).toEqual(data);
});
}); });
...@@ -11,11 +11,10 @@ export class CategoriesAccompagnementService { ...@@ -11,11 +11,10 @@ export class CategoriesAccompagnementService {
) {} ) {}
public async create(createDto: CreateCategoriesAccompagnement): Promise<CategoriesAccompagnement> { public async create(createDto: CreateCategoriesAccompagnement): Promise<CategoriesAccompagnement> {
const createdStructure = new this.structureModel(createDto); return this.structureModel.create(createDto);
return createdStructure.save();
} }
public async findAll(): Promise<CategoriesAccompagnement[]> { public async findAll(): Promise<CategoriesAccompagnement[]> {
return this.structureModel.find().exec(); return this.structureModel.find();
} }
} }
import { getModelToken } from '@nestjs/mongoose'; import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { CategoriesFormations } from '../schemas/categoriesFormations.schema'; import { CreateCategoriesFormations } from '../dto/create-categoriesFormations.dto';
import { CategoriesFormationsService } from './categories-formations.service'; import { CategoriesFormationsService } from './categories-formations.service';
describe('CategoriesFormationsService', () => { describe('CategoriesFormationsService', () => {
let service: CategoriesFormationsService; let service: CategoriesFormationsService;
const mockCategoriesFormationModel = {
create: jest.fn(),
find: jest.fn(),
};
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
imports: [], imports: [],
...@@ -13,7 +18,7 @@ describe('CategoriesFormationsService', () => { ...@@ -13,7 +18,7 @@ describe('CategoriesFormationsService', () => {
CategoriesFormationsService, CategoriesFormationsService,
{ {
provide: getModelToken('CategoriesFormations'), provide: getModelToken('CategoriesFormations'),
useValue: CategoriesFormations, useValue: mockCategoriesFormationModel,
}, },
], ],
}).compile(); }).compile();
...@@ -24,4 +29,53 @@ describe('CategoriesFormationsService', () => { ...@@ -24,4 +29,53 @@ describe('CategoriesFormationsService', () => {
it('should be defined', () => { it('should be defined', () => {
expect(service).toBeDefined(); expect(service).toBeDefined();
}); });
it('should create categorie formation', async () => {
const data: CreateCategoriesFormations = {
name: 'test',
modules: [
{
id: '2',
display_id: '2',
display_name: 'Modules APTIC - n°2',
text: 'Les conduites à risques et les bons usages du numérique',
digest: 'Les conduites à risques et les bons usages du numérique - 02',
},
],
};
const _doc = { _id: '5fbb92ef80a5c257dc0161f2', ...data };
mockCategoriesFormationModel.create.mockResolvedValueOnce(_doc);
expect(await service.create(data)).toEqual(_doc);
});
it('should findAll structures', async () => {
const data: CreateCategoriesFormations[] = [
{
name: 'test',
modules: [
{
id: '2',
display_id: '2',
display_name: 'Modules APTIC - n°2',
text: 'Les conduites à risques et les bons usages du numérique',
digest: 'Les conduites à risques et les bons usages du numérique - 02',
},
],
},
{
name: 'test',
modules: [
{
id: '1',
display_id: '1',
display_name: 'Modules APTIC - n°1',
text: 'Les conduites à risques et les bons usages',
digest: 'Les conduites à risques et les bons usages - 01',
},
],
},
];
mockCategoriesFormationModel.find.mockResolvedValueOnce(data);
expect(await service.findAll()).toEqual(data);
});
}); });
...@@ -9,15 +9,14 @@ export class CategoriesFormationsService { ...@@ -9,15 +9,14 @@ export class CategoriesFormationsService {
constructor(@InjectModel(CategoriesFormations.name) private structureModel: Model<CategoriesFormationsDocument>) {} constructor(@InjectModel(CategoriesFormations.name) private structureModel: Model<CategoriesFormationsDocument>) {}
public async create(createDto: CreateCategoriesFormations): Promise<CategoriesFormations> { public async create(createDto: CreateCategoriesFormations): Promise<CategoriesFormations> {
const createdStructure = new this.structureModel(createDto); return this.structureModel.create(createDto);
return createdStructure.save();
} }
public async findAll(): Promise<CategoriesFormations[]> { public async findAll(): Promise<CategoriesFormations[]> {
return this.structureModel.find().exec(); return this.structureModel.find();
} }
public findOne(categoryId: string): Promise<any> { 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();
} }
} }
import { getModelToken } from '@nestjs/mongoose'; import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { CategoriesOthers } from '../schemas/categoriesOthers.schema'; import { CreateCategoriesOthers } from '../dto/create-categoriesOthers.dto';
import { CategoriesOthersService } from './categories-others.service'; import { CategoriesOthersService } from './categories-others.service';
describe('CategoriesFormationsService', () => { describe('CategoriesFormationsService', () => {
let service: CategoriesOthersService; let service: CategoriesOthersService;
const mockCategoriesOthersModel = {
create: jest.fn(),
find: jest.fn(),
};
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
imports: [], imports: [],
...@@ -13,7 +18,7 @@ describe('CategoriesFormationsService', () => { ...@@ -13,7 +18,7 @@ describe('CategoriesFormationsService', () => {
CategoriesOthersService, CategoriesOthersService,
{ {
provide: getModelToken('CategoriesOthers'), provide: getModelToken('CategoriesOthers'),
useValue: CategoriesOthers, useValue: mockCategoriesOthersModel,
}, },
], ],
}).compile(); }).compile();
...@@ -24,4 +29,20 @@ describe('CategoriesFormationsService', () => { ...@@ -24,4 +29,20 @@ describe('CategoriesFormationsService', () => {
it('should be defined', () => { it('should be defined', () => {
expect(service).toBeDefined(); expect(service).toBeDefined();
}); });
it('should create categorie accompagnement', async () => {
const data: CreateCategoriesOthers = { name: 'test', modules: [{ id: 'Test', text: 'Text du test' }] };
const _doc = { _id: '5fbb92ef80a5c257dc0161f2', ...data };
mockCategoriesOthersModel.create.mockResolvedValueOnce(_doc);
expect(await service.create(data)).toEqual(_doc);
});
it('should findAll structures', async () => {
const data: CreateCategoriesOthers[] = [
{ name: 'test', modules: [{ id: 'Test', text: 'Text du test' }] },
{ name: 'test2', modules: [{ id: 'Test2', text: 'Text du test test 2' }] },
];
mockCategoriesOthersModel.find.mockResolvedValueOnce(data);
expect(await service.findAll()).toEqual(data);
});
}); });
...@@ -9,11 +9,10 @@ export class CategoriesOthersService { ...@@ -9,11 +9,10 @@ export class CategoriesOthersService {
constructor(@InjectModel(CategoriesOthers.name) private structureModel: Model<CategoriesOthersDocument>) {} constructor(@InjectModel(CategoriesOthers.name) private structureModel: Model<CategoriesOthersDocument>) {}
public async create(createDto: CreateCategoriesOthers): Promise<CategoriesOthers> { public async create(createDto: CreateCategoriesOthers): Promise<CategoriesOthers> {
const createdStructure = new this.structureModel(createDto); return this.structureModel.create(createDto);
return createdStructure.save();
} }
public async findAll(): Promise<CategoriesOthers[]> { public async findAll(): Promise<CategoriesOthers[]> {
return this.structureModel.find().exec(); return this.structureModel.find();
} }
} }
...@@ -61,5 +61,9 @@ export const config = { ...@@ -61,5 +61,9 @@ export const config = {
ejs: 'structureDeletionNotification.ejs', ejs: 'structureDeletionNotification.ejs',
json: 'structureDeletionNotification.json', json: 'structureDeletionNotification.json',
}, },
newApticStructure: {
ejs: 'newApticStructure.ejs',
json: 'newApticStructure.json',
},
}, },
}; };
Bonjour,<br /> Bonjour,<br />
<br /> <br />
Une nouvelle structure a été revendiquée. Pour valider ou refuser la demande, merci de vous rendre sur La structure <%= structureName %> a été revendiquée par <%= user.name %> <%= user.surname %>.
<br />
Voici les informations de la structure : <br />
<%= structureAdress %><br />
<%= structureDescription %><br />
Et du demandeur : <br />
<%= user.email %><br />
Pour valider ou refuser la demande, merci de vous rendre sur
<a href="<%= config.protocol %>://<%= config.host %><%= config.port ? ':' + config.port : '' %>/admin">ce lien</a>. <a href="<%= config.protocol %>://<%= config.host %><%= config.port ? ':' + config.port : '' %>/admin">ce lien</a>.
Bonjour,<br />
<br />
Une nouvelle structure a été crée via Aptic. Ses caractéristiques sont : <br />
- Nom : <%= name %><br />
- Adresse : <%= address %><br />
- Description : <%= description %><br />
{
"subject": "Nouvelle structure Aptic"
}
import { Db } from 'mongodb';
import { getDb } from '../migrations-utils/db';
export const up = async () => {
const db: Db = await getDb();
const cursor = db.collection('structures').find({});
let document;
while ((document = await cursor.next())) {
const newDoc = document;
if (document.nbComputers === null) {
newDoc.nbComputers = 0;
}
if (document.nbPrinters === null) {
newDoc.nbPrinters = 0;
}
if (document.nbScanners === null) {
newDoc.nbScanners = 0;
}
if (document.nbTablets === null) {
newDoc.nbTablets = 0;
}
if (document.nbNumericTerminal === null) {
newDoc.nbNumericTerminal = 0;
}
await db.collection('structures').updateOne({ _id: document._id }, [{ $set: newDoc }]);
}
console.log(`Update done`);
};
export const down = async () => {
const db: Db = await getDb();
const cursor = db.collection('structures').find({});
let document;
while ((document = await cursor.next())) {
const newDoc = document;
if (document.nbComputers === 0) {
newDoc.nbComputers = null;
}
if (document.nbPrinters === 0) {
newDoc.nbPrinters = null;
}
if (document.nbScanners === 0) {
newDoc.nbScanners = null;
}
if (document.nbTablets === 0) {
newDoc.nbTablets = null;
}
if (document.nbNumericTerminal === 0) {
newDoc.nbNumericTerminal = null;
}
await db.collection('structures').updateOne({ _id: document._id }, [{ $set: newDoc }]);
}
console.log(`Update done`);
};
import { HttpModule, HttpStatus } from '@nestjs/common';
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { INewsletterSubscription } from './interface/newsletter-subscription.interface';
import { NewsletterSubscription } from './newsletter-subscription.schema';
import { NewsletterService } from './newsletter.service';
describe('NewsletterService', () => {
let service: NewsletterService;
const mockNewsletterModel = {
create: jest.fn(),
deleteOne: jest.fn(),
countDocuments: jest.fn(),
findOne: jest.fn(),
exec: jest.fn(),
find: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [HttpModule],
providers: [
NewsletterService,
{
provide: getModelToken(NewsletterSubscription.name),
useValue: mockNewsletterModel,
},
],
}).compile();
service = module.get<NewsletterService>(NewsletterService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('newsletterSubscribe', () => {
it('it should not add subscription for email test2@test.com : already exist', async () => {
const result = { email: 'test2@test.com' } as INewsletterSubscription;
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
try {
await service.newsletterSubscribe('test2@test.com');
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('Email already exists');
expect(e.status).toEqual(HttpStatus.BAD_REQUEST);
}
});
it('it should add a subscription for email test2@test.com', async () => {
const result: INewsletterSubscription = { email: 'test2@test.com' } as INewsletterSubscription;
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' };
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => undefined)
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
mockNewsletterModel.create.mockResolvedValueOnce(_doc);
const subscription = await service.newsletterSubscribe('test2@test.com');
expect(subscription).toEqual({ email: 'test2@test.com' });
});
});
describe('newsletterUnsubscribe', () => {
it('it should not remove subscription for email test@test.com : does not exist', async () => {
const result: INewsletterSubscription = undefined;
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
try {
await service.newsletterUnsubscribe('test@test.com');
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('Invalid email');
expect(e.status).toEqual(HttpStatus.BAD_REQUEST);
}
});
it('it should remove a subscription for email test2@test.com', async () => {
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' };
const result = {
email: 'test2@test.com',
deleteOne: async () => _doc,
} as INewsletterSubscription;
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
const subscription = await service.newsletterUnsubscribe('test2@test.com');
expect(subscription).toEqual(_doc);
});
});
describe('countNewsletterSubscriptions', () => {
it('it should count subscriptions', async () => {
mockNewsletterModel.countDocuments.mockResolvedValueOnce(69);
const count = await service.countNewsletterSubscriptions();
expect(count).toEqual(69);
});
});
describe('findOne', () => {
it('it should not find a subscription with email test@test.com', async () => {
mockNewsletterModel.findOne.mockResolvedValueOnce(undefined);
const findOneEmail = await service.findOne('test@test.com');
expect(findOneEmail).toEqual(undefined);
});
it('it should find a subscription with email test2@test.com', async () => {
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' } as INewsletterSubscription;
mockNewsletterModel.findOne.mockResolvedValueOnce(_doc);
const findOneEmail = await service.findOne('test2@test.com');
expect(findOneEmail).toEqual(_doc);
});
});
describe('findAll', () => {
it('it should find all', async () => {
const _docs = [{ _id: 'a1aaaaa1a1', email: 'test2@test.com' } as INewsletterSubscription];
mockNewsletterModel.find.mockResolvedValueOnce(_docs);
const findOneEmail = await service.findAll();
expect(findOneEmail).toEqual(_docs);
});
});
describe('searchNewsletterSubscription', () => {
it('it should find 2 search result', async () => {
const _docs = [
{ _id: 'a1aaaaa1a1', email: 'test2@test.com' } as INewsletterSubscription,
{ _id: 'bbbbb', email: 'test@test.com' } as INewsletterSubscription,
];
mockNewsletterModel.find.mockResolvedValueOnce(_docs);
const findOneEmail = await service.searchNewsletterSubscription('test');
expect(findOneEmail.length).toBe(2);
});
});
});
...@@ -15,40 +15,31 @@ export class NewsletterService { ...@@ -15,40 +15,31 @@ export class NewsletterService {
if (existingEmail) { if (existingEmail) {
throw new HttpException('Email already exists', HttpStatus.BAD_REQUEST); throw new HttpException('Email already exists', HttpStatus.BAD_REQUEST);
} }
const createSubscription = new this.newsletterSubscriptionModel({ email: email }); await this.newsletterSubscriptionModel.create({ email: email });
createSubscription.save(); return this.findOne(email);
return await this.findOne(email);
} }
public async newsletterUnsubscribe(email: string): Promise<NewsletterSubscription> { public async newsletterUnsubscribe(email: string): Promise<NewsletterSubscription> {
const subscription = await this.newsletterSubscriptionModel.findOne({ email: email }).exec(); const subscription = await this.findOne(email);
if (!subscription) { if (!subscription) {
throw new HttpException('Invalid email', HttpStatus.BAD_REQUEST); throw new HttpException('Invalid email', HttpStatus.BAD_REQUEST);
} }
return subscription.deleteOne(); return subscription.deleteOne();
} }
public async findOne(mail: string): Promise<NewsletterSubscription | undefined> { public async findOne(mail: string): Promise<INewsletterSubscription | undefined> {
return this.newsletterSubscriptionModel.findOne({ email: mail }).exec(); return this.newsletterSubscriptionModel.findOne({ email: mail });
} }
public async searchNewsletterSubscription(searchString: string): Promise<NewsletterSubscriptionDocument[]> { public async searchNewsletterSubscription(searchString: string): Promise<NewsletterSubscriptionDocument[]> {
return this.newsletterSubscriptionModel.find({ email: new RegExp(searchString, 'i') }).exec(); return this.newsletterSubscriptionModel.find({ email: new RegExp(searchString, 'i') });
} }
public async countNewsletterSubscriptions(): Promise<number> { public async countNewsletterSubscriptions(): Promise<number> {
return this.newsletterSubscriptionModel.countDocuments({}).exec(); return this.newsletterSubscriptionModel.countDocuments({});
}
public async deleteOneEmail(mail: string): Promise<NewsletterSubscription | undefined> {
const subscription = await this.newsletterSubscriptionModel.findOne({ email: mail }).exec();
if (!subscription) {
throw new HttpException('Invalid email', HttpStatus.BAD_REQUEST);
}
return subscription.deleteOne();
} }
public async findAll(): Promise<NewsletterSubscription[]> { public async findAll(): Promise<NewsletterSubscription[]> {
return await this.newsletterSubscriptionModel.find().exec(); return this.newsletterSubscriptionModel.find();
} }
} }