Merge master
9
.github/dependabot.yml
vendored
@ -57,19 +57,10 @@ updates:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "*apollo-server*"
|
||||
babel:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "@babel*"
|
||||
metascraper:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "metascraper*"
|
||||
typescript:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "ts*"
|
||||
- "*types?"
|
||||
|
||||
# webapp
|
||||
- package-ecosystem: docker
|
||||
|
||||
8
.github/workflows/check-documentation.yml
vendored
@ -30,11 +30,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
|
||||
- name: Remove old documentation files
|
||||
run: rm -rf ./deployment/src/old/ ./CHANGELOG.md # workaround until https://github.com/gaurav-nelson/github-action-markdown-link-check/pull/183 has been done
|
||||
- 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
|
||||
|
||||
- name: Check Markdown Links
|
||||
uses: gaurav-nelson/github-action-markdown-link-check@7d83e59a57f3c201c76eed3d33dff64ec4452d27 # 1.0.15
|
||||
uses: gaurav-nelson/github-action-markdown-link-check@1b916f2cf6c36510a6059943104e3c42ce6c16bc # 1.0.15
|
||||
with:
|
||||
use-quiet-mode: 'yes'
|
||||
use-verbose-mode: 'no'
|
||||
@ -54,7 +54,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
|
||||
- name: Setup Node 20
|
||||
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.0.3
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
|
||||
4
.github/workflows/deploy-documentation.yml
vendored
@ -30,7 +30,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
|
||||
- name: Setup Node 20
|
||||
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.0.3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
@ -38,7 +38,7 @@ jobs:
|
||||
run: npm install && npm run docs:build
|
||||
|
||||
- name: Deploy Vuepress to Github Pages
|
||||
uses: crazy-max/ghaction-github-pages@fbf0a4fa4e00f45accd6cf3232368436ec06ed59 # v4.0.0
|
||||
uses: crazy-max/ghaction-github-pages@df5cc2bfa78282ded844b354faee141f06b41865 # v4.0.0
|
||||
with:
|
||||
target_branch: gh-pages
|
||||
build_dir: .vuepress/dist
|
||||
|
||||
91
.github/workflows/docker-push.yml
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
name: docker-push
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
build-and-push-images:
|
||||
strategy:
|
||||
matrix:
|
||||
app:
|
||||
- name: neo4j
|
||||
context: neo4j
|
||||
file: neo4j/Dockerfile
|
||||
target: community
|
||||
- name: backend-base
|
||||
context: backend
|
||||
file: backend/Dockerfile
|
||||
target: base
|
||||
- name: backend-build
|
||||
context: backend
|
||||
file: backend/Dockerfile
|
||||
target: build
|
||||
- name: backend
|
||||
context: backend
|
||||
file: backend/Dockerfile
|
||||
target: production
|
||||
- name: webapp-base
|
||||
context: webapp
|
||||
file: webapp/Dockerfile
|
||||
target: base
|
||||
- name: webapp-build
|
||||
context: webapp
|
||||
file: webapp/Dockerfile
|
||||
target: build
|
||||
- name: webapp
|
||||
context: webapp
|
||||
file: webapp/Dockerfile
|
||||
target: production
|
||||
- name: maintenance-base
|
||||
context: webapp
|
||||
file: webapp/Dockerfile.maintenance
|
||||
target: base
|
||||
- name: maintenance-build
|
||||
context: webapp
|
||||
file: webapp/Dockerfile.maintenance
|
||||
target: build
|
||||
- name: maintenance
|
||||
context: webapp
|
||||
file: webapp/Dockerfile.maintenance
|
||||
target: production
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}/${{ matrix.app.name }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
attestations: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=schedule
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=sha
|
||||
- name: Build and push Docker images
|
||||
id: push
|
||||
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0
|
||||
with:
|
||||
context: ${{ matrix.app.context }}
|
||||
target: ${{ matrix.app.target }}
|
||||
file: ${{ matrix.app.file }}
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
235
.github/workflows/publish.yml
vendored
@ -6,241 +6,12 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
##############################################################################
|
||||
# JOB: DOCKER BUILD COMMUNITY NEO4J ##########################################
|
||||
##############################################################################
|
||||
build_production_neo4j:
|
||||
name: Docker Build Production - Neo4J
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- name: Setup env
|
||||
run: |
|
||||
echo "VERSION=$(node -p -e "require('./package.json').version")" >> $GITHUB_ENV
|
||||
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
|
||||
echo "BUILD_COMMIT=${GITHUB_SHA}" >> $GITHUB_ENV
|
||||
- run: echo "BUILD_VERSION=${VERSION}-${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
|
||||
- name: Neo4J | Build `community` image
|
||||
run: |
|
||||
docker build --target community \
|
||||
--tag "ocelotsocialnetwork/neo4j-community:latest" \
|
||||
--tag "ocelotsocialnetwork/neo4j-community:${VERSION}" \
|
||||
--tag "ocelotsocialnetwork/neo4j-community:${BUILD_VERSION}" \
|
||||
--build-arg BBUILD_DATE=$BUILD_DATE \
|
||||
--build-arg BBUILD_VERSION=$BUILD_VERSION \
|
||||
--build-arg BBUILD_COMMIT=$BUILD_COMMIT \
|
||||
neo4j/
|
||||
- name: Neo4J | Save docker image
|
||||
run: docker save "ocelotsocialnetwork/neo4j-community" > /tmp/neo4j.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
with:
|
||||
name: docker-neo4j-community
|
||||
path: /tmp/neo4j.tar
|
||||
|
||||
##############################################################################
|
||||
# JOB: DOCKER BUILD PRODUCTION BACKEND #######################################
|
||||
##############################################################################
|
||||
build_production_backend:
|
||||
name: Docker Build Production - Backend
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- name: Setup env
|
||||
run: |
|
||||
echo "VERSION=$(node -p -e "require('./package.json').version")" >> $GITHUB_ENV
|
||||
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
|
||||
echo "BUILD_COMMIT=${GITHUB_SHA}" >> $GITHUB_ENV
|
||||
- run: echo "BUILD_VERSION=${VERSION}-${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
|
||||
- name: Backend | Build `production` image
|
||||
run: |
|
||||
docker build --target base \
|
||||
--tag "ocelotsocialnetwork/backend:latest-base" \
|
||||
--tag "ocelotsocialnetwork/backend:${VERSION}-base" \
|
||||
--tag "ocelotsocialnetwork/backend:${BUILD_VERSION}-base" \
|
||||
--build-arg BBUILD_DATE=$BUILD_DATE \
|
||||
--build-arg BBUILD_VERSION=$BUILD_VERSION \
|
||||
--build-arg BBUILD_COMMIT=$BUILD_COMMIT \
|
||||
backend/
|
||||
docker build --target code \
|
||||
--tag "ocelotsocialnetwork/backend:latest-code" \
|
||||
--tag "ocelotsocialnetwork/backend:${VERSION}-code" \
|
||||
--tag "ocelotsocialnetwork/backend:${BUILD_VERSION}-code" \
|
||||
--build-arg BBUILD_DATE=$BUILD_DATE \
|
||||
--build-arg BBUILD_VERSION=$BUILD_VERSION \
|
||||
--build-arg BBUILD_COMMIT=$BUILD_COMMIT \
|
||||
backend/
|
||||
docker build --target production \
|
||||
--tag "ocelotsocialnetwork/backend:latest" \
|
||||
--tag "ocelotsocialnetwork/backend:${VERSION}" \
|
||||
--tag "ocelotsocialnetwork/backend:${BUILD_VERSION}" \
|
||||
--build-arg BBUILD_DATE=$BUILD_DATE \
|
||||
--build-arg BBUILD_VERSION=$BUILD_VERSION \
|
||||
--build-arg BBUILD_COMMIT=$BUILD_COMMIT \
|
||||
backend/
|
||||
- name: Backend | Save docker image
|
||||
run: docker save "ocelotsocialnetwork/backend" > /tmp/backend.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
with:
|
||||
name: docker-backend-production
|
||||
path: /tmp/backend.tar
|
||||
|
||||
##############################################################################
|
||||
# JOB: DOCKER BUILD PRODUCTION WEBAPP ########################################
|
||||
##############################################################################
|
||||
build_production_webapp:
|
||||
name: Docker Build Production - WebApp
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- name: Setup env
|
||||
run: |
|
||||
echo "VERSION=$(node -p -e "require('./package.json').version")" >> $GITHUB_ENV
|
||||
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
|
||||
echo "BUILD_COMMIT=${GITHUB_SHA}" >> $GITHUB_ENV
|
||||
- run: echo "BUILD_VERSION=${VERSION}-${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
|
||||
- name: Webapp | Build `production` image
|
||||
run: |
|
||||
docker build --target base \
|
||||
--tag "ocelotsocialnetwork/webapp:latest-base" \
|
||||
--tag "ocelotsocialnetwork/webapp:${VERSION}-base" \
|
||||
--tag "ocelotsocialnetwork/webapp:${BUILD_VERSION}-base" \
|
||||
--build-arg BBUILD_DATE=$BUILD_DATE \
|
||||
--build-arg BBUILD_VERSION=$BUILD_VERSION \
|
||||
--build-arg BBUILD_COMMIT=$BUILD_COMMIT \
|
||||
webapp/
|
||||
docker build --target code \
|
||||
--tag "ocelotsocialnetwork/webapp:latest-code" \
|
||||
--tag "ocelotsocialnetwork/webapp:${VERSION}-code" \
|
||||
--tag "ocelotsocialnetwork/webapp:${BUILD_VERSION}-code" \
|
||||
--build-arg BBUILD_DATE=$BUILD_DATE \
|
||||
--build-arg BBUILD_VERSION=$BUILD_VERSION \
|
||||
--build-arg BBUILD_COMMIT=$BUILD_COMMIT \
|
||||
webapp/
|
||||
docker build --target production \
|
||||
--tag "ocelotsocialnetwork/webapp:latest" \
|
||||
--tag "ocelotsocialnetwork/webapp:${VERSION}" \
|
||||
--tag "ocelotsocialnetwork/webapp:${BUILD_VERSION}" \
|
||||
--build-arg BBUILD_DATE=$BUILD_DATE \
|
||||
--build-arg BBUILD_VERSION=$BUILD_VERSION \
|
||||
--build-arg BBUILD_COMMIT=$BUILD_COMMIT \
|
||||
webapp/
|
||||
- name: Webapp | Save docker image
|
||||
run: docker save "ocelotsocialnetwork/webapp" > /tmp/webapp.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
with:
|
||||
name: docker-webapp-production
|
||||
path: /tmp/webapp.tar
|
||||
|
||||
##############################################################################
|
||||
# JOB: DOCKER BUILD PRODUCTION MAINTENANCE ###################################
|
||||
##############################################################################
|
||||
build_production_maintenance:
|
||||
name: Docker Build Production - Maintenance
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
- name: Setup env
|
||||
run: |
|
||||
echo "VERSION=$(node -p -e "require('./package.json').version")" >> $GITHUB_ENV
|
||||
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
|
||||
echo "BUILD_COMMIT=${GITHUB_SHA}" >> $GITHUB_ENV
|
||||
- run: echo "BUILD_VERSION=${VERSION}-${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
|
||||
- name: Maintenance | Build `production` image
|
||||
run: |
|
||||
docker build --target base \
|
||||
--tag "ocelotsocialnetwork/maintenance:latest-base" \
|
||||
--tag "ocelotsocialnetwork/maintenance:${VERSION}-base" \
|
||||
--tag "ocelotsocialnetwork/maintenance:${BUILD_VERSION}-base" \
|
||||
--build-arg BBUILD_DATE=$BUILD_DATE \
|
||||
--build-arg BBUILD_VERSION=$BUILD_VERSION \
|
||||
--build-arg BBUILD_COMMIT=$BUILD_COMMIT \
|
||||
-f webapp/Dockerfile.maintenance \
|
||||
webapp/
|
||||
docker build --target code \
|
||||
--tag "ocelotsocialnetwork/maintenance:latest-code" \
|
||||
--tag "ocelotsocialnetwork/maintenance:${VERSION}-code" \
|
||||
--tag "ocelotsocialnetwork/maintenance:${BUILD_VERSION}-code" \
|
||||
--build-arg BBUILD_DATE=$BUILD_DATE \
|
||||
--build-arg BBUILD_VERSION=$BUILD_VERSION \
|
||||
--build-arg BBUILD_COMMIT=$BUILD_COMMIT \
|
||||
-f webapp/Dockerfile.maintenance \
|
||||
webapp/
|
||||
docker build --target production \
|
||||
--tag "ocelotsocialnetwork/maintenance:latest" \
|
||||
--tag "ocelotsocialnetwork/maintenance:${VERSION}" \
|
||||
--tag "ocelotsocialnetwork/maintenance:${BUILD_VERSION}" \
|
||||
--build-arg BBUILD_DATE=$BUILD_DATE \
|
||||
--build-arg BBUILD_VERSION=$BUILD_VERSION \
|
||||
--build-arg BBUILD_COMMIT=$BUILD_COMMIT \
|
||||
-f webapp/Dockerfile.maintenance \
|
||||
webapp/
|
||||
- name: Maintenance | Save docker image
|
||||
run: docker save "ocelotsocialnetwork/maintenance" > /tmp/maintenance.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
with:
|
||||
name: docker-maintenance-production
|
||||
path: /tmp/maintenance.tar
|
||||
|
||||
##############################################################################
|
||||
# JOB: UPLOAD TO DOCKERHUB ###################################################
|
||||
##############################################################################
|
||||
upload_to_dockerhub:
|
||||
name: Upload to Dockerhub
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_production_neo4j,build_production_backend,build_production_webapp,build_production_maintenance]
|
||||
env:
|
||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Download Docker Image (Neo4J)
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: docker-neo4j-community
|
||||
path: /tmp
|
||||
- run: docker load < /tmp/neo4j.tar
|
||||
- name: Download Docker Image (Backend)
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: docker-backend-production
|
||||
path: /tmp
|
||||
- run: docker load < /tmp/backend.tar
|
||||
- name: Download Docker Image (WebApp)
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: docker-webapp-production
|
||||
path: /tmp
|
||||
- run: docker load < /tmp/webapp.tar
|
||||
- name: Download Docker Image (Maintenance)
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: docker-maintenance-production
|
||||
path: /tmp
|
||||
- run: docker load < /tmp/maintenance.tar
|
||||
|
||||
- name: login to dockerhub
|
||||
run: echo "${DOCKERHUB_TOKEN}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin
|
||||
- name: Push images
|
||||
run: |
|
||||
docker push --all-tags ocelotsocialnetwork/neo4j-community
|
||||
docker push --all-tags ocelotsocialnetwork/backend
|
||||
docker push --all-tags ocelotsocialnetwork/webapp
|
||||
docker push --all-tags ocelotsocialnetwork/maintenance
|
||||
|
||||
##############################################################################
|
||||
# JOB: GITHUB TAG LATEST VERSION #############################################
|
||||
##############################################################################
|
||||
github_tag:
|
||||
name: Tag latest version on Github
|
||||
runs-on: ubuntu-latest
|
||||
needs: [upload_to_dockerhub]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
@ -293,7 +64,7 @@ jobs:
|
||||
echo "BUILD_COMMIT=${GITHUB_SHA}" >> $GITHUB_ENV
|
||||
- run: echo "BUILD_VERSION=${VERSION}-${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
|
||||
#- name: Repository Dispatch
|
||||
# uses: peter-evans/repository-dispatch@39d2331fbbe4be56c4434ca745a23633155f9cdf # v3.0.0
|
||||
# uses: peter-evans/repository-dispatch@342b4dee76f7e22ff463b5e5d632b75319eb411e # v3.0.0
|
||||
# with:
|
||||
# token: ${{ github.token }}
|
||||
# event-type: trigger-ocelot-build-success
|
||||
@ -301,7 +72,7 @@ jobs:
|
||||
# client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}", "VERSION": "${VERSION}", "BUILD_DATE": "${BUILD_DATE}", "BUILD_COMMIT": "${BUILD_COMMIT}", "BUILD_VERSION": "${BUILD_VERSION}"}'
|
||||
|
||||
- name: Repository Dispatch stage.ocelot.social
|
||||
uses: peter-evans/repository-dispatch@39d2331fbbe4be56c4434ca745a23633155f9cdf # v3.0.0
|
||||
uses: peter-evans/repository-dispatch@342b4dee76f7e22ff463b5e5d632b75319eb411e # v3.0.0
|
||||
with:
|
||||
token: ${{ secrets.OCELOT_PUBLISH_EVENT_PAT }} # this token is required to access the other repository
|
||||
event-type: trigger-ocelot-build-success
|
||||
@ -309,7 +80,7 @@ jobs:
|
||||
client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}", "GITHUB_RUN_NUMBER": "${{ env.GITHUB_RUN_NUMBER }}", "VERSION": "${VERSION}", "BUILD_DATE": "${BUILD_DATE}", "BUILD_COMMIT": "${BUILD_COMMIT}", "BUILD_VERSION": "${BUILD_VERSION}"}'
|
||||
|
||||
- name: Repository Dispatch stage.yunite.me
|
||||
uses: peter-evans/repository-dispatch@39d2331fbbe4be56c4434ca745a23633155f9cdf # v3.0.0
|
||||
uses: peter-evans/repository-dispatch@342b4dee76f7e22ff463b5e5d632b75319eb411e # v3.0.0
|
||||
with:
|
||||
token: ${{ secrets.OCELOT_PUBLISH_EVENT_PAT }} # this token is required to access the other repository
|
||||
event-type: trigger-ocelot-build-success
|
||||
|
||||
11
.github/workflows/test-backend.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
||||
|
||||
- name: Cache docker images
|
||||
id: cache-neo4j
|
||||
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.0.2
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/neo4j.tar
|
||||
key: ${{ github.run_id }}-backend-neo4j-cache
|
||||
@ -58,7 +58,7 @@ jobs:
|
||||
|
||||
- name: Cache docker images
|
||||
id: cache-backend
|
||||
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.0.2
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/backend.tar
|
||||
key: ${{ github.run_id }}-backend-cache
|
||||
@ -87,14 +87,14 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
|
||||
- name: Restore Neo4J cache
|
||||
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.0.2
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/neo4j.tar
|
||||
key: ${{ github.run_id }}-backend-neo4j-cache
|
||||
fail-on-cache-miss: true
|
||||
|
||||
- name: Restore Backend cache
|
||||
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.0.2
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/backend.tar
|
||||
key: ${{ github.run_id }}-backend-cache
|
||||
@ -112,7 +112,8 @@ jobs:
|
||||
cp backend/.env.template backend/.env
|
||||
|
||||
- name: backend | docker compose
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps neo4j backend
|
||||
# doesn't work without the --build flag - this either means we should not load the cached images or cache the correct image
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps neo4j backend --build
|
||||
|
||||
- name: backend | Initialize Database
|
||||
run: docker compose exec -T backend yarn db:migrate init
|
||||
|
||||
149
.github/workflows/test-e2e.yml
vendored
@ -3,8 +3,62 @@ name: ocelot.social end-to-end test CI
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
docker_preparation:
|
||||
name: Fullstack test preparation
|
||||
prepare_neo4j_image:
|
||||
name: Fullstack | prepare neo4j image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
|
||||
- name: Build docker image
|
||||
run: |
|
||||
docker build --target community -t "ocelotsocialnetwork/neo4j-community:test" neo4j/
|
||||
docker save "ocelotsocialnetwork/neo4j-community:test" > /tmp/neo4j.tar
|
||||
|
||||
- name: Cache docker image
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/neo4j.tar
|
||||
key: ${{ github.run_id }}-e2e-neo4j-cache
|
||||
|
||||
prepare_backend_image:
|
||||
name: Fullstack | prepare backend image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
|
||||
- name: Build docker image
|
||||
run: |
|
||||
docker build --target test -t "ocelotsocialnetwork/backend:test" backend/
|
||||
docker save "ocelotsocialnetwork/backend:test" > /tmp/backend.tar
|
||||
|
||||
- name: Cache docker image
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/backend.tar
|
||||
key: ${{ github.run_id }}-e2e-backend-cache
|
||||
|
||||
prepare_webapp_image:
|
||||
name: Fullstack | prepare webapp image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
|
||||
- name: Build docker image
|
||||
run: |
|
||||
docker build --target test -t "ocelotsocialnetwork/webapp:test" webapp/
|
||||
docker save "ocelotsocialnetwork/webapp:test" > /tmp/webapp.tar
|
||||
|
||||
- name: Cache docker image
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/webapp.tar
|
||||
key: ${{ github.run_id }}-e2e-webapp-cache
|
||||
|
||||
prepare_cypress:
|
||||
name: Fullstack | prepare cypress
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@ -13,18 +67,7 @@ jobs:
|
||||
- name: Copy env files
|
||||
run: |
|
||||
cp webapp/.env.template webapp/.env
|
||||
cp frontend/.env.dist frontend/.env
|
||||
cp backend/.env.template backend/.env
|
||||
|
||||
- name: Build docker images
|
||||
run: |
|
||||
mkdir /tmp/images
|
||||
docker build --target community -t "ocelotsocialnetwork/neo4j-community:test" neo4j/
|
||||
docker save "ocelotsocialnetwork/neo4j-community:test" > /tmp/images/neo4j.tar
|
||||
docker build --target test -t "ocelotsocialnetwork/backend:test" backend/
|
||||
docker save "ocelotsocialnetwork/backend:test" > /tmp/images/backend.tar
|
||||
docker build --target test -t "ocelotsocialnetwork/webapp:test" webapp/
|
||||
docker save "ocelotsocialnetwork/webapp:test" > /tmp/images/webapp.tar
|
||||
cp backend/.env.test_e2e backend/.env
|
||||
|
||||
- name: Install cypress requirements
|
||||
run: |
|
||||
@ -35,21 +78,20 @@ jobs:
|
||||
cd ..
|
||||
yarn install
|
||||
|
||||
- name: Cache docker images
|
||||
id: cache
|
||||
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.0.2
|
||||
- name: Cache docker image
|
||||
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: |
|
||||
/opt/cucumber-json-formatter
|
||||
/home/runner/.cache/Cypress
|
||||
/home/runner/work/Ocelot-Social/Ocelot-Social
|
||||
/tmp/images/
|
||||
key: ${{ github.run_id }}-e2e-preparation-cache
|
||||
key: ${{ github.run_id }}-e2e-cypress
|
||||
|
||||
fullstack_tests:
|
||||
name: Fullstack tests
|
||||
name: Fullstack | tests
|
||||
if: success()
|
||||
needs: docker_preparation
|
||||
needs: [prepare_neo4j_image, prepare_backend_image, prepare_webapp_image, prepare_cypress]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
jobs: 8
|
||||
@ -58,26 +100,42 @@ jobs:
|
||||
# run copies of the current job in parallel
|
||||
job: [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
steps:
|
||||
- name: Restore cache
|
||||
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.0.2
|
||||
id: cache
|
||||
- name: Restore cypress cache
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: |
|
||||
/opt/cucumber-json-formatter
|
||||
/home/runner/.cache/Cypress
|
||||
/home/runner/work/Ocelot-Social/Ocelot-Social
|
||||
/tmp/images/
|
||||
key: ${{ github.run_id }}-e2e-preparation-cache
|
||||
fail-on-cache-miss: true
|
||||
key: ${{ github.run_id }}-e2e-cypress
|
||||
restore-keys: ${{ github.run_id }}-e2e-cypress
|
||||
|
||||
- name: Restore neo4j cache
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/neo4j.tar
|
||||
key: ${{ github.run_id }}-e2e-neo4j-cache
|
||||
|
||||
- name: Restore backend cache
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/backend.tar
|
||||
key: ${{ github.run_id }}-e2e-backend-cache
|
||||
|
||||
- name: Restore webapp cache
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/webapp.tar
|
||||
key: ${{ github.run_id }}-e2e-webapp-cache
|
||||
|
||||
- name: Boot up test system | docker compose
|
||||
run: |
|
||||
chmod +x /opt/cucumber-json-formatter
|
||||
sudo ln -fs /opt/cucumber-json-formatter /usr/bin/cucumber-json-formatter
|
||||
docker load < /tmp/images/neo4j.tar
|
||||
docker load < /tmp/images/backend.tar
|
||||
docker load < /tmp/images/webapp.tar
|
||||
docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps webapp neo4j backend
|
||||
docker load < /tmp/neo4j.tar
|
||||
docker load < /tmp/backend.tar
|
||||
docker load < /tmp/webapp.tar
|
||||
docker compose -f docker-compose.yml -f docker-compose.test.yml up --build --detach --no-deps webapp neo4j backend mailserver
|
||||
sleep 90s
|
||||
|
||||
- name: Full stack tests | run tests
|
||||
@ -93,22 +151,29 @@ jobs:
|
||||
- name: Full stack tests | if tests failed, upload report
|
||||
id: e2e-report
|
||||
if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }}
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: ocelot-e2e-test-report-pr${{ needs.docker_preparation.outputs.pr-number }}
|
||||
path: /home/runner/work/Ocelot-Social/Ocelot-Social/cypress/reports/cucumber_html_report
|
||||
|
||||
cleanup:
|
||||
name: Cleanup
|
||||
needs: [docker_preparation, fullstack_tests]
|
||||
cleanup_cache:
|
||||
name: Cleanup Cache
|
||||
needs: fullstack_tests
|
||||
runs-on: ubuntu-latest
|
||||
permissions: write-all
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- name: Delete cache
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
|
||||
- name: Full stack tests | cleanup cache
|
||||
run: |
|
||||
gh extension install actions/gh-actions-cache
|
||||
KEY="${{ github.run_id }}-e2e-preparation-cache"
|
||||
gh actions-cache delete $KEY -R Ocelot-Social-Community/Ocelot-Social --confirm
|
||||
cacheKeys=$(gh cache list --json key --jq '.[] | select(.key | startswith("${{ github.run_id }}-e2e-")) | .key')
|
||||
set +e
|
||||
echo "Deleting caches..."
|
||||
for cacheKey in $cacheKeys
|
||||
do
|
||||
gh cache delete "$cacheKey"
|
||||
done
|
||||
echo "Done"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
7
.github/workflows/test-webapp.yml
vendored
@ -50,7 +50,7 @@ jobs:
|
||||
docker save "ocelotsocialnetwork/webapp:test" > /tmp/webapp.tar
|
||||
|
||||
- name: Cache docker image
|
||||
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.0.2
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/webapp.tar
|
||||
key: ${{ github.run_id }}-webapp-cache
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
|
||||
|
||||
- name: Restore webapp cache
|
||||
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.0.2
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.0.2
|
||||
with:
|
||||
path: /tmp/webapp.tar
|
||||
key: ${{ github.run_id }}-webapp-cache
|
||||
@ -94,7 +94,8 @@ jobs:
|
||||
cp backend/.env.template backend/.env
|
||||
|
||||
- name: backend | docker compose
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps webapp
|
||||
# doesn't work without the --build flag - this either means we should not load the cached images or cache the correct image
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps webapp --build
|
||||
|
||||
- name: webapp | Unit tests incl. coverage check
|
||||
run: docker compose exec -T webapp yarn test
|
||||
|
||||
2
.github/workflows/test.lint_pr.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.actor != 'dependabot[bot]' }}
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@40166f00814508ec3201fc8595b393d451c8cd80 # v5.5.3
|
||||
- uses: amannn/action-semantic-pull-request@335288255954904a41ddda8947c8f2c844b8bfeb # v5.5.3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
|
||||
2
.gitignore
vendored
@ -10,11 +10,13 @@ yarn-error.log*
|
||||
kubeconfig.yaml
|
||||
backup-cron-job.log
|
||||
.vscode
|
||||
.nuxt
|
||||
|
||||
node_modules/
|
||||
cypress/videos
|
||||
cypress/screenshots/
|
||||
cypress.env.json
|
||||
deployment/configurations/
|
||||
|
||||
.vuepress/.cache/
|
||||
.vuepress/.temp/
|
||||
|
||||
1
.tool-versions
Normal file
@ -0,0 +1 @@
|
||||
nodejs 20.12.1
|
||||
733
CHANGELOG.md
@ -186,7 +186,6 @@ $ cp .env.template .env
|
||||
|
||||
# in folder backend/
|
||||
$ cp .env.template .env
|
||||
```
|
||||
|
||||
For Development:
|
||||
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
coverage:
|
||||
range: "60...100"
|
||||
@ -6,18 +6,28 @@ NEO4J_PASSWORD=letmein
|
||||
GRAPHQL_URI=http://localhost:4000
|
||||
CLIENT_URI=http://localhost:3000
|
||||
|
||||
# EMail
|
||||
EMAIL_SUPPORT="devops@ocelot.social"
|
||||
# E-Mail default settings
|
||||
SUPPORT_EMAIL="devops@ocelot.social"
|
||||
EMAIL_DEFAULT_SENDER="devops@ocelot.social"
|
||||
SMTP_HOST=
|
||||
SMTP_PORT=
|
||||
SMTP_IGNORE_TLS=true
|
||||
SMTP_MAX_CONNECTIONS=5
|
||||
SMTP_MAX_MESSAGES=Infinity
|
||||
SMTP_USERNAME=
|
||||
SMTP_PASSWORD=
|
||||
SMTP_SECURE="false" # true for 465, false for other ports
|
||||
SMTP_DKIM_DOMAINNAME=
|
||||
SMTP_DKIM_KEYSELECTOR=
|
||||
SMTP_DKIM_PRIVATKEY=
|
||||
# E-Mail settings for our 'docker compose up mailserver'
|
||||
# SMTP_HOST=localhost
|
||||
# SMTP_PORT=1025
|
||||
# SMTP_IGNORE_TLS=true
|
||||
# SMTP_USERNAME=
|
||||
# SMTP_PASSWORD=
|
||||
# SMTP_MAX_CONNECTIONS=1
|
||||
# SMTP_MAX_MESSAGES= 10
|
||||
|
||||
JWT_SECRET="b/&&7b78BF&fv/Vd"
|
||||
JWT_EXPIRES="2y"
|
||||
|
||||
41
backend/.env.test_e2e
Normal file
@ -0,0 +1,41 @@
|
||||
DEBUG=true
|
||||
|
||||
NEO4J_URI=bolt://localhost:7687
|
||||
NEO4J_USERNAME=neo4j
|
||||
NEO4J_PASSWORD=letmein
|
||||
GRAPHQL_URI=http://localhost:4000
|
||||
CLIENT_URI=http://localhost:3000
|
||||
|
||||
# E-Mail default settings
|
||||
SUPPORT_EMAIL="devops@ocelot.social"
|
||||
EMAIL_DEFAULT_SENDER="devops@ocelot.social"
|
||||
SMTP_HOST=mailserver
|
||||
SMTP_PORT=1025
|
||||
SMTP_IGNORE_TLS=true
|
||||
SMTP_MAX_CONNECTIONS=5
|
||||
SMTP_MAX_MESSAGES=Infinity
|
||||
SMTP_USERNAME=
|
||||
SMTP_PASSWORD=
|
||||
SMTP_SECURE="false" # true for 465, false for other ports
|
||||
SMTP_DKIM_DOMAINNAME=
|
||||
SMTP_DKIM_KEYSELECTOR=
|
||||
SMTP_DKIM_PRIVATKEY=
|
||||
|
||||
JWT_SECRET="b/&&7b78BF&fv/Vd"
|
||||
JWT_EXPIRES="2y"
|
||||
MAPBOX_TOKEN="pk.eyJ1IjoiYnVzZmFrdG9yIiwiYSI6ImNraDNiM3JxcDBhaWQydG1uczhpZWtpOW4ifQ.7TNRTO-o9aK1Y6MyW_Nd4g"
|
||||
|
||||
PRIVATE_KEY_PASSPHRASE="a7dsf78sadg87ad87sfagsadg78"
|
||||
|
||||
SENTRY_DSN_BACKEND=
|
||||
COMMIT=
|
||||
PUBLIC_REGISTRATION=false
|
||||
INVITE_REGISTRATION=true
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_ENDPOINT=
|
||||
AWS_REGION=
|
||||
AWS_BUCKET=
|
||||
|
||||
CATEGORIES_ACTIVE=false
|
||||
3
backend/.eslintignore
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
build/
|
||||
coverage/
|
||||
232
backend/.eslintrc.cjs
Normal file
@ -0,0 +1,232 @@
|
||||
// eslint-disable-next-line import/no-commonjs
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['prettier', '@typescript-eslint', 'import', 'n', 'promise', 'security', 'no-catch-all'],
|
||||
extends: [
|
||||
'standard',
|
||||
'eslint:recommended',
|
||||
'plugin:n/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
'plugin:import/recommended',
|
||||
'plugin:import/typescript',
|
||||
'plugin:promise/recommended',
|
||||
'plugin:security/recommended-legacy',
|
||||
'plugin:@eslint-community/eslint-comments/recommended',
|
||||
'prettier',
|
||||
],
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
project: ['./tsconfig.json', './backend/tsconfig.json'],
|
||||
},
|
||||
node: true,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'no-catch-all/no-catch-all': 'error',
|
||||
'no-console': 'error',
|
||||
camelcase: 'error',
|
||||
'no-debugger': 'error',
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
htmlWhitespaceSensitivity: 'ignore',
|
||||
},
|
||||
],
|
||||
// import
|
||||
'import/export': 'error',
|
||||
// 'import/no-deprecated': 'error',
|
||||
'import/no-empty-named-blocks': 'error',
|
||||
'import/no-extraneous-dependencies': 'error',
|
||||
'import/no-mutable-exports': 'error',
|
||||
'import/no-unused-modules': 'error',
|
||||
'import/no-named-as-default': 'error',
|
||||
'import/no-named-as-default-member': 'error',
|
||||
'import/no-amd': 'error',
|
||||
'import/no-commonjs': 'error',
|
||||
'import/no-import-module-exports': 'error',
|
||||
'import/no-nodejs-modules': 'off',
|
||||
'import/unambiguous': 'off', // not compatible with .eslintrc.cjs
|
||||
'import/default': 'error',
|
||||
'import/named': 'off', // has false positives
|
||||
'import/namespace': 'error',
|
||||
'import/no-absolute-path': 'error',
|
||||
'import/no-cycle': 'error',
|
||||
'import/no-dynamic-require': 'error',
|
||||
'import/no-internal-modules': 'off',
|
||||
'import/no-relative-packages': 'error',
|
||||
'import/no-relative-parent-imports': ['error', { ignore: ['@/*'] }],
|
||||
'import/no-self-import': 'error',
|
||||
'import/no-unresolved': 'error',
|
||||
'import/no-useless-path-segments': 'error',
|
||||
'import/no-webpack-loader-syntax': 'error',
|
||||
'import/consistent-type-specifier-style': 'error',
|
||||
'import/exports-last': 'off',
|
||||
'import/extensions': 'error',
|
||||
'import/first': 'error',
|
||||
'import/group-exports': 'off',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-anonymous-default-export': 'off', // not compatible with neode
|
||||
'import/no-default-export': 'off', // not compatible with neode
|
||||
'import/no-duplicates': 'error',
|
||||
'import/no-named-default': 'error',
|
||||
'import/no-namespace': 'error',
|
||||
'import/no-unassigned-import': 'error',
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
||||
'newlines-between': 'always',
|
||||
pathGroups: [
|
||||
{
|
||||
pattern: '@?*/**',
|
||||
group: 'external',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: '@/**',
|
||||
group: 'external',
|
||||
position: 'after',
|
||||
},
|
||||
],
|
||||
alphabetize: {
|
||||
order: 'asc' /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */,
|
||||
caseInsensitive: true /* ignore case. Options: [true, false] */,
|
||||
},
|
||||
distinctGroup: true,
|
||||
},
|
||||
],
|
||||
'import/prefer-default-export': 'off',
|
||||
|
||||
// n
|
||||
// 'n/callback-return': 'error',
|
||||
'n/exports-style': 'error',
|
||||
'n/file-extension-in-import': ['error', 'never'],
|
||||
'n/global-require': 'error',
|
||||
'n/handle-callback-err': 'error',
|
||||
// 'n/hashbang': 'error', // part of n/recommended
|
||||
'n/no-callback-literal': 'error',
|
||||
// 'n/no-deprecated-api': 'error', // part of n/recommended
|
||||
// 'n/no-exports-assign': 'error', // part of n/recommended
|
||||
'n/no-extraneous-import': 'off', // duplicate of import/no-extraneous-dependencies // part of n/recommended
|
||||
// 'n/no-extraneous-require': 'error', // part of n/recommended
|
||||
'n/no-hide-core-modules': 'error',
|
||||
'n/no-missing-import': 'off', // not compatible with typescript // part of n/recommended
|
||||
// 'n/no-missing-require': 'error', // part of n/recommended
|
||||
'n/no-mixed-requires': 'error',
|
||||
'n/no-new-require': 'error',
|
||||
'n/no-path-concat': 'error',
|
||||
'n/no-process-env': 'error',
|
||||
// 'n/no-process-exit': 'error', // part of n/recommended
|
||||
'n/no-restricted-import': 'error',
|
||||
'n/no-restricted-require': 'error',
|
||||
'n/no-sync': 'error',
|
||||
// 'n/no-unpublished-bin': 'error', // part of n/recommended
|
||||
'n/no-unpublished-import': [
|
||||
'error',
|
||||
{ allowModules: ['apollo-server-testing', 'rosie', '@faker-js/faker', 'ts-jest'] },
|
||||
], // part of n/recommended
|
||||
'n/no-unpublished-require': ['error', { allowModules: ['ts-jest', 'require-json5'] }], // part of n/recommended
|
||||
// 'n/no-unsupported-features/es-builtins': 'error', // part of n/recommended
|
||||
// 'n/no-unsupported-features/es-syntax': 'error', // part of n/recommended
|
||||
// 'n/no-unsupported-features/node-builtins': 'error', // part of n/recommended
|
||||
'n/prefer-global/buffer': 'error',
|
||||
'n/prefer-global/console': 'error',
|
||||
'n/prefer-global/process': 'error',
|
||||
'n/prefer-global/text-decoder': 'error',
|
||||
'n/prefer-global/text-encoder': 'error',
|
||||
'n/prefer-global/url': 'error',
|
||||
'n/prefer-global/url-search-params': 'error',
|
||||
'n/prefer-node-protocol': 'error',
|
||||
'n/prefer-promises/dns': 'error',
|
||||
'n/prefer-promises/fs': 'error',
|
||||
// 'n/process-exit-as-throw': 'error', // part of n/recommended
|
||||
'n/shebang': 'error',
|
||||
|
||||
// promise
|
||||
// 'promise/always-return': 'error', // part of promise/recommended
|
||||
'promise/avoid-new': 'error',
|
||||
// 'promise/catch-or-return': 'error', // part of promise/recommended
|
||||
// 'promise/no-callback-in-promise': 'warn', // part of promise/recommended
|
||||
'promise/no-multiple-resolved': 'error',
|
||||
'promise/no-native': 'off', // ES5 only
|
||||
// 'promise/no-nesting': 'warn', // part of promise/recommended
|
||||
// 'promise/no-new-statics': 'error', // part of promise/recommended
|
||||
// 'promise/no-promise-in-callback': 'warn', // part of promise/recommended
|
||||
// 'promise/no-return-in-finally': 'warn', // part of promise/recommended
|
||||
// 'promise/no-return-wrap': 'error', // part of promise/recommended
|
||||
// 'promise/param-names': 'error', // part of promise/recommended
|
||||
'promise/prefer-await-to-callbacks': 'error',
|
||||
'promise/prefer-catch': 'error',
|
||||
'promise/spec-only': 'error',
|
||||
// 'promise/valid-params': 'error', // part of promise/recommended
|
||||
|
||||
// eslint comments
|
||||
'@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],
|
||||
'@eslint-community/eslint-comments/no-restricted-disable': 'error',
|
||||
'@eslint-community/eslint-comments/no-use': 'off',
|
||||
'@eslint-community/eslint-comments/require-description': 'off',
|
||||
},
|
||||
overrides: [
|
||||
// only for ts files
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||
'plugin:@typescript-eslint/strict',
|
||||
'prettier',
|
||||
],
|
||||
rules: {
|
||||
// allow explicitly defined dangling promises
|
||||
// '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],
|
||||
'no-void': ['error', { allowAsStatement: true }],
|
||||
// ignore prefer-regexp-exec rule to allow string.match(regex)
|
||||
'@typescript-eslint/prefer-regexp-exec': 'off',
|
||||
// this should not run on ts files: https://github.com/import-js/eslint-plugin-import/issues/2215#issuecomment-911245486
|
||||
'import/unambiguous': 'off',
|
||||
// this is not compatible with typeorm, due to joined tables can be null, but are not defined as nullable
|
||||
'@typescript-eslint/no-unnecessary-condition': 'off',
|
||||
// respect underscore as acceptable unused variable
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
|
||||
],
|
||||
},
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json'],
|
||||
// this is to properly reference the referenced project database without requirement of compiling it
|
||||
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.spec.ts'],
|
||||
plugins: ['jest'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
rules: {
|
||||
'jest/no-disabled-tests': 'error',
|
||||
'jest/no-focused-tests': 'error',
|
||||
'jest/no-identical-title': 'error',
|
||||
'jest/prefer-to-have-length': 'error',
|
||||
'jest/valid-expect': 'error',
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'jest/unbound-method': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
extends: ['plugin:jsonc/recommended-with-jsonc'],
|
||||
files: ['*.json', '*.json5', '*.jsonc'],
|
||||
parser: 'jsonc-eslint-parser',
|
||||
},
|
||||
],
|
||||
}
|
||||
@ -1,219 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
// es6: true,
|
||||
node: true,
|
||||
},
|
||||
/* parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
},*/
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['prettier', '@typescript-eslint' /*, 'import', 'n', 'promise'*/],
|
||||
extends: [
|
||||
'standard',
|
||||
// 'eslint:recommended',
|
||||
'plugin:prettier/recommended',
|
||||
// 'plugin:import/recommended',
|
||||
// 'plugin:import/typescript',
|
||||
// 'plugin:security/recommended',
|
||||
// 'plugin:@eslint-community/eslint-comments/recommended',
|
||||
],
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
project: ['./tsconfig.json'],
|
||||
},
|
||||
node: true,
|
||||
},
|
||||
},
|
||||
/* rules: {
|
||||
//'indent': [ 'error', 2 ],
|
||||
//'quotes': [ "error", "single"],
|
||||
// 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
> 'no-console': ['error'],
|
||||
> 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
> 'prettier/prettier': ['error'],
|
||||
}, */
|
||||
rules: {
|
||||
'no-console': 'error',
|
||||
camelcase: 'error',
|
||||
'no-debugger': 'error',
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
htmlWhitespaceSensitivity: 'ignore',
|
||||
},
|
||||
],
|
||||
// import
|
||||
// 'import/export': 'error',
|
||||
// 'import/no-deprecated': 'error',
|
||||
// 'import/no-empty-named-blocks': 'error',
|
||||
// 'import/no-extraneous-dependencies': 'error',
|
||||
// 'import/no-mutable-exports': 'error',
|
||||
// 'import/no-unused-modules': 'error',
|
||||
// 'import/no-named-as-default': 'error',
|
||||
// 'import/no-named-as-default-member': 'error',
|
||||
// 'import/no-amd': 'error',
|
||||
// 'import/no-commonjs': 'error',
|
||||
// 'import/no-import-module-exports': 'error',
|
||||
// 'import/no-nodejs-modules': 'off',
|
||||
// 'import/unambiguous': 'error',
|
||||
// 'import/default': 'error',
|
||||
// 'import/named': 'error',
|
||||
// 'import/namespace': 'error',
|
||||
// 'import/no-absolute-path': 'error',
|
||||
// 'import/no-cycle': 'error',
|
||||
// 'import/no-dynamic-require': 'error',
|
||||
// 'import/no-internal-modules': 'off',
|
||||
// 'import/no-relative-packages': 'error',
|
||||
// 'import/no-relative-parent-imports': ['error', { ignore: ['@/*'] }],
|
||||
// 'import/no-self-import': 'error',
|
||||
// 'import/no-unresolved': 'error',
|
||||
// 'import/no-useless-path-segments': 'error',
|
||||
// 'import/no-webpack-loader-syntax': 'error',
|
||||
// 'import/consistent-type-specifier-style': 'error',
|
||||
// 'import/exports-last': 'off',
|
||||
// 'import/extensions': 'error',
|
||||
// 'import/first': 'error',
|
||||
// 'import/group-exports': 'off',
|
||||
// 'import/newline-after-import': 'error',
|
||||
// 'import/no-anonymous-default-export': 'error',
|
||||
// 'import/no-default-export': 'error',
|
||||
// 'import/no-duplicates': 'error',
|
||||
// 'import/no-named-default': 'error',
|
||||
// 'import/no-namespace': 'error',
|
||||
// 'import/no-unassigned-import': 'error',
|
||||
// 'import/order': [
|
||||
// 'error',
|
||||
// {
|
||||
// groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
||||
// 'newlines-between': 'always',
|
||||
// pathGroups: [
|
||||
// {
|
||||
// pattern: '@?*/**',
|
||||
// group: 'external',
|
||||
// position: 'after',
|
||||
// },
|
||||
// {
|
||||
// pattern: '@/**',
|
||||
// group: 'external',
|
||||
// position: 'after',
|
||||
// },
|
||||
// ],
|
||||
// alphabetize: {
|
||||
// order: 'asc' /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */,
|
||||
// caseInsensitive: true /* ignore case. Options: [true, false] */,
|
||||
// },
|
||||
// distinctGroup: true,
|
||||
// },
|
||||
// ],
|
||||
// 'import/prefer-default-export': 'off',
|
||||
// n
|
||||
// 'n/handle-callback-err': 'error',
|
||||
// 'n/no-callback-literal': 'error',
|
||||
// 'n/no-exports-assign': 'error',
|
||||
// 'n/no-extraneous-import': 'error',
|
||||
// 'n/no-extraneous-require': 'error',
|
||||
// 'n/no-hide-core-modules': 'error',
|
||||
// 'n/no-missing-import': 'off', // not compatible with typescript
|
||||
// 'n/no-missing-require': 'error',
|
||||
// 'n/no-new-require': 'error',
|
||||
// 'n/no-path-concat': 'error',
|
||||
// 'n/no-process-exit': 'error',
|
||||
// 'n/no-unpublished-bin': 'error',
|
||||
// 'n/no-unpublished-import': 'off', // TODO need to exclude seeds
|
||||
// 'n/no-unpublished-require': 'error',
|
||||
// 'n/no-unsupported-features': ['error', { ignores: ['modules'] }],
|
||||
// 'n/no-unsupported-features/es-builtins': 'error',
|
||||
// 'n/no-unsupported-features/es-syntax': 'error',
|
||||
// 'n/no-unsupported-features/node-builtins': 'error',
|
||||
// 'n/process-exit-as-throw': 'error',
|
||||
// 'n/shebang': 'error',
|
||||
// 'n/callback-return': 'error',
|
||||
// 'n/exports-style': 'error',
|
||||
// 'n/file-extension-in-import': 'off',
|
||||
// 'n/global-require': 'error',
|
||||
// 'n/no-mixed-requires': 'error',
|
||||
// 'n/no-process-env': 'error',
|
||||
// 'n/no-restricted-import': 'error',
|
||||
// 'n/no-restricted-require': 'error',
|
||||
// 'n/no-sync': 'error',
|
||||
// 'n/prefer-global/buffer': 'error',
|
||||
// 'n/prefer-global/console': 'error',
|
||||
// 'n/prefer-global/process': 'error',
|
||||
// 'n/prefer-global/text-decoder': 'error',
|
||||
// 'n/prefer-global/text-encoder': 'error',
|
||||
// 'n/prefer-global/url': 'error',
|
||||
// 'n/prefer-global/url-search-params': 'error',
|
||||
// 'n/prefer-promises/dns': 'error',
|
||||
// 'n/prefer-promises/fs': 'error',
|
||||
// promise
|
||||
// 'promise/catch-or-return': 'error',
|
||||
// 'promise/no-return-wrap': 'error',
|
||||
// 'promise/param-names': 'error',
|
||||
// 'promise/always-return': 'error',
|
||||
// 'promise/no-native': 'off',
|
||||
// 'promise/no-nesting': 'warn',
|
||||
// 'promise/no-promise-in-callback': 'warn',
|
||||
// 'promise/no-callback-in-promise': 'warn',
|
||||
// 'promise/avoid-new': 'warn',
|
||||
// 'promise/no-new-statics': 'error',
|
||||
// 'promise/no-return-in-finally': 'warn',
|
||||
// 'promise/valid-params': 'warn',
|
||||
// 'promise/prefer-await-to-callbacks': 'error',
|
||||
// 'promise/no-multiple-resolved': 'error',
|
||||
// eslint comments
|
||||
// '@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],
|
||||
// '@eslint-community/eslint-comments/no-restricted-disable': 'error',
|
||||
// '@eslint-community/eslint-comments/no-use': 'off',
|
||||
// '@eslint-community/eslint-comments/require-description': 'off',
|
||||
},
|
||||
overrides: [
|
||||
// only for ts files
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
extends: [
|
||||
// 'plugin:@typescript-eslint/recommended',
|
||||
// 'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||
// 'plugin:@typescript-eslint/strict',
|
||||
],
|
||||
rules: {
|
||||
// allow explicitly defined dangling promises
|
||||
// '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],
|
||||
'no-void': ['error', { allowAsStatement: true }],
|
||||
// ignore prefer-regexp-exec rule to allow string.match(regex)
|
||||
'@typescript-eslint/prefer-regexp-exec': 'off',
|
||||
// this should not run on ts files: https://github.com/import-js/eslint-plugin-import/issues/2215#issuecomment-911245486
|
||||
'import/unambiguous': 'off',
|
||||
// this is not compatible with typeorm, due to joined tables can be null, but are not defined as nullable
|
||||
'@typescript-eslint/no-unnecessary-condition': 'off',
|
||||
},
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json'],
|
||||
// this is to properly reference the referenced project database without requirement of compiling it
|
||||
// eslint-disable-next-line camelcase
|
||||
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.spec.ts'],
|
||||
plugins: ['jest'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
rules: {
|
||||
'jest/no-disabled-tests': 'error',
|
||||
'jest/no-focused-tests': 'error',
|
||||
'jest/no-identical-title': 'error',
|
||||
'jest/prefer-to-have-length': 'error',
|
||||
'jest/valid-expect': 'error',
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
// 'jest/unbound-method': 'error',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -1,3 +0,0 @@
|
||||
{
|
||||
"schemaPath": "./src/schema.graphql"
|
||||
}
|
||||
@ -1,103 +1,47 @@
|
||||
##################################################################################
|
||||
# BASE (Is pushed to DockerHub for rebranding) ###################################
|
||||
##################################################################################
|
||||
FROM node:20.12.1-alpine3.19 AS base
|
||||
|
||||
# ENVs
|
||||
## DOCKER_WORKDIR would be a classical ARG, but that is not multi layer persistent - shame
|
||||
ENV DOCKER_WORKDIR="/app"
|
||||
## We Cannot do `$(date -u +'%Y-%m-%dT%H:%M:%SZ')` here so we use unix timestamp=0
|
||||
ARG BBUILD_DATE="1970-01-01T00:00:00.00Z"
|
||||
ENV BUILD_DATE=$BBUILD_DATE
|
||||
## We cannot do $(yarn run version)-${BUILD_NUMBER} here so we default to 0.0.0-0
|
||||
ARG BBUILD_VERSION="0.0.0-0"
|
||||
ENV BUILD_VERSION=$BBUILD_VERSION
|
||||
## We cannot do `$(git rev-parse --short HEAD)` here so we default to 0000000
|
||||
ARG BBUILD_COMMIT="0000000"
|
||||
ENV BUILD_COMMIT=$BBUILD_COMMIT
|
||||
## SET NODE_ENV
|
||||
ENV NODE_ENV="production"
|
||||
## App relevant Envs
|
||||
ENV PORT="4000"
|
||||
|
||||
# Labels
|
||||
LABEL org.label-schema.build-date="${BUILD_DATE}"
|
||||
FROM node:24.0.2-alpine AS base
|
||||
LABEL org.label-schema.name="ocelot.social:backend"
|
||||
LABEL org.label-schema.description="Backend of the Social Network Software ocelot.social"
|
||||
LABEL org.label-schema.usage="https://github.com/Ocelot-Social-Community/Ocelot-Social/blob/master/README.md"
|
||||
LABEL org.label-schema.url="https://ocelot.social"
|
||||
LABEL org.label-schema.vcs-url="https://github.com/Ocelot-Social-Community/Ocelot-Social/tree/master/backend"
|
||||
LABEL org.label-schema.vcs-ref="${BUILD_COMMIT}"
|
||||
LABEL org.label-schema.vendor="ocelot.social Community"
|
||||
LABEL org.label-schema.version="${BUILD_VERSION}"
|
||||
LABEL org.label-schema.schema-version="1.0"
|
||||
LABEL maintainer="devops@ocelot.social"
|
||||
|
||||
# Install Additional Software
|
||||
## install: git
|
||||
RUN apk --no-cache add git python3 make g++
|
||||
|
||||
# Settings
|
||||
## Expose Container Port
|
||||
ENV NODE_ENV="production"
|
||||
ENV PORT="4000"
|
||||
EXPOSE ${PORT}
|
||||
RUN apk --no-cache add git python3 make g++ bash linux-headers
|
||||
RUN mkdir -p /app
|
||||
WORKDIR /app
|
||||
CMD ["/bin/bash", "-c", "yarn run start"]
|
||||
|
||||
## Workdir
|
||||
RUN mkdir -p ${DOCKER_WORKDIR}
|
||||
WORKDIR ${DOCKER_WORKDIR}
|
||||
|
||||
##################################################################################
|
||||
# DEVELOPMENT (Connected to the local environment, to reload on demand) ##########
|
||||
##################################################################################
|
||||
FROM base AS development
|
||||
CMD ["/bin/sh", "-c", "yarn install && yarn run dev"]
|
||||
|
||||
# We don't need to copy or build anything since we gonna bind to the
|
||||
# local filesystem which will need a rebuild anyway
|
||||
|
||||
# Run command
|
||||
# (for development we need to execute yarn install since the
|
||||
# node_modules are on another volume and need updating)
|
||||
CMD /bin/sh -c "yarn install && yarn run dev"
|
||||
|
||||
##################################################################################
|
||||
# CODE (Does contain all code files and is pushed to DockerHub for rebranding) ###
|
||||
##################################################################################
|
||||
FROM base AS code
|
||||
|
||||
# copy everything, but do not build.
|
||||
FROM base AS build
|
||||
COPY . .
|
||||
ONBUILD COPY ./branding/constants/ src/config/tmp
|
||||
# copy categories to brand them (use yarn prod:db:data:categories)
|
||||
ONBUILD COPY ./branding/constants/ src/constants/
|
||||
ONBUILD RUN tools/replace-constants.sh
|
||||
ONBUILD COPY ./branding/email/ src/middleware/helpers/email/
|
||||
ONBUILD COPY ./branding/middlewares/ src/middleware/branding/
|
||||
ONBUILD COPY ./branding/data/ src/db/data
|
||||
ONBUILD COPY ./branding/public/ public/
|
||||
ONBUILD RUN yarn install --production=false --frozen-lockfile --non-interactive
|
||||
ONBUILD RUN yarn run build
|
||||
ONBUILD RUN mkdir /build
|
||||
ONBUILD RUN cp -r ./build /build
|
||||
ONBUILD RUN cp -r ./public /build
|
||||
ONBUILD RUN cp -r ./package.json yarn.lock /build
|
||||
ONBUILD RUN cd /build && yarn install --production=true --frozen-lockfile --non-interactive
|
||||
|
||||
##################################################################################
|
||||
# BUILD (Does contain all files and the compilate and is therefore bloated) ######
|
||||
##################################################################################
|
||||
FROM code AS build
|
||||
|
||||
# yarn install
|
||||
RUN yarn install --production=false --frozen-lockfile --non-interactive
|
||||
# yarn build
|
||||
RUN /bin/sh -c "yarn run build"
|
||||
|
||||
##################################################################################
|
||||
# TEST ###########################################################################
|
||||
##################################################################################
|
||||
FROM build AS test
|
||||
# required for the migrations
|
||||
# ONBUILD RUN cp -r ./src /src
|
||||
CMD ["/bin/bash", "-c", "yarn run dev"]
|
||||
|
||||
# Run command
|
||||
CMD /bin/sh -c "yarn run dev"
|
||||
FROM build AS production_build
|
||||
|
||||
##################################################################################
|
||||
# PRODUCTION (Does contain only "binary"- and static-files to reduce image size) #
|
||||
##################################################################################
|
||||
FROM base AS production
|
||||
|
||||
# Copy "binary"-files from build image
|
||||
COPY --from=build ${DOCKER_WORKDIR}/build ./build
|
||||
COPY --from=build ${DOCKER_WORKDIR}/node_modules ./node_modules
|
||||
# Copy static files
|
||||
# TODO - externalize the uploads so we can copy the whole folder
|
||||
COPY --from=build ${DOCKER_WORKDIR}/public/img/ ./public/img/
|
||||
COPY --from=build ${DOCKER_WORKDIR}/public/providers.json ./public/providers.json
|
||||
# Copy package.json for script definitions (lock file should not be needed)
|
||||
COPY --from=build ${DOCKER_WORKDIR}/package.json ./package.json
|
||||
|
||||
# Run command
|
||||
CMD /bin/sh -c "yarn run start"
|
||||
COPY --from=production_build /build .
|
||||
|
||||
@ -6,12 +6,12 @@ Run the following command to install everything through docker.
|
||||
|
||||
The installation takes a bit longer on the first pass or on rebuild ...
|
||||
|
||||
```bash
|
||||
```sh
|
||||
# in main folder
|
||||
$ docker-compose up
|
||||
$ docker compose up
|
||||
# or
|
||||
# rebuild the containers for a cleanup
|
||||
$ docker-compose up --build
|
||||
$ docker compose up --build
|
||||
```
|
||||
|
||||
Wait a little until your backend is up and running at [http://localhost:4000/](http://localhost:4000/).
|
||||
@ -26,7 +26,7 @@ some known problems with more recent node versions). You can use the
|
||||
[node version manager](https://github.com/nvm-sh/nvm) `nvm` to switch
|
||||
between different local Node versions:
|
||||
|
||||
```bash
|
||||
```sh
|
||||
# install Node
|
||||
$ cd backend
|
||||
$ nvm install v20.12.1
|
||||
@ -35,7 +35,7 @@ $ nvm use v20.12.1
|
||||
|
||||
Install node dependencies with [yarn](https://yarnpkg.com/en/):
|
||||
|
||||
```bash
|
||||
```sh
|
||||
# in main folder
|
||||
$ cd backend
|
||||
$ yarn install
|
||||
@ -47,7 +47,7 @@ $ nvm use && yarn
|
||||
|
||||
Copy Environment Variables:
|
||||
|
||||
```bash
|
||||
```sh
|
||||
# in backend/
|
||||
$ cp .env.template .env
|
||||
```
|
||||
@ -57,14 +57,14 @@ a [local Neo4J](http://localhost:7474) instance is up and running.
|
||||
|
||||
Start the backend for development with:
|
||||
|
||||
```bash
|
||||
```sh
|
||||
# in backend/
|
||||
$ yarn run dev
|
||||
```
|
||||
|
||||
or start the backend in production environment with:
|
||||
|
||||
```bash
|
||||
```sh
|
||||
# in backend/
|
||||
$ yarn run start
|
||||
```
|
||||
@ -79,154 +79,141 @@ More details about our GraphQL playground and how to use it with ocelot.social c
|
||||
|
||||

|
||||
|
||||
### Database Indexes and Constraints
|
||||
## Database
|
||||
|
||||
Database indexes and constraints need to be created and upgraded when the database and the backend are running:
|
||||
A fresh database needs to be initialized and migrated.
|
||||
|
||||
::: tabs
|
||||
@tab:active Docker
|
||||
|
||||
```bash
|
||||
# in main folder while docker-compose is running
|
||||
$ docker exec backend yarn run db:migrate init
|
||||
|
||||
# only once: init admin user and create indexes and constraints in Neo4j database
|
||||
# for development
|
||||
$ docker compose exec backend yarn prod:migrate init
|
||||
# in production mode use command
|
||||
$ docker compose exec backend /bin/sh -c "yarn prod:migrate init"
|
||||
```sh
|
||||
# in folder backend while database is running
|
||||
yarn db:migrate init
|
||||
# for docker environments:
|
||||
docker exec ocelot-social-backend-1 yarn db:migrate init
|
||||
# for docker production:
|
||||
docker exec ocelot-social-backend-1 yarn prod:migrate init
|
||||
```
|
||||
|
||||
```bash
|
||||
# in main folder with docker compose running
|
||||
$ docker exec backend yarn run db:migrate up
|
||||
```sh
|
||||
# in backend with database running (In docker or local)
|
||||
yarn db:migrate up
|
||||
|
||||
# for docker development:
|
||||
docker exec ocelot-social-backend-1 yarn db:migrate up
|
||||
# for docker production
|
||||
docker exec ocelot-social-backend-1 yarn prod:migrate up
|
||||
```
|
||||
|
||||
@tab Without Docker
|
||||
### Optional Data
|
||||
|
||||
```bash
|
||||
# in folder backend/ while database is running
|
||||
# make sure your database is running on http://localhost:7474/browser/
|
||||
yarn run db:migrate init
|
||||
You can seed some optional data into the database.
|
||||
|
||||
To create the default admin <admin@example.org> with password `1234` use:
|
||||
|
||||
```sh
|
||||
# in backend with database running (In docker or local)
|
||||
yarn db:data:admin
|
||||
```
|
||||
|
||||
```bash
|
||||
# in backend/ with database running (In docker or local)
|
||||
yarn run db:migrate up
|
||||
When using `CATEGORIES_ACTIVE=true` you also want to seed the categories with:
|
||||
|
||||
```sh
|
||||
# in backend with database running (In docker or local)
|
||||
yarn db:data:categories
|
||||
```
|
||||
|
||||
:::
|
||||
### Branding Data
|
||||
|
||||
#### Seed Database
|
||||
You might need to seed some branding specific data into the database.
|
||||
|
||||
If you want your backend to return anything else than an empty response, you
|
||||
need to seed your database:
|
||||
To do so, run:
|
||||
|
||||
::: tabs
|
||||
@tab:active Docker
|
||||
```sh
|
||||
# in backend with database running (In docker or local)
|
||||
yarn db:data:branding
|
||||
|
||||
In another terminal run:
|
||||
|
||||
```bash
|
||||
# in main folder while docker-compose is running
|
||||
$ docker exec backend yarn run db:seed
|
||||
# for docker
|
||||
docker exec ocelot-social-backend-1 yarn db:data:branding
|
||||
```
|
||||
|
||||
To reset the database run:
|
||||
### Seed Data
|
||||
|
||||
```bash
|
||||
# in main folder while docker-compose is running
|
||||
$ docker exec backend yarn run db:reset
|
||||
For a predefined set of test data you can seed the database with:
|
||||
|
||||
```sh
|
||||
# in backend with database running (In docker or local)
|
||||
yarn db:seed
|
||||
|
||||
# for docker
|
||||
docker exec ocelot-social-backend-1 yarn db:seed
|
||||
```
|
||||
|
||||
### Reset Data
|
||||
|
||||
In order to reset the database you can run:
|
||||
|
||||
```sh
|
||||
# in backend with database running (In docker or local)
|
||||
yarn db:reset
|
||||
# or deleting the migrations as well
|
||||
yarn db:reset:withmigrations
|
||||
|
||||
# for docker
|
||||
docker exec ocelot-social-backend-1 yarn db:reset
|
||||
# or deleting the migrations as well
|
||||
docker exec ocelot-social-backend-1 yarn db:reset:withmigrations
|
||||
# you could also wipe out your neo4j database and delete all volumes with:
|
||||
$ docker-compose down -v
|
||||
# if container is not running, run this command to set up your database indexes and constraints
|
||||
$ docker exec backend yarn run db:migrate init
|
||||
# And then upgrade the indexes and const
|
||||
$ docker exec backend yarn run db:migrate up
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
@tab Without Docker
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
# in backend/ while database is running
|
||||
$ yarn run db:seed
|
||||
```
|
||||
|
||||
To reset the database run:
|
||||
|
||||
```bash
|
||||
# in backend/ while database is running
|
||||
$ yarn run db:reset
|
||||
```
|
||||
|
||||
:::
|
||||
> Note: This just deletes the data and not the constraints, hence you do not need to rerun `yarn db:migrate init` or `yarn db:migrate up`.
|
||||
|
||||
### Data migrations
|
||||
|
||||
Although Neo4J is schema-less,you might find yourself in a situation in which
|
||||
you have to migrate your data e.g. because your data modeling has changed.
|
||||
|
||||
::: tabs
|
||||
@tab:active Docker
|
||||
|
||||
Generate a data migration file:
|
||||
|
||||
```bash
|
||||
# in main folder while docker-compose is running
|
||||
$ docker-compose exec backend yarn run db:migrate:create your_data_migration
|
||||
# Edit the file in ./src/db/migrations/
|
||||
```
|
||||
|
||||
To run the migration:
|
||||
|
||||
```bash
|
||||
# in main folder while docker-compose is running
|
||||
$ docker exec backend yarn run db:migrate up
|
||||
```
|
||||
|
||||
@tab Without Docker
|
||||
|
||||
Generate a data migration file:
|
||||
|
||||
```bash
|
||||
# in backend/
|
||||
```sh
|
||||
# in backend
|
||||
$ yarn run db:migrate:create your_data_migration
|
||||
# Edit the file in ./src/db/migrations/
|
||||
|
||||
# for docker
|
||||
# in main folder while docker compose is running
|
||||
$ docker compose exec ocelot-social-backend-1 yarn run db:migrate:create your_data_migration
|
||||
# Edit the file in ./src/db/migrations/
|
||||
```
|
||||
|
||||
To run the migration:
|
||||
|
||||
```bash
|
||||
```sh
|
||||
# in backend/ while database is running
|
||||
$ yarn run db:migrate up
|
||||
```
|
||||
|
||||
:::
|
||||
# for docker
|
||||
# in main folder while docker compose is running
|
||||
$ docker exec backend yarn run db:migrate up
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
**Beware**: We have no multiple database setup at the moment. We clean the
|
||||
database after each test, running the tests will wipe out all your data!
|
||||
|
||||
::: tabs
|
||||
@tab:active Docker
|
||||
|
||||
Run the unit tests:
|
||||
|
||||
```bash
|
||||
# in main folder while docker-compose is running
|
||||
$ docker exec backend yarn run test
|
||||
```
|
||||
|
||||
@tab Without Docker
|
||||
|
||||
Run the unit tests:
|
||||
|
||||
```bash
|
||||
```sh
|
||||
# in backend/ while database is running
|
||||
$ yarn run test
|
||||
|
||||
# for docker
|
||||
# in main folder while docker compose is running
|
||||
$ docker exec ocelot-social-backend-1 yarn run test
|
||||
```
|
||||
|
||||
:::
|
||||
If the snapshots of the emails must be updated, you have to run the tests in docker! Otherwise the CI will fail.
|
||||
|
||||
```sh
|
||||
# in main folder while docker compose is running
|
||||
$ docker exec ocelot-social-backend-1 yarn run test -u src/emails/
|
||||
```
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"node": "10"
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-throw-expressions"
|
||||
]
|
||||
}
|
||||
27
backend/jest.config.cjs
Normal file
@ -0,0 +1,27 @@
|
||||
/* eslint-disable import/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: 90,
|
||||
},
|
||||
},
|
||||
testMatch: ['**/src/**/?(*.)+(spec|test).ts?(x)'],
|
||||
setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],
|
||||
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/' }),
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
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: 90,
|
||||
},
|
||||
},
|
||||
testMatch: ['**/src/**/?(*.)+(spec|test).ts?(x)'],
|
||||
setupFilesAfterEnv: ['<rootDir>/test/setup.ts']
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ocelot-social-backend",
|
||||
"version": "3.2.0",
|
||||
"version": "3.6.1",
|
||||
"description": "GraphQL Backend for ocelot.social",
|
||||
"repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social",
|
||||
"author": "ocelot.social Community",
|
||||
@ -8,120 +8,132 @@
|
||||
"private": false,
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"__migrate": "migrate --compiler 'ts:./src/db/compiler.ts' --migrations-dir ./src/db/migrations",
|
||||
"prod:migrate": "migrate --migrations-dir ./build/src/db/migrations --store ./build/src/db/migrate/store.js",
|
||||
"start": "node build/src/",
|
||||
"build": "tsc && ./scripts/build.copy.files.sh",
|
||||
"dev": "nodemon --exec ts-node src/ -e js,ts,gql",
|
||||
"dev:debug": "nodemon --exec babel-node --inspect=0.0.0.0:9229 src/ -e js,ts,gql",
|
||||
"lint": "eslint --max-warnings=0 --ext .js,.ts ./src",
|
||||
"build": "tsc && tsc-alias && ./scripts/build.copy.files.sh",
|
||||
"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",
|
||||
"lint": "eslint --max-warnings=0 --report-unused-disable-directives --ext .js,.ts,.cjs,.json,.json5,.jsonc .",
|
||||
"test": "cross-env NODE_ENV=test NODE_OPTIONS=--max-old-space-size=8192 jest --runInBand --coverage --forceExit --detectOpenHandles",
|
||||
"db:clean": "ts-node src/db/clean.ts",
|
||||
"db:reset": "yarn run db:clean",
|
||||
"db:seed": "ts-node src/db/seed.ts",
|
||||
"db:migrate": "yarn run __migrate --store ./src/db/migrate/store.ts",
|
||||
"db:migrate:create": "yarn run __migrate --template-file ./src/db/migrate/template.ts --date-format 'yyyymmddHHmmss' create"
|
||||
"db:reset": "ts-node --require tsconfig-paths/register src/db/reset.ts",
|
||||
"db:reset:withmigrations": "ts-node --require tsconfig-paths/register src/db/reset-with-migrations.ts",
|
||||
"db:seed": "ts-node --require tsconfig-paths/register src/db/seed.ts",
|
||||
"db:data:admin": "ts-node --require tsconfig-paths/register src/db/admin.ts",
|
||||
"db:data:badges": "ts-node --require tsconfig-paths/register src/db/badges.ts",
|
||||
"db:data:branding": "ts-node --require tsconfig-paths/register src/db/data-branding.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:create": "migrate --compiler 'ts:./src/db/compiler.ts' --migrations-dir ./src/db/migrations --template-file ./src/db/migrate/template.ts --date-format 'yyyymmddHHmmss' create",
|
||||
"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:categories": "node build/src/db/categories.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/cli": "~7.26.4",
|
||||
"@babel/core": "^7.26.0",
|
||||
"@babel/node": "~7.26.0",
|
||||
"@babel/plugin-proposal-throw-expressions": "^7.25.9",
|
||||
"@babel/preset-env": "~7.26.0",
|
||||
"@babel/register": "^7.23.7",
|
||||
"@aws-sdk/client-s3": "^3.817.0",
|
||||
"@aws-sdk/lib-storage": "^3.797.0",
|
||||
"@sentry/node": "^5.15.4",
|
||||
"apollo-cache-inmemory": "~1.6.6",
|
||||
"apollo-client": "~2.6.10",
|
||||
"apollo-link-context": "~1.0.20",
|
||||
"apollo-link-http": "~1.5.17",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"apollo-server": "~2.14.2",
|
||||
"apollo-server-express": "^2.14.2",
|
||||
"aws-sdk": "^2.1692.0",
|
||||
"babel-core": "~7.0.0-0",
|
||||
"babel-eslint": "~10.1.0",
|
||||
"babel-jest": "~29.7.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"bcryptjs": "~2.4.3",
|
||||
"bcryptjs": "~3.0.2",
|
||||
"body-parser": "^1.20.3",
|
||||
"cheerio": "~1.0.0",
|
||||
"cors": "~2.8.5",
|
||||
"cross-env": "~7.0.3",
|
||||
"dotenv": "~16.4.7",
|
||||
"express": "^4.21.2",
|
||||
"dotenv": "~16.5.0",
|
||||
"email-templates": "^12.0.2",
|
||||
"express": "^5.1.0",
|
||||
"graphql": "^14.6.0",
|
||||
"graphql-middleware": "~4.0.2",
|
||||
"graphql-middleware-sentry": "^3.2.1",
|
||||
"graphql-redis-subscriptions": "^2.7.0",
|
||||
"graphql-shield": "~7.2.2",
|
||||
"graphql-subscriptions": "^1.1.0",
|
||||
"graphql-tag": "~2.10.3",
|
||||
"helmet": "~8.0.0",
|
||||
"ioredis": "^4.16.1",
|
||||
"graphql-upload": "^13.0.0",
|
||||
"helmet": "~8.1.0",
|
||||
"ioredis": "^5.6.1",
|
||||
"jsonwebtoken": "~8.5.1",
|
||||
"languagedetect": "^2.0.0",
|
||||
"linkify-html": "^4.3.1",
|
||||
"linkifyjs": "^4.2.0",
|
||||
"linkify-html": "^4.2.0",
|
||||
"lodash": "~4.17.21",
|
||||
"merge-graphql-schemas": "^1.7.8",
|
||||
"metascraper": "^5.33.5",
|
||||
"metascraper-author": "^5.33.5",
|
||||
"metascraper-date": "^5.33.5",
|
||||
"metascraper-description": "^5.33.5",
|
||||
"metascraper-image": "^5.33.5",
|
||||
"metascraper-lang": "^5.33.5",
|
||||
"metascraper": "^5.46.11",
|
||||
"metascraper-author": "^5.46.11",
|
||||
"metascraper-date": "^5.46.11",
|
||||
"metascraper-description": "^5.46.11",
|
||||
"metascraper-image": "^5.46.11",
|
||||
"metascraper-lang": "^5.46.11",
|
||||
"metascraper-lang-detector": "^4.10.2",
|
||||
"metascraper-logo": "^5.33.5",
|
||||
"metascraper-publisher": "^5.33.5",
|
||||
"metascraper-logo": "^5.46.11",
|
||||
"metascraper-publisher": "^5.46.11",
|
||||
"metascraper-soundcloud": "^5.34.4",
|
||||
"metascraper-title": "^5.34.7",
|
||||
"metascraper-url": "^5.34.2",
|
||||
"metascraper-video": "^5.33.5",
|
||||
"metascraper-youtube": "^5.33.5",
|
||||
"metascraper-title": "^5.46.11",
|
||||
"metascraper-url": "^5.46.11",
|
||||
"metascraper-video": "^5.46.11",
|
||||
"metascraper-youtube": "^5.46.11",
|
||||
"migrate": "^2.1.0",
|
||||
"mime-types": "^2.1.35",
|
||||
"mime-types": "^3.0.1",
|
||||
"minimatch": "^9.0.4",
|
||||
"mustache": "^4.2.0",
|
||||
"neo4j-driver": "^4.4.11",
|
||||
"neo4j-graphql-js": "^2.11.5",
|
||||
"neode": "^0.4.9",
|
||||
"node-fetch": "^2.7.0",
|
||||
"nodemailer": "^6.9.16",
|
||||
"nodemailer": "^6.10.1",
|
||||
"nodemailer-html-to-text": "^3.2.0",
|
||||
"preview-email": "^3.1.0",
|
||||
"pug": "^3.0.3",
|
||||
"request": "~2.88.2",
|
||||
"sanitize-html": "~2.14.0",
|
||||
"sanitize-html": "~2.17.0",
|
||||
"slug": "~9.1.0",
|
||||
"subscriptions-transport-ws": "^0.9.19",
|
||||
"trunc-html": "~1.1.2",
|
||||
"uuid": "~9.0.1",
|
||||
"validator": "^13.12.0",
|
||||
"xregexp": "^4.3.0"
|
||||
"validator": "^13.15.0",
|
||||
"xregexp": "^5.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "9.3.0",
|
||||
"@eslint-community/eslint-plugin-eslint-comments": "^4.5.0",
|
||||
"@faker-js/faker": "9.8.0",
|
||||
"@types/email-templates": "^10.0.4",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^22.10.2",
|
||||
"@types/lodash": "^4.17.17",
|
||||
"@types/node": "^22.15.21",
|
||||
"@types/slug": "^5.0.9",
|
||||
"@types/uuid": "~9.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"apollo-server-testing": "~2.11.0",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-config-standard": "^17.1.0",
|
||||
"eslint-import-resolver-typescript": "^3.7.0",
|
||||
"eslint-import-resolver-typescript": "^4.3.4",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-jest": "^28.10.0",
|
||||
"eslint-plugin-n": "^16.6.2",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-jest": "^28.11.0",
|
||||
"eslint-plugin-jsonc": "^2.20.1",
|
||||
"eslint-plugin-n": "^17.17.0",
|
||||
"eslint-plugin-no-catch-all": "^1.1.0",
|
||||
"eslint-plugin-prettier": "^5.4.0",
|
||||
"eslint-plugin-promise": "^7.2.1",
|
||||
"eslint-plugin-security": "^3.0.1",
|
||||
"jest": "^29.7.0",
|
||||
"nodemon": "~3.1.9",
|
||||
"prettier": "^3.4.2",
|
||||
"nodemon": "~3.1.10",
|
||||
"prettier": "^3.5.3",
|
||||
"require-json5": "^1.3.0",
|
||||
"rosie": "^2.1.1",
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-jest": "^29.3.4",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.7.2"
|
||||
"tsc-alias": "^1.8.16",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"**/**/fs-capacitor": "^6.2.0",
|
||||
"**/graphql-upload": "^11.0.0",
|
||||
"nan": "2.17.0"
|
||||
"**/strip-ansi": "6.0.1",
|
||||
"**/string-width": "4.2.0",
|
||||
"**/wrap-ansi": "7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.12.1"
|
||||
}
|
||||
}
|
||||
|
||||
12
backend/public/img/badges/default_trophy.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="400" height="346.67" version="1.1" viewBox="0 0 400 346.67" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<linearGradient id="linearGradient4" x1="708.76" x2="493.17" y1="280.91" y2="65.326" gradientTransform="translate(-404.06 .215)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#c1c1c1" offset="0"/>
|
||||
<stop stop-color="#fcfcfc" offset="1"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path d="m-0.21505 173.98 100.65-173.76h198.71l101.08 173.76-99.785 172.04-201.29 0.43011z" fill="#bebebe"/>
|
||||
<path d="m22.482 173.91 89.236-154.07h176.18l89.617 154.07-88.473 152.54-178.47 0.38135z" fill="url(#linearGradient4)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 773 B |
29
backend/public/img/badges/default_verification.svg
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="513"
|
||||
height="444"
|
||||
version="1.1"
|
||||
id="svg3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs3" />
|
||||
<g
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
id="g3">
|
||||
<path
|
||||
fill="#333"
|
||||
d="M384.5.297L512.325 221.9l-128 221.702-255.825.102L.675 222.1 128.675.4z"
|
||||
id="path1"
|
||||
style="fill:#868383;fill-opacity:1" />
|
||||
<g
|
||||
fill="#ffffff"
|
||||
id="g2"
|
||||
transform="translate(92)">
|
||||
<path
|
||||
d="m 35.01,367.726 c -0.08,-21.169 -0.205,-53.162 21.257,-71.332 3.817,-3.253 9.93,-7.497 17.321,-9.224 2.575,-0.523 4.956,-0.756 7.262,-0.979 4.438,-0.431 8.27,-0.804 12.054,-2.9 l 4.954,-2.846 c 9.87,-5.655 19.194,-10.996 28.226,-17.377 5.085,-3.632 6.726,-15.73 6.095,-25.428 -0.214,-2.792 -1.893,-5.7 -3.67,-8.777 -1.097,-1.901 -2.232,-3.867 -3.065,-5.916 l -0.073,-0.199 a 56.976,56.976 0 0 1 -0.422,-1.443 c -1.195,-4.205 -1.933,-6.378 -2.386,-7.476 -7.029,-0.944 -11.8,-8.647 -12.888,-21.006 l -0.031,-0.557 c -0.645,-12.785 0.808,-16.13 2.316,-17.716 0.24,-0.254 0.505,-0.475 0.783,-0.666 -1.754,-16.051 3.115,-32.521 13.358,-44.704 9.314,-11.079 21.955,-17.18 35.592,-17.18 3.73,0 7.55,0.458 11.355,1.362 25.63,6.228 41.679,30.27 40.062,59.227 0.53,0.251 1.018,0.61 1.44,1.066 2.752,2.964 2.47,10.97 2.22,14.276 l -0.024,0.41 c -0.335,5.236 -0.684,10.65 -3.052,15.73 -1.739,3.918 -4.405,6.242 -6.76,8.29 -2.396,2.089 -4.288,3.735 -5.294,6.885 -0.7,2.416 -1.645,4.866 -2.559,7.235 -1.752,4.538 -3.407,8.827 -3.54,13.244 -0.427,10.222 1.17,18.391 4.172,21.359 5.097,5.163 13.003,9.391 19.978,13.121 1.6,0.855 3.166,1.692 4.654,2.517 9.28,5.052 16.07,7.915 25.309,8.557 9.118,0.849 18.056,5.193 24.754,11.97 0.736,0.641 1.82,1.744 3.694,3.648 4.416,4.492 4.416,4.492 4.426,5.852 l 0.007,0.758 c 10.783,17.702 11.14,40.656 11.415,58.169 l 0.05,3.28 -3.278,0.028 c -42.05,0.363 -84.058,0.677 -126.058,0.993 -42.12,0.314 -84.232,0.632 -126.367,0.994 L 35.024,371 Z"
|
||||
id="path2" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 637 B After Width: | Height: | Size: 637 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 654 B After Width: | Height: | Size: 654 B |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
@ -1 +0,0 @@
|
||||
<svg width="513" height="444" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="#AD245D" d="M384.5.297L512.325 221.9l-128 221.702-255.825.102L.675 222.1 128.675.4z"/><path d="M35.01 367.726c-.08-21.169-.205-53.162 21.257-71.332 3.817-3.253 9.93-7.497 17.321-9.224 2.575-.523 4.956-.756 7.262-.979 4.438-.431 8.27-.804 12.054-2.9l4.954-2.846c9.87-5.655 19.194-10.996 28.226-17.377 5.085-3.632 6.726-15.73 6.095-25.428-.214-2.792-1.893-5.7-3.67-8.777-1.097-1.901-2.232-3.867-3.065-5.916l-.073-.199a56.976 56.976 0 0 1-.422-1.443c-1.195-4.205-1.933-6.378-2.386-7.476-7.029-.944-11.8-8.647-12.888-21.006l-.031-.557c-.645-12.785.808-16.13 2.316-17.716.24-.254.505-.475.783-.666-1.754-16.051 3.115-32.521 13.358-44.704 9.314-11.079 21.955-17.18 35.592-17.18 3.73 0 7.55.458 11.355 1.362 25.63 6.228 41.679 30.27 40.062 59.227.53.251 1.018.61 1.44 1.066 2.752 2.964 2.47 10.97 2.22 14.276l-.024.41c-.335 5.236-.684 10.65-3.052 15.73-1.739 3.918-4.405 6.242-6.76 8.29-2.396 2.089-4.288 3.735-5.294 6.885-.7 2.416-1.645 4.866-2.559 7.235-1.752 4.538-3.407 8.827-3.54 13.244-.427 10.222 1.17 18.391 4.172 21.359 5.097 5.163 13.003 9.391 19.978 13.121 1.6.855 3.166 1.692 4.654 2.517 9.28 5.052 16.07 7.915 25.309 8.557 9.118.849 18.056 5.193 24.754 11.97.736.641 1.82 1.744 3.694 3.648 4.416 4.492 4.416 4.492 4.426 5.852l.007.758c10.783 17.702 11.14 40.656 11.415 58.169l.05 3.28-3.278.028c-42.05.363-84.058.677-126.058.993-42.12.314-84.232.632-126.367.994l-3.273.029-.014-3.274zM329.011 135.763a5.232 5.232 0 0 0-5.223 5.23 5.232 5.232 0 0 0 5.223 5.23 5.236 5.236 0 0 0 5.231-5.23 5.236 5.236 0 0 0-5.23-5.23m0 40.237C309.705 176 294 160.297 294 140.993 294 121.698 309.706 106 329.011 106 348.303 106 364 121.698 364 140.993 364 160.297 348.303 176 329.011 176" fill="#FFF"/><path d="M330.511 101C308.173 101 290 119.164 290 141.492 290 163.828 308.173 182 330.511 182 352.836 182 371 163.828 371 141.492 371 119.164 352.836 101 330.511 101m0 51.022c5.823 0 10.531-4.716 10.531-10.53a10.517 10.517 0 0 0-10.53-10.529 10.51 10.51 0 0 0-10.523 10.529c0 5.814 4.7 10.53 10.522 10.53m0-40.496c16.563 0 29.963 13.406 29.963 29.966 0 16.555-13.4 29.982-29.963 29.982-16.555 0-29.985-13.427-29.985-29.982 0-16.56 13.43-29.966 29.985-29.966" fill="#AD245D"/><path d="M331 106.209c-20.305 0-36.825 16.06-36.825 35.799 0 19.747 16.52 35.813 36.825 35.813 20.306 0 36.827-16.066 36.827-35.813 0-19.74-16.521-35.8-36.827-35.8zM314.287 215l-4.11-21.345c-.324-.129-.648-.265-.972-.404l-18.012 12.169-23.607-23.609 12.186-18.009a63.31 63.31 0 0 1-.403-.968L258 158.712v-33.383l21.361-4.13c.131-.327.267-.652.407-.979l-12.18-18.025 23.608-23.612 18.015 12.198c.322-.137.643-.27.964-.4L314.287 69h33.416l4.13 21.387c.319.13.638.26.956.396l18.024-12.2 23.608 23.612-12.186 18.031c.139.324.273.648.402.971L404 125.33v33.381l-21.37 4.124c-.13.32-.262.64-.398.96l12.19 18.017-23.606 23.609-18.021-12.171c-.32.137-.642.27-.964.402L347.701 215h-33.414z" fill="#FFF"/><path d="M330 171.448c-17.342 0-31.45-13.656-31.45-30.44 0-16.778 14.108-30.427 31.45-30.427 17.341 0 31.449 13.649 31.449 30.426 0 16.785-14.108 30.441-31.45 30.441zM350.979 63h-41.97l-1.64 8.517-1.953 10.156-8.55-5.788-7.18-4.862-6.132 6.132-17.399 17.4-6.126 6.126 4.85 7.178 5.8 8.583-10.173 1.966-8.506 1.646v41.932l8.51 1.643 10.16 1.962-5.787 8.553-4.858 7.179 6.13 6.13 17.399 17.399 6.126 6.126 7.177-4.85 8.56-5.782 1.954 10.141 1.64 8.513H350.975l1.645-8.507 1.964-10.15 8.566 5.787 7.178 4.846 6.124-6.124 17.4-17.399 6.13-6.13-4.858-7.18-5.788-8.554 10.153-1.96 8.51-1.643v-41.932l-8.507-1.646-10.165-1.965 5.8-8.584 4.85-7.178-6.125-6.126-17.4-17.4-6.13-6.13-7.18 4.858-8.558 5.792-1.964-10.166L350.98 63zm-20.98 118.948c23.176 0 41.95-18.318 41.95-40.94 0-22.607-18.774-40.927-41.95-40.927-23.174 0-41.948 18.32-41.948 40.926 0 22.623 18.774 40.941 41.949 40.941zM342.313 73.5l3.855 19.963a47.184 47.184 0 0 1 6.037 2.502l16.824-11.386 17.4 17.4-11.362 16.818a53.171 53.171 0 0 1 2.502 6.066l19.932 3.855v24.601l-19.932 3.848a56.644 56.644 0 0 1-2.502 6.066l11.362 16.795-17.4 17.4-16.824-11.364a44.931 44.931 0 0 1-6.037 2.504l-3.855 19.932H317.68l-3.84-19.932a43.821 43.821 0 0 1-6.043-2.504l-16.818 11.364-17.4-17.4 11.364-16.795a53.759 53.759 0 0 1-2.51-6.066l-19.933-3.848v-24.601l19.933-3.855a50.617 50.617 0 0 1 2.51-6.066l-11.364-16.818 17.4-17.4 16.818 11.386a45.957 45.957 0 0 1 6.043-2.502l3.84-19.963h24.632z" fill="#AD245D"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 4.3 KiB |
@ -1 +0,0 @@
|
||||
<svg width="513" height="444" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="#AD245D" d="M384.5.297L512.325 221.9l-128 221.702-255.825.102L.675 222.1 128.675.4z"/><g fill="#FFF"><path d="M35.01 367.726c-.08-21.169-.205-53.162 21.257-71.332 3.817-3.253 9.93-7.497 17.321-9.224 2.575-.523 4.956-.756 7.262-.979 4.438-.431 8.27-.804 12.054-2.9l4.954-2.846c9.87-5.655 19.194-10.996 28.226-17.377 5.085-3.632 6.726-15.73 6.095-25.428-.214-2.792-1.893-5.7-3.67-8.777-1.097-1.901-2.232-3.867-3.065-5.916l-.073-.199a56.976 56.976 0 0 1-.422-1.443c-1.195-4.205-1.933-6.378-2.386-7.476-7.029-.944-11.8-8.647-12.888-21.006l-.031-.557c-.645-12.785.808-16.13 2.316-17.716.24-.254.505-.475.783-.666-1.754-16.051 3.115-32.521 13.358-44.704 9.314-11.079 21.955-17.18 35.592-17.18 3.73 0 7.55.458 11.355 1.362 25.63 6.228 41.679 30.27 40.062 59.227.53.251 1.018.61 1.44 1.066 2.752 2.964 2.47 10.97 2.22 14.276l-.024.41c-.335 5.236-.684 10.65-3.052 15.73-1.739 3.918-4.405 6.242-6.76 8.29-2.396 2.089-4.288 3.735-5.294 6.885-.7 2.416-1.645 4.866-2.559 7.235-1.752 4.538-3.407 8.827-3.54 13.244-.427 10.222 1.17 18.391 4.172 21.359 5.097 5.163 13.003 9.391 19.978 13.121 1.6.855 3.166 1.692 4.654 2.517 9.28 5.052 16.07 7.915 25.309 8.557 9.118.849 18.056 5.193 24.754 11.97.736.641 1.82 1.744 3.694 3.648 4.416 4.492 4.416 4.492 4.426 5.852l.007.758c10.783 17.702 11.14 40.656 11.415 58.169l.05 3.28-3.278.028c-42.05.363-84.058.677-126.058.993-42.12.314-84.232.632-126.367.994l-3.273.029-.014-3.274z"/><text font-family="Impact" font-size="118" font-style="condensed" font-weight="700" transform="translate(1 -1)"><tspan x="256" y="208"></></tspan></text></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@ -1 +0,0 @@
|
||||
<svg width="512" height="444" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="#AD245D" d="M384 .297L511.392 221.65l-128 221.702-255.392.352L.608 222.35 128.608.65z"/><g fill="#FFF"><path d="M34.944 367.726c-.081-21.169-.205-53.162 21.215-71.332 3.81-3.253 9.91-7.497 17.288-9.224 2.57-.523 4.946-.756 7.247-.979 4.43-.431 8.254-.804 12.03-2.9l4.945-2.846c9.851-5.655 19.157-10.996 28.171-17.377 5.075-3.632 6.713-15.73 6.082-25.428-.213-2.792-1.888-5.7-3.662-8.777-1.095-1.901-2.228-3.867-3.059-5.916l-.073-.199a57.061 57.061 0 0 1-.42-1.443c-1.194-4.205-1.93-6.378-2.382-7.476-7.015-.944-11.778-8.647-12.864-21.006l-.03-.557c-.644-12.785.806-16.13 2.31-17.716.241-.254.505-.475.783-.666-1.75-16.051 3.11-32.521 13.331-44.704 9.296-11.079 21.912-17.18 35.524-17.18 3.722 0 7.535.458 11.332 1.362 25.58 6.228 41.597 30.27 39.983 59.227.53.251 1.016.61 1.439 1.066 2.745 2.964 2.464 10.97 2.215 14.276l-.024.41c-.335 5.236-.683 10.65-3.046 15.73-1.736 3.918-4.397 6.242-6.747 8.29-2.391 2.089-4.28 3.735-5.284 6.885-.698 2.416-1.642 4.866-2.554 7.235-1.749 4.538-3.4 8.827-3.534 13.244-.425 10.222 1.17 18.391 4.165 21.359 5.087 5.163 12.977 9.391 19.939 13.121 1.597.855 3.16 1.692 4.645 2.517 9.262 5.052 16.038 7.915 25.259 8.557 9.1.849 18.02 5.193 24.706 11.97.735.641 1.817 1.744 3.687 3.648 4.408 4.492 4.408 4.492 4.417 5.852l.007.758c10.762 17.702 11.12 40.656 11.392 58.169l.05 3.28-3.271.028c-41.968.363-83.894.677-125.812.993-42.038.314-84.067.632-126.12.994l-3.267.029-.013-3.274zM332.387 115.763h15.318v86.734h-15.318v.513l-22.127-17.64v.12h-10.21V211h-22.128v-25.51h-20.424v-52.722h52.762v-.508l22.127-17.065v.568zm34.313 72.093l-7.988-4.591c15.803-27.453 1.717-46.642 1.106-47.443l7.304-5.607c.774.993 18.547 24.675-.422 57.641zm27.361 21.216l-13.866-7.975c27.437-47.66 2.98-80.973 1.918-82.36L394.795 109c1.343 1.723 32.2 42.839-.734 100.072z"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
45
backend/public/img/badges/verification_red_admin.svg
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="513"
|
||||
height="444"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs5" />
|
||||
<g
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
id="g5">
|
||||
<path
|
||||
fill="#ad245d"
|
||||
d="M 384.5,0.297 512.325,221.9 384.325,443.602 128.5,443.704 0.675,222.1 128.675,0.4 Z"
|
||||
id="path1"
|
||||
style="display:inline;fill:#e67919;fill-opacity:1" />
|
||||
<path
|
||||
d="m 83.051688,348.226 c -0.08,-21.169 -0.205,-53.162 21.257002,-71.332 3.817,-3.253 9.93,-7.497 17.321,-9.224 2.575,-0.523 4.956,-0.756 7.262,-0.979 4.438,-0.431 8.27,-0.804 12.054,-2.9 l 4.954,-2.846 c 9.87,-5.655 19.194,-10.996 28.226,-17.377 5.085,-3.632 6.726,-15.73 6.095,-25.428 -0.214,-2.792 -1.893,-5.7 -3.67,-8.777 -1.097,-1.901 -2.232,-3.867 -3.065,-5.916 l -0.073,-0.199 a 56.976,56.976 0 0 1 -0.422,-1.443 c -1.195,-4.205 -1.933,-6.378 -2.386,-7.476 -7.029,-0.944 -11.8,-8.647 -12.888,-21.006 l -0.031,-0.557 c -0.645,-12.785 0.808,-16.13 2.316,-17.716 0.24,-0.254 0.505,-0.475 0.783,-0.666 -1.754,-16.051 3.115,-32.521 13.358,-44.704 9.314,-11.079 21.955,-17.18 35.592,-17.18 3.73,0 7.55,0.458 11.355,1.362 25.63,6.228 41.679,30.27 40.062,59.227 0.53,0.251 1.018,0.61 1.44,1.066 2.752,2.964 2.47,10.97 2.22,14.276 l -0.024,0.41 c -0.335,5.236 -0.684,10.65 -3.052,15.73 -1.739,3.918 -4.405,6.242 -6.76,8.29 -2.396,2.089 -4.288,3.735 -5.294,6.885 -0.7,2.416 -1.645,4.866 -2.559,7.235 -1.752,4.538 -3.407,8.827 -3.54,13.244 -0.427,10.222 1.17,18.391 4.172,21.359 5.097,5.163 13.003,9.391 19.978,13.121 1.6,0.855 3.166,1.692 4.654,2.517 9.28,5.052 16.07,7.915 25.309,8.557 9.118,0.849 18.056,5.193 24.754,11.97 0.736,0.641 1.82,1.744 3.694,3.648 4.416,4.492 4.416,4.492 4.426,5.852 l 0.007,0.758 c 10.783,17.702 11.14,40.656 11.415,58.169 l 0.05,3.28 -3.278,0.028 c -42.05,0.363 -84.058,0.677 -126.058,0.993 -42.12,0.314 -84.232,0.632 -126.367002,0.994 l -3.273,0.029 z"
|
||||
id="path2-5"
|
||||
style="display:inline;fill:#ffffff" />
|
||||
<path
|
||||
d="m 351.97006,182.43811 c -2.88526,0.005 -5.2219,2.34474 -5.223,5.23 0.001,2.88526 2.33774,5.22504 5.223,5.23 2.88747,-0.003 5.22769,-2.34253 5.231,-5.23 -0.003,-2.88708 -2.34292,-5.22669 -5.23,-5.23 m 0,40.237 c -19.307,0 -35.012,-15.703 -35.012,-35.007 0,-19.295 15.706,-34.993 35.011,-34.993 19.292,0 34.989,15.698 34.989,34.993 0,19.304 -15.697,35.007 -34.989,35.007"
|
||||
fill="#ffffff"
|
||||
id="path2"
|
||||
style="display:inline" />
|
||||
<path
|
||||
d="m 351.97006,147.67511 c -22.338,0 -40.511,18.164 -40.511,40.492 0,22.336 18.173,40.508 40.511,40.508 22.325,0 40.489,-18.172 40.489,-40.508 0,-22.328 -18.164,-40.492 -40.489,-40.492 m 0,51.022 c 5.823,0 10.531,-4.716 10.531,-10.53 a 10.517,10.517 0 0 0 -10.53,-10.529 10.51,10.51 0 0 0 -10.523,10.529 c 0,5.814 4.7,10.53 10.522,10.53 m 0,-40.496 c 16.563,0 29.963,13.406 29.963,29.966 0,16.555 -13.4,29.982 -29.963,29.982 -16.555,0 -29.985,-13.427 -29.985,-29.982 0,-16.56 13.43,-29.966 29.985,-29.966"
|
||||
fill="#ad245d"
|
||||
id="path3"
|
||||
style="display:inline;fill:#e67919;fill-opacity:1" />
|
||||
<path
|
||||
d="m 351.95906,152.88411 c -20.305,0 -36.825,16.06 -36.825,35.799 0,19.747 16.52,35.813 36.825,35.813 20.306,0 36.827,-16.066 36.827,-35.813 0,-19.74 -16.521,-35.8 -36.827,-35.8 z m -16.713,108.791 -4.11,-21.345 c -0.324,-0.129 -0.648,-0.265 -0.972,-0.404 l -18.012,12.169 -23.607,-23.609 12.186,-18.009 a 63.31,63.31 0 0 1 -0.403,-0.968 l -21.369,-4.122 v -33.383 l 21.361,-4.13 c 0.131,-0.327 0.267,-0.652 0.407,-0.979 l -12.18,-18.025 23.608,-23.612 18.015,12.198 c 0.322,-0.137 0.643,-0.27 0.964,-0.4 l 4.112,-21.381 h 33.416 l 4.13,21.387 c 0.319,0.13 0.638,0.26 0.956,0.396 l 18.024,-12.2 23.608,23.612 -12.186,18.031 c 0.139,0.324 0.273,0.648 0.402,0.971 l 21.363,4.133 v 33.381 l -21.37,4.124 c -0.13,0.32 -0.262,0.64 -0.398,0.96 l 12.19,18.017 -23.606,23.609 -18.021,-12.171 c -0.32,0.137 -0.642,0.27 -0.964,0.402 l -4.13,21.348 z"
|
||||
fill="#ffffff"
|
||||
id="path4"
|
||||
style="display:inline" />
|
||||
<path
|
||||
d="m 351.95956,218.12311 c -17.342,0 -31.45,-13.656 -31.45,-30.44 0,-16.778 14.108,-30.427 31.45,-30.427 17.341,0 31.449,13.649 31.449,30.426 0,16.785 -14.108,30.441 -31.45,30.441 z m 20.979,-108.448 h -41.97 l -1.64,8.517 -1.953,10.156 -8.55,-5.788 -7.18,-4.862 -6.132,6.132 -17.399,17.4 -6.126,6.126 4.85,7.178 5.8,8.583 -10.173,1.966 -8.506,1.646 v 41.932 l 8.51,1.643 10.16,1.962 -5.787,8.553 -4.858,7.179 6.13,6.13 17.399,17.399 6.126,6.126 7.177,-4.85 8.56,-5.782 1.954,10.141 1.64,8.513 h 41.964 l 1.645,-8.507 1.964,-10.15 8.566,5.787 7.178,4.846 6.124,-6.124 17.4,-17.399 6.13,-6.13 -4.858,-7.18 -5.788,-8.554 10.153,-1.96 8.51,-1.643 v -41.932 l -8.507,-1.646 -10.165,-1.965 5.8,-8.584 4.85,-7.178 -6.125,-6.126 -17.4,-17.4 -6.13,-6.13 -7.18,4.858 -8.558,5.792 -1.964,-10.166 -1.64,-8.509 z m -20.98,118.948 c 23.176,0 41.95,-18.318 41.95,-40.94 0,-22.607 -18.774,-40.927 -41.95,-40.927 -23.174,0 -41.948,18.32 -41.948,40.926 0,22.623 18.774,40.941 41.949,40.941 z m 12.314,-108.448 3.855,19.963 a 47.184,47.184 0 0 1 6.037,2.502 l 16.824,-11.386 17.4,17.4 -11.362,16.818 a 53.171,53.171 0 0 1 2.502,6.066 l 19.932,3.855 v 24.601 l -19.932,3.848 a 56.644,56.644 0 0 1 -2.502,6.066 l 11.362,16.795 -17.4,17.4 -16.824,-11.364 a 44.931,44.931 0 0 1 -6.037,2.504 l -3.855,19.932 h -24.633 l -3.84,-19.932 a 43.821,43.821 0 0 1 -6.043,-2.504 l -16.818,11.364 -17.4,-17.4 11.364,-16.795 a 53.759,53.759 0 0 1 -2.51,-6.066 l -19.933,-3.848 v -24.601 l 19.933,-3.855 a 50.617,50.617 0 0 1 2.51,-6.066 l -11.364,-16.818 17.4,-17.4 16.818,11.386 a 45.957,45.957 0 0 1 6.043,-2.502 l 3.84,-19.963 h 24.632 z"
|
||||
fill="#ad245d"
|
||||
id="path5"
|
||||
style="display:inline;fill:#e67919;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
38
backend/public/img/badges/verification_red_developer.svg
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="513"
|
||||
height="444"
|
||||
version="1.1"
|
||||
id="svg3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs3" />
|
||||
<g
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
id="g3">
|
||||
<path
|
||||
fill="#AD245D"
|
||||
d="M384.5.297L512.325 221.9l-128 221.702-255.825.102L.675 222.1 128.675.4z"
|
||||
id="path1"
|
||||
style="fill:#e67919;fill-opacity:1" />
|
||||
<path
|
||||
d="m 80.877371,348.226 c -0.08,-21.169 -0.205,-53.162 21.256999,-71.332 3.817,-3.253 9.93,-7.497 17.321,-9.224 2.575,-0.523 4.956,-0.756 7.262,-0.979 4.438,-0.431 8.27,-0.804 12.054,-2.9 l 4.954,-2.846 c 9.87,-5.655 19.194,-10.996 28.226,-17.377 5.085,-3.632 6.726,-15.73 6.095,-25.428 -0.214,-2.792 -1.893,-5.7 -3.67,-8.777 -1.097,-1.901 -2.232,-3.867 -3.065,-5.916 l -0.073,-0.199 a 56.976,56.976 0 0 1 -0.422,-1.443 c -1.195,-4.205 -1.933,-6.378 -2.386,-7.476 -7.029,-0.944 -11.8,-8.647 -12.888,-21.006 l -0.031,-0.557 c -0.645,-12.785 0.808,-16.13 2.316,-17.716 0.24,-0.254 0.505,-0.475 0.783,-0.666 -1.754,-16.051 3.115,-32.521 13.358,-44.704 9.314,-11.079 21.955,-17.18 35.592,-17.18 3.73,0 7.55,0.458 11.355,1.362 25.63,6.228 41.679,30.27 40.062,59.227 0.53,0.251 1.018,0.61 1.44,1.066 2.752,2.964 2.47,10.97 2.22,14.276 l -0.024,0.41 c -0.335,5.236 -0.684,10.65 -3.052,15.73 -1.739,3.918 -4.405,6.242 -6.76,8.29 -2.396,2.089 -4.288,3.735 -5.294,6.885 -0.7,2.416 -1.645,4.866 -2.559,7.235 -1.752,4.538 -3.407,8.827 -3.54,13.244 -0.427,10.222 1.17,18.391 4.172,21.359 5.097,5.163 13.003,9.391 19.978,13.121 1.6,0.855 3.166,1.692 4.654,2.517 9.28,5.052 16.07,7.915 25.309,8.557 9.118,0.849 18.056,5.193 24.754,11.97 0.736,0.641 1.82,1.744 3.694,3.648 4.416,4.492 4.416,4.492 4.426,5.852 l 0.007,0.758 c 10.783,17.702 11.14,40.656 11.415,58.169 l 0.05,3.28 -3.278,0.028 c -42.05,0.363 -84.058,0.677 -126.058,0.993 -42.12,0.314 -84.232,0.632 -126.366999,0.994 l -3.273,0.029 z"
|
||||
id="path2-5"
|
||||
style="display:inline;fill:#ffffff" />
|
||||
<text
|
||||
font-family="Impact"
|
||||
font-size="118px"
|
||||
font-style="condensed"
|
||||
font-weight="700"
|
||||
id="text2"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:96px;font-family:Monospace;-inkscape-font-specification:Monospace;display:inline;fill:#ffffff"
|
||||
x="6.8672509"
|
||||
y="17"><tspan
|
||||
x="262.86725"
|
||||
y="225"
|
||||
id="tspan2"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:96px;font-family:Monospace;-inkscape-font-specification:Monospace;fill:#ffffff"></></tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
29
backend/public/img/badges/verification_red_moderator.svg
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="512"
|
||||
height="444"
|
||||
version="1.1"
|
||||
id="svg3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs3" />
|
||||
<g
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
id="g3">
|
||||
<path
|
||||
fill="#AD245D"
|
||||
d="M384 .297L511.392 221.65l-128 221.702-255.392.352L.608 222.35 128.608.65z"
|
||||
id="path1"
|
||||
style="fill:#e67919;fill-opacity:1" />
|
||||
<path
|
||||
d="m 85.310542,348.226 c -0.08,-21.169 -0.205,-53.162 21.256998,-71.332 3.817,-3.253 9.93,-7.497 17.321,-9.224 2.575,-0.523 4.956,-0.756 7.262,-0.979 4.438,-0.431 8.27,-0.804 12.054,-2.9 l 4.954,-2.846 c 9.87,-5.655 19.194,-10.996 28.226,-17.377 5.085,-3.632 6.726,-15.73 6.095,-25.428 -0.214,-2.792 -1.893,-5.7 -3.67,-8.777 -1.097,-1.901 -2.232,-3.867 -3.065,-5.916 l -0.073,-0.199 a 56.976,56.976 0 0 1 -0.422,-1.443 c -1.195,-4.205 -1.933,-6.378 -2.386,-7.476 -7.029,-0.944 -11.8,-8.647 -12.888,-21.006 l -0.031,-0.557 c -0.645,-12.785 0.808,-16.13 2.316,-17.716 0.24,-0.254 0.505,-0.475 0.783,-0.666 -1.754,-16.051 3.115,-32.521 13.358,-44.704 9.314,-11.079 21.955,-17.18 35.592,-17.18 3.73,0 7.55,0.458 11.355,1.362 25.63,6.228 41.679,30.27 40.062,59.227 0.53,0.251 1.018,0.61 1.44,1.066 2.752,2.964 2.47,10.97 2.22,14.276 l -0.024,0.41 c -0.335,5.236 -0.684,10.65 -3.052,15.73 -1.739,3.918 -4.405,6.242 -6.76,8.29 -2.396,2.089 -4.288,3.735 -5.294,6.885 -0.7,2.416 -1.645,4.866 -2.559,7.235 -1.752,4.538 -3.407,8.827 -3.54,13.244 -0.427,10.222 1.17,18.391 4.172,21.359 5.097,5.163 13.003,9.391 19.978,13.121 1.6,0.855 3.166,1.692 4.654,2.517 9.28,5.052 16.07,7.915 25.309,8.557 9.118,0.849 18.056,5.193 24.754,11.97 0.736,0.641 1.82,1.744 3.694,3.648 4.416,4.492 4.416,4.492 4.426,5.852 l 0.007,0.758 c 10.783,17.702 11.14,40.656 11.415,58.169 l 0.05,3.28 -3.278,0.028 c -42.05,0.363 -84.058,0.677 -126.058,0.993 -42.12,0.314 -84.232,0.632 -126.366998,0.994 l -3.273,0.029 z"
|
||||
id="path2-5"
|
||||
style="display:inline;fill:#ffffff" />
|
||||
<path
|
||||
d="m 349.88573,158.65792 h 15.318 v 86.734 h -15.318 v 0.513 l -22.127,-17.64 v 0.12 h -10.21 v 25.51 h -22.128 v -25.51 h -20.424 v -52.722 h 52.762 v -0.508 l 22.127,-17.065 z m 34.313,72.093 -7.988,-4.591 c 15.803,-27.453 1.717,-46.642 1.106,-47.443 l 7.304,-5.607 c 0.774,0.993 18.547,24.675 -0.422,57.641 z m 27.361,21.216 -13.866,-7.975 c 27.437,-47.66 2.98,-80.973 1.918,-82.36 l 12.682,-9.737 c 1.343,1.723 32.2,42.839 -0.734,100.072 z"
|
||||
id="path2-1"
|
||||
style="display:inline;fill:#ffffff" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@ -1,257 +1,234 @@
|
||||
[
|
||||
{
|
||||
"provider_name": "Codepen",
|
||||
"provider_url": "https:\/\/codepen.io",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http:\/\/codepen.io\/*",
|
||||
"https:\/\/codepen.io\/*"
|
||||
],
|
||||
"url": "http:\/\/codepen.io\/api\/oembed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "DTube",
|
||||
"provider_url": "https:\/\/d.tube\/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https:\/\/d.tube\/v\/*"
|
||||
],
|
||||
"url": "https:\/\/api.d.tube\/oembed",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Facebook (Post)",
|
||||
"provider_url": "https:\/\/www.facebook.com\/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https:\/\/www.facebook.com\/*\/posts\/*",
|
||||
"https:\/\/www.facebook.com\/photos\/*",
|
||||
"https:\/\/www.facebook.com\/*\/photos\/*",
|
||||
"https:\/\/www.facebook.com\/photo.php*",
|
||||
"https:\/\/www.facebook.com\/photo.php",
|
||||
"https:\/\/www.facebook.com\/*\/activity\/*",
|
||||
"https:\/\/www.facebook.com\/permalink.php",
|
||||
"https:\/\/www.facebook.com\/media\/set?set=*",
|
||||
"https:\/\/www.facebook.com\/questions\/*",
|
||||
"https:\/\/www.facebook.com\/notes\/*\/*\/*"
|
||||
],
|
||||
"url": "https:\/\/www.facebook.com\/plugins\/post\/oembed.json",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Facebook (Video)",
|
||||
"provider_url": "https:\/\/www.facebook.com\/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https:\/\/www.facebook.com\/*\/videos\/*",
|
||||
"https:\/\/www.facebook.com\/video.php"
|
||||
],
|
||||
"url": "https:\/\/www.facebook.com\/plugins\/video\/oembed.json",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Flickr",
|
||||
"provider_url": "https:\/\/www.flickr.com\/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http:\/\/*.flickr.com\/photos\/*",
|
||||
"http:\/\/flic.kr\/p\/*",
|
||||
"https:\/\/*.flickr.com\/photos\/*",
|
||||
"https:\/\/flic.kr\/p\/*"
|
||||
],
|
||||
"url": "https:\/\/www.flickr.com\/services\/oembed\/",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "GIPHY",
|
||||
"provider_url": "https:\/\/giphy.com",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https:\/\/giphy.com\/gifs\/*",
|
||||
"http:\/\/gph.is\/*",
|
||||
"https:\/\/media.giphy.com\/media\/*\/giphy.gif"
|
||||
],
|
||||
"url": "https:\/\/giphy.com\/services\/oembed",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Instagram",
|
||||
"provider_url": "https:\/\/instagram.com",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http:\/\/instagram.com\/p\/*",
|
||||
"http:\/\/instagr.am\/p\/*",
|
||||
"http:\/\/www.instagram.com\/p\/*",
|
||||
"http:\/\/www.instagr.am\/p\/*",
|
||||
"https:\/\/instagram.com\/p\/*",
|
||||
"https:\/\/instagr.am\/p\/*",
|
||||
"https:\/\/www.instagram.com\/p\/*",
|
||||
"https:\/\/www.instagr.am\/p\/*"
|
||||
],
|
||||
"url": "https:\/\/api.instagram.com\/oembed",
|
||||
"formats": [
|
||||
"json"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Meetup",
|
||||
"provider_url": "http:\/\/www.meetup.com",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http:\/\/meetup.com\/*",
|
||||
"https:\/\/www.meetup.com\/*",
|
||||
"https:\/\/meetup.com\/*",
|
||||
"http:\/\/meetu.ps\/*"
|
||||
],
|
||||
"url": "https:\/\/api.meetup.com\/oembed",
|
||||
"formats": [
|
||||
"json"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "MixCloud",
|
||||
"provider_url": "https:\/\/mixcloud.com\/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http:\/\/www.mixcloud.com\/*\/*\/",
|
||||
"https:\/\/www.mixcloud.com\/*\/*\/"
|
||||
],
|
||||
"url": "https:\/\/www.mixcloud.com\/oembed\/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Reddit",
|
||||
"provider_url": "https:\/\/reddit.com\/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https:\/\/reddit.com\/r\/*\/comments\/*\/*",
|
||||
"https:\/\/www.reddit.com\/r\/*\/comments\/*\/*"
|
||||
],
|
||||
"url": "https:\/\/www.reddit.com\/oembed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "SlideShare",
|
||||
"provider_url": "http:\/\/www.slideshare.net\/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http:\/\/www.slideshare.net\/*\/*",
|
||||
"http:\/\/fr.slideshare.net\/*\/*",
|
||||
"http:\/\/de.slideshare.net\/*\/*",
|
||||
"http:\/\/es.slideshare.net\/*\/*",
|
||||
"http:\/\/pt.slideshare.net\/*\/*"
|
||||
],
|
||||
"url": "http:\/\/www.slideshare.net\/api\/oembed\/2",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "SoundCloud",
|
||||
"provider_url": "http:\/\/soundcloud.com\/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http:\/\/soundcloud.com\/*",
|
||||
"https:\/\/soundcloud.com\/*"
|
||||
],
|
||||
"url": "https:\/\/soundcloud.com\/oembed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Twitch",
|
||||
"provider_url": "https:\/\/www.twitch.tv",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http:\/\/clips.twitch.tv\/*",
|
||||
"https:\/\/clips.twitch.tv\/*",
|
||||
"http:\/\/www.twitch.tv\/*",
|
||||
"https:\/\/www.twitch.tv\/*",
|
||||
"http:\/\/twitch.tv\/*",
|
||||
"https:\/\/twitch.tv\/*"
|
||||
],
|
||||
"url": "https:\/\/api.twitch.tv\/v4\/oembed",
|
||||
"formats": [
|
||||
"json"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Twitter",
|
||||
"provider_url": "http:\/\/www.twitter.com\/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https:\/\/twitter.com\/*\/status\/*",
|
||||
"https:\/\/*.twitter.com\/*\/status\/*"
|
||||
],
|
||||
"url": "https:\/\/publish.twitter.com\/oembed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Vimeo",
|
||||
"provider_url": "https:\/\/vimeo.com\/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https:\/\/vimeo.com\/*",
|
||||
"https:\/\/vimeo.com\/album\/*\/video\/*",
|
||||
"https:\/\/vimeo.com\/channels\/*\/*",
|
||||
"https:\/\/vimeo.com\/groups\/*\/videos\/*",
|
||||
"https:\/\/vimeo.com\/ondemand\/*\/*",
|
||||
"https:\/\/player.vimeo.com\/video\/*"
|
||||
],
|
||||
"url": "https:\/\/vimeo.com\/api\/oembed.{format}",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "YouTube",
|
||||
"provider_url": "https:\/\/www.youtube.com\/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https:\/\/*.youtube.com\/watch*",
|
||||
"https:\/\/*.youtube.com\/v\/*",
|
||||
"https:\/\/youtu.be\/*"
|
||||
],
|
||||
"url": "https:\/\/www.youtube.com\/oembed",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
{
|
||||
"provider_name": "Codepen",
|
||||
"provider_url": "https://codepen.io",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": ["http://codepen.io/*", "https://codepen.io/*"],
|
||||
"url": "http://codepen.io/api/oembed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "DTube",
|
||||
"provider_url": "https://d.tube/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": ["https://d.tube/v/*"],
|
||||
"url": "https://api.d.tube/oembed",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Facebook (Post)",
|
||||
"provider_url": "https://www.facebook.com/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https://www.facebook.com/*/posts/*",
|
||||
"https://www.facebook.com/photos/*",
|
||||
"https://www.facebook.com/*/photos/*",
|
||||
"https://www.facebook.com/photo.php*",
|
||||
"https://www.facebook.com/photo.php",
|
||||
"https://www.facebook.com/*/activity/*",
|
||||
"https://www.facebook.com/permalink.php",
|
||||
"https://www.facebook.com/media/set?set=*",
|
||||
"https://www.facebook.com/questions/*",
|
||||
"https://www.facebook.com/notes/*/*/*"
|
||||
],
|
||||
"url": "https://www.facebook.com/plugins/post/oembed.json",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Facebook (Video)",
|
||||
"provider_url": "https://www.facebook.com/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": ["https://www.facebook.com/*/videos/*", "https://www.facebook.com/video.php"],
|
||||
"url": "https://www.facebook.com/plugins/video/oembed.json",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Flickr",
|
||||
"provider_url": "https://www.flickr.com/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http://*.flickr.com/photos/*",
|
||||
"http://flic.kr/p/*",
|
||||
"https://*.flickr.com/photos/*",
|
||||
"https://flic.kr/p/*"
|
||||
],
|
||||
"url": "https://www.flickr.com/services/oembed/",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "GIPHY",
|
||||
"provider_url": "https://giphy.com",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https://giphy.com/gifs/*",
|
||||
"http://gph.is/*",
|
||||
"https://media.giphy.com/media/*/giphy.gif"
|
||||
],
|
||||
"url": "https://giphy.com/services/oembed",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Instagram",
|
||||
"provider_url": "https://instagram.com",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http://instagram.com/p/*",
|
||||
"http://instagr.am/p/*",
|
||||
"http://www.instagram.com/p/*",
|
||||
"http://www.instagr.am/p/*",
|
||||
"https://instagram.com/p/*",
|
||||
"https://instagr.am/p/*",
|
||||
"https://www.instagram.com/p/*",
|
||||
"https://www.instagr.am/p/*"
|
||||
],
|
||||
"url": "https://api.instagram.com/oembed",
|
||||
"formats": ["json"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Meetup",
|
||||
"provider_url": "http://www.meetup.com",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http://meetup.com/*",
|
||||
"https://www.meetup.com/*",
|
||||
"https://meetup.com/*",
|
||||
"http://meetu.ps/*"
|
||||
],
|
||||
"url": "https://api.meetup.com/oembed",
|
||||
"formats": ["json"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "MixCloud",
|
||||
"provider_url": "https://mixcloud.com/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": ["http://www.mixcloud.com/*/*/", "https://www.mixcloud.com/*/*/"],
|
||||
"url": "https://www.mixcloud.com/oembed/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Reddit",
|
||||
"provider_url": "https://reddit.com/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https://reddit.com/r/*/comments/*/*",
|
||||
"https://www.reddit.com/r/*/comments/*/*"
|
||||
],
|
||||
"url": "https://www.reddit.com/oembed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "SlideShare",
|
||||
"provider_url": "http://www.slideshare.net/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http://www.slideshare.net/*/*",
|
||||
"http://fr.slideshare.net/*/*",
|
||||
"http://de.slideshare.net/*/*",
|
||||
"http://es.slideshare.net/*/*",
|
||||
"http://pt.slideshare.net/*/*"
|
||||
],
|
||||
"url": "http://www.slideshare.net/api/oembed/2",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "SoundCloud",
|
||||
"provider_url": "http://soundcloud.com/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": ["http://soundcloud.com/*", "https://soundcloud.com/*"],
|
||||
"url": "https://soundcloud.com/oembed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Twitch",
|
||||
"provider_url": "https://www.twitch.tv",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"http://clips.twitch.tv/*",
|
||||
"https://clips.twitch.tv/*",
|
||||
"http://www.twitch.tv/*",
|
||||
"https://www.twitch.tv/*",
|
||||
"http://twitch.tv/*",
|
||||
"https://twitch.tv/*"
|
||||
],
|
||||
"url": "https://api.twitch.tv/v4/oembed",
|
||||
"formats": ["json"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Twitter",
|
||||
"provider_url": "http://www.twitter.com/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": ["https://twitter.com/*/status/*", "https://*.twitter.com/*/status/*"],
|
||||
"url": "https://publish.twitter.com/oembed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "Vimeo",
|
||||
"provider_url": "https://vimeo.com/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https://vimeo.com/*",
|
||||
"https://vimeo.com/album/*/video/*",
|
||||
"https://vimeo.com/channels/*/*",
|
||||
"https://vimeo.com/groups/*/videos/*",
|
||||
"https://vimeo.com/ondemand/*/*",
|
||||
"https://player.vimeo.com/video/*"
|
||||
],
|
||||
"url": "https://vimeo.com/api/oembed.{format}",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider_name": "YouTube",
|
||||
"provider_url": "https://www.youtube.com/",
|
||||
"endpoints": [
|
||||
{
|
||||
"schemes": [
|
||||
"https://*.youtube.com/watch*",
|
||||
"https://*.youtube.com/v/*",
|
||||
"https://youtu.be/*"
|
||||
],
|
||||
"url": "https://www.youtube.com/oembed",
|
||||
"discovery": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@ -1,24 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
# html files
|
||||
mkdir -p build/src/middleware/helpers/email/templates/
|
||||
cp -r src/middleware/helpers/email/templates/*.html build/src/middleware/helpers/email/templates/
|
||||
# public
|
||||
cp -r public/ build/public/
|
||||
|
||||
mkdir -p build/src/middleware/helpers/email/templates/en/
|
||||
cp -r src/middleware/helpers/email/templates/en/*.html build/src/middleware/helpers/email/templates/en/
|
||||
# email files
|
||||
mkdir -p build/src/emails/templates/
|
||||
cp -r src/emails/templates/ build/src/emails/
|
||||
|
||||
mkdir -p build/src/middleware/helpers/email/templates/de/
|
||||
cp -r src/middleware/helpers/email/templates/de/*.html build/src/middleware/helpers/email/templates/de/
|
||||
mkdir -p build/src/emails/locales/
|
||||
cp -r src/emails/locales/ build/src/emails/
|
||||
|
||||
# gql files
|
||||
mkdir -p build/src/schema/types/
|
||||
cp -r src/schema/types/*.gql build/src/schema/types/
|
||||
mkdir -p build/src/graphql/types/
|
||||
cp -r src/graphql/types/*.gql build/src/graphql/types/
|
||||
|
||||
mkdir -p build/src/schema/types/enum/
|
||||
cp -r src/schema/types/enum/*.gql build/src/schema/types/enum/
|
||||
mkdir -p build/src/graphql/types/enum/
|
||||
cp -r src/graphql/types/enum/*.gql build/src/graphql/types/enum/
|
||||
|
||||
mkdir -p build/src/schema/types/scalar/
|
||||
cp -r src/schema/types/scalar/*.gql build/src/schema/types/scalar/
|
||||
mkdir -p build/src/graphql/types/scalar/
|
||||
cp -r src/graphql/types/scalar/*.gql build/src/graphql/types/scalar/
|
||||
|
||||
mkdir -p build/src/schema/types/type/
|
||||
cp -r src/schema/types/type/*.gql build/src/schema/types/type/
|
||||
mkdir -p build/src/graphql/types/type/
|
||||
cp -r src/graphql/types/type/*.gql build/src/graphql/types/type/
|
||||
@ -1,8 +1,5 @@
|
||||
// this file is duplicated in `backend/src/config/` and `webapp/constants/` and replaced on rebranding by https://github.com/Ocelot-Social-Community/Ocelot-Social-Deploy-Rebranding/tree/master/branding/constants/
|
||||
export default {
|
||||
SUPPORT_EMAIL: 'support@changemedia.at',
|
||||
MODERATION_EMAIL: 'support@changemedia.at',
|
||||
// ATTENTION: the following links have to be defined even for internal pages with full URLs as example like 'https://staging.ocelot.social/support', because they are used in e-mails!
|
||||
ORGANIZATION_LINK: 'https://changemedia.club',
|
||||
SUPPORT_LINK: 'https://changemedia.club/impressum',
|
||||
}
|
||||
|
||||
@ -1,31 +1,34 @@
|
||||
import dotenv from 'dotenv'
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
|
||||
/* eslint-disable n/no-process-env */
|
||||
import { config } from 'dotenv'
|
||||
// eslint-disable-next-line import/no-namespace
|
||||
import * as SMTPTransport from 'nodemailer/lib/smtp-pool'
|
||||
|
||||
import emails from './emails'
|
||||
import metadata from './metadata'
|
||||
|
||||
// Load env file
|
||||
if (require.resolve) {
|
||||
try {
|
||||
dotenv.config({ path: require.resolve('../../.env') })
|
||||
} catch (error) {
|
||||
// This error is thrown when the .env is not found
|
||||
if (error.code !== 'MODULE_NOT_FOUND') {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
config()
|
||||
|
||||
// Use Cypress env or process.env
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
declare let Cypress: any | undefined
|
||||
const env = typeof Cypress !== 'undefined' ? Cypress.env() : process.env // eslint-disable-line no-undef
|
||||
const env = (typeof Cypress !== 'undefined' ? Cypress.env() : process.env) as typeof process.env
|
||||
|
||||
const environment = {
|
||||
NODE_ENV: env.NODE_ENV || process.env.NODE_ENV,
|
||||
NODE_ENV: env.NODE_ENV ?? process.env.NODE_ENV,
|
||||
DEBUG: env.NODE_ENV !== 'production' && env.DEBUG,
|
||||
TEST: env.NODE_ENV === 'test',
|
||||
PRODUCTION: env.NODE_ENV === 'production',
|
||||
// used for staging enviroments if 'PRODUCTION=true' and 'PRODUCTION_DB_CLEAN_ALLOW=true'
|
||||
PRODUCTION_DB_CLEAN_ALLOW: env.PRODUCTION_DB_CLEAN_ALLOW === 'true' || false, // default = false
|
||||
DISABLED_MIDDLEWARES: (env.NODE_ENV !== 'production' && env.DISABLED_MIDDLEWARES) || false,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
DISABLED_MIDDLEWARES: ['test', 'development'].includes(env.NODE_ENV!)
|
||||
? (env.DISABLED_MIDDLEWARES?.split(',') ?? [])
|
||||
: [],
|
||||
SEND_MAIL: env.NODE_ENV !== 'test',
|
||||
}
|
||||
|
||||
const required = {
|
||||
@ -35,30 +38,51 @@ const required = {
|
||||
}
|
||||
|
||||
const server = {
|
||||
CLIENT_URI: env.CLIENT_URI || 'http://localhost:3000',
|
||||
GRAPHQL_URI: env.GRAPHQL_URI || 'http://localhost:4000',
|
||||
JWT_EXPIRES: env.JWT_EXPIRES || '2y',
|
||||
CLIENT_URI: env.CLIENT_URI ?? 'http://localhost:3000',
|
||||
GRAPHQL_URI: env.GRAPHQL_URI ?? 'http://localhost:4000',
|
||||
JWT_EXPIRES: env.JWT_EXPIRES ?? '2y',
|
||||
}
|
||||
|
||||
const hasDKIMData = env.SMTP_DKIM_DOMAINNAME && env.SMTP_DKIM_KEYSELECTOR && env.SMTP_DKIM_PRIVATKEY
|
||||
const SMTP_HOST = env.SMTP_HOST
|
||||
const SMTP_PORT = (env.SMTP_PORT && parseInt(env.SMTP_PORT)) || undefined
|
||||
const SMTP_IGNORE_TLS = env.SMTP_IGNORE_TLS !== 'false' // default = true
|
||||
const SMTP_SECURE = env.SMTP_SECURE === 'true'
|
||||
const SMTP_USERNAME = env.SMTP_USERNAME
|
||||
const SMTP_PASSWORD = env.SMTP_PASSWORD
|
||||
const SMTP_DKIM_DOMAINNAME = env.SMTP_DKIM_DOMAINNAME
|
||||
const SMTP_DKIM_KEYSELECTOR = env.SMTP_DKIM_KEYSELECTOR
|
||||
// PEM format = https://docs.progress.com/bundle/datadirect-hybrid-data-pipeline-installation-46/page/PEM-file-format.html
|
||||
const SMTP_DKIM_PRIVATKEY = env.SMTP_DKIM_PRIVATKEY?.replace(/\\n/g, '\n') // replace all "\n" in .env string by real line break
|
||||
const SMTP_MAX_CONNECTIONS = (env.SMTP_MAX_CONNECTIONS && parseInt(env.SMTP_MAX_CONNECTIONS)) || 5
|
||||
const SMTP_MAX_MESSAGES = (env.SMTP_MAX_MESSAGES && parseInt(env.SMTP_MAX_MESSAGES)) || 100
|
||||
|
||||
const smtp = {
|
||||
SMTP_HOST: env.SMTP_HOST,
|
||||
SMTP_PORT: env.SMTP_PORT,
|
||||
SMTP_IGNORE_TLS: env.SMTP_IGNORE_TLS !== 'false', // default = true
|
||||
SMTP_SECURE: env.SMTP_SECURE === 'true',
|
||||
SMTP_USERNAME: env.SMTP_USERNAME,
|
||||
SMTP_PASSWORD: env.SMTP_PASSWORD,
|
||||
SMTP_DKIM_DOMAINNAME: hasDKIMData && env.SMTP_DKIM_DOMAINNAME,
|
||||
SMTP_DKIM_KEYSELECTOR: hasDKIMData && env.SMTP_DKIM_KEYSELECTOR,
|
||||
// PEM format: https://docs.progress.com/bundle/datadirect-hybrid-data-pipeline-installation-46/page/PEM-file-format.html
|
||||
SMTP_DKIM_PRIVATKEY: hasDKIMData && env.SMTP_DKIM_PRIVATKEY.replace(/\\n/g, '\n'), // replace all "\n" in .env string by real line break
|
||||
const nodemailerTransportOptions: SMTPTransport.Options = {
|
||||
host: SMTP_HOST,
|
||||
port: SMTP_PORT,
|
||||
ignoreTLS: SMTP_IGNORE_TLS,
|
||||
secure: SMTP_SECURE, // true for 465, false for other ports
|
||||
pool: true,
|
||||
maxConnections: SMTP_MAX_CONNECTIONS,
|
||||
maxMessages: SMTP_MAX_MESSAGES,
|
||||
}
|
||||
if (SMTP_USERNAME && SMTP_PASSWORD) {
|
||||
nodemailerTransportOptions.auth = {
|
||||
user: SMTP_USERNAME,
|
||||
pass: SMTP_PASSWORD,
|
||||
}
|
||||
}
|
||||
if (SMTP_DKIM_DOMAINNAME && SMTP_DKIM_KEYSELECTOR && SMTP_DKIM_PRIVATKEY) {
|
||||
nodemailerTransportOptions.dkim = {
|
||||
domainName: SMTP_DKIM_DOMAINNAME,
|
||||
keySelector: SMTP_DKIM_KEYSELECTOR,
|
||||
privateKey: SMTP_DKIM_PRIVATKEY,
|
||||
}
|
||||
}
|
||||
|
||||
const neo4j = {
|
||||
NEO4J_URI: env.NEO4J_URI || 'bolt://localhost:7687',
|
||||
NEO4J_USERNAME: env.NEO4J_USERNAME || 'neo4j',
|
||||
NEO4J_PASSWORD: env.NEO4J_PASSWORD || 'neo4j',
|
||||
NEO4J_URI: env.NEO4J_URI ?? 'bolt://localhost:7687',
|
||||
NEO4J_USERNAME: env.NEO4J_USERNAME ?? 'neo4j',
|
||||
NEO4J_PASSWORD: env.NEO4J_PASSWORD ?? 'neo4j',
|
||||
}
|
||||
|
||||
const sentry = {
|
||||
@ -68,7 +92,7 @@ const sentry = {
|
||||
|
||||
const redis = {
|
||||
REDIS_DOMAIN: env.REDIS_DOMAIN,
|
||||
REDIS_PORT: env.REDIS_PORT,
|
||||
REDIS_PORT: (env.REDIS_PORT && parseInt(env.REDIS_PORT)) || undefined,
|
||||
REDIS_PASSWORD: env.REDIS_PASSWORD,
|
||||
}
|
||||
|
||||
@ -88,14 +112,23 @@ const s3 = {
|
||||
|
||||
const options = {
|
||||
EMAIL_DEFAULT_SENDER: env.EMAIL_DEFAULT_SENDER,
|
||||
SUPPORT_EMAIL: env.SUPPORT_EMAIL,
|
||||
SUPPORT_URL: emails.SUPPORT_LINK,
|
||||
APPLICATION_NAME: metadata.APPLICATION_NAME,
|
||||
ORGANIZATION_URL: emails.ORGANIZATION_LINK,
|
||||
PUBLIC_REGISTRATION: env.PUBLIC_REGISTRATION === 'true' || false,
|
||||
INVITE_REGISTRATION: env.INVITE_REGISTRATION !== 'false', // default = true
|
||||
INVITE_CODES_PERSONAL_PER_USER:
|
||||
(env.INVITE_CODES_PERSONAL_PER_USER && parseInt(env.INVITE_CODES_PERSONAL_PER_USER)) || 7,
|
||||
INVITE_CODES_GROUP_PER_USER:
|
||||
(env.INVITE_CODES_GROUP_PER_USER && parseInt(env.INVITE_CODES_GROUP_PER_USER)) || 7,
|
||||
CATEGORIES_ACTIVE: process.env.CATEGORIES_ACTIVE === 'true' || false,
|
||||
}
|
||||
|
||||
const language = {
|
||||
LANGUAGE_DEFAULT: process.env.LANGUAGE_DEFAULT ?? 'en',
|
||||
}
|
||||
|
||||
// Check if all required configs are present
|
||||
Object.entries(required).map((entry) => {
|
||||
if (!entry[1]) {
|
||||
@ -108,10 +141,12 @@ export default {
|
||||
...environment,
|
||||
...server,
|
||||
...required,
|
||||
...smtp,
|
||||
...neo4j,
|
||||
...sentry,
|
||||
...redis,
|
||||
...s3,
|
||||
...options,
|
||||
...language,
|
||||
}
|
||||
|
||||
export { nodemailerTransportOptions }
|
||||
|
||||
@ -1,10 +1,3 @@
|
||||
// this file is duplicated in `backend/src/config/logos` and `webapp/constants/logos.js` and replaced on rebranding
|
||||
// this file is duplicated in `backend/src/config/logos.ts` and `webapp/constants/logos.js` and replaced on rebranding
|
||||
// this are the paths in the webapp
|
||||
export default {
|
||||
LOGO_HEADER_PATH: '/img/custom/logo-horizontal.svg',
|
||||
LOGO_SIGNUP_PATH: '/img/custom/logo-squared.svg',
|
||||
LOGO_WELCOME_PATH: '/img/custom/logo-squared.svg',
|
||||
LOGO_LOGOUT_PATH: '/img/custom/logo-squared.svg',
|
||||
LOGO_PASSWORD_RESET_PATH: '/img/custom/logo-squared.svg',
|
||||
LOGO_MAINTENACE_RESET_PATH: '/img/custom/logo-squared.svg',
|
||||
}
|
||||
export default {}
|
||||
|
||||
32
backend/src/config/logosBranded.ts
Normal file
@ -0,0 +1,32 @@
|
||||
// this file is duplicated in `backend/src/config/logos.ts` and `webapp/constants/logos.js` and replaced on rebranding
|
||||
// this are the paths in the webapp
|
||||
import { merge } from 'lodash'
|
||||
|
||||
import logos from '@config/logos'
|
||||
|
||||
const defaultLogos = {
|
||||
LOGO_HEADER_PATH: '/img/custom/logo-horizontal.svg',
|
||||
LOGO_HEADER_MOBILE_PATH: '/img/custom/logo-horizontal.svg',
|
||||
LOGO_HEADER_WIDTH: '130px',
|
||||
LOGO_HEADER_MOBILE_WIDTH: '100px',
|
||||
LOGO_HEADER_CLICK: {
|
||||
// externalLink: {
|
||||
// url: 'https://ocelot.social',
|
||||
// target: '_blank',
|
||||
// },
|
||||
externalLink: null,
|
||||
internalPath: {
|
||||
to: {
|
||||
name: 'index',
|
||||
},
|
||||
scrollTo: '.main-navigation',
|
||||
},
|
||||
},
|
||||
LOGO_SIGNUP_PATH: '/img/custom/logo-squared.svg',
|
||||
LOGO_WELCOME_PATH: '/img/custom/logo-squared.svg',
|
||||
LOGO_LOGOUT_PATH: '/img/custom/logo-squared.svg',
|
||||
LOGO_PASSWORD_RESET_PATH: '/img/custom/logo-squared.svg',
|
||||
LOGO_MAINTENACE_RESET_PATH: '/img/custom/logo-squared.svg',
|
||||
}
|
||||
|
||||
export default merge(defaultLogos, logos)
|
||||
2
backend/src/constants/badges.ts
Normal file
@ -0,0 +1,2 @@
|
||||
// this file is duplicated in `backend/src/constants/badges` and `webapp/constants/badges.js`
|
||||
export const TROPHY_BADGES_SELECTED_MAX = 9
|
||||
@ -5,98 +5,116 @@ export const CATEGORIES_MAX = 3
|
||||
export const categories = [
|
||||
{
|
||||
icon: 'networking',
|
||||
id: 'cat0',
|
||||
slug: 'networking',
|
||||
name: 'networking',
|
||||
description: 'Kooperation, Aktionsbündnisse, Solidarität, Hilfe',
|
||||
},
|
||||
{
|
||||
icon: 'home',
|
||||
id: 'cat1',
|
||||
slug: 'home',
|
||||
name: 'home',
|
||||
description: 'Bauen, Lebensgemeinschaften, Tiny Houses, Gemüsegarten',
|
||||
},
|
||||
{
|
||||
icon: 'energy',
|
||||
id: 'cat2',
|
||||
slug: 'energy',
|
||||
name: 'energy',
|
||||
description: 'Öl, Gas, Kohle, Wind, Wasserkraft, Biogas, Atomenergie, ...',
|
||||
},
|
||||
{
|
||||
icon: 'psyche',
|
||||
id: 'cat3',
|
||||
slug: 'psyche',
|
||||
name: 'psyche',
|
||||
description: 'Seele, Gefühle, Glück',
|
||||
},
|
||||
{
|
||||
icon: 'movement',
|
||||
id: 'cat4',
|
||||
slug: 'body-and-excercise',
|
||||
name: 'body-and-excercise',
|
||||
description: 'Sport, Yoga, Massage, Tanzen, Entspannung',
|
||||
},
|
||||
{
|
||||
icon: 'balance-scale',
|
||||
id: 'cat5',
|
||||
slug: 'law',
|
||||
name: 'law',
|
||||
description: 'Menschenrechte, Gesetze, Verordnungen',
|
||||
},
|
||||
{
|
||||
icon: 'finance',
|
||||
id: 'cat6',
|
||||
slug: 'finance',
|
||||
name: 'finance',
|
||||
description: 'Geld, Finanzsystem, Alternativwährungen, ...',
|
||||
},
|
||||
{
|
||||
icon: 'child',
|
||||
id: 'cat7',
|
||||
slug: 'children',
|
||||
name: 'children',
|
||||
description: 'Familie, Pädagogik, Schule, Prägung',
|
||||
},
|
||||
{
|
||||
icon: 'mobility',
|
||||
id: 'cat8',
|
||||
slug: 'mobility',
|
||||
name: 'mobility',
|
||||
description: 'Reise, Verkehr, Elektromobilität',
|
||||
},
|
||||
{
|
||||
icon: 'shopping-cart',
|
||||
id: 'cat9',
|
||||
slug: 'economy',
|
||||
name: 'economy',
|
||||
description: 'Handel, Konsum, Marketing, Lebensmittel, Lieferketten, ...',
|
||||
},
|
||||
{
|
||||
icon: 'peace',
|
||||
id: 'cat10',
|
||||
slug: 'peace',
|
||||
name: 'peace',
|
||||
description: 'Krieg, Militär, soziale Verteidigung, Waffen, Cyberattacken',
|
||||
},
|
||||
{
|
||||
icon: 'politics',
|
||||
id: 'cat11',
|
||||
slug: 'politics',
|
||||
name: 'politics',
|
||||
description: 'Demokratie, Mitbestimmung, Wahlen, Korruption, Parteien',
|
||||
},
|
||||
{
|
||||
icon: 'nature',
|
||||
id: 'cat12',
|
||||
slug: 'nature',
|
||||
name: 'nature',
|
||||
description: 'Tiere, Pflanzen, Landwirtschaft, Ökologie, Artenvielfalt',
|
||||
},
|
||||
{
|
||||
icon: 'science',
|
||||
id: 'cat13',
|
||||
slug: 'science',
|
||||
name: 'science',
|
||||
description: 'Bildung, Hochschule, Publikationen, ...',
|
||||
},
|
||||
{
|
||||
icon: 'health',
|
||||
id: 'cat14',
|
||||
slug: 'health',
|
||||
name: 'health',
|
||||
description: 'Medizin, Ernährung, WHO, Impfungen, Schadstoffe, ...',
|
||||
},
|
||||
{
|
||||
icon: 'media',
|
||||
id: 'cat15',
|
||||
slug: 'it-and-media',
|
||||
name: 'it-and-media',
|
||||
description:
|
||||
'Nachrichten, Manipulation, Datenschutz, Überwachung, Datenkraken, AI, Software, Apps',
|
||||
},
|
||||
{
|
||||
icon: 'spirituality',
|
||||
id: 'cat16',
|
||||
slug: 'spirituality',
|
||||
name: 'spirituality',
|
||||
description: 'Religion, Werte, Ethik',
|
||||
},
|
||||
{
|
||||
icon: 'culture',
|
||||
id: 'cat17',
|
||||
slug: 'culture',
|
||||
name: 'culture',
|
||||
description: 'Kunst, Theater, Musik, Fotografie, Film',
|
||||
},
|
||||
{
|
||||
icon: 'miscellaneous',
|
||||
id: 'cat18',
|
||||
slug: 'miscellaneous',
|
||||
name: 'miscellaneous',
|
||||
description: '',
|
||||
},
|
||||
]
|
||||
|
||||
@ -1,5 +1,2 @@
|
||||
// this file is duplicated in `backend/src/config/metadata` and `webapp/constants/metadata.js`
|
||||
export default {
|
||||
NONCE_LENGTH: 5,
|
||||
INVITE_CODE_LENGTH: 6,
|
||||
}
|
||||
// this file is duplicated in `backend/src/config/registration.ts` and `webapp/constants/registration.js`
|
||||
export default {}
|
||||
|
||||
12
backend/src/constants/registrationBranded.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// this file is duplicated in `backend/src/config/registrationBranded.ts` and `webapp/constants/registrationBranded.js`
|
||||
import { merge } from 'lodash'
|
||||
|
||||
import registration from '@constants/registration'
|
||||
|
||||
const defaultRegistration = {
|
||||
NONCE_LENGTH: 5,
|
||||
INVITE_CODE_LENGTH: 6,
|
||||
LAYOUT: 'no-header',
|
||||
}
|
||||
|
||||
export default merge(defaultRegistration, registration)
|
||||
3
backend/src/constants/subscriptions.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const NOTIFICATION_ADDED = 'NOTIFICATION_ADDED'
|
||||
export const CHAT_MESSAGE_ADDED = 'CHAT_MESSAGE_ADDED'
|
||||
export const ROOM_COUNT_UPDATED = 'ROOM_COUNT_UPDATED'
|
||||
49
backend/src/context/database.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { getDriver, getNeode } from '@db/neo4j'
|
||||
|
||||
import type { Driver } from 'neo4j-driver'
|
||||
|
||||
export const query =
|
||||
(driver: Driver) =>
|
||||
async ({ query, variables = {} }: { query: string; variables?: object }) => {
|
||||
const session = driver.session()
|
||||
|
||||
const result = session.readTransaction(async (transaction) => {
|
||||
const response = await transaction.run(query, variables)
|
||||
return response
|
||||
})
|
||||
|
||||
try {
|
||||
return await result
|
||||
} finally {
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
export const write =
|
||||
(driver: Driver) =>
|
||||
async ({ query, variables = {} }: { query: string; variables?: object }) => {
|
||||
const session = driver.session()
|
||||
|
||||
const result = session.writeTransaction(async (transaction) => {
|
||||
const response = await transaction.run(query, variables)
|
||||
return response
|
||||
})
|
||||
|
||||
try {
|
||||
return await result
|
||||
} finally {
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
|
||||
return {
|
||||
driver,
|
||||
neode,
|
||||
query: query(driver),
|
||||
write: write(driver),
|
||||
}
|
||||
}
|
||||
25
backend/src/context/pubsub.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { RedisPubSub } from 'graphql-redis-subscriptions'
|
||||
import { PubSub } from 'graphql-subscriptions'
|
||||
import Redis from 'ioredis'
|
||||
|
||||
import CONFIG from '@config/index'
|
||||
|
||||
export default () => {
|
||||
const { REDIS_DOMAIN, REDIS_PORT, REDIS_PASSWORD } = CONFIG
|
||||
if (!(REDIS_DOMAIN && REDIS_PORT && REDIS_PASSWORD)) {
|
||||
return new PubSub()
|
||||
}
|
||||
|
||||
const options = {
|
||||
host: REDIS_DOMAIN,
|
||||
port: REDIS_PORT,
|
||||
password: REDIS_PASSWORD,
|
||||
retryStrategy: (times) => {
|
||||
return Math.min(times * 50, 2000)
|
||||
},
|
||||
}
|
||||
return new RedisPubSub({
|
||||
publisher: new Redis(options),
|
||||
subscriber: new Redis(options),
|
||||
})
|
||||
}
|
||||
54
backend/src/db/admin.ts
Normal file
@ -0,0 +1,54 @@
|
||||
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||
/* eslint-disable @typescript-eslint/require-await */
|
||||
|
||||
import { hashSync } from 'bcryptjs'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
import { getDriver } from './neo4j'
|
||||
|
||||
const defaultAdmin = {
|
||||
email: 'admin@example.org',
|
||||
// eslint-disable-next-line n/no-sync
|
||||
password: hashSync('1234', 10),
|
||||
name: 'admin',
|
||||
id: uuid(),
|
||||
slug: 'admin',
|
||||
}
|
||||
|
||||
const createDefaultAdminUser = async () => {
|
||||
const driver = getDriver()
|
||||
const session = driver.session()
|
||||
const createAdminTxResultPromise = session.writeTransaction(async (txc) => {
|
||||
txc.run(
|
||||
`MERGE (e:EmailAddress {
|
||||
email: "${defaultAdmin.email}",
|
||||
createdAt: toString(datetime())
|
||||
})-[:BELONGS_TO]->(u:User {
|
||||
name: "${defaultAdmin.name}",
|
||||
encryptedPassword: "${defaultAdmin.password}",
|
||||
role: "admin",
|
||||
id: "${defaultAdmin.id}",
|
||||
slug: "${defaultAdmin.slug}",
|
||||
createdAt: toString(datetime()),
|
||||
allowEmbedIframes: false,
|
||||
showShoutsPublicly: false,
|
||||
deleted: false,
|
||||
disabled: false
|
||||
})-[:PRIMARY_EMAIL]->(e)`,
|
||||
)
|
||||
})
|
||||
try {
|
||||
await createAdminTxResultPromise
|
||||
console.log('Successfully created default admin user!') // eslint-disable-line no-console
|
||||
// eslint-disable-next-line no-catch-all/no-catch-all
|
||||
} catch (error) {
|
||||
console.log(error) // eslint-disable-line no-console
|
||||
} finally {
|
||||
session.close()
|
||||
driver.close()
|
||||
}
|
||||
}
|
||||
|
||||
;(async function () {
|
||||
await createDefaultAdminUser()
|
||||
})()
|
||||
14
backend/src/db/badges.ts
Normal file
@ -0,0 +1,14 @@
|
||||
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||
import { getNeode } from './neo4j'
|
||||
import { trophies, verification } from './seed/badges'
|
||||
|
||||
// eslint-disable-next-line import/newline-after-import
|
||||
;(async function () {
|
||||
const neode = getNeode()
|
||||
try {
|
||||
await trophies()
|
||||
await verification()
|
||||
} finally {
|
||||
neode.close()
|
||||
}
|
||||
})()
|
||||
48
backend/src/db/categories.ts
Normal file
@ -0,0 +1,48 @@
|
||||
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
|
||||
import { categories } from '@constants/categories'
|
||||
import databaseContext from '@context/database'
|
||||
|
||||
const { query, write, driver } = databaseContext()
|
||||
|
||||
const createCategories = async () => {
|
||||
const result = await query({
|
||||
query: 'MATCH (category:Category) RETURN category { .* }',
|
||||
})
|
||||
|
||||
const categoryIds = categories.map((c) => c.id)
|
||||
const categorySlugs = categories.map((c) => c.slug)
|
||||
await write({
|
||||
query: `MATCH (category:Category)
|
||||
WHERE NOT category.id IN $categoryIds
|
||||
DETACH DELETE category`,
|
||||
variables: {
|
||||
categoryIds,
|
||||
categorySlugs,
|
||||
},
|
||||
})
|
||||
|
||||
const existingCategories = result.records.map((r) => r.get('category'))
|
||||
|
||||
const newCategories = categories.filter((c) => !existingCategories.some((cat) => c.id === cat.id))
|
||||
|
||||
await write({
|
||||
query: `UNWIND $newCategories AS map
|
||||
CREATE (category:Category)
|
||||
SET category = map
|
||||
SET category.createdAt = toString(datetime())`,
|
||||
variables: {
|
||||
newCategories,
|
||||
},
|
||||
})
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Successfully created categories!')
|
||||
await driver.close()
|
||||
}
|
||||
|
||||
;(async function () {
|
||||
await createCategories()
|
||||
})()
|
||||
@ -1,2 +1,9 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable import/no-commonjs */
|
||||
// eslint-disable-next-line n/no-unpublished-require, @typescript-eslint/no-var-requires
|
||||
const tsNode = require('ts-node')
|
||||
// eslint-disable-next-line import/no-unassigned-import, n/no-unpublished-require
|
||||
require('tsconfig-paths/register')
|
||||
|
||||
module.exports = tsNode.register
|
||||
|
||||
27
backend/src/db/data-branding.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||
import { readdir } from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
|
||||
import { getNeode } from './neo4j'
|
||||
|
||||
const dataFolder = path.join(__dirname, 'data/')
|
||||
const neode = getNeode()
|
||||
|
||||
;(async function () {
|
||||
const files = await readdir(dataFolder)
|
||||
for await (const file of files) {
|
||||
if (file.slice(0, -3).endsWith('-branding')) {
|
||||
const importedModule = await import(path.join(dataFolder, file))
|
||||
if (!importedModule.default) {
|
||||
throw new Error('Your data file must export a default function')
|
||||
}
|
||||
await importedModule.default()
|
||||
}
|
||||
}
|
||||
|
||||
// close database connection
|
||||
neode.close()
|
||||
})()
|
||||
@ -1,35 +1,43 @@
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import slugify from 'slug'
|
||||
/* eslint-disable @typescript-eslint/unbound-method */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
import { faker } from '@faker-js/faker'
|
||||
import { hashSync } from 'bcryptjs'
|
||||
import { Factory } from 'rosie'
|
||||
import { faker } from '@faker-js/faker'
|
||||
import slugify from 'slug'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
import { generateInviteCode } from '@graphql/resolvers/inviteCodes'
|
||||
|
||||
import { getDriver, getNeode } from './neo4j'
|
||||
import CONFIG from '../config/index'
|
||||
import generateInviteCode from '../schema/resolvers/helpers/generateInviteCode'
|
||||
|
||||
const neode = getNeode()
|
||||
|
||||
const uniqueImageUrl = (imageUrl) => {
|
||||
const newUrl = new URL(imageUrl, CONFIG.CLIENT_URI)
|
||||
const newUrl = new URL(imageUrl)
|
||||
newUrl.search = `random=${uuid()}`
|
||||
return newUrl.toString()
|
||||
}
|
||||
|
||||
export const cleanDatabase = async (options: any = {}) => {
|
||||
const { driver = getDriver() } = options
|
||||
export const cleanDatabase = async ({ withMigrations } = { withMigrations: false }) => {
|
||||
const driver = getDriver()
|
||||
const session = driver.session()
|
||||
|
||||
const clean = `
|
||||
MATCH (everything)
|
||||
${withMigrations ? '' : "WHERE NOT 'Migration' IN labels(everything)"}
|
||||
DETACH DELETE everything
|
||||
`
|
||||
|
||||
try {
|
||||
await session.writeTransaction((transaction) => {
|
||||
return transaction.run(
|
||||
`
|
||||
MATCH (everything)
|
||||
WHERE NOT 'Migration' IN labels(everything)
|
||||
DETACH DELETE everything
|
||||
`,
|
||||
)
|
||||
return transaction.run(clean)
|
||||
})
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,25 +45,34 @@ Factory.define('category')
|
||||
.attr('id', uuid)
|
||||
.attr('icon', 'globe')
|
||||
.attr('name', 'Global Peace & Nonviolence')
|
||||
.after((buildObject, options) => {
|
||||
.after((buildObject, _options) => {
|
||||
return neode.create('Category', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('badge')
|
||||
.attr('type', 'crowdfunding')
|
||||
.attr('status', 'permanent')
|
||||
.after((buildObject, options) => {
|
||||
.after((buildObject, _options) => {
|
||||
return neode.create('Badge', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('image')
|
||||
.attr('url', faker.image.url)
|
||||
.attr('aspectRatio', 1.3333333333333333)
|
||||
.attr('width', 400)
|
||||
.attr('height', 300)
|
||||
.attr('blur', 0)
|
||||
.attr('alt', faker.lorem.sentence)
|
||||
.attr('type', 'image/jpeg')
|
||||
.after((buildObject, options) => {
|
||||
const { url: imageUrl } = buildObject
|
||||
if (imageUrl) buildObject.url = uniqueImageUrl(imageUrl)
|
||||
.attr('url', null)
|
||||
.after((buildObject, _options) => {
|
||||
if (!buildObject.url) {
|
||||
buildObject.url = faker.image.urlPicsumPhotos({
|
||||
width: buildObject.width,
|
||||
height: buildObject.height,
|
||||
blur: buildObject.blur,
|
||||
})
|
||||
}
|
||||
buildObject.url = uniqueImageUrl(buildObject.url)
|
||||
buildObject.aspectRatio = buildObject.width / buildObject.height
|
||||
return neode.create('Image', buildObject)
|
||||
})
|
||||
|
||||
@ -70,34 +87,34 @@ Factory.define('basicUser')
|
||||
termsAndConditionsAgreedAt: '2019-08-01T10:47:19.212Z',
|
||||
allowEmbedIframes: false,
|
||||
showShoutsPublicly: false,
|
||||
sendNotificationEmails: true,
|
||||
locale: 'en',
|
||||
})
|
||||
.attr('slug', ['slug', 'name'], (slug, name) => {
|
||||
return slug || slugify(name, { lower: true })
|
||||
})
|
||||
.attr('encryptedPassword', ['password'], (password) => {
|
||||
// eslint-disable-next-line n/no-sync
|
||||
return hashSync(password, 10)
|
||||
})
|
||||
|
||||
Factory.define('userWithoutEmailAddress')
|
||||
.extend('basicUser')
|
||||
.option('about', faker.lorem.paragraph)
|
||||
.after(async (buildObject, options) => {
|
||||
.after(async (buildObject, _options) => {
|
||||
return neode.create('User', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('userWithAboutNull')
|
||||
.extend('basicUser')
|
||||
.option('about', null)
|
||||
.after(async (buildObject, options) => {
|
||||
.after(async (buildObject, _options) => {
|
||||
return neode.create('User', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('userWithAboutEmpty')
|
||||
.extend('basicUser')
|
||||
.option('about', '')
|
||||
.after(async (buildObject, options) => {
|
||||
.after(async (buildObject, _options) => {
|
||||
return neode.create('User', buildObject)
|
||||
})
|
||||
|
||||
@ -173,6 +190,7 @@ Factory.define('post')
|
||||
])
|
||||
await Promise.all([
|
||||
post.relateTo(author, 'author'),
|
||||
post.relateTo(author, 'observes'),
|
||||
// Promise.all(categories.map((c) => c.relateTo(post, 'post'))),
|
||||
Promise.all(tags.map((t) => t.relateTo(post, 'post'))),
|
||||
])
|
||||
@ -208,7 +226,11 @@ Factory.define('comment')
|
||||
options.author,
|
||||
options.post,
|
||||
])
|
||||
await Promise.all([comment.relateTo(author, 'author'), comment.relateTo(post, 'post')])
|
||||
await Promise.all([
|
||||
comment.relateTo(author, 'author'),
|
||||
comment.relateTo(post, 'post'),
|
||||
post.relateTo(author, 'observes'),
|
||||
])
|
||||
return comment
|
||||
})
|
||||
|
||||
@ -217,7 +239,7 @@ Factory.define('donations')
|
||||
.attr('showDonations', true)
|
||||
.attr('goal', 15000)
|
||||
.attr('progress', 7000)
|
||||
.after((buildObject, options) => {
|
||||
.after((buildObject, _options) => {
|
||||
return neode.create('Donations', buildObject)
|
||||
})
|
||||
|
||||
@ -228,13 +250,13 @@ const emailDefaults = {
|
||||
|
||||
Factory.define('emailAddress')
|
||||
.attrs(emailDefaults)
|
||||
.after((buildObject, options) => {
|
||||
.after((buildObject, _options) => {
|
||||
return neode.create('EmailAddress', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('unverifiedEmailAddress')
|
||||
.attr(emailDefaults)
|
||||
.after((buildObject, options) => {
|
||||
.after((buildObject, _options) => {
|
||||
return neode.create('UnverifiedEmailAddress', buildObject)
|
||||
})
|
||||
|
||||
@ -246,17 +268,27 @@ const inviteCodeDefaults = {
|
||||
|
||||
Factory.define('inviteCode')
|
||||
.attrs(inviteCodeDefaults)
|
||||
.option('groupId', null)
|
||||
.option('group', ['groupId'], (groupId) => {
|
||||
if (groupId) {
|
||||
return neode.find('Group', groupId)
|
||||
}
|
||||
})
|
||||
.option('generatedById', null)
|
||||
.option('generatedBy', ['generatedById'], (generatedById) => {
|
||||
if (generatedById) return neode.find('User', generatedById)
|
||||
return Factory.build('user')
|
||||
})
|
||||
.after(async (buildObject, options) => {
|
||||
const [inviteCode, generatedBy] = await Promise.all([
|
||||
const [inviteCode, generatedBy, group] = await Promise.all([
|
||||
neode.create('InviteCode', buildObject),
|
||||
options.generatedBy,
|
||||
options.group,
|
||||
])
|
||||
await Promise.all([inviteCode.relateTo(generatedBy, 'generated')])
|
||||
await inviteCode.relateTo(generatedBy, 'generated')
|
||||
if (group) {
|
||||
await inviteCode.relateTo(group, 'invitesTo')
|
||||
}
|
||||
return inviteCode
|
||||
})
|
||||
|
||||
@ -274,11 +306,11 @@ Factory.define('location')
|
||||
id: 'country.10743216036480410',
|
||||
type: 'country',
|
||||
})
|
||||
.after((buildObject, options) => {
|
||||
.after((buildObject, _options) => {
|
||||
return neode.create('Location', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('report').after((buildObject, options) => {
|
||||
Factory.define('report').after((buildObject, _options) => {
|
||||
return neode.create('Report', buildObject)
|
||||
})
|
||||
|
||||
@ -286,7 +318,7 @@ Factory.define('tag')
|
||||
.attrs({
|
||||
name: '#human-connection',
|
||||
})
|
||||
.after((buildObject, options) => {
|
||||
.after((buildObject, _options) => {
|
||||
return neode.create('Tag', buildObject)
|
||||
})
|
||||
|
||||
@ -294,7 +326,7 @@ Factory.define('socialMedia')
|
||||
.attrs({
|
||||
url: 'https://mastodon.social/@Gargron',
|
||||
})
|
||||
.after((buildObject, options) => {
|
||||
.after((buildObject, _options) => {
|
||||
return neode.create('SocialMedia', buildObject)
|
||||
})
|
||||
|
||||
|
||||
@ -1,104 +1,52 @@
|
||||
import { getDriver, getNeode } from '../../db/neo4j'
|
||||
import { hashSync } from 'bcryptjs'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import { categories } from '../../constants/categories'
|
||||
import CONFIG from '../../config'
|
||||
|
||||
const defaultAdmin = {
|
||||
email: 'admin@example.org',
|
||||
password: hashSync('1234', 10),
|
||||
name: 'admin',
|
||||
id: uuid(),
|
||||
slug: 'admin',
|
||||
}
|
||||
|
||||
const createCategories = async (session) => {
|
||||
const createCategoriesTxResultPromise = session.writeTransaction(async (txc) => {
|
||||
categories.forEach(({ icon, name }, index) => {
|
||||
const id = `cat${index + 1}`
|
||||
txc.run(
|
||||
`MERGE (c:Category {
|
||||
icon: "${icon}",
|
||||
slug: "${name}",
|
||||
name: "${name}",
|
||||
id: "${id}",
|
||||
createdAt: toString(datetime())
|
||||
})`,
|
||||
)
|
||||
})
|
||||
})
|
||||
try {
|
||||
await createCategoriesTxResultPromise
|
||||
console.log('Successfully created categories!') // eslint-disable-line no-console
|
||||
} catch (error) {
|
||||
console.log(`Error creating categories: ${error}`) // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
|
||||
const createDefaultAdminUser = async (session) => {
|
||||
const readTxResultPromise = session.readTransaction(async (txc) => {
|
||||
const result = await txc.run('MATCH (user:User) RETURN count(user) AS userCount')
|
||||
return result.records.map((r) => r.get('userCount'))
|
||||
})
|
||||
let createAdmin = false
|
||||
try {
|
||||
const userCount = parseInt(String(await readTxResultPromise))
|
||||
if (userCount === 0) createAdmin = true
|
||||
} catch (error) {
|
||||
console.log(error) // eslint-disable-line no-console
|
||||
}
|
||||
if (createAdmin) {
|
||||
const createAdminTxResultPromise = session.writeTransaction(async (txc) => {
|
||||
txc.run(
|
||||
`MERGE (e:EmailAddress {
|
||||
email: "${defaultAdmin.email}",
|
||||
createdAt: toString(datetime())
|
||||
})-[:BELONGS_TO]->(u:User {
|
||||
name: "${defaultAdmin.name}",
|
||||
encryptedPassword: "${defaultAdmin.password}",
|
||||
role: "admin",
|
||||
id: "${defaultAdmin.id}",
|
||||
slug: "${defaultAdmin.slug}",
|
||||
createdAt: toString(datetime()),
|
||||
allowEmbedIframes: false,
|
||||
showShoutsPublicly: false,
|
||||
sendNotificationEmails: true,
|
||||
deleted: false,
|
||||
disabled: false
|
||||
})-[:PRIMARY_EMAIL]->(e)`,
|
||||
)
|
||||
})
|
||||
try {
|
||||
await createAdminTxResultPromise
|
||||
console.log('Successfully created default admin user!') // eslint-disable-line no-console
|
||||
} catch (error) {
|
||||
console.log(error) // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
}
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
import { getDriver, getNeode } from '@db/neo4j'
|
||||
|
||||
class Store {
|
||||
async init(next) {
|
||||
async init(errFn) {
|
||||
const neode = getNeode()
|
||||
const { driver } = neode
|
||||
const session = driver.session()
|
||||
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 constraints
|
||||
const session = neode.session()
|
||||
const txFreshIndicesConstrains = session.writeTransaction(async (txc) => {
|
||||
// drop all indices and constraints
|
||||
await txc.run('CALL apoc.schema.assert({},{},true)')
|
||||
/*
|
||||
#############################################
|
||||
# ADD YOUR CUSTOM INDICES & CONSTRAINS HERE #
|
||||
#############################################
|
||||
*/
|
||||
// Search indexes (also part of migration 20230320130345-fulltext-search-indexes)
|
||||
await txc.run(
|
||||
`CALL db.index.fulltext.createNodeIndex("user_fulltext_search",["User"],["name", "slug"])`,
|
||||
)
|
||||
await txc.run(
|
||||
`CALL db.index.fulltext.createNodeIndex("post_fulltext_search",["Post"],["title", "content"])`,
|
||||
)
|
||||
await txc.run(`CALL db.index.fulltext.createNodeIndex("tag_fulltext_search",["Tag"],["id"])`) // also part of migration 20200207080200-fulltext_index_for_tags
|
||||
// Search indexes (also part of migration 20220803060819-create_fulltext_indices_and_unique_keys_for_groups)
|
||||
await txc.run(`
|
||||
CALL db.index.fulltext.createNodeIndex("group_fulltext_search",["Group"],["name", "slug", "about", "description"])
|
||||
`)
|
||||
})
|
||||
try {
|
||||
await writeTxResultPromise
|
||||
// Due to limitations of neode in combination with the limitations of the community version of neo4j
|
||||
// we need to have all constraints and indexes defined here. They can not be properly migrated
|
||||
await txFreshIndicesConstrains
|
||||
|
||||
// You have to wait for the schema to install, else the constraints will not be present.
|
||||
// This is a type error of the library
|
||||
// eslint-disable-next-line @typescript-eslint/await-thenable
|
||||
await getNeode().schema.install()
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Successfully created database indices and constraints!')
|
||||
next()
|
||||
// eslint-disable-next-line no-catch-all/no-catch-all
|
||||
} catch (error) {
|
||||
console.log(error) // eslint-disable-line no-console
|
||||
next(error, null)
|
||||
errFn(error)
|
||||
} finally {
|
||||
session.close()
|
||||
driver.close()
|
||||
await session.close()
|
||||
neode.close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,11 +70,12 @@ class Store {
|
||||
}
|
||||
const [{ title: lastRun }] = migrations
|
||||
next(null, { lastRun, migrations })
|
||||
// eslint-disable-next-line no-catch-all/no-catch-all
|
||||
} catch (error) {
|
||||
console.log(error) // eslint-disable-line no-console
|
||||
next(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,13 +106,14 @@ class Store {
|
||||
try {
|
||||
await writeTxResultPromise
|
||||
next()
|
||||
// eslint-disable-next-line no-catch-all/no-catch-all
|
||||
} catch (error) {
|
||||
console.log(error) // eslint-disable-line no-console
|
||||
next(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Store
|
||||
export default Store
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
|
||||
import { getDriver } from '@db/neo4j'
|
||||
|
||||
export const description = ''
|
||||
|
||||
export async function up(next) {
|
||||
export async function up(_next) {
|
||||
const driver = getDriver()
|
||||
const session = driver.session()
|
||||
const transaction = session.beginTransaction()
|
||||
@ -11,7 +13,6 @@ export async function up(next) {
|
||||
// Implement your migration here.
|
||||
await transaction.run(``)
|
||||
await transaction.commit()
|
||||
next()
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error)
|
||||
@ -20,11 +21,11 @@ export async function up(next) {
|
||||
console.log('rolled back')
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(next) {
|
||||
export async function down(_next) {
|
||||
const driver = getDriver()
|
||||
const session = driver.session()
|
||||
const transaction = session.beginTransaction()
|
||||
@ -33,7 +34,6 @@ export async function down(next) {
|
||||
// Implement your migration here.
|
||||
await transaction.run(``)
|
||||
await transaction.commit()
|
||||
next()
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error)
|
||||
@ -42,6 +42,6 @@ export async function down(next) {
|
||||
console.log('rolled back')
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,16 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable promise/prefer-await-to-callbacks */
|
||||
import { throwError, concat } from 'rxjs'
|
||||
import { flatMap, mergeMap, map, catchError, filter } from 'rxjs/operators'
|
||||
import { getDriver } from '../neo4j'
|
||||
import normalizeEmail from '../../schema/resolvers//helpers/normalizeEmail'
|
||||
|
||||
import { getDriver } from '@db/neo4j'
|
||||
import normalizeEmail from '@graphql/resolvers/helpers/normalizeEmail'
|
||||
|
||||
export const description = `
|
||||
This migration merges duplicate :User and :EmailAddress nodes. It became
|
||||
@ -14,16 +23,19 @@ export const description = `
|
||||
`
|
||||
export function up(next) {
|
||||
const driver = getDriver()
|
||||
const rxSession = driver.rxSession()
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const rxSession = driver.rxSession() as any
|
||||
rxSession
|
||||
.beginTransaction()
|
||||
.pipe(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
flatMap((txc: any) =>
|
||||
concat(
|
||||
txc
|
||||
.run('MATCH (email:EmailAddress) RETURN email {.email}')
|
||||
.records()
|
||||
.pipe(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
map((record: any) => {
|
||||
const { email } = record.get('email')
|
||||
const normalizedEmail = normalizeEmail(email)
|
||||
@ -45,6 +57,7 @@ export function up(next) {
|
||||
)
|
||||
.records()
|
||||
.pipe(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
map((r: any) => ({
|
||||
oldEmail: email,
|
||||
email: r.get('email'),
|
||||
@ -58,7 +71,7 @@ export function up(next) {
|
||||
),
|
||||
)
|
||||
.subscribe({
|
||||
next: ({ user, email, oldUser, oldEmail }) =>
|
||||
next: ({ user, email, _oldUser, oldEmail }) =>
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`
|
||||
Merged:
|
||||
|
||||
@ -1,6 +1,15 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable promise/prefer-await-to-callbacks */
|
||||
import { throwError, concat } from 'rxjs'
|
||||
import { flatMap, mergeMap, map, catchError } from 'rxjs/operators'
|
||||
import { getDriver } from '../neo4j'
|
||||
|
||||
import { getDriver } from '@db/neo4j'
|
||||
|
||||
export const description = `
|
||||
This migration merges duplicate :Location nodes. It became
|
||||
@ -8,10 +17,12 @@ export const description = `
|
||||
`
|
||||
export function up(next) {
|
||||
const driver = getDriver()
|
||||
const rxSession = driver.rxSession()
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const rxSession = driver.rxSession() as any
|
||||
rxSession
|
||||
.beginTransaction()
|
||||
.pipe(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
flatMap((transaction: any) =>
|
||||
concat(
|
||||
transaction
|
||||
@ -23,6 +34,7 @@ export function up(next) {
|
||||
)
|
||||
.records()
|
||||
.pipe(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
map((record: any) => {
|
||||
const { id: locationId } = record.get('location')
|
||||
return { locationId }
|
||||
@ -40,6 +52,7 @@ export function up(next) {
|
||||
)
|
||||
.records()
|
||||
.pipe(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
map((record: any) => ({
|
||||
location: record.get('location'),
|
||||
updatedLocation: record.get('updatedLocation'),
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
|
||||
import { getDriver } from '@db/neo4j'
|
||||
|
||||
export const description = `
|
||||
This migration creates a MUTED relationship between two edges(:User) that have a pre-existing BLOCKED relationship.
|
||||
@ -8,7 +10,7 @@ export const description = `
|
||||
A blocked user will still be able to see your contributions, but will not be able to interact with them and vice versa.
|
||||
`
|
||||
|
||||
export async function up(next) {
|
||||
export async function up(_next) {
|
||||
const driver = getDriver()
|
||||
const session = driver.session()
|
||||
const transaction = session.beginTransaction()
|
||||
@ -21,6 +23,7 @@ export async function up(next) {
|
||||
`,
|
||||
)
|
||||
await transaction.commit()
|
||||
// eslint-disable-next-line no-catch-all/no-catch-all
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error)
|
||||
@ -28,19 +31,20 @@ export async function up(next) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('rolled back')
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
export function down(next) {
|
||||
export async function down(next) {
|
||||
const driver = getDriver()
|
||||
const session = driver.session()
|
||||
try {
|
||||
// Rollback your migration here.
|
||||
next()
|
||||
// next()
|
||||
// eslint-disable-next-line no-catch-all/no-catch-all
|
||||
} catch (err) {
|
||||
next(err)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||
/* eslint-disable @typescript-eslint/require-await */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
|
||||
import { getDriver } from '@db/neo4j'
|
||||
|
||||
export const description = `
|
||||
This migration swaps the value stored in Location.lat with the value
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
import { getDriver } from '@db/neo4j'
|
||||
|
||||
export const description =
|
||||
'This migration adds a fulltext index for the tags in order to search for Hasthags.'
|
||||
@ -9,10 +13,13 @@ export async function up(next) {
|
||||
const transaction = session.beginTransaction()
|
||||
|
||||
try {
|
||||
// We do do this in /src/db/migrate/store.ts
|
||||
/*
|
||||
await transaction.run(`
|
||||
CALL db.index.fulltext.createNodeIndex("tag_fulltext_search",["Tag"],["id"])
|
||||
`)
|
||||
await transaction.commit()
|
||||
*/
|
||||
next()
|
||||
} catch (error) {
|
||||
const { message } = error
|
||||
@ -28,7 +35,7 @@ export async function up(next) {
|
||||
throw new Error(error)
|
||||
}
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,10 +46,13 @@ export async function down(next) {
|
||||
|
||||
try {
|
||||
// Implement your migration here.
|
||||
// We do do this in /src/db/migrate/store.ts
|
||||
/*
|
||||
await transaction.run(`
|
||||
CALL db.index.fulltext.drop("tag_fulltext_search")
|
||||
`)
|
||||
await transaction.commit()
|
||||
*/
|
||||
next()
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
@ -52,6 +62,6 @@ export async function down(next) {
|
||||
console.log('rolled back')
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
import { getDriver } from '@db/neo4j'
|
||||
|
||||
export const description = `
|
||||
We introduced a new node label 'Image' and we need a primary key for it. Best
|
||||
@ -32,7 +36,7 @@ export async function up(next) {
|
||||
throw new Error(error)
|
||||
}
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +52,7 @@ export async function down(next) {
|
||||
`)
|
||||
await transaction.commit()
|
||||
next()
|
||||
// eslint-disable-next-line no-catch-all/no-catch-all
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error)
|
||||
@ -55,6 +60,6 @@ export async function down(next) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('rolled back')
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,107 +0,0 @@
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
import { existsSync, createReadStream } from 'fs'
|
||||
import path from 'path'
|
||||
import { S3 } from 'aws-sdk'
|
||||
import mime from 'mime-types'
|
||||
import s3Configs from '../../config'
|
||||
import https from 'https'
|
||||
|
||||
export const description = `
|
||||
Upload all image files to a S3 compatible object storage in order to reduce
|
||||
load on our backend.
|
||||
`
|
||||
|
||||
export async function up(next) {
|
||||
const driver = getDriver()
|
||||
const session = driver.session()
|
||||
const transaction = session.beginTransaction()
|
||||
const agent = new https.Agent({
|
||||
maxSockets: 5,
|
||||
})
|
||||
|
||||
const {
|
||||
AWS_ENDPOINT: endpoint,
|
||||
AWS_REGION: region,
|
||||
AWS_BUCKET: Bucket,
|
||||
S3_CONFIGURED,
|
||||
} = s3Configs
|
||||
|
||||
if (!S3_CONFIGURED) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('No S3 given, cannot upload image files')
|
||||
return
|
||||
}
|
||||
|
||||
const s3 = new S3({ region, endpoint, httpOptions: { agent } })
|
||||
try {
|
||||
// Implement your migration here.
|
||||
const { records } = await transaction.run('MATCH (image:Image) RETURN image.url as url')
|
||||
let urls = records.map((r) => r.get('url'))
|
||||
urls = urls.filter((url) => url.startsWith('/uploads'))
|
||||
const locations = await Promise.all(
|
||||
urls
|
||||
.map((url) => {
|
||||
return async () => {
|
||||
const { pathname } = new URL(url, 'http://example.org')
|
||||
const fileLocation = path.join(__dirname, `../../../public/${pathname}`)
|
||||
const s3Location = `original${pathname}`
|
||||
if (existsSync(fileLocation)) {
|
||||
const mimeType = mime.lookup(fileLocation)
|
||||
const params = {
|
||||
Bucket,
|
||||
Key: s3Location,
|
||||
ACL: 'public-read',
|
||||
ContentType: mimeType || 'image/jpeg',
|
||||
Body: createReadStream(fileLocation),
|
||||
}
|
||||
|
||||
const data = await s3.upload(params).promise()
|
||||
const { Location: spacesUrl } = data
|
||||
|
||||
const updatedRecord = await transaction.run(
|
||||
'MATCH (image:Image {url: $url}) SET image.url = $spacesUrl RETURN image.url as url',
|
||||
{ url, spacesUrl },
|
||||
)
|
||||
const [updatedUrl] = updatedRecord.records.map((record) => record.get('url'))
|
||||
return updatedUrl
|
||||
}
|
||||
}
|
||||
})
|
||||
.map((p) => p()),
|
||||
)
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('this is locations', locations)
|
||||
await transaction.commit()
|
||||
next()
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error)
|
||||
await transaction.rollback()
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('rolled back')
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(next) {
|
||||
const driver = getDriver()
|
||||
const session = driver.session()
|
||||
const transaction = session.beginTransaction()
|
||||
|
||||
try {
|
||||
// Implement your migration here.
|
||||
await transaction.run(``)
|
||||
await transaction.commit()
|
||||
next()
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error)
|
||||
await transaction.rollback()
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('rolled back')
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
|
||||
/* eslint-disable no-console */
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
import { getDriver } from '@db/neo4j'
|
||||
|
||||
export const description = `
|
||||
Refactor all our image properties on posts and users to a dedicated type
|
||||
@ -58,7 +61,7 @@ export async function up() {
|
||||
console.log('Created image nodes from all user avatars and post images.')
|
||||
printSummaries(stats)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,6 +99,6 @@ export async function down() {
|
||||
console.log('UNDO: Split images from users and posts.')
|
||||
printSummaries(stats)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
/* eslint-disable @typescript-eslint/require-await */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
|
||||
import { getDriver } from '@db/neo4j'
|
||||
|
||||
export const description =
|
||||
'We should not maintain obsolete attributes for users who have been deleted.'
|
||||
@ -20,7 +25,7 @@ export async function up(next) {
|
||||
`)
|
||||
try {
|
||||
// Implement your migration here.
|
||||
const users = await updateDeletedUserAttributes.records.map((record) => record.get('user'))
|
||||
const users = updateDeletedUserAttributes.records.map((record) => record.get('user'))
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(users)
|
||||
await transaction.commit()
|
||||
@ -33,7 +38,7 @@ export async function up(next) {
|
||||
console.log('rolled back')
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
/* eslint-disable @typescript-eslint/require-await */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
|
||||
import { getDriver } from '@db/neo4j'
|
||||
|
||||
export const description =
|
||||
'We should not maintain obsolete attributes for posts which have been deleted.'
|
||||
@ -22,7 +27,7 @@ export async function up(next) {
|
||||
`)
|
||||
try {
|
||||
// Implement your migration here.
|
||||
const posts = await updateDeletedPostsAttributes.records.map((record) => record.get('post'))
|
||||
const posts = updateDeletedPostsAttributes.records.map((record) => record.get('post'))
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(posts)
|
||||
await transaction.commit()
|
||||
@ -35,7 +40,7 @@ export async function up(next) {
|
||||
console.log('rolled back')
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,13 @@
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
import { existsSync } from 'fs'
|
||||
/* eslint-disable @typescript-eslint/require-await */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
|
||||
/* eslint-disable security/detect-non-literal-fs-filename */
|
||||
import { existsSync } from 'node:fs'
|
||||
|
||||
import { getDriver } from '@db/neo4j'
|
||||
|
||||
export const description = `
|
||||
In this review:
|
||||
@ -24,6 +32,7 @@ export async function up(next) {
|
||||
const urls = records.map((record) => record.get('url'))
|
||||
const danglingUrls = urls.filter((url) => {
|
||||
const fileLocation = `public${url}`
|
||||
// eslint-disable-next-line n/no-sync
|
||||
return !existsSync(fileLocation)
|
||||
})
|
||||
await transaction.run(
|
||||
@ -52,7 +61,7 @@ export async function up(next) {
|
||||
console.log('rolled back')
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
'use strict'
|
||||
|
||||
module.exports.up = function (next) {
|
||||
next()
|
||||
}
|
||||
export async function up(_next) {}
|
||||
|
||||
module.exports.down = function (next) {
|
||||
next()
|
||||
}
|
||||
export async function down(_next) {}
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
|
||||
import { getDriver } from '@db/neo4j'
|
||||
|
||||
export const description = `
|
||||
This migration adds the clickedCount property to all posts, setting it to 0.
|
||||
`
|
||||
|
||||
module.exports.up = async function (next) {
|
||||
export async function up(_next) {
|
||||
const driver = getDriver()
|
||||
const session = driver.session()
|
||||
const transaction = session.beginTransaction()
|
||||
@ -15,7 +17,6 @@ module.exports.up = async function (next) {
|
||||
SET p.clickedCount = 0
|
||||
`)
|
||||
await transaction.commit()
|
||||
next()
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error)
|
||||
@ -24,11 +25,11 @@ module.exports.up = async function (next) {
|
||||
console.log('rolled back')
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.down = async function (next) {
|
||||
export async function down(_next) {
|
||||
const driver = getDriver()
|
||||
const session = driver.session()
|
||||
const transaction = session.beginTransaction()
|
||||
@ -39,7 +40,6 @@ module.exports.down = async function (next) {
|
||||
REMOVE p.clickedCount
|
||||
`)
|
||||
await transaction.commit()
|
||||
next()
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error)
|
||||
@ -48,6 +48,6 @@ module.exports.down = async function (next) {
|
||||
console.log('rolled back')
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
|
||||