mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-12 23:35:52 +00:00
Merge branch 'master' into cypress-migrate-to-v10
This commit is contained in:
commit
4afe3e05a5
71
.github/workflows/lint_pr.yml
vendored
Normal file
71
.github/workflows/lint_pr.yml
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
name: "ocelot.social lint pull request CI"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
main:
|
||||
name: Validate PR title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
# Configure which types are allowed (newline delimited).
|
||||
# Default: https://github.com/commitizen/conventional-commit-types
|
||||
#types: |
|
||||
# fix
|
||||
# feat
|
||||
# Configure which scopes are allowed (newline delimited).
|
||||
scopes: |
|
||||
backend
|
||||
webapp
|
||||
database
|
||||
release
|
||||
other
|
||||
# Configure that a scope must always be provided.
|
||||
requireScope: true
|
||||
# Configure which scopes (newline delimited) are disallowed in PR
|
||||
# titles. For instance by setting # the value below, `chore(release):
|
||||
# ...` and `ci(e2e,release): ...` will be rejected.
|
||||
#disallowScopes: |
|
||||
# release
|
||||
# Configure additional validation for the subject based on a regex.
|
||||
# This example ensures the subject doesn't start with an uppercase character.
|
||||
subjectPattern: ^(?![A-Z]).+$
|
||||
# If `subjectPattern` is configured, you can use this property to override
|
||||
# the default error message that is shown when the pattern doesn't match.
|
||||
# The variables `subject` and `title` can be used within the message.
|
||||
subjectPatternError: |
|
||||
The subject "{subject}" found in the pull request title "{title}"
|
||||
didn't match the configured pattern. Please ensure that the subject
|
||||
doesn't start with an uppercase character.
|
||||
# If you use GitHub Enterprise, you can set this to the URL of your server
|
||||
#githubBaseUrl: https://github.myorg.com/api/v3
|
||||
# If the PR contains one of these labels (newline delimited), the
|
||||
# validation is skipped.
|
||||
# If you want to rerun the validation when labels change, you might want
|
||||
# to use the `labeled` and `unlabeled` event triggers in your workflow.
|
||||
#ignoreLabels: |
|
||||
# bot
|
||||
# ignore-semantic-pull-request
|
||||
# If you're using a format for the PR title that differs from the traditional Conventional
|
||||
# Commits spec, you can use these options to customize the parsing of the type, scope and
|
||||
# subject. The `headerPattern` should contain a regex where the capturing groups in parentheses
|
||||
# correspond to the parts listed in `headerPatternCorrespondence`.
|
||||
# See: https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-commits-parser#headerpattern
|
||||
headerPattern: '^(\w*)(?:\(([\w$.\-*/ ]*)\))?: (.*)$'
|
||||
headerPatternCorrespondence: type, scope, subject
|
||||
# For work-in-progress PRs you can typically use draft pull requests
|
||||
# from GitHub. However, private repositories on the free plan don't have
|
||||
# this option and therefore this action allows you to opt-in to using the
|
||||
# special "[WIP]" prefix to indicate this state. This will avoid the
|
||||
# validation of the PR title and the pull request checks remain pending.
|
||||
# Note that a second check will be reported if this is enabled.
|
||||
wip: true
|
||||
32
.github/workflows/publish.yml
vendored
32
.github/workflows/publish.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# TODO: DO STUFF ??? #####################################################
|
||||
##########################################################################
|
||||
@ -42,7 +42,7 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# SET ENVS ###############################################################
|
||||
##########################################################################
|
||||
@ -62,7 +62,7 @@ jobs:
|
||||
- name: Neo4J | Save docker image
|
||||
run: docker save "ocelotsocialnetwork/neo4j-community" > /tmp/neo4j.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docker-neo4j-community
|
||||
path: /tmp/neo4j.tar
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# SET ENVS ###############################################################
|
||||
##########################################################################
|
||||
@ -102,7 +102,7 @@ jobs:
|
||||
- name: Backend | Save docker image
|
||||
run: docker save "ocelotsocialnetwork/backend" > /tmp/backend.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docker-backend-production
|
||||
path: /tmp/backend.tar
|
||||
@ -119,7 +119,7 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# SET ENVS ###############################################################
|
||||
##########################################################################
|
||||
@ -142,7 +142,7 @@ jobs:
|
||||
- name: Webapp | Save docker image
|
||||
run: docker save "ocelotsocialnetwork/webapp" > /tmp/webapp.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docker-webapp-production
|
||||
path: /tmp/webapp.tar
|
||||
@ -159,7 +159,7 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# SET ENVS ###############################################################
|
||||
##########################################################################
|
||||
@ -182,7 +182,7 @@ jobs:
|
||||
- name: Maintenance | Save docker image
|
||||
run: docker save "ocelotsocialnetwork/maintenance" > /tmp/maintenance.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docker-maintenance-production
|
||||
path: /tmp/maintenance.tar
|
||||
@ -202,33 +202,33 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGES #################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Neo4J)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-neo4j-community
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/neo4j.tar
|
||||
- name: Download Docker Image (Backend)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-backend-production
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/backend.tar
|
||||
- name: Download Docker Image (WebApp)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-webapp-production
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/webapp.tar
|
||||
- name: Download Docker Image (Maintenance)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-maintenance-production
|
||||
path: /tmp
|
||||
@ -262,7 +262,7 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# SET ENVS ###############################################################
|
||||
##########################################################################
|
||||
@ -335,7 +335,7 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Fetch full History for changelog
|
||||
##########################################################################
|
||||
|
||||
44
.github/workflows/test.yml
vendored
44
.github/workflows/test.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# TODO: DO STUFF ??? #####################################################
|
||||
##########################################################################
|
||||
@ -37,7 +37,7 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# NEO4J ##################################################################
|
||||
##########################################################################
|
||||
@ -46,7 +46,7 @@ jobs:
|
||||
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
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docker-neo4j-image
|
||||
path: /tmp/neo4j.tar
|
||||
@ -63,7 +63,7 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# BUILD BACKEND DOCKER IMAGE (build) #####################################
|
||||
##########################################################################
|
||||
@ -72,7 +72,7 @@ jobs:
|
||||
docker build --target test -t "ocelotsocialnetwork/backend:test" backend/
|
||||
docker save "ocelotsocialnetwork/backend:test" > /tmp/backend.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docker-backend-test
|
||||
path: /tmp/backend.tar
|
||||
@ -89,7 +89,7 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# BUILD WEBAPP DOCKER IMAGE (build) ######################################
|
||||
##########################################################################
|
||||
@ -98,7 +98,7 @@ jobs:
|
||||
docker build --target test -t "ocelotsocialnetwork/webapp:test" webapp/
|
||||
docker save "ocelotsocialnetwork/webapp:test" > /tmp/webapp.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docker-webapp-test
|
||||
path: /tmp/webapp.tar
|
||||
@ -115,12 +115,12 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Backend)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-backend-test
|
||||
path: /tmp
|
||||
@ -144,12 +144,12 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Webapp)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-webapp-test
|
||||
path: /tmp
|
||||
@ -173,19 +173,19 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGES #################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Neo4J)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-neo4j-image
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/neo4j.tar
|
||||
- name: Download Docker Image (Backend)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-backend-test
|
||||
path: /tmp
|
||||
@ -230,12 +230,12 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGES #################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Webapp)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-webapp-test
|
||||
path: /tmp
|
||||
@ -290,26 +290,26 @@ jobs:
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGES #################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Neo4J)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-neo4j-image
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/neo4j.tar
|
||||
- name: Download Docker Image (Backend)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-backend-test
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/backend.tar
|
||||
- name: Download Docker Image (Webapp)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-webapp-test
|
||||
path: /tmp
|
||||
@ -332,12 +332,12 @@ jobs:
|
||||
# UPLOAD SCREENSHOTS & VIDEO #############################################
|
||||
##########################################################################
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cypress-screenshots
|
||||
path: cypress/screenshots/
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cypress-videos
|
||||
path: cypress/videos/
|
||||
|
||||
98
CHANGELOG.md
98
CHANGELOG.md
@ -4,8 +4,54 @@ 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).
|
||||
|
||||
#### [2.2.0](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/1.1.0...2.2.0)
|
||||
#### [2.4.0](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/2.3.0...2.4.0)
|
||||
|
||||
- fix(webapp): post teaser width in mobile view [`#5958`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5958)
|
||||
- fix(webapp): navbar disappears when scrolling to top [`#5957`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5957)
|
||||
- fix(webapp): close mobile menu on all links [`#5956`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5956)
|
||||
- feat(webapp): mark active filters on the posts [`#5952`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5952)
|
||||
- refactor(webapp): refacchange postion add content button, refactor mobile filter menu [`#5943`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5943)
|
||||
- refactor(webapp): set legend to map [`#5950`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5950)
|
||||
- fix(webapp): small changes for deploy [`#5949`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5949)
|
||||
- feat(webapp): hide navbar by scroll, filter button for content [`#5926`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5926)
|
||||
- feat(webapp): map [`#5843`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5843)
|
||||
- refactor(webapp): upgrade node version to 19.4 [`#5910`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5910)
|
||||
- fix(webapp): texts for groups [`#5923`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5923)
|
||||
- fix(webapp): add category name in tooltip [`#5884`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5884)
|
||||
- refactor(webapp): 🍰 Refactor Social Media And `MySomethingList` [`#5138`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5138)
|
||||
- fix(backend): do not expose registered emails on registration [`#5909`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5909)
|
||||
- refactor(backend): node 19 with fixed image upload [`#5897`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5897)
|
||||
- refactor(webapp): nump docker version to `16.19.0` in webapp & maintenance [`#5842`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5842)
|
||||
- updated required packages for node19, fix fs-capacitator [`11087cb`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/11087cbaefde604668ac192b710666df09cb813c)
|
||||
- fixed build error [`3889204`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/3889204f871df97b307401032900db7940913038)
|
||||
- linting [`8bfe486`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/8bfe486034badd55a8096982f81aba08207b9e83)
|
||||
|
||||
#### [2.3.0](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/2.2.0...2.3.0)
|
||||
|
||||
> 5 December 2022
|
||||
|
||||
- chore(release): v2.3.0 [`#5768`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5768)
|
||||
- feat(webapp): 🍰 Sort Categories By Name [`#5709`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5709)
|
||||
- fix(backend): sanitize group description [`#5707`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5707)
|
||||
- fix(webapp): clean up webapp unit tests [`#5711`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5711)
|
||||
- feat(webapp): 🍰 Search Users To Add To Group [`#5652`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5652)
|
||||
- feat(webapp): 🍰 Params For Category Filter [`#5699`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5699)
|
||||
- fix(backend): 🍰 Misspelled Notification [`#5703`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5703)
|
||||
- test(other): jest coverage report in console [`#5637`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5637)
|
||||
- fix(webapp): centralize mobile hamburger menu [`#5674`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5674)
|
||||
- refactor(backend): 🍰 Move `db/graphql` Folder Content To `graphql` Folder [`#5661`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5661)
|
||||
- feat(other): semantic pullrequest workflow [`#5634`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5634)
|
||||
- fix: Cannot Add Group Members as New Members to Group [`#5635`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5635)
|
||||
- fix: My Groups Count Includes Pending Membership [`#5631`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5631)
|
||||
- frontend: jest coverage [`f57e11d`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/f57e11dd021dbb156b33fbd5538cf5ca32df7334)
|
||||
- reverted yarn lock [`a01aee8`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/a01aee89a92bbc9885e2895c577eb3c63042ba22)
|
||||
- reverted all package updates [`a520089`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/a5200893f4508d45619447231b6789178a51daf7)
|
||||
|
||||
#### [2.2.0](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/2.1.0...2.2.0)
|
||||
|
||||
> 28 October 2022
|
||||
|
||||
- chore: 🍰 Release v2.2.0 [`#5610`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5610)
|
||||
- refactor: 🍰 Refactor Design Of Category Filter In Filter Menu [`#5597`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5597)
|
||||
- feat: 🍰 Footer And Header Links Configurable To Have External Link Target [`#5590`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5590)
|
||||
- feat: 🍰 Header Menu To Component And Other Refinements [`#5546`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5546)
|
||||
@ -19,10 +65,26 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
- fix: 🍰 Fix Group Teaser [`#5584`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5584)
|
||||
- feat: 🍰 List All Groups [`#5582`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5582)
|
||||
- feat: 🍰 Header Logo Routing Update [`#5579`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5579)
|
||||
- add header menu to component, central variabl for screen width [`401f59a`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/401f59ae8de5b1c27f0e26e1f71778d3257d2180)
|
||||
- comment out LanguagesFilter, EmotionsFilter, fix tests, fix lint [`52dcd77`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/52dcd772fa81e02a0d95e89a9fc8232e70a09d28)
|
||||
- fix lint [`15561cb`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/15561cb94f8768e93846c25945c935ae83977553)
|
||||
|
||||
#### [2.1.0](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/2.0.0...2.1.0)
|
||||
|
||||
> 25 October 2022
|
||||
|
||||
- chore: 🍰 Release v2.1.0 [`#5574`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5574)
|
||||
- feat: 🍰 EPIC Groups [`#5132`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5132)
|
||||
- chore: 🍰 Remove Group Branchs `5059-epic-groups` Separate Auto-Deployment [`#5552`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5552)
|
||||
- fix: [WIP] 🍰 Long Words Are Being Wrapped Now [`#5559`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5559)
|
||||
- Remove groups separate auto-deployment [`c8d8168`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/c8d816887b2d49293d1b8ee2805d452fe10d907e)
|
||||
- Release v2.1.0 [`dc085e9`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/dc085e9e69b288fce6dd06e8d7eb05ef34bd9a7b)
|
||||
- Add database migration to auto-deployment on publish [`ef06f1a`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/ef06f1a67d2654aaeb55d0434d3324a3ac37a380)
|
||||
|
||||
### [2.0.0](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/1.1.1...2.0.0)
|
||||
|
||||
> 23 October 2022
|
||||
|
||||
- feat: 🍰 Search For Groups [`#5543`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5543)
|
||||
- feat: 🍰 Mobile Footer Menu To Header Menu [`#5524`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5524)
|
||||
- feat: 🍰 Implement `LOGO_HEADER_CLICK` As Configuration [`#5525`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5525)
|
||||
@ -39,25 +101,35 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
- feat: 🍰 Group Members Management [`#5345`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5345)
|
||||
- feat: 🍰 Have My Groups In The User Menu And Configure Groups Button In Header [`#5411`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5411)
|
||||
- chore: 🍰 Implement Automatic Deployment For Groups Branch '5059-epic-groups' [`#5408`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5408)
|
||||
- Chore: 🍰 Release v1.1.1 – Refactor Rebranding [`#5392`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5392)
|
||||
- chore: 🍰 Refactor Rebranding [`#5390`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5390)
|
||||
- feat: 🍰 Group Profile Description Etc [`#5368`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5368)
|
||||
- feat: 🍰 Tooltips For Topics [`#5350`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5350)
|
||||
- feat: 🍰 Group Profile Members List Etc [`#5335`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5335)
|
||||
- feat: 🍰 Implement Group Profile – Visibility [`#5332`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5332)
|
||||
- feat: 🍰 Save Categories In Frontend [`#5284`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5284)
|
||||
- feat: 🍰 Add New Yunite Icons [`#5319`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5319)
|
||||
- chore: 🍰 Update Neode From v^0.4.7 To v^0.4.8 In Backend [`#5334`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5334)
|
||||
- feat: 🍰 My Groups Page [`#5148`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5148)
|
||||
- feat: 🍰 Hidden Groups Shall Not Be Visible For None Or Pending Members In Backend [`#5317`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5317)
|
||||
- feat: 🍰 Implement Group Profile [`#5197`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5197)
|
||||
- feat: 🍰 Implement `UpdateGroup` Resolver [`#5224`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5224)
|
||||
- feat: 🍰 Implement `JoinGroup`, `GroupMember`, `SwitchGroupMemberRole` Resolvers [`#5199`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5199)
|
||||
- chore: 🍰 Add Groups To Seeding [`#5185`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5185)
|
||||
- feat: 🍰 Implement Group GQL Model And CRUD Resolvers – First Step [`#5139`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5139)
|
||||
- Refine design and functionality of group list and create, edit group [`7b11122`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/7b11122bea4868624dd1c1641219e71070412e20)
|
||||
- improved code and tests as suggested by @tirokk, thanks for the great review! [`631f34a`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/631f34a2e5224d68279337a92e7535794b670d70)
|
||||
- implement and test post visibilty when leaving or changing the role in a group [`76bfe48`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/76bfe484768cf9b20b2dced865d5d3e3eb999235)
|
||||
|
||||
#### [1.1.1](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/1.1.0...1.1.1)
|
||||
|
||||
> 22 September 2022
|
||||
|
||||
- Chore: 🍰 Release v1.1.1 – Refactor Rebranding [`#5392`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5392)
|
||||
- chore: 🍰 Refactor Rebranding [`#5390`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5390)
|
||||
- feat: 🍰 Tooltips For Topics [`#5350`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5350)
|
||||
- feat: 🍰 Save Categories In Frontend [`#5284`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5284)
|
||||
- feat: 🍰 Add New Yunite Icons [`#5319`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5319)
|
||||
- chore: 🍰 Update Neode From v^0.4.7 To v^0.4.8 In Backend [`#5334`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5334)
|
||||
- fix: Category Filter Menu Client Only [`#5301`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5301)
|
||||
- feat: Save Category Settings [`#5261`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5261)
|
||||
- feat: 🍰 Implement `UpdateGroup` Resolver [`#5224`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5224)
|
||||
- feat: Topics Menu [`#5248`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5248)
|
||||
- docs: 🍰 Document GraqhQL Playground [`#5253`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5253)
|
||||
- feat: Categories Filter Menu [`#5198`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5198)
|
||||
- feat: 🍰 Implement `JoinGroup`, `GroupMember`, `SwitchGroupMemberRole` Resolvers [`#5199`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5199)
|
||||
- fix: 🍰 Fix Test Description From `enter-nonce.vue` To `change-password` [`#5217`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5217)
|
||||
- Bump cookie-universal-nuxt from 2.1.5 to 2.2.2 in /webapp [`#5218`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5218)
|
||||
- Bump prettier from 2.2.1 to 2.7.1 in /webapp [`#5170`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5170)
|
||||
@ -69,12 +141,10 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
- feat: 🍰 Change Error Message With `Authorised` To `Authorized` All Over The Place To Have American English [`#5206`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5206)
|
||||
- Bump cross-env from 7.0.2 to 7.0.3 in /webapp [`#5168`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5168)
|
||||
- chore: 🍰 Add `--logHeapUsage` To Jest Test Call [`#5182`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5182)
|
||||
- chore: 🍰 Add Groups To Seeding [`#5185`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5185)
|
||||
- feat: 🍰 Implement Group GQL Model And CRUD Resolvers – First Step [`#5139`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5139)
|
||||
- refactor: 🍰 Rename `UserGroup` To `UserRole` [`#5143`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/5143)
|
||||
- improved code and tests as suggested by @tirokk, thanks for the great review! [`631f34a`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/631f34a2e5224d68279337a92e7535794b670d70)
|
||||
- implement and test post visibilty when leaving or changing the role in a group [`76bfe48`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/76bfe484768cf9b20b2dced865d5d3e3eb999235)
|
||||
- comment out LanguagesFilter, EmotionsFilter, fix tests, fix lint [`52dcd77`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/52dcd772fa81e02a0d95e89a9fc8232e70a09d28)
|
||||
- add new yunite icons [`bb0d632`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/bb0d6329e7e36ea03671318ea8dd128a6d5a5a7a)
|
||||
- cleanup refactor rebranding [`5f5c0fa`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/5f5c0faa1f28cd4df7681eba335ae5998b2d9cca)
|
||||
- change color and scss in branding [`52070b8`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/52070b8c570970bf48df561134bf67cb4111b640)
|
||||
|
||||
#### [1.1.0](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/1.0.9...1.1.0)
|
||||
|
||||
|
||||
107
CONTRIBUTING.md
107
CONTRIBUTING.md
@ -105,7 +105,7 @@ Sprint retrospective
|
||||
|
||||
## Philosophy
|
||||
|
||||
We practise [collective code ownership](http://www.extremeprogramming.org/rules/collective.html) rather than strong code ownership, which means that:
|
||||
We practice [collective code ownership](http://www.extremeprogramming.org/rules/collective.html) rather than strong code ownership, which means that:
|
||||
|
||||
* developers can make contributions to other people's PRs (after checking in with them)
|
||||
* we avoid blocking because someone else isn't working, so we sometimes take over PRs from other developers
|
||||
@ -115,7 +115,7 @@ We believe in open source contributions as a learning experience – everyone is
|
||||
|
||||
We use pair programming sessions as a tool for knowledge sharing. We can learn a lot from each other and only by sharing what we know and overcoming challenges together can we grow as a team and truly own this project collectively.
|
||||
|
||||
As a volunteeer you have no commitment except your own self development and your awesomeness by contributing to this free and open-source software project. Cheers to you!
|
||||
As a volunteer you have no commitment except your own self development and your awesomeness by contributing to this free and open-source software project. Cheers to you!
|
||||
|
||||
<!--
|
||||
## Open-Source Bounties
|
||||
@ -149,3 +149,106 @@ Our Open-Source bounty program is a work-in-progress. Based on our future
|
||||
experience we will make changes and improvements. So keep an eye on this
|
||||
contribution guide.
|
||||
-->
|
||||
|
||||
## Programming
|
||||
|
||||
### Localization
|
||||
|
||||
#### Quotation Marks
|
||||
|
||||
The following characters are different from the programming quotation mark:
|
||||
|
||||
`"` or `\"`
|
||||
|
||||
Please copy and paste the following quotes for the languages:
|
||||
|
||||
* de: „Dies ist ein Beispielsatz.“
|
||||
* en: “This is a sample sentence.”
|
||||
* See <https://grammar.collinsdictionary.com/easy-learning/when-do-you-use-quotation-marks-or-in-english>
|
||||
|
||||
## Docker – More Closely
|
||||
|
||||
### Apple M1 Platform
|
||||
|
||||
***Attention:** For using Docker commands in Apple M1 environments!*
|
||||
|
||||
#### Environment 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
|
||||
# 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
|
||||
$ docker compose exec backend yarn db:seed
|
||||
|
||||
# for production
|
||||
$ docker compose -f docker-compose.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 /bin/sh -c "yarn prod:migrate init"
|
||||
```
|
||||
|
||||
### Analyzing 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 <layer-name> -t "ocelotsocialnetwork/<app-name>:local-<layer-name>" --build-arg BBUILD_DATE="<build-date>" --build-arg BBUILD_VERSION="<build-version>" --build-arg BBUILD_COMMIT="<build-commit>" <app-folder-name-or-dot>/
|
||||
```
|
||||
|
||||
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/
|
||||
```
|
||||
|
||||
@ -1,86 +0,0 @@
|
||||
# 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
|
||||
# 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
|
||||
$ docker compose exec backend yarn db:seed
|
||||
|
||||
# for production
|
||||
$ docker compose -f docker-compose.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 /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 <layer-name> -t "ocelotsocialnetwork/<app-name>:local-<layer-name>" --build-arg BBUILD_DATE="<build-date>" --build-arg BBUILD_VERSION="<build-version>" --build-arg BBUILD_COMMIT="<build-commit>" <app-folder-name-or-dot>/
|
||||
```
|
||||
|
||||
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/
|
||||
```
|
||||
@ -1 +1 @@
|
||||
v12.19.0
|
||||
v19.4.0
|
||||
@ -1,7 +1,7 @@
|
||||
##################################################################################
|
||||
# BASE (Is pushed to DockerHub for rebranding) ###################################
|
||||
##################################################################################
|
||||
FROM node:12.19.0-alpine3.10 as base
|
||||
FROM node:19.4.0-alpine3.17 as base
|
||||
|
||||
# ENVs
|
||||
## DOCKER_WORKDIR would be a classical ARG, but that is not multi layer persistent - shame
|
||||
|
||||
@ -19,12 +19,19 @@ Wait a little until your backend is up and running at [http://localhost:4000/](h
|
||||
## Installation without Docker
|
||||
|
||||
For the local installation you need a recent version of
|
||||
[node](https://nodejs.org/en/) (>= `v10.12.0`). We are using
|
||||
`12.19.0` and therefore we recommend to use the same version
|
||||
[Node](https://nodejs.org/en/) (>= `v16.19.0`). We are using
|
||||
`v19.4.0` and therefore we recommend to use the same version
|
||||
([see](https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4082)
|
||||
some known problems with more recent node versions). You can use the
|
||||
[node version manager](https://github.com/nvm-sh/nvm) to switch
|
||||
between different local node versions.
|
||||
[node version manager](https://github.com/nvm-sh/nvm) `nvm` to switch
|
||||
between different local Node versions:
|
||||
|
||||
```bash
|
||||
# install Node
|
||||
$ cd backend
|
||||
$ nvm install v19.4.0
|
||||
$ nvm use v19.4.0
|
||||
```
|
||||
|
||||
Install node dependencies with [yarn](https://yarnpkg.com/en/):
|
||||
|
||||
@ -32,6 +39,10 @@ Install node dependencies with [yarn](https://yarnpkg.com/en/):
|
||||
# in main folder
|
||||
$ cd backend
|
||||
$ yarn install
|
||||
# or just
|
||||
$ yarn
|
||||
# or just later on to use version of ".nvmrc" file
|
||||
$ nvm use && yarn
|
||||
```
|
||||
|
||||
Copy Environment Variables:
|
||||
|
||||
14
backend/jest.config.js
Normal file
14
backend/jest.config.js
Normal file
@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
verbose: true,
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: [
|
||||
'**/*.js',
|
||||
'!**/node_modules/**',
|
||||
'!**/test/**',
|
||||
'!**/dist/**',
|
||||
'!**/src/**/?(*.)+(spec|test).js?(x)'
|
||||
],
|
||||
coverageReporters: ['lcov', 'text'],
|
||||
testMatch: ['**/src/**/?(*.)+(spec|test).js?(x)'],
|
||||
setupFilesAfterEnv: ['<rootDir>/test/setup.js']
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ocelot-social-backend",
|
||||
"version": "2.2.0",
|
||||
"version": "2.4.0",
|
||||
"description": "GraphQL Backend for ocelot.social",
|
||||
"repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social",
|
||||
"author": "ocelot.social Community",
|
||||
@ -15,29 +15,13 @@
|
||||
"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 NODE_OPTIONS=--max-old-space-size=8192 jest --forceExit --detectOpenHandles --runInBand --coverage --logHeapUsage",
|
||||
"test": "cross-env NODE_ENV=test NODE_OPTIONS=--max-old-space-size=8192 jest --runInBand --coverage --forceExit --detectOpenHandles",
|
||||
"db:clean": "babel-node src/db/clean.js",
|
||||
"db:reset": "yarn run db:clean",
|
||||
"db:seed": "babel-node src/db/seed.js",
|
||||
"db:migrate": "yarn run __migrate --store ./src/db/migrate/store.js",
|
||||
"db:migrate:create": "yarn run __migrate --template-file ./src/db/migrate/template.js --date-format 'yyyymmddHHmmss' create"
|
||||
},
|
||||
"jest": {
|
||||
"verbose": true,
|
||||
"collectCoverageFrom": [
|
||||
"**/*.js",
|
||||
"!**/node_modules/**",
|
||||
"!**/test/**",
|
||||
"!**/dist/**",
|
||||
"!**/src/**/?(*.)+(spec|test).js?(x)"
|
||||
],
|
||||
"coverageReporters": [
|
||||
"lcov"
|
||||
],
|
||||
"testMatch": [
|
||||
"**/src/**/?(*.)+(spec|test).js?(x)"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/cli": "~7.8.4",
|
||||
"@babel/core": "~7.9.0",
|
||||
@ -81,22 +65,22 @@
|
||||
"linkifyjs": "~2.1.8",
|
||||
"lodash": "~4.17.14",
|
||||
"merge-graphql-schemas": "^1.7.8",
|
||||
"metascraper": "^5.11.8",
|
||||
"metascraper-audio": "^5.14.26",
|
||||
"metascraper-author": "^5.14.22",
|
||||
"metascraper": "^5.33.5",
|
||||
"metascraper-audio": "^5.33.5",
|
||||
"metascraper-author": "^5.33.5",
|
||||
"metascraper-clearbit-logo": "^5.3.0",
|
||||
"metascraper-date": "^5.11.8",
|
||||
"metascraper-description": "^5.23.1",
|
||||
"metascraper-image": "^5.11.8",
|
||||
"metascraper-lang": "^5.23.1",
|
||||
"metascraper-date": "^5.33.5",
|
||||
"metascraper-description": "^5.33.5",
|
||||
"metascraper-image": "^5.33.5",
|
||||
"metascraper-lang": "^5.33.5",
|
||||
"metascraper-lang-detector": "^4.10.2",
|
||||
"metascraper-logo": "^5.14.26",
|
||||
"metascraper-publisher": "^5.23.0",
|
||||
"metascraper-soundcloud": "^5.23.0",
|
||||
"metascraper-title": "^5.11.8",
|
||||
"metascraper-url": "^5.14.26",
|
||||
"metascraper-video": "^5.11.8",
|
||||
"metascraper-youtube": "^5.23.0",
|
||||
"metascraper-logo": "^5.33.5",
|
||||
"metascraper-publisher": "^5.33.5",
|
||||
"metascraper-soundcloud": "^5.33.5",
|
||||
"metascraper-title": "^5.33.5",
|
||||
"metascraper-url": "^5.33.5",
|
||||
"metascraper-video": "^5.33.5",
|
||||
"metascraper-youtube": "^5.33.5",
|
||||
"migrate": "^1.7.0",
|
||||
"mime-types": "^2.1.26",
|
||||
"minimatch": "^3.0.4",
|
||||
@ -132,13 +116,15 @@
|
||||
"eslint-plugin-prettier": "~3.4.1",
|
||||
"eslint-plugin-promise": "~4.3.1",
|
||||
"eslint-plugin-standard": "~4.0.1",
|
||||
"jest": "~25.3.0",
|
||||
"jest": "29.4",
|
||||
"nodemon": "~2.0.2",
|
||||
"prettier": "~2.3.2",
|
||||
"rosie": "^2.0.1",
|
||||
"supertest": "~4.0.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"fs-capacitor": "6.0.0"
|
||||
"**/**/fs-capacitor": "^6.2.0",
|
||||
"**/graphql-upload": "^11.0.0",
|
||||
"nan": "2.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
// TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
// 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
|
||||
export const DESCRIPTION_WITHOUT_HTML_LENGTH_MIN = 50 // with removed HTML tags
|
||||
export const DESCRIPTION_EXCERPT_HTML_LENGTH = 250 // with removed HTML tags
|
||||
|
||||
@ -85,7 +85,7 @@ class Store {
|
||||
await createDefaultAdminUser(session)
|
||||
if (CONFIG.CATEGORIES_ACTIVE) await createCategories(session)
|
||||
const writeTxResultPromise = session.writeTransaction(async (txc) => {
|
||||
await txc.run('CALL apoc.schema.assert({},{},true)') // drop all indices and contraints
|
||||
await txc.run('CALL apoc.schema.assert({},{},true)') // drop all indices and constraints
|
||||
return Promise.all(
|
||||
[
|
||||
'CALL db.index.fulltext.createNodeIndex("user_fulltext_search",["User"],["name", "slug"])',
|
||||
|
||||
@ -9,9 +9,9 @@ import {
|
||||
createGroupMutation,
|
||||
joinGroupMutation,
|
||||
changeGroupMemberRoleMutation,
|
||||
} from './graphql/groups'
|
||||
import { createPostMutation } from './graphql/posts'
|
||||
import { createCommentMutation } from './graphql/comments'
|
||||
} from '../graphql/groups'
|
||||
import { createPostMutation } from '../graphql/posts'
|
||||
import { createCommentMutation } from '../graphql/comments'
|
||||
import { categories } from '../constants/categories'
|
||||
|
||||
if (CONFIG.PRODUCTION && !CONFIG.PRODUCTION_DB_CLEAN_ALLOW) {
|
||||
|
||||
@ -2,24 +2,26 @@
|
||||
* iterate through all fields and replace it with the callback result
|
||||
* @property data Array
|
||||
* @property fields Array
|
||||
* @property fieldName String
|
||||
* @property callback Function
|
||||
*/
|
||||
function walkRecursive(data, fields, callback, _key) {
|
||||
function walkRecursive(data, fields, fieldName, callback, _key) {
|
||||
if (!Array.isArray(fields)) {
|
||||
throw new Error('please provide an fields array for the walkRecursive helper')
|
||||
}
|
||||
if (data && typeof data === 'string' && fields.includes(_key)) {
|
||||
// well we found what we searched for, lets replace the value with our callback result
|
||||
data = callback(data, _key)
|
||||
const key = _key.split('!')
|
||||
if (key.length === 1 || key[1] !== fieldName) data = callback(data, key[0])
|
||||
} else if (data && Array.isArray(data)) {
|
||||
// go into the rabbit hole and dig through that array
|
||||
data.forEach((res, index) => {
|
||||
data[index] = walkRecursive(data[index], fields, callback, index)
|
||||
data[index] = walkRecursive(data[index], fields, fieldName, callback, index)
|
||||
})
|
||||
} else if (data && typeof data === 'object') {
|
||||
// lets get some keys and stir them
|
||||
Object.keys(data).forEach((k) => {
|
||||
data[k] = walkRecursive(data[k], fields, callback, k)
|
||||
data[k] = walkRecursive(data[k], fields, fieldName, callback, k)
|
||||
})
|
||||
}
|
||||
return data
|
||||
|
||||
@ -36,6 +36,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
// TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543
|
||||
|
||||
@ -50,6 +50,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -80,14 +80,6 @@ const testEmailData = (emailTemplate, templateBuilder, templateData, texts) => {
|
||||
return emailTemplate
|
||||
}
|
||||
|
||||
// beforeAll(async () => {
|
||||
// await cleanDatabase()
|
||||
// })
|
||||
|
||||
// afterAll(async () => {
|
||||
// await cleanDatabase()
|
||||
// })
|
||||
|
||||
describe('templateBuilder', () => {
|
||||
describe('signupTemplate', () => {
|
||||
describe('multi language', () => {
|
||||
|
||||
@ -28,6 +28,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
const createPostMutation = gql`
|
||||
|
||||
@ -10,11 +10,14 @@ const sendSignupMail = async (resolve, root, args, context, resolveInfo) => {
|
||||
const { inviteCode } = args
|
||||
const response = await resolve(root, args, context, resolveInfo)
|
||||
const { email, nonce } = response
|
||||
if (nonce) {
|
||||
// emails that already exist do not have a nonce
|
||||
if (inviteCode) {
|
||||
await sendMail(signupTemplate({ email, variables: { nonce, inviteCode } }))
|
||||
} else {
|
||||
await sendMail(signupTemplate({ email, variables: { nonce } }))
|
||||
}
|
||||
}
|
||||
delete response.nonce
|
||||
return response
|
||||
}
|
||||
@ -30,7 +33,9 @@ const sendPasswordResetMail = async (resolve, root, args, context, resolveInfo)
|
||||
const sendEmailVerificationMail = async (resolve, root, args, context, resolveInfo) => {
|
||||
const response = await resolve(root, args, context, resolveInfo)
|
||||
const { email, nonce, name } = response
|
||||
if (nonce) {
|
||||
await sendMail(emailVerificationTemplate({ email, variables: { nonce, name } }))
|
||||
}
|
||||
delete response.nonce
|
||||
return response
|
||||
}
|
||||
|
||||
@ -56,6 +56,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -24,6 +24,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -122,37 +122,41 @@ const isAllowedToChangeGroupMemberRole = rule({
|
||||
cache: 'no_cache',
|
||||
})(async (_parent, args, { user, driver }) => {
|
||||
if (!(user && user.id)) return false
|
||||
const adminId = user.id
|
||||
const currentUserId = user.id
|
||||
const { groupId, userId, roleInGroup } = args
|
||||
if (adminId === userId) return false
|
||||
if (currentUserId === userId) return false
|
||||
const session = driver.session()
|
||||
const readTxPromise = session.readTransaction(async (transaction) => {
|
||||
const transactionResponse = await transaction.run(
|
||||
`
|
||||
MATCH (admin:User {id: $adminId})-[adminMembership:MEMBER_OF]->(group:Group {id: $groupId})
|
||||
MATCH (currentUser:User {id: $currentUserId})-[currentUserMembership:MEMBER_OF]->(group:Group {id: $groupId})
|
||||
OPTIONAL MATCH (group)<-[userMembership:MEMBER_OF]-(member:User {id: $userId})
|
||||
RETURN group {.*}, admin {.*, myRoleInGroup: adminMembership.role}, member {.*, myRoleInGroup: userMembership.role}
|
||||
RETURN group {.*}, currentUser {.*, myRoleInGroup: currentUserMembership.role}, member {.*, myRoleInGroup: userMembership.role}
|
||||
`,
|
||||
{ groupId, adminId, userId },
|
||||
{ groupId, currentUserId, userId },
|
||||
)
|
||||
return {
|
||||
admin: transactionResponse.records.map((record) => record.get('admin'))[0],
|
||||
currentUser: transactionResponse.records.map((record) => record.get('currentUser'))[0],
|
||||
group: transactionResponse.records.map((record) => record.get('group'))[0],
|
||||
member: transactionResponse.records.map((record) => record.get('member'))[0],
|
||||
}
|
||||
})
|
||||
try {
|
||||
const { admin, group, member } = await readTxPromise
|
||||
const { currentUser, group, member } = await readTxPromise
|
||||
const groupExists = !!group
|
||||
const currentUserExists = !!currentUser
|
||||
const userIsMember = !!member
|
||||
const sameUserRoleInGroup = member && member.myRoleInGroup === roleInGroup
|
||||
const userIsOwner = member && ['owner'].includes(member.myRoleInGroup)
|
||||
const currentUserIsAdmin = currentUser && ['admin'].includes(currentUser.myRoleInGroup)
|
||||
const adminCanSetRole = ['pending', 'usual', 'admin'].includes(roleInGroup)
|
||||
const currentUserIsOwner = currentUser && ['owner'].includes(currentUser.myRoleInGroup)
|
||||
const ownerCanSetRole = ['pending', 'usual', 'admin', 'owner'].includes(roleInGroup)
|
||||
return (
|
||||
!!group &&
|
||||
!!admin &&
|
||||
(!member ||
|
||||
(!!member &&
|
||||
(member.myRoleInGroup === roleInGroup || !['owner'].includes(member.myRoleInGroup)))) &&
|
||||
((['admin'].includes(admin.myRoleInGroup) &&
|
||||
['pending', 'usual', 'admin'].includes(roleInGroup)) ||
|
||||
(['owner'].includes(admin.myRoleInGroup) &&
|
||||
['pending', 'usual', 'admin', 'owner'].includes(roleInGroup)))
|
||||
groupExists &&
|
||||
currentUserExists &&
|
||||
(!userIsMember || (userIsMember && (sameUserRoleInGroup || !userIsOwner))) &&
|
||||
((currentUserIsAdmin && adminCanSetRole) || (currentUserIsOwner && ownerCanSetRole))
|
||||
)
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
|
||||
@ -28,6 +28,7 @@ describe('authorization', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
// TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543
|
||||
|
||||
@ -2,9 +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 { createGroupMutation, updateGroupMutation } from '../db/graphql/groups'
|
||||
import { createPostMutation } from '../db/graphql/posts'
|
||||
import { signupVerificationMutation } from '../db/graphql/authentications'
|
||||
import { createGroupMutation, updateGroupMutation } from '../graphql/groups'
|
||||
import { createPostMutation } from '../graphql/posts'
|
||||
import { signupVerificationMutation } from '../graphql/authentications'
|
||||
|
||||
let authenticatedUser
|
||||
let variables
|
||||
@ -33,6 +33,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
@ -152,7 +153,7 @@ describe('slugifyMiddleware', () => {
|
||||
})
|
||||
|
||||
describe('but if the client specifies a slug', () => {
|
||||
it('rejects CreateGroup', async (done) => {
|
||||
it('rejects CreateGroup', async () => {
|
||||
try {
|
||||
await expect(
|
||||
mutate({
|
||||
@ -171,7 +172,6 @@ describe('slugifyMiddleware', () => {
|
||||
},
|
||||
],
|
||||
})
|
||||
done()
|
||||
} catch (error) {
|
||||
throw new Error(`
|
||||
${error}
|
||||
@ -258,7 +258,7 @@ describe('slugifyMiddleware', () => {
|
||||
})
|
||||
|
||||
describe('setting slug explicitly', () => {
|
||||
it('rejects UpdateGroup', async (done) => {
|
||||
it('rejects UpdateGroup', async () => {
|
||||
try {
|
||||
await expect(
|
||||
mutate({
|
||||
@ -275,7 +275,6 @@ describe('slugifyMiddleware', () => {
|
||||
},
|
||||
],
|
||||
})
|
||||
done()
|
||||
} catch (error) {
|
||||
throw new Error(`
|
||||
${error}
|
||||
@ -382,7 +381,7 @@ describe('slugifyMiddleware', () => {
|
||||
})
|
||||
|
||||
describe('but if the client specifies a slug', () => {
|
||||
it('rejects CreatePost', async (done) => {
|
||||
it('rejects CreatePost', async () => {
|
||||
try {
|
||||
await expect(
|
||||
mutate({
|
||||
@ -402,7 +401,6 @@ describe('slugifyMiddleware', () => {
|
||||
},
|
||||
],
|
||||
})
|
||||
done()
|
||||
} catch (error) {
|
||||
throw new Error(`
|
||||
${error}
|
||||
|
||||
@ -195,6 +195,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
describe('softDeleteMiddleware', () => {
|
||||
|
||||
@ -42,6 +42,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
describe('middleware/userInteractions', () => {
|
||||
|
||||
@ -75,6 +75,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -1,15 +1,22 @@
|
||||
import walkRecursive from '../helpers/walkRecursive'
|
||||
import { cleanHtml } from '../middleware/helpers/cleanHtml.js'
|
||||
|
||||
const fields = ['content', 'contentExcerpt', 'reasonDescription']
|
||||
// exclamation mark separetes field names, that should not be sanitized
|
||||
const fields = [
|
||||
'content',
|
||||
'contentExcerpt',
|
||||
'reasonDescription',
|
||||
'description!embed',
|
||||
'descriptionExcerpt',
|
||||
]
|
||||
|
||||
export default {
|
||||
Mutation: async (resolve, root, args, context, info) => {
|
||||
args = walkRecursive(args, fields, cleanHtml)
|
||||
args = walkRecursive(args, fields, info.fieldName, cleanHtml)
|
||||
return resolve(root, args, context, info)
|
||||
},
|
||||
Query: async (resolve, root, args, context, info) => {
|
||||
const result = await resolve(root, args, context, info)
|
||||
return walkRecursive(result, fields, cleanHtml)
|
||||
return walkRecursive(result, fields, info.fieldName, cleanHtml)
|
||||
},
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { cleanDatabase } from '../db/factories'
|
||||
import { getNeode } from '../db/neo4j'
|
||||
import { getNeode, getDriver } from '../db/neo4j'
|
||||
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
|
||||
beforeAll(async () => {
|
||||
@ -9,6 +10,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
// TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543
|
||||
@ -37,11 +39,10 @@ describe('slug', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('must be unique', async (done) => {
|
||||
it('must be unique', async () => {
|
||||
await neode.create('User', { slug: 'Matt' })
|
||||
try {
|
||||
await expect(neode.create('User', { slug: 'Matt' })).rejects.toThrow('already exists')
|
||||
done()
|
||||
} catch (error) {
|
||||
throw new Error(`
|
||||
${error}
|
||||
|
||||
@ -11,7 +11,7 @@ export default makeAugmentedSchema({
|
||||
'Badge',
|
||||
'Embed',
|
||||
'EmailAddress',
|
||||
'Notfication',
|
||||
'Notification',
|
||||
'Statistics',
|
||||
'LoggedInUser',
|
||||
'Location',
|
||||
|
||||
7
backend/src/schema/resolvers/Upload.js
Normal file
7
backend/src/schema/resolvers/Upload.js
Normal file
@ -0,0 +1,7 @@
|
||||
import { GraphQLUpload } from 'graphql-upload'
|
||||
|
||||
export default {
|
||||
// This maps the `Upload` scalar to the implementation provided
|
||||
// by the `graphql-upload` package.
|
||||
Upload: GraphQLUpload,
|
||||
}
|
||||
@ -25,6 +25,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -37,6 +37,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
describe('donations', () => {
|
||||
|
||||
@ -40,7 +40,9 @@ export default {
|
||||
}
|
||||
|
||||
// check email does not belong to anybody
|
||||
await existingEmailAddress({ args, context })
|
||||
const existingEmail = await existingEmailAddress({ args, context })
|
||||
if (existingEmail && existingEmail.alreadyExistingEmail && existingEmail.user)
|
||||
return existingEmail.alreadyExistingEmail
|
||||
|
||||
const nonce = generateNonce()
|
||||
const {
|
||||
|
||||
@ -30,6 +30,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
@ -134,11 +135,17 @@ describe('AddEmailAddress', () => {
|
||||
})
|
||||
|
||||
describe('but if another user owns an `EmailAddress` already with that email', () => {
|
||||
it('throws UserInputError because of unique constraints', async () => {
|
||||
it('does not throw UserInputError', async () => {
|
||||
await Factory.build('user', {}, { email: 'new-email@example.org' })
|
||||
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
|
||||
data: { AddEmailAddress: null },
|
||||
errors: [{ message: 'A user account with this email already exists.' }],
|
||||
data: {
|
||||
AddEmailAddress: {
|
||||
createdAt: expect.any(String),
|
||||
verifiedAt: null,
|
||||
email: 'new-email@example.org',
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -96,7 +96,7 @@ describe('Query', () => {
|
||||
description: null,
|
||||
html: null,
|
||||
image: null,
|
||||
lang: null,
|
||||
lang: 'false',
|
||||
publisher: null,
|
||||
sources: ['resource'],
|
||||
title: null,
|
||||
|
||||
@ -71,6 +71,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -97,7 +97,7 @@ export default {
|
||||
if (isMember) {
|
||||
cypher = `MATCH (user:User)-[membership:MEMBER_OF]->(group:Group)
|
||||
WHERE user.id = $userId
|
||||
AND membership.role IN ['usual', 'admin', 'owner']
|
||||
AND membership.role IN ['usual', 'admin', 'owner', 'pending']
|
||||
RETURN toString(count(group)) AS count`
|
||||
} else {
|
||||
cypher = `MATCH (group:Group)
|
||||
|
||||
@ -8,7 +8,7 @@ import {
|
||||
changeGroupMemberRoleMutation,
|
||||
groupMembersQuery,
|
||||
groupQuery,
|
||||
} from '../../db/graphql/groups'
|
||||
} from '../../graphql/groups'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
import CONFIG from '../../config'
|
||||
@ -252,6 +252,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
describe('in mode', () => {
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import { UserInputError } from 'apollo-server'
|
||||
|
||||
export default async function alreadyExistingMail({ args, context }) {
|
||||
const session = context.driver.session()
|
||||
try {
|
||||
@ -20,9 +18,11 @@ export default async function alreadyExistingMail({ args, context }) {
|
||||
})
|
||||
})
|
||||
const [emailBelongsToUser] = await existingEmailAddressTxPromise
|
||||
const { alreadyExistingEmail, user } = emailBelongsToUser || {}
|
||||
/*
|
||||
const { alreadyExistingEmail, user } =
|
||||
if (user) throw new UserInputError('A user account with this email already exists.')
|
||||
return alreadyExistingEmail
|
||||
*/
|
||||
return emailBelongsToUser || {}
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
|
||||
@ -113,10 +113,11 @@ const sanitizeRelationshipType = (relationshipType) => {
|
||||
const localFileUpload = ({ createReadStream, uniqueFilename }) => {
|
||||
const destination = `/uploads/${uniqueFilename}`
|
||||
return new Promise((resolve, reject) =>
|
||||
createReadStream()
|
||||
.pipe(createWriteStream(`public${destination}`))
|
||||
createReadStream().pipe(
|
||||
createWriteStream(`public${destination}`)
|
||||
.on('finish', () => resolve(destination))
|
||||
.on('error', reject),
|
||||
.on('error', (error) => reject(error)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
@ -78,7 +79,7 @@ describe('deleteImage', () => {
|
||||
await expect(someString).toEqual('Hello')
|
||||
})
|
||||
|
||||
it('rolls back the transaction in case of errors', async (done) => {
|
||||
it('rolls back the transaction in case of errors', async () => {
|
||||
await expect(neode.all('Image')).resolves.toHaveLength(1)
|
||||
const session = driver.session()
|
||||
try {
|
||||
@ -93,7 +94,6 @@ describe('deleteImage', () => {
|
||||
// nothing has been deleted
|
||||
await expect(neode.all('Image')).resolves.toHaveLength(1)
|
||||
// all good
|
||||
done()
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
@ -239,7 +239,7 @@ describe('mergeImage', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('rolls back the transaction in case of errors', async (done) => {
|
||||
it('rolls back the transaction in case of errors', async () => {
|
||||
const session = driver.session()
|
||||
try {
|
||||
await session.writeTransaction(async (transaction) => {
|
||||
@ -254,7 +254,6 @@ describe('mergeImage', () => {
|
||||
// nothing has been created
|
||||
await expect(neode.all('Image')).resolves.toHaveLength(0)
|
||||
// all good
|
||||
done()
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
|
||||
@ -52,6 +52,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
describe('inviteCodes', () => {
|
||||
|
||||
@ -26,6 +26,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
// TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543
|
||||
|
||||
@ -70,6 +70,7 @@ describe('moderate resources', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -29,6 +29,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -38,6 +38,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@ -56,6 +56,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -6,19 +6,19 @@ import {
|
||||
createGroupMutation,
|
||||
changeGroupMemberRoleMutation,
|
||||
leaveGroupMutation,
|
||||
} from '../../db/graphql/groups'
|
||||
} from '../../graphql/groups'
|
||||
import {
|
||||
createPostMutation,
|
||||
postQuery,
|
||||
filterPosts,
|
||||
profilePagePosts,
|
||||
searchPosts,
|
||||
} from '../../db/graphql/posts'
|
||||
import { createCommentMutation } from '../../db/graphql/comments'
|
||||
} from '../../graphql/posts'
|
||||
import { createCommentMutation } from '../../graphql/comments'
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import { DESCRIPTION_WITHOUT_HTML_LENGTH_MIN } from '../../constants/groups'
|
||||
import CONFIG from '../../config'
|
||||
import { signupVerificationMutation } from '../../db/graphql/authentications'
|
||||
import { signupVerificationMutation } from '../../graphql/authentications'
|
||||
|
||||
CONFIG.CATEGORIES_ACTIVE = false
|
||||
|
||||
@ -61,6 +61,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
describe('Posts in Groups', () => {
|
||||
|
||||
@ -13,7 +13,12 @@ export default {
|
||||
args.nonce = generateNonce()
|
||||
args.email = normalizeEmail(args.email)
|
||||
let emailAddress = await existingEmailAddress({ args, context })
|
||||
if (emailAddress) return emailAddress
|
||||
/*
|
||||
if (emailAddress.user) {
|
||||
// what to do?
|
||||
}
|
||||
*/
|
||||
if (emailAddress.alreadyExistingEmail) return emailAddress.alreadyExistingEmail
|
||||
try {
|
||||
emailAddress = await neode.create('EmailAddress', args)
|
||||
return emailAddress.toJson()
|
||||
|
||||
@ -29,6 +29,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
@ -118,9 +119,9 @@ describe('Signup', () => {
|
||||
await emailAddress.relateTo(user, 'belongsTo')
|
||||
})
|
||||
|
||||
it('throws UserInputError error because of unique constraint violation', async () => {
|
||||
it('does not throw UserInputError error', async () => {
|
||||
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
|
||||
errors: [{ message: 'A user account with this email already exists.' }],
|
||||
data: { Signup: { email: 'someuser@example.org' } },
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -117,6 +117,7 @@ describe('file a report on a resource', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
// TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543
|
||||
|
||||
@ -33,6 +33,7 @@ describe('rewards', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -26,6 +26,8 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
neode.close()
|
||||
})
|
||||
|
||||
const searchQuery = gql`
|
||||
|
||||
@ -51,6 +51,7 @@ describe('shout and unshout posts', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -12,6 +12,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
describe('SocialMedia', () => {
|
||||
|
||||
@ -39,6 +39,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
// TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543
|
||||
|
||||
@ -60,6 +60,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
describe('resolvers/userData', () => {
|
||||
|
||||
@ -2,14 +2,16 @@ 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 { loginMutation } from '../../graphql/userManagement'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer, { context } from '../../server'
|
||||
import encode from '../../jwt/encode'
|
||||
import { getNeode } from '../../db/neo4j'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import { categories } from '../../constants/categories'
|
||||
|
||||
const neode = getNeode()
|
||||
const driver = getDriver()
|
||||
|
||||
let query, mutate, variables, req, user
|
||||
|
||||
const disable = async (id) => {
|
||||
@ -47,6 +49,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
@ -137,7 +140,12 @@ describe('currentUser', () => {
|
||||
|
||||
describe('authenticated', () => {
|
||||
describe('and corresponding user in the database', () => {
|
||||
let avatar
|
||||
|
||||
beforeEach(async () => {
|
||||
avatar = await Factory.build('image', {
|
||||
url: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
|
||||
})
|
||||
await Factory.build(
|
||||
'user',
|
||||
{
|
||||
@ -149,9 +157,7 @@ describe('currentUser', () => {
|
||||
},
|
||||
{
|
||||
email: 'test@example.org',
|
||||
avatar: Factory.build('image', {
|
||||
url: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
|
||||
}),
|
||||
avatar,
|
||||
},
|
||||
)
|
||||
const userBearerToken = encode({ id: 'u3' })
|
||||
@ -163,9 +169,11 @@ describe('currentUser', () => {
|
||||
data: {
|
||||
currentUser: {
|
||||
id: 'u3',
|
||||
avatar: Factory.build('image', {
|
||||
url: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
|
||||
}),
|
||||
avatar: {
|
||||
url: expect.stringContaining(
|
||||
'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
|
||||
),
|
||||
},
|
||||
email: 'test@example.org',
|
||||
name: 'Matilde Hermiston',
|
||||
slug: 'matilde-hermiston',
|
||||
@ -243,7 +251,7 @@ describe('login', () => {
|
||||
|
||||
describe('ask for a `token`', () => {
|
||||
describe('with a valid email/password combination', () => {
|
||||
it('responds with a JWT bearer token', async (done) => {
|
||||
it('responds with a JWT bearer token', async () => {
|
||||
const {
|
||||
data: { login: token },
|
||||
} = await mutate({ mutation: loginMutation, variables })
|
||||
@ -252,7 +260,6 @@ describe('login', () => {
|
||||
id: 'acb2d923-f3af-479e-9f00-61b12e864666',
|
||||
})
|
||||
expect(err).toBeNull()
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -81,6 +81,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
// TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543
|
||||
|
||||
@ -90,6 +90,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@ -18,6 +18,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@ -28,6 +28,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
driver.close()
|
||||
})
|
||||
|
||||
describe('count post teaser views', () => {
|
||||
|
||||
@ -12,6 +12,7 @@ import { RedisPubSub } from 'graphql-redis-subscriptions'
|
||||
import { PubSub } from 'graphql-subscriptions'
|
||||
import Redis from 'ioredis'
|
||||
import bodyParser from 'body-parser'
|
||||
import { graphqlUploadExpress } from 'graphql-upload'
|
||||
|
||||
export const NOTIFICATION_ADDED = 'NOTIFICATION_ADDED'
|
||||
const { REDIS_DOMAIN, REDIS_PORT, REDIS_PASSWORD } = CONFIG
|
||||
@ -67,6 +68,7 @@ const createServer = (options) => {
|
||||
},
|
||||
},
|
||||
debug: !!CONFIG.DEBUG,
|
||||
uploads: false,
|
||||
tracing: !!CONFIG.DEBUG,
|
||||
formatError: (error) => {
|
||||
if (error.message === 'ERROR_VALIDATION') {
|
||||
@ -85,6 +87,7 @@ const createServer = (options) => {
|
||||
app.use(express.static('public'))
|
||||
app.use(bodyParser.json({ limit: '10mb' }))
|
||||
app.use(bodyParser.urlencoded({ limit: '10mb', extended: true }))
|
||||
app.use(graphqlUploadExpress())
|
||||
server.applyMiddleware({ app, path: '/' })
|
||||
const httpServer = http.createServer(app)
|
||||
server.installSubscriptionHandlers(httpServer)
|
||||
|
||||
8
backend/test/setup.js
Normal file
8
backend/test/setup.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Polyfill missing encoders in jsdom
|
||||
// https://stackoverflow.com/questions/68468203/why-am-i-getting-textencoder-is-not-defined-in-jest
|
||||
import { TextEncoder, TextDecoder } from 'util'
|
||||
global.TextEncoder = TextEncoder
|
||||
global.TextDecoder = TextDecoder
|
||||
|
||||
// Metascraper takes longer nowadays, double time
|
||||
jest.setTimeout(10000)
|
||||
4169
backend/yarn.lock
4169
backend/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -13,29 +13,29 @@ Feature: User profile - list social media accounts
|
||||
When I navigate to page "/settings/my-social-media"
|
||||
Then I am on page "/settings/my-social-media"
|
||||
When I add a social media link
|
||||
Then I see a toaster with "Added social media"
|
||||
Then I see a toaster with status "success"
|
||||
And the new social media link shows up on the page
|
||||
|
||||
Scenario: Other users viewing my Social Media
|
||||
Given I have added a social media link
|
||||
Given I have added the social media link "https://freeradical.zone/peter-pan"
|
||||
When I navigate to page "/profile/peter-pan"
|
||||
Then they should be able to see my social media links
|
||||
|
||||
Scenario: Deleting Social Media
|
||||
When I navigate to page "/settings/my-social-media"
|
||||
Then I am on page "/settings/my-social-media"
|
||||
Given I have added a social media link
|
||||
When I delete a social media link
|
||||
Then I see a toaster with "Deleted social media"
|
||||
Given I have added the social media link "https://freeradical.zone/peter-pan"
|
||||
When I delete the social media link "https://freeradical.zone/peter-pan"
|
||||
Then I see a toaster with status "success"
|
||||
|
||||
Scenario: Editing Social Media
|
||||
When I navigate to page "/settings/my-social-media"
|
||||
Then I am on page "/settings/my-social-media"
|
||||
Given I have added a social media link
|
||||
Given I have added the social media link "https://freeradical.zone/peter-pan"
|
||||
When I start editing a social media link
|
||||
Then I can cancel editing
|
||||
When I start editing a social media link
|
||||
And I edit and save the link
|
||||
Then I see a toaster with "Added social media"
|
||||
Then I see a toaster with status "success"
|
||||
And the new url is displayed
|
||||
But the old url is not displayed
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
import { Then } from "@badeball/cypress-cucumber-preprocessor";
|
||||
|
||||
Then('I can see my new name {string} when I click on my profile picture in the top right', name => {
|
||||
cy.get(".avatar-menu").then(($menu) => {
|
||||
if (!$menu.is(':visible')){
|
||||
cy.scrollTo("top");
|
||||
cy.wait(500);
|
||||
}
|
||||
})
|
||||
cy.get('.avatar-menu').click() // open
|
||||
cy.get('.avatar-menu-popover').contains(name)
|
||||
cy.get('.avatar-menu').click() // close again
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import { When } from "@badeball/cypress-cucumber-preprocessor";
|
||||
|
||||
When('I add a social media link', () => {
|
||||
cy.get('button')
|
||||
.contains('Add link')
|
||||
cy.get('[data-test="add-save-button"]')
|
||||
.click()
|
||||
.get('#editSocialMedia')
|
||||
.type('https://freeradical.zone/peter-pan')
|
||||
.get('button')
|
||||
.contains('Save')
|
||||
.get('[data-test="add-save-button"]')
|
||||
.click()
|
||||
})
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
import { When } from "cypress-cucumber-preprocessor/steps";
|
||||
|
||||
When('I delete the social media link {string}', (link) => {
|
||||
cy.get('[data-test="delete-button"]')
|
||||
.click()
|
||||
cy.get('[data-test="confirm-modal"]')
|
||||
.should("be.visible")
|
||||
cy.get('[data-test="confirm-button"]')
|
||||
.click()
|
||||
cy.get('.ds-list-item-content > a')
|
||||
.contains(link).should('not.exist')
|
||||
})
|
||||
@ -4,7 +4,6 @@ When('I edit and save the link', () => {
|
||||
cy.get('input#editSocialMedia')
|
||||
.clear()
|
||||
.type('https://freeradical.zone/tinkerbell')
|
||||
.get('button')
|
||||
.contains('Save')
|
||||
.get('[data-test="add-save-button"]')
|
||||
.click()
|
||||
})
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
import { Given } from "cypress-cucumber-preprocessor/steps";
|
||||
|
||||
Given('I have added the social media link {string}', (link) => {
|
||||
cy.visit('/settings/my-social-media')
|
||||
.get('[data-test="add-save-button"]')
|
||||
.click()
|
||||
.get('#editSocialMedia')
|
||||
.type(link)
|
||||
.get('[data-test="add-save-button"]')
|
||||
.click()
|
||||
cy.get('.ds-list-item-content > a')
|
||||
.contains(link)
|
||||
})
|
||||
@ -1,6 +1,6 @@
|
||||
import { When } from "@badeball/cypress-cucumber-preprocessor";
|
||||
|
||||
When('I start editing a social media link', () => {
|
||||
cy.get(".base-button[title='Edit']")
|
||||
cy.get('[data-test="edit-button"]')
|
||||
.click()
|
||||
})
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { Then } from "@badeball/cypress-cucumber-preprocessor";
|
||||
|
||||
Then('they should be able to see my social media links', () => {
|
||||
cy.get('.base-card')
|
||||
.contains('Where else can I find Peter Pan?')
|
||||
cy.get('[data-test="social-media-list-headline"]')
|
||||
.contains('Peter Pan')
|
||||
.get('a[href="https://freeradical.zone/peter-pan"]')
|
||||
.should('have.length', 1)
|
||||
})
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
import { When } from "@badeball/cypress-cucumber-preprocessor";
|
||||
|
||||
When("I log out", () => {
|
||||
cy.get(".avatar-menu").then(($menu) => {
|
||||
if (!$menu.is(':visible')){
|
||||
cy.scrollTo("top");
|
||||
cy.wait(500);
|
||||
}
|
||||
})
|
||||
cy.get(".avatar-menu")
|
||||
.click();
|
||||
cy.get(".avatar-menu-popover")
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
import { Then } from "cypress-cucumber-preprocessor/steps";
|
||||
|
||||
Then("I see a toaster with status {string}", (status) => {
|
||||
switch (status) {
|
||||
case "success":
|
||||
cy.get(".iziToast.iziToast-color-green").should("be.visible");
|
||||
break;
|
||||
}
|
||||
})
|
||||
@ -20,7 +20,6 @@ services:
|
||||
- GRAPHQL_URI=http://localhost:4000
|
||||
- CLIENT_URI=http://localhost:3000
|
||||
- JWT_SECRET=b/&&7b78BF&fv/Vd
|
||||
- MAPBOX_TOKEN=pk.eyJ1IjoiYnVzZmFrdG9yIiwiYSI6ImNraDNiM3JxcDBhaWQydG1uczhpZWtpOW4ifQ.7TNRTO-o9aK1Y6MyW_Nd4g
|
||||
- PRIVATE_KEY_PASSPHRASE=a7dsf78sadg87ad87sfagsadg78
|
||||
- NEO4J_apoc_import_file_enabled=true
|
||||
- "SSH_USERNAME=${SSH_USERNAME}"
|
||||
|
||||
@ -98,22 +98,22 @@ On a server with Kubernetes cluster:
|
||||
$ 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***
|
||||
***Cypher commands to show indexes and constraints***
|
||||
|
||||
```bash
|
||||
# in browser command line or cypher shell
|
||||
|
||||
# show all indexes and contraints
|
||||
# show all indexes and constraints
|
||||
$ :schema
|
||||
|
||||
# show all indexes
|
||||
$ CALL db.indexes();
|
||||
|
||||
# show all contraints
|
||||
# show all constraints
|
||||
$ CALL db.constraints();
|
||||
```
|
||||
|
||||
***Cypher commands to create and drop indexes and contraints***
|
||||
***Cypher commands to create and drop indexes and constraints***
|
||||
|
||||
```bash
|
||||
# in browser command line or cypher shell
|
||||
@ -126,6 +126,6 @@ $ 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
|
||||
# drop all indexes and constraints
|
||||
$ CALL apoc.schema.assert({},{},true) YIELD label, key RETURN * ;
|
||||
```
|
||||
|
||||
17
package.json
17
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ocelot-social",
|
||||
"version": "2.2.0",
|
||||
"version": "2.4.0",
|
||||
"description": "Free and open source software program code available to run social networks.",
|
||||
"author": "ocelot.social Community",
|
||||
"license": "MIT",
|
||||
@ -15,8 +15,8 @@
|
||||
"scripts": {
|
||||
"db:seed": "cd backend && yarn run db:seed",
|
||||
"db:reset": "cd backend && yarn run db:reset",
|
||||
"cypress:run": "cypress run --browser electron --config-file ./cypress/cypress.config.js",
|
||||
"cypress:open": "cypress open --browser electron --config-file ./cypress/cypress.config.js",
|
||||
"cypress:run": "cypress run --browser electron --config-file ./cypress/cypress.json",
|
||||
"cypress:open": "cypress open --browser electron --config-file ./cypress/cypress.json",
|
||||
"cucumber:setup": "cd backend && yarn run dev",
|
||||
"cucumber": "wait-on tcp:4000 && cucumber-js --require-module @babel/register --exit",
|
||||
"release": "yarn version --no-git-tag-version --no-commit-hooks --no-commit && auto-changelog --latest-version $(node -p -e \"require('./package.json').version\") && cd backend && yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version $(node -p -e \"require('./../package.json').version\") && cd ../webapp && yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version $(node -p -e \"require('./../package.json').version\") && cd ../webapp/maintenance/source && yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version $(node -p -e \"require('./../../../package.json').version\")"
|
||||
@ -25,15 +25,15 @@
|
||||
"@babel/core": "^7.9.0",
|
||||
"@babel/preset-env": "^7.12.7",
|
||||
"@babel/register": "^7.12.10",
|
||||
"@badeball/cypress-cucumber-preprocessor": "^13.0.3",
|
||||
"@cypress/browserify-preprocessor": "^3.0.2",
|
||||
"@faker-js/faker": "5.1.0",
|
||||
"auto-changelog": "^2.3.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"codecov": "^3.8.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"cypress": "^10.11.0",
|
||||
"cypress-file-upload": "^5.0.8",
|
||||
"cucumber": "^6.0.5",
|
||||
"cypress": "^7.0.1",
|
||||
"cypress-cucumber-preprocessor": "^2.2.1",
|
||||
"cypress-file-upload": "^3.5.3",
|
||||
"date-fns": "^2.25.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"expect": "^25.3.0",
|
||||
@ -48,7 +48,8 @@
|
||||
"slug": "^6.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"set-value": "^2.0.1"
|
||||
"set-value": "^2.0.1",
|
||||
"nan": "2.17.0"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
SENTRY_DSN_WEBAPP=
|
||||
COMMIT=
|
||||
PUBLIC_REGISTRATION=false
|
||||
INVITE_REGISTRATION=true
|
||||
WEBSOCKETS_URI=ws://localhost:3000/api/graphql
|
||||
GRAPHQL_URI=http://localhost:4000/
|
||||
MAPBOX_TOKEN="pk.eyJ1IjoiYnVzZmFrdG9yIiwiYSI6ImNraDNiM3JxcDBhaWQydG1uczhpZWtpOW4ifQ.7TNRTO-o9aK1Y6MyW_Nd4g"
|
||||
PUBLIC_REGISTRATION=false
|
||||
INVITE_REGISTRATION=true
|
||||
CATEGORIES_ACTIVE=false
|
||||
|
||||
@ -1 +1 @@
|
||||
v12.19.0
|
||||
v19.4.0
|
||||
@ -1,7 +1,7 @@
|
||||
##################################################################################
|
||||
# BASE (Is pushed to DockerHub for rebranding) ###################################
|
||||
##################################################################################
|
||||
FROM node:12.19.0-alpine3.10 as base
|
||||
FROM node:19.4.0-alpine3.17 as base
|
||||
|
||||
# ENVs
|
||||
## DOCKER_WORKDIR would be a classical ARG, but that is not multi layer persistent - shame
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
##################################################################################
|
||||
# BASE ###########################################################################
|
||||
##################################################################################
|
||||
FROM node:12.19.0-alpine3.10 as base
|
||||
FROM node:19.4.0-alpine3.17 as base
|
||||
|
||||
# ENVs
|
||||
## DOCKER_WORKDIR would be a classical ARG, but that is not multi layer persistent - shame
|
||||
|
||||
@ -4,18 +4,32 @@
|
||||
|
||||
## Installation
|
||||
|
||||
For preparation we need Node and recommend to use [node version manager](https://github.com/nvm-sh/nvm) `nvm` to switch
|
||||
between different local Node versions:
|
||||
|
||||
```bash
|
||||
# install Node
|
||||
$ cd webapp
|
||||
$ nvm install v16.19.0
|
||||
$ nvm use v16.19.0
|
||||
```
|
||||
|
||||
Install node dependencies with [yarn](https://yarnpkg.com/en/):
|
||||
|
||||
```bash
|
||||
# install all dependencies
|
||||
$ cd webapp/
|
||||
$ cd webapp
|
||||
$ yarn install
|
||||
# or just
|
||||
$ yarn
|
||||
# or just later on to use version of ".nvmrc" file
|
||||
$ nvm use && yarn
|
||||
```
|
||||
|
||||
Copy:
|
||||
|
||||
```text
|
||||
# in webapp/
|
||||
# in webapp
|
||||
cp .env.template .env
|
||||
```
|
||||
|
||||
|
||||
5
webapp/assets/_new/icons/svgs/angle-up.svg
Normal file
5
webapp/assets/_new/icons/svgs/angle-up.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>angle-up</title>
|
||||
<path d="M16 6.594l0.719 0.688 12.5 12.5-1.438 1.438-11.781-11.781-11.781 11.781-1.438-1.438 12.5-12.5z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 275 B |
1
webapp/assets/_new/icons/svgs/globe-detailed.svg
Normal file
1
webapp/assets/_new/icons/svgs/globe-detailed.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 121 KiB |
@ -31,7 +31,10 @@
|
||||
slot-scope="item"
|
||||
:route="item.route"
|
||||
:parents="item.parents"
|
||||
@click.native="closeMenu(false)"
|
||||
@click.native="
|
||||
closeMenu(false)
|
||||
$emit('toggle-Mobile-Menu-view')
|
||||
"
|
||||
>
|
||||
<base-icon :name="item.route.icon" />
|
||||
{{ item.route.name }}
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
import CategoryQuery from '~/graphql/CategoryQuery'
|
||||
import { CATEGORIES_MAX } from '~/constants/categories.js'
|
||||
import xor from 'lodash/xor'
|
||||
import SortCategories from '~/mixins/sortCategoriesMixin.js'
|
||||
|
||||
export default {
|
||||
inject: {
|
||||
@ -30,6 +31,7 @@ export default {
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
mixins: [SortCategories],
|
||||
props: {
|
||||
existingCategoryIds: { type: Array, default: () => [] },
|
||||
model: { type: String, required: true },
|
||||
@ -72,7 +74,7 @@ export default {
|
||||
return CategoryQuery()
|
||||
},
|
||||
result({ data: { Category } }) {
|
||||
this.categories = Category
|
||||
this.categories = this.sortCategories(Category)
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<ds-tag class="category-tag">
|
||||
<ds-tag class="category-tag" :class="filterActive ? 'filterActive' : ''">
|
||||
<base-icon :name="icon" />
|
||||
{{ name }}
|
||||
</ds-tag>
|
||||
@ -11,6 +11,7 @@ export default {
|
||||
props: {
|
||||
icon: { type: String, required: true },
|
||||
name: { type: String, default: '' },
|
||||
filterActive: { type: Boolean, default: false, required: false },
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -28,4 +29,7 @@ export default {
|
||||
font-size: $font-size-base;
|
||||
}
|
||||
}
|
||||
.filterActive {
|
||||
background-color: $color-success-active;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
:filled="!filteredCategoryIds.length"
|
||||
:label="$t('filter-menu.all')"
|
||||
icon="check"
|
||||
@click="resetCategories"
|
||||
@click="setResetCategories"
|
||||
/>
|
||||
</li>
|
||||
<li class="item item-save-topics">
|
||||
@ -39,15 +39,14 @@ import CategoryQuery from '~/graphql/CategoryQuery.js'
|
||||
import SaveCategories from '~/graphql/SaveCategories.js'
|
||||
import FilterMenuSection from '~/components/FilterMenu/FilterMenuSection'
|
||||
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
||||
import SortCategories from '~/mixins/sortCategoriesMixin.js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FilterMenuSection,
|
||||
LabeledButton,
|
||||
},
|
||||
props: {
|
||||
showMobileMenu: { type: Boolean, default: false },
|
||||
},
|
||||
mixins: [SortCategories],
|
||||
data() {
|
||||
return {
|
||||
categories: [],
|
||||
@ -63,6 +62,10 @@ export default {
|
||||
resetCategories: 'posts/RESET_CATEGORIES',
|
||||
toggleCategory: 'posts/TOGGLE_CATEGORY',
|
||||
}),
|
||||
setResetCategories() {
|
||||
this.resetCategories()
|
||||
this.$emit('showFilterMenu')
|
||||
},
|
||||
saveCategories() {
|
||||
this.$apollo
|
||||
.mutate({
|
||||
@ -70,6 +73,7 @@ export default {
|
||||
variables: { activeCategories: this.filteredCategoryIds },
|
||||
})
|
||||
.then(() => {
|
||||
this.$emit('showFilterMenu')
|
||||
this.$toast.success(this.$t('filter-menu.save.success'))
|
||||
})
|
||||
.catch(() => {
|
||||
@ -84,7 +88,7 @@ export default {
|
||||
},
|
||||
update({ Category }) {
|
||||
if (!Category) return []
|
||||
this.categories = Category
|
||||
this.categories = this.sortCategories(Category)
|
||||
},
|
||||
fetchPolicy: 'cache-and-network',
|
||||
},
|
||||
|
||||
@ -11,15 +11,7 @@
|
||||
<base-icon class="dropdown-arrow" name="angle-down" />
|
||||
</base-button>
|
||||
<template slot="popover">
|
||||
<div class="filter-menu-options">
|
||||
<h2 class="title">{{ $t('filter-menu.filter-by') }}</h2>
|
||||
<following-filter />
|
||||
<categories-filter v-if="categoriesActive" :showMobileMenu="showMobileMenu" />
|
||||
</div>
|
||||
<div class="filter-menu-options">
|
||||
<h2 class="title">{{ $t('filter-menu.order-by') }}</h2>
|
||||
<order-by-filter />
|
||||
</div>
|
||||
<filter-menu-component />
|
||||
</template>
|
||||
</dropdown>
|
||||
</template>
|
||||
@ -27,26 +19,16 @@
|
||||
<script>
|
||||
import Dropdown from '~/components/Dropdown'
|
||||
import { mapGetters } from 'vuex'
|
||||
import FollowingFilter from './FollowingFilter'
|
||||
import OrderByFilter from './OrderByFilter'
|
||||
import CategoriesFilter from './CategoriesFilter'
|
||||
import FilterMenuComponent from './FilterMenuComponent'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Dropdown,
|
||||
FollowingFilter,
|
||||
OrderByFilter,
|
||||
CategoriesFilter,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
categoriesActive: this.$env.CATEGORIES_ACTIVE,
|
||||
}
|
||||
FilterMenuComponent,
|
||||
},
|
||||
props: {
|
||||
placement: { type: String },
|
||||
offset: { type: [String, Number] },
|
||||
showMobileMenu: { type: Boolean, default: false },
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
@ -55,14 +37,3 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.filter-menu-options {
|
||||
max-width: $size-max-width-filter-menu;
|
||||
padding: $space-small $space-x-small;
|
||||
|
||||
> .title {
|
||||
font-size: $font-size-large;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
43
webapp/components/FilterMenu/FilterMenuComponent.vue
Normal file
43
webapp/components/FilterMenu/FilterMenuComponent.vue
Normal file
@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="filter-menu-options">
|
||||
<h2 class="title">{{ $t('filter-menu.filter-by') }}</h2>
|
||||
<following-filter />
|
||||
<categories-filter v-if="categoriesActive" @showFilterMenu="$emit('showFilterMenu')" />
|
||||
</div>
|
||||
<div class="filter-menu-options">
|
||||
<h2 class="title">{{ $t('filter-menu.order-by') }}</h2>
|
||||
<order-by-filter />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FollowingFilter from './FollowingFilter'
|
||||
import OrderByFilter from './OrderByFilter'
|
||||
import CategoriesFilter from './CategoriesFilter'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FollowingFilter,
|
||||
OrderByFilter,
|
||||
CategoriesFilter,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
categoriesActive: this.$env.CATEGORIES_ACTIVE,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.filter-menu-options {
|
||||
max-width: $size-max-width-filter-menu;
|
||||
padding: $space-small $space-x-small;
|
||||
|
||||
> .title {
|
||||
font-size: $font-size-large;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user