Compare commits

..

No commits in common. "master" and "b3.14.1-37" have entirely different histories.

316 changed files with 9469 additions and 10039 deletions

View File

@ -11,7 +11,7 @@ jobs:
documentation: ${{ steps.changes.outputs.documentation }} documentation: ${{ steps.changes.outputs.documentation }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Check for markdown file changes - name: Check for markdown file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@ -28,7 +28,7 @@ jobs:
if: needs.files-changed.outputs.markdown == 'true' if: needs.files-changed.outputs.markdown == 'true'
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Remove uncheckable documentation files - name: Remove uncheckable documentation files
run: rm -rf ./CHANGELOG.md # workaround until https://github.com/gaurav-nelson/github-action-markdown-link-check/pull/183 has been done run: rm -rf ./CHANGELOG.md # workaround until https://github.com/gaurav-nelson/github-action-markdown-link-check/pull/183 has been done
@ -51,10 +51,10 @@ jobs:
if: needs.files-changed.outputs.documentation == 'true' if: needs.files-changed.outputs.documentation == 'true'
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Setup Node 20 - name: Setup Node 20
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
with: with:
node-version: '20' node-version: '20'

View File

@ -13,7 +13,7 @@ jobs:
documentation: ${{ steps.changes.outputs.documentation }} documentation: ${{ steps.changes.outputs.documentation }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Check for file changes - name: Check for file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@ -27,10 +27,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Setup Node 20 - name: Setup Node 20
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
with: with:
node-version: 20 node-version: 20

View File

@ -59,9 +59,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Log in to the Container registry - name: Log in to the Container registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
with: with:
@ -83,7 +81,7 @@ jobs:
type=sha type=sha
- name: Build and push Docker images - name: Build and push Docker images
id: push id: push
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with: with:
context: ${{ matrix.app.context }} context: ${{ matrix.app.context }}
target: ${{ matrix.app.target }} target: ${{ matrix.app.target }}
@ -91,5 +89,3 @@ jobs:
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.app.name }}
cache-to: type=gha,mode=max,scope=${{ matrix.app.name }}

View File

@ -14,11 +14,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
with: with:
fetch-depth: 0 # Fetch full History for changelog fetch-depth: 0 # Fetch full History for changelog
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
- name: Setup env - name: Setup env
@ -58,11 +58,11 @@ jobs:
needs: [github_tag] needs: [github_tag]
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
with: with:
fetch-depth: 0 # Fetch full History for changelog fetch-depth: 0 # Fetch full History for changelog
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
- name: Setup env - name: Setup env

View File

@ -11,7 +11,7 @@ jobs:
backend: ${{ steps.changes.outputs.backend }} backend: ${{ steps.changes.outputs.backend }}
docker: ${{ steps.changes.outputs.docker }} docker: ${{ steps.changes.outputs.docker }}
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Check for backend file changes - name: Check for backend file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@ -28,24 +28,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Neo4J | Build 'community' image - name: Neo4J | Build 'community' image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 run: |
with: docker compose -f docker-compose.yml -f docker-compose.test.yml build neo4j
context: neo4j docker save "ghcr.io/ocelot-social-community/ocelot-social/neo4j:community" > /tmp/neo4j.tar
file: neo4j/Dockerfile
target: community
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/neo4j:community
cache-from: type=gha,scope=neo4j
cache-to: type=gha,mode=max,scope=neo4j
- name: Save image for test job
run: docker save "ghcr.io/ocelot-social-community/ocelot-social/neo4j:community" > /tmp/neo4j.tar
- name: Cache docker images - name: Cache docker images
id: cache-neo4j id: cache-neo4j
@ -61,24 +49,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: backend | Build 'test' image - name: backend | Build 'test' image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 run: |
with: docker compose -f docker-compose.yml -f docker-compose.test.yml build backend
context: backend docker save "ghcr.io/ocelot-social-community/ocelot-social/backend:test" > /tmp/backend.tar
file: backend/Dockerfile
target: test
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/backend:test
cache-from: type=gha,scope=backend-test
cache-to: type=gha,mode=max,scope=backend-test
- name: Save image for test job
run: docker save "ghcr.io/ocelot-social-community/ocelot-social/backend:test" > /tmp/backend.tar
- name: Cache docker images - name: Cache docker images
id: cache-backend id: cache-backend
@ -94,17 +70,15 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
with: with:
node-version-file: 'backend/.nvmrc' node-version-file: 'backend/.nvmrc'
cache: 'yarn'
cache-dependency-path: 'backend/yarn.lock'
- name: backend | Lint - name: backend | Lint
run: cd backend && yarn --frozen-lockfile && yarn run lint run: cd backend && yarn && yarn run lint
unit_test_backend: unit_test_backend:
name: Unit tests - Backend name: Unit tests - Backend
@ -115,7 +89,7 @@ jobs:
checks: write checks: write
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Restore Neo4J cache - name: Restore Neo4J cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2

View File

@ -8,52 +8,28 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Copy backend env file - name: Copy backend env file
run: | run: |
cp backend/.env.test_e2e backend/.env cp backend/.env.test_e2e backend/.env
cp webapp/.env.template webapp/.env cp webapp/.env.template webapp/.env
- name: Neo4J | Build image - name: Build backend and dependencies
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: neo4j
file: neo4j/Dockerfile
target: community
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/neo4j:community
cache-from: type=gha,scope=neo4j
cache-to: type=gha,mode=max,scope=neo4j
- name: Backend | Build image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: backend
file: backend/Dockerfile
target: test
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/backend:test
cache-from: type=gha,scope=backend-test
cache-to: type=gha,mode=max,scope=backend-test
- name: Pull third-party images
run: | run: |
docker pull quay.io/minio/minio:latest # Build and start all required images for backend
docker pull quay.io/minio/mc:latest docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach neo4j backend --build
docker pull maildev/maildev:latest
- name: Save all images # Save the build images
run: |
docker save "ghcr.io/ocelot-social-community/ocelot-social/backend:test" > /tmp/backend.tar docker save "ghcr.io/ocelot-social-community/ocelot-social/backend:test" > /tmp/backend.tar
docker save "ghcr.io/ocelot-social-community/ocelot-social/neo4j:community" > /tmp/neo4j.tar docker save "ghcr.io/ocelot-social-community/ocelot-social/neo4j:community" > /tmp/neo4j.tar
docker save "quay.io/minio/minio:latest" > /tmp/minio.tar docker save "quay.io/minio/minio:latest" > /tmp/minio.tar
docker save "quay.io/minio/mc:latest" > /tmp/minio-mc.tar docker save "quay.io/minio/mc:latest" > /tmp/minio-mc.tar
docker save "maildev/maildev:latest" > /tmp/mailserver.tar docker save "maildev/maildev:latest" > /tmp/mailserver.tar
# Stop the containers
docker compose -f docker-compose.yml -f docker-compose.test.yml down
- name: Cache docker images - name: Cache docker images
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
with: with:
@ -70,24 +46,17 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
- name: Set up Docker Buildx - name: Copy backend env file
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 run: |
cp backend/.env.test_e2e backend/.env
cp webapp/.env.template webapp/.env
- name: Webapp | Build 'test' image - name: Build docker image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 run: |
with: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach webapp --build --no-deps
context: . docker save "ghcr.io/ocelot-social-community/ocelot-social/webapp:test" > /tmp/webapp.tar
file: webapp/Dockerfile
target: test
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/webapp:test
cache-from: type=gha,scope=webapp-test
cache-to: type=gha,mode=max,scope=webapp-test
- name: Save image for test jobs
run: docker save "ghcr.io/ocelot-social-community/ocelot-social/webapp:test" > /tmp/webapp.tar
- name: Cache docker image - name: Cache docker image
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
@ -103,10 +72,10 @@ jobs:
run: rm -rf /opt/hostedtoolcache run: rm -rf /opt/hostedtoolcache
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.4.0
with: with:
node-version-file: 'backend/.nvmrc' node-version-file: 'backend/.nvmrc'
cache: 'yarn' cache: 'yarn'
@ -118,8 +87,7 @@ jobs:
- name: Install cypress requirements - name: Install cypress requirements
run: | run: |
sudo wget --no-verbose -O /opt/cucumber-json-formatter "https://github.com/cucumber/json-formatter/releases/download/v19.0.0/cucumber-json-formatter-linux-amd64" sudo wget --no-verbose -O /opt/cucumber-json-formatter "https://github.com/cucumber/json-formatter/releases/download/v19.0.0/cucumber-json-formatter-linux-386"
echo "66a2ef158866c3ecb3d8e49a7189814a485bddca43e133e4ca5735b8d3951bf7 /opt/cucumber-json-formatter" | sha256sum -c -
sudo chmod +x /opt/cucumber-json-formatter sudo chmod +x /opt/cucumber-json-formatter
cd backend cd backend
yarn install yarn install
@ -144,7 +112,7 @@ jobs:
features: ${{ steps.list.outputs.features }} features: ${{ steps.list.outputs.features }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
- name: List feature files - name: List feature files
id: list id: list
@ -166,10 +134,10 @@ jobs:
run: rm -rf /opt/hostedtoolcache run: rm -rf /opt/hostedtoolcache
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.4.0
with: with:
node-version-file: 'backend/.nvmrc' node-version-file: 'backend/.nvmrc'
cache: 'yarn' cache: 'yarn'
@ -201,22 +169,10 @@ jobs:
path: /tmp/webapp.tar path: /tmp/webapp.tar
key: ${{ github.run_id }}-e2e-webapp-cache key: ${{ github.run_id }}-e2e-webapp-cache
- name: Copy env files
run: |
cp webapp/.env.template webapp/.env
cp backend/.env.test_e2e backend/.env
- name: Ensure cucumber-json-formatter exists
run: |
if [ ! -f /opt/cucumber-json-formatter ]; then
sudo wget --no-verbose -O /opt/cucumber-json-formatter "https://github.com/cucumber/json-formatter/releases/download/v19.0.0/cucumber-json-formatter-linux-amd64"
echo "66a2ef158866c3ecb3d8e49a7189814a485bddca43e133e4ca5735b8d3951bf7 /opt/cucumber-json-formatter" | sha256sum -c -
fi
sudo chmod +x /opt/cucumber-json-formatter
sudo ln -fs /opt/cucumber-json-formatter /usr/bin/cucumber-json-formatter
- name: Boot up test system | docker compose - name: Boot up test system | docker compose
run: | run: |
chmod +x /opt/cucumber-json-formatter
sudo ln -fs /opt/cucumber-json-formatter /usr/bin/cucumber-json-formatter
docker load < /tmp/neo4j.tar docker load < /tmp/neo4j.tar
docker load < /tmp/backend.tar docker load < /tmp/backend.tar
docker load < /tmp/minio.tar docker load < /tmp/minio.tar
@ -224,14 +180,7 @@ jobs:
docker load < /tmp/mailserver.tar docker load < /tmp/mailserver.tar
docker load < /tmp/webapp.tar docker load < /tmp/webapp.tar
docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach backend mailserver webapp docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach backend mailserver webapp
sleep 90s
echo "Waiting for backend (max 120s)..."
timeout 120 bash -c 'until curl -sf -X POST -H "Content-Type: application/json" -d "{\"query\":\"{__typename}\"}" http://localhost:4000 > /dev/null 2>&1; do sleep 5; done'
echo "Backend is ready."
echo "Waiting for webapp (max 120s)..."
timeout 120 bash -c 'until curl -sf http://localhost:3000 > /dev/null 2>&1; do sleep 5; done'
echo "Webapp is ready."
- name: Full stack tests | run tests - name: Full stack tests | run tests
id: e2e-tests id: e2e-tests

View File

@ -11,7 +11,7 @@ jobs:
docker: ${{ steps.changes.outputs.docker }} docker: ${{ steps.changes.outputs.docker }}
webapp: ${{ steps.changes.outputs.webapp }} webapp: ${{ steps.changes.outputs.webapp }}
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Check for frontend file changes - name: Check for frontend file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@ -28,10 +28,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
with: with:
node-version-file: 'webapp/.nvmrc' node-version-file: 'webapp/.nvmrc'
@ -43,28 +43,16 @@ jobs:
build_test_webapp: build_test_webapp:
name: Docker Build Test - Webapp name: Docker Build Test - Webapp
if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.webapp == 'true' if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.webapp == 'true'
needs: files-changed needs: [files-changed, prepare]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Webapp | Build 'test' image - name: Webapp | Build 'test' image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 run: |
with: docker build --target test -f webapp/Dockerfile -t "ghcr.io/ocelot-social-community/ocelot-social/webapp:test" .
context: . docker save "ghcr.io/ocelot-social-community/ocelot-social/webapp:test" > /tmp/webapp.tar
file: webapp/Dockerfile
target: test
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/webapp:test
cache-from: type=gha,scope=webapp-test
cache-to: type=gha,mode=max,scope=webapp-test
- name: Save image for test job
run: docker save "ghcr.io/ocelot-social-community/ocelot-social/webapp:test" > /tmp/webapp.tar
- name: Cache docker image - name: Cache docker image
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
@ -79,17 +67,15 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
with: with:
node-version-file: 'webapp/.nvmrc' node-version-file: 'webapp/.nvmrc'
cache: 'yarn'
cache-dependency-path: 'webapp/yarn.lock'
- name: webapp | Lint - name: webapp | Lint
run: cd webapp && yarn --frozen-lockfile && yarn run lint run: cd webapp && yarn && yarn run lint
unit_test_webapp: unit_test_webapp:
name: Unit Tests - Webapp name: Unit Tests - Webapp
@ -100,7 +86,7 @@ jobs:
checks: write checks: write
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Restore webapp cache - name: Restore webapp cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2

View File

@ -34,26 +34,26 @@ jobs:
uses: actions/checkout@v6 uses: actions/checkout@v6
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 uses: docker/setup-buildx-action@v3
- name: Build development image - name: Build development image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 uses: docker/build-push-action@v6
with: with:
context: ./packages/ui context: ./packages/ui
file: ./packages/ui/Dockerfile file: ./packages/ui/Dockerfile
target: development target: development
push: false push: false
tags: ocelot-social/ui:development tags: ocelot-social/ui:development
cache-from: type=gha,scope=ui-development cache-from: type=gha
cache-to: type=gha,mode=max,scope=ui-development cache-to: type=gha,mode=max
- name: Build production image - name: Build production image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 uses: docker/build-push-action@v6
with: with:
context: ./packages/ui context: ./packages/ui
file: ./packages/ui/Dockerfile file: ./packages/ui/Dockerfile
target: production target: production
push: false push: false
tags: ocelot-social/ui:latest tags: ocelot-social/ui:latest
cache-from: type=gha,scope=ui-production cache-from: type=gha
cache-to: type=gha,mode=max,scope=ui-production cache-to: type=gha,mode=max

View File

@ -1,62 +1,73 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-call */ import comments from 'eslint-config-it4c/modules/comments'
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ import eslint from 'eslint-config-it4c/modules/eslint'
/* eslint-disable @typescript-eslint/no-unsafe-return */ import importX from 'eslint-config-it4c/modules/import-x'
import config from 'eslint-config-it4c'
import graphql from 'eslint-config-it4c/modules/graphql'
import jest from 'eslint-config-it4c/modules/jest' import jest from 'eslint-config-it4c/modules/jest'
import json from 'eslint-config-it4c/modules/json'
import node from 'eslint-config-it4c/modules/node'
import prettier from 'eslint-config-it4c/modules/prettier'
import promise from 'eslint-config-it4c/modules/promise'
import security from 'eslint-config-it4c/modules/security'
import typescript from 'eslint-config-it4c/modules/typescript'
import yaml from 'eslint-config-it4c/modules/yaml'
// TODO: GraphQL linting is disabled because @graphql-eslint/eslint-plugin v4
// (bundled with eslint-config-it4c) requires graphql@^16, but the backend
// uses graphql@^14 (required by apollo-server v2). Re-enable when upgrading graphql.
// import graphql from 'eslint-config-it4c/modules/graphql'
//
// ...graphql.map((c) => ({
// ...c,
// files: ['**/*.graphql', '**/*.gql'],
// })),
// {
// files: ['**/*.graphql', '**/*.gql'],
// languageOptions: {
// parserOptions: {
// schema: './src/graphql/types/**/*.gql',
// assumeValid: true,
// },
// },
// rules: {
// '@graphql-eslint/require-description': 'off',
// '@graphql-eslint/naming-convention': 'off',
// '@graphql-eslint/strict-id-in-types': 'off',
// '@graphql-eslint/no-typename-prefix': 'off',
// '@graphql-eslint/known-directives': 'off',
// '@graphql-eslint/known-argument-names': 'off',
// '@graphql-eslint/known-type-names': 'off',
// '@graphql-eslint/lone-schema-definition': 'off',
// '@graphql-eslint/provided-required-arguments': 'off',
// '@graphql-eslint/unique-directive-names': 'off',
// '@graphql-eslint/unique-directive-names-per-location': 'off',
// '@graphql-eslint/unique-field-definition-names': 'off',
// '@graphql-eslint/unique-operation-types': 'off',
// '@graphql-eslint/unique-type-names': 'off',
// },
// },
export default [ export default [
{ {
ignores: ['node_modules/', 'build/', 'coverage/'], ignores: ['node_modules/', 'build/', 'coverage/'],
}, },
...config, ...eslint,
...typescript,
...importX,
...node,
...promise,
...security,
...comments,
...json,
...yaml,
...prettier,
...jest, ...jest,
// GraphQL schema linting (extend file pattern to include .gql)
...graphql.map((c) => ({
...c,
files: ['**/*.graphql', '**/*.gql'],
})),
{
files: ['**/*.graphql', '**/*.gql'],
// TODO: Parser must be set explicitly because the it4c module only provides
// plugins and rules, not languageOptions. Without this, ESLint uses the JS
// parser for .gql files. Remove when fixed in eslint-config-it4c.
languageOptions: {
parser: graphql[0].plugins['@graphql-eslint'].parser,
parserOptions: {
graphQLConfig: {
schema: './src/graphql/types/**/*.gql',
documents: './src/graphql/queries/**/*.gql',
},
},
},
rules: {
// Would require descriptions on every type/field/input — too noisy for now
'@graphql-eslint/require-description': 'off',
// camelCase operation names and _id/_ne underscores conflict with existing schema
'@graphql-eslint/naming-convention': 'off',
// Many types (Image, File, InviteCode, etc.) intentionally lack id: ID!
'@graphql-eslint/strict-id-in-types': 'off',
// Fields like groupType, queryLocations match parent type name by coincidence
'@graphql-eslint/no-typename-prefix': 'off',
// neo4j-graphql-js adds arguments (first, offset) at runtime not present in static schema
'@graphql-eslint/known-argument-names': 'off',
// TODO: operations-recommended rules must be disabled because the it4c
// graphql module bundles both schema and operations configs together.
// Remove when eslint-config-it4c exports them separately (e.g. graphql/schema).
'@graphql-eslint/executable-definitions': 'off',
// neo4j-graphql-js adds fields at runtime (_id, relations) not present in static schema
'@graphql-eslint/fields-on-correct-type': 'off',
},
},
{ {
// Backend-specific TypeScript overrides // Backend-specific TypeScript overrides
files: ['**/*.ts'], files: ['**/*.ts'],
languageOptions: { languageOptions: {
parserOptions: { parserOptions: {
projectService: { projectService: {
allowDefaultProject: ['eslint.config.ts', 'jest.config.ts', 'prettier.config.ts'], allowDefaultProject: ['eslint.config.ts'],
}, },
tsconfigRootDir: import.meta.dirname, tsconfigRootDir: import.meta.dirname,
}, },

27
backend/jest.config.cjs Normal file
View File

@ -0,0 +1,27 @@
/* eslint-disable import-x/no-commonjs */
const requireJSON5 = require('require-json5')
const { pathsToModuleNameMapper } = require('ts-jest')
const { compilerOptions } = requireJSON5('./tsconfig.json')
module.exports = {
verbose: true,
preset: 'ts-jest',
collectCoverage: true,
collectCoverageFrom: [
'**/*.ts',
'!**/node_modules/**',
'!**/test/**',
'!**/build/**',
'!**/src/**/?(*.)+(spec|test).ts?(x)',
'!**/src/db/**',
],
coverageThreshold: {
global: {
lines: 93,
},
},
testMatch: ['**/src/**/?(*.)+(spec|test).ts?(x)'],
setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/' }),
}

View File

@ -1,40 +0,0 @@
import { readFileSync } from 'node:fs'
import { pathsToModuleNameMapper } from 'ts-jest'
import { parseConfigFileTextToJson } from 'typescript'
// eslint-disable-next-line n/no-sync -- config files are synchronous by nature
const tsconfigText = readFileSync('./tsconfig.json', 'utf-8')
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- parseConfigFileTextToJson returns untyped config
const { config } = parseConfigFileTextToJson('tsconfig.json', tsconfigText)
const paths = (config as { compilerOptions: { paths: Record<string, string[]> } }).compilerOptions
.paths
export default {
verbose: true,
preset: 'ts-jest',
collectCoverage: true,
collectCoverageFrom: [
'**/*.ts',
'!**/node_modules/**',
'!**/test/**',
'!**/build/**',
'!**/src/**/?(*.)+(spec|test).ts?(x)',
'!**/src/db/**',
'!*.config.ts',
'!**/*.d.ts',
'!**/gql-register.ts',
],
coverageThreshold: {
global: {
lines: 93,
},
},
testMatch: ['**/src/**/?(*.)+(spec|test).ts?(x)'],
setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],
transform: {
'\\.gql$': '<rootDir>/test/graphqlTransform.ts',
'\\.tsx?$': 'ts-jest',
},
moduleNameMapper: pathsToModuleNameMapper(paths, { prefix: '<rootDir>/' }),
}

View File

@ -10,20 +10,20 @@
"scripts": { "scripts": {
"start": "node build/src/", "start": "node build/src/",
"build": "tsc && tsc-alias && ./scripts/build.copy.files.sh", "build": "tsc && tsc-alias && ./scripts/build.copy.files.sh",
"dev": "nodemon --exec tsx src/index.ts -e js,ts,gql", "dev": "nodemon --exec ts-node --require tsconfig-paths/register src/index.ts -e js,ts,gql",
"dev:debug": "nodemon --exec node --inspect=0.0.0.0:9229 build/src/index.js -e js,ts,gql", "dev:debug": "nodemon --exec node --inspect=0.0.0.0:9229 build/src/index.js -e js,ts,gql",
"lint": "eslint --max-warnings 0 .", "lint": "eslint --max-warnings 0 .",
"test": "cross-env NODE_ENV=test NODE_OPTIONS=--max-old-space-size=8192 jest --runInBand --coverage --forceExit --detectOpenHandles", "test": "cross-env NODE_ENV=test NODE_OPTIONS=--max-old-space-size=8192 jest --runInBand --coverage --forceExit --detectOpenHandles",
"db:reset": "tsx src/db/reset.ts", "db:reset": "ts-node --require tsconfig-paths/register src/db/reset.ts",
"db:reset:withmigrations": "tsx src/db/reset-with-migrations.ts", "db:reset:withmigrations": "ts-node --require tsconfig-paths/register src/db/reset-with-migrations.ts",
"db:seed": "tsx --require ./src/graphql/gql-register.ts src/db/seed.ts", "db:seed": "ts-node --require tsconfig-paths/register src/db/seed.ts",
"db:data:admin": "tsx src/db/admin.ts", "db:data:admin": "ts-node --require tsconfig-paths/register src/db/admin.ts",
"db:data:badges": "tsx src/db/badges.ts", "db:data:badges": "ts-node --require tsconfig-paths/register src/db/badges.ts",
"db:data:branding": "tsx src/db/data-branding.ts", "db:data:branding": "ts-node --require tsconfig-paths/register src/db/data-branding.ts",
"db:data:categories": "tsx src/db/categories.ts", "db:data:categories": "ts-node --require tsconfig-paths/register src/db/categories.ts",
"db:migrate": "migrate --compiler 'ts:./src/db/compiler.ts' --migrations-dir ./src/db/migrations --store ./src/db/migrate/store.ts", "db:migrate": "migrate --compiler 'ts:./src/db/compiler.ts' --migrations-dir ./src/db/migrations --store ./src/db/migrate/store.ts",
"db:migrate:create": "migrate --compiler 'ts:./src/db/compiler.ts' --migrations-dir ./src/db/migrations --template-file ./src/db/migrate/template.ts --date-format 'yyyymmddHHmmss' create", "db:migrate:create": "migrate --compiler 'ts:./src/db/compiler.ts' --migrations-dir ./src/db/migrations --template-file ./src/db/migrate/template.ts --date-format 'yyyymmddHHmmss' create",
"db:func:disable:notifications": "tsx src/db/disable-notifications.ts", "db:func:disable:notifications": "ts-node --require tsconfig-paths/register src/db/disable-notifications.ts",
"prod:migrate": "migrate --migrations-dir ./build/src/db/migrations --store ./build/src/db/migrate/store.js", "prod:migrate": "migrate --migrations-dir ./build/src/db/migrations --store ./build/src/db/migrate/store.js",
"prod:db:data:branding": "node build/src/db/data-branding.js", "prod:db:data:branding": "node build/src/db/data-branding.js",
"prod:db:data:categories": "node build/src/db/categories.js", "prod:db:data:categories": "node build/src/db/categories.js",
@ -31,27 +31,27 @@
"prod:db:func:disable:notifications": "node build/src/db/disable-notifications.js" "prod:db:func:disable:notifications": "node build/src/db/disable-notifications.js"
}, },
"dependencies": { "dependencies": {
"@apollo/server": "^4.11.3", "@aws-sdk/client-s3": "^3.995.0",
"@aws-sdk/client-s3": "^3.1000.0", "@aws-sdk/lib-storage": "^3.990.0",
"@aws-sdk/lib-storage": "^3.1000.0",
"@graphql-tools/load-files": "^7.0.0",
"@graphql-tools/merge": "^9.0.0",
"@sentry/node": "^5.30.0", "@sentry/node": "^5.30.0",
"@types/mime-types": "^3.0.1", "@types/mime-types": "^3.0.1",
"apollo-server": "~2.14.2",
"apollo-server-express": "^2.14.2",
"bcryptjs": "~3.0.3", "bcryptjs": "~3.0.3",
"body-parser": "^2.2.2", "body-parser": "^1.20.3",
"cheerio": "~1.2.0", "cheerio": "~1.2.0",
"cross-env": "~10.1.0", "cross-env": "~10.1.0",
"dotenv": "~17.0.1", "dotenv": "~17.0.1",
"email-templates": "^13.0.1", "email-templates": "^13.0.1",
"express": "^4.22.1", "express": "^4.22.1",
"graphql": "^16.13.0", "graphql": "^14.6.0",
"graphql-middleware": "~6.1.35", "graphql-middleware": "~6.1.35",
"graphql-middleware-sentry": "^3.2.1",
"graphql-redis-subscriptions": "^2.7.0", "graphql-redis-subscriptions": "^2.7.0",
"graphql-shield": "^7.6.5", "graphql-shield": "~7.2.2",
"graphql-subscriptions": "^2.0.0", "graphql-subscriptions": "^1.1.0",
"graphql-tag": "~2.10.3",
"graphql-upload": "^13.0.0", "graphql-upload": "^13.0.0",
"graphql-ws": "^5.16.2",
"helmet": "~8.1.0", "helmet": "~8.1.0",
"ioredis": "^5.9.3", "ioredis": "^5.9.3",
"jsonwebtoken": "~8.5.1", "jsonwebtoken": "~8.5.1",
@ -59,23 +59,24 @@
"linkify-html": "^4.3.2", "linkify-html": "^4.3.2",
"linkifyjs": "^4.3.2", "linkifyjs": "^4.3.2",
"lodash": "~4.17.23", "lodash": "~4.17.23",
"metascraper": "^5.49.24", "merge-graphql-schemas": "^1.7.8",
"metascraper-author": "^5.49.24", "metascraper": "^5.49.19",
"metascraper-date": "^5.49.24", "metascraper-author": "^5.49.19",
"metascraper-description": "^5.49.24", "metascraper-date": "^5.49.19",
"metascraper-image": "^5.49.24", "metascraper-description": "^5.49.19",
"metascraper-lang": "^5.49.24", "metascraper-image": "^5.49.19",
"metascraper-lang": "^5.49.19",
"metascraper-lang-detector": "^4.10.2", "metascraper-lang-detector": "^4.10.2",
"metascraper-logo": "^5.49.24", "metascraper-logo": "^5.49.19",
"metascraper-publisher": "^5.49.24", "metascraper-publisher": "^5.49.19",
"metascraper-soundcloud": "^5.34.4", "metascraper-soundcloud": "^5.34.4",
"metascraper-title": "^5.49.24", "metascraper-title": "^5.49.19",
"metascraper-url": "^5.49.24", "metascraper-url": "^5.49.19",
"metascraper-video": "^5.49.24", "metascraper-video": "^5.49.19",
"metascraper-youtube": "^5.49.24", "metascraper-youtube": "^5.49.20",
"migrate": "^2.1.0", "migrate": "^2.1.0",
"mime-types": "^3.0.2", "mime-types": "^3.0.2",
"minimatch": "^10.2.4", "minimatch": "^10.2.2",
"mustache": "^4.2.0", "mustache": "^4.2.0",
"neo4j-driver": "^4.4.11", "neo4j-driver": "^4.4.11",
"neo4j-graphql-js": "2.11.5", "neo4j-graphql-js": "2.11.5",
@ -87,12 +88,10 @@
"pug": "^3.0.3", "pug": "^3.0.3",
"sanitize-html": "~2.17.1", "sanitize-html": "~2.17.1",
"slugify": "^1.6.6", "slugify": "^1.6.6",
"subscriptions-transport-ws": "^0.11.0",
"trunc-html": "~1.1.2", "trunc-html": "~1.1.2",
"tslog": "^4.10.2", "tslog": "^4.10.2",
"uuid": "~9.0.1", "uuid": "~9.0.1",
"validator": "^13.15.26", "validator": "^13.15.26",
"ws": "^8.18.2",
"xregexp": "^5.1.2" "xregexp": "^5.1.2"
}, },
"devDependencies": { "devDependencies": {
@ -100,21 +99,23 @@
"@types/email-templates": "^10.0.4", "@types/email-templates": "^10.0.4",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/jsonwebtoken": "~8.5.1", "@types/jsonwebtoken": "~8.5.1",
"@types/lodash": "^4.17.24", "@types/lodash": "^4.17.23",
"@types/node": "^25.3.2", "@types/node": "^25.3.0",
"@types/request": "^2.48.13", "@types/request": "^2.48.13",
"@types/slug": "^5.0.9", "@types/slug": "^5.0.9",
"@types/uuid": "~9.0.1", "@types/uuid": "~9.0.1",
"@types/ws": "^8.18.1", "apollo-server-testing": "~2.11.0",
"eslint": "^9.27.0", "eslint": "^9.27.0",
"eslint-config-it4c": "^0.12.0", "eslint-config-it4c": "^0.12.0",
"jest": "^30.2.0", "jest": "^30.2.0",
"nodemon": "~3.1.14", "nodemon": "~3.1.11",
"prettier": "^3.8.1", "prettier": "^3.8.1",
"require-json5": "^1.3.0",
"rosie": "^2.1.1", "rosie": "^2.1.1",
"ts-jest": "^29.4.6", "ts-jest": "^29.4.6",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.16", "tsc-alias": "^1.8.16",
"tsx": "^4.21.0", "tsconfig-paths": "^4.2.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
}, },
"resolutions": { "resolutions": {
@ -124,9 +125,7 @@
"**/string-width": "4.2.0", "**/string-width": "4.2.0",
"**/wrap-ansi": "7.0.0", "**/wrap-ansi": "7.0.0",
"**/jwa": "^2.0.1", "**/jwa": "^2.0.1",
"**/@types/express": "4.17.25", "**/@types/express": "4.17.25"
"neo4j-graphql-js/graphql": "^16.11.0",
"graphql-upload/graphql": "^16.11.0"
}, },
"engines": { "engines": {
"node": ">=20.12.1" "node": ">=20.12.1"

View File

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
import databaseContext from '@context/database' import databaseContext from '@context/database'
import pubsubContext from '@context/pubsub' import pubsubContext from '@context/pubsub'
import CONFIG from '@src/config' import CONFIG from '@src/config'
@ -5,6 +7,8 @@ import { decode } from '@src/jwt/decode'
import ocelotLogger from '@src/logger' import ocelotLogger from '@src/logger'
import type { DecodedUser } from '@src/jwt/decode' import type { DecodedUser } from '@src/jwt/decode'
import type OcelotLogger from '@src/logger'
import type { ApolloServerExpressConfig } from 'apollo-server-express'
const serverDatabase = databaseContext() const serverDatabase = databaseContext()
const serverPubsub = pubsubContext() const serverPubsub = pubsubContext()
@ -14,7 +18,7 @@ export const getContext =
database?: ReturnType<typeof databaseContext> database?: ReturnType<typeof databaseContext>
pubsub?: ReturnType<typeof pubsubContext> pubsub?: ReturnType<typeof pubsubContext>
authenticatedUser: DecodedUser | null | undefined authenticatedUser: DecodedUser | null | undefined
logger?: typeof ocelotLogger logger?: typeof OcelotLogger
config: typeof CONFIG config: typeof CONFIG
}) => }) =>
async (req: { headers: { authorization?: string } }) => { async (req: { headers: { authorization?: string } }) => {
@ -40,11 +44,18 @@ export const getContext =
req, req,
cypherParams: { cypherParams: {
currentUserId: user ? user.id : null, currentUserId: user ? user.id : null,
languageDefault: config.LANGUAGE_DEFAULT.toUpperCase(),
}, },
config, config,
} }
return result return result
} }
export const context: ApolloServerExpressConfig['context'] = async (options) => {
const { connection, req } = options
if (connection) {
return connection.context
} else {
return getContext()(req)
}
}
export type Context = Awaited<ReturnType<ReturnType<typeof getContext>>> export type Context = Awaited<ReturnType<ReturnType<typeof getContext>>>

View File

@ -1,8 +1,10 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-require-imports */ /* eslint-disable @typescript-eslint/no-require-imports */
/* eslint-disable import-x/no-commonjs */ /* eslint-disable import-x/no-commonjs */
// eslint-disable-next-line n/no-unpublished-require // eslint-disable-next-line n/no-unpublished-require
const tsx = require('tsx/cjs/api') const tsNode = require('ts-node')
// eslint-disable-next-line import-x/no-unassigned-import, n/no-unpublished-require
require('tsconfig-paths/register')
module.exports = tsx.register module.exports = tsNode.register

View File

@ -13,7 +13,6 @@ export default {
nameNL: { type: 'string' }, nameNL: { type: 'string' },
namePL: { type: 'string' }, namePL: { type: 'string' },
nameRU: { type: 'string' }, nameRU: { type: 'string' },
nameSQ: { type: 'string' },
isIn: { isIn: {
type: 'relationship', type: 'relationship',
relationship: 'IS_IN', relationship: 'IS_IN',

View File

@ -11,13 +11,13 @@ import sample from 'lodash/sample'
import CONFIG from '@config/index' import CONFIG from '@config/index'
import { categories } from '@constants/categories' import { categories } from '@constants/categories'
import CreateComment from '@graphql/queries/comments/CreateComment.gql' import { ChangeGroupMemberRole } from '@graphql/queries/ChangeGroupMemberRole'
import ChangeGroupMemberRole from '@graphql/queries/groups/ChangeGroupMemberRole.gql' import { CreateComment } from '@graphql/queries/CreateComment'
import CreateGroup from '@graphql/queries/groups/CreateGroup.gql' import { CreateGroup } from '@graphql/queries/CreateGroup'
import JoinGroup from '@graphql/queries/groups/JoinGroup.gql' import { CreateMessage } from '@graphql/queries/CreateMessage'
import CreateMessage from '@graphql/queries/messaging/CreateMessage.gql' import { CreatePost } from '@graphql/queries/CreatePost'
import CreateRoom from '@graphql/queries/messaging/CreateRoom.gql' import { CreateRoom } from '@graphql/queries/CreateRoom'
import CreatePost from '@graphql/queries/posts/CreatePost.gql' import { JoinGroup } from '@graphql/queries/JoinGroup'
import { createApolloTestSetup } from '@root/test/helpers' import { createApolloTestSetup } from '@root/test/helpers'
import Factory from './factories' import Factory from './factories'
@ -42,7 +42,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
authenticatedUser, authenticatedUser,
config: CONFIG, config: CONFIG,
}) })
const apolloSetup = await createApolloTestSetup({ context }) const apolloSetup = createApolloTestSetup({ context })
const { mutate, server, database } = apolloSetup const { mutate, server, database } = apolloSetup
const { neode } = database const { neode } = database

View File

@ -14,7 +14,6 @@ export interface LocationDbProperties {
namePL: string namePL: string
namePT: string namePT: string
nameRU: string nameRU: string
nameSQ: string
type: string type: string
} }

View File

@ -1,6 +0,0 @@
declare module '*.gql' {
import type { DocumentNode } from 'graphql'
const value: DocumentNode
export default value
}

View File

@ -1,19 +0,0 @@
import { GraphQLError } from 'graphql'
export class UserInputError extends GraphQLError {
constructor(message: string) {
super(message, { extensions: { code: 'BAD_USER_INPUT' } })
}
}
export class AuthenticationError extends GraphQLError {
constructor(message: string) {
super(message, { extensions: { code: 'UNAUTHENTICATED' } })
}
}
export class ForbiddenError extends GraphQLError {
constructor(message: string) {
super(message, { extensions: { code: 'FORBIDDEN' } })
}
}

View File

@ -1,21 +0,0 @@
/* eslint-disable n/no-sync, security/detect-non-literal-fs-filename */
// Register a require hook for .gql files so they can be imported at runtime.
// Jest uses its own graphqlTransform.ts for this; this hook covers tsx/node usage
// (e.g. db:seed).
import { readFileSync } from 'node:fs'
import Module from 'node:module'
import { parse } from 'graphql'
// @ts-expect-error -- require.extensions is deprecated but still functional for CJS hooks
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
Module._extensions['.gql'] = function (_module: typeof module, filename: string) {
const content = readFileSync(filename, 'utf-8')
try {
_module.exports = parse(content)
} catch (error: unknown) {
throw new Error(
`Failed to parse ${filename}: ${error instanceof Error ? error.message : String(error)}`,
)
}
}

View File

@ -0,0 +1,11 @@
import gql from 'graphql-tag'
export const AddEmailAddress = gql`
mutation ($email: String!) {
AddEmailAddress(email: $email) {
email
verifiedAt
createdAt
}
}
`

View File

@ -0,0 +1,15 @@
import gql from 'graphql-tag'
export const AddPostEmotions = gql`
mutation ($to: _PostInput!, $data: _EMOTEDInput!) {
AddPostEmotions(to: $to, data: $data) {
from {
id
}
to {
id
}
emotion
}
}
`

View File

@ -1,8 +0,0 @@
query Category {
Category {
id
slug
name
icon
}
}

View File

@ -0,0 +1,12 @@
import gql from 'graphql-tag'
export const Category = gql`
query {
Category {
id
slug
name
icon
}
}
`

View File

@ -0,0 +1,16 @@
import gql from 'graphql-tag'
export const ChangeGroupMemberRole = gql`
mutation ($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) {
ChangeGroupMemberRole(groupId: $groupId, userId: $userId, roleInGroup: $roleInGroup) {
user {
id
name
slug
}
membership {
role
}
}
}
`

View File

@ -0,0 +1,15 @@
import gql from 'graphql-tag'
export const CreateComment = gql`
mutation ($id: ID, $postId: ID!, $content: String!) {
CreateComment(id: $id, postId: $postId, content: $content) {
id
content
author {
name
}
isPostObservedByMe
postObservingUsersCount
}
}
`

View File

@ -0,0 +1,53 @@
import gql from 'graphql-tag'
export const CreateGroup = gql`
mutation (
$id: ID
$name: String!
$slug: String
$about: String
$description: String!
$groupType: GroupType!
$actionRadius: GroupActionRadius!
$categoryIds: [ID]
$locationName: String # empty string '' sets it to null
) {
CreateGroup(
id: $id
name: $name
slug: $slug
about: $about
description: $description
groupType: $groupType
actionRadius: $actionRadius
categoryIds: $categoryIds
locationName: $locationName
) {
id
name
slug
createdAt
updatedAt
disabled
deleted
about
description
descriptionExcerpt
groupType
actionRadius
categories {
id
slug
name
icon
}
locationName
location {
name
nameDE
nameEN
}
myRole
}
}
`

View File

@ -0,0 +1,22 @@
import gql from 'graphql-tag'
export const CreateMessage = gql`
mutation ($roomId: ID!, $content: String!, $files: [FileInput]) {
CreateMessage(roomId: $roomId, content: $content, files: $files) {
id
content
senderId
username
avatar
date
saved
distributed
seen
files {
url
name
type
}
}
}
`

View File

@ -0,0 +1,51 @@
import gql from 'graphql-tag'
export const CreatePost = gql`
mutation (
$id: ID
$title: String!
$slug: String
$content: String!
$categoryIds: [ID]
$groupId: ID
$postType: PostType
$eventInput: _EventInput
) {
CreatePost(
id: $id
title: $title
slug: $slug
content: $content
categoryIds: $categoryIds
groupId: $groupId
postType: $postType
eventInput: $eventInput
) {
id
slug
title
content
disabled
deleted
postType
author {
name
}
categories {
id
}
eventStart
eventEnd
eventLocationName
eventVenue
eventIsOnline
eventLocation {
lng
lat
}
isObservedByMe
observingUsersCount
language
}
}
`

View File

@ -0,0 +1,22 @@
import gql from 'graphql-tag'
export const CreateRoom = gql`
mutation ($userId: ID!) {
CreateRoom(userId: $userId) {
id
roomId
roomName
lastMessageAt
unreadCount
#avatar
users {
_id
id
name
avatar {
url
}
}
}
}
`

View File

@ -0,0 +1,14 @@
import gql from 'graphql-tag'
export const CreateSocialMedia = gql`
mutation ($url: String!) {
CreateSocialMedia(url: $url) {
id
url
url
ownedBy {
name
}
}
}
`

View File

@ -0,0 +1,12 @@
import gql from 'graphql-tag'
export const DeleteComment = gql`
mutation ($id: ID!) {
DeleteComment(id: $id) {
id
content
contentExcerpt
deleted
}
}
`

View File

@ -0,0 +1,20 @@
import gql from 'graphql-tag'
export const DeletePost = gql`
mutation ($id: ID!) {
DeletePost(id: $id) {
id
deleted
content
contentExcerpt
image {
url
}
comments {
deleted
content
contentExcerpt
}
}
}
`

View File

@ -0,0 +1,10 @@
import gql from 'graphql-tag'
export const DeleteSocialMedia = gql`
mutation ($id: ID!) {
DeleteSocialMedia(id: $id) {
id
url
}
}
`

View File

@ -0,0 +1,30 @@
import gql from 'graphql-tag'
export const DeleteUser = gql`
mutation ($id: ID!, $resource: [Deletable]) {
DeleteUser(id: $id, resource: $resource) {
id
name
about
deleted
contributions {
id
content
contentExcerpt
deleted
comments {
id
content
contentExcerpt
deleted
}
}
comments {
id
content
contentExcerpt
deleted
}
}
}
`

View File

@ -0,0 +1,12 @@
import gql from 'graphql-tag'
export const Donations = gql`
query {
Donations {
id
showDonations
goal
progress
}
}
`

View File

@ -0,0 +1,40 @@
import gql from 'graphql-tag'
export const Group = gql`
query Group($isMember: Boolean, $id: ID, $slug: String) {
Group(isMember: $isMember, id: $id, slug: $slug) {
id
name
slug
createdAt
updatedAt
disabled
deleted
about
description
descriptionExcerpt
groupType
actionRadius
categories {
id
slug
name
icon
}
avatar {
url
}
locationName
location {
name
nameDE
nameEN
}
myRole
inviteCodes {
code
redeemedByCount
}
}
}
`

View File

@ -0,0 +1,16 @@
import gql from 'graphql-tag'
export const GroupMembers = gql`
query GroupMembers($id: ID!) {
GroupMembers(id: $id) {
user {
id
name
slug
}
membership {
role
}
}
}
`

View File

@ -0,0 +1,16 @@
import gql from 'graphql-tag'
export const JoinGroup = gql`
mutation ($groupId: ID!, $userId: ID!) {
JoinGroup(groupId: $groupId, userId: $userId) {
user {
id
name
slug
}
membership {
role
}
}
}
`

View File

@ -0,0 +1,16 @@
import gql from 'graphql-tag'
export const LeaveGroup = gql`
mutation ($groupId: ID!, $userId: ID!) {
LeaveGroup(groupId: $groupId, userId: $userId) {
user {
id
name
slug
}
membership {
role
}
}
}
`

View File

@ -0,0 +1,7 @@
import gql from 'graphql-tag'
export const MarkMessagesAsSeen = gql`
mutation ($messageIds: [String!]) {
MarkMessagesAsSeen(messageIds: $messageIds)
}
`

View File

@ -0,0 +1,27 @@
import gql from 'graphql-tag'
export const Message = gql`
query ($roomId: ID!, $first: Int, $offset: Int) {
Message(roomId: $roomId, first: $first, offset: $offset, orderBy: indexId_desc) {
_id
id
indexId
content
senderId
author {
id
}
username
avatar
date
saved
distributed
seen
files {
url
name
type
}
}
}
`

View File

@ -0,0 +1,39 @@
import gql from 'graphql-tag'
export const Post = gql`
query ($id: ID, $filter: _PostFilter, $first: Int, $offset: Int, $orderBy: [_PostOrdering]) {
Post(id: $id, filter: $filter, first: $first, offset: $offset, orderBy: $orderBy) {
id
title
content
contentExcerpt
eventStart
pinned
createdAt
pinnedAt
isObservedByMe
observingUsersCount
clickedCount
emotionsCount
emotions {
emotion
User {
id
}
}
author {
id
name
}
shoutedBy {
id
}
tags {
id
}
comments {
content
}
}
}
`

View File

@ -0,0 +1,7 @@
import gql from 'graphql-tag'
export const PostsEmotionsByCurrentUser = gql`
query ($postId: ID!) {
PostsEmotionsByCurrentUser(postId: $postId)
}
`

View File

@ -0,0 +1,7 @@
import gql from 'graphql-tag'
export const PostsEmotionsCountByEmotion = gql`
query ($postId: ID!, $data: _EMOTEDInput!) {
PostsEmotionsCountByEmotion(postId: $postId, data: $data)
}
`

View File

@ -0,0 +1,15 @@
import gql from 'graphql-tag'
export const RemovePostEmotions = gql`
mutation ($to: _PostInput!, $data: _EMOTEDInput!) {
RemovePostEmotions(to: $to, data: $data) {
from {
id
}
to {
id
}
emotion
}
}
`

View File

@ -0,0 +1,16 @@
import gql from 'graphql-tag'
export const RemoveUserFromGroup = gql`
mutation ($groupId: ID!, $userId: ID!) {
RemoveUserFromGroup(groupId: $groupId, userId: $userId) {
user {
id
name
slug
}
membership {
role
}
}
}
`

View File

@ -0,0 +1,34 @@
import gql from 'graphql-tag'
export const Room = gql`
query Room($first: Int, $offset: Int, $id: ID) {
Room(first: $first, offset: $offset, id: $id, orderBy: lastMessageAt_desc) {
id
roomId
roomName
avatar
lastMessageAt
unreadCount
lastMessage {
_id
id
content
senderId
username
avatar
date
saved
distributed
seen
}
users {
_id
id
name
avatar {
url
}
}
}
}
`

View File

@ -0,0 +1,9 @@
import gql from 'graphql-tag'
export const Signup = gql`
mutation ($email: String!, $locale: String!, $inviteCode: String) {
Signup(email: $email, locale: $locale, inviteCode: $inviteCode) {
email
}
}
`

View File

@ -0,0 +1,30 @@
import gql from 'graphql-tag'
export const SignupVerification = gql`
mutation (
$password: String!
$email: String!
$name: String!
$slug: String
$nonce: String!
$termsAndConditionsAgreedVersion: String!
$about: String
$locale: String
) {
SignupVerification(
email: $email
password: $password
name: $name
slug: $slug
nonce: $nonce
termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion
about: $about
locale: $locale
) {
id
slug
termsAndConditionsAgreedVersion
termsAndConditionsAgreedAt
}
}
`

View File

@ -0,0 +1,7 @@
import gql from 'graphql-tag'
export const UnreadRooms = gql`
query {
UnreadRooms
}
`

View File

@ -0,0 +1,12 @@
import gql from 'graphql-tag'
export const UpdateComment = gql`
mutation ($content: String!, $id: ID!) {
UpdateComment(content: $content, id: $id) {
id
content
createdAt
updatedAt
}
}
`

View File

@ -0,0 +1,14 @@
import gql from 'graphql-tag'
export const UpdateDonations = gql`
mutation ($showDonations: Boolean, $goal: Int, $progress: Int) {
UpdateDonations(showDonations: $showDonations, goal: $goal, progress: $progress) {
id
showDonations
goal
progress
createdAt
updatedAt
}
}
`

View File

@ -0,0 +1,54 @@
import gql from 'graphql-tag'
export const UpdateGroup = gql`
mutation (
$id: ID!
$name: String
$slug: String
$about: String
$description: String
$actionRadius: GroupActionRadius
$categoryIds: [ID]
$avatar: ImageInput
$locationName: String # empty string '' sets it to null
) {
UpdateGroup(
id: $id
name: $name
slug: $slug
about: $about
description: $description
actionRadius: $actionRadius
categoryIds: $categoryIds
avatar: $avatar
locationName: $locationName
) {
id
name
slug
createdAt
updatedAt
disabled
deleted
about
description
descriptionExcerpt
groupType
actionRadius
categories {
id
slug
name
icon
}
# avatar # test this as result
locationName
location {
name
nameDE
nameEN
}
myRole
}
}
`

View File

@ -0,0 +1,44 @@
import gql from 'graphql-tag'
export const UpdatePost = gql`
mutation (
$id: ID!
$title: String!
$content: String!
$image: ImageInput
$categoryIds: [ID]
$postType: PostType
$eventInput: _EventInput
) {
UpdatePost(
id: $id
title: $title
content: $content
image: $image
categoryIds: $categoryIds
postType: $postType
eventInput: $eventInput
) {
id
title
content
author {
name
slug
}
createdAt
updatedAt
categories {
id
}
postType
eventStart
eventLocationName
eventVenue
eventLocation {
lng
lat
}
}
}
`

View File

@ -0,0 +1,10 @@
import gql from 'graphql-tag'
export const UpdateSocialMedia = gql`
mutation ($id: ID!, $url: String!) {
UpdateSocialMedia(id: $id, url: $url) {
id
url
}
}
`

View File

@ -0,0 +1,67 @@
import gql from 'graphql-tag'
export const UpdateUser = gql`
mutation (
$id: ID!
$slug: String
$name: String
$about: String
$allowEmbedIframes: Boolean
$showShoutsPublicly: Boolean
$emailNotificationSettings: [EmailNotificationSettingsInput]
$termsAndConditionsAgreedVersion: String
$avatar: ImageInput
$locationName: String # empty string '' sets it to null
$locale: String
) {
UpdateUser(
id: $id
slug: $slug
name: $name
about: $about
allowEmbedIframes: $allowEmbedIframes
showShoutsPublicly: $showShoutsPublicly
emailNotificationSettings: $emailNotificationSettings
termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion
avatar: $avatar
locationName: $locationName
locale: $locale
) {
id
slug
name
about
allowEmbedIframes
showShoutsPublicly
termsAndConditionsAgreedVersion
termsAndConditionsAgreedAt
locationName
locale
location {
name
nameDE
nameEN
nameRU
}
emailNotificationSettings {
type
settings {
name
value
}
}
avatar {
url
alt
sensitive
aspectRatio
type
}
badgeVerification {
id
description
icon
}
}
}
`

View File

@ -0,0 +1,165 @@
import gql from 'graphql-tag'
export const User = gql`
query ($id: ID, $name: String, $email: String) {
User(id: $id, name: $name, email: $email) {
id
name
badgeTrophiesCount
badgeTrophies {
id
}
badgeVerification {
id
isDefault
}
badgeTrophiesSelected {
id
isDefault
}
followedBy {
id
}
followedByCurrentUser
following {
name
slug
about
avatar {
url
}
comments {
content
contentExcerpt
}
contributions {
title
slug
image {
url
}
content
contentExcerpt
}
}
isMuted
isBlocked
location {
distanceToMe
}
activeCategories
}
}
`
export const UserEmailNotificationSettings = gql`
query ($id: ID, $name: String, $email: String) {
User(id: $id, name: $name, email: $email) {
id
name
badgeTrophiesCount
badgeTrophies {
id
}
badgeVerification {
id
isDefault
}
badgeTrophiesSelected {
id
isDefault
}
followedBy {
id
}
followedByCurrentUser
following {
name
slug
about
avatar {
url
}
comments {
content
contentExcerpt
}
contributions {
title
slug
image {
url
}
content
contentExcerpt
}
}
isMuted
isBlocked
location {
distanceToMe
}
emailNotificationSettings {
type
settings {
name
value
}
}
activeCategories
}
}
`
export const UserEmail = gql`
query ($id: ID, $name: String, $email: String) {
User(id: $id, name: $name, email: $email) {
id
name
email
badgeTrophiesCount
badgeTrophies {
id
}
badgeVerification {
id
isDefault
}
badgeTrophiesSelected {
id
isDefault
}
followedBy {
id
}
followedByCurrentUser
following {
name
slug
about
avatar {
url
}
comments {
content
contentExcerpt
}
contributions {
title
slug
image {
url
}
content
contentExcerpt
}
}
isMuted
isBlocked
location {
distanceToMe
}
activeCategories
}
}
`

View File

@ -0,0 +1,11 @@
import gql from 'graphql-tag'
export const VerifyEmailAddress = gql`
mutation ($email: String!, $nonce: String!) {
VerifyEmailAddress(email: $email, nonce: $nonce) {
email
createdAt
verifiedAt
}
}
`

View File

@ -0,0 +1,7 @@
import gql from 'graphql-tag'
export const VerifyNonce = gql`
query ($email: String!, $nonce: String!) {
VerifyNonce(email: $email, nonce: $nonce)
}
`

View File

@ -1,5 +0,0 @@
mutation Signup($email: String!, $locale: String!, $inviteCode: String) {
Signup(email: $email, locale: $locale, inviteCode: $inviteCode) {
email
}
}

View File

@ -1,26 +0,0 @@
mutation SignupVerification(
$password: String!
$email: String!
$name: String!
$slug: String
$nonce: String!
$termsAndConditionsAgreedVersion: String!
$about: String
$locale: String
) {
SignupVerification(
email: $email
password: $password
name: $name
slug: $slug
nonce: $nonce
termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion
about: $about
locale: $locale
) {
id
slug
termsAndConditionsAgreedVersion
termsAndConditionsAgreedAt
}
}

View File

@ -1,3 +0,0 @@
query VerifyNonce($email: String!, $nonce: String!) {
VerifyNonce(email: $email, nonce: $nonce)
}

View File

@ -1,3 +0,0 @@
mutation changePassword($oldPassword: String!, $newPassword: String!) {
changePassword(oldPassword: $oldPassword, newPassword: $newPassword)
}

View File

@ -1,21 +0,0 @@
query currentUser {
currentUser {
id
slug
name
avatar {
url
}
email
role
activeCategories
following {
id
name
}
inviteCodes {
code
redeemedByCount
}
}
}

View File

@ -1,3 +0,0 @@
mutation login($email: String!, $password: String!) {
login(email: $email, password: $password)
}

View File

@ -1,3 +0,0 @@
mutation requestPasswordReset($email: String!, $locale: String!) {
requestPasswordReset(email: $email, locale: $locale)
}

View File

@ -1,3 +0,0 @@
mutation resetPassword($nonce: String!, $email: String!, $newPassword: String!) {
resetPassword(nonce: $nonce, email: $email, newPassword: $newPassword)
}

View File

@ -0,0 +1,7 @@
import gql from 'graphql-tag'
export const availableRoles = gql`
query {
availableRoles
}
`

View File

@ -1,14 +0,0 @@
mutation resetTrophyBadgesSelected {
resetTrophyBadgesSelected {
id
badgeTrophiesCount
badgeTrophiesSelected {
id
isDefault
}
badgeTrophiesUnused {
id
}
badgeTrophiesUnusedCount
}
}

View File

@ -1,16 +0,0 @@
mutation revokeBadge($badgeId: ID!, $userId: ID!) {
revokeBadge(badgeId: $badgeId, userId: $userId) {
id
badgeTrophies {
id
}
badgeVerification {
id
isDefault
}
badgeTrophiesSelected {
id
isDefault
}
}
}

View File

@ -1,16 +0,0 @@
mutation rewardTrophyBadge($badgeId: ID!, $userId: ID!) {
rewardTrophyBadge(badgeId: $badgeId, userId: $userId) {
id
badgeVerification {
id
isDefault
}
badgeTrophiesCount
badgeTrophies {
id
}
badgeTrophiesSelected {
id
}
}
}

View File

@ -1,14 +0,0 @@
mutation setTrophyBadgeSelected($slot: Int!, $badgeId: ID) {
setTrophyBadgeSelected(slot: $slot, badgeId: $badgeId) {
id
badgeTrophiesCount
badgeTrophiesSelected {
id
isDefault
}
badgeTrophiesUnused {
id
}
badgeTrophiesUnusedCount
}
}

View File

@ -1,12 +0,0 @@
mutation setVerificationBadge($badgeId: ID!, $userId: ID!) {
setVerificationBadge(badgeId: $badgeId, userId: $userId) {
id
badgeVerification {
id
isDefault
}
badgeTrophies {
id
}
}
}

View File

@ -0,0 +1,11 @@
import gql from 'graphql-tag'
export const blockUser = gql`
mutation ($id: ID!) {
blockUser(id: $id) {
id
name
isBlocked
}
}
`

View File

@ -0,0 +1,11 @@
import gql from 'graphql-tag'
export const blockedUsers = gql`
query {
blockedUsers {
id
name
isBlocked
}
}
`

View File

@ -0,0 +1,7 @@
import gql from 'graphql-tag'
export const changePassword = gql`
mutation ($oldPassword: String!, $newPassword: String!) {
changePassword(oldPassword: $oldPassword, newPassword: $newPassword)
}
`

View File

@ -1,12 +0,0 @@
mutation CreateComment($id: ID, $postId: ID!, $content: String!) {
CreateComment(id: $id, postId: $postId, content: $content) {
id
content
author {
id
name
}
isPostObservedByMe
postObservingUsersCount
}
}

View File

@ -1,8 +0,0 @@
mutation DeleteComment($id: ID!) {
DeleteComment(id: $id) {
id
content
contentExcerpt
deleted
}
}

View File

@ -1,8 +0,0 @@
mutation UpdateComment($content: String!, $id: ID!) {
UpdateComment(content: $content, id: $id) {
id
content
createdAt
updatedAt
}
}

View File

@ -0,0 +1,24 @@
import gql from 'graphql-tag'
export const currentUser = gql`
query currentUser {
currentUser {
id
slug
name
avatar {
url
}
email
role
activeCategories
following {
name
}
inviteCodes {
code
redeemedByCount
}
}
}
`

View File

@ -1,8 +0,0 @@
query Donations {
Donations {
id
showDonations
goal
progress
}
}

View File

@ -1,10 +0,0 @@
mutation UpdateDonations($showDonations: Boolean, $goal: Int, $progress: Int) {
UpdateDonations(showDonations: $showDonations, goal: $goal, progress: $progress) {
id
showDonations
goal
progress
createdAt
updatedAt
}
}

View File

@ -1,17 +0,0 @@
query embed($url: String!) {
embed(url: $url) {
type
title
author
publisher
date
description
url
image
audio
video
lang
sources
html
}
}

View File

@ -0,0 +1,21 @@
import gql from 'graphql-tag'
export const embed = gql`
query ($url: String!) {
embed(url: $url) {
type
title
author
publisher
date
description
url
image
audio
video
lang
sources
html
}
}
`

View File

@ -1,11 +0,0 @@
mutation AddPostEmotions($to: _PostInput!, $data: _EMOTEDInput!) {
AddPostEmotions(to: $to, data: $data) {
from {
id
}
to {
id
}
emotion
}
}

View File

@ -1,3 +0,0 @@
query PostsEmotionsByCurrentUser($postId: ID!) {
PostsEmotionsByCurrentUser(postId: $postId)
}

View File

@ -1,3 +0,0 @@
query PostsEmotionsCountByEmotion($postId: ID!, $data: _EMOTEDInput!) {
PostsEmotionsCountByEmotion(postId: $postId, data: $data)
}

View File

@ -1,11 +0,0 @@
mutation RemovePostEmotions($to: _PostInput!, $data: _EMOTEDInput!) {
RemovePostEmotions(to: $to, data: $data) {
from {
id
}
to {
id
}
emotion
}
}

View File

@ -1,3 +0,0 @@
mutation shout($id: ID!) {
shout(id: $id, type: Post)
}

View File

@ -1,3 +0,0 @@
mutation unshout($id: ID!) {
unshout(id: $id, type: Post)
}

View File

@ -0,0 +1,28 @@
import gql from 'graphql-tag'
export const fileReport = gql`
mutation ($resourceId: ID!, $reasonCategory: ReasonCategory!, $reasonDescription: String!) {
fileReport(
resourceId: $resourceId
reasonCategory: $reasonCategory
reasonDescription: $reasonDescription
) {
createdAt
reasonCategory
reasonDescription
reportId
resource {
__typename
... on User {
name
}
... on Post {
title
}
... on Comment {
content
}
}
}
}
`

View File

@ -0,0 +1,15 @@
import gql from 'graphql-tag'
export const followUser = gql`
mutation ($id: ID!) {
followUser(id: $id) {
id
name
followedBy {
id
name
}
followedByCurrentUser
}
}
`

View File

@ -0,0 +1,36 @@
import gql from 'graphql-tag'
export const generateGroupInviteCode = gql`
mutation generateGroupInviteCode($groupId: ID!, $expiresAt: String, $comment: String) {
generateGroupInviteCode(groupId: $groupId, expiresAt: $expiresAt, comment: $comment) {
code
createdAt
generatedBy {
id
name
avatar {
url
}
}
redeemedBy {
id
name
avatar {
url
}
}
expiresAt
comment
invitedTo {
id
groupType
name
about
avatar {
url
}
}
isValid
}
}
`

View File

@ -0,0 +1,36 @@
import gql from 'graphql-tag'
export const generatePersonalInviteCode = gql`
mutation generatePersonalInviteCode($expiresAt: String, $comment: String) {
generatePersonalInviteCode(expiresAt: $expiresAt, comment: $comment) {
code
createdAt
generatedBy {
id
name
avatar {
url
}
}
redeemedBy {
id
name
avatar {
url
}
}
expiresAt
comment
invitedTo {
id
groupType
name
about
avatar {
url
}
}
isValid
}
}
`

View File

@ -1,12 +0,0 @@
mutation ChangeGroupMemberRole($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) {
ChangeGroupMemberRole(groupId: $groupId, userId: $userId, roleInGroup: $roleInGroup) {
user {
id
name
slug
}
membership {
role
}
}
}

View File

@ -1,48 +0,0 @@
mutation CreateGroup(
$id: ID
$name: String!
$slug: String
$about: String
$description: String!
$groupType: GroupType!
$actionRadius: GroupActionRadius!
$categoryIds: [ID]
$locationName: String # empty string '' sets it to null
) {
CreateGroup(
id: $id
name: $name
slug: $slug
about: $about
description: $description
groupType: $groupType
actionRadius: $actionRadius
categoryIds: $categoryIds
locationName: $locationName
) {
id
name
slug
createdAt
updatedAt
disabled
deleted
about
description
descriptionExcerpt
groupType
actionRadius
categories {
id
slug
name
icon
}
locationName
location {
id
name
}
myRole
}
}

View File

@ -1,35 +0,0 @@
query Group($isMember: Boolean, $id: ID, $slug: String) {
Group(isMember: $isMember, id: $id, slug: $slug) {
id
name
slug
createdAt
updatedAt
disabled
deleted
about
description
descriptionExcerpt
groupType
actionRadius
categories {
id
slug
name
icon
}
avatar {
url
}
locationName
location {
id
name
}
myRole
inviteCodes {
code
redeemedByCount
}
}
}

View File

@ -1,12 +0,0 @@
query GroupMembers($id: ID!) {
GroupMembers(id: $id) {
user {
id
name
slug
}
membership {
role
}
}
}

Some files were not shown because too many files have changed in this diff Show More