From d57c02c48e2ab857eac297f227f82dc4a5610a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 4 Oct 2021 13:03:04 +0200 Subject: [PATCH 001/588] Refine backend README.md --- backend/README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/backend/README.md b/backend/README.md index 6d837856c..3601dd2fa 100644 --- a/backend/README.md +++ b/backend/README.md @@ -7,8 +7,9 @@ Run the following command to install everything through docker. The installation takes a bit longer on the first pass or on rebuild ... ```bash +# in main folder $ docker-compose up - +# or # rebuild the containers for a cleanup $ docker-compose up --build ``` @@ -28,6 +29,7 @@ between different local node versions. Install node dependencies with [yarn](https://yarnpkg.com/en/): ```bash +# in main folder $ cd backend $ yarn install ``` @@ -45,12 +47,14 @@ a [local Neo4J](http://localhost:7474) instance is up and running. Start the backend for development with: ```bash +# in backend/ $ yarn run dev ``` or start the backend in production environment with: ```bash +# in backend/ $ yarn run start ``` @@ -72,6 +76,7 @@ backend is running: {% tab title="Docker" %} ```bash +# in main folder while docker-compose is running $ docker-compose exec backend yarn run db:migrate init ``` @@ -79,7 +84,7 @@ $ docker-compose exec backend yarn run db:migrate init {% tab title="Without Docker" %} ```bash -# in folder backend/ +# in folder backend/ while database is running # make sure your database is running on http://localhost:7474/browser/ yarn run db:migrate init ``` @@ -98,12 +103,14 @@ need to seed your database: In another terminal run: ```bash +# in main folder while docker-compose is running $ docker-compose exec backend yarn run db:seed ``` To reset the database run: ```bash +# in main folder while docker-compose is running $ docker-compose exec backend yarn run db:reset # you could also wipe out your neo4j database and delete all volumes with: $ docker-compose down -v @@ -117,12 +124,14 @@ $ docker-compose exec backend yarn run db:migrate init Run: ```bash +# in backend/ while database is running $ yarn run db:seed ``` To reset the database run: ```bash +# in backend/ while database is running $ yarn run db:reset ``` @@ -140,6 +149,7 @@ you have to migrate your data e.g. because your data modeling has changed. Generate a data migration file: ```bash +# in main folder while docker-compose is running $ docker-compose exec backend yarn run db:migrate:create your_data_migration # Edit the file in ./src/db/migrations/ ``` @@ -147,6 +157,7 @@ $ docker-compose exec backend yarn run db:migrate:create your_data_migration To run the migration: ```bash +# in main folder while docker-compose is running $ docker-compose exec backend yarn run db:migrate up ``` @@ -156,6 +167,7 @@ $ docker-compose exec backend yarn run db:migrate up Generate a data migration file: ```bash +# in backend/ $ yarn run db:migrate:create your_data_migration # Edit the file in ./src/db/migrations/ ``` @@ -163,6 +175,7 @@ $ yarn run db:migrate:create your_data_migration To run the migration: ```bash +# in backend/ while database is running $ yarn run db:migrate up ``` @@ -180,6 +193,7 @@ database after each test, running the tests will wipe out all your data! Run the unit tests: ```bash +# in main folder while docker-compose is running $ docker-compose exec backend yarn run test ``` @@ -190,6 +204,7 @@ $ docker-compose exec backend yarn run test Run the unit tests: ```bash +# in backend/ while database is running $ yarn run test ``` From cd07c9b2f6f67245d1d2a4336081b8ecb6f063a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 1 Jul 2022 09:51:48 +0200 Subject: [PATCH 002/588] Release v1.0.8 --- CHANGELOG.md | 19 +++++++++++++++++++ backend/package.json | 2 +- package.json | 4 ++-- webapp/maintenance/source/package.json | 2 +- webapp/package.json | 2 +- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acc917e13..6efb54686 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,27 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.0.8](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/1.0.7...1.0.8) + +- chore: 🍰 Log E-Mail If Not Sending It [`#5038`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5038) +- test: 🍰 Test And Refactor E-Mail Templates [`#4787`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4787) +- fix: 🍰 Replace Hashtag In d.tube Url [`#4980`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4980) +- Fix location backend test [`#5034`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5034) +- fix: 🍰 Add Expiration Date To Cookies Etc. [`#4882`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4882) +- feat: 🍰 Refactor Social Media List With Slots [`#4773`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4773) +- bug: 🍰 Replace Deleted Faker Package – Change To Import Again [`#4975`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4975) +- bug: 🍰 Replace Deleted Faker Package [`#4973`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4973) +- fix: 🍰 Change Tip Tap Editor Legend Hover To Click [`#4911`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4911) +- fix: 🍰 Fix Embed iframe Width And Height CSS [`#4897`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4897) +- Implement MySomethingList for social media, use list item slot [`d3cc49d`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/d3cc49d37ba260f9a285c078c57e673a32a76732) +- Split social media page and list component [`b740033`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/b7400339aba22d5fb5506dc3b25f082d7f09edfc) +- Remove input addSocialMedia [`58464fd`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/58464fd53ef6aab52af1c2477c2615648ad889e3) + #### [1.0.7](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/1.0.6...1.0.7) +> 2 December 2021 + +- fix: 🍰 Fix Migration 'add donations node‘ And Release V1.0.7 [`#4821`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4821) - Bump rosie from 2.0.1 to 2.1.0 [`#4520`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4520) - fix: 🍰 Renew JWT In Decode Test [`#4798`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4798) - docs: 🍰 Refine Main README.md With Test Tech Stack And Video Link [`#4772`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4772) diff --git a/backend/package.json b/backend/package.json index e0d53b5b9..c4aa8d98b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "ocelot-social-backend", - "version": "1.0.7", + "version": "1.0.8", "description": "GraphQL Backend for ocelot.social", "repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social", "author": "ocelot.social Community", diff --git a/package.json b/package.json index 9b0e27d95..a914a4096 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ocelot-social", - "version": "1.0.7", + "version": "1.0.8", "description": "Free and open source software program code available to run social networks.", "author": "ocelot.social Community", "license": "MIT", @@ -25,6 +25,7 @@ "@babel/core": "^7.9.0", "@babel/preset-env": "^7.12.7", "@babel/register": "^7.12.10", + "@faker-js/faker": "5.1.0", "auto-changelog": "^2.3.0", "bcryptjs": "^2.4.3", "codecov": "^3.8.2", @@ -36,7 +37,6 @@ "date-fns": "^2.25.0", "dotenv": "^8.2.0", "expect": "^25.3.0", - "@faker-js/faker": "5.1.0", "graphql-request": "^2.0.0", "import": "^0.0.6", "jsonwebtoken": "^8.5.1", diff --git a/webapp/maintenance/source/package.json b/webapp/maintenance/source/package.json index e38f34370..e7bdf8e66 100644 --- a/webapp/maintenance/source/package.json +++ b/webapp/maintenance/source/package.json @@ -1,6 +1,6 @@ { "name": "@ocelot-social/maintenance", - "version": "1.0.7", + "version": "1.0.8", "description": "Maintenance page for ocelot.social", "repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social", "author": "ocelot.social Community", diff --git a/webapp/package.json b/webapp/package.json index cf4354dde..d713a1f1e 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -1,6 +1,6 @@ { "name": "ocelot-social-webapp", - "version": "1.0.7", + "version": "1.0.8", "description": "ocelot.social Frontend", "repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social", "author": "ocelot.social Community", From de8da7fb30c0e1650b8be91c8269b8742f5d30f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 13 Jul 2022 10:00:55 +0200 Subject: [PATCH 003/588] Add platform for Apple M1 via docker compose override --- docker-compose.apple-m1.override.yml | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docker-compose.apple-m1.override.yml diff --git a/docker-compose.apple-m1.override.yml b/docker-compose.apple-m1.override.yml new file mode 100644 index 000000000..214655ab6 --- /dev/null +++ b/docker-compose.apple-m1.override.yml @@ -0,0 +1,32 @@ +version: "3.4" + +services: + ######################################################## + # WEBAPP ############################################### + ######################################################## + webapp: + platform: linux/amd64 + + ######################################################## + # BACKEND ############################################## + ######################################################## + backend: + platform: linux/amd64 + + ######################################################## + # NEO4J ################################################ + ######################################################## + neo4j: + platform: linux/amd64 + + ######################################################## + # MAINTENANCE ########################################## + ######################################################## + maintenance: + platform: linux/amd64 + + ######################################################## + # MAILSERVER TO FAKE SMTP ############################## + ######################################################## + mailserver: + platform: linux/amd64 From 04cd391a39c58560ac967c6da92a69876bf72fdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 13 Jul 2022 10:02:18 +0200 Subject: [PATCH 004/588] Remove image entries in 'docker-compose.yml' and 'docker-compose.override.yml' --- docker-compose.override.yml | 14 +++++++++----- docker-compose.yml | 11 +++++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 15cf00e7a..e1ee25fd7 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -5,7 +5,7 @@ services: # WEBAPP ############################################### ######################################################## webapp: - image: ocelotsocialnetwork/webapp:development + # image: ocelotsocialnetwork/webapp:development build: target: development environment: @@ -18,11 +18,12 @@ services: - webapp_node_modules:/app/node_modules # bind the local folder to the docker to allow live reload - ./webapp:/app + ######################################################## # BACKEND ############################################## ######################################################## backend: - image: ocelotsocialnetwork/backend:development + # image: ocelotsocialnetwork/backend:development build: target: development environment: @@ -34,22 +35,25 @@ services: - backend_node_modules:/app/node_modules # bind the local folder to the docker to allow live reload - ./backend:/app + ######################################################## # NEO4J ################################################ ######################################################## neo4j: - image: ocelotsocialnetwork/neo4j:development + # image: ocelotsocialnetwork/neo4j:development ports: # Also expose the neo4j query browser - 7474:7474 networks: # So we can access the neo4j query browser from our host machine - external-net + ######################################################## # MAINTENANCE ########################################## ######################################################## - maintenance: - image: ocelotsocialnetwork/maintenance:development + # maintenance: + # image: ocelotsocialnetwork/maintenance:development + ######################################################## # MAILSERVER TO FAKE SMTP ############################## ######################################################## diff --git a/docker-compose.yml b/docker-compose.yml index d20bb6aec..f1baaf58c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,7 +10,7 @@ services: # WEBAPP ############################################### ######################################################## webapp: - image: ocelotsocialnetwork/webapp:latest + # image: ocelotsocialnetwork/webapp:latest build: context: ./webapp target: production @@ -35,11 +35,12 @@ services: - GRAPHQL_URI=http://backend:4000 env_file: - ./webapp/.env + ######################################################## # BACKEND ############################################## ######################################################## backend: - image: ocelotsocialnetwork/backend:latest + # image: ocelotsocialnetwork/backend:latest build: context: ./backend target: production @@ -67,11 +68,12 @@ services: - CLIENT_URI=http://webapp:3000 env_file: - ./backend/.env + ######################################################## # NEO4J ################################################ ######################################################## neo4j: - image: ocelotsocialnetwork/neo4j:latest + # image: ocelotsocialnetwork/neo4j:latest build: context: ./neo4j # community edition 👆🏼, because we have no enterprise licence 👇🏼 at the moment @@ -90,11 +92,12 @@ services: # TODO: clarify if that is the only thing needed to unlock the Enterprise version # - NEO4J_ACCEPT_LICENSE_AGREEMENT=yes # TODO: Remove the playground from production + ######################################################## # MAINTENANCE ########################################## ######################################################## maintenance: - image: ocelotsocialnetwork/maintenance:latest + # image: ocelotsocialnetwork/maintenance:latest build: # TODO: Separate from webapp, this must be independent context: ./webapp From 0fef1bbd60349d1bd7ea1f20a8917146a751d09a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 13 Jul 2022 10:49:21 +0200 Subject: [PATCH 005/588] Change Docker compose 'maintenance' port from '5000' to '3001' - Because port '5000' has a standard use on macOS, it is said. --- docker-compose.yml | 2 +- webapp/maintenance/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f1baaf58c..a75e65883 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -105,7 +105,7 @@ services: networks: - external-net ports: - - 5000:80 + - 3001:80 networks: external-net: diff --git a/webapp/maintenance/README.md b/webapp/maintenance/README.md index 99e410a1c..95c09bae8 100644 --- a/webapp/maintenance/README.md +++ b/webapp/maintenance/README.md @@ -36,4 +36,4 @@ $ docker-compose up ```` And the maintenance mode page or service will be started as well in an own container. -In the browser you can reach it under `http://localhost:5000/`. +In the browser you can reach it under `http://localhost:3001/`. From 2c4ee18c9e2c79c90cf2a99c5f2c6dd741a50268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 15 Jul 2022 09:19:10 +0200 Subject: [PATCH 006/588] Make 'docker-compose-apple-m1.override.yml' usable for overriding development as well - Do this by removing 'mailserver' platform in 'docker-compose-apple-m1.override.yml'. --- docker-compose.apple-m1.override.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker-compose.apple-m1.override.yml b/docker-compose.apple-m1.override.yml index 214655ab6..e5b8ddb9e 100644 --- a/docker-compose.apple-m1.override.yml +++ b/docker-compose.apple-m1.override.yml @@ -28,5 +28,6 @@ services: ######################################################## # MAILSERVER TO FAKE SMTP ############################## ######################################################## - mailserver: - platform: linux/amd64 + # commented out, because otherwise override of production would error. and it seems unnecessary + # mailserver: + # platform: linux/amd64 From 8d10066fbaaebd02196d18d753b1a3ec0c18b5fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 15 Jul 2022 09:28:53 +0200 Subject: [PATCH 007/588] Replace in docker compose 'ocelotsocialnetwork/*:development' by 'ocelotsocialnetwork/*:local-development' --- docker-compose.override.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index e1ee25fd7..fd9e6f41f 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -5,7 +5,7 @@ services: # WEBAPP ############################################### ######################################################## webapp: - # image: ocelotsocialnetwork/webapp:development + image: ocelotsocialnetwork/webapp:local-development build: target: development environment: @@ -23,7 +23,7 @@ services: # BACKEND ############################################## ######################################################## backend: - # image: ocelotsocialnetwork/backend:development + image: ocelotsocialnetwork/backend:local-development build: target: development environment: @@ -40,7 +40,7 @@ services: # NEO4J ################################################ ######################################################## neo4j: - # image: ocelotsocialnetwork/neo4j:development + image: ocelotsocialnetwork/neo4j:local-development ports: # Also expose the neo4j query browser - 7474:7474 @@ -51,8 +51,8 @@ services: ######################################################## # MAINTENANCE ########################################## ######################################################## - # maintenance: - # image: ocelotsocialnetwork/maintenance:development + maintenance: + image: ocelotsocialnetwork/maintenance:local-development ######################################################## # MAILSERVER TO FAKE SMTP ############################## From f5c4cd77013a323ecddc6f653dd1df787f43b1bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 15 Jul 2022 09:29:59 +0200 Subject: [PATCH 008/588] Replace in docker compose 'ocelotsocialnetwork/*:latest' by 'ocelotsocialnetwork/*:local-production' --- docker-compose.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index a75e65883..d71a9e947 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,7 +10,7 @@ services: # WEBAPP ############################################### ######################################################## webapp: - # image: ocelotsocialnetwork/webapp:latest + image: ocelotsocialnetwork/webapp:local-production build: context: ./webapp target: production @@ -40,7 +40,7 @@ services: # BACKEND ############################################## ######################################################## backend: - # image: ocelotsocialnetwork/backend:latest + image: ocelotsocialnetwork/backend:local-production build: context: ./backend target: production @@ -73,7 +73,7 @@ services: # NEO4J ################################################ ######################################################## neo4j: - # image: ocelotsocialnetwork/neo4j:latest + image: ocelotsocialnetwork/neo4j:local-production build: context: ./neo4j # community edition 👆🏼, because we have no enterprise licence 👇🏼 at the moment @@ -97,7 +97,7 @@ services: # MAINTENANCE ########################################## ######################################################## maintenance: - # image: ocelotsocialnetwork/maintenance:latest + image: ocelotsocialnetwork/maintenance:local-production build: # TODO: Separate from webapp, this must be independent context: ./webapp From 9468e3c697d0d9f151a3c9598188e05debce61c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Sun, 17 Jul 2022 19:42:38 +0200 Subject: [PATCH 009/588] Add todo comment for our old maintenance worker --- docker-compose.maintenance.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker-compose.maintenance.yml b/docker-compose.maintenance.yml index 56da9be52..831bb3f4a 100644 --- a/docker-compose.maintenance.yml +++ b/docker-compose.maintenance.yml @@ -1,3 +1,5 @@ +# Todo: !!! This file seems related to our old maintenance worker for MongoDB and has to be refactored in case of using it !!! + version: "3.4" services: From 5f9155805d5e6956ce7c0e8522fa92a0463099be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Sun, 17 Jul 2022 20:32:03 +0200 Subject: [PATCH 010/588] Fix 'Dockerfile' for webapp and backend for running locally and in cluster --- backend/Dockerfile | 1 + webapp/Dockerfile | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/backend/Dockerfile b/backend/Dockerfile index 0ebdfb1eb..6c2f72bd3 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -91,6 +91,7 @@ FROM base as production # Copy "binary"-files from build image COPY --from=build ${DOCKER_WORKDIR}/dist ./dist +COPY --from=build ${DOCKER_WORKDIR}/node_modules ./node_modules # Copy static files # TODO - externalize the uploads so we can copy the whole folder COPY --from=build ${DOCKER_WORKDIR}/public/img/ ./public/img/ diff --git a/webapp/Dockerfile b/webapp/Dockerfile index 8d830a9d5..a086a4b2a 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -94,6 +94,13 @@ FROM base as production COPY --from=build ${DOCKER_WORKDIR}/.nuxt ./.nuxt COPY --from=build ${DOCKER_WORKDIR}/node_modules ./node_modules COPY --from=build ${DOCKER_WORKDIR}/nuxt.config.js ./nuxt.config.js +# Copy static files +# TODO - this seems not be needed anymore for the new rebranding +# TODO - this should be one Folder containign all stuff needed to be copied +COPY --from=build ${DOCKER_WORKDIR}/config/ ./config/ +COPY --from=build ${DOCKER_WORKDIR}/constants ./constants +COPY --from=build ${DOCKER_WORKDIR}/static ./static +COPY --from=build ${DOCKER_WORKDIR}/locales ./locales # Copy package.json for script definitions (lock file should not be needed) COPY --from=build ${DOCKER_WORKDIR}/package.json ./package.json From fbbcc5bb854d53b5fa658b83d56d381a3cbc2b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Sun, 17 Jul 2022 20:35:16 +0200 Subject: [PATCH 011/588] Add documentation for Docker build analyzes --- DOCKER_MORE_CLOSELY.md | 64 ++++++++++++++++++++++++++++++++++++++++++ SUMMARY.md | 1 + 2 files changed, 65 insertions(+) create mode 100644 DOCKER_MORE_CLOSELY.md diff --git a/DOCKER_MORE_CLOSELY.md b/DOCKER_MORE_CLOSELY.md new file mode 100644 index 000000000..e4b40579e --- /dev/null +++ b/DOCKER_MORE_CLOSELY.md @@ -0,0 +1,64 @@ +# Docker More Closely + +## Apple M1 Platform + +***Attention:** For using Docker commands in Apple M1 environments!* + +### Enviroment Variable For Apple M1 Platform + +To set the Docker platform environment variable in your terminal tab, run: + +```bash +# set env variable for your shell +$ export DOCKER_DEFAULT_PLATFORM=linux/amd64 +``` + +## Analysing Docker Builds + +To analyze a Docker build, there is a wonderful tool called [dive](https://github.com/wagoodman/dive). Please sponsor if you're using it! + +The `dive build` command is exactly the right one to fulfill what we are looking for. +We can use it just like the `docker build` command and get an analysis afterwards. + +So, in our main folder, we use it in the following way: + +```bash +# in main folder +$ dive build --target -t "ocelotsocialnetwork/:local-" --build-arg BBUILD_DATE="" --build-arg BBUILD_VERSION="" --build-arg BBUILD_COMMIT="" / +``` + +The build arguments are optional. + +For the specific applications, we use them as follows. + +### Backend + +#### Production For Backend + +```bash +# in main folder +$ dive build --target production -t "ocelotsocialnetwork/backend:local-production" backend/ +``` + +#### Development For Backend + +```bash +# in main folder +$ dive build --target development -t "ocelotsocialnetwork/backend:local-development" backend/ +``` + +### Webapp + +#### Production For Webapp + +```bash +# in main folder +$ dive build --target production -t "ocelotsocialnetwork/webapp:local-production" webapp/ +``` + +#### Development For Webapp + +```bash +# in main folder +$ dive build --target development -t "ocelotsocialnetwork/webapp:local-development" webapp/ +``` diff --git a/SUMMARY.md b/SUMMARY.md index 9c74b1974..f848633d5 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -15,6 +15,7 @@ * [End-to-end tests](cypress/README.md) * [Frontend tests](webapp/testing.md) * [Backend tests](backend/testing.md) +* [Docker More Closely](DOCKER_MORE_CLOSELY.md) * [Deployment](https://github.com/Ocelot-Social-Community/Ocelot-Social-Deploy-Rebranding/blob/master/deployment/README.md) * [Contributing](CONTRIBUTING.md) * [Feature Specification](cypress/features.md) From 2f3f37c158cfc9b300540d3c8f016548b15a5277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Sun, 17 Jul 2022 20:37:33 +0200 Subject: [PATCH 012/588] Add documentation for Apple M1 Docker Compose override files --- DOCKER_MORE_CLOSELY.md | 84 ++++++++++++++++++++++++++++++++++++++++++ SUMMARY.md | 1 + 2 files changed, 85 insertions(+) create mode 100644 DOCKER_MORE_CLOSELY.md diff --git a/DOCKER_MORE_CLOSELY.md b/DOCKER_MORE_CLOSELY.md new file mode 100644 index 000000000..592b5bb9b --- /dev/null +++ b/DOCKER_MORE_CLOSELY.md @@ -0,0 +1,84 @@ +# Docker More Closely + +## Apple M1 Platform + +***Attention:** For using Docker commands in Apple M1 environments!* + +### Enviroment Variable For Apple M1 Platform + +To set the Docker platform environment variable in your terminal tab, run: + +```bash +# set env variable for your shell +$ export DOCKER_DEFAULT_PLATFORM=linux/amd64 +``` + +### Docker Compose Override File For Apple M1 Platform + +For Docker compose `up` or `build` commands, you can use our Apple M1 override file that specifies the M1 platform: + +```bash +# in main folder + +# for development +$ docker compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.apple-m1.override.yml up +# clean db +$ docker compose exec backend yarn db:reset +# seed db +$ docker compose exec backend yarn db:seed + +# for production +$ docker compose -f docker-compose.yml -f docker-compose.apple-m1.override.yml up +# init admin user +$ docker compose exec backend /bin/sh -c "yarn prod:migrate init" +``` + +## Analysing Docker Builds + +To analyze a Docker build, there is a wonderful tool called [dive](https://github.com/wagoodman/dive). Please sponsor if you're using it! + +The `dive build` command is exactly the right one to fulfill what we are looking for. +We can use it just like the `docker build` command and get an analysis afterwards. + +So, in our main folder, we use it in the following way: + +```bash +# in main folder +$ dive build --target -t "ocelotsocialnetwork/:local-" --build-arg BBUILD_DATE="" --build-arg BBUILD_VERSION="" --build-arg BBUILD_COMMIT="" / +``` + +The build arguments are optional. + +For the specific applications, we use them as follows. + +### Backend + +#### Production For Backend + +```bash +# in main folder +$ dive build --target production -t "ocelotsocialnetwork/backend:local-production" backend/ +``` + +#### Development For Backend + +```bash +# in main folder +$ dive build --target development -t "ocelotsocialnetwork/backend:local-development" backend/ +``` + +### Webapp + +#### Production For Webapp + +```bash +# in main folder +$ dive build --target production -t "ocelotsocialnetwork/webapp:local-production" webapp/ +``` + +#### Development For Webapp + +```bash +# in main folder +$ dive build --target development -t "ocelotsocialnetwork/webapp:local-development" webapp/ +``` diff --git a/SUMMARY.md b/SUMMARY.md index 9c74b1974..f848633d5 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -15,6 +15,7 @@ * [End-to-end tests](cypress/README.md) * [Frontend tests](webapp/testing.md) * [Backend tests](backend/testing.md) +* [Docker More Closely](DOCKER_MORE_CLOSELY.md) * [Deployment](https://github.com/Ocelot-Social-Community/Ocelot-Social-Deploy-Rebranding/blob/master/deployment/README.md) * [Contributing](CONTRIBUTING.md) * [Feature Specification](cypress/features.md) From bc97b1db0c79e16b5c4578f950b96be32d430ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 18 Jul 2022 06:42:14 +0200 Subject: [PATCH 013/588] Add comments for Docker image naming --- docker-compose.apple-m1.override.yml | 1 + docker-compose.override.yml | 5 +++++ docker-compose.test.yml | 9 +++++++++ docker-compose.yml | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/docker-compose.apple-m1.override.yml b/docker-compose.apple-m1.override.yml index e5b8ddb9e..a91b3ab77 100644 --- a/docker-compose.apple-m1.override.yml +++ b/docker-compose.apple-m1.override.yml @@ -1,6 +1,7 @@ version: "3.4" services: + ######################################################## # WEBAPP ############################################### ######################################################## diff --git a/docker-compose.override.yml b/docker-compose.override.yml index fd9e6f41f..baf4bf89f 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,10 +1,12 @@ version: "3.4" services: + ######################################################## # WEBAPP ############################################### ######################################################## webapp: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/webapp:local-development build: target: development @@ -23,6 +25,7 @@ services: # BACKEND ############################################## ######################################################## backend: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/backend:local-development build: target: development @@ -40,6 +43,7 @@ services: # NEO4J ################################################ ######################################################## neo4j: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/neo4j:local-development ports: # Also expose the neo4j query browser @@ -52,6 +56,7 @@ services: # MAINTENANCE ########################################## ######################################################## maintenance: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/maintenance:local-development ######################################################## diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 973cf87cf..843dd5ff8 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -1,10 +1,12 @@ version: "3.4" services: + ######################################################## # WEBAPP ############################################### ######################################################## webapp: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/webapp:test build: target: test @@ -12,10 +14,12 @@ services: - NODE_ENV="test" volumes: - ./coverage:/app/coverage + ######################################################## # BACKEND ############################################## ######################################################## backend: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/backend:test build: target: test @@ -23,10 +27,12 @@ services: - NODE_ENV="test" volumes: - ./coverage:/app/coverage + ######################################################## # NEO4J ################################################ ######################################################## neo4j: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/neo4j:community #environment: # - NEO4J_dbms_connector_bolt_enabled=true @@ -39,11 +45,14 @@ services: networks: # So we can access the neo4j query browser from our host machine - external-net + ######################################################## # MAINTENANCE ########################################## ######################################################## maintenance: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/maintenance:test + ######################################################## # MAILSERVER TO FAKE SMTP ############################## ######################################################## diff --git a/docker-compose.yml b/docker-compose.yml index d71a9e947..796489439 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,10 +6,12 @@ version: "3.4" services: + ######################################################## # WEBAPP ############################################### ######################################################## webapp: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/webapp:local-production build: context: ./webapp @@ -40,6 +42,7 @@ services: # BACKEND ############################################## ######################################################## backend: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/backend:local-production build: context: ./backend @@ -73,6 +76,7 @@ services: # NEO4J ################################################ ######################################################## neo4j: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/neo4j:local-production build: context: ./neo4j @@ -97,6 +101,7 @@ services: # MAINTENANCE ########################################## ######################################################## maintenance: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: ocelotsocialnetwork/maintenance:local-production build: # TODO: Separate from webapp, this must be independent From 2bc09aceeb09a67b9f1eecc0942c04158971b6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 18 Jul 2022 07:11:35 +0200 Subject: [PATCH 014/588] Rename Neo4j Docker in general image to 'neo4j-community:*' --- .github/workflows/publish.yml | 6 +++--- .github/workflows/test.yml | 4 ++-- docker-compose.override.yml | 2 +- docker-compose.test.yml | 2 +- docker-compose.yml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1c7927665..56df65ea0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -56,9 +56,9 @@ jobs: # NEO4J ################################################################## ########################################################################## - name: Neo4J | Build `community` image - run: docker build --target community -t "ocelotsocialnetwork/neo4j:latest" -t "ocelotsocialnetwork/neo4j:community" -t "ocelotsocialnetwork/neo4j:${VERSION}" -t "ocelotsocialnetwork/neo4j:${BUILD_VERSION}" --build-arg BBUILD_DATE=$BUILD_DATE --build-arg BBUILD_VERSION=$BUILD_VERSION --build-arg BBUILD_COMMIT=$BUILD_COMMIT neo4j/ + run: docker build --target community -t "ocelotsocialnetwork/neo4j-community:latest" -t "ocelotsocialnetwork/neo4j-community:${VERSION}" -t "ocelotsocialnetwork/neo4j-community:${BUILD_VERSION}" --build-arg BBUILD_DATE=$BUILD_DATE --build-arg BBUILD_VERSION=$BUILD_VERSION --build-arg BBUILD_COMMIT=$BUILD_COMMIT neo4j/ - name: Neo4J | Save docker image - run: docker save "ocelotsocialnetwork/neo4j" > /tmp/neo4j.tar + run: docker save "ocelotsocialnetwork/neo4j-community" > /tmp/neo4j.tar - name: Upload Artifact uses: actions/upload-artifact@v2 with: @@ -238,7 +238,7 @@ jobs: - name: login to dockerhub run: echo "${DOCKERHUB_TOKEN}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin - name: Push neo4j - run: docker push --all-tags ocelotsocialnetwork/neo4j + run: docker push --all-tags ocelotsocialnetwork/neo4j-community - name: Push backend run: docker push --all-tags ocelotsocialnetwork/backend - name: Push webapp diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5dd385ad8..9564aa2f7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,8 +43,8 @@ jobs: ########################################################################## - name: Neo4J | Build `community` image run: | - docker build --target community -t "ocelotsocialnetwork/neo4j:community" neo4j/ - docker save "ocelotsocialnetwork/neo4j:community" > /tmp/neo4j.tar + docker build --target community -t "ocelotsocialnetwork/neo4j-community:test" neo4j/ + docker save "ocelotsocialnetwork/neo4j-community:test" > /tmp/neo4j.tar - name: Upload Artifact uses: actions/upload-artifact@v2 with: diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 15cf00e7a..ff2a398bb 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -38,7 +38,7 @@ services: # NEO4J ################################################ ######################################################## neo4j: - image: ocelotsocialnetwork/neo4j:development + image: ocelotsocialnetwork/neo4j-community:development ports: # Also expose the neo4j query browser - 7474:7474 diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 973cf87cf..d11ecde54 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -27,7 +27,7 @@ services: # NEO4J ################################################ ######################################################## neo4j: - image: ocelotsocialnetwork/neo4j:community + image: ocelotsocialnetwork/neo4j-community:test #environment: # - NEO4J_dbms_connector_bolt_enabled=true # - NEO4J_dbms_connector_bolt_tls__level=OPTIONAL diff --git a/docker-compose.yml b/docker-compose.yml index d20bb6aec..863fb2c25 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -71,7 +71,7 @@ services: # NEO4J ################################################ ######################################################## neo4j: - image: ocelotsocialnetwork/neo4j:latest + image: ocelotsocialnetwork/neo4j-community:latest build: context: ./neo4j # community edition 👆🏼, because we have no enterprise licence 👇🏼 at the moment From cc62d9e0a3c846516e6357c62f6ea2a80d91dd26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 18 Jul 2022 19:08:03 +0200 Subject: [PATCH 015/588] Switch in Docker Compose files Neo4j and maintenance --- docker-compose.apple-m1.override.yml | 12 +++++------ docker-compose.override.yml | 14 ++++++------- docker-compose.yml | 30 ++++++++++++++-------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docker-compose.apple-m1.override.yml b/docker-compose.apple-m1.override.yml index a91b3ab77..cbb041c51 100644 --- a/docker-compose.apple-m1.override.yml +++ b/docker-compose.apple-m1.override.yml @@ -14,18 +14,18 @@ services: backend: platform: linux/amd64 - ######################################################## - # NEO4J ################################################ - ######################################################## - neo4j: - platform: linux/amd64 - ######################################################## # MAINTENANCE ########################################## ######################################################## maintenance: platform: linux/amd64 + ######################################################## + # NEO4J ################################################ + ######################################################## + neo4j: + platform: linux/amd64 + ######################################################## # MAILSERVER TO FAKE SMTP ############################## ######################################################## diff --git a/docker-compose.override.yml b/docker-compose.override.yml index e740af1fe..d8a3edc06 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -39,6 +39,13 @@ services: # bind the local folder to the docker to allow live reload - ./backend:/app + ######################################################## + # MAINTENANCE ########################################## + ######################################################## + maintenance: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: ocelotsocialnetwork/maintenance:local-development + ######################################################## # NEO4J ################################################ ######################################################## @@ -52,13 +59,6 @@ services: # So we can access the neo4j query browser from our host machine - external-net - ######################################################## - # MAINTENANCE ########################################## - ######################################################## - maintenance: - # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there - image: ocelotsocialnetwork/maintenance:local-development - ######################################################## # MAILSERVER TO FAKE SMTP ############################## ######################################################## diff --git a/docker-compose.yml b/docker-compose.yml index 98024362a..154a8fd4c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -72,6 +72,21 @@ services: env_file: - ./backend/.env + ######################################################## + # MAINTENANCE ########################################## + ######################################################## + maintenance: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: ocelotsocialnetwork/maintenance:local-production + build: + # TODO: Separate from webapp, this must be independent + context: ./webapp + dockerfile: Dockerfile.maintenance + networks: + - external-net + ports: + - 3001:80 + ######################################################## # NEO4J ################################################ ######################################################## @@ -97,21 +112,6 @@ services: # - NEO4J_ACCEPT_LICENSE_AGREEMENT=yes # TODO: Remove the playground from production - ######################################################## - # MAINTENANCE ########################################## - ######################################################## - maintenance: - # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there - image: ocelotsocialnetwork/maintenance:local-production - build: - # TODO: Separate from webapp, this must be independent - context: ./webapp - dockerfile: Dockerfile.maintenance - networks: - - external-net - ports: - - 3001:80 - networks: external-net: internal-net: From 3491f2ae15c4fe202d0736b11784fca39e3917e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 18 Jul 2022 19:10:17 +0200 Subject: [PATCH 016/588] Switch in Docker Compose test file Neo4j and maintenance --- docker-compose.test.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 3485274db..fa858f28c 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -28,6 +28,13 @@ services: volumes: - ./coverage:/app/coverage + ######################################################## + # MAINTENANCE ########################################## + ######################################################## + maintenance: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: ocelotsocialnetwork/maintenance:test + ######################################################## # NEO4J ################################################ ######################################################## @@ -46,13 +53,6 @@ services: # So we can access the neo4j query browser from our host machine - external-net - ######################################################## - # MAINTENANCE ########################################## - ######################################################## - maintenance: - # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there - image: ocelotsocialnetwork/maintenance:test - ######################################################## # MAILSERVER TO FAKE SMTP ############################## ######################################################## From ced38f552c5d217bfeb39a3860f53480722a30ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 18 Jul 2022 20:10:15 +0200 Subject: [PATCH 017/588] Trigger publish on push of this branch for testing purposes, for now --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 56df65ea0..da8d006e7 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,7 +4,7 @@ on: push: branches: - master - # - 4451-new-deployment-with-base-and-code # for testing while developing + - 5065-automatic-deployment-to-stage.ocelot.social-on-push-to-master-branch # for testing while developing jobs: ############################################################################## From 485e6986b88a14db5ab75ed12bab5cdc73592ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 19 Jul 2022 08:30:56 +0200 Subject: [PATCH 018/588] Implement DigitalOcean Kubernetes deployment on publishing --- .github/workflows/publish.yml | 59 ++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index da8d006e7..a2e9c84de 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -246,6 +246,63 @@ jobs: - name: Push maintenance run: docker push --all-tags ocelotsocialnetwork/maintenance + ############################################################################## + # JOB: KUBERNETES DEPLOY LATEST VERSION ###################################### + ############################################################################## + kubernetes_deploy: + # see example https://github.com/do-community/example-doctl-action + # see example https://github.com/do-community/example-doctl-action/blob/main/.github/workflows/workflow.yaml + name: Kubernetes deploy of latest version to stage.ocelot.social cluster at DigitalOcean + runs-on: ubuntu-latest + needs: [upload_to_dockerhub] + steps: + ########################################################################## + # CHECKOUT CODE ########################################################## + ########################################################################## + - name: Checkout code + uses: actions/checkout@v2 + ########################################################################## + # SET ENVS ############################################################### + ########################################################################## + - name: ENV - VERSION + run: echo "VERSION=$(node -p -e "require('./package.json').version")" >> $GITHUB_ENV + - name: ENV - BUILD_VERSION + run: echo "BUILD_VERSION=${VERSION}-${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + ########################################################################## + # Install DigitalOceans doctl and set kubeconfig ######################### + ########################################################################## + - name: Install doctl + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + - name: Save DigitalOcean kubeconfig with short-lived credentials + run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 cluster-stage-ocelot-social + ########################################################################## + # Deploy new Docker images to DigitalOcean Kubernetes cluster ############ + ########################################################################## + # - name: Deploy 'latest' to DigitalOcean Kubernetes + # run: | + # kubectl set image deployment/ocelot-webapp container-ocelot-webapp=ocelotsocialnetwork/webapp:latest + # kubectl rollout restart deployment/ocelot-webapp + # kubectl set image deployment/ocelot-backend container-ocelot-backend=ocelotsocialnetwork/backend:latest + # kubectl rollout restart deployment/ocelot-backend + # kubectl set image deployment/ocelot-maintenance container-ocelot-maintenance=ocelotsocialnetwork/maintenance:latest + # kubectl rollout restart deployment/ocelot-backend + # kubectl set image deployment/ocelot-neo4j container-ocelot-neo4j=ocelotsocialnetwork/neo4j-community:latest + # kubectl rollout restart deployment/ocelot-neo4j + - name: Deploy actual version '$BUILD_VERSION' to DigitalOcean Kubernetes + run: | + kubectl set image deployment/ocelot-webapp container-ocelot-webapp=ocelotsocialnetwork/webapp:$BUILD_VERSION + kubectl set image deployment/ocelot-backend container-ocelot-backend=ocelotsocialnetwork/backend:$BUILD_VERSION + kubectl set image deployment/ocelot-maintenance container-ocelot-maintenance=ocelotsocialnetwork/maintenance:$BUILD_VERSION + kubectl set image deployment/ocelot-neo4j container-ocelot-neo4j=ocelotsocialnetwork/neo4j-community:$BUILD_VERSION + # - name: Verify deployment + # run: | + # kubectl rollout status deployment/ocelot-webapp + # kubectl rollout status deployment/ocelot-backend + # kubectl rollout status deployment/ocelot-backend + # kubectl rollout status deployment/ocelot-neo4j + ############################################################################## # JOB: GITHUB TAG LATEST VERSION ############################################# ############################################################################## @@ -313,4 +370,4 @@ jobs: release_name: ${{ env.VERSION }} body_path: ./CHANGELOG.md draft: false - prerelease: false \ No newline at end of file + prerelease: false From 7ad398fb20f26b93df16365090f04e5f39185da1 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 19 Jul 2022 11:50:59 +0200 Subject: [PATCH 019/588] refactor search info text --- webapp/locales/de.json | 2 +- webapp/locales/en.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/locales/de.json b/webapp/locales/de.json index 392cd9771..65419ebf0 100644 --- a/webapp/locales/de.json +++ b/webapp/locales/de.json @@ -620,7 +620,7 @@ "Tag": "Hashtag ::: Hashtags", "User": "Benutzer ::: Benutzer" }, - "hint": "Wonach suchst Du?", + "hint": "Wonach suchst Du? Nutze !… für Beitrag, @… für Mitglied, #… für Hashtag", "no-results": "Keine Ergebnisse für \"{search}\" gefunden. Versuch' es mit einem anderen Begriff!", "page": "Seite", "placeholder": "Suchen", diff --git a/webapp/locales/en.json b/webapp/locales/en.json index 24c0fa2be..8a8af14e7 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -620,7 +620,7 @@ "Tag": "Hashtag ::: Hashtags", "User": "User ::: Users" }, - "hint": "What are you searching for?", + "hint": "What are you searching for? Use !... for post, @... for member, #... for hashtag", "no-results": "No results found for \"{search}\". Try a different search term!", "page": "Page", "placeholder": "Search", From f4a746aa384d6a0e71e830f62f6159cbb8f79a63 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 19 Jul 2022 12:14:30 +0200 Subject: [PATCH 020/588] add all locales, set text in plural --- webapp/locales/de.json | 2 +- webapp/locales/en.json | 2 +- webapp/locales/es.json | 2 +- webapp/locales/fr.json | 2 +- webapp/locales/it.json | 6 +++--- webapp/locales/nl.json | 5 +++++ webapp/locales/pl.json | 2 +- webapp/locales/pt.json | 2 +- webapp/locales/ru.json | 5 +++++ 9 files changed, 19 insertions(+), 9 deletions(-) diff --git a/webapp/locales/de.json b/webapp/locales/de.json index 65419ebf0..297daa511 100644 --- a/webapp/locales/de.json +++ b/webapp/locales/de.json @@ -620,7 +620,7 @@ "Tag": "Hashtag ::: Hashtags", "User": "Benutzer ::: Benutzer" }, - "hint": "Wonach suchst Du? Nutze !… für Beitrag, @… für Mitglied, #… für Hashtag", + "hint": "Wonach suchst Du? Nutze !… für Beiträge, @… für Mitglieder, #… für Hashtags", "no-results": "Keine Ergebnisse für \"{search}\" gefunden. Versuch' es mit einem anderen Begriff!", "page": "Seite", "placeholder": "Suchen", diff --git a/webapp/locales/en.json b/webapp/locales/en.json index 8a8af14e7..8499b0290 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -620,7 +620,7 @@ "Tag": "Hashtag ::: Hashtags", "User": "User ::: Users" }, - "hint": "What are you searching for? Use !... for post, @... for member, #... for hashtag", + "hint": "What are you searching for? Use !… for posts, @… for users, #… for hashtags.", "no-results": "No results found for \"{search}\". Try a different search term!", "page": "Page", "placeholder": "Search", diff --git a/webapp/locales/es.json b/webapp/locales/es.json index 1d37cde5d..900b2fa5d 100644 --- a/webapp/locales/es.json +++ b/webapp/locales/es.json @@ -537,7 +537,7 @@ "Post": "Contribuciones", "User": "Usuarios" }, - "hint": "¿Qué estás buscando?", + "hint": "¿Qué estás buscando? Utiliza !… para contribuciones, @… para usuarios, #… para hashtags.", "placeholder": "Buscar" }, "settings": { diff --git a/webapp/locales/fr.json b/webapp/locales/fr.json index 642c93c8c..684f080b7 100644 --- a/webapp/locales/fr.json +++ b/webapp/locales/fr.json @@ -525,7 +525,7 @@ "Post": "Posts", "User": "Utilisateurs" }, - "hint": "Qu'est-ce que vous cherchez ?", + "hint": "Qu'est-ce que vous cherchez? Utiliser !… pour des posts, @… pour des membres, #… pour des hashtag.", "placeholder": "Rechercher" }, "settings": { diff --git a/webapp/locales/it.json b/webapp/locales/it.json index 8950ddabd..71994167b 100644 --- a/webapp/locales/it.json +++ b/webapp/locales/it.json @@ -473,9 +473,9 @@ } }, "search": { - "failed": null, - "hint": null, - "placeholder": null + "failed": "Non è stato trovato nulla", + "hint": "Cosa state cercando? Usate !... per i post, @... per gli utenti, #... per gli hashtag.", + "placeholder": "Ricerca" }, "settings": { "data": { diff --git a/webapp/locales/nl.json b/webapp/locales/nl.json index 3bf453655..3c1a8902d 100644 --- a/webapp/locales/nl.json +++ b/webapp/locales/nl.json @@ -131,6 +131,11 @@ "type": "Gebruiker" } }, + "search": { + "failed": "Niets gevonden", + "hint": "Waar zoekt u naar? Gebruik !... voor berichten, @... voor gebruikers, #... voor hashtags.", + "placeholder": "Zoeken" + }, "settings": { "data": { "name": "Uw gegevens" diff --git a/webapp/locales/pl.json b/webapp/locales/pl.json index dd416f0af..6ae3e32f7 100644 --- a/webapp/locales/pl.json +++ b/webapp/locales/pl.json @@ -278,7 +278,7 @@ }, "search": { "failed": "Niczego nie znaleziono", - "hint": "Czego szukasz?", + "hint": "Czego szukasz? Użyj !... dla postów, @... dla użytkowników, #... dla hashtagów.", "placeholder": "Szukaj" }, "settings": { diff --git a/webapp/locales/pt.json b/webapp/locales/pt.json index 64625840f..f5f89374a 100644 --- a/webapp/locales/pt.json +++ b/webapp/locales/pt.json @@ -510,7 +510,7 @@ }, "search": { "failed": "Nada encontrado", - "hint": "O que você está buscando?", + "hint": "O que você está buscando? Use !... para postagens, @... para usuários, #... para hashtags.", "placeholder": "Buscar" }, "settings": { diff --git a/webapp/locales/ru.json b/webapp/locales/ru.json index e7087cb9a..62979fc62 100644 --- a/webapp/locales/ru.json +++ b/webapp/locales/ru.json @@ -54,6 +54,11 @@ "pages": { "name": "Страницы" }, + "search": { + "failed": "Ничего не найдено", + "hint": "Что вы ищете? Используйте !... для постов, @... для пользователей, #... для хэштегов.", + "placeholder": "Поиск" + }, "settings": { "name": "Настройки" }, From c4d9e028d7a0c4501bb01cd5b4d29ad5399ed182 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 19 Jul 2022 12:26:01 +0200 Subject: [PATCH 021/588] add RU locales, set text in plural --- webapp/locales/ru.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/webapp/locales/ru.json b/webapp/locales/ru.json index 62979fc62..5f1368820 100644 --- a/webapp/locales/ru.json +++ b/webapp/locales/ru.json @@ -54,11 +54,6 @@ "pages": { "name": "Страницы" }, - "search": { - "failed": "Ничего не найдено", - "hint": "Что вы ищете? Используйте !... для постов, @... для пользователей, #... для хэштегов.", - "placeholder": "Поиск" - }, "settings": { "name": "Настройки" }, @@ -556,7 +551,7 @@ "Post": "Посты", "User": "Пользователи" }, - "hint": "Что вы хотите найти?", + "hint": "Что вы хотите найти? Используйте !... для постов, @... для пользователей, #... для хэштегов.", "placeholder": "Поиск" }, "settings": { From a1a8529c9c3a9b4ba277c5e9327497e06cf944fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 19 Jul 2022 15:15:33 +0200 Subject: [PATCH 022/588] Add Neo4j docu for important commands --- neo4j/README.md | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/neo4j/README.md b/neo4j/README.md index a4242b512..c9bff7741 100644 --- a/neo4j/README.md +++ b/neo4j/README.md @@ -7,7 +7,7 @@ database available. The community edition of Neo4J is Free and Open Source and we try our best to keep our application compatible with the community edition only. -## Installation with Docker +## Installation With Docker Run: @@ -19,7 +19,7 @@ You can access Neo4J through [http://localhost:7474/](http://localhost:7474/) for an interactive cypher shell and a visualization of the graph. -## Installation without Docker +## Installation Without Docker Install the community edition of [Neo4j](https://neo4j.com/) along with the plugin [Apoc](https://github.com/neo4j-contrib/neo4j-apoc-procedures) on your system. @@ -51,3 +51,42 @@ in `backend/.env`. Start Neo4J and confirm the database is running at [http://localhost:7474](http://localhost:7474). +## Commands + +Here we describe some rarely used Cypher commands for Neo4j that are needed from time to time: + +### Index And Contraint Commands + +The indexes and constraints of our database are set in `backend/src/db/migrate/store.js`. +This is where the magic happens. + +If they are missing or not set correctly, the browser search will not work or the database seed for development will not work. + +#### Show Indexes And Contraints + +```bash +# in browser command line or cypher shell + +# show all indexes and contraints +$ :schema + +# show all indexes +$ CALL db.indexes(); + +# show all contraints +$ CALL db.constraints(); +``` + +#### Add And Drop Indexes And Contraints + +```bash +# in browser command line or cypher shell + +# create indexes +$ CALL db.index.fulltext.createNodeIndex("post_fulltext_search",["Post"],["title", "content"]); +$ CALL db.index.fulltext.createNodeIndex("user_fulltext_search",["User"],["name", "slug"]); +$ CALL db.index.fulltext.createNodeIndex("tag_fulltext_search",["Tag"],["id"]); + +# drop all indexes and contraints +$ CALL apoc.schema.assert({},{},true) YIELD label, key RETURN * ; +``` From e2f01385437c0581939e5879b86b00ce4497dad1 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 19 Jul 2022 15:30:18 +0200 Subject: [PATCH 023/588] change footer version-link --- webapp/components/PageFooter/PageFooter.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/components/PageFooter/PageFooter.vue b/webapp/components/PageFooter/PageFooter.vue index 586843b81..24d35244b 100644 --- a/webapp/components/PageFooter/PageFooter.vue +++ b/webapp/components/PageFooter/PageFooter.vue @@ -9,7 +9,7 @@ From 0487a280a3294e219745c785b6e4f4cbd70038a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 19 Jul 2022 17:46:07 +0200 Subject: [PATCH 024/588] Refine description and add calls of 'prod:migrate init' and single index drop example --- DOCKER_MORE_CLOSELY.md | 4 +++- neo4j/README.md | 45 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/DOCKER_MORE_CLOSELY.md b/DOCKER_MORE_CLOSELY.md index 592b5bb9b..03e6417ec 100644 --- a/DOCKER_MORE_CLOSELY.md +++ b/DOCKER_MORE_CLOSELY.md @@ -22,6 +22,8 @@ For Docker compose `up` or `build` commands, you can use our Apple M1 override f # for development $ docker compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.apple-m1.override.yml up +# only once: init admin user and create indexes and contraints in Neo4j database +$ docker compose exec backend yarn prod:migrate init # clean db $ docker compose exec backend yarn db:reset # seed db @@ -29,7 +31,7 @@ $ docker compose exec backend yarn db:seed # for production $ docker compose -f docker-compose.yml -f docker-compose.apple-m1.override.yml up -# init admin user +# only once: init admin user and create indexes and contraints in Neo4j database $ docker compose exec backend /bin/sh -c "yarn prod:migrate init" ``` diff --git a/neo4j/README.md b/neo4j/README.md index c9bff7741..f2b26d551 100644 --- a/neo4j/README.md +++ b/neo4j/README.md @@ -57,12 +57,48 @@ Here we describe some rarely used Cypher commands for Neo4j that are needed from ### Index And Contraint Commands +If indexes or constraints are missing or not set correctly, the browser search will not work or the database seed for development will not work. + The indexes and constraints of our database are set in `backend/src/db/migrate/store.js`. This is where the magic happens. -If they are missing or not set correctly, the browser search will not work or the database seed for development will not work. +It's called by our `prod:migrate init` command. +This command initializes the Admin user and creates all necessary indexes and constraints in the Neo4j database. -#### Show Indexes And Contraints +***Calls in development*** + +Locally without Docker: + +```bash +# in backend folder +$ yarn prod:migrate init +``` + +Locally with Docker: + +```bash +# in main folder +$ docker compose exec backend yarn prod:migrate init +``` + +***Calls in production*** + +Locally with Docker: + +```bash +# in main folder +$ docker compose exec backend /bin/sh -c "yarn prod:migrate init" +``` + +On a server with Kubernetes cluster: + +```bash +# tested for one backend replica +# !!! be aware of the kubectl context !!! +$ kubectl -n default exec -it $(kubectl -n default get pods | grep ocelot-backend | awk '{ print $1 }') -- /bin/sh -c "yarn prod:migrate init" +``` + +***Cypher commands to show indexes and contraints*** ```bash # in browser command line or cypher shell @@ -77,7 +113,7 @@ $ CALL db.indexes(); $ CALL db.constraints(); ``` -#### Add And Drop Indexes And Contraints +***Cypher commands to create and drop indexes and contraints*** ```bash # in browser command line or cypher shell @@ -87,6 +123,9 @@ $ CALL db.index.fulltext.createNodeIndex("post_fulltext_search",["Post"],["title $ CALL db.index.fulltext.createNodeIndex("user_fulltext_search",["User"],["name", "slug"]); $ CALL db.index.fulltext.createNodeIndex("tag_fulltext_search",["Tag"],["id"]); +# drop an index +$ DROP CONSTRAINT ON ( image:Image ) ASSERT image.url IS UNIQUE + # drop all indexes and contraints $ CALL apoc.schema.assert({},{},true) YIELD label, key RETURN * ; ``` From 794b8b29e11a0c4fc1da456ba2823d0ca23e41cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 19 Jul 2022 18:50:42 +0200 Subject: [PATCH 025/588] Add Neo4j db seed to publish.yml --- .github/workflows/publish.yml | 47 +++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a2e9c84de..2720236fe 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -247,7 +247,7 @@ jobs: run: docker push --all-tags ocelotsocialnetwork/maintenance ############################################################################## - # JOB: KUBERNETES DEPLOY LATEST VERSION ###################################### + # JOB: KUBERNETES DEPLOY ACTUAL/LATEST VERSION ###################################### ############################################################################## kubernetes_deploy: # see example https://github.com/do-community/example-doctl-action @@ -282,26 +282,35 @@ jobs: ########################################################################## # - name: Deploy 'latest' to DigitalOcean Kubernetes # run: | - # kubectl set image deployment/ocelot-webapp container-ocelot-webapp=ocelotsocialnetwork/webapp:latest - # kubectl rollout restart deployment/ocelot-webapp - # kubectl set image deployment/ocelot-backend container-ocelot-backend=ocelotsocialnetwork/backend:latest - # kubectl rollout restart deployment/ocelot-backend - # kubectl set image deployment/ocelot-maintenance container-ocelot-maintenance=ocelotsocialnetwork/maintenance:latest - # kubectl rollout restart deployment/ocelot-backend - # kubectl set image deployment/ocelot-neo4j container-ocelot-neo4j=ocelotsocialnetwork/neo4j-community:latest - # kubectl rollout restart deployment/ocelot-neo4j + # kubectl -n default set image deployment/ocelot-webapp container-ocelot-webapp=ocelotsocialnetwork/webapp:latest + # kubectl -n default rollout restart deployment/ocelot-webapp + # kubectl -n default set image deployment/ocelot-backend container-ocelot-backend=ocelotsocialnetwork/backend:latest + # kubectl -n default rollout restart deployment/ocelot-backend + # kubectl -n default set image deployment/ocelot-maintenance container-ocelot-maintenance=ocelotsocialnetwork/maintenance:latest + # kubectl -n default rollout restart deployment/ocelot-maintenance + # kubectl -n default set image deployment/ocelot-neo4j container-ocelot-neo4j=ocelotsocialnetwork/neo4j-community:latest + # kubectl -n default rollout restart deployment/ocelot-neo4j - name: Deploy actual version '$BUILD_VERSION' to DigitalOcean Kubernetes run: | - kubectl set image deployment/ocelot-webapp container-ocelot-webapp=ocelotsocialnetwork/webapp:$BUILD_VERSION - kubectl set image deployment/ocelot-backend container-ocelot-backend=ocelotsocialnetwork/backend:$BUILD_VERSION - kubectl set image deployment/ocelot-maintenance container-ocelot-maintenance=ocelotsocialnetwork/maintenance:$BUILD_VERSION - kubectl set image deployment/ocelot-neo4j container-ocelot-neo4j=ocelotsocialnetwork/neo4j-community:$BUILD_VERSION - # - name: Verify deployment - # run: | - # kubectl rollout status deployment/ocelot-webapp - # kubectl rollout status deployment/ocelot-backend - # kubectl rollout status deployment/ocelot-backend - # kubectl rollout status deployment/ocelot-neo4j + kubectl -n default set image deployment/ocelot-webapp container-ocelot-webapp=ocelotsocialnetwork/webapp:$BUILD_VERSION + kubectl -n default rollout restart deployment/ocelot-webapp + kubectl -n default set image deployment/ocelot-backend container-ocelot-backend=ocelotsocialnetwork/backend:$BUILD_VERSION + kubectl -n default rollout restart deployment/ocelot-backend + kubectl -n default set image deployment/ocelot-maintenance container-ocelot-maintenance=ocelotsocialnetwork/maintenance:$BUILD_VERSION + kubectl -n default rollout restart deployment/ocelot-maintenance + kubectl -n default set image deployment/ocelot-neo4j container-ocelot-neo4j=ocelotsocialnetwork/neo4j-community:$BUILD_VERSION + kubectl -n default rollout restart deployment/ocelot-neo4j + - name: Verify deployment + run: | + kubectl -n default rollout status deployment/ocelot-backend --timeout=240s + kubectl -n default rollout status deployment/ocelot-neo4j --timeout=240s + kubectl -n default rollout status deployment/ocelot-webapp --timeout=240s + kubectl -n default rollout status deployment/ocelot-maintenance --timeout=240s + - name: Reset and seed Neo4j database via backend for staging + # db cleaning is only possible if env 'PRODUCTION_DB_CLEAN_ALLOW=true' is set in deployment + run: | + kubectl -n default exec -it $(kubectl -n default get pods | grep ocelot-backend | awk '{ print $1 }') -- /bin/sh -c "node dist/db/clean.js" + kubectl -n default exec -it $(kubectl -n default get pods | grep ocelot-backend | awk '{ print $1 }') -- /bin/sh -c "node dist/db/seed.js" ############################################################################## # JOB: GITHUB TAG LATEST VERSION ############################################# From 7c78474cee3e5d55ba42c4c35a9a0b58aa78353e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 19 Jul 2022 18:51:50 +0200 Subject: [PATCH 026/588] Implement backend constant 'PRODUCTION_DB_CLEAN_ALLOW' to enable cleaning of database for staging, a start --- backend/src/db/clean.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/db/clean.js b/backend/src/db/clean.js index db8e8aad6..c55e31443 100644 --- a/backend/src/db/clean.js +++ b/backend/src/db/clean.js @@ -1,7 +1,7 @@ import { cleanDatabase } from '../db/factories' import CONFIG from '../config' -if (CONFIG.PRODUCTION) { +if (CONFIG.PRODUCTION && !CONFIG.PRODUCTION_DB_CLEAN_ALLOW) { throw new Error(`You cannot clean the database in production environment!`) } From 16812e0966084128e665f53bed281c9c0e562eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 20 Jul 2022 07:56:43 +0200 Subject: [PATCH 027/588] Disallow database seeding in non-staging and real production environments --- backend/src/db/seed.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/db/seed.js b/backend/src/db/seed.js index 7bfd4f159..92d49e98f 100644 --- a/backend/src/db/seed.js +++ b/backend/src/db/seed.js @@ -6,6 +6,10 @@ import Factory from '../db/factories' import { getNeode, getDriver } from '../db/neo4j' import { gql } from '../helpers/jest' +if (CONFIG.PRODUCTION && !CONFIG.PRODUCTION_DB_CLEAN_ALLOW) { + throw new Error(`You cannot seed the database in a non-staging and real production environment!`) +} + const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] /* eslint-disable no-multi-spaces */ From 089c4ee1bbbcc958e84d84d45b50367a3276a9c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 20 Jul 2022 07:57:45 +0200 Subject: [PATCH 028/588] Refine 'publish.yml' --- .github/workflows/publish.yml | 8 ++++---- backend/src/config/index.js | 2 ++ backend/src/db/clean.js | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2720236fe..d2c20e352 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -300,14 +300,14 @@ jobs: kubectl -n default rollout restart deployment/ocelot-maintenance kubectl -n default set image deployment/ocelot-neo4j container-ocelot-neo4j=ocelotsocialnetwork/neo4j-community:$BUILD_VERSION kubectl -n default rollout restart deployment/ocelot-neo4j - - name: Verify deployment + - name: Verify deployment and wait for the pods of each deplyment to get ready for cleaning and seeding of the database run: | - kubectl -n default rollout status deployment/ocelot-backend --timeout=240s - kubectl -n default rollout status deployment/ocelot-neo4j --timeout=240s kubectl -n default rollout status deployment/ocelot-webapp --timeout=240s kubectl -n default rollout status deployment/ocelot-maintenance --timeout=240s + kubectl -n default rollout status deployment/ocelot-backend --timeout=240s + kubectl -n default rollout status deployment/ocelot-neo4j --timeout=240s - name: Reset and seed Neo4j database via backend for staging - # db cleaning is only possible if env 'PRODUCTION_DB_CLEAN_ALLOW=true' is set in deployment + # db cleaning and seeding is only possible in production if env 'PRODUCTION_DB_CLEAN_ALLOW=true' is set in deployment run: | kubectl -n default exec -it $(kubectl -n default get pods | grep ocelot-backend | awk '{ print $1 }') -- /bin/sh -c "node dist/db/clean.js" kubectl -n default exec -it $(kubectl -n default get pods | grep ocelot-backend | awk '{ print $1 }') -- /bin/sh -c "node dist/db/seed.js" diff --git a/backend/src/config/index.js b/backend/src/config/index.js index d6d8cc166..6ad8c578b 100644 --- a/backend/src/config/index.js +++ b/backend/src/config/index.js @@ -22,6 +22,8 @@ const environment = { DEBUG: env.NODE_ENV !== 'production' && env.DEBUG, TEST: env.NODE_ENV === 'test', PRODUCTION: env.NODE_ENV === 'production', + // used for staging enviroments if 'PRODUCTION=true' and 'PRODUCTION_DB_CLEAN_ALLOW=true' + PRODUCTION_DB_CLEAN_ALLOW: env.PRODUCTION_DB_CLEAN_ALLOW === 'true' || false, // default = false DISABLED_MIDDLEWARES: (env.NODE_ENV !== 'production' && env.DISABLED_MIDDLEWARES) || false, } diff --git a/backend/src/db/clean.js b/backend/src/db/clean.js index c55e31443..db4e10bdf 100644 --- a/backend/src/db/clean.js +++ b/backend/src/db/clean.js @@ -2,7 +2,7 @@ import { cleanDatabase } from '../db/factories' import CONFIG from '../config' if (CONFIG.PRODUCTION && !CONFIG.PRODUCTION_DB_CLEAN_ALLOW) { - throw new Error(`You cannot clean the database in production environment!`) + throw new Error(`You cannot clean the database in a non-staging and real production environment!`) } ;(async function () { From 2afd0828eb04237e718b9916421e4eaacfb49bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 20 Jul 2022 08:58:23 +0200 Subject: [PATCH 029/588] Fix undefined 'CONFIG' in 'seed.js' --- backend/src/db/clean.js | 2 +- backend/src/db/seed.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/db/clean.js b/backend/src/db/clean.js index db4e10bdf..eac26036c 100644 --- a/backend/src/db/clean.js +++ b/backend/src/db/clean.js @@ -1,5 +1,5 @@ -import { cleanDatabase } from '../db/factories' import CONFIG from '../config' +import { cleanDatabase } from '../db/factories' if (CONFIG.PRODUCTION && !CONFIG.PRODUCTION_DB_CLEAN_ALLOW) { throw new Error(`You cannot clean the database in a non-staging and real production environment!`) diff --git a/backend/src/db/seed.js b/backend/src/db/seed.js index 92d49e98f..46c5870e0 100644 --- a/backend/src/db/seed.js +++ b/backend/src/db/seed.js @@ -1,5 +1,6 @@ import sample from 'lodash/sample' import { createTestClient } from 'apollo-server-testing' +import CONFIG from '../config' import createServer from '../server' import faker from '@faker-js/faker' import Factory from '../db/factories' From 884f7774605794ee92c67afdac143d518f5dfc26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 20 Jul 2022 09:26:11 +0200 Subject: [PATCH 030/588] Change order of deployments and the timeout to wait for in 'publish.yml' --- .github/workflows/publish.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d2c20e352..0c2a69f24 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -302,10 +302,10 @@ jobs: kubectl -n default rollout restart deployment/ocelot-neo4j - name: Verify deployment and wait for the pods of each deplyment to get ready for cleaning and seeding of the database run: | - kubectl -n default rollout status deployment/ocelot-webapp --timeout=240s - kubectl -n default rollout status deployment/ocelot-maintenance --timeout=240s - kubectl -n default rollout status deployment/ocelot-backend --timeout=240s - kubectl -n default rollout status deployment/ocelot-neo4j --timeout=240s + kubectl -n default rollout status deployment/ocelot-backend --timeout=400s + kubectl -n default rollout status deployment/ocelot-neo4j --timeout=400s + kubectl -n default rollout status deployment/ocelot-maintenance --timeout=400s + kubectl -n default rollout status deployment/ocelot-webapp --timeout=400s - name: Reset and seed Neo4j database via backend for staging # db cleaning and seeding is only possible in production if env 'PRODUCTION_DB_CLEAN_ALLOW=true' is set in deployment run: | From d39f53359a90fa443b57e25c7a543c0faccccd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 20 Jul 2022 09:57:02 +0200 Subject: [PATCH 031/588] Change timeout to wait for rollout status to '600s' in 'publish.yml' --- .github/workflows/publish.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0c2a69f24..3b4913d22 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -302,10 +302,10 @@ jobs: kubectl -n default rollout restart deployment/ocelot-neo4j - name: Verify deployment and wait for the pods of each deplyment to get ready for cleaning and seeding of the database run: | - kubectl -n default rollout status deployment/ocelot-backend --timeout=400s - kubectl -n default rollout status deployment/ocelot-neo4j --timeout=400s - kubectl -n default rollout status deployment/ocelot-maintenance --timeout=400s - kubectl -n default rollout status deployment/ocelot-webapp --timeout=400s + kubectl -n default rollout status deployment/ocelot-backend --timeout=600s + kubectl -n default rollout status deployment/ocelot-neo4j --timeout=600s + kubectl -n default rollout status deployment/ocelot-maintenance --timeout=600s + kubectl -n default rollout status deployment/ocelot-webapp --timeout=600s - name: Reset and seed Neo4j database via backend for staging # db cleaning and seeding is only possible in production if env 'PRODUCTION_DB_CLEAN_ALLOW=true' is set in deployment run: | From cb90ceeefc1f6584d9b9bce0ef4d183303097aa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 20 Jul 2022 10:29:24 +0200 Subject: [PATCH 032/588] Stop waiting for rollout of 'webapp' and 'maintenance' in 'publish.yml' --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3b4913d22..e4b8b8bb1 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -304,8 +304,8 @@ jobs: run: | kubectl -n default rollout status deployment/ocelot-backend --timeout=600s kubectl -n default rollout status deployment/ocelot-neo4j --timeout=600s - kubectl -n default rollout status deployment/ocelot-maintenance --timeout=600s - kubectl -n default rollout status deployment/ocelot-webapp --timeout=600s + # kubectl -n default rollout status deployment/ocelot-maintenance --timeout=600s + # kubectl -n default rollout status deployment/ocelot-webapp --timeout=600s - name: Reset and seed Neo4j database via backend for staging # db cleaning and seeding is only possible in production if env 'PRODUCTION_DB_CLEAN_ALLOW=true' is set in deployment run: | From e2089f36b5da278bbf31db438e58e6aebf92407b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 20 Jul 2022 12:43:58 +0200 Subject: [PATCH 033/588] Accumulate Neo4j db 'clean.js' and 'seed.js' and make the node calls await with flag '--experimental-repl-await' in 'publish.yml' --- .github/workflows/publish.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e4b8b8bb1..5d31987d4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -309,8 +309,7 @@ jobs: - name: Reset and seed Neo4j database via backend for staging # db cleaning and seeding is only possible in production if env 'PRODUCTION_DB_CLEAN_ALLOW=true' is set in deployment run: | - kubectl -n default exec -it $(kubectl -n default get pods | grep ocelot-backend | awk '{ print $1 }') -- /bin/sh -c "node dist/db/clean.js" - kubectl -n default exec -it $(kubectl -n default get pods | grep ocelot-backend | awk '{ print $1 }') -- /bin/sh -c "node dist/db/seed.js" + kubectl -n default exec -it $(kubectl -n default get pods | grep ocelot-backend | awk '{ print $1 }') -- /bin/sh -c "node --experimental-repl-await dist/db/clean.js && node --experimental-repl-await dist/db/seed.js" ############################################################################## # JOB: GITHUB TAG LATEST VERSION ############################################# From 6c6435266221a9ca4de63112c5549c73fcb54ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 20 Jul 2022 13:53:09 +0200 Subject: [PATCH 034/588] change back to publish just on master branch push --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5d31987d4..ff149b6bc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,7 +4,7 @@ on: push: branches: - master - - 5065-automatic-deployment-to-stage.ocelot.social-on-push-to-master-branch # for testing while developing + # - 5065-automatic-deployment-to-stage.ocelot.social-on-push-to-master-branch # for testing while developing jobs: ############################################################################## From 6247734a326a0f1634abf6e6c99d1d2f89c65184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 20 Jul 2022 14:42:38 +0200 Subject: [PATCH 035/588] Release v1.0.9 --- CHANGELOG.md | 16 ++++++++++++++++ backend/package.json | 2 +- package.json | 2 +- webapp/maintenance/source/package.json | 2 +- webapp/package.json | 2 +- 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6efb54686..8f8aa04ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,24 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.0.9](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/1.0.8...1.0.9) + +- chore: 🍰 Automatic Deployment To `stage.ocelot.social` On Push To `master` Branch [`#5080`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5080) +- change footer version-link [`#5091`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5091) +- docs: 🍰 Add Neo4j Docu For Important Commands [`#5090`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5090) +- 5079 legends for search field [`#5088`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5088) +- chore: 🍰 Change `image` Entries In Docker Compose Files And Fix Apple M1 Problem [`#5073`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5073) +- chore: 🍰 Rename Neo4j Docker Image In General To `neo4j-community:*` [`#5078`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5078) +- chore: 🍰 Fix `ocelotsocialnetwork/webapp:latest` And `ocelotsocialnetwork/backend:latest` On Start In Cluster [`#5076`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5076) +- Add documentation for Apple M1 Docker Compose override files [`2f3f37c`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/2f3f37c158cfc9b300540d3c8f016548b15a5277) +- Add documentation for Docker build analyzes [`fbbcc5b`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/fbbcc5bb854d53b5fa658b83d56d381a3cbc2b1a) +- Implement DigitalOcean Kubernetes deployment on publishing [`485e698`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/485e6986b88a14db5ab75ed12bab5cdc73592ca6) + #### [1.0.8](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/1.0.7...1.0.8) +> 1 July 2022 + +- chore: 🍰 Release v1.0.8 [`#5058`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5058) - chore: 🍰 Log E-Mail If Not Sending It [`#5038`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5038) - test: 🍰 Test And Refactor E-Mail Templates [`#4787`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4787) - fix: 🍰 Replace Hashtag In d.tube Url [`#4980`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4980) diff --git a/backend/package.json b/backend/package.json index c4aa8d98b..028b9295e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "ocelot-social-backend", - "version": "1.0.8", + "version": "1.0.9", "description": "GraphQL Backend for ocelot.social", "repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social", "author": "ocelot.social Community", diff --git a/package.json b/package.json index a914a4096..e23a5f5c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ocelot-social", - "version": "1.0.8", + "version": "1.0.9", "description": "Free and open source software program code available to run social networks.", "author": "ocelot.social Community", "license": "MIT", diff --git a/webapp/maintenance/source/package.json b/webapp/maintenance/source/package.json index e7bdf8e66..3ee1a5b5c 100644 --- a/webapp/maintenance/source/package.json +++ b/webapp/maintenance/source/package.json @@ -1,6 +1,6 @@ { "name": "@ocelot-social/maintenance", - "version": "1.0.8", + "version": "1.0.9", "description": "Maintenance page for ocelot.social", "repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social", "author": "ocelot.social Community", diff --git a/webapp/package.json b/webapp/package.json index d713a1f1e..77455f49f 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -1,6 +1,6 @@ { "name": "ocelot-social-webapp", - "version": "1.0.8", + "version": "1.0.9", "description": "ocelot.social Frontend", "repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social", "author": "ocelot.social Community", From 9d6a5d7700a45f3305c5d4870d1c55ab15893d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 21 Jul 2022 16:56:20 +0200 Subject: [PATCH 036/588] Change temporarily push branch to this one as well in 'publish.yml' --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ff149b6bc..93b960dfe 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,7 +4,7 @@ on: push: branches: - master - # - 5065-automatic-deployment-to-stage.ocelot.social-on-push-to-master-branch # for testing while developing + - 5093-fix-automatic-deployment # for testing while developing jobs: ############################################################################## From 861de8edcbee23ec451997b17b8aa7101236ced2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 21 Jul 2022 17:15:58 +0200 Subject: [PATCH 037/588] Add sleep for 4 minutes (240s) in 'publish.yml' --- .github/workflows/publish.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 93b960dfe..1228f738a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -300,12 +300,18 @@ jobs: kubectl -n default rollout restart deployment/ocelot-maintenance kubectl -n default set image deployment/ocelot-neo4j container-ocelot-neo4j=ocelotsocialnetwork/neo4j-community:$BUILD_VERSION kubectl -n default rollout restart deployment/ocelot-neo4j + # because this step 'kubectl -n default rollout status deployment/* --timeout=600s' does not work as expected + # and we need the pods to be up again for cleaning and seeding the Neo4j database and the backend. + # !!! this is not a perfect solution !!! + - name: Sleep for 4 minutes, means 240 seconds + run: sleep 240s + shell: bash - name: Verify deployment and wait for the pods of each deplyment to get ready for cleaning and seeding of the database run: | kubectl -n default rollout status deployment/ocelot-backend --timeout=600s kubectl -n default rollout status deployment/ocelot-neo4j --timeout=600s - # kubectl -n default rollout status deployment/ocelot-maintenance --timeout=600s - # kubectl -n default rollout status deployment/ocelot-webapp --timeout=600s + kubectl -n default rollout status deployment/ocelot-maintenance --timeout=600s + kubectl -n default rollout status deployment/ocelot-webapp --timeout=600s - name: Reset and seed Neo4j database via backend for staging # db cleaning and seeding is only possible in production if env 'PRODUCTION_DB_CLEAN_ALLOW=true' is set in deployment run: | From 6bc4663d24eeb5ca929400150ec853900238107f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 21 Jul 2022 17:46:20 +0200 Subject: [PATCH 038/588] Add a comment that deployment need to come up again regulerly 3m 10s 'publish.yml' --- .github/workflows/publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1228f738a..e628f0d9c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -303,6 +303,7 @@ jobs: # because this step 'kubectl -n default rollout status deployment/* --timeout=600s' does not work as expected # and we need the pods to be up again for cleaning and seeding the Neo4j database and the backend. # !!! this is not a perfect solution !!! + # deployments are regularely up again after 3 minutes and 10 seconds - name: Sleep for 4 minutes, means 240 seconds run: sleep 240s shell: bash From e93b7bdcf3a092b22857165112e3766e29ef04fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 21 Jul 2022 17:46:51 +0200 Subject: [PATCH 039/588] Remove temporarily push branch to this one as well in 'publish.yml' --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e628f0d9c..ac333604e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,7 +4,7 @@ on: push: branches: - master - - 5093-fix-automatic-deployment # for testing while developing + # - 5093-fix-automatic-deployment # for testing while developing jobs: ############################################################################## From 2ac3a9f9e30f59fe9d040640b9bef36f91b4d1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 25 Jul 2022 18:07:14 +0200 Subject: [PATCH 040/588] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 6 ++++-- .github/ISSUE_TEMPLATE/devops_ticket.md | 6 ++++-- .github/ISSUE_TEMPLATE/epic.md | 7 +++++-- .github/ISSUE_TEMPLATE/feature_request.md | 6 ++++-- .github/ISSUE_TEMPLATE/question.md | 7 +++++-- .github/ISSUE_TEMPLATE/refactor_tickets.md | 7 ++++--- 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 595c9d584..1fe27f6c6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,8 +1,10 @@ --- -name: 🐛 Bug Report +name: "\U0001F41B Bug Report" about: Create a report to help us to improve. +title: "\U0001F41B [Bug] XXX" labels: bug -title: 🐛 [Bug] +assignees: '' + --- ## :bug: Bug Report diff --git a/.github/ISSUE_TEMPLATE/devops_ticket.md b/.github/ISSUE_TEMPLATE/devops_ticket.md index 115664911..17533cd54 100644 --- a/.github/ISSUE_TEMPLATE/devops_ticket.md +++ b/.github/ISSUE_TEMPLATE/devops_ticket.md @@ -1,8 +1,10 @@ --- -name: 💥 DevOps Ticket +name: "\U0001F4A5 DevOps Ticket" about: Help us manage our deployed app. +title: "\U0001F4A5 [DevOps] XXX" labels: devops -title: 💥 [DevOps] +assignees: '' + --- ## 💥 DevOps Ticket diff --git a/.github/ISSUE_TEMPLATE/epic.md b/.github/ISSUE_TEMPLATE/epic.md index cf72cd673..57eca6dfe 100644 --- a/.github/ISSUE_TEMPLATE/epic.md +++ b/.github/ISSUE_TEMPLATE/epic.md @@ -1,9 +1,12 @@ --- -name: 🌟 Epic +name: "\U0001F31F Epic" about: Define a big development step. +title: "\U0001F31F [EPIC] XXX" labels: epic -title: 🌟 [EPIC] +assignees: '' + --- + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index beae80901..22cd5045e 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,8 +1,10 @@ --- -name: 🚀 Feature Request +name: "\U0001F680 Feature Request" about: Suggest an idea for this project. +title: "\U0001F680 [Feature] XXX" labels: feature -title: 🚀 [Feature] +assignees: '' + --- ## :rocket: Feature Request diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 40e6e381b..f2328dcc7 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,9 +1,12 @@ --- -name: 💬 Question +name: "\U0001F4AC Question" about: If you need help understanding ocelot.social. +title: "\U0001F4AC [Question] XXX" labels: question -title: 💬 [Question] +assignees: '' + --- + diff --git a/.github/ISSUE_TEMPLATE/refactor_tickets.md b/.github/ISSUE_TEMPLATE/refactor_tickets.md index d1841e35e..867c809ae 100644 --- a/.github/ISSUE_TEMPLATE/refactor_tickets.md +++ b/.github/ISSUE_TEMPLATE/refactor_tickets.md @@ -1,10 +1,11 @@ --- -name: 🔧 Refactor +name: "\U0001F527 Refactor" about: Help us improve our code by refactoring it. +title: "\U0001F527 [Refactor] XXX" labels: refactor -title: 🔧 [Refactor] +assignees: '' + --- ## 🔧 Refactor - From e31f250ea5e1949f4f08e72fe82622d41ecd85f1 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Jul 2022 18:41:39 +0200 Subject: [PATCH 041/588] env vatiable for CATEGORIES_ACTIVE and switch for categories in contribution form --- webapp/.env.template | 1 + .../ContributionForm/ContributionForm.vue | 32 +++++++++++++++++-- webapp/config/index.js | 1 + 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/webapp/.env.template b/webapp/.env.template index 7373255a9..0a4c3405f 100644 --- a/webapp/.env.template +++ b/webapp/.env.template @@ -4,3 +4,4 @@ PUBLIC_REGISTRATION=false INVITE_REGISTRATION=true WEBSOCKETS_URI=ws://localhost:3000/api/graphql GRAPHQL_URI=http://localhost:4000/ +CATEGORIES_ACTIVE=false \ No newline at end of file diff --git a/webapp/components/ContributionForm/ContributionForm.vue b/webapp/components/ContributionForm/ContributionForm.vue index a06679149..e25dd6b0f 100644 --- a/webapp/components/ContributionForm/ContributionForm.vue +++ b/webapp/components/ContributionForm/ContributionForm.vue @@ -51,6 +51,19 @@ {{ contentLength }} + + + {{ formData.categoryIds.length }} / 3 + +
{{ $t('actions.cancel') }} @@ -69,6 +82,7 @@ import gql from 'graphql-tag' import { mapGetters } from 'vuex' import HcEditor from '~/components/Editor/Editor' import PostMutations from '~/graphql/PostMutations.js' +import CategoriesSelect from '~/components/CategoriesSelect/CategoriesSelect' import ImageUploader from '~/components/ImageUploader/ImageUploader' import links from '~/constants/links.js' import PageParamsLink from '~/components/_new/features/PageParamsLink/PageParamsLink.vue' @@ -78,6 +92,7 @@ export default { HcEditor, ImageUploader, PageParamsLink, + CategoriesSelect, }, props: { contribution: { @@ -86,7 +101,7 @@ export default { }, }, data() { - const { title, content, image } = this.contribution + const { title, content, image, categories } = this.contribution const { sensitive: imageBlurred = false, aspectRatio: imageAspectRatio = null, @@ -94,6 +109,7 @@ export default { } = image || {} return { + categoriesActive: this.$env.CATEGORIES_ACTIVE, links, formData: { title: title || '', @@ -102,11 +118,22 @@ export default { imageAspectRatio, imageType, imageBlurred, + categoryIds: categories ? categories.map((category) => category.id) : [], }, formSchema: { title: { required: true, min: 3, max: 100 }, content: { required: true }, imageBlurred: { required: false }, + categoryIds: { + type: 'array', + required: true, + validator: (_, value = []) => { + if (value.length === 0 || value.length > 3) { + return [new Error(this.$t('common.validations.categories'))] + } + return [] + }, + }, }, loading: false, users: [], @@ -125,7 +152,7 @@ export default { methods: { submit() { let image = null - const { title, content } = this.formData + const { title, content, categoryIds } = this.formData if (this.formData.image) { image = { sensitive: this.formData.imageBlurred, @@ -143,6 +170,7 @@ export default { variables: { title, content, + categoryIds, id: this.contribution.id || null, image, }, diff --git a/webapp/config/index.js b/webapp/config/index.js index 00df85bac..db030e929 100644 --- a/webapp/config/index.js +++ b/webapp/config/index.js @@ -33,6 +33,7 @@ const options = { // Cookies COOKIE_EXPIRE_TIME: process.env.COOKIE_EXPIRE_TIME || 730, // Two years by default COOKIE_HTTPS_ONLY: process.env.COOKIE_HTTPS_ONLY || process.env.NODE_ENV === 'production', // ensure true in production if not set explicitly + CATEGORIES_ACTIVE: process.env.CATEGORIES_ACTIVE === 'true' || false, } const CONFIG = { From 28ddfde0e31d424ef0f48766e7d705bc525f0f28 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Jul 2022 19:02:08 +0200 Subject: [PATCH 042/588] add categories active to .env, save categories on create --- backend/.env.template | 2 ++ backend/src/config/index.js | 1 + backend/src/schema/resolvers/posts.js | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/backend/.env.template b/backend/.env.template index 5858a5d1e..239046dd3 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -28,3 +28,5 @@ AWS_BUCKET= EMAIL_DEFAULT_SENDER="devops@ocelot.social" EMAIL_SUPPORT="devops@ocelot.social" + +CATEGORIES_ACTIVE=false \ No newline at end of file diff --git a/backend/src/config/index.js b/backend/src/config/index.js index 6ad8c578b..7df780cfc 100644 --- a/backend/src/config/index.js +++ b/backend/src/config/index.js @@ -86,6 +86,7 @@ const options = { ORGANIZATION_URL: emails.ORGANIZATION_LINK, PUBLIC_REGISTRATION: env.PUBLIC_REGISTRATION === 'true' || false, INVITE_REGISTRATION: env.INVITE_REGISTRATION !== 'false', // default = true + CATEGORIES_ACTIVE: process.env.CATEGORIES_ACTIVE === 'true' || false, } // Check if all required configs are present diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index d199b6f09..f4faaeb17 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -5,6 +5,7 @@ import { UserInputError } from 'apollo-server' import { mergeImage, deleteImage } from './images/images' import Resolver from './helpers/Resolver' import { filterForMutedUsers } from './helpers/filterForMutedUsers' +import CONFIG from '../../config' const maintainPinnedPosts = (params) => { const pinnedPostFilter = { pinned: true } @@ -76,12 +77,20 @@ export default { }, Mutation: { CreatePost: async (_parent, params, context, _resolveInfo) => { + const { categoryIds } = params const { image: imageInput } = params delete params.categoryIds delete params.image params.id = params.id || uuid() const session = context.driver.session() const writeTxResultPromise = session.writeTransaction(async (transaction) => { + const categoriesCypher = + CONFIG.CATEGORIES_ACTIVE && categoryIds + ? `WITH post + UNWIND $categoryIds AS categoryId + MATCH (category:Category {id: categoryId}) + MERGE (post)-[:CATEGORIZED]->(category)` + : '' const createPostTransactionResponse = await transaction.run( ` CREATE (post:Post) @@ -91,11 +100,13 @@ export default { SET post.clickedCount = 0 SET post.viewedTeaserCount = 0 WITH post + UNWIND $categoryIds AS categoryId MATCH (author:User {id: $userId}) MERGE (post)<-[:WROTE]-(author) + ${categoriesCypher} RETURN post {.*} `, - { userId: context.user.id, params }, + { userId: context.user.id, params, categoryIds }, ) const [post] = createPostTransactionResponse.records.map((record) => record.get('post')) if (imageInput) { @@ -127,7 +138,7 @@ export default { WITH post ` - if (categoryIds && categoryIds.length) { + if (CONFIG.CATEGORIES_ACTIVE && categoryIds && categoryIds.length) { const cypherDeletePreviousRelations = ` MATCH (post:Post { id: $params.id })-[previousRelations:CATEGORIZED]->(category:Category) DELETE previousRelations From 1b2509229c7f6aa0c37338584d592f44c17f7c3d Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Jul 2022 19:22:17 +0200 Subject: [PATCH 043/588] remove bad line in cypher --- backend/src/schema/resolvers/posts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index f4faaeb17..b09bb3edd 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -100,7 +100,6 @@ export default { SET post.clickedCount = 0 SET post.viewedTeaserCount = 0 WITH post - UNWIND $categoryIds AS categoryId MATCH (author:User {id: $userId}) MERGE (post)<-[:WROTE]-(author) ${categoriesCypher} From bc955003f7c33aabe592bee782aca973b4f00cba Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Jul 2022 20:03:00 +0200 Subject: [PATCH 044/588] add optional categories to teaser and post --- webapp/components/PostTeaser/PostTeaser.vue | 21 +++++++++++++++++- webapp/graphql/Fragments.js | 6 ++++++ webapp/pages/post/_id/_slug/index.vue | 24 +++++++++++++++++---- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/webapp/components/PostTeaser/PostTeaser.vue b/webapp/components/PostTeaser/PostTeaser.vue index 949c7032e..a973ca31f 100644 --- a/webapp/components/PostTeaser/PostTeaser.vue +++ b/webapp/components/PostTeaser/PostTeaser.vue @@ -26,7 +26,19 @@ class="footer" v-observe-visibility="(isVisible, entry) => visibilityChanged(isVisible, entry, post.id)" > -
+
+ +
+
{}, }, }, + data() { + return { + categoriesActive: this.$env.CATEGORIES_ACTIVE, + } + }, mounted() { const { image } = this.post if (!image) return diff --git a/webapp/graphql/Fragments.js b/webapp/graphql/Fragments.js index 7b05e2369..b67851873 100644 --- a/webapp/graphql/Fragments.js +++ b/webapp/graphql/Fragments.js @@ -78,6 +78,12 @@ export const tagsCategoriesAndPinnedFragment = gql` tags { id } + categories { + id + slug + name + icon + } pinnedBy { id name diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index b1ca870d7..d02a448da 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -44,6 +44,19 @@

{{ post.title }}

+ +
+ + + + +
+
@@ -91,6 +104,7 @@ + + diff --git a/webapp/components/GroupTeaser/GroupTeaser.vue b/webapp/components/GroupTeaser/GroupTeaser.vue new file mode 100644 index 000000000..e9b3ba670 --- /dev/null +++ b/webapp/components/GroupTeaser/GroupTeaser.vue @@ -0,0 +1,24 @@ + diff --git a/webapp/locales/de.json b/webapp/locales/de.json index 297daa511..162897883 100644 --- a/webapp/locales/de.json +++ b/webapp/locales/de.json @@ -366,6 +366,9 @@ "follow": "Folgen", "following": "Folge Ich" }, + "group": { + "newGroup":"Erstelle eine neue Gruppe" + }, "hashtags-filter": { "clearSearch": "Suche löschen", "hashtag-search": "Suche nach #{hashtag}", diff --git a/webapp/locales/en.json b/webapp/locales/en.json index 8499b0290..4043eefd8 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -366,6 +366,9 @@ "follow": "Follow", "following": "Following" }, + "group": { + "newGroup":"Create a new Group" + }, "hashtags-filter": { "clearSearch": "Clear search", "hashtag-search": "Searching for #{hashtag}", diff --git a/webapp/pages/group/create.vue b/webapp/pages/group/create.vue new file mode 100644 index 000000000..6b52167f2 --- /dev/null +++ b/webapp/pages/group/create.vue @@ -0,0 +1,18 @@ + + + diff --git a/webapp/pages/my-groups.vue b/webapp/pages/my-groups.vue new file mode 100644 index 000000000..386bb1e51 --- /dev/null +++ b/webapp/pages/my-groups.vue @@ -0,0 +1,16 @@ + + From 45558f06dd4ef948ff785aa0a065677eac5f7829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 3 Aug 2022 11:49:46 +0200 Subject: [PATCH 059/588] Add comment about faking the 'gql' tag in the backend --- backend/src/helpers/jest.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/helpers/jest.js b/backend/src/helpers/jest.js index 201d68c14..14317642b 100644 --- a/backend/src/helpers/jest.js +++ b/backend/src/helpers/jest.js @@ -1,3 +1,6 @@ +// TODO: can be replaced with, which is no a fake: +// import gql from 'graphql-tag' + //* This is a fake ES2015 template string, just to benefit of syntax // highlighting of `gql` template strings in certain editors. export function gql(strings) { From 520598c89770044534a1c64f67be593a76b3b861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 3 Aug 2022 11:50:56 +0200 Subject: [PATCH 060/588] Implement 'description', 'groupType', and 'actionRadius' in 'CreateGroup' --- backend/src/db/graphql/mutations.ts | 9 ++++ .../src/middleware/slugifyMiddleware.spec.js | 8 +++ backend/src/models/Group.js | 54 +++++++++++-------- backend/src/schema/resolvers/groups.spec.js | 4 +- backend/src/schema/types/type/Group.gql | 23 ++++---- 5 files changed, 64 insertions(+), 34 deletions(-) diff --git a/backend/src/db/graphql/mutations.ts b/backend/src/db/graphql/mutations.ts index 5fc554ee2..c49856f2a 100644 --- a/backend/src/db/graphql/mutations.ts +++ b/backend/src/db/graphql/mutations.ts @@ -6,6 +6,9 @@ export const createGroupMutation = gql` $name: String!, $slug: String, $about: String, + $description: String!, + $groupType: GroupType!, + $actionRadius: GroupActionRadius!, $categoryIds: [ID] ) { CreateGroup( @@ -13,12 +16,18 @@ export const createGroupMutation = gql` name: $name slug: $slug about: $about + description: $description + groupType: $groupType + actionRadius: $actionRadius categoryIds: $categoryIds ) { id name slug about + description + groupType + actionRadius disabled deleted owner { diff --git a/backend/src/middleware/slugifyMiddleware.spec.js b/backend/src/middleware/slugifyMiddleware.spec.js index 44701970d..af6ff25b0 100644 --- a/backend/src/middleware/slugifyMiddleware.spec.js +++ b/backend/src/middleware/slugifyMiddleware.spec.js @@ -69,6 +69,9 @@ describe('slugifyMiddleware', () => { ...variables, name: 'The Best Group', about: 'Some about', + description: 'Some description', + groupType: 'closed', + actionRadius: 'national', categoryIds, } }) @@ -83,7 +86,12 @@ describe('slugifyMiddleware', () => { ).resolves.toMatchObject({ data: { CreateGroup: { + name: 'The Best Group', slug: 'the-best-group', + about: 'Some about', + description: 'Some description', + groupType: 'closed', + actionRadius: 'national', }, }, }) diff --git a/backend/src/models/Group.js b/backend/src/models/Group.js index 651c2983e..53b02fbec 100644 --- a/backend/src/models/Group.js +++ b/backend/src/models/Group.js @@ -4,19 +4,44 @@ export default { id: { type: 'string', primary: true, default: uuid }, // TODO: should be type: 'uuid' but simplified for our tests name: { type: 'string', disallow: [null], min: 3 }, slug: { type: 'string', unique: 'true', regex: /^[a-z0-9_-]+$/, lowercase: true }, + + createdAt: { + type: 'string', + isoDate: true, + required: true, + default: () => new Date().toISOString(), + }, + updatedAt: { + type: 'string', + isoDate: true, + required: true, + default: () => new Date().toISOString(), + }, + deleted: { type: 'boolean', default: false }, + disabled: { type: 'boolean', default: false }, + avatar: { type: 'relationship', relationship: 'AVATAR_IMAGE', target: 'Image', direction: 'out', }, - deleted: { type: 'boolean', default: false }, - disabled: { type: 'boolean', default: false }, - wasSeeded: 'boolean', // Wolle: used or needed? - locationName: { type: 'string', allow: [null] }, - about: { type: 'string', allow: [null, ''] }, // Wolle: null? - description: { type: 'string', allow: [null, ''] }, // Wolle: null? HTML with Tiptap, similar to post content, wie bei Posts "content: { type: 'string', disallow: [null], min: 3 },"? + + about: { type: 'string', allow: [null, ''] }, + description: { type: 'string', disallow: [null], min: 100 }, descriptionExcerpt: { type: 'string', allow: [null] }, + groupType: { type: 'string', default: 'public' }, + actionRadius: { type: 'string', default: 'regional' }, + + locationName: { type: 'string', allow: [null] }, + + wasSeeded: 'boolean', // Wolle: used or needed? + owner: { + type: 'relationship', + relationship: 'OWNS', + target: 'User', + direction: 'in', + }, // Wolle: followedBy: { // type: 'relationship', // relationship: 'FOLLOWS', @@ -26,26 +51,9 @@ export default { // createdAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() }, // }, // }, - owner: { - type: 'relationship', - relationship: 'OWNS', - target: 'User', - direction: 'in', - }, // Wolle: correct this way? // members: { type: 'relationship', relationship: 'MEMBERS', target: 'User', direction: 'out' }, // Wolle: needed? lastActiveAt: { type: 'string', isoDate: true }, - createdAt: { - type: 'string', - isoDate: true, - default: () => new Date().toISOString(), - }, - updatedAt: { - type: 'string', - isoDate: true, - required: true, - default: () => new Date().toISOString(), - }, // Wolle: emoted: { // type: 'relationships', // relationship: 'EMOTED', diff --git a/backend/src/schema/resolvers/groups.spec.js b/backend/src/schema/resolvers/groups.spec.js index 8d8c7c3d8..4932c2c5e 100644 --- a/backend/src/schema/resolvers/groups.spec.js +++ b/backend/src/schema/resolvers/groups.spec.js @@ -252,6 +252,9 @@ describe('CreateGroup', () => { name: 'The Best Group', slug: 'the-group', about: 'We will change the world!', + description: 'Some description', + groupType: 'public', + actionRadius: 'regional', categoryIds, } }) @@ -272,7 +275,6 @@ describe('CreateGroup', () => { const expected = { data: { CreateGroup: { - // Wolle: id: 'g589', name: 'The Best Group', slug: 'the-group', about: 'We will change the world!', diff --git a/backend/src/schema/types/type/Group.gql b/backend/src/schema/types/type/Group.gql index 310df9dbc..ee71f3e1f 100644 --- a/backend/src/schema/types/type/Group.gql +++ b/backend/src/schema/types/type/Group.gql @@ -19,27 +19,28 @@ enum _GroupOrdering { type Group { id: ID! - name: String # title + name: String! # title slug: String! - createdAt: String - updatedAt: String + createdAt: String! + updatedAt: String! deleted: Boolean disabled: Boolean avatar: Image @relation(name: "AVATAR_IMAGE", direction: "OUT") + about: String # goal + description: String! + groupType: GroupType! + actionRadius: GroupActionRadius! + location: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l") locationName: String - about: String # goal - description: String - groupType: GroupType - actionRadius: GroupActionRadius categories: [Category] @relation(name: "CATEGORIZED", direction: "OUT") # Wolle: needed? - socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN") + # socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN") owner: User @relation(name: "OWNS", direction: "IN") @@ -213,10 +214,12 @@ type Mutation { name: String! slug: String avatar: ImageInput - locationName: String about: String - description: String + description: String! + groupType: GroupType! + actionRadius: GroupActionRadius! categoryIds: [ID] + locationName: String ): # Wolle: add group settings # Wolle: # showShoutsPublicly: Boolean From cc44ee8ebcf6157172d92d2267d1e4607e7df73b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 3 Aug 2022 13:12:50 +0200 Subject: [PATCH 061/588] Refactor relations ':OWNS' and ':ADMINISTERS' to ':MEMBER_OF' with properties --- backend/src/db/graphql/mutations.ts | 7 +- backend/src/models/Group.js | 14 +- backend/src/schema/resolvers/groups.js | 128 ++++++++---------- backend/src/schema/resolvers/groups.spec.js | 7 +- .../src/schema/types/enum/GroupMemberRole.gql | 6 + backend/src/schema/types/type/Group.gql | 15 +- backend/src/schema/types/type/MEMBER_OF.gql | 5 + 7 files changed, 94 insertions(+), 88 deletions(-) create mode 100644 backend/src/schema/types/enum/GroupMemberRole.gql create mode 100644 backend/src/schema/types/type/MEMBER_OF.gql diff --git a/backend/src/db/graphql/mutations.ts b/backend/src/db/graphql/mutations.ts index c49856f2a..4f07e0f1e 100644 --- a/backend/src/db/graphql/mutations.ts +++ b/backend/src/db/graphql/mutations.ts @@ -30,9 +30,10 @@ export const createGroupMutation = gql` actionRadius disabled deleted - owner { - name - } + myRole + # Wolle: owner { + # name + # } } } ` diff --git a/backend/src/models/Group.js b/backend/src/models/Group.js index 53b02fbec..0cec02bf8 100644 --- a/backend/src/models/Group.js +++ b/backend/src/models/Group.js @@ -33,15 +33,17 @@ export default { groupType: { type: 'string', default: 'public' }, actionRadius: { type: 'string', default: 'regional' }, + myRole: { type: 'string', default: 'pending' }, + locationName: { type: 'string', allow: [null] }, wasSeeded: 'boolean', // Wolle: used or needed? - owner: { - type: 'relationship', - relationship: 'OWNS', - target: 'User', - direction: 'in', - }, + // Wolle: owner: { + // type: 'relationship', + // relationship: 'OWNS', + // target: 'User', + // direction: 'in', + // }, // Wolle: followedBy: { // type: 'relationship', // relationship: 'FOLLOWS', diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js index 0ed5d1356..b202c6037 100644 --- a/backend/src/schema/resolvers/groups.js +++ b/backend/src/schema/resolvers/groups.js @@ -18,63 +18,47 @@ import Resolver from './helpers/Resolver' // } export default { - // Wolle: Query: { - // Post: async (object, params, context, resolveInfo) => { - // params = await filterForMutedUsers(params, context) - // params = await maintainPinnedPosts(params) - // return neo4jgraphql(object, params, context, resolveInfo) - // }, - // findPosts: async (object, params, context, resolveInfo) => { - // params = await filterForMutedUsers(params, context) - // return neo4jgraphql(object, params, context, resolveInfo) - // }, - // profilePagePosts: async (object, params, context, resolveInfo) => { - // params = await filterForMutedUsers(params, context) - // return neo4jgraphql(object, params, context, resolveInfo) - // }, - // PostsEmotionsCountByEmotion: async (object, params, context, resolveInfo) => { - // const { postId, data } = params - // const session = context.driver.session() - // const readTxResultPromise = session.readTransaction(async (transaction) => { - // const emotionsCountTransactionResponse = await transaction.run( - // ` - // MATCH (post:Post {id: $postId})<-[emoted:EMOTED {emotion: $data.emotion}]-() - // RETURN COUNT(DISTINCT emoted) as emotionsCount - // `, - // { postId, data }, - // ) - // return emotionsCountTransactionResponse.records.map( - // (record) => record.get('emotionsCount').low, - // ) - // }) - // try { - // const [emotionsCount] = await readTxResultPromise - // return emotionsCount - // } finally { - // session.close() - // } - // }, - // PostsEmotionsByCurrentUser: async (object, params, context, resolveInfo) => { - // const { postId } = params - // const session = context.driver.session() - // const readTxResultPromise = session.readTransaction(async (transaction) => { - // const emotionsTransactionResponse = await transaction.run( - // ` - // MATCH (user:User {id: $userId})-[emoted:EMOTED]->(post:Post {id: $postId}) - // RETURN collect(emoted.emotion) as emotion - // `, - // { userId: context.user.id, postId }, - // ) - // return emotionsTransactionResponse.records.map((record) => record.get('emotion')) - // }) - // try { - // const [emotions] = await readTxResultPromise - // return emotions - // } finally { - // session.close() - // } - // }, - // }, + Query: { + // Wolle: Post: async (object, params, context, resolveInfo) => { + // params = await filterForMutedUsers(params, context) + // // params = await maintainPinnedPosts(params) + // return neo4jgraphql(object, params, context, resolveInfo) + // }, + // Group: async (object, params, context, resolveInfo) => { + // // const { email } = params + // const session = context.driver.session() + // const readTxResultPromise = session.readTransaction(async (txc) => { + // const result = await txc.run( + // ` + // MATCH (user:User {id: $userId})-[:MEMBER_OF]->(group:Group) + // RETURN properties(group) AS inviteCodes + // `, + // { + // userId: context.user.id, + // }, + // ) + // return result.records.map((record) => record.get('inviteCodes')) + // }) + // if (email) { + // try { + // session = context.driver.session() + // const readTxResult = await session.readTransaction((txc) => { + // const result = txc.run( + // ` + // MATCH (user:User)-[:PRIMARY_EMAIL]->(e:EmailAddress {email: $args.email}) + // RETURN user`, + // { args }, + // ) + // return result + // }) + // return readTxResult.records.map((r) => r.get('user').properties) + // } finally { + // session.close() + // } + // } + // return neo4jgraphql(object, args, context, resolveInfo) + // }, + }, Mutation: { CreateGroup: async (_parent, params, context, _resolveInfo) => { const { categoryIds } = params @@ -84,12 +68,14 @@ export default { const writeTxResultPromise = session.writeTransaction(async (transaction) => { const categoriesCypher = CONFIG.CATEGORIES_ACTIVE && categoryIds - ? `WITH group - UNWIND $categoryIds AS categoryId - MATCH (category:Category {id: categoryId}) - MERGE (group)-[:CATEGORIZED]->(category)` + ? ` + WITH group, membership + UNWIND $categoryIds AS categoryId + MATCH (category:Category {id: categoryId}) + MERGE (group)-[:CATEGORIZED]->(category) + ` : '' - const ownercreateGroupTransactionResponse = await transaction.run( + const ownerCreateGroupTransactionResponse = await transaction.run( ` CREATE (group:Group) SET group += $params @@ -97,14 +83,16 @@ export default { SET group.updatedAt = toString(datetime()) WITH group MATCH (owner:User {id: $userId}) - MERGE (group)<-[:OWNS]-(owner) - MERGE (group)<-[:ADMINISTERS]-(owner) + MERGE (owner)-[membership:MEMBER_OF]->(group) + SET membership.createdAt = toString(datetime()) + SET membership.updatedAt = toString(datetime()) + SET membership.role = 'owner' ${categoriesCypher} - RETURN group {.*} + RETURN group {.*, myRole: membership.role} `, { userId: context.user.id, categoryIds, params }, ) - const [group] = ownercreateGroupTransactionResponse.records.map((record) => + const [group] = ownerCreateGroupTransactionResponse.records.map((record) => record.get('group'), ) return group @@ -205,10 +193,10 @@ export default { // Wolle: tags: '-[:TAGGED]->(related:Tag)', categories: '-[:CATEGORIZED]->(related:Category)', }, - hasOne: { - owner: '<-[:OWNS]-(related:User)', - // Wolle: image: '-[:HERO_IMAGE]->(related:Image)', - }, + // hasOne: { + // owner: '<-[:OWNS]-(related:User)', + // // Wolle: image: '-[:HERO_IMAGE]->(related:Image)', + // }, // Wolle: count: { // contributionsCount: // '-[:WROTE]->(related:Post) WHERE NOT related.disabled = true AND NOT related.deleted = true', diff --git a/backend/src/schema/resolvers/groups.spec.js b/backend/src/schema/resolvers/groups.spec.js index 4932c2c5e..17fc4b1da 100644 --- a/backend/src/schema/resolvers/groups.spec.js +++ b/backend/src/schema/resolvers/groups.spec.js @@ -292,9 +292,10 @@ describe('CreateGroup', () => { data: { CreateGroup: { name: 'The Best Group', - owner: { - name: 'TestUser', - }, + myRole: 'owner', + // Wolle: owner: { + // name: 'TestUser', + // }, }, }, errors: undefined, diff --git a/backend/src/schema/types/enum/GroupMemberRole.gql b/backend/src/schema/types/enum/GroupMemberRole.gql new file mode 100644 index 000000000..dacdd4b52 --- /dev/null +++ b/backend/src/schema/types/enum/GroupMemberRole.gql @@ -0,0 +1,6 @@ +enum GroupMemberRole { + pending + usual + admin + owner +} diff --git a/backend/src/schema/types/type/Group.gql b/backend/src/schema/types/type/Group.gql index ee71f3e1f..72ac9b57a 100644 --- a/backend/src/schema/types/type/Group.gql +++ b/backend/src/schema/types/type/Group.gql @@ -39,10 +39,12 @@ type Group { categories: [Category] @relation(name: "CATEGORIZED", direction: "OUT") + myRole: GroupMemberRole # if 'null' then the current user is no member + # Wolle: needed? # socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN") - owner: User @relation(name: "OWNS", direction: "IN") + # Wolle: owner: User @relation(name: "OWNS", direction: "IN") # Wolle: showShoutsPublicly: Boolean # Wolle: sendNotificationEmails: Boolean @@ -129,9 +131,12 @@ input _GroupFilter { AND: [_GroupFilter!] OR: [_GroupFilter!] name_contains: String + slug_contains: String about_contains: String description_contains: String - slug_contains: String + groupType_in: [GroupType!] + actionRadius_in: [GroupActionRadius!] + myRole_in: [GroupMemberRole!] id: ID id_not: ID id_in: [ID!] @@ -161,20 +166,18 @@ input _GroupFilter { # followedBy_none: _GroupFilter # followedBy_single: _GroupFilter # followedBy_every: _GroupFilter - # role_in: [UserRole!] } type Query { Group( id: ID - email: String # admins need to search for a user sometimes name: String slug: String + createdAt: String + updatedAt: String locationName: String about: String description: String - createdAt: String - updatedAt: String first: Int offset: Int orderBy: [_GroupOrdering] diff --git a/backend/src/schema/types/type/MEMBER_OF.gql b/backend/src/schema/types/type/MEMBER_OF.gql new file mode 100644 index 000000000..edda989f6 --- /dev/null +++ b/backend/src/schema/types/type/MEMBER_OF.gql @@ -0,0 +1,5 @@ +type MEMBER_OF { + createdAt: String! + updatedAt: String! + role: GroupMemberRole! +} From 94411648fd23feb74564f978c8e6988829de196f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 3 Aug 2022 13:29:49 +0200 Subject: [PATCH 062/588] Implement 'Group' query, first step --- .../src/middleware/permissionsMiddleware.js | 1 + backend/src/schema/resolvers/groups.js | 64 ++++++++----------- 2 files changed, 28 insertions(+), 37 deletions(-) diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 7e23cfe0f..99dcfc0cd 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -114,6 +114,7 @@ export default shield( reports: isModerator, statistics: allow, currentUser: allow, + Group: isAuthenticated, Post: allow, profilePagePosts: allow, Comment: allow, diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js index b202c6037..9a55c9f4d 100644 --- a/backend/src/schema/resolvers/groups.js +++ b/backend/src/schema/resolvers/groups.js @@ -24,40 +24,30 @@ export default { // // params = await maintainPinnedPosts(params) // return neo4jgraphql(object, params, context, resolveInfo) // }, - // Group: async (object, params, context, resolveInfo) => { - // // const { email } = params - // const session = context.driver.session() - // const readTxResultPromise = session.readTransaction(async (txc) => { - // const result = await txc.run( - // ` - // MATCH (user:User {id: $userId})-[:MEMBER_OF]->(group:Group) - // RETURN properties(group) AS inviteCodes - // `, - // { - // userId: context.user.id, - // }, - // ) - // return result.records.map((record) => record.get('inviteCodes')) - // }) - // if (email) { - // try { - // session = context.driver.session() - // const readTxResult = await session.readTransaction((txc) => { - // const result = txc.run( - // ` - // MATCH (user:User)-[:PRIMARY_EMAIL]->(e:EmailAddress {email: $args.email}) - // RETURN user`, - // { args }, - // ) - // return result - // }) - // return readTxResult.records.map((r) => r.get('user').properties) - // } finally { - // session.close() - // } - // } - // return neo4jgraphql(object, args, context, resolveInfo) - // }, + Group: async (_object, _params, context, _resolveInfo) => { + const session = context.driver.session() + const readTxResultPromise = session.readTransaction(async (txc) => { + const result = await txc.run( + ` + MATCH (user:User {id: $userId})-[membership:MEMBER_OF]->(group:Group) + RETURN group {.*, myRole: membership.role} + `, + { + userId: context.user.id, + }, + ) + const group = result.records.map((record) => record.get('group')) + return group + }) + try { + const group = await readTxResultPromise + return group + } catch (error) { + throw new Error(error) + } finally { + session.close() + } + }, }, Mutation: { CreateGroup: async (_parent, params, context, _resolveInfo) => { @@ -100,10 +90,10 @@ export default { try { const group = await writeTxResultPromise return group - } catch (e) { - if (e.code === 'Neo.ClientError.Schema.ConstraintValidationFailed') + } catch (error) { + if (error.code === 'Neo.ClientError.Schema.ConstraintValidationFailed') throw new UserInputError('Group with this slug already exists!') - throw new Error(e) + throw new Error(error) } finally { session.close() } From 867b78dfa3983f92978ff7ec5284830a6fc34d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 3 Aug 2022 15:16:23 +0200 Subject: [PATCH 063/588] Implement 'Group' query, second step --- backend/src/db/graphql/authentications.ts | 29 ++ backend/src/db/graphql/groups.ts | 95 +++++ backend/src/db/graphql/mutations.ts | 69 ---- backend/src/db/graphql/posts.ts | 15 + .../src/middleware/slugifyMiddleware.spec.js | 8 +- backend/src/schema/resolvers/groups.spec.js | 325 +++++++++--------- backend/src/schema/types/type/Group.gql | 2 +- 7 files changed, 302 insertions(+), 241 deletions(-) create mode 100644 backend/src/db/graphql/authentications.ts create mode 100644 backend/src/db/graphql/groups.ts delete mode 100644 backend/src/db/graphql/mutations.ts create mode 100644 backend/src/db/graphql/posts.ts diff --git a/backend/src/db/graphql/authentications.ts b/backend/src/db/graphql/authentications.ts new file mode 100644 index 000000000..f05970650 --- /dev/null +++ b/backend/src/db/graphql/authentications.ts @@ -0,0 +1,29 @@ +import gql from 'graphql-tag' + +// ------ mutations + +export const signupVerificationMutation = gql` + mutation ( + $password: String! + $email: String! + $name: String! + $slug: String + $nonce: String! + $termsAndConditionsAgreedVersion: String! + ) { + SignupVerification( + email: $email + password: $password + name: $name + slug: $slug + nonce: $nonce + termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion + ) { + slug + } + } +` + +// ------ queries + +// fill queries in here diff --git a/backend/src/db/graphql/groups.ts b/backend/src/db/graphql/groups.ts new file mode 100644 index 000000000..80b599658 --- /dev/null +++ b/backend/src/db/graphql/groups.ts @@ -0,0 +1,95 @@ +import gql from 'graphql-tag' + +// ------ mutations + +export const createGroupMutation = gql` + mutation ( + $id: ID, + $name: String!, + $slug: String, + $about: String, + $description: String!, + $groupType: GroupType!, + $actionRadius: GroupActionRadius!, + $categoryIds: [ID] + ) { + CreateGroup( + id: $id + name: $name + slug: $slug + about: $about + description: $description + groupType: $groupType + actionRadius: $actionRadius + categoryIds: $categoryIds + ) { + id + name + slug + createdAt + updatedAt + disabled + deleted + about + description + groupType + actionRadius + myRole + # Wolle: owner { + # name + # } + } + } +` + +// ------ queries + +export const groupQuery = gql` + query ( + $id: ID, + $name: String, + $slug: String, + $createdAt: String + $updatedAt: String + $about: String, + $description: String, + # $groupType: GroupType!, + # $actionRadius: GroupActionRadius!, + $categoryIds: [ID] + $locationName: String + $first: Int + $offset: Int + $orderBy: [_GroupOrdering] + $filter: _GroupFilter + ) { + Group( + id: $id + name: $name + slug: $slug + createdAt: $createdAt + updatedAt: $updatedAt + about: $about + description: $description + # groupType: $groupType + # actionRadius: $actionRadius + categoryIds: $categoryIds + locationName: $locationName + ) { + id + name + slug + createdAt + updatedAt + disabled + deleted + about + description + groupType + actionRadius + myRole + # Wolle: owner { + # name + # } + } + } +` diff --git a/backend/src/db/graphql/mutations.ts b/backend/src/db/graphql/mutations.ts deleted file mode 100644 index 4f07e0f1e..000000000 --- a/backend/src/db/graphql/mutations.ts +++ /dev/null @@ -1,69 +0,0 @@ -import gql from 'graphql-tag' - -export const createGroupMutation = gql` - mutation ( - $id: ID, - $name: String!, - $slug: String, - $about: String, - $description: String!, - $groupType: GroupType!, - $actionRadius: GroupActionRadius!, - $categoryIds: [ID] - ) { - CreateGroup( - id: $id - name: $name - slug: $slug - about: $about - description: $description - groupType: $groupType - actionRadius: $actionRadius - categoryIds: $categoryIds - ) { - id - name - slug - about - description - groupType - actionRadius - disabled - deleted - myRole - # Wolle: owner { - # name - # } - } - } -` - -export const createPostMutation = gql` - mutation ($title: String!, $content: String!, $categoryIds: [ID]!, $slug: String) { - CreatePost(title: $title, content: $content, categoryIds: $categoryIds, slug: $slug) { - slug - } - } -` - -export const signupVerificationMutation = gql` - mutation ( - $password: String! - $email: String! - $name: String! - $slug: String - $nonce: String! - $termsAndConditionsAgreedVersion: String! - ) { - SignupVerification( - email: $email - password: $password - name: $name - slug: $slug - nonce: $nonce - termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion - ) { - slug - } - } -` diff --git a/backend/src/db/graphql/posts.ts b/backend/src/db/graphql/posts.ts new file mode 100644 index 000000000..3277af820 --- /dev/null +++ b/backend/src/db/graphql/posts.ts @@ -0,0 +1,15 @@ +import gql from 'graphql-tag' + +// ------ mutations + +export const createPostMutation = gql` + mutation ($title: String!, $content: String!, $categoryIds: [ID]!, $slug: String) { + CreatePost(title: $title, content: $content, categoryIds: $categoryIds, slug: $slug) { + slug + } + } +` + +// ------ queries + +// fill queries in here diff --git a/backend/src/middleware/slugifyMiddleware.spec.js b/backend/src/middleware/slugifyMiddleware.spec.js index af6ff25b0..3c18e70b0 100644 --- a/backend/src/middleware/slugifyMiddleware.spec.js +++ b/backend/src/middleware/slugifyMiddleware.spec.js @@ -2,11 +2,9 @@ import { getNeode, getDriver } from '../db/neo4j' import createServer from '../server' import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '../db/factories' -import { - createPostMutation, - createGroupMutation, - signupVerificationMutation, -} from '../db/graphql/mutations' +import { createGroupMutation } from '../db/graphql/groups' +import { createPostMutation } from '../db/graphql/posts' +import { signupVerificationMutation } from '../db/graphql/authentications' let mutate let authenticatedUser diff --git a/backend/src/schema/resolvers/groups.spec.js b/backend/src/schema/resolvers/groups.spec.js index 17fc4b1da..8860f87f2 100644 --- a/backend/src/schema/resolvers/groups.spec.js +++ b/backend/src/schema/resolvers/groups.spec.js @@ -1,6 +1,6 @@ import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '../../db/factories' -import { createGroupMutation } from '../../db/graphql/mutations' +import { createGroupMutation } from '../../db/graphql/groups' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' @@ -78,171 +78,164 @@ afterEach(async () => { await cleanDatabase() }) -// describe('Group', () => { -// describe('can be filtered', () => { -// let followedUser, happyPost, cryPost -// beforeEach(async () => { -// ;[followedUser] = await Promise.all([ -// Factory.build( -// 'user', -// { -// id: 'followed-by-me', -// name: 'Followed User', -// }, -// { -// email: 'followed@example.org', -// password: '1234', -// }, -// ), -// ]) -// ;[happyPost, cryPost] = await Promise.all([ -// Factory.build('post', { id: 'happy-post' }, { categoryIds: ['cat4'] }), -// Factory.build('post', { id: 'cry-post' }, { categoryIds: ['cat15'] }), -// Factory.build( -// 'post', -// { -// id: 'post-by-followed-user', -// }, -// { -// categoryIds: ['cat9'], -// author: followedUser, -// }, -// ), -// ]) -// }) - -// describe('no filter', () => { -// it('returns all posts', async () => { -// const postQueryNoFilters = gql` -// query Post($filter: _PostFilter) { -// Post(filter: $filter) { -// id -// } -// } -// ` -// const expected = [{ id: 'happy-post' }, { id: 'cry-post' }, { id: 'post-by-followed-user' }] -// variables = { filter: {} } -// await expect(query({ query: postQueryNoFilters, variables })).resolves.toMatchObject({ -// data: { -// Post: expect.arrayContaining(expected), -// }, -// }) -// }) -// }) - -// /* it('by categories', async () => { -// const postQueryFilteredByCategories = gql` -// query Post($filter: _PostFilter) { -// Post(filter: $filter) { -// id -// categories { -// id -// } -// } -// } -// ` -// const expected = { -// data: { -// Post: [ -// { -// id: 'post-by-followed-user', -// categories: [{ id: 'cat9' }], -// }, -// ], -// }, -// } -// variables = { ...variables, filter: { categories_some: { id_in: ['cat9'] } } } -// await expect( -// query({ query: postQueryFilteredByCategories, variables }), -// ).resolves.toMatchObject(expected) -// }) */ - -// describe('by emotions', () => { -// const postQueryFilteredByEmotions = gql` -// query Post($filter: _PostFilter) { -// Post(filter: $filter) { -// id -// emotions { -// emotion -// } -// } -// } -// ` - -// it('filters by single emotion', async () => { -// const expected = { -// data: { -// Post: [ -// { -// id: 'happy-post', -// emotions: [{ emotion: 'happy' }], -// }, -// ], -// }, -// } -// await user.relateTo(happyPost, 'emoted', { emotion: 'happy' }) -// variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy'] } } } -// await expect( -// query({ query: postQueryFilteredByEmotions, variables }), -// ).resolves.toMatchObject(expected) -// }) - -// it('filters by multiple emotions', async () => { -// const expected = [ -// { -// id: 'happy-post', -// emotions: [{ emotion: 'happy' }], -// }, -// { -// id: 'cry-post', -// emotions: [{ emotion: 'cry' }], -// }, -// ] -// await user.relateTo(happyPost, 'emoted', { emotion: 'happy' }) -// await user.relateTo(cryPost, 'emoted', { emotion: 'cry' }) -// variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy', 'cry'] } } } -// await expect( -// query({ query: postQueryFilteredByEmotions, variables }), -// ).resolves.toMatchObject({ -// data: { -// Post: expect.arrayContaining(expected), -// }, -// errors: undefined, -// }) -// }) -// }) - -// it('by followed-by', async () => { -// const postQueryFilteredByUsersFollowed = gql` -// query Post($filter: _PostFilter) { -// Post(filter: $filter) { -// id -// author { -// id -// name -// } -// } -// } -// ` - -// await user.relateTo(followedUser, 'following') -// variables = { filter: { author: { followedBy_some: { id: 'current-user' } } } } -// await expect( -// query({ query: postQueryFilteredByUsersFollowed, variables }), -// ).resolves.toMatchObject({ -// data: { -// Post: [ -// { -// id: 'post-by-followed-user', -// author: { id: 'followed-by-me', name: 'Followed User' }, -// }, -// ], -// }, -// errors: undefined, -// }) -// }) -// }) -// }) +describe('Group', () => { + // describe('can be filtered', () => { + // let followedUser, happyPost, cryPost + // beforeEach(async () => { + // ;[followedUser] = await Promise.all([ + // Factory.build( + // 'user', + // { + // id: 'followed-by-me', + // name: 'Followed User', + // }, + // { + // email: 'followed@example.org', + // password: '1234', + // }, + // ), + // ]) + // ;[happyPost, cryPost] = await Promise.all([ + // Factory.build('post', { id: 'happy-post' }, { categoryIds: ['cat4'] }), + // Factory.build('post', { id: 'cry-post' }, { categoryIds: ['cat15'] }), + // Factory.build( + // 'post', + // { + // id: 'post-by-followed-user', + // }, + // { + // categoryIds: ['cat9'], + // author: followedUser, + // }, + // ), + // ]) + // }) + // describe('no filter', () => { + // it('returns all posts', async () => { + // const postQueryNoFilters = gql` + // query Post($filter: _PostFilter) { + // Post(filter: $filter) { + // id + // } + // } + // ` + // const expected = [{ id: 'happy-post' }, { id: 'cry-post' }, { id: 'post-by-followed-user' }] + // variables = { filter: {} } + // await expect(query({ query: postQueryNoFilters, variables })).resolves.toMatchObject({ + // data: { + // Post: expect.arrayContaining(expected), + // }, + // }) + // }) + // }) + // /* it('by categories', async () => { + // const postQueryFilteredByCategories = gql` + // query Post($filter: _PostFilter) { + // Post(filter: $filter) { + // id + // categories { + // id + // } + // } + // } + // ` + // const expected = { + // data: { + // Post: [ + // { + // id: 'post-by-followed-user', + // categories: [{ id: 'cat9' }], + // }, + // ], + // }, + // } + // variables = { ...variables, filter: { categories_some: { id_in: ['cat9'] } } } + // await expect( + // query({ query: postQueryFilteredByCategories, variables }), + // ).resolves.toMatchObject(expected) + // }) */ + // describe('by emotions', () => { + // const postQueryFilteredByEmotions = gql` + // query Post($filter: _PostFilter) { + // Post(filter: $filter) { + // id + // emotions { + // emotion + // } + // } + // } + // ` + // it('filters by single emotion', async () => { + // const expected = { + // data: { + // Post: [ + // { + // id: 'happy-post', + // emotions: [{ emotion: 'happy' }], + // }, + // ], + // }, + // } + // await user.relateTo(happyPost, 'emoted', { emotion: 'happy' }) + // variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy'] } } } + // await expect( + // query({ query: postQueryFilteredByEmotions, variables }), + // ).resolves.toMatchObject(expected) + // }) + // it('filters by multiple emotions', async () => { + // const expected = [ + // { + // id: 'happy-post', + // emotions: [{ emotion: 'happy' }], + // }, + // { + // id: 'cry-post', + // emotions: [{ emotion: 'cry' }], + // }, + // ] + // await user.relateTo(happyPost, 'emoted', { emotion: 'happy' }) + // await user.relateTo(cryPost, 'emoted', { emotion: 'cry' }) + // variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy', 'cry'] } } } + // await expect( + // query({ query: postQueryFilteredByEmotions, variables }), + // ).resolves.toMatchObject({ + // data: { + // Post: expect.arrayContaining(expected), + // }, + // errors: undefined, + // }) + // }) + // }) + // it('by followed-by', async () => { + // const postQueryFilteredByUsersFollowed = gql` + // query Post($filter: _PostFilter) { + // Post(filter: $filter) { + // id + // author { + // id + // name + // } + // } + // } + // ` + // await user.relateTo(followedUser, 'following') + // variables = { filter: { author: { followedBy_some: { id: 'current-user' } } } } + // await expect( + // query({ query: postQueryFilteredByUsersFollowed, variables }), + // ).resolves.toMatchObject({ + // data: { + // Post: [ + // { + // id: 'post-by-followed-user', + // author: { id: 'followed-by-me', name: 'Followed User' }, + // }, + // ], + // }, + // errors: undefined, + // }) + // }) + // }) +}) describe('CreateGroup', () => { beforeEach(() => { diff --git a/backend/src/schema/types/type/Group.gql b/backend/src/schema/types/type/Group.gql index 72ac9b57a..cd15689ec 100644 --- a/backend/src/schema/types/type/Group.gql +++ b/backend/src/schema/types/type/Group.gql @@ -175,9 +175,9 @@ type Query { slug: String createdAt: String updatedAt: String - locationName: String about: String description: String + locationName: String first: Int offset: Int orderBy: [_GroupOrdering] From e758e1337d94e9925c52ab0a06ff28ad0f562c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 3 Aug 2022 15:24:42 +0200 Subject: [PATCH 064/588] Release v1.1.0 - implement categories again --- CHANGELOG.md | 6 +++++- backend/package.json | 2 +- package.json | 2 +- webapp/maintenance/source/package.json | 2 +- webapp/package.json | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f8aa04ee..74f2c1dcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,12 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -#### [1.0.9](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/1.0.8...1.0.9) +#### [1.1.0](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/1.0.8...1.1.0) +- feat: Make Categories Optional [`#5102`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5102) +- Update issue templates [`#5101`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5101) +- chore: 🍰 Betters Automatic Deployment To `stage.ocelot.social` On Push To `master` Branch [`#5097`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5097) +- chore: 🍰 Release v1.0.9 [`#5095`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5095) - chore: 🍰 Automatic Deployment To `stage.ocelot.social` On Push To `master` Branch [`#5080`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5080) - change footer version-link [`#5091`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5091) - docs: 🍰 Add Neo4j Docu For Important Commands [`#5090`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5090) diff --git a/backend/package.json b/backend/package.json index 028b9295e..62188a650 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "ocelot-social-backend", - "version": "1.0.9", + "version": "1.1.0", "description": "GraphQL Backend for ocelot.social", "repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social", "author": "ocelot.social Community", diff --git a/package.json b/package.json index e23a5f5c7..7756ac8e6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ocelot-social", - "version": "1.0.9", + "version": "1.1.0", "description": "Free and open source software program code available to run social networks.", "author": "ocelot.social Community", "license": "MIT", diff --git a/webapp/maintenance/source/package.json b/webapp/maintenance/source/package.json index 3ee1a5b5c..79ced0031 100644 --- a/webapp/maintenance/source/package.json +++ b/webapp/maintenance/source/package.json @@ -1,6 +1,6 @@ { "name": "@ocelot-social/maintenance", - "version": "1.0.9", + "version": "1.1.0", "description": "Maintenance page for ocelot.social", "repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social", "author": "ocelot.social Community", diff --git a/webapp/package.json b/webapp/package.json index 77455f49f..234149521 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -1,6 +1,6 @@ { "name": "ocelot-social-webapp", - "version": "1.0.9", + "version": "1.1.0", "description": "ocelot.social Frontend", "repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social", "author": "ocelot.social Community", From fcca0f378d92726f5dc63e0fd0e6672edd210d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 4 Aug 2022 09:24:04 +0200 Subject: [PATCH 065/588] Implement 'Group' query, next step --- ...{authentications.ts => authentications.js} | 0 .../src/db/graphql/{groups.ts => groups.js} | 10 +- backend/src/db/graphql/{posts.ts => posts.js} | 0 backend/src/schema/resolvers/groups.js | 34 +- backend/src/schema/resolvers/groups.spec.js | 432 +++++++++++------- backend/src/schema/types/type/Group.gql | 1 + 6 files changed, 307 insertions(+), 170 deletions(-) rename backend/src/db/graphql/{authentications.ts => authentications.js} (100%) rename backend/src/db/graphql/{groups.ts => groups.js} (89%) rename backend/src/db/graphql/{posts.ts => posts.js} (100%) diff --git a/backend/src/db/graphql/authentications.ts b/backend/src/db/graphql/authentications.js similarity index 100% rename from backend/src/db/graphql/authentications.ts rename to backend/src/db/graphql/authentications.js diff --git a/backend/src/db/graphql/groups.ts b/backend/src/db/graphql/groups.js similarity index 89% rename from backend/src/db/graphql/groups.ts rename to backend/src/db/graphql/groups.js index 80b599658..e8da8e90b 100644 --- a/backend/src/db/graphql/groups.ts +++ b/backend/src/db/graphql/groups.js @@ -46,6 +46,7 @@ export const createGroupMutation = gql` export const groupQuery = gql` query ( + $isMember: Boolean $id: ID, $name: String, $slug: String, @@ -55,7 +56,7 @@ export const groupQuery = gql` $description: String, # $groupType: GroupType!, # $actionRadius: GroupActionRadius!, - $categoryIds: [ID] + # $categoryIds: [ID] $locationName: String $first: Int $offset: Int @@ -63,6 +64,7 @@ export const groupQuery = gql` $filter: _GroupFilter ) { Group( + isMember: $isMember id: $id name: $name slug: $slug @@ -72,8 +74,12 @@ export const groupQuery = gql` description: $description # groupType: $groupType # actionRadius: $actionRadius - categoryIds: $categoryIds + # categoryIds: $categoryIds locationName: $locationName + first: $first + offset: $offset + orderBy: $orderBy + filter: $filter ) { id name diff --git a/backend/src/db/graphql/posts.ts b/backend/src/db/graphql/posts.js similarity index 100% rename from backend/src/db/graphql/posts.ts rename to backend/src/db/graphql/posts.js diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js index 9a55c9f4d..be07fecc6 100644 --- a/backend/src/schema/resolvers/groups.js +++ b/backend/src/schema/resolvers/groups.js @@ -24,18 +24,34 @@ export default { // // params = await maintainPinnedPosts(params) // return neo4jgraphql(object, params, context, resolveInfo) // }, - Group: async (_object, _params, context, _resolveInfo) => { + Group: async (_object, params, context, _resolveInfo) => { + const { isMember } = params const session = context.driver.session() const readTxResultPromise = session.readTransaction(async (txc) => { - const result = await txc.run( - ` - MATCH (user:User {id: $userId})-[membership:MEMBER_OF]->(group:Group) + let groupCypher + if (isMember === true) { + groupCypher = ` + MATCH (:User {id: $userId})-[membership:MEMBER_OF]->(group:Group) RETURN group {.*, myRole: membership.role} - `, - { - userId: context.user.id, - }, - ) + ` + } else { + if (isMember === false) { + groupCypher = ` + MATCH (group:Group) + WHERE NOT (:User {id: $userId})-[:MEMBER_OF]->(group) + RETURN group {.*, myRole: NULL} + ` + } else { + groupCypher = ` + MATCH (group:Group) + OPTIONAL MATCH (:User {id: $userId})-[membership:MEMBER_OF]->(group) + RETURN group {.*, myRole: membership.role} + ` + } + } + const result = await txc.run(groupCypher, { + userId: context.user.id, + }) const group = result.records.map((record) => record.get('group')) return group }) diff --git a/backend/src/schema/resolvers/groups.spec.js b/backend/src/schema/resolvers/groups.spec.js index 8860f87f2..58e5f37be 100644 --- a/backend/src/schema/resolvers/groups.spec.js +++ b/backend/src/schema/resolvers/groups.spec.js @@ -1,13 +1,13 @@ import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '../../db/factories' -import { createGroupMutation } from '../../db/graphql/groups' +import { createGroupMutation, groupQuery } from '../../db/graphql/groups' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' const driver = getDriver() const neode = getNeode() -// Wolle: let query +let query let mutate let authenticatedUser let user @@ -27,7 +27,7 @@ beforeAll(async () => { } }, }) - // Wolle: query = createTestClient(server).query + query = createTestClient(server).query mutate = createTestClient(server).mutate }) @@ -79,162 +79,276 @@ afterEach(async () => { }) describe('Group', () => { - // describe('can be filtered', () => { - // let followedUser, happyPost, cryPost - // beforeEach(async () => { - // ;[followedUser] = await Promise.all([ - // Factory.build( - // 'user', - // { - // id: 'followed-by-me', - // name: 'Followed User', - // }, - // { - // email: 'followed@example.org', - // password: '1234', - // }, - // ), - // ]) - // ;[happyPost, cryPost] = await Promise.all([ - // Factory.build('post', { id: 'happy-post' }, { categoryIds: ['cat4'] }), - // Factory.build('post', { id: 'cry-post' }, { categoryIds: ['cat15'] }), - // Factory.build( - // 'post', - // { - // id: 'post-by-followed-user', - // }, - // { - // categoryIds: ['cat9'], - // author: followedUser, - // }, - // ), - // ]) - // }) - // describe('no filter', () => { - // it('returns all posts', async () => { - // const postQueryNoFilters = gql` - // query Post($filter: _PostFilter) { - // Post(filter: $filter) { - // id - // } - // } - // ` - // const expected = [{ id: 'happy-post' }, { id: 'cry-post' }, { id: 'post-by-followed-user' }] - // variables = { filter: {} } - // await expect(query({ query: postQueryNoFilters, variables })).resolves.toMatchObject({ - // data: { - // Post: expect.arrayContaining(expected), - // }, - // }) - // }) - // }) - // /* it('by categories', async () => { - // const postQueryFilteredByCategories = gql` - // query Post($filter: _PostFilter) { - // Post(filter: $filter) { - // id - // categories { - // id - // } - // } - // } - // ` - // const expected = { - // data: { - // Post: [ - // { - // id: 'post-by-followed-user', - // categories: [{ id: 'cat9' }], - // }, - // ], - // }, - // } - // variables = { ...variables, filter: { categories_some: { id_in: ['cat9'] } } } - // await expect( - // query({ query: postQueryFilteredByCategories, variables }), - // ).resolves.toMatchObject(expected) - // }) */ - // describe('by emotions', () => { - // const postQueryFilteredByEmotions = gql` - // query Post($filter: _PostFilter) { - // Post(filter: $filter) { - // id - // emotions { - // emotion - // } - // } - // } - // ` - // it('filters by single emotion', async () => { - // const expected = { - // data: { - // Post: [ - // { - // id: 'happy-post', - // emotions: [{ emotion: 'happy' }], - // }, - // ], - // }, - // } - // await user.relateTo(happyPost, 'emoted', { emotion: 'happy' }) - // variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy'] } } } - // await expect( - // query({ query: postQueryFilteredByEmotions, variables }), - // ).resolves.toMatchObject(expected) - // }) - // it('filters by multiple emotions', async () => { - // const expected = [ - // { - // id: 'happy-post', - // emotions: [{ emotion: 'happy' }], - // }, - // { - // id: 'cry-post', - // emotions: [{ emotion: 'cry' }], - // }, - // ] - // await user.relateTo(happyPost, 'emoted', { emotion: 'happy' }) - // await user.relateTo(cryPost, 'emoted', { emotion: 'cry' }) - // variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy', 'cry'] } } } - // await expect( - // query({ query: postQueryFilteredByEmotions, variables }), - // ).resolves.toMatchObject({ - // data: { - // Post: expect.arrayContaining(expected), - // }, - // errors: undefined, - // }) - // }) - // }) - // it('by followed-by', async () => { - // const postQueryFilteredByUsersFollowed = gql` - // query Post($filter: _PostFilter) { - // Post(filter: $filter) { - // id - // author { - // id - // name - // } - // } - // } - // ` - // await user.relateTo(followedUser, 'following') - // variables = { filter: { author: { followedBy_some: { id: 'current-user' } } } } - // await expect( - // query({ query: postQueryFilteredByUsersFollowed, variables }), - // ).resolves.toMatchObject({ - // data: { - // Post: [ - // { - // id: 'post-by-followed-user', - // author: { id: 'followed-by-me', name: 'Followed User' }, - // }, - // ], - // }, - // errors: undefined, - // }) - // }) - // }) + describe('unauthenticated', () => { + it('throws authorization error', async () => { + const { errors } = await query({ query: groupQuery, variables: {} }) + expect(errors[0]).toHaveProperty('message', 'Not Authorised!') + }) + }) + + describe('authenticated', () => { + beforeEach(async () => { + authenticatedUser = await user.toJson() + }) + + let otherUser + + beforeEach(async () => { + otherUser = await Factory.build( + 'user', + { + id: 'other-user', + name: 'Other TestUser', + }, + { + email: 'test2@example.org', + password: '1234', + }, + ) + authenticatedUser = await otherUser.toJson() + await mutate({ + mutation: createGroupMutation, + variables: { + id: 'others-group', + name: 'Uninteresting Group', + about: 'We will change nothing!', + description: 'We love it like it is!?', + groupType: 'closed', + actionRadius: 'international', + categoryIds, + }, + }) + authenticatedUser = await user.toJson() + await mutate({ + mutation: createGroupMutation, + variables: { + id: 'my-group', + name: 'The Best Group', + about: 'We will change the world!', + description: 'Some description', + groupType: 'public', + actionRadius: 'regional', + categoryIds, + }, + }) + }) + + describe('query can fetch', () => { + it('groups where user is member (or owner in this case)', async () => { + const expected = { + data: { + Group: [ + { + id: 'my-group', + slug: 'the-best-group', + myRole: 'owner', + }, + ], + }, + errors: undefined, + } + await expect( + query({ query: groupQuery, variables: { isMember: true } }), + ).resolves.toMatchObject(expected) + }) + + it('groups where user is not(!) member', async () => { + const expected = { + data: { + Group: expect.arrayContaining([ + expect.objectContaining({ + id: 'others-group', + slug: 'uninteresting-group', + myRole: null, + }), + ]), + }, + errors: undefined, + } + await expect( + query({ query: groupQuery, variables: { isMember: false } }), + ).resolves.toMatchObject(expected) + }) + + it('all groups', async () => { + const expected = { + data: { + Group: expect.arrayContaining([ + expect.objectContaining({ + id: 'my-group', + slug: 'the-best-group', + myRole: 'owner', + }), + expect.objectContaining({ + id: 'others-group', + slug: 'uninteresting-group', + myRole: null, + }), + ]), + }, + errors: undefined, + } + await expect(query({ query: groupQuery, variables: {} })).resolves.toMatchObject(expected) + }) + }) + + // Wolle: describe('can be filtered', () => { + // let followedUser, happyPost, cryPost + // beforeEach(async () => { + // ;[followedUser] = await Promise.all([ + // Factory.build( + // 'user', + // { + // id: 'followed-by-me', + // name: 'Followed User', + // }, + // { + // email: 'followed@example.org', + // password: '1234', + // }, + // ), + // ]) + // ;[happyPost, cryPost] = await Promise.all([ + // Factory.build('post', { id: 'happy-post' }, { categoryIds: ['cat4'] }), + // Factory.build('post', { id: 'cry-post' }, { categoryIds: ['cat15'] }), + // Factory.build( + // 'post', + // { + // id: 'post-by-followed-user', + // }, + // { + // categoryIds: ['cat9'], + // author: followedUser, + // }, + // ), + // ]) + // }) + // describe('no filter', () => { + // it('returns all posts', async () => { + // const postQueryNoFilters = gql` + // query Post($filter: _PostFilter) { + // Post(filter: $filter) { + // id + // } + // } + // ` + // const expected = [{ id: 'happy-post' }, { id: 'cry-post' }, { id: 'post-by-followed-user' }] + // variables = { filter: {} } + // await expect(query({ query: postQueryNoFilters, variables })).resolves.toMatchObject({ + // data: { + // Post: expect.arrayContaining(expected), + // }, + // }) + // }) + // }) + // /* it('by categories', async () => { + // const postQueryFilteredByCategories = gql` + // query Post($filter: _PostFilter) { + // Post(filter: $filter) { + // id + // categories { + // id + // } + // } + // } + // ` + // const expected = { + // data: { + // Post: [ + // { + // id: 'post-by-followed-user', + // categories: [{ id: 'cat9' }], + // }, + // ], + // }, + // } + // variables = { ...variables, filter: { categories_some: { id_in: ['cat9'] } } } + // await expect( + // query({ query: postQueryFilteredByCategories, variables }), + // ).resolves.toMatchObject(expected) + // }) */ + // describe('by emotions', () => { + // const postQueryFilteredByEmotions = gql` + // query Post($filter: _PostFilter) { + // Post(filter: $filter) { + // id + // emotions { + // emotion + // } + // } + // } + // ` + // it('filters by single emotion', async () => { + // const expected = { + // data: { + // Post: [ + // { + // id: 'happy-post', + // emotions: [{ emotion: 'happy' }], + // }, + // ], + // }, + // } + // await user.relateTo(happyPost, 'emoted', { emotion: 'happy' }) + // variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy'] } } } + // await expect( + // query({ query: postQueryFilteredByEmotions, variables }), + // ).resolves.toMatchObject(expected) + // }) + // it('filters by multiple emotions', async () => { + // const expected = [ + // { + // id: 'happy-post', + // emotions: [{ emotion: 'happy' }], + // }, + // { + // id: 'cry-post', + // emotions: [{ emotion: 'cry' }], + // }, + // ] + // await user.relateTo(happyPost, 'emoted', { emotion: 'happy' }) + // await user.relateTo(cryPost, 'emoted', { emotion: 'cry' }) + // variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy', 'cry'] } } } + // await expect( + // query({ query: postQueryFilteredByEmotions, variables }), + // ).resolves.toMatchObject({ + // data: { + // Post: expect.arrayContaining(expected), + // }, + // errors: undefined, + // }) + // }) + // }) + // it('by followed-by', async () => { + // const postQueryFilteredByUsersFollowed = gql` + // query Post($filter: _PostFilter) { + // Post(filter: $filter) { + // id + // author { + // id + // name + // } + // } + // } + // ` + // await user.relateTo(followedUser, 'following') + // variables = { filter: { author: { followedBy_some: { id: 'current-user' } } } } + // await expect( + // query({ query: postQueryFilteredByUsersFollowed, variables }), + // ).resolves.toMatchObject({ + // data: { + // Post: [ + // { + // id: 'post-by-followed-user', + // author: { id: 'followed-by-me', name: 'Followed User' }, + // }, + // ], + // }, + // errors: undefined, + // }) + // }) + // }) + }) }) describe('CreateGroup', () => { diff --git a/backend/src/schema/types/type/Group.gql b/backend/src/schema/types/type/Group.gql index cd15689ec..b8e00f0ee 100644 --- a/backend/src/schema/types/type/Group.gql +++ b/backend/src/schema/types/type/Group.gql @@ -170,6 +170,7 @@ input _GroupFilter { type Query { Group( + isMember: Boolean # if 'undefined' or 'null' then all groups id: ID name: String slug: String From f1831661e58c1547485b16d49036e8ef5a14ac9b Mon Sep 17 00:00:00 2001 From: ogerly Date: Sun, 7 Aug 2022 14:12:17 +0200 Subject: [PATCH 066/588] add my-groups page and setting link --- webapp/components/GroupForm/GroupForm.vue | 208 +++++------------- webapp/components/GroupTeaser/GroupTeaser.vue | 40 ++-- webapp/locales/de.json | 3 + webapp/locales/en.json | 3 + webapp/pages/group/create.vue | 9 +- webapp/pages/settings.vue | 4 + 6 files changed, 88 insertions(+), 179 deletions(-) diff --git a/webapp/components/GroupForm/GroupForm.vue b/webapp/components/GroupForm/GroupForm.vue index 76d659b96..e730a3c13 100644 --- a/webapp/components/GroupForm/GroupForm.vue +++ b/webapp/components/GroupForm/GroupForm.vue @@ -3,10 +3,7 @@ - - diff --git a/webapp/pages/group/create.vue b/webapp/pages/group/create.vue index b77096859..9463083f1 100644 --- a/webapp/pages/group/create.vue +++ b/webapp/pages/group/create.vue @@ -1,11 +1,13 @@ + \ No newline at end of file diff --git a/webapp/constants/headerMenu.js b/webapp/constants/headerMenu.js new file mode 100644 index 000000000..da7a72e85 --- /dev/null +++ b/webapp/constants/headerMenu.js @@ -0,0 +1,35 @@ +export default { + SHOW_HEADER_MENU: true, + MENU: [{ + name: 'Themen', + path: '/#' + }, + { + name: 'Gruppen', + path: '/#', + children: [ + { + name: 'Gruppe 1', + path: '/#' + }, + { + name: 'Gruppe 2', + path: '/#' + } + ] + }, + { + name: 'Über Yunite', + path: '/#', + children: [ + { + name: 'Impressum', + path: '/#' + }, + { + name: 'Yunite Team', + path: '/#' + } + ] + }] + } \ No newline at end of file diff --git a/webapp/layouts/default.vue b/webapp/layouts/default.vue index 0dfd752bf..503b22185 100644 --- a/webapp/layouts/default.vue +++ b/webapp/layouts/default.vue @@ -9,6 +9,7 @@ + import Logo from '~/components/Logo/Logo' +import HeaderMenu from '~/components/HeaderMenu/HeaderMenu.vue' +import headerMenu from '../constants/headerMenu.js' import { mapGetters } from 'vuex' import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch' import SearchField from '~/components/features/SearchField/SearchField.vue' @@ -94,6 +97,7 @@ import InviteButton from '~/components/InviteButton/InviteButton' export default { components: { Logo, + HeaderMenu, LocaleSwitch, SearchField, Modal, @@ -106,6 +110,7 @@ export default { mixins: [seo], data() { return { + show: headerMenu.SHOW_HEADER_MENU, mobileSearchVisible: false, toggleMobileMenu: false, inviteRegistration: this.$env.INVITE_REGISTRATION === true, // for 'false' in .env INVITE_REGISTRATION is of type undefined and not(!) boolean false, because of internal handling, From 336e9469dbdd30c839667f24e4b148a727a5fe5e Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 9 Aug 2022 11:55:00 +0200 Subject: [PATCH 072/588] add optional header menu --- webapp/components/HeaderMenu/HeaderMenu.vue | 24 ++++++++---------- webapp/constants/headerMenu.js | 28 +++++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/webapp/components/HeaderMenu/HeaderMenu.vue b/webapp/components/HeaderMenu/HeaderMenu.vue index 1228d1e4a..31afe93b4 100644 --- a/webapp/components/HeaderMenu/HeaderMenu.vue +++ b/webapp/components/HeaderMenu/HeaderMenu.vue @@ -1,20 +1,18 @@ \ No newline at end of file + diff --git a/webapp/constants/headerMenu.js b/webapp/constants/headerMenu.js index da7a72e85..1dfed43d8 100644 --- a/webapp/constants/headerMenu.js +++ b/webapp/constants/headerMenu.js @@ -1,8 +1,9 @@ export default { - SHOW_HEADER_MENU: true, - MENU: [{ + SHOW_HEADER_MENU: true, + MENU: [ + { name: 'Themen', - path: '/#' + path: '/#', }, { name: 'Gruppen', @@ -10,13 +11,13 @@ export default { children: [ { name: 'Gruppe 1', - path: '/#' + path: '/#', }, { name: 'Gruppe 2', - path: '/#' - } - ] + path: '/#', + }, + ], }, { name: 'Über Yunite', @@ -24,12 +25,13 @@ export default { children: [ { name: 'Impressum', - path: '/#' + path: '/#', }, { name: 'Yunite Team', - path: '/#' - } - ] - }] - } \ No newline at end of file + path: '/#', + }, + ], + }, + ], +} From 968dcc72763a19c2b7777a077590b1fa45fd3d81 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 9 Aug 2022 13:24:31 +0200 Subject: [PATCH 073/588] add yunite logo and branding scss file --- webapp/assets/styles/imports/_branding.scss | 6 ++ webapp/assets/styles/main.scss | 1 + webapp/components/Logo/Logo.vue | 4 +- webapp/components/Logo/style.scss | 2 +- webapp/layouts/default.vue | 4 +- webapp/static/img/custom/logo-horizontal.svg | 69 ++++--------------- webapp/static/img/custom/logo-squared.svg | 71 ++++---------------- 7 files changed, 36 insertions(+), 121 deletions(-) create mode 100644 webapp/assets/styles/imports/_branding.scss diff --git a/webapp/assets/styles/imports/_branding.scss b/webapp/assets/styles/imports/_branding.scss new file mode 100644 index 000000000..fb4c80970 --- /dev/null +++ b/webapp/assets/styles/imports/_branding.scss @@ -0,0 +1,6 @@ +.header-menu { + background-color: #748885; +} +.ds-menu-item-link { + color: antiquewhite; +} \ No newline at end of file diff --git a/webapp/assets/styles/main.scss b/webapp/assets/styles/main.scss index d6821e013..dc745585d 100644 --- a/webapp/assets/styles/main.scss +++ b/webapp/assets/styles/main.scss @@ -1,3 +1,4 @@ +@import './imports/_branding.scss'; @import './imports/_tooltip.scss'; @import './imports/_toast.scss'; diff --git a/webapp/components/Logo/Logo.vue b/webapp/components/Logo/Logo.vue index ed5c147e8..6e4dd3cbc 100644 --- a/webapp/components/Logo/Logo.vue +++ b/webapp/components/Logo/Logo.vue @@ -59,7 +59,7 @@ export default { }, data() { const logosObject = { - header: { path: logos.LOGO_HEADER_PATH, alt: 'Header', widthDefault: '130px' }, + header: { path: logos.LOGO_HEADER_PATH, alt: 'Header', widthDefault: '47px' }, welcome: { path: logos.LOGO_WELCOME_PATH, alt: 'Welcome', widthDefault: '200px' }, signup: { path: logos.LOGO_SIGNUP_PATH, alt: 'Sign Up', widthDefault: '200px' }, logout: { path: logos.LOGO_LOGOUT_PATH, alt: 'Logging Out', widthDefault: '200px' }, @@ -107,7 +107,7 @@ export default { } .ds-logo-svg { - width: 130px; + width: 47px; height: auto; fill: #000000; } diff --git a/webapp/components/Logo/style.scss b/webapp/components/Logo/style.scss index 305e907c5..aa153c8f6 100644 --- a/webapp/components/Logo/style.scss +++ b/webapp/components/Logo/style.scss @@ -11,7 +11,7 @@ } .ds-logo-svg { - width: 130px; + width: 47px; height: auto; fill: currentColor; } \ No newline at end of file diff --git a/webapp/layouts/default.vue b/webapp/layouts/default.vue index 503b22185..8e9f09616 100644 --- a/webapp/layouts/default.vue +++ b/webapp/layouts/default.vue @@ -4,7 +4,7 @@
- + @@ -17,7 +17,7 @@ - - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/webapp/static/img/custom/logo-squared.svg b/webapp/static/img/custom/logo-squared.svg index 2a926f0a9..6ed4a3f62 100644 --- a/webapp/static/img/custom/logo-squared.svg +++ b/webapp/static/img/custom/logo-squared.svg @@ -1,65 +1,18 @@ - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + From 3c11d1f468dfcf8806284ec704cf53a3911733df Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 9 Aug 2022 13:27:24 +0200 Subject: [PATCH 074/588] fix lint --- webapp/layouts/default.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/webapp/layouts/default.vue b/webapp/layouts/default.vue index 8e9f09616..4c5d9d0de 100644 --- a/webapp/layouts/default.vue +++ b/webapp/layouts/default.vue @@ -17,7 +17,12 @@ Date: Tue, 9 Aug 2022 16:34:50 +0200 Subject: [PATCH 075/588] Implement error for to short 'description' and test it --- backend/src/constants/categories.js | 8 +++--- backend/src/constants/groups.js | 2 ++ backend/src/middleware/helpers/cleanHtml.js | 7 +++++ backend/src/middleware/languages/languages.js | 9 +------ backend/src/schema/resolvers/groups.js | 15 ++++++++--- backend/src/schema/resolvers/groups.spec.js | 27 ++++++++++++++++--- webapp/constants/categories.js | 3 +++ webapp/constants/groups.js | 2 ++ 8 files changed, 54 insertions(+), 19 deletions(-) create mode 100644 backend/src/constants/groups.js create mode 100644 webapp/constants/categories.js create mode 100644 webapp/constants/groups.js diff --git a/backend/src/constants/categories.js b/backend/src/constants/categories.js index 37cac8151..64ceb9021 100644 --- a/backend/src/constants/categories.js +++ b/backend/src/constants/categories.js @@ -1,5 +1,3 @@ -// this file is duplicated in `backend/src/config/metadata.js` and `webapp/constants/metadata.js` -export default { - CATEGORIES_MIN: 1, - CATEGORIES_MAX: 3, -} +// this file is duplicated in `backend/src/constants/metadata.js` and `webapp/constants/metadata.js` +export const CATEGORIES_MIN = 1 +export const CATEGORIES_MAX = 3 diff --git a/backend/src/constants/groups.js b/backend/src/constants/groups.js new file mode 100644 index 000000000..b4a6063f1 --- /dev/null +++ b/backend/src/constants/groups.js @@ -0,0 +1,2 @@ +// this file is duplicated in `backend/src/constants/group.js` and `webapp/constants/group.js` +export const DESCRIPTION_WITHOUT_HTML_LENGTH_MIN = 100 // with removed HTML tags diff --git a/backend/src/middleware/helpers/cleanHtml.js b/backend/src/middleware/helpers/cleanHtml.js index 72976b43c..ac71f6bdc 100644 --- a/backend/src/middleware/helpers/cleanHtml.js +++ b/backend/src/middleware/helpers/cleanHtml.js @@ -1,6 +1,13 @@ import sanitizeHtml from 'sanitize-html' import linkifyHtml from 'linkifyjs/html' +export const removeHtmlTags = (input) => { + return sanitizeHtml(input, { + allowedTags: [], + allowedAttributes: {}, + }) +} + const standardSanitizeHtmlOptions = { allowedTags: [ 'img', diff --git a/backend/src/middleware/languages/languages.js b/backend/src/middleware/languages/languages.js index 3cf760f31..087252975 100644 --- a/backend/src/middleware/languages/languages.js +++ b/backend/src/middleware/languages/languages.js @@ -1,12 +1,5 @@ import LanguageDetect from 'languagedetect' -import sanitizeHtml from 'sanitize-html' - -const removeHtmlTags = (input) => { - return sanitizeHtml(input, { - allowedTags: [], - allowedAttributes: {}, - }) -} +import { removeHtmlTags } from '../helpers/cleanHtml.js' const setPostLanguage = (text) => { const lngDetector = new LanguageDetect() diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js index a958e990e..0e07b7542 100644 --- a/backend/src/schema/resolvers/groups.js +++ b/backend/src/schema/resolvers/groups.js @@ -3,7 +3,9 @@ import { v4 as uuid } from 'uuid' // Wolle: import { isEmpty } from 'lodash' import { UserInputError } from 'apollo-server' import CONFIG from '../../config' -import categories from '../../constants/categories' +import { CATEGORIES_MIN, CATEGORIES_MAX } from '../../constants/categories' +import { DESCRIPTION_WITHOUT_HTML_LENGTH_MIN } from '../../constants/groups' +import { removeHtmlTags } from '../../middleware/helpers/cleanHtml.js' // Wolle: import { mergeImage, deleteImage } from './images/images' import Resolver from './helpers/Resolver' // Wolle: import { filterForMutedUsers } from './helpers/filterForMutedUsers' @@ -70,12 +72,19 @@ export default { CreateGroup: async (_parent, params, context, _resolveInfo) => { const { categoryIds } = params delete params.categoryIds - if (!categoryIds || categoryIds.length < categories.CATEGORIES_MIN) { + if (!categoryIds || categoryIds.length < CATEGORIES_MIN) { throw new UserInputError('To Less Categories!') } - if (categoryIds && categoryIds.length > categories.CATEGORIES_MAX) { + if (categoryIds && categoryIds.length > CATEGORIES_MAX) { throw new UserInputError('To Many Categories!') } + if ( + params.description === undefined || + params.description === null || + removeHtmlTags(params.description).length < DESCRIPTION_WITHOUT_HTML_LENGTH_MIN + ) { + throw new UserInputError('To Short Description!') + } params.id = params.id || uuid() const session = context.driver.session() const writeTxResultPromise = session.writeTransaction(async (transaction) => { diff --git a/backend/src/schema/resolvers/groups.spec.js b/backend/src/schema/resolvers/groups.spec.js index 8f20c4fa7..ad9b6d68e 100644 --- a/backend/src/schema/resolvers/groups.spec.js +++ b/backend/src/schema/resolvers/groups.spec.js @@ -13,6 +13,8 @@ let authenticatedUser let user const categoryIds = ['cat9', 'cat4', 'cat15'] +const descriptionAddition100 = + ' 123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789' let variables = {} beforeAll(async () => { @@ -116,7 +118,7 @@ describe('Group', () => { id: 'others-group', name: 'Uninteresting Group', about: 'We will change nothing!', - description: 'We love it like it is!?', + description: 'We love it like it is!?' + descriptionAddition100, groupType: 'closed', actionRadius: 'international', categoryIds, @@ -129,7 +131,7 @@ describe('Group', () => { id: 'my-group', name: 'The Best Group', about: 'We will change the world!', - description: 'Some description', + description: 'Some description' + descriptionAddition100, groupType: 'public', actionRadius: 'regional', categoryIds, @@ -363,7 +365,7 @@ describe('CreateGroup', () => { name: 'The Best Group', slug: 'the-group', about: 'We will change the world!', - description: 'Some description', + description: 'Some description' + descriptionAddition100, groupType: 'public', actionRadius: 'regional', categoryIds, @@ -423,6 +425,25 @@ describe('CreateGroup', () => { ) }) + describe('description', () => { + describe('length without HTML', () => { + describe('less then 100 chars', () => { + it('throws error: "To Less Categories!"', async () => { + const { errors } = await mutate({ + mutation: createGroupMutation, + variables: { + ...variables, + description: + '0123456789' + + '0123456789', + }, + }) + expect(errors[0]).toHaveProperty('message', 'To Short Description!') + }) + }) + }) + }) + describe('categories', () => { describe('not even one', () => { it('throws error: "To Less Categories!"', async () => { diff --git a/webapp/constants/categories.js b/webapp/constants/categories.js new file mode 100644 index 000000000..64ceb9021 --- /dev/null +++ b/webapp/constants/categories.js @@ -0,0 +1,3 @@ +// this file is duplicated in `backend/src/constants/metadata.js` and `webapp/constants/metadata.js` +export const CATEGORIES_MIN = 1 +export const CATEGORIES_MAX = 3 diff --git a/webapp/constants/groups.js b/webapp/constants/groups.js new file mode 100644 index 000000000..b4a6063f1 --- /dev/null +++ b/webapp/constants/groups.js @@ -0,0 +1,2 @@ +// this file is duplicated in `backend/src/constants/group.js` and `webapp/constants/group.js` +export const DESCRIPTION_WITHOUT_HTML_LENGTH_MIN = 100 // with removed HTML tags From 0149af12d4c09ca8ec3f99c62a746609bacf6e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 9 Aug 2022 16:48:46 +0200 Subject: [PATCH 076/588] Cleanup --- backend/src/db/graphql/groups.js | 12 - backend/src/models/Group.js | 100 +---- backend/src/schema/resolvers/groups.js | 112 ----- backend/src/schema/resolvers/groups.spec.js | 458 -------------------- backend/src/schema/types/type/Group.gql | 164 +------ 5 files changed, 3 insertions(+), 843 deletions(-) diff --git a/backend/src/db/graphql/groups.js b/backend/src/db/graphql/groups.js index c41f06e4d..2a611f324 100644 --- a/backend/src/db/graphql/groups.js +++ b/backend/src/db/graphql/groups.js @@ -35,9 +35,6 @@ export const createGroupMutation = gql` groupType actionRadius myRole - # Wolle: owner { - # name - # } } } ` @@ -54,9 +51,6 @@ export const groupQuery = gql` $updatedAt: String $about: String $description: String - # $groupType: GroupType!, - # $actionRadius: GroupActionRadius!, - # $categoryIds: [ID] $locationName: String $first: Int $offset: Int @@ -72,9 +66,6 @@ export const groupQuery = gql` updatedAt: $updatedAt about: $about description: $description - # groupType: $groupType - # actionRadius: $actionRadius - # categoryIds: $categoryIds locationName: $locationName first: $first offset: $offset @@ -99,9 +90,6 @@ export const groupQuery = gql` name icon } - # Wolle: owner { - # name - # } } } ` diff --git a/backend/src/models/Group.js b/backend/src/models/Group.js index 0cec02bf8..25149e9c3 100644 --- a/backend/src/models/Group.js +++ b/backend/src/models/Group.js @@ -38,109 +38,11 @@ export default { locationName: { type: 'string', allow: [null] }, wasSeeded: 'boolean', // Wolle: used or needed? - // Wolle: owner: { - // type: 'relationship', - // relationship: 'OWNS', - // target: 'User', - // direction: 'in', - // }, - // Wolle: followedBy: { - // type: 'relationship', - // relationship: 'FOLLOWS', - // target: 'User', - // direction: 'in', - // properties: { - // createdAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() }, - // }, - // }, - // Wolle: correct this way? - // members: { type: 'relationship', relationship: 'MEMBERS', target: 'User', direction: 'out' }, - // Wolle: needed? lastActiveAt: { type: 'string', isoDate: true }, - // Wolle: emoted: { - // type: 'relationships', - // relationship: 'EMOTED', - // target: 'Post', - // direction: 'out', - // properties: { - // emotion: { - // type: 'string', - // valid: ['happy', 'cry', 'surprised', 'angry', 'funny'], - // invalid: [null], - // }, - // }, - // eager: true, - // cascade: true, - // }, - // Wolle: blocked: { - // type: 'relationship', - // relationship: 'BLOCKED', - // target: 'User', - // direction: 'out', - // properties: { - // createdAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() }, - // }, - // }, - // Wolle: muted: { - // type: 'relationship', - // relationship: 'MUTED', - // target: 'User', - // direction: 'out', - // properties: { - // createdAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() }, - // }, - // }, - // Wolle: notifications: { - // type: 'relationship', - // relationship: 'NOTIFIED', - // target: 'User', - // direction: 'in', - // }, - // Wolle inviteCodes: { - // type: 'relationship', - // relationship: 'GENERATED', - // target: 'InviteCode', - // direction: 'out', - // }, - // Wolle: redeemedInviteCode: { - // type: 'relationship', - // relationship: 'REDEEMED', - // target: 'InviteCode', - // direction: 'out', - // }, - // Wolle: shouted: { - // type: 'relationship', - // relationship: 'SHOUTED', - // target: 'Post', - // direction: 'out', - // properties: { - // createdAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() }, - // }, - // }, + isIn: { type: 'relationship', relationship: 'IS_IN', target: 'Location', direction: 'out', }, - // Wolle: pinned: { - // type: 'relationship', - // relationship: 'PINNED', - // target: 'Post', - // direction: 'out', - // properties: { - // createdAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() }, - // }, - // }, - // Wolle: showShoutsPublicly: { - // type: 'boolean', - // default: false, - // }, - // Wolle: sendNotificationEmails: { - // type: 'boolean', - // default: true, - // }, - // Wolle: locale: { - // type: 'string', - // allow: [null], - // }, } diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js index 0e07b7542..75f9e35df 100644 --- a/backend/src/schema/resolvers/groups.js +++ b/backend/src/schema/resolvers/groups.js @@ -1,32 +1,13 @@ import { v4 as uuid } from 'uuid' -// Wolle: import { neo4jgraphql } from 'neo4j-graphql-js' -// Wolle: import { isEmpty } from 'lodash' import { UserInputError } from 'apollo-server' import CONFIG from '../../config' import { CATEGORIES_MIN, CATEGORIES_MAX } from '../../constants/categories' import { DESCRIPTION_WITHOUT_HTML_LENGTH_MIN } from '../../constants/groups' import { removeHtmlTags } from '../../middleware/helpers/cleanHtml.js' -// Wolle: import { mergeImage, deleteImage } from './images/images' import Resolver from './helpers/Resolver' -// Wolle: import { filterForMutedUsers } from './helpers/filterForMutedUsers' - -// Wolle: const maintainPinnedPosts = (params) => { -// const pinnedPostFilter = { pinned: true } -// if (isEmpty(params.filter)) { -// params.filter = { OR: [pinnedPostFilter, {}] } -// } else { -// params.filter = { OR: [pinnedPostFilter, { ...params.filter }] } -// } -// return params -// } export default { Query: { - // Wolle: Post: async (object, params, context, resolveInfo) => { - // params = await filterForMutedUsers(params, context) - // // params = await maintainPinnedPosts(params) - // return neo4jgraphql(object, params, context, resolveInfo) - // }, Group: async (_object, params, context, _resolveInfo) => { const { isMember } = params const session = context.driver.session() @@ -130,105 +111,12 @@ export default { session.close() } }, - // UpdatePost: async (_parent, params, context, _resolveInfo) => { - // const { categoryIds } = params - // const { image: imageInput } = params - // delete params.categoryIds - // delete params.image - // const session = context.driver.session() - // let updatePostCypher = ` - // MATCH (post:Post {id: $params.id}) - // SET post += $params - // SET post.updatedAt = toString(datetime()) - // WITH post - // ` - - // if (categoryIds && categoryIds.length) { - // const cypherDeletePreviousRelations = ` - // MATCH (post:Post { id: $params.id })-[previousRelations:CATEGORIZED]->(category:Category) - // DELETE previousRelations - // RETURN post, category - // ` - - // await session.writeTransaction((transaction) => { - // return transaction.run(cypherDeletePreviousRelations, { params }) - // }) - - // updatePostCypher += ` - // UNWIND $categoryIds AS categoryId - // MATCH (category:Category {id: categoryId}) - // MERGE (post)-[:CATEGORIZED]->(category) - // WITH post - // ` - // } - - // updatePostCypher += `RETURN post {.*}` - // const updatePostVariables = { categoryIds, params } - // try { - // const writeTxResultPromise = session.writeTransaction(async (transaction) => { - // const updatePostTransactionResponse = await transaction.run( - // updatePostCypher, - // updatePostVariables, - // ) - // const [post] = updatePostTransactionResponse.records.map((record) => record.get('post')) - // await mergeImage(post, 'HERO_IMAGE', imageInput, { transaction }) - // return post - // }) - // const post = await writeTxResultPromise - // return post - // } finally { - // session.close() - // } - // }, - - // DeletePost: async (object, args, context, resolveInfo) => { - // const session = context.driver.session() - // const writeTxResultPromise = session.writeTransaction(async (transaction) => { - // const deletePostTransactionResponse = await transaction.run( - // ` - // MATCH (post:Post {id: $postId}) - // OPTIONAL MATCH (post)<-[:COMMENTS]-(comment:Comment) - // SET post.deleted = TRUE - // SET post.content = 'UNAVAILABLE' - // SET post.contentExcerpt = 'UNAVAILABLE' - // SET post.title = 'UNAVAILABLE' - // SET comment.deleted = TRUE - // RETURN post {.*} - // `, - // { postId: args.id }, - // ) - // const [post] = deletePostTransactionResponse.records.map((record) => record.get('post')) - // await deleteImage(post, 'HERO_IMAGE', { transaction }) - // return post - // }) - // try { - // const post = await writeTxResultPromise - // return post - // } finally { - // session.close() - // } }, Group: { ...Resolver('Group', { - // Wolle: undefinedToNull: ['activityId', 'objectId', 'language', 'pinnedAt', 'pinned'], hasMany: { - // Wolle: tags: '-[:TAGGED]->(related:Tag)', categories: '-[:CATEGORIZED]->(related:Category)', }, - // hasOne: { - // owner: '<-[:OWNS]-(related:User)', - // // Wolle: image: '-[:HERO_IMAGE]->(related:Image)', - // }, - // Wolle: count: { - // contributionsCount: - // '-[:WROTE]->(related:Post) WHERE NOT related.disabled = true AND NOT related.deleted = true', - // }, - // Wolle: boolean: { - // shoutedByCurrentUser: - // 'MATCH(this)<-[:SHOUTED]-(related:User {id: $cypherParams.currentUserId}) RETURN COUNT(related) >= 1', - // viewedTeaserByCurrentUser: - // 'MATCH (this)<-[:VIEWED_TEASER]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1', - // }, }), }, } diff --git a/backend/src/schema/resolvers/groups.spec.js b/backend/src/schema/resolvers/groups.spec.js index ad9b6d68e..bae530c61 100644 --- a/backend/src/schema/resolvers/groups.spec.js +++ b/backend/src/schema/resolvers/groups.spec.js @@ -197,163 +197,6 @@ describe('Group', () => { ).resolves.toMatchObject(expected) }) }) - - // describe('can be filtered', () => { - // Wolle: it('by categories', async () => { - // const postQueryFilteredByCategories = gql` - // query Post($filter: _PostFilter) { - // Post(filter: $filter) { - // id - // categories { - // id - // } - // } - // } - // ` - // const expected = { - // data: { - // Post: [ - // { - // id: 'post-by-followed-user', - // categories: [{ id: 'cat9' }], - // }, - // ], - // }, - // } - // variables = { ...variables, filter: { categories_some: { id_in: ['cat9'] } } } - // await expect( - // query({ query: postQueryFilteredByCategories, variables }), - // ).resolves.toMatchObject(expected) - // }) - // Wolle: let followedUser, happyPost, cryPost - // beforeEach(async () => { - // ;[followedUser] = await Promise.all([ - // Factory.build( - // 'user', - // { - // id: 'followed-by-me', - // name: 'Followed User', - // }, - // { - // email: 'followed@example.org', - // password: '1234', - // }, - // ), - // ]) - // ;[happyPost, cryPost] = await Promise.all([ - // Factory.build('post', { id: 'happy-post' }, { categoryIds: ['cat4'] }), - // Factory.build('post', { id: 'cry-post' }, { categoryIds: ['cat15'] }), - // Factory.build( - // 'post', - // { - // id: 'post-by-followed-user', - // }, - // { - // categoryIds: ['cat9'], - // author: followedUser, - // }, - // ), - // ]) - // }) - // describe('no filter', () => { - // it('returns all posts', async () => { - // const postQueryNoFilters = gql` - // query Post($filter: _PostFilter) { - // Post(filter: $filter) { - // id - // } - // } - // ` - // const expected = [{ id: 'happy-post' }, { id: 'cry-post' }, { id: 'post-by-followed-user' }] - // variables = { filter: {} } - // await expect(query({ query: postQueryNoFilters, variables })).resolves.toMatchObject({ - // data: { - // Post: expect.arrayContaining(expected), - // }, - // }) - // }) - // }) - // describe('by emotions', () => { - // const postQueryFilteredByEmotions = gql` - // query Post($filter: _PostFilter) { - // Post(filter: $filter) { - // id - // emotions { - // emotion - // } - // } - // } - // ` - // it('filters by single emotion', async () => { - // const expected = { - // data: { - // Post: [ - // { - // id: 'happy-post', - // emotions: [{ emotion: 'happy' }], - // }, - // ], - // }, - // } - // await user.relateTo(happyPost, 'emoted', { emotion: 'happy' }) - // variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy'] } } } - // await expect( - // query({ query: postQueryFilteredByEmotions, variables }), - // ).resolves.toMatchObject(expected) - // }) - // it('filters by multiple emotions', async () => { - // const expected = [ - // { - // id: 'happy-post', - // emotions: [{ emotion: 'happy' }], - // }, - // { - // id: 'cry-post', - // emotions: [{ emotion: 'cry' }], - // }, - // ] - // await user.relateTo(happyPost, 'emoted', { emotion: 'happy' }) - // await user.relateTo(cryPost, 'emoted', { emotion: 'cry' }) - // variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy', 'cry'] } } } - // await expect( - // query({ query: postQueryFilteredByEmotions, variables }), - // ).resolves.toMatchObject({ - // data: { - // Post: expect.arrayContaining(expected), - // }, - // errors: undefined, - // }) - // }) - // }) - // it('by followed-by', async () => { - // const postQueryFilteredByUsersFollowed = gql` - // query Post($filter: _PostFilter) { - // Post(filter: $filter) { - // id - // author { - // id - // name - // } - // } - // } - // ` - // await user.relateTo(followedUser, 'following') - // variables = { filter: { author: { followedBy_some: { id: 'current-user' } } } } - // await expect( - // query({ query: postQueryFilteredByUsersFollowed, variables }), - // ).resolves.toMatchObject({ - // data: { - // Post: [ - // { - // id: 'post-by-followed-user', - // author: { id: 'followed-by-me', name: 'Followed User' }, - // }, - // ], - // }, - // errors: undefined, - // }) - // }) - // }) }) }) @@ -406,9 +249,6 @@ describe('CreateGroup', () => { CreateGroup: { name: 'The Best Group', myRole: 'owner', - // Wolle: owner: { - // name: 'TestUser', - // }, }, }, errors: undefined, @@ -467,301 +307,3 @@ describe('CreateGroup', () => { }) }) }) - -// describe('UpdatePost', () => { -// let author, newlyCreatedPost -// const updatePostMutation = gql` -// mutation ($id: ID!, $title: String!, $content: String!, $image: ImageInput) { -// UpdatePost(id: $id, title: $title, content: $content, image: $image) { -// id -// title -// content -// author { -// name -// slug -// } -// createdAt -// updatedAt -// } -// } -// ` -// beforeEach(async () => { -// author = await Factory.build('user', { slug: 'the-author' }) -// newlyCreatedPost = await Factory.build( -// 'post', -// { -// id: 'p9876', -// title: 'Old title', -// content: 'Old content', -// }, -// { -// author, -// categoryIds, -// }, -// ) - -// variables = { -// id: 'p9876', -// title: 'New title', -// content: 'New content', -// } -// }) - -// describe('unauthenticated', () => { -// it('throws authorization error', async () => { -// authenticatedUser = null -// expect(mutate({ mutation: updatePostMutation, variables })).resolves.toMatchObject({ -// errors: [{ message: 'Not Authorised!' }], -// data: { UpdatePost: null }, -// }) -// }) -// }) - -// describe('authenticated but not the author', () => { -// beforeEach(async () => { -// authenticatedUser = await user.toJson() -// }) - -// it('throws authorization error', async () => { -// const { errors } = await mutate({ mutation: updatePostMutation, variables }) -// expect(errors[0]).toHaveProperty('message', 'Not Authorised!') -// }) -// }) - -// describe('authenticated as author', () => { -// beforeEach(async () => { -// authenticatedUser = await author.toJson() -// }) - -// it('updates a post', async () => { -// const expected = { -// data: { UpdatePost: { id: 'p9876', content: 'New content' } }, -// errors: undefined, -// } -// await expect(mutate({ mutation: updatePostMutation, variables })).resolves.toMatchObject( -// expected, -// ) -// }) - -// it('updates a post, but maintains non-updated attributes', async () => { -// const expected = { -// data: { -// UpdatePost: { id: 'p9876', content: 'New content', createdAt: expect.any(String) }, -// }, -// errors: undefined, -// } -// await expect(mutate({ mutation: updatePostMutation, variables })).resolves.toMatchObject( -// expected, -// ) -// }) - -// it('updates the updatedAt attribute', async () => { -// newlyCreatedPost = await newlyCreatedPost.toJson() -// const { -// data: { UpdatePost }, -// } = await mutate({ mutation: updatePostMutation, variables }) -// expect(newlyCreatedPost.updatedAt).toBeTruthy() -// expect(Date.parse(newlyCreatedPost.updatedAt)).toEqual(expect.any(Number)) -// expect(UpdatePost.updatedAt).toBeTruthy() -// expect(Date.parse(UpdatePost.updatedAt)).toEqual(expect.any(Number)) -// expect(newlyCreatedPost.updatedAt).not.toEqual(UpdatePost.updatedAt) -// }) - -// /* describe('no new category ids provided for update', () => { -// it('resolves and keeps current categories', async () => { -// const expected = { -// data: { -// UpdatePost: { -// id: 'p9876', -// categories: expect.arrayContaining([{ id: 'cat9' }, { id: 'cat4' }, { id: 'cat15' }]), -// }, -// }, -// errors: undefined, -// } -// await expect(mutate({ mutation: updatePostMutation, variables })).resolves.toMatchObject( -// expected, -// ) -// }) -// }) */ - -// /* describe('given category ids', () => { -// beforeEach(() => { -// variables = { ...variables, categoryIds: ['cat27'] } -// }) - -// it('updates categories of a post', async () => { -// const expected = { -// data: { -// UpdatePost: { -// id: 'p9876', -// categories: expect.arrayContaining([{ id: 'cat27' }]), -// }, -// }, -// errors: undefined, -// } -// await expect(mutate({ mutation: updatePostMutation, variables })).resolves.toMatchObject( -// expected, -// ) -// }) -// }) */ - -// describe('params.image', () => { -// describe('is object', () => { -// beforeEach(() => { -// variables = { ...variables, image: { sensitive: true } } -// }) -// it('updates the image', async () => { -// await expect(neode.first('Image', { sensitive: true })).resolves.toBeFalsy() -// await mutate({ mutation: updatePostMutation, variables }) -// await expect(neode.first('Image', { sensitive: true })).resolves.toBeTruthy() -// }) -// }) - -// describe('is null', () => { -// beforeEach(() => { -// variables = { ...variables, image: null } -// }) -// it('deletes the image', async () => { -// await expect(neode.all('Image')).resolves.toHaveLength(6) -// await mutate({ mutation: updatePostMutation, variables }) -// await expect(neode.all('Image')).resolves.toHaveLength(5) -// }) -// }) - -// describe('is undefined', () => { -// beforeEach(() => { -// delete variables.image -// }) -// it('keeps the image unchanged', async () => { -// await expect(neode.first('Image', { sensitive: true })).resolves.toBeFalsy() -// await mutate({ mutation: updatePostMutation, variables }) -// await expect(neode.first('Image', { sensitive: true })).resolves.toBeFalsy() -// }) -// }) -// }) -// }) -// }) - -// describe('DeletePost', () => { -// let author -// const deletePostMutation = gql` -// mutation ($id: ID!) { -// DeletePost(id: $id) { -// id -// deleted -// content -// contentExcerpt -// image { -// url -// } -// comments { -// deleted -// content -// contentExcerpt -// } -// } -// } -// ` - -// beforeEach(async () => { -// author = await Factory.build('user') -// await Factory.build( -// 'post', -// { -// id: 'p4711', -// title: 'I will be deleted', -// content: 'To be deleted', -// }, -// { -// image: Factory.build('image', { -// url: 'path/to/some/image', -// }), -// author, -// categoryIds, -// }, -// ) -// variables = { ...variables, id: 'p4711' } -// }) - -// describe('unauthenticated', () => { -// it('throws authorization error', async () => { -// const { errors } = await mutate({ mutation: deletePostMutation, variables }) -// expect(errors[0]).toHaveProperty('message', 'Not Authorised!') -// }) -// }) - -// describe('authenticated but not the author', () => { -// beforeEach(async () => { -// authenticatedUser = await user.toJson() -// }) - -// it('throws authorization error', async () => { -// const { errors } = await mutate({ mutation: deletePostMutation, variables }) -// expect(errors[0]).toHaveProperty('message', 'Not Authorised!') -// }) -// }) - -// describe('authenticated as author', () => { -// beforeEach(async () => { -// authenticatedUser = await author.toJson() -// }) - -// it('marks the post as deleted and blacks out attributes', async () => { -// const expected = { -// data: { -// DeletePost: { -// id: 'p4711', -// deleted: true, -// content: 'UNAVAILABLE', -// contentExcerpt: 'UNAVAILABLE', -// image: null, -// comments: [], -// }, -// }, -// } -// await expect(mutate({ mutation: deletePostMutation, variables })).resolves.toMatchObject( -// expected, -// ) -// }) - -// describe('if there are comments on the post', () => { -// beforeEach(async () => { -// await Factory.build( -// 'comment', -// { -// content: 'to be deleted comment content', -// contentExcerpt: 'to be deleted comment content', -// }, -// { -// postId: 'p4711', -// }, -// ) -// }) - -// it('marks the comments as deleted', async () => { -// const expected = { -// data: { -// DeletePost: { -// id: 'p4711', -// deleted: true, -// content: 'UNAVAILABLE', -// contentExcerpt: 'UNAVAILABLE', -// image: null, -// comments: [ -// { -// deleted: true, -// // Should we black out the comment content in the database, too? -// content: 'UNAVAILABLE', -// contentExcerpt: 'UNAVAILABLE', -// }, -// ], -// }, -// }, -// } -// await expect(mutate({ mutation: deletePostMutation, variables })).resolves.toMatchObject( -// expected, -// ) -// }) -// }) -// }) -// }) diff --git a/backend/src/schema/types/type/Group.gql b/backend/src/schema/types/type/Group.gql index 2dc20aebf..3165b4a44 100644 --- a/backend/src/schema/types/type/Group.gql +++ b/backend/src/schema/types/type/Group.gql @@ -13,8 +13,6 @@ enum _GroupOrdering { createdAt_desc updatedAt_asc updatedAt_desc - # Wolle: needed? locale_asc - # locale_desc } type Group { @@ -40,90 +38,6 @@ type Group { categories: [Category] @relation(name: "CATEGORIZED", direction: "OUT") myRole: GroupMemberRole # if 'null' then the current user is no member - - # Wolle: needed? - # socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN") - - # Wolle: owner: User @relation(name: "OWNS", direction: "IN") - - # Wolle: showShoutsPublicly: Boolean - # Wolle: sendNotificationEmails: Boolean - # Wolle: needed? locale: String - # members: [User]! @relation(name: "MEMBERS", direction: "OUT") - # membersCount: Int! - # @cypher(statement: "MATCH (this)-[:MEMBERS]->(r:User) RETURN COUNT(DISTINCT r)") - - # Wolle: followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN") - # Wolle: followedByCount: Int! - # @cypher(statement: "MATCH (this)<-[:FOLLOWS]-(r:User) RETURN COUNT(DISTINCT r)") - - # Wolle: inviteCodes: [InviteCode] @relation(name: "GENERATED", direction: "OUT") - # Wolle: redeemedInviteCode: InviteCode @relation(name: "REDEEMED", direction: "OUT") - - # Is the currently logged in user following that user? - # Wolle: followedByCurrentUser: Boolean! - # @cypher( - # statement: """ - # MATCH (this)<-[:FOLLOWS]-(u:User { id: $cypherParams.currentUserId}) - # RETURN COUNT(u) >= 1 - # """ - # ) - - # Wolle: isBlocked: Boolean! - # @cypher( - # statement: """ - # MATCH (this)<-[:BLOCKED]-(user:User {id: $cypherParams.currentUserId}) - # RETURN COUNT(user) >= 1 - # """ - # ) - # Wolle: blocked: Boolean! - # @cypher( - # statement: """ - # MATCH (this)-[:BLOCKED]-(user:User {id: $cypherParams.currentUserId}) - # RETURN COUNT(user) >= 1 - # """ - # ) - - # Wolle: isMuted: Boolean! - # @cypher( - # statement: """ - # MATCH (this)<-[:MUTED]-(user:User { id: $cypherParams.currentUserId}) - # RETURN COUNT(user) >= 1 - # """ - # ) - - # contributions: [WrittenPost]! - # contributions2(first: Int = 10, offset: Int = 0): [WrittenPost2]! - # @cypher( - # statement: "MATCH (this)-[w:WROTE]->(p:Post) RETURN p as Post, w.timestamp as timestamp" - # ) - # Wolle: needed? - # contributions: [Post]! @relation(name: "WROTE", direction: "OUT") - # contributionsCount: Int! - # @cypher( - # statement: """ - # MATCH (this)-[:WROTE]->(r:Post) - # WHERE NOT r.deleted = true AND NOT r.disabled = true - # RETURN COUNT(r) - # """ - # ) - - # Wolle: comments: [Comment]! @relation(name: "WROTE", direction: "OUT") - # commentedCount: Int! - # @cypher( - # statement: "MATCH (this)-[:WROTE]->(:Comment)-[:COMMENTS]->(p:Post) WHERE NOT p.deleted = true AND NOT p.disabled = true RETURN COUNT(DISTINCT(p))" - # ) - - # Wolle: shouted: [Post]! @relation(name: "SHOUTED", direction: "OUT") - # shoutedCount: Int! - # @cypher( - # statement: "MATCH (this)-[:SHOUTED]->(r:Post) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)" - # ) - - # Wolle: badges: [Badge]! @relation(name: "REWARDED", direction: "IN") - # badgesCount: Int! @cypher(statement: "MATCH (this)<-[:REWARDED]-(r:Badge) RETURN COUNT(r)") - - # Wolle: emotions: [EMOTED] } @@ -141,39 +55,6 @@ input _GroupFilter { id_not: ID id_in: [ID!] id_not_in: [ID!] - # categories: _CategoryFilter - # categories_not: _CategoryFilter - # categories_in: [_CategoryFilter!] - # categories_not_in: [_CategoryFilter!] - # categories_some: _CategoryFilter - # categories_none: _CategoryFilter - # categories_single: _CategoryFilter - # categories_every: _CategoryFilter - # Wolle: - # friends: _GroupFilter - # friends_not: _GroupFilter - # friends_in: [_GroupFilter!] - # friends_not_in: [_GroupFilter!] - # friends_some: _GroupFilter - # friends_none: _GroupFilter - # friends_single: _GroupFilter - # friends_every: _GroupFilter - # following: _GroupFilter - # following_not: _GroupFilter - # following_in: [_GroupFilter!] - # following_not_in: [_GroupFilter!] - # following_some: _GroupFilter - # following_none: _GroupFilter - # following_single: _GroupFilter - # following_every: _GroupFilter - # followedBy: _GroupFilter - # followedBy_not: _GroupFilter - # followedBy_in: [_GroupFilter!] - # followedBy_not_in: [_GroupFilter!] - # followedBy_some: _GroupFilter - # followedBy_none: _GroupFilter - # followedBy_single: _GroupFilter - # followedBy_every: _GroupFilter } type Query { @@ -198,32 +79,8 @@ type Query { AvailableGroupActionRadii: [GroupActionRadius]! AvailableGroupMemberRoles: [GroupMemberRole]! - - # Wolle: - # availableRoles: [UserRole]! - # mutedUsers: [User] - # blockedUsers: [User] - # isLoggedIn: Boolean! - # currentUser: User - # findUsers(query: String!,limit: Int = 10, filter: _GroupFilter): [User]! - # @cypher( - # statement: """ - # CALL db.index.fulltext.queryNodes('user_fulltext_search', $query) - # YIELD node as post, score - # MATCH (user) - # WHERE score >= 0.2 - # AND NOT user.deleted = true AND NOT user.disabled = true - # RETURN user - # LIMIT $limit - # """ - # ) } -# Wolle: enum Deletable { -# Post -# Comment -# } - type Mutation { CreateGroup( id: ID @@ -236,12 +93,7 @@ type Mutation { actionRadius: GroupActionRadius! categoryIds: [ID] locationName: String - ): # Wolle: add group settings - # Wolle: - # showShoutsPublicly: Boolean - # sendNotificationEmails: Boolean - # locale: String - Group + ): Group UpdateGroup( id: ID! @@ -251,19 +103,7 @@ type Mutation { locationName: String about: String description: String - ): # Wolle: - # showShoutsPublicly: Boolean - # sendNotificationEmails: Boolean - # locale: String - Group + ): Group DeleteGroup(id: ID!): Group - - # Wolle: - # muteUser(id: ID!): User - # unmuteUser(id: ID!): User - # blockUser(id: ID!): User - # unblockUser(id: ID!): User - - # Wolle: switchUserRole(role: UserRole!, id: ID!): User } From 3d1b403656969929b4f2163f4d3d095cc961c5ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 9 Aug 2022 16:55:43 +0200 Subject: [PATCH 077/588] Add relation 'CREATED' between owner and group --- backend/src/schema/resolvers/groups.js | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js index 75f9e35df..e6a8c3a18 100644 --- a/backend/src/schema/resolvers/groups.js +++ b/backend/src/schema/resolvers/groups.js @@ -86,6 +86,7 @@ export default { SET group.updatedAt = toString(datetime()) WITH group MATCH (owner:User {id: $userId}) + MERGE (owner)-[:CREATED]->(group) MERGE (owner)-[membership:MEMBER_OF]->(group) SET membership.createdAt = toString(datetime()) SET membership.updatedAt = toString(datetime()) From 85fd02a30f8ddc026723dd0ae0504acbc35ed652 Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 10 Aug 2022 08:05:54 +0200 Subject: [PATCH 078/588] remove grey from sccs branding --- webapp/assets/styles/imports/_branding.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/assets/styles/imports/_branding.scss b/webapp/assets/styles/imports/_branding.scss index fb4c80970..9a0d5a4e1 100644 --- a/webapp/assets/styles/imports/_branding.scss +++ b/webapp/assets/styles/imports/_branding.scss @@ -1,5 +1,5 @@ .header-menu { - background-color: #748885; + // background-color: #748885; } .ds-menu-item-link { color: antiquewhite; From 9cae32e6e13ce27a01b53e2641c5a937361eb401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 10 Aug 2022 08:41:01 +0200 Subject: [PATCH 079/588] Upgrade neode to v0.4.8 --- backend/package.json | 2 +- backend/yarn.lock | 83 +++++++++++++++++++++++++++----------------- 2 files changed, 52 insertions(+), 33 deletions(-) diff --git a/backend/package.json b/backend/package.json index 62188a650..9651cbb95 100644 --- a/backend/package.json +++ b/backend/package.json @@ -103,7 +103,7 @@ "mustache": "^4.2.0", "neo4j-driver": "^4.0.2", "neo4j-graphql-js": "^2.11.5", - "neode": "^0.4.7", + "neode": "^0.4.8", "node-fetch": "~2.6.1", "nodemailer": "^6.4.4", "nodemailer-html-to-text": "^3.2.0", diff --git a/backend/yarn.lock b/backend/yarn.lock index 24bd00b3a..8c69a0814 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -997,9 +997,9 @@ tslib "1.11.1" "@hapi/address@2.x.x": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.2.tgz#1c794cd6dbf2354d1eb1ef10e0303f573e1c7222" - integrity sha512-O4QDrx+JoGKZc6aN64L04vqa7e41tIiLU+OvKdcYaEMP97UttL0f9GIi9/0A4WAMx0uBd6SidDIhktZhgOcN8Q== + version "2.1.4" + resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" + integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== "@hapi/address@^4.0.1": version "4.0.1" @@ -1018,10 +1018,10 @@ resolved "https://registry.yarnpkg.com/@hapi/formula/-/formula-2.0.0.tgz#edade0619ed58c8e4f164f233cda70211e787128" integrity sha512-V87P8fv7PI0LH7LiVi8Lkf3x+KCO7pQozXRssAHNXXL9L1K+uyu4XypLXwxqVDKgyQai6qj3/KteNlrqDx4W5A== -"@hapi/hoek@8.x.x": - version "8.2.4" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.2.4.tgz#684a14f4ca35d46f44abc87dfc696e5e4fe8a020" - integrity sha512-Ze5SDNt325yZvNO7s5C4fXDscjJ6dcqLFXJQ/M7dZRQCewuDj2iDUuBi6jLQt+APbW9RjjVEvLr35FXuOEqjow== +"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0": + version "8.5.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" + integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== "@hapi/hoek@^9.0.0": version "9.0.0" @@ -1055,11 +1055,11 @@ integrity sha512-vzXR5MY7n4XeIvLpfl3HtE3coZYO4raKXW766R6DZw/6aLqR26iuZ109K7a0NtF2Db0jxqh7xz2AxkUwpUFybw== "@hapi/topo@3.x.x": - version "3.1.3" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.3.tgz#c7a02e0d936596d29f184e6d7fdc07e8b5efce11" - integrity sha512-JmS9/vQK6dcUYn7wc2YZTqzIKubAQcJKu2KCKAru6es482U5RT5fP1EXCPtlXpiK7PR0On/kpQKI4fRKkzpZBQ== + version "3.1.6" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29" + integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ== dependencies: - "@hapi/hoek" "8.x.x" + "@hapi/hoek" "^8.3.0" "@hapi/topo@^5.0.0": version "5.0.0" @@ -2681,6 +2681,11 @@ base64-js@^1.0.2: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -2850,6 +2855,14 @@ buffer@4.9.1: ieee754 "^1.1.4" isarray "^1.0.0" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + busboy@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.1.tgz#170899274c5bf38aae27d5c62b71268cd585fd1b" @@ -3929,7 +3942,7 @@ dot-prop@^4.1.0: dotenv@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d" - integrity sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0= + integrity sha512-XcaMACOr3JMVcEv0Y/iUM2XaOsATRZ3U1In41/1jjK6vJZ2PZbQ1bzCG8uvaByfaBpl9gqc9QWJovpUGBXLLYQ== dotenv@^6.1.0: version "6.2.0" @@ -5516,6 +5529,11 @@ ieee754@1.1.13, ieee754@^1.1.4: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ienoopen@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.1.0.tgz#411e5d530c982287dbdc3bb31e7a9c9e32630974" @@ -7528,18 +7546,19 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -neo4j-driver-bolt-connection@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/neo4j-driver-bolt-connection/-/neo4j-driver-bolt-connection-4.3.4.tgz#de642bb6a62ffc6ae2e280dccf21395b4d1705a2" - integrity sha512-yxbvwGav+N7EYjcEAINqL6D3CZV+ee2qLInpAhx+iNurwbl3zqtBGiVP79SZ+7tU++y3Q1fW5ofikH06yc+LqQ== +neo4j-driver-bolt-connection@^4.4.7: + version "4.4.7" + resolved "https://registry.yarnpkg.com/neo4j-driver-bolt-connection/-/neo4j-driver-bolt-connection-4.4.7.tgz#0582d54de1f213e60c374209193d1f645ba523ea" + integrity sha512-6Q4hCtvWE6gzN64N09UqZqf/3rDl7FUWZZXiVQL0ZRbaMkJpZNC2NmrDIgGXYE05XEEbRBexf2tVv5OTYZYrow== dependencies: - neo4j-driver-core "^4.3.4" - text-encoding-utf-8 "^1.0.2" + buffer "^6.0.3" + neo4j-driver-core "^4.4.7" + string_decoder "^1.3.0" -neo4j-driver-core@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/neo4j-driver-core/-/neo4j-driver-core-4.3.4.tgz#b445a4fbf94dce8441075099bd6ac3133c1cf5ee" - integrity sha512-3tn3j6IRUNlpXeehZ9Xv7dLTZPB4a7APaoJ+xhQyMmYQO3ujDM4RFHc0pZcG+GokmaltT5pUCIPTDYx6ODdhcA== +neo4j-driver-core@^4.4.7: + version "4.4.7" + resolved "https://registry.yarnpkg.com/neo4j-driver-core/-/neo4j-driver-core-4.4.7.tgz#d2475e107b3fea2b9d1c36b0c273da5c5a291c37" + integrity sha512-NhvVuQYgG7eO/vXxRaoJfkWUNkjvIpmCIS9UWU9Bbhb4V+wCOyX/MVOXqD0Yizhs4eyIkD7x90OXb79q+vi+oA== neo4j-driver@^4.0.1, neo4j-driver@^4.0.2: version "4.0.2" @@ -7552,13 +7571,13 @@ neo4j-driver@^4.0.1, neo4j-driver@^4.0.2: uri-js "^4.2.2" neo4j-driver@^4.2.2: - version "4.3.4" - resolved "https://registry.yarnpkg.com/neo4j-driver/-/neo4j-driver-4.3.4.tgz#a54f0562f868ee94dff7509df74e3eb2c1f95a85" - integrity sha512-AGrsFFqnoZv4KhJdmKt4mOBV5mnxmV3+/t8KJTOM68jQuEWoy+RlmAaRRaCSU4eY586OFN/R8lg9MrJpZdSFjw== + version "4.4.7" + resolved "https://registry.yarnpkg.com/neo4j-driver/-/neo4j-driver-4.4.7.tgz#51b3fb48241e66eb3be94e90032cc494c44e59f3" + integrity sha512-N7GddPhp12gVJe4eB84u5ik5SmrtRv8nH3rK47Qy7IUKnJkVEos/F1QjOJN6zt1jLnDXwDcGzCKK8XklYpzogw== dependencies: "@babel/runtime" "^7.5.5" - neo4j-driver-bolt-connection "^4.3.4" - neo4j-driver-core "^4.3.4" + neo4j-driver-bolt-connection "^4.4.7" + neo4j-driver-core "^4.4.7" rxjs "^6.6.3" neo4j-graphql-js@^2.11.5: @@ -7574,10 +7593,10 @@ neo4j-graphql-js@^2.11.5: lodash "^4.17.15" neo4j-driver "^4.0.1" -neode@^0.4.7: - version "0.4.7" - resolved "https://registry.yarnpkg.com/neode/-/neode-0.4.7.tgz#033007b57a2ee167e9ee5537493086db08d005eb" - integrity sha512-YXlc187JRpeKCBcUIkY6nimXXG+Tvlopfe71/FPno2THrwmYt5mm0RPHZ+mXF2O1Xg6zvjKvOpCpDz2vHBfroQ== +neode@^0.4.8: + version "0.4.8" + resolved "https://registry.yarnpkg.com/neode/-/neode-0.4.8.tgz#0889b4fc7f1bf0b470b01fa5b8870373b5d47ad6" + integrity sha512-pb91NfCOg4Fj5o+98H+S2XYC+ByQfbdhwcc1UVuzuUQ0Ezzj+jWz8NmKWU8ZfCH6l4plk71yDAPd2eTwpt+Xvg== dependencies: "@hapi/joi" "^15.1.1" dotenv "^4.0.0" @@ -9603,7 +9622,7 @@ string.prototype.trimstart@^1.0.1: define-properties "^1.1.3" es-abstract "^1.17.5" -string_decoder@^1.1.1: +string_decoder@^1.1.1, string_decoder@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== From d50ae27e49412a38c35d925a2ad2955cbc11a2da Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 10 Aug 2022 09:07:32 +0200 Subject: [PATCH 080/588] prework for group list --- webapp/components/GroupForm/GroupForm.vue | 5 ++-- webapp/components/GroupList/GroupList.vue | 27 +++++++++++++++++ webapp/components/GroupTeaser/GroupTeaser.vue | 9 ++++-- webapp/pages/my-groups.vue | 30 +++++++++++++++++++ 4 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 webapp/components/GroupList/GroupList.vue diff --git a/webapp/components/GroupForm/GroupForm.vue b/webapp/components/GroupForm/GroupForm.vue index bff03ec8a..1bd4455d7 100644 --- a/webapp/components/GroupForm/GroupForm.vue +++ b/webapp/components/GroupForm/GroupForm.vue @@ -25,8 +25,8 @@ - zurück - + zurück +
@@ -35,6 +35,7 @@ import CategoriesSelect from '~/components/CategoriesSelect/CategoriesSelect' export default { + name: 'GroupForm', components: { CategoriesSelect, }, diff --git a/webapp/components/GroupList/GroupList.vue b/webapp/components/GroupList/GroupList.vue new file mode 100644 index 000000000..bfaceed21 --- /dev/null +++ b/webapp/components/GroupList/GroupList.vue @@ -0,0 +1,27 @@ + + diff --git a/webapp/components/GroupTeaser/GroupTeaser.vue b/webapp/components/GroupTeaser/GroupTeaser.vue index a199106a5..22df641e9 100644 --- a/webapp/components/GroupTeaser/GroupTeaser.vue +++ b/webapp/components/GroupTeaser/GroupTeaser.vue @@ -1,7 +1,5 @@ + + diff --git a/webapp/pages/my-groups.vue b/webapp/pages/my-groups.vue index 386bb1e51..a861403ed 100644 --- a/webapp/pages/my-groups.vue +++ b/webapp/pages/my-groups.vue @@ -2,15 +2,45 @@
my groups
+
From afb5c719dcf42d165f640a83edd3ba2d46b75c1a Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 10 Aug 2022 09:52:59 +0200 Subject: [PATCH 081/588] add color from yunite in branding --- webapp/assets/styles/imports/_branding.scss | 19 +++++++++++++++++++ webapp/assets/styles/main.scss | 3 ++- .../components/LocaleSwitch/LocaleSwitch.vue | 1 - webapp/constants/headerMenu.js | 4 ++++ webapp/layouts/default.vue | 2 +- 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/webapp/assets/styles/imports/_branding.scss b/webapp/assets/styles/imports/_branding.scss index 9a0d5a4e1..103ae9243 100644 --- a/webapp/assets/styles/imports/_branding.scss +++ b/webapp/assets/styles/imports/_branding.scss @@ -1,3 +1,22 @@ +.main-navigation { + background-color: #748885; +} +.main-navigation .ds-menu-item-link { + color: #c8fc4f;; +} + +.main-navigation .ds-menu-item-link:hover { + color: #f2f2f1;; +} + +.main-navigation .locale-menu { + color: #c8fc4f;; +} + +.base-button { + color: #c8fc4f; +} + .header-menu { // background-color: #748885; } diff --git a/webapp/assets/styles/main.scss b/webapp/assets/styles/main.scss index dc745585d..d797bbf4e 100644 --- a/webapp/assets/styles/main.scss +++ b/webapp/assets/styles/main.scss @@ -1,4 +1,3 @@ -@import './imports/_branding.scss'; @import './imports/_tooltip.scss'; @import './imports/_toast.scss'; @@ -181,3 +180,5 @@ hr { .dropdown-arrow { font-size: $font-size-xx-small; } + +@import './imports/_branding.scss'; \ No newline at end of file diff --git a/webapp/components/LocaleSwitch/LocaleSwitch.vue b/webapp/components/LocaleSwitch/LocaleSwitch.vue index 47e53028b..b302afd76 100644 --- a/webapp/components/LocaleSwitch/LocaleSwitch.vue +++ b/webapp/components/LocaleSwitch/LocaleSwitch.vue @@ -117,7 +117,6 @@ export default { align-items: center; height: 100%; padding: $space-xx-small; - color: $text-color-soft; > .label { margin: 0 $space-xx-small; diff --git a/webapp/constants/headerMenu.js b/webapp/constants/headerMenu.js index 1dfed43d8..06eae4109 100644 --- a/webapp/constants/headerMenu.js +++ b/webapp/constants/headerMenu.js @@ -1,6 +1,10 @@ export default { SHOW_HEADER_MENU: true, MENU: [ + { + name: 'Beiträge', + path: '/#', + }, { name: 'Themen', path: '/#', diff --git a/webapp/layouts/default.vue b/webapp/layouts/default.vue index 4c5d9d0de..b8a377aec 100644 --- a/webapp/layouts/default.vue +++ b/webapp/layouts/default.vue @@ -40,7 +40,7 @@
Date: Wed, 10 Aug 2022 11:34:51 +0200 Subject: [PATCH 082/588] Fix description length for slugify tests --- backend/src/middleware/slugifyMiddleware.spec.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/src/middleware/slugifyMiddleware.spec.js b/backend/src/middleware/slugifyMiddleware.spec.js index 3c18e70b0..59fa72ba7 100644 --- a/backend/src/middleware/slugifyMiddleware.spec.js +++ b/backend/src/middleware/slugifyMiddleware.spec.js @@ -12,6 +12,8 @@ let variables const driver = getDriver() const neode = getNeode() +const descriptionAddition100 = + ' 123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789' beforeAll(async () => { await cleanDatabase() @@ -67,7 +69,7 @@ describe('slugifyMiddleware', () => { ...variables, name: 'The Best Group', about: 'Some about', - description: 'Some description', + description: 'Some description' + descriptionAddition100, groupType: 'closed', actionRadius: 'national', categoryIds, @@ -87,7 +89,7 @@ describe('slugifyMiddleware', () => { name: 'The Best Group', slug: 'the-best-group', about: 'Some about', - description: 'Some description', + description: 'Some description' + descriptionAddition100, groupType: 'closed', actionRadius: 'national', }, From 82401b1488dd6aee9282b6b9f810f480f25edf2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 10 Aug 2022 12:52:20 +0200 Subject: [PATCH 083/588] Update backend/src/schema/resolvers/groups.js Co-authored-by: Moriz Wahl --- backend/src/schema/resolvers/groups.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js index e6a8c3a18..f6d482421 100644 --- a/backend/src/schema/resolvers/groups.js +++ b/backend/src/schema/resolvers/groups.js @@ -36,8 +36,7 @@ export default { const result = await txc.run(groupCypher, { userId: context.user.id, }) - const group = result.records.map((record) => record.get('group')) - return group + return result.records.map((record) => record.get('group')) }) try { const group = await readTxResultPromise From f150ea3d7ce24286127d2ddf8fa08ca977c5ded7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 10 Aug 2022 12:52:31 +0200 Subject: [PATCH 084/588] Update backend/src/schema/resolvers/groups.js Co-authored-by: Moriz Wahl --- backend/src/schema/resolvers/groups.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js index f6d482421..dadbcd2a1 100644 --- a/backend/src/schema/resolvers/groups.js +++ b/backend/src/schema/resolvers/groups.js @@ -39,8 +39,7 @@ export default { return result.records.map((record) => record.get('group')) }) try { - const group = await readTxResultPromise - return group + return await readTxResultPromise } catch (error) { throw new Error(error) } finally { From 5e741ead8d3f96d5d4eacf88a7e7e3f70a361fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 10 Aug 2022 13:15:43 +0200 Subject: [PATCH 085/588] Overtake Moriz suggestions --- backend/src/models/Group.js | 2 - backend/src/schema/resolvers/groups.js | 6 +- backend/src/schema/resolvers/groups.spec.js | 126 +++++++++--------- .../schema/types/enum/GroupActionRadius.gql | 3 +- 4 files changed, 71 insertions(+), 66 deletions(-) diff --git a/backend/src/models/Group.js b/backend/src/models/Group.js index 25149e9c3..a75ad518f 100644 --- a/backend/src/models/Group.js +++ b/backend/src/models/Group.js @@ -37,8 +37,6 @@ export default { locationName: { type: 'string', allow: [null] }, - wasSeeded: 'boolean', // Wolle: used or needed? - isIn: { type: 'relationship', relationship: 'IS_IN', diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js index dadbcd2a1..d1af98513 100644 --- a/backend/src/schema/resolvers/groups.js +++ b/backend/src/schema/resolvers/groups.js @@ -52,17 +52,17 @@ export default { const { categoryIds } = params delete params.categoryIds if (!categoryIds || categoryIds.length < CATEGORIES_MIN) { - throw new UserInputError('To Less Categories!') + throw new UserInputError('Too view categories!') } if (categoryIds && categoryIds.length > CATEGORIES_MAX) { - throw new UserInputError('To Many Categories!') + throw new UserInputError('Too many categories!') } if ( params.description === undefined || params.description === null || removeHtmlTags(params.description).length < DESCRIPTION_WITHOUT_HTML_LENGTH_MIN ) { - throw new UserInputError('To Short Description!') + throw new UserInputError('Description too short!') } params.id = params.id || uuid() const session = context.driver.session() diff --git a/backend/src/schema/resolvers/groups.spec.js b/backend/src/schema/resolvers/groups.spec.js index bae530c61..5354f5ebe 100644 --- a/backend/src/schema/resolvers/groups.spec.js +++ b/backend/src/schema/resolvers/groups.spec.js @@ -120,7 +120,7 @@ describe('Group', () => { about: 'We will change nothing!', description: 'We love it like it is!?' + descriptionAddition100, groupType: 'closed', - actionRadius: 'international', + actionRadius: 'global', categoryIds, }, }) @@ -139,62 +139,68 @@ describe('Group', () => { }) }) - describe('can find', () => { - it('all', async () => { - const expected = { - data: { - Group: expect.arrayContaining([ - expect.objectContaining({ - id: 'my-group', - slug: 'the-best-group', - myRole: 'owner', - }), - expect.objectContaining({ - id: 'others-group', - slug: 'uninteresting-group', - myRole: null, - }), - ]), - }, - errors: undefined, - } - await expect(query({ query: groupQuery, variables: {} })).resolves.toMatchObject(expected) + describe('query groups', () => { + describe('without any filters', () => { + it('finds all groups', async () => { + const expected = { + data: { + Group: expect.arrayContaining([ + expect.objectContaining({ + id: 'my-group', + slug: 'the-best-group', + myRole: 'owner', + }), + expect.objectContaining({ + id: 'others-group', + slug: 'uninteresting-group', + myRole: null, + }), + ]), + }, + errors: undefined, + } + await expect(query({ query: groupQuery, variables: {} })).resolves.toMatchObject(expected) + }) }) - it('where user is member (or owner in this case)', async () => { - const expected = { - data: { - Group: [ - { - id: 'my-group', - slug: 'the-best-group', - myRole: 'owner', - }, - ], - }, - errors: undefined, - } - await expect( - query({ query: groupQuery, variables: { isMember: true } }), - ).resolves.toMatchObject(expected) + describe('isMember = true', () => { + it('finds only groups where user is member', async () => { + const expected = { + data: { + Group: [ + { + id: 'my-group', + slug: 'the-best-group', + myRole: 'owner', + }, + ], + }, + errors: undefined, + } + await expect( + query({ query: groupQuery, variables: { isMember: true } }), + ).resolves.toMatchObject(expected) + }) }) - it('where user is not(!) member', async () => { - const expected = { - data: { - Group: expect.arrayContaining([ - expect.objectContaining({ - id: 'others-group', - slug: 'uninteresting-group', - myRole: null, - }), - ]), - }, - errors: undefined, - } - await expect( - query({ query: groupQuery, variables: { isMember: false } }), - ).resolves.toMatchObject(expected) + describe('isMember = false', () => { + it('finds only groups where user is not(!) member', async () => { + const expected = { + data: { + Group: expect.arrayContaining([ + expect.objectContaining({ + id: 'others-group', + slug: 'uninteresting-group', + myRole: null, + }), + ]), + }, + errors: undefined, + } + await expect( + query({ query: groupQuery, variables: { isMember: false } }), + ).resolves.toMatchObject(expected) + }) }) }) }) @@ -258,7 +264,7 @@ describe('CreateGroup', () => { ) }) - it('"disabled" and "deleted" default to "false"', async () => { + it('has "disabled" and "deleted" default to "false"', async () => { const expected = { data: { CreateGroup: { disabled: false, deleted: false } } } await expect(mutate({ mutation: createGroupMutation, variables })).resolves.toMatchObject( expected, @@ -268,7 +274,7 @@ describe('CreateGroup', () => { describe('description', () => { describe('length without HTML', () => { describe('less then 100 chars', () => { - it('throws error: "To Less Categories!"', async () => { + it('throws error: "Too view categories!"', async () => { const { errors } = await mutate({ mutation: createGroupMutation, variables: { @@ -278,7 +284,7 @@ describe('CreateGroup', () => { '0123456789', }, }) - expect(errors[0]).toHaveProperty('message', 'To Short Description!') + expect(errors[0]).toHaveProperty('message', 'Description too short!') }) }) }) @@ -286,22 +292,22 @@ describe('CreateGroup', () => { describe('categories', () => { describe('not even one', () => { - it('throws error: "To Less Categories!"', async () => { + it('throws error: "Too view categories!"', async () => { const { errors } = await mutate({ mutation: createGroupMutation, variables: { ...variables, categoryIds: null }, }) - expect(errors[0]).toHaveProperty('message', 'To Less Categories!') + expect(errors[0]).toHaveProperty('message', 'Too view categories!') }) }) describe('four', () => { - it('throws error: "To Many Categories!"', async () => { + it('throws error: "Too many categories!"', async () => { const { errors } = await mutate({ mutation: createGroupMutation, variables: { ...variables, categoryIds: ['cat9', 'cat4', 'cat15', 'cat27'] }, }) - expect(errors[0]).toHaveProperty('message', 'To Many Categories!') + expect(errors[0]).toHaveProperty('message', 'Too many categories!') }) }) }) diff --git a/backend/src/schema/types/enum/GroupActionRadius.gql b/backend/src/schema/types/enum/GroupActionRadius.gql index afc421133..221ed7f87 100644 --- a/backend/src/schema/types/enum/GroupActionRadius.gql +++ b/backend/src/schema/types/enum/GroupActionRadius.gql @@ -2,5 +2,6 @@ enum GroupActionRadius { regional national continental - international + global + interplanetary } From b0d28f8649bba912a11263f206d6d368b579b648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 10 Aug 2022 13:19:42 +0200 Subject: [PATCH 086/588] Rename 'descriptionAddition100' to 'descriptionAdditional100' --- backend/src/middleware/slugifyMiddleware.spec.js | 6 +++--- backend/src/schema/resolvers/groups.spec.js | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/src/middleware/slugifyMiddleware.spec.js b/backend/src/middleware/slugifyMiddleware.spec.js index 59fa72ba7..9605aada9 100644 --- a/backend/src/middleware/slugifyMiddleware.spec.js +++ b/backend/src/middleware/slugifyMiddleware.spec.js @@ -12,7 +12,7 @@ let variables const driver = getDriver() const neode = getNeode() -const descriptionAddition100 = +const descriptionAdditional100 = ' 123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789' beforeAll(async () => { @@ -69,7 +69,7 @@ describe('slugifyMiddleware', () => { ...variables, name: 'The Best Group', about: 'Some about', - description: 'Some description' + descriptionAddition100, + description: 'Some description' + descriptionAdditional100, groupType: 'closed', actionRadius: 'national', categoryIds, @@ -89,7 +89,7 @@ describe('slugifyMiddleware', () => { name: 'The Best Group', slug: 'the-best-group', about: 'Some about', - description: 'Some description' + descriptionAddition100, + description: 'Some description' + descriptionAdditional100, groupType: 'closed', actionRadius: 'national', }, diff --git a/backend/src/schema/resolvers/groups.spec.js b/backend/src/schema/resolvers/groups.spec.js index 5354f5ebe..b3327d44a 100644 --- a/backend/src/schema/resolvers/groups.spec.js +++ b/backend/src/schema/resolvers/groups.spec.js @@ -13,7 +13,7 @@ let authenticatedUser let user const categoryIds = ['cat9', 'cat4', 'cat15'] -const descriptionAddition100 = +const descriptionAdditional100 = ' 123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789' let variables = {} @@ -118,7 +118,7 @@ describe('Group', () => { id: 'others-group', name: 'Uninteresting Group', about: 'We will change nothing!', - description: 'We love it like it is!?' + descriptionAddition100, + description: 'We love it like it is!?' + descriptionAdditional100, groupType: 'closed', actionRadius: 'global', categoryIds, @@ -131,7 +131,7 @@ describe('Group', () => { id: 'my-group', name: 'The Best Group', about: 'We will change the world!', - description: 'Some description' + descriptionAddition100, + description: 'Some description' + descriptionAdditional100, groupType: 'public', actionRadius: 'regional', categoryIds, @@ -214,7 +214,7 @@ describe('CreateGroup', () => { name: 'The Best Group', slug: 'the-group', about: 'We will change the world!', - description: 'Some description' + descriptionAddition100, + description: 'Some description' + descriptionAdditional100, groupType: 'public', actionRadius: 'regional', categoryIds, From d2f6590e057d94e1d2e7678069b027608efb6564 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Aug 2022 04:25:39 +0000 Subject: [PATCH 087/588] Bump vue-sweetalert-icons from 4.3.0 to 4.3.1 in /webapp Bumps [vue-sweetalert-icons](https://github.com/JorgenVatle/vue-sweetalert-icons) from 4.3.0 to 4.3.1. - [Release notes](https://github.com/JorgenVatle/vue-sweetalert-icons/releases) - [Commits](https://github.com/JorgenVatle/vue-sweetalert-icons/compare/v4.3.0...v4.3.1) --- updated-dependencies: - dependency-name: vue-sweetalert-icons dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- webapp/package.json | 2 +- webapp/yarn.lock | 325 +++----------------------------------------- 2 files changed, 21 insertions(+), 306 deletions(-) diff --git a/webapp/package.json b/webapp/package.json index 234149521..5b6b381a0 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -99,7 +99,7 @@ "vue-izitoast": "^1.2.1", "vue-observe-visibility": "^1.0.0", "vue-scrollto": "^2.20.0", - "vue-sweetalert-icons": "~4.3.0", + "vue-sweetalert-icons": "~4.3.1", "vuex-i18n": "~1.13.1", "xregexp": "^4.3.0", "zxcvbn": "^4.4.2" diff --git a/webapp/yarn.lock b/webapp/yarn.lock index ef71a2a53..0b7dcf028 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -5538,11 +5538,6 @@ alphanum-sort@^1.0.0: resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= -amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= - ansi-align@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" @@ -6223,11 +6218,6 @@ array-filter@~0.0.0: resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" integrity sha1-fajPLiZijtcygDWB/SH2fKzS7uw= -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -6392,11 +6382,6 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -async-foreach@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" - integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= - async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" @@ -7016,13 +7001,6 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= - dependencies: - inherits "~2.0.0" - bluebird@^3.1.1, bluebird@^3.5.1: version "3.5.4" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.4.tgz#d6cc661595de30d5b3af5fcedd3c0b3ef6ec5714" @@ -7450,19 +7428,6 @@ camelcase-css@2.0.1: resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= - camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" @@ -7567,7 +7532,7 @@ chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3. escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: +chalk@^1.0.0, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= @@ -8568,14 +8533,6 @@ cross-spawn@7.0.3: shebang-command "^2.0.0" which "^2.0.1" -cross-spawn@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" - integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI= - dependencies: - lru-cache "^4.0.1" - which "^1.2.9" - cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -8915,13 +8872,6 @@ cuint@^0.2.2: resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" integrity sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs= -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= - dependencies: - array-find-index "^1.0.1" - cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" @@ -9000,7 +8950,7 @@ debug@^3.0.0, debug@^3.0.1, debug@^3.1.0, debug@^3.2.6: dependencies: ms "^2.1.1" -decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.1.1, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -10805,16 +10755,6 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -fstream@^1.0.0, fstream@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" - integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - function-bind@^1.0.2, function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -10859,7 +10799,7 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -gaze@1.1.3, gaze@^1.0.0: +gaze@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== @@ -10911,11 +10851,6 @@ get-intrinsic@^1.0.2: has "^1.0.3" has-symbols "^1.0.1" -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= - get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" @@ -11046,7 +10981,7 @@ glob@7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1: +glob@^7.0.0, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -11995,18 +11930,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -in-publish@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" - integrity sha1-4g/146KvwmkDILbcVSaCqcf631E= - -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= - dependencies: - repeating "^2.0.0" - indent-string@^3.0.0, indent-string@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" @@ -12035,7 +11958,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -12359,13 +12282,6 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= - dependencies: - number-is-nan "^1.0.0" - is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -13215,11 +13131,6 @@ jimp-compact@^0.8.0: resolved "https://registry.yarnpkg.com/jimp-compact/-/jimp-compact-0.8.4.tgz#0878a0c30f22d2d4f8b33e96722eb09d20770627" integrity sha512-9mvZ7/TJ28bWtdx0RxmfiOTzSom4zuRniFTLtJHfNL6HxQdnRtjmX8XIRjmofgVXj2TW/GgSuZKB3dSZ5hNhKg== -js-base64@^2.1.8: - version "2.5.1" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121" - integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw== - js-beautify@^1.6.12: version "1.10.2" resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.2.tgz#88c9099cd6559402b124cfab18754936f8a7b178" @@ -13754,7 +13665,7 @@ loader-utils@^0.2.16: json5 "^0.5.0" object-assign "^4.0.1" -loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.0.4, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: +loader-utils@^1.0.2, loader-utils@^1.0.4, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== @@ -13913,7 +13824,7 @@ lodash.xorby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.xorby/-/lodash.xorby-4.7.0.tgz#9c19a6f9f063a6eb53dd03c1b6871799801463d7" integrity sha1-nBmm+fBjputT3QPBtocXmYAUY9c= -lodash@4.x, lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10: +lodash@4.x, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -13958,14 +13869,6 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - lower-case-first@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1" @@ -14102,11 +14005,6 @@ map-cache@^0.2.2: resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= - map-or-similar@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/map-or-similar/-/map-or-similar-1.5.0.tgz#6de2653174adfb5d9edc33c69d3e92a1b76faf08" @@ -14229,22 +14127,6 @@ mensch@0.3.4: resolved "https://registry.yarnpkg.com/mensch/-/mensch-0.3.4.tgz#770f91b46cb16ea5b204ee735768c3f0c491fecd" integrity sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g== -meow@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -14420,7 +14302,7 @@ minimist@^0.1.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.1.0.tgz#99df657a52574c21c9057497df742790b2b4c0de" integrity sha1-md9lelJXTCHJBXSX33QnkLK0wN4= -minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: +minimist@^1.1.1, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= @@ -14512,7 +14394,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.1: +mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.1: version "0.5.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== @@ -14566,7 +14448,7 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.12.1, nan@^2.13.2: +nan@^2.12.1: version "2.13.2" resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw== @@ -14685,24 +14567,6 @@ node-fetch@^2.1.2, node-fetch@^2.2.0, node-fetch@^2.6.0, node-fetch@^2.6.1: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== -node-gyp@^3.8.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" - integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== - dependencies: - fstream "^1.0.0" - glob "^7.0.3" - graceful-fs "^4.1.2" - mkdirp "^0.5.0" - nopt "2 || 3" - npmlog "0 || 1 || 2 || 3 || 4" - osenv "0" - request "^2.87.0" - rimraf "2" - semver "~5.3.0" - tar "^2.0.0" - which "1" - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -14816,29 +14680,6 @@ node-res@^5.0.1: on-finished "^2.3.0" vary "^1.1.2" -node-sass@^4.12.0: - version "4.13.1" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.13.1.tgz#9db5689696bb2eec2c32b98bfea4c7a2e992d0a3" - integrity sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw== - dependencies: - async-foreach "^0.1.3" - chalk "^1.1.1" - cross-spawn "^3.0.0" - gaze "^1.0.0" - get-stdin "^4.0.1" - glob "^7.0.3" - in-publish "^2.0.0" - lodash "^4.17.15" - meow "^3.7.0" - mkdirp "^0.5.1" - nan "^2.13.2" - node-gyp "^3.8.0" - npmlog "^4.0.0" - request "^2.88.0" - sass-graph "^2.2.4" - stdout-stream "^1.4.0" - "true-case-path" "^1.0.2" - nodemon@^1.19.4: version "1.19.4" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.19.4.tgz#56db5c607408e0fdf8920d2b444819af1aae0971" @@ -14855,13 +14696,6 @@ nodemon@^1.19.4: undefsafe "^2.0.2" update-notifier "^2.5.0" -"nopt@2 || 3": - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= - dependencies: - abbrev "1" - nopt@^4.0.1, nopt@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" @@ -14877,7 +14711,7 @@ nopt@~1.0.10: dependencies: abbrev "1" -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0: +normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -14953,7 +14787,7 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" -"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2, npmlog@^4.1.2: +npmlog@^4.0.2, npmlog@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -15273,7 +15107,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@0, osenv@^0.1.4: +osenv@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -17627,14 +17461,6 @@ recursive-readdir@2.2.2: dependencies: minimatch "3.0.4" -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - redeyed@~2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-2.1.1.tgz#8984b5815d99cb220469c99eeeffe38913e6cc0b" @@ -17887,13 +17713,6 @@ repeat-string@^1.5.4, repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= - dependencies: - is-finite "^1.0.0" - request-promise-core@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" @@ -17910,7 +17729,7 @@ request-promise-native@^1.0.5, request-promise-native@^1.0.8: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -"request@>=2.76.0 <3.0.0", request@^2.87.0, request@^2.88.0, request@^2.88.2: +"request@>=2.76.0 <3.0.0", request@^2.87.0, request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -18062,7 +17881,7 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= -rimraf@2, rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@~2.6.2: +rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@~2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -18183,27 +18002,6 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sass-graph@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" - integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k= - dependencies: - glob "^7.0.0" - lodash "^4.0.0" - scss-tokenizer "^0.2.3" - yargs "^7.0.0" - -sass-loader@^7.1.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.3.1.tgz#a5bf68a04bcea1c13ff842d747150f7ab7d0d23f" - integrity sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA== - dependencies: - clone-deep "^4.0.1" - loader-utils "^1.0.1" - neo-async "^2.5.0" - pify "^4.0.1" - semver "^6.3.0" - sass-loader@~10.1.1: version "10.1.1" resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-10.1.1.tgz#4ddd5a3d7638e7949065dd6e9c7c04037f7e663d" @@ -18296,14 +18094,6 @@ schema-utils@^3.0.0: ajv "^6.12.5" ajv-keywords "^3.5.2" -scss-tokenizer@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" - integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE= - dependencies: - js-base64 "^2.1.8" - source-map "^0.4.2" - select@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" @@ -18345,11 +18135,6 @@ semver@^7.3.4: dependencies: lru-cache "^6.0.0" -semver@~5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= - send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -18739,13 +18524,6 @@ source-map@0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= -source-map@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" - integrity sha1-66T12pwNyZneaAMti092FzZSA2s= - dependencies: - amdefine ">=0.0.4" - source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -18905,13 +18683,6 @@ std-env@^2.2.1: dependencies: ci-info "^1.6.0" -stdout-stream@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" - integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== - dependencies: - readable-stream "^2.0.1" - stealthy-require@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" @@ -19212,13 +18983,6 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= - dependencies: - get-stdin "^4.0.1" - strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -19420,15 +19184,6 @@ tapable@^1.0.0, tapable@^1.0.0-beta.5, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tar@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" - integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== - dependencies: - block-stream "*" - fstream "^1.0.12" - inherits "2" - tar@^4: version "4.4.8" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" @@ -19888,11 +19643,6 @@ treeify@^1.1.0: resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8" integrity sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A== -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= - trim-trailing-lines@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz#bd4abbec7cc880462f10b2c8b5ce1d8d1ec7c2c0" @@ -19908,13 +19658,6 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== -"true-case-path@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" - integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew== - dependencies: - glob "^7.1.2" - trunc-html@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/trunc-html/-/trunc-html-1.1.2.tgz#1e97d51f67d470b67662b1a670e6d0ea7a8edafe" @@ -20878,14 +20621,12 @@ vue-svg-loader@~0.16.0: loader-utils "^1.2.3" svg-to-vue "^0.7.0" -vue-sweetalert-icons@~4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/vue-sweetalert-icons/-/vue-sweetalert-icons-4.3.0.tgz#0808632cb6bfa67bf07afab1ae683352c038af7d" - integrity sha512-8SgzgyqppIj/gQt6Y5JLXPnqt1pEq50w6TeQ1B3aVd1mWm3gHTeWHWujiycjouo8too1fgtWkn3mi16vumKSJw== +vue-sweetalert-icons@~4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/vue-sweetalert-icons/-/vue-sweetalert-icons-4.3.1.tgz#dad763abb5084b015ba3e209dd28dcf1371b030c" + integrity sha512-FqKcMB8Ebgb32UyzvhIBzj23U0NRP91cTXovDYfYwNHpJ1TAFBEHoemgyu01h2Wp+UJhytvQ+13GL+GAs8QkWw== dependencies: color "^3.1.2" - node-sass "^4.12.0" - sass-loader "^7.1.0" validate-color "^2.1.0" vue-template-compiler@^2.6.11: @@ -21228,7 +20969,7 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@1, which@^1.2.9, which@^1.3.1: +which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -21515,13 +21256,6 @@ yargs-parser@^4.2.0: dependencies: camelcase "^3.0.0" -yargs-parser@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" - integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= - dependencies: - camelcase "^3.0.0" - yargs@6.6.0: version "6.6.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" @@ -21558,25 +21292,6 @@ yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" - integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= - dependencies: - camelcase "^3.0.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.2" - which-module "^1.0.0" - y18n "^3.2.1" - yargs-parser "^5.0.0" - yargs@~1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/yargs/-/yargs-1.2.6.tgz#9c7b4a82fd5d595b2bf17ab6dcc43135432fe34b" From addfc39c4c3b1a6132b4e1b82061a01ed651fb48 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 11 Aug 2022 11:10:52 +0200 Subject: [PATCH 088/588] add groupe site id und slug --- webapp/components/GroupForm/GroupForm.vue | 60 +++++++-------- webapp/components/GroupList/GroupCard.vue | 50 ++++++++++++ webapp/components/GroupList/GroupList.vue | 73 +++++++++++++----- webapp/components/GroupMember/GroupMember.vue | 67 ++++++++++++++++ webapp/components/GroupTeaser/GroupTeaser.vue | 6 +- webapp/pages/group/_id.vue | 9 +++ webapp/pages/group/_id/_slug.vue | 6 ++ webapp/pages/group/create.vue | 7 +- webapp/pages/my-groups.vue | 76 ++++++++++++------- 9 files changed, 270 insertions(+), 84 deletions(-) create mode 100644 webapp/components/GroupList/GroupCard.vue create mode 100644 webapp/components/GroupMember/GroupMember.vue create mode 100644 webapp/pages/group/_id.vue create mode 100644 webapp/pages/group/_id/_slug.vue diff --git a/webapp/components/GroupForm/GroupForm.vue b/webapp/components/GroupForm/GroupForm.vue index 1bd4455d7..703adc45c 100644 --- a/webapp/components/GroupForm/GroupForm.vue +++ b/webapp/components/GroupForm/GroupForm.vue @@ -1,32 +1,31 @@ @@ -44,19 +43,20 @@ export default { name: '', status: '', description: '', + disable: false, } }, - + methods: { - submit() { - console.log('handleSubmit') + submit() { + console.log('handleSubmit') + }, + handleSubmit() { + console.log('handleSubmit') + }, + reset() { + console.log('handleSubmit') + }, }, - handleSubmit() { - console.log('handleSubmit') - }, - reset() { - console.log('handleSubmit') - }, - }, } diff --git a/webapp/components/GroupList/GroupCard.vue b/webapp/components/GroupList/GroupCard.vue new file mode 100644 index 000000000..4ae9f807f --- /dev/null +++ b/webapp/components/GroupList/GroupCard.vue @@ -0,0 +1,50 @@ + + diff --git a/webapp/components/GroupList/GroupList.vue b/webapp/components/GroupList/GroupList.vue index bfaceed21..69df8acb7 100644 --- a/webapp/components/GroupList/GroupList.vue +++ b/webapp/components/GroupList/GroupList.vue @@ -1,27 +1,58 @@ diff --git a/webapp/components/GroupMember/GroupMember.vue b/webapp/components/GroupMember/GroupMember.vue new file mode 100644 index 000000000..f83b00685 --- /dev/null +++ b/webapp/components/GroupMember/GroupMember.vue @@ -0,0 +1,67 @@ + + diff --git a/webapp/components/GroupTeaser/GroupTeaser.vue b/webapp/components/GroupTeaser/GroupTeaser.vue index 22df641e9..33a50dca7 100644 --- a/webapp/components/GroupTeaser/GroupTeaser.vue +++ b/webapp/components/GroupTeaser/GroupTeaser.vue @@ -21,9 +21,7 @@
- diff --git a/webapp/pages/group/_id.vue b/webapp/pages/group/_id.vue new file mode 100644 index 000000000..7ce25e827 --- /dev/null +++ b/webapp/pages/group/_id.vue @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/webapp/pages/group/_id/_slug.vue b/webapp/pages/group/_id/_slug.vue new file mode 100644 index 000000000..36f2ccb2b --- /dev/null +++ b/webapp/pages/group/_id/_slug.vue @@ -0,0 +1,6 @@ + diff --git a/webapp/pages/group/create.vue b/webapp/pages/group/create.vue index 9463083f1..e82fadd6e 100644 --- a/webapp/pages/group/create.vue +++ b/webapp/pages/group/create.vue @@ -1,19 +1,24 @@ - diff --git a/webapp/pages/my-groups.vue b/webapp/pages/my-groups.vue index a861403ed..81843f5d2 100644 --- a/webapp/pages/my-groups.vue +++ b/webapp/pages/my-groups.vue @@ -2,45 +2,65 @@
my groups
- + +
+
+
From 46d26a0ef8ab16b32662e53f763e25fc676b6037 Mon Sep 17 00:00:00 2001 From: ogerly Date: Sun, 14 Aug 2022 11:45:33 +0200 Subject: [PATCH 089/588] add graphql groups, add createGroup mutation --- webapp/components/GroupForm/GroupForm.vue | 41 +++++---- webapp/graphql/groups.js | 107 ++++++++++++++++++++++ webapp/pages/group/create.vue | 40 +++++++- 3 files changed, 171 insertions(+), 17 deletions(-) create mode 100644 webapp/graphql/groups.js diff --git a/webapp/components/GroupForm/GroupForm.vue b/webapp/components/GroupForm/GroupForm.vue index 703adc45c..2cbc67464 100644 --- a/webapp/components/GroupForm/GroupForm.vue +++ b/webapp/components/GroupForm/GroupForm.vue @@ -2,25 +2,25 @@
- + - + -
{{ name }}
-
{{ status }}
-
{{ description }}
+
{{ form.name }}
+
{{ form.status }}
+
{{ form.description }}
Reset form - Save group + Save group
@@ -38,24 +38,33 @@ export default { components: { CategoriesSelect, }, + props:{ + value: { + type: Object, + default: () => ({}), + required: true, + } + }, data() { return { - name: '', - status: '', - description: '', - disable: false, + form: { + name: '', + status: '', + description: '', + disable: false, + } + } }, methods: { submit() { - console.log('handleSubmit') - }, - handleSubmit() { - console.log('handleSubmit') + console.log('submit', this.form) + this.$emit('createGroup', this.form) + }, reset() { - console.log('handleSubmit') + console.log('reset') }, }, } diff --git a/webapp/graphql/groups.js b/webapp/graphql/groups.js new file mode 100644 index 000000000..c41f06e4d --- /dev/null +++ b/webapp/graphql/groups.js @@ -0,0 +1,107 @@ +import gql from 'graphql-tag' + +// ------ mutations + +export const createGroupMutation = gql` + mutation ( + $id: ID + $name: String! + $slug: String + $about: String + $description: String! + $groupType: GroupType! + $actionRadius: GroupActionRadius! + $categoryIds: [ID] + ) { + CreateGroup( + id: $id + name: $name + slug: $slug + about: $about + description: $description + groupType: $groupType + actionRadius: $actionRadius + categoryIds: $categoryIds + ) { + id + name + slug + createdAt + updatedAt + disabled + deleted + about + description + groupType + actionRadius + myRole + # Wolle: owner { + # name + # } + } + } +` + +// ------ queries + +export const groupQuery = gql` + query ( + $isMember: Boolean + $id: ID + $name: String + $slug: String + $createdAt: String + $updatedAt: String + $about: String + $description: String + # $groupType: GroupType!, + # $actionRadius: GroupActionRadius!, + # $categoryIds: [ID] + $locationName: String + $first: Int + $offset: Int + $orderBy: [_GroupOrdering] + $filter: _GroupFilter + ) { + Group( + isMember: $isMember + id: $id + name: $name + slug: $slug + createdAt: $createdAt + updatedAt: $updatedAt + about: $about + description: $description + # groupType: $groupType + # actionRadius: $actionRadius + # categoryIds: $categoryIds + locationName: $locationName + first: $first + offset: $offset + orderBy: $orderBy + filter: $filter + ) { + id + name + slug + createdAt + updatedAt + disabled + deleted + about + description + groupType + actionRadius + myRole + categories { + id + slug + name + icon + } + # Wolle: owner { + # name + # } + } + } +` diff --git a/webapp/pages/group/create.vue b/webapp/pages/group/create.vue index e82fadd6e..c76be5360 100644 --- a/webapp/pages/group/create.vue +++ b/webapp/pages/group/create.vue @@ -2,7 +2,7 @@
- +   @@ -14,11 +14,49 @@ From c2a769f325c98665f97ebb1366a7e85ddec70f51 Mon Sep 17 00:00:00 2001 From: ogerly Date: Sun, 14 Aug 2022 12:49:15 +0200 Subject: [PATCH 090/588] add CategoriesSelect in GroupForm.vue --- webapp/components/GroupForm/GroupForm.vue | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/webapp/components/GroupForm/GroupForm.vue b/webapp/components/GroupForm/GroupForm.vue index 2cbc67464..8e29bf300 100644 --- a/webapp/components/GroupForm/GroupForm.vue +++ b/webapp/components/GroupForm/GroupForm.vue @@ -14,9 +14,13 @@ +
{{ form.name }}
{{ form.status }}
{{ form.description }}
+
{{ form.categoryIds }}
Reset form @@ -39,19 +43,18 @@ export default { CategoriesSelect, }, props:{ - value: { - type: Object, - default: () => ({}), - required: true, - } + model: { type: String, required: true }, + value: { type: String, default: '' }, }, data() { return { + categoriesActive: this.$env.CATEGORIES_ACTIVE, form: { name: '', status: '', description: '', disable: false, + categoryIds: [], } } From dd876c52fab328eabccb1379923f2dbf6ba9891d Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 15 Aug 2022 10:52:31 +0200 Subject: [PATCH 091/588] increas max-old-space-size for jest, handle some asyncs, test validation for caregories only if categories are active --- backend/package.json | 2 +- backend/src/middleware/excerptMiddleware.js | 15 ++++-------- .../src/middleware/slugifyMiddleware.spec.js | 24 +++++++++---------- backend/src/schema/resolvers/groups.js | 6 ++--- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/backend/package.json b/backend/package.json index 9651cbb95..9aa7f539f 100644 --- a/backend/package.json +++ b/backend/package.json @@ -15,7 +15,7 @@ "dev": "nodemon --exec babel-node src/ -e js,gql", "dev:debug": "nodemon --exec babel-node --inspect=0.0.0.0:9229 src/ -e js,gql", "lint": "eslint src --config .eslintrc.js", - "test": "cross-env NODE_ENV=test jest --forceExit --detectOpenHandles --runInBand --coverage", + "test": "cross-env NODE_ENV=test NODE_OPTIONS=--max-old-space-size=8192 jest --forceExit --detectOpenHandles --runInBand --coverage", "db:clean": "babel-node src/db/clean.js", "db:reset": "yarn run db:clean", "db:seed": "babel-node src/db/seed.js", diff --git a/backend/src/middleware/excerptMiddleware.js b/backend/src/middleware/excerptMiddleware.js index cfaf7f1b0..ca061609a 100644 --- a/backend/src/middleware/excerptMiddleware.js +++ b/backend/src/middleware/excerptMiddleware.js @@ -4,28 +4,23 @@ export default { Mutation: { CreateGroup: async (resolve, root, args, context, info) => { args.descriptionExcerpt = trunc(args.description, 120).html - const result = await resolve(root, args, context, info) - return result + return resolve(root, args, context, info) }, CreatePost: async (resolve, root, args, context, info) => { args.contentExcerpt = trunc(args.content, 120).html - const result = await resolve(root, args, context, info) - return result + return resolve(root, args, context, info) }, UpdatePost: async (resolve, root, args, context, info) => { args.contentExcerpt = trunc(args.content, 120).html - const result = await resolve(root, args, context, info) - return result + return resolve(root, args, context, info) }, CreateComment: async (resolve, root, args, context, info) => { args.contentExcerpt = trunc(args.content, 180).html - const result = await resolve(root, args, context, info) - return result + return resolve(root, args, context, info) }, UpdateComment: async (resolve, root, args, context, info) => { args.contentExcerpt = trunc(args.content, 180).html - const result = await resolve(root, args, context, info) - return result + return resolve(root, args, context, info) }, }, } diff --git a/backend/src/middleware/slugifyMiddleware.spec.js b/backend/src/middleware/slugifyMiddleware.spec.js index 9605aada9..3fea526ee 100644 --- a/backend/src/middleware/slugifyMiddleware.spec.js +++ b/backend/src/middleware/slugifyMiddleware.spec.js @@ -6,7 +6,6 @@ import { createGroupMutation } from '../db/graphql/groups' import { createPostMutation } from '../db/graphql/posts' import { signupVerificationMutation } from '../db/graphql/authentications' -let mutate let authenticatedUser let variables @@ -15,19 +14,20 @@ const neode = getNeode() const descriptionAdditional100 = ' 123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789' +const { server } = createServer({ + context: () => { + return { + driver, + neode, + user: authenticatedUser, + } + }, +}) + +const { mutate } = createTestClient(server) + beforeAll(async () => { await cleanDatabase() - - const { server } = createServer({ - context: () => { - return { - driver, - neode, - user: authenticatedUser, - } - }, - }) - mutate = createTestClient(server).mutate }) afterAll(async () => { diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js index d1af98513..5737f5505 100644 --- a/backend/src/schema/resolvers/groups.js +++ b/backend/src/schema/resolvers/groups.js @@ -51,10 +51,10 @@ export default { CreateGroup: async (_parent, params, context, _resolveInfo) => { const { categoryIds } = params delete params.categoryIds - if (!categoryIds || categoryIds.length < CATEGORIES_MIN) { + if (CONFIG.CATEGORIES_ACTIVE && (!categoryIds || categoryIds.length < CATEGORIES_MIN)) { throw new UserInputError('Too view categories!') } - if (categoryIds && categoryIds.length > CATEGORIES_MAX) { + if (CONFIG.CATEGORIES_ACTIVE && categoryIds && categoryIds.length > CATEGORIES_MAX) { throw new UserInputError('Too many categories!') } if ( @@ -94,7 +94,7 @@ export default { `, { userId: context.user.id, categoryIds, params }, ) - const [group] = ownerCreateGroupTransactionResponse.records.map((record) => + const [group] = await ownerCreateGroupTransactionResponse.records.map((record) => record.get('group'), ) return group From beacad4a17b33ececa908b6fe655626f1487f949 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 15 Aug 2022 11:07:45 +0200 Subject: [PATCH 092/588] set CONFIG in specs --- backend/src/schema/resolvers/groups.spec.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/src/schema/resolvers/groups.spec.js b/backend/src/schema/resolvers/groups.spec.js index b3327d44a..707558a06 100644 --- a/backend/src/schema/resolvers/groups.spec.js +++ b/backend/src/schema/resolvers/groups.spec.js @@ -3,6 +3,7 @@ import Factory, { cleanDatabase } from '../../db/factories' import { createGroupMutation, groupQuery } from '../../db/graphql/groups' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' +import CONFIG from '../../config' const driver = getDriver() const neode = getNeode() @@ -291,6 +292,10 @@ describe('CreateGroup', () => { }) describe('categories', () => { + beforeEach(() => { + CONFIG.CATEGORIES_ACTIVE = true + }) + describe('not even one', () => { it('throws error: "Too view categories!"', async () => { const { errors } = await mutate({ From 2d0ba9982bc1ce7db6d96af878aa2bd9e11a14ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 15 Aug 2022 12:17:16 +0200 Subject: [PATCH 093/588] Add '--logHeapUsage' to jest test call --- backend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/package.json b/backend/package.json index 62188a650..e619874af 100644 --- a/backend/package.json +++ b/backend/package.json @@ -15,7 +15,7 @@ "dev": "nodemon --exec babel-node src/ -e js,gql", "dev:debug": "nodemon --exec babel-node --inspect=0.0.0.0:9229 src/ -e js,gql", "lint": "eslint src --config .eslintrc.js", - "test": "cross-env NODE_ENV=test jest --forceExit --detectOpenHandles --runInBand --coverage", + "test": "cross-env NODE_ENV=test jest --forceExit --detectOpenHandles --runInBand --coverage --logHeapUsage", "db:clean": "babel-node src/db/clean.js", "db:reset": "yarn run db:clean", "db:seed": "babel-node src/db/seed.js", From 916dfbb46ed08cb7e786b9b16b723ca78c0ccf7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 15 Aug 2022 14:00:36 +0200 Subject: [PATCH 094/588] Move or use GQL mutations in seeding to or from separate files --- backend/src/db/graphql/comments.js | 15 +++++++++++++++ backend/src/db/graphql/posts.js | 5 +++-- backend/src/db/seed.js | 18 +++--------------- 3 files changed, 21 insertions(+), 17 deletions(-) create mode 100644 backend/src/db/graphql/comments.js diff --git a/backend/src/db/graphql/comments.js b/backend/src/db/graphql/comments.js new file mode 100644 index 000000000..b408c5e95 --- /dev/null +++ b/backend/src/db/graphql/comments.js @@ -0,0 +1,15 @@ +import gql from 'graphql-tag' + +// ------ mutations + +export const createCommentMutation = gql` + mutation ($id: ID, $postId: ID!, $content: String!) { + CreateComment(id: $id, postId: $postId, content: $content) { + id + } + } +` + +// ------ queries + +// fill queries in here diff --git a/backend/src/db/graphql/posts.js b/backend/src/db/graphql/posts.js index 3277af820..237446d41 100644 --- a/backend/src/db/graphql/posts.js +++ b/backend/src/db/graphql/posts.js @@ -3,8 +3,9 @@ import gql from 'graphql-tag' // ------ mutations export const createPostMutation = gql` - mutation ($title: String!, $content: String!, $categoryIds: [ID]!, $slug: String) { - CreatePost(title: $title, content: $content, categoryIds: $categoryIds, slug: $slug) { + mutation ($id: ID, $title: String!, $slug: String, $content: String!, $categoryIds: [ID]!) { + CreatePost(id: $id, title: $title, slug: $slug, content: $content, categoryIds: $categoryIds) { + id slug } } diff --git a/backend/src/db/seed.js b/backend/src/db/seed.js index 46c5870e0..0a0926f06 100644 --- a/backend/src/db/seed.js +++ b/backend/src/db/seed.js @@ -5,7 +5,9 @@ import createServer from '../server' import faker from '@faker-js/faker' import Factory from '../db/factories' import { getNeode, getDriver } from '../db/neo4j' -import { gql } from '../helpers/jest' +// import { createGroupMutation } from './graphql/groups' +import { createPostMutation } from './graphql/posts' +import { createCommentMutation } from './graphql/comments' if (CONFIG.PRODUCTION && !CONFIG.PRODUCTION_DB_CLEAN_ALLOW) { throw new Error(`You cannot seed the database in a non-staging and real production environment!`) @@ -558,13 +560,6 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] 'See #NaturphilosophieYoga, it can really help you!' const hashtagAndMention1 = 'The new physics of #QuantenFlussTheorie can explain #QuantumGravity! @peter-lustig got that already. ;-)' - const createPostMutation = gql` - mutation ($id: ID, $title: String!, $content: String!, $categoryIds: [ID]) { - CreatePost(id: $id, title: $title, content: $content, categoryIds: $categoryIds) { - id - } - } - ` await Promise.all([ mutate({ @@ -615,13 +610,6 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] 'I heard @jenny-rostock has practiced it for 3 years now.' const mentionInComment2 = 'Did @peter-lustig tell you?' - const createCommentMutation = gql` - mutation ($id: ID, $postId: ID!, $content: String!) { - CreateComment(id: $id, postId: $postId, content: $content) { - id - } - } - ` await Promise.all([ mutate({ mutation: createCommentMutation, From 0f8abe770a1856629efefcbeacb6e6c2eb376fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 15 Aug 2022 15:01:26 +0200 Subject: [PATCH 095/588] Move GQL mutation 'loginMutation' in 'user_management.spec.js' into a separate file --- backend/src/db/graphql/userManagement.js | 13 +++++++++++++ .../src/schema/resolvers/user_management.spec.js | 7 +------ 2 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 backend/src/db/graphql/userManagement.js diff --git a/backend/src/db/graphql/userManagement.js b/backend/src/db/graphql/userManagement.js new file mode 100644 index 000000000..3cb8a05f8 --- /dev/null +++ b/backend/src/db/graphql/userManagement.js @@ -0,0 +1,13 @@ +import gql from 'graphql-tag' + +// ------ mutations + +export const loginMutation = gql` + mutation ($email: String!, $password: String!) { + login(email: $email, password: $password) + } +` + +// ------ queries + +// fill queries in here diff --git a/backend/src/schema/resolvers/user_management.spec.js b/backend/src/schema/resolvers/user_management.spec.js index 2dcb14855..15b39e80d 100644 --- a/backend/src/schema/resolvers/user_management.spec.js +++ b/backend/src/schema/resolvers/user_management.spec.js @@ -2,6 +2,7 @@ import jwt from 'jsonwebtoken' import CONFIG from './../../config' import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' +import { loginMutation } from '../../db/graphql/userManagement' import { createTestClient } from 'apollo-server-testing' import createServer, { context } from '../../server' import encode from '../../jwt/encode' @@ -177,12 +178,6 @@ describe('currentUser', () => { }) describe('login', () => { - const loginMutation = gql` - mutation ($email: String!, $password: String!) { - login(email: $email, password: $password) - } - ` - const respondsWith = async (expected) => { await expect(mutate({ mutation: loginMutation, variables })).resolves.toMatchObject(expected) } From bbda8e6dd06bb39725d5c731041c36dd825c5d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 15 Aug 2022 15:22:49 +0200 Subject: [PATCH 096/588] Seed some groups --- backend/src/db/seed.js | 54 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/backend/src/db/seed.js b/backend/src/db/seed.js index 0a0926f06..64ee3c1dd 100644 --- a/backend/src/db/seed.js +++ b/backend/src/db/seed.js @@ -5,7 +5,7 @@ import createServer from '../server' import faker from '@faker-js/faker' import Factory from '../db/factories' import { getNeode, getDriver } from '../db/neo4j' -// import { createGroupMutation } from './graphql/groups' +import { createGroupMutation } from './graphql/groups' import { createPostMutation } from './graphql/posts' import { createCommentMutation } from './graphql/comments' @@ -383,6 +383,58 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] }), ]) + // Create Groups + + authenticatedUser = await peterLustig.toJson() + await Promise.all([ + mutate({ + mutation: createGroupMutation, + variables: { + id: 'g0', + name: 'Investigative Journalism', + about: 'Investigative journalists share ideas and insights and can collaborate.', + description: `

English:

This group is hidden.

What is our group for?

This group was created to allow investigative journalists to share and collaborate.

How does it work?

Here you can internally share posts and comments about them.


Deutsch:

Diese Gruppe ist verborgen.

Wofür ist unsere Gruppe?

Diese Gruppe wurde geschaffen, um investigativen Journalisten den Austausch und die Zusammenarbeit zu ermöglichen.

Wie funktioniert das?

Hier könnt ihr euch intern über Beiträge und Kommentare zu ihnen austauschen.

`, + groupType: 'hidden', + actionRadius: 'global', + categoryIds: ['cat3', 'cat13', 'cat16'], + }, + }), + ]) + + authenticatedUser = await jennyRostock.toJson() + await Promise.all([ + mutate({ + mutation: createGroupMutation, + variables: { + id: 'g1', + name: 'School For Citizens', + about: 'Our children shall receive education for life.', + description: `

English

Our goal

Only those who enjoy learning and do not lose their curiosity can obtain a good education for life and continue to learn with joy throughout their lives.

Curiosity

For this we need a school that takes up the curiosity of the children, the people, and satisfies it through a lot of experience.


Deutsch

Unser Ziel

Nur wer Spaß am Lernen hat und seine Neugier nicht verliert, kann gute Bildung für's Leben erlangen und sein ganzes Leben mit Freude weiter lernen.

Neugier

Dazu benötigen wir eine Schule, die die Neugier der Kinder, der Menschen, aufnimmt und durch viel Erfahrung befriedigt.

`, + groupType: 'closed', + actionRadius: 'national', + categoryIds: ['cat3', 'cat13', 'cat16'], + }, + }), + ]) + + authenticatedUser = await bobDerBaumeister.toJson() + await Promise.all([ + mutate({ + mutation: createGroupMutation, + variables: { + id: 'g2', + name: 'Yoga Practice', + about: 'We do yoga around the clock.', + description: `

What Is yoga?

Yoga is not just about practicing asanas. It's about how we do it.

And practicing asanas doesn't have to be yoga, it can be more athletic than yogic.

What makes practicing asanas yogic?

The important thing is:

  • Use the exercises (consciously) for your personal development.

`, + groupType: 'public', + actionRadius: 'interplanetary', + categoryIds: ['cat3', 'cat13', 'cat16'], + }, + }), + ]) + + // Create Posts + const [p0, p1, p3, p4, p5, p6, p9, p10, p11, p13, p14, p15] = await Promise.all([ Factory.build( 'post', From 936ecf247728456ddc42bb5d3959c79ba03e4bca Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 15 Aug 2022 15:35:33 +0200 Subject: [PATCH 097/588] add mutation createGroup and query GroupList --- .../CategoriesSelect/CategoriesSelect.vue | 1 + webapp/components/GroupForm/GroupForm.vue | 91 ++++++++++++----- webapp/components/GroupList/GroupCard.vue | 28 +++--- webapp/components/GroupList/GroupList.vue | 5 +- webapp/components/GroupMember/GroupMember.vue | 98 +++++++++---------- webapp/graphql/groups.js | 16 +-- webapp/pages/group/_id.vue | 17 ++-- webapp/pages/group/_id/_slug.vue | 6 +- webapp/pages/group/create.vue | 43 ++++---- webapp/pages/my-groups.vue | 21 +++- 10 files changed, 183 insertions(+), 143 deletions(-) diff --git a/webapp/components/CategoriesSelect/CategoriesSelect.vue b/webapp/components/CategoriesSelect/CategoriesSelect.vue index b7d71de2d..1fb95a8db 100644 --- a/webapp/components/CategoriesSelect/CategoriesSelect.vue +++ b/webapp/components/CategoriesSelect/CategoriesSelect.vue @@ -46,6 +46,7 @@ export default { }, methods: { toggleCategory(id) { + console.log('toggleCategory', id) this.selectedCategoryIds = xor(this.selectedCategoryIds, [id]) if (this.$parentForm) { this.$parentForm.update(this.model, this.selectedCategoryIds) diff --git a/webapp/components/GroupForm/GroupForm.vue b/webapp/components/GroupForm/GroupForm.vue index 8e29bf300..d52fea0c4 100644 --- a/webapp/components/GroupForm/GroupForm.vue +++ b/webapp/components/GroupForm/GroupForm.vue @@ -1,30 +1,53 @@ From 0c9fcaa5c6dd68e67247a5e3f9e0cc557b9d731f Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 28 Oct 2022 08:47:55 +0200 Subject: [PATCH 567/588] test coverage to 64% --- webapp/components/Group/GroupMember.vue | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/webapp/components/Group/GroupMember.vue b/webapp/components/Group/GroupMember.vue index 0a99aa21c..fc7f6e25a 100644 --- a/webapp/components/Group/GroupMember.vue +++ b/webapp/components/Group/GroupMember.vue @@ -91,7 +91,6 @@ v-if="scope.row.myRoleInGroup !== 'owner'" size="small" primary - @click="deleteMember(scope.row.id)" > @@ -226,7 +222,7 @@ export default { // this.memberId = row.id // }, // deleteMember(id) { - // alert('deleteMember: ' + id) + // alert('deleteMember: ' + id) // }, }, } From ef97b4c388e9bb7fb0a9b90deee3c388c779adcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 28 Oct 2022 09:11:01 +0200 Subject: [PATCH 569/588] Fix a merging left over with header logo click and fix functionallity on empty string targets --- webapp/components/HeaderMenu/HeaderMenu.vue | 26 +++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/webapp/components/HeaderMenu/HeaderMenu.vue b/webapp/components/HeaderMenu/HeaderMenu.vue index 8876338ee..44d34e5b7 100644 --- a/webapp/components/HeaderMenu/HeaderMenu.vue +++ b/webapp/components/HeaderMenu/HeaderMenu.vue @@ -7,7 +7,13 @@ @@ -91,7 +97,23 @@ - + + + + From 6d3c7f0acb533f1fb54e5e44a9abb104b6befb3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 28 Oct 2022 10:12:39 +0200 Subject: [PATCH 570/588] Simplify usage of 'LOGOS.LOGO_HEADER_CLICK.externalLink.target' --- webapp/components/HeaderMenu/HeaderMenu.vue | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/webapp/components/HeaderMenu/HeaderMenu.vue b/webapp/components/HeaderMenu/HeaderMenu.vue index 44d34e5b7..a9340a3be 100644 --- a/webapp/components/HeaderMenu/HeaderMenu.vue +++ b/webapp/components/HeaderMenu/HeaderMenu.vue @@ -8,12 +8,7 @@ @@ -100,12 +95,7 @@ From 847775a3f4d662e54aa2cfdf676a8dcd22a976ff Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 28 Oct 2022 11:00:27 +0200 Subject: [PATCH 571/588] fix: Comments on Posts in Groups in Webapp --- webapp/pages/post/_id/_slug/index.vue | 37 ++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index f111a4a89..2366eb072 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -103,7 +103,7 @@ /> From 00c10cc1a7c6339e4bcccec6ae43d9384fcdadad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 28 Oct 2022 11:12:34 +0200 Subject: [PATCH 572/588] Refine footer links and donation link and fix their tests --- .../components/PageFooter/PageFooter.spec.js | 31 +++++++++--- .../PageParamsLink/PageParamsLink.vue | 2 +- webapp/components/utils/InternalPages.js | 48 +++++++++++++++---- webapp/components/utils/PageParams.js | 13 +++-- webapp/constants/links.js | 39 +++++++++------ 5 files changed, 101 insertions(+), 32 deletions(-) diff --git a/webapp/components/PageFooter/PageFooter.spec.js b/webapp/components/PageFooter/PageFooter.spec.js index 95be76630..aecdcf2f7 100644 --- a/webapp/components/PageFooter/PageFooter.spec.js +++ b/webapp/components/PageFooter/PageFooter.spec.js @@ -100,21 +100,40 @@ describe('PageFooter.vue', () => { const links = { ...linksDefault, ORGANIZATION: linksDefault.ORGANIZATION.overwrite({ - externalLink: 'https://ocelot.social', + externalLink: { + url: 'https://ocelot.social', + target: '_blank', + }, }), IMPRINT: linksDefault.IMPRINT.overwrite({ - externalLink: 'https://ocelot.social/IMPRINT', + externalLink: { + url: 'https://ocelot.social/IMPRINT', + target: '_blank', + }, }), TERMS_AND_CONDITIONS: linksDefault.TERMS_AND_CONDITIONS.overwrite({ - externalLink: 'https://ocelot.social/TERMS_AND_CONDITIONS', + externalLink: { + url: 'https://ocelot.social/TERMS_AND_CONDITIONS', + target: '_blank', + }, }), CODE_OF_CONDUCT: linksDefault.CODE_OF_CONDUCT.overwrite({ - externalLink: 'https://ocelot.social/CODE_OF_CONDUCT', + externalLink: { + url: 'https://ocelot.social/CODE_OF_CONDUCT', + target: '_blank', + }, }), DATA_PRIVACY: linksDefault.DATA_PRIVACY.overwrite({ - externalLink: 'https://ocelot.social/DATA_PRIVACY', + externalLink: { + url: 'https://ocelot.social/DATA_PRIVACY', + target: '_blank', + }, }), - FAQ: linksDefault.FAQ.overwrite({ externalLink: 'https://ocelot.social/FAQ' }), + FAQ: linksDefault.FAQ.overwrite({ + externalLink: { + url: 'https://ocelot.social/FAQ', + target: '_blank', + } }), } wrapper = Wrapper() wrapper.setData({ links }) diff --git a/webapp/components/_new/features/PageParamsLink/PageParamsLink.vue b/webapp/components/_new/features/PageParamsLink/PageParamsLink.vue index 359e76210..dc03aa373 100644 --- a/webapp/components/_new/features/PageParamsLink/PageParamsLink.vue +++ b/webapp/components/_new/features/PageParamsLink/PageParamsLink.vue @@ -8,7 +8,7 @@ diff --git a/webapp/components/utils/InternalPages.js b/webapp/components/utils/InternalPages.js index f45601af9..dfdc04a6e 100644 --- a/webapp/components/utils/InternalPages.js +++ b/webapp/components/utils/InternalPages.js @@ -4,7 +4,11 @@ export const defaultPageParamsPages = { ORGANIZATION: new PageParams({ name: 'organization', - externalLink: null, // if string is defined and not empty it's dominating + // externalLink: { + // url: 'https://ocelot.social', + // target: '_blank', + // }, + externalLink: null, // if defined it's dominating internalPage: { pageRoute: '/organization', // static, don't change! internal page in case no external is defined @@ -21,7 +25,11 @@ export const defaultPageParamsPages = { DONATE: new PageParams({ name: 'donate', - externalLink: null, // if string is defined and not empty it's dominating + // externalLink: { + // url: 'https://ocelot.social', + // target: '_blank', + // }, + externalLink: null, // if defined it's dominating internalPage: { pageRoute: '/donate', // static, don't change! internal page in case no external is defined @@ -38,7 +46,11 @@ export const defaultPageParamsPages = { IMPRINT: new PageParams({ name: 'imprint', - externalLink: null, // if string is defined and not empty it's dominating + // externalLink: { + // url: 'https://ocelot.social', + // target: '_blank', + // }, + externalLink: null, // if defined it's dominating internalPage: { pageRoute: '/imprint', // static, don't change! internal page in case no external is defined @@ -55,7 +67,11 @@ export const defaultPageParamsPages = { TERMS_AND_CONDITIONS: new PageParams({ name: 'terms-and-conditions', - externalLink: null, // if string is defined and not empty it's dominating + // externalLink: { + // url: 'https://ocelot.social', + // target: '_blank', + // }, + externalLink: null, // if defined it's dominating internalPage: { pageRoute: '/terms-and-conditions', // static, don't change! internal page in case no external is defined @@ -72,7 +88,11 @@ export const defaultPageParamsPages = { CODE_OF_CONDUCT: new PageParams({ name: 'code-of-conduct', - externalLink: null, // if string is defined and not empty it's dominating + // externalLink: { + // url: 'https://ocelot.social', + // target: '_blank', + // }, + externalLink: null, // if defined it's dominating internalPage: { pageRoute: '/code-of-conduct', // static, don't change! internal page in case no external is defined @@ -89,7 +109,11 @@ export const defaultPageParamsPages = { DATA_PRIVACY: new PageParams({ name: 'data-privacy', - externalLink: null, // if string is defined and not empty it's dominating + // externalLink: { + // url: 'https://ocelot.social', + // target: '_blank', + // }, + externalLink: null, // if defined it's dominating internalPage: { pageRoute: '/data-privacy', // static, don't change! internal page in case no external is defined @@ -106,7 +130,11 @@ export const defaultPageParamsPages = { FAQ: new PageParams({ name: 'faq', - externalLink: null, // if string is defined and not empty it's dominating + // externalLink: { + // url: 'https://ocelot.social', + // target: '_blank', + // }, + externalLink: null, // if defined it's dominating internalPage: { pageRoute: '/faq', // static, don't change! internal page in case no external is defined @@ -123,7 +151,11 @@ export const defaultPageParamsPages = { SUPPORT: new PageParams({ name: 'support', - externalLink: null, + // externalLink: { + // url: 'https://ocelot.social', + // target: '_blank', + // }, + externalLink: null, // if defined it's dominating internalPage: { pageRoute: '/support', // static, don't change '*/support'! internal page in case no external is defined diff --git a/webapp/components/utils/PageParams.js b/webapp/components/utils/PageParams.js index 9d1fc6dfe..50b58a18f 100644 --- a/webapp/components/utils/PageParams.js +++ b/webapp/components/utils/PageParams.js @@ -24,18 +24,25 @@ export class PageParams { } get isInternalPage() { - return this.noStringDefined(this.externalLink) + return !(this.externalLink && !this.noStringDefined(this.externalLink.url)) } get link() { - return this.isInternalPage ? this.internalPage.pageRoute : this.externalLink + return this.isInternalPage ? this.internalPage.pageRoute : this.externalLink.url } redirectToPage(thisComponent) { if (this.isInternalPage) { thisComponent.$router.push(this.internalPage.pageRoute) } else if (typeof window !== 'undefined') { - window.location.href = this.externalLink + if (this.externalLink.target === '_blank') { + window.open( + this.externalLink.url, + this.externalLink.target, + ) + } else { + window.location.href = this.externalLink.url + } } } } diff --git a/webapp/constants/links.js b/webapp/constants/links.js index 07bbd970b..3af64d374 100644 --- a/webapp/constants/links.js +++ b/webapp/constants/links.js @@ -3,10 +3,13 @@ import { defaultPageParamsPages } from '~/components/utils/InternalPages.js' const ORGANIZATION = defaultPageParamsPages.ORGANIZATION.overwrite({ - externalLink: 'https://ocelot.social', // if string is defined and not empty it's dominating + // if defined it's dominating + externalLink: { + url: 'https://ocelot.social', + target: '_blank', + }, internalPage: { - target: '_blank', // footerIdent: 'site.made', // localized string identifier, if undefined default is used // headTitleIdent: 'site.made', // localized string identifier, if undefined default is used // headlineIdent: 'site.made', // localized string identifier, on null it's hidden, if undefined default is used @@ -17,11 +20,14 @@ const ORGANIZATION = defaultPageParamsPages.ORGANIZATION.overwrite({ }, }) const DONATE = defaultPageParamsPages.DONATE.overwrite({ - // we use 'ocelot-social.herokuapp.com' at the moment, because redirections of 'ocelot.social' subpages are not working correctly - externalLink: 'https://ocelot-social.herokuapp.com/donations', // if string is defined and not empty it's dominating + // if defined it's dominating + externalLink: { + // we use 'ocelot-social.herokuapp.com' at the moment, because redirections of 'ocelot.social' subpages are not working correctly + url: 'https://ocelot-social.herokuapp.com/donations', + target: '_blank', + }, internalPage: { - target: '_blank', // footerIdent: 'site.donate', // localized string identifier, if undefined default is used // headTitleIdent: 'site.donate', // localized string identifier, if undefined default is used // headlineIdent: 'site.donate', // localized string identifier, on null it's hidden, if undefined default is used @@ -32,11 +38,13 @@ const DONATE = defaultPageParamsPages.DONATE.overwrite({ }, }) const IMPRINT = defaultPageParamsPages.IMPRINT.overwrite({ - // we use 'ocelot-social.herokuapp.com' at the moment, because redirections of 'ocelot.social' subpages are not working correctly - externalLink: 'https://ocelot-social.herokuapp.com/imprint', // if string is defined and not empty it's dominating + externalLink: { + // we use 'ocelot-social.herokuapp.com' at the moment, because redirections of 'ocelot.social' subpages are not working correctly + url: 'https://ocelot-social.herokuapp.com/imprint', + target: '_blank', + }, internalPage: { - target: '_blank', // footerIdent: 'site.imprint', // localized string identifier, if undefined default is used // headTitleIdent: 'site.imprint', // localized string identifier, if undefined default is used // headlineIdent: 'site.imprint', // localized string identifier, on null it's hidden, if undefined default is used @@ -47,7 +55,7 @@ const IMPRINT = defaultPageParamsPages.IMPRINT.overwrite({ }, }) const TERMS_AND_CONDITIONS = defaultPageParamsPages.TERMS_AND_CONDITIONS.overwrite({ - // externalLink: null, // if string is defined and not empty it's dominating + // externalLink: null, // if defined it's dominating internalPage: { // footerIdent: 'site.termsAndConditions', // localized string identifier, if undefined default is used @@ -60,7 +68,7 @@ const TERMS_AND_CONDITIONS = defaultPageParamsPages.TERMS_AND_CONDITIONS.overwri }, }) const CODE_OF_CONDUCT = defaultPageParamsPages.CODE_OF_CONDUCT.overwrite({ - // externalLink: null, // if string is defined and not empty it's dominating + // externalLink: null, // if defined it's dominating internalPage: { // footerIdent: 'site.code-of-conduct', // localized string identifier, if undefined default is used @@ -73,7 +81,7 @@ const CODE_OF_CONDUCT = defaultPageParamsPages.CODE_OF_CONDUCT.overwrite({ }, }) const DATA_PRIVACY = defaultPageParamsPages.DATA_PRIVACY.overwrite({ - // externalLink: null, // if string is defined and not empty it's dominating + // externalLink: null, // if defined it's dominating internalPage: { // footerIdent: 'site.data-privacy', // localized string identifier, if undefined default is used @@ -86,7 +94,7 @@ const DATA_PRIVACY = defaultPageParamsPages.DATA_PRIVACY.overwrite({ }, }) const FAQ = defaultPageParamsPages.FAQ.overwrite({ - // externalLink: null, // if string is defined and not empty it's dominating + // externalLink: null, // if defined it's dominating internalPage: { // footerIdent: 'site.faq', // localized string identifier, if undefined default is used @@ -99,10 +107,13 @@ const FAQ = defaultPageParamsPages.FAQ.overwrite({ }, }) const SUPPORT = defaultPageParamsPages.SUPPORT.overwrite({ - externalLink: 'https://ocelot.social', // if string is defined and not empty it's dominating + // if defined it's dominating + externalLink: { + url: 'https://ocelot.social', + target: '_blank', + }, internalPage: { - target: '_blank', // footerIdent: 'site.support', // localized string identifier, if undefined default is used // headTitleIdent: 'site.support', // localized string identifier, if undefined default is used // headlineIdent: 'site.support', // on null default is used, on empty string it's hidden From 8c1c2604186e5214c36b68f4135a2ee7d7c7f9f7 Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 28 Oct 2022 12:05:23 +0200 Subject: [PATCH 573/588] menu filter clear position of buttons --- .../FilterMenu/CategoriesFilter.vue | 13 ++-- .../FilterMenu/FilterMenuSection.vue | 63 +++++++++---------- .../components/FilterMenu/FollowingFilter.vue | 7 ++- 3 files changed, 43 insertions(+), 40 deletions(-) diff --git a/webapp/components/FilterMenu/CategoriesFilter.vue b/webapp/components/FilterMenu/CategoriesFilter.vue index fef947178..0e0504731 100644 --- a/webapp/components/FilterMenu/CategoriesFilter.vue +++ b/webapp/components/FilterMenu/CategoriesFilter.vue @@ -1,16 +1,19 @@