diff --git a/.github/workflows/docker-push.yml b/.github/workflows/docker-push.yml
index 643c5436d..406d8304b 100644
--- a/.github/workflows/docker-push.yml
+++ b/.github/workflows/docker-push.yml
@@ -61,14 +61,14 @@ jobs:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7
- name: Log in to the Container registry
- uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
+ 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@70b2cdc6480c1a8b86edf1777157f8f437de2166
+ uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@@ -81,7 +81,7 @@ jobs:
type=sha
- name: Build and push Docker images
id: push
- uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75
+ uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4
with:
context: ${{ matrix.app.context }}
target: ${{ matrix.app.target }}
diff --git a/backend/.eslintrc.cjs b/backend/.eslintrc.cjs
new file mode 100644
index 000000000..e781e15b7
--- /dev/null
+++ b/backend/.eslintrc.cjs
@@ -0,0 +1,209 @@
+// 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:prettier/recommended',
+ 'plugin:import/recommended',
+ 'plugin:import/typescript',
+ 'plugin:security/recommended-legacy',
+ 'plugin:@eslint-community/eslint-comments/recommended',
+ ],
+ settings: {
+ 'import/parsers': {
+ '@typescript-eslint/parser': ['.ts', '.tsx'],
+ },
+ 'import/resolver': {
+ typescript: {
+ project: ['./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 scriptless vue files
+ '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',
+ },
+ },
+ ],
+};
diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js
deleted file mode 100644
index cc5440d82..000000000
--- a/backend/.eslintrc.js
+++ /dev/null
@@ -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',
- },
- },
- ],
-};
diff --git a/backend/package.json b/backend/package.json
index 9c52815a1..2cff584d2 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -76,7 +76,7 @@
"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",
@@ -95,6 +95,7 @@
"xregexp": "^5.1.2"
},
"devDependencies": {
+ "@eslint-community/eslint-plugin-eslint-comments": "^4.4.1",
"@faker-js/faker": "9.6.0",
"@types/jest": "^29.5.14",
"@types/node": "^22.14.0",
@@ -108,6 +109,7 @@
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-n": "^16.6.2",
+ "eslint-plugin-no-catch-all": "^1.1.0",
"eslint-plugin-prettier": "^5.2.6",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-security": "^3.0.1",
@@ -121,7 +123,9 @@
},
"resolutions": {
"**/**/fs-capacitor": "^6.2.0",
- "**/graphql-upload": "^11.0.0",
- "nan": "2.17.0"
+ "**/graphql-upload": "^11.0.0"
+ },
+ "engines": {
+ "node": ">=20.12.1"
}
}
diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts
index 9f03622a5..e6a02a87d 100644
--- a/backend/src/config/index.ts
+++ b/backend/src/config/index.ts
@@ -1,11 +1,14 @@
-import dotenv from 'dotenv'
+/* eslint-disable n/no-process-env */
+/* eslint-disable n/no-unpublished-require */
+/* eslint-disable n/no-missing-require */
+import { config } from 'dotenv'
import emails from './emails'
import metadata from './metadata'
// Load env file
if (require.resolve) {
try {
- dotenv.config({ path: require.resolve('../../.env') })
+ config({ path: require.resolve('../../.env') })
} catch (error) {
// This error is thrown when the .env is not found
if (error.code !== 'MODULE_NOT_FOUND') {
diff --git a/backend/src/db/clean.ts b/backend/src/db/clean.ts
index eac26036c..ae5ce7320 100644
--- a/backend/src/db/clean.ts
+++ b/backend/src/db/clean.ts
@@ -1,5 +1,6 @@
+/* eslint-disable n/no-process-exit */
import CONFIG from '../config'
-import { cleanDatabase } from '../db/factories'
+import { cleanDatabase } from './factories'
if (CONFIG.PRODUCTION && !CONFIG.PRODUCTION_DB_CLEAN_ALLOW) {
throw new Error(`You cannot clean the database in a non-staging and real production environment!`)
@@ -10,6 +11,7 @@ if (CONFIG.PRODUCTION && !CONFIG.PRODUCTION_DB_CLEAN_ALLOW) {
await cleanDatabase()
console.log('Successfully deleted all nodes and relations!') // eslint-disable-line no-console
process.exit(0)
+ // eslint-disable-next-line no-catch-all/no-catch-all
} catch (err) {
console.log(`Error occurred deleting the nodes and relations (reset the db)\n\n${err}`) // eslint-disable-line no-console
process.exit(1)
diff --git a/backend/src/db/compiler.ts b/backend/src/db/compiler.ts
index 8b09ac9c3..4dd36f16b 100644
--- a/backend/src/db/compiler.ts
+++ b/backend/src/db/compiler.ts
@@ -1,2 +1,5 @@
+/* eslint-disable import/no-commonjs */
+// eslint-disable-next-line n/no-unpublished-require
const tsNode = require('ts-node')
+
module.exports = tsNode.register
diff --git a/backend/src/db/migrate/store.ts b/backend/src/db/migrate/store.ts
index 0a9788b9a..6f8d248d9 100644
--- a/backend/src/db/migrate/store.ts
+++ b/backend/src/db/migrate/store.ts
@@ -1,4 +1,4 @@
-import { getDriver, getNeode } from '../../db/neo4j'
+import { getDriver, getNeode } from '../neo4j'
import { hashSync } from 'bcryptjs'
import { v4 as uuid } from 'uuid'
import { categories } from '../../constants/categories'
@@ -30,6 +30,7 @@ const createCategories = async (session) => {
try {
await createCategoriesTxResultPromise
console.log('Successfully created categories!') // eslint-disable-line no-console
+ // eslint-disable-next-line no-catch-all/no-catch-all
} catch (error) {
console.log(`Error creating categories: ${error}`) // eslint-disable-line no-console
}
@@ -44,6 +45,7 @@ const createDefaultAdminUser = async (session) => {
try {
const userCount = parseInt(String(await readTxResultPromise))
if (userCount === 0) createAdmin = true
+ // eslint-disable-next-line no-catch-all/no-catch-all
} catch (error) {
console.log(error) // eslint-disable-line no-console
}
@@ -70,6 +72,7 @@ const createDefaultAdminUser = async (session) => {
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
}
@@ -92,6 +95,7 @@ class Store {
// 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)
@@ -121,6 +125,7 @@ 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)
@@ -156,6 +161,7 @@ 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)
@@ -165,4 +171,4 @@ class Store {
}
}
-module.exports = Store
+export default Store
diff --git a/backend/src/db/migrate/template.ts b/backend/src/db/migrate/template.ts
index 72bfc9b1b..9661dcf9c 100644
--- a/backend/src/db/migrate/template.ts
+++ b/backend/src/db/migrate/template.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = ''
diff --git a/backend/src/db/migrations-examples/20200123150105-merge_duplicate_user_accounts.ts b/backend/src/db/migrations-examples/20200123150105-merge_duplicate_user_accounts.ts
index 7d98d9dcc..6eb9e0ed0 100644
--- a/backend/src/db/migrations-examples/20200123150105-merge_duplicate_user_accounts.ts
+++ b/backend/src/db/migrations-examples/20200123150105-merge_duplicate_user_accounts.ts
@@ -1,7 +1,8 @@
+/* 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 normalizeEmail from '../../schema/resolvers/helpers/normalizeEmail'
export const description = `
This migration merges duplicate :User and :EmailAddress nodes. It became
diff --git a/backend/src/db/migrations-examples/20200123150110-merge_duplicate_location_nodes.ts b/backend/src/db/migrations-examples/20200123150110-merge_duplicate_location_nodes.ts
index 10b77c6dd..23d1d55bc 100644
--- a/backend/src/db/migrations-examples/20200123150110-merge_duplicate_location_nodes.ts
+++ b/backend/src/db/migrations-examples/20200123150110-merge_duplicate_location_nodes.ts
@@ -1,3 +1,4 @@
+/* eslint-disable promise/prefer-await-to-callbacks */
import { throwError, concat } from 'rxjs'
import { flatMap, mergeMap, map, catchError } from 'rxjs/operators'
import { getDriver } from '../neo4j'
diff --git a/backend/src/db/migrations-examples/20200127110135-create_muted_relationship_between_existing_blocked_relationships.ts b/backend/src/db/migrations-examples/20200127110135-create_muted_relationship_between_existing_blocked_relationships.ts
index ce46be9d6..49506aae3 100644
--- a/backend/src/db/migrations-examples/20200127110135-create_muted_relationship_between_existing_blocked_relationships.ts
+++ b/backend/src/db/migrations-examples/20200127110135-create_muted_relationship_between_existing_blocked_relationships.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = `
This migration creates a MUTED relationship between two edges(:User) that have a pre-existing BLOCKED relationship.
@@ -21,6 +21,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)
@@ -38,6 +39,7 @@ export function down(next) {
try {
// Rollback your migration here.
next()
+ // eslint-disable-next-line no-catch-all/no-catch-all
} catch (err) {
next(err)
} finally {
diff --git a/backend/src/db/migrations-examples/20200206190233-swap_latitude_with_longitude.ts b/backend/src/db/migrations-examples/20200206190233-swap_latitude_with_longitude.ts
index 94a2f442d..73c329bfc 100644
--- a/backend/src/db/migrations-examples/20200206190233-swap_latitude_with_longitude.ts
+++ b/backend/src/db/migrations-examples/20200206190233-swap_latitude_with_longitude.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = `
This migration swaps the value stored in Location.lat with the value
diff --git a/backend/src/db/migrations-examples/20200207080200-fulltext_index_for_tags.ts b/backend/src/db/migrations-examples/20200207080200-fulltext_index_for_tags.ts
index ffcd3d4b6..8ef6976a3 100644
--- a/backend/src/db/migrations-examples/20200207080200-fulltext_index_for_tags.ts
+++ b/backend/src/db/migrations-examples/20200207080200-fulltext_index_for_tags.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description =
'This migration adds a fulltext index for the tags in order to search for Hasthags.'
diff --git a/backend/src/db/migrations-examples/20200213230248-add_unique_index_to_image_url.ts b/backend/src/db/migrations-examples/20200213230248-add_unique_index_to_image_url.ts
index 4582d938c..e949713b8 100644
--- a/backend/src/db/migrations-examples/20200213230248-add_unique_index_to_image_url.ts
+++ b/backend/src/db/migrations-examples/20200213230248-add_unique_index_to_image_url.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = `
We introduced a new node label 'Image' and we need a primary key for it. Best
@@ -48,6 +48,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)
diff --git a/backend/src/db/migrations-examples/20200312140328-bulk_upload_to_s3.ts b/backend/src/db/migrations-examples/20200312140328-bulk_upload_to_s3.ts
index 356004237..7818001fb 100644
--- a/backend/src/db/migrations-examples/20200312140328-bulk_upload_to_s3.ts
+++ b/backend/src/db/migrations-examples/20200312140328-bulk_upload_to_s3.ts
@@ -1,4 +1,5 @@
-import { getDriver } from '../../db/neo4j'
+/* eslint-disable security/detect-non-literal-fs-filename */
+import { getDriver } from '../neo4j'
import { existsSync, createReadStream } from 'fs'
import path from 'path'
import { S3 } from 'aws-sdk'
@@ -95,6 +96,7 @@ export async function down(next) {
await transaction.run(``)
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)
diff --git a/backend/src/db/migrations-examples/20200320200315-refactor_all_images_to_separate_type.ts b/backend/src/db/migrations-examples/20200320200315-refactor_all_images_to_separate_type.ts
index 1ad5e645d..6f347b99b 100644
--- a/backend/src/db/migrations-examples/20200320200315-refactor_all_images_to_separate_type.ts
+++ b/backend/src/db/migrations-examples/20200320200315-refactor_all_images_to_separate_type.ts
@@ -1,5 +1,5 @@
/* eslint-disable no-console */
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = `
Refactor all our image properties on posts and users to a dedicated type
diff --git a/backend/src/db/migrations-examples/20200323140300-remove_deleted_users_obsolete_attributes.ts b/backend/src/db/migrations-examples/20200323140300-remove_deleted_users_obsolete_attributes.ts
index e4852f79c..a8880d8e8 100644
--- a/backend/src/db/migrations-examples/20200323140300-remove_deleted_users_obsolete_attributes.ts
+++ b/backend/src/db/migrations-examples/20200323140300-remove_deleted_users_obsolete_attributes.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description =
'We should not maintain obsolete attributes for users who have been deleted.'
diff --git a/backend/src/db/migrations-examples/20200323160336-remove_deleted_posts_obsolete_attributes.ts b/backend/src/db/migrations-examples/20200323160336-remove_deleted_posts_obsolete_attributes.ts
index 8c1efe5c6..70d81e5c0 100644
--- a/backend/src/db/migrations-examples/20200323160336-remove_deleted_posts_obsolete_attributes.ts
+++ b/backend/src/db/migrations-examples/20200323160336-remove_deleted_posts_obsolete_attributes.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description =
'We should not maintain obsolete attributes for posts which have been deleted.'
diff --git a/backend/src/db/migrations-examples/20200326160326-remove_dangling_image_urls.ts b/backend/src/db/migrations-examples/20200326160326-remove_dangling_image_urls.ts
index a77ac360c..9d0d44f26 100644
--- a/backend/src/db/migrations-examples/20200326160326-remove_dangling_image_urls.ts
+++ b/backend/src/db/migrations-examples/20200326160326-remove_dangling_image_urls.ts
@@ -1,4 +1,5 @@
-import { getDriver } from '../../db/neo4j'
+/* eslint-disable security/detect-non-literal-fs-filename */
+import { getDriver } from '../neo4j'
import { existsSync } from 'fs'
export const description = `
diff --git a/backend/src/db/migrations/1613589876420-null_mutation.ts b/backend/src/db/migrations/1613589876420-null_mutation.ts
index f158549de..8efe667be 100644
--- a/backend/src/db/migrations/1613589876420-null_mutation.ts
+++ b/backend/src/db/migrations/1613589876420-null_mutation.ts
@@ -1,9 +1,9 @@
'use strict'
-module.exports.up = function (next) {
+export async function up(next) {
next()
}
-module.exports.down = function (next) {
+export async function down(next) {
next()
}
diff --git a/backend/src/db/migrations/1614023644903-add-clickedCount-to-posts.ts b/backend/src/db/migrations/1614023644903-add-clickedCount-to-posts.ts
index ff95a25df..0d8f28e1b 100644
--- a/backend/src/db/migrations/1614023644903-add-clickedCount-to-posts.ts
+++ b/backend/src/db/migrations/1614023644903-add-clickedCount-to-posts.ts
@@ -1,10 +1,10 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../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()
@@ -28,7 +28,7 @@ module.exports.up = async function (next) {
}
}
-module.exports.down = async function (next) {
+export async function down(next) {
const driver = getDriver()
const session = driver.session()
const transaction = session.beginTransaction()
diff --git a/backend/src/db/migrations/1614177130817-add-viewedTeaserCount-to-posts.ts b/backend/src/db/migrations/1614177130817-add-viewedTeaserCount-to-posts.ts
index ee1fad124..31b9d69ff 100644
--- a/backend/src/db/migrations/1614177130817-add-viewedTeaserCount-to-posts.ts
+++ b/backend/src/db/migrations/1614177130817-add-viewedTeaserCount-to-posts.ts
@@ -1,10 +1,10 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = `
This migration adds the viewedTeaserCount 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()
@@ -28,7 +28,7 @@ module.exports.up = async function (next) {
}
}
-module.exports.down = async function (next) {
+export async function down(next) {
const driver = getDriver()
const session = driver.session()
const transaction = session.beginTransaction()
diff --git a/backend/src/db/migrations/20210506150512-add-donations-node.ts b/backend/src/db/migrations/20210506150512-add-donations-node.ts
index 6cbc1e897..b7e0e026a 100644
--- a/backend/src/db/migrations/20210506150512-add-donations-node.ts
+++ b/backend/src/db/migrations/20210506150512-add-donations-node.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
import { v4 as uuid } from 'uuid'
export const description =
diff --git a/backend/src/db/migrations/20210923140939-add-sendNotificationEmails-property-to-all-users.ts b/backend/src/db/migrations/20210923140939-add-sendNotificationEmails-property-to-all-users.ts
index 0d1f4fb91..a555efa3a 100644
--- a/backend/src/db/migrations/20210923140939-add-sendNotificationEmails-property-to-all-users.ts
+++ b/backend/src/db/migrations/20210923140939-add-sendNotificationEmails-property-to-all-users.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = ''
diff --git a/backend/src/db/migrations/20220803060819-create_fulltext_indices_and_unique_keys_for_groups.ts b/backend/src/db/migrations/20220803060819-create_fulltext_indices_and_unique_keys_for_groups.ts
index 63e40c72b..586a090f4 100644
--- a/backend/src/db/migrations/20220803060819-create_fulltext_indices_and_unique_keys_for_groups.ts
+++ b/backend/src/db/migrations/20220803060819-create_fulltext_indices_and_unique_keys_for_groups.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = `
We introduced a new node label 'Group' and we need two primary keys 'id' and 'slug' for it.
diff --git a/backend/src/db/migrations/20230320130345-fulltext-search-indexes.ts b/backend/src/db/migrations/20230320130345-fulltext-search-indexes.ts
index 40ebc6c2e..34cf7b7a2 100644
--- a/backend/src/db/migrations/20230320130345-fulltext-search-indexes.ts
+++ b/backend/src/db/migrations/20230320130345-fulltext-search-indexes.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = ''
diff --git a/backend/src/db/migrations/20230329150329-article-label-for-posts.ts b/backend/src/db/migrations/20230329150329-article-label-for-posts.ts
index 3cf435203..2ca705bf4 100644
--- a/backend/src/db/migrations/20230329150329-article-label-for-posts.ts
+++ b/backend/src/db/migrations/20230329150329-article-label-for-posts.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = 'Add to all existing posts the Article label'
diff --git a/backend/src/db/migrations/20230608130637-add-postType-property.ts b/backend/src/db/migrations/20230608130637-add-postType-property.ts
index 433577715..83c2f4ed3 100644
--- a/backend/src/db/migrations/20230608130637-add-postType-property.ts
+++ b/backend/src/db/migrations/20230608130637-add-postType-property.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = 'Add postType property Article to all posts'
diff --git a/backend/src/db/migrations/20231017141022-fix-event-dates.ts b/backend/src/db/migrations/20231017141022-fix-event-dates.ts
index 3c4302f13..e793e173c 100644
--- a/backend/src/db/migrations/20231017141022-fix-event-dates.ts
+++ b/backend/src/db/migrations/20231017141022-fix-event-dates.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = `
Transform event start and end date of format 'YYYY-MM-DD HH:MM:SS' in CEST
diff --git a/backend/src/db/migrations/20250331130323-author-observes-own-post.ts b/backend/src/db/migrations/20250331130323-author-observes-own-post.ts
index 7343d5010..026f7f29c 100644
--- a/backend/src/db/migrations/20250331130323-author-observes-own-post.ts
+++ b/backend/src/db/migrations/20250331130323-author-observes-own-post.ts
@@ -1,4 +1,4 @@
-import { getDriver } from '../../db/neo4j'
+import { getDriver } from '../neo4j'
export const description = `
All authors observe their posts.
diff --git a/backend/src/db/neo4j.ts b/backend/src/db/neo4j.ts
index 78b52237e..dc5bf2764 100644
--- a/backend/src/db/neo4j.ts
+++ b/backend/src/db/neo4j.ts
@@ -1,5 +1,6 @@
+/* eslint-disable import/no-named-as-default-member */
import neo4j from 'neo4j-driver'
-import CONFIG from './../config'
+import CONFIG from '../config'
import Neode from 'neode'
import models from '../models'
diff --git a/backend/src/db/seed.ts b/backend/src/db/seed.ts
index bff236f64..4183b8ce5 100644
--- a/backend/src/db/seed.ts
+++ b/backend/src/db/seed.ts
@@ -1,10 +1,11 @@
+/* eslint-disable n/no-process-exit */
import sample from 'lodash/sample'
import { createTestClient } from 'apollo-server-testing'
import CONFIG from '../config'
import createServer from '../server'
import { faker } from '@faker-js/faker'
-import Factory from '../db/factories'
-import { getNeode, getDriver } from '../db/neo4j'
+import Factory from './factories'
+import { getNeode, getDriver } from './neo4j'
import {
createGroupMutation,
joinGroupMutation,
@@ -1565,6 +1566,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
await driver.close()
await neode.close()
process.exit(0)
+ // eslint-disable-next-line no-catch-all/no-catch-all
} catch (err) {
/* eslint-disable-next-line no-console */
console.error(err)
diff --git a/backend/src/helpers/asyncForEach.ts b/backend/src/helpers/asyncForEach.ts
index 5577cce14..00b0f85a3 100644
--- a/backend/src/helpers/asyncForEach.ts
+++ b/backend/src/helpers/asyncForEach.ts
@@ -1,3 +1,5 @@
+/* eslint-disable promise/prefer-await-to-callbacks */
+/* eslint-disable security/detect-object-injection */
/**
* Provide a way to iterate for each element in an array while waiting for async functions to finish
*
diff --git a/backend/src/helpers/jest.ts b/backend/src/helpers/jest.ts
index 09744e9f2..f1a0deb15 100644
--- a/backend/src/helpers/jest.ts
+++ b/backend/src/helpers/jest.ts
@@ -1,3 +1,4 @@
+/* eslint-disable promise/avoid-new */
// sometime we have to wait to check a db state by having a look into the db in a certain moment
// or we wait a bit to check if we missed to set an await somewhere
// see: https://www.sitepoint.com/delay-sleep-pause-wait/
diff --git a/backend/src/helpers/walkRecursive.ts b/backend/src/helpers/walkRecursive.ts
index f3be67575..4937f61bb 100644
--- a/backend/src/helpers/walkRecursive.ts
+++ b/backend/src/helpers/walkRecursive.ts
@@ -1,3 +1,5 @@
+/* eslint-disable promise/prefer-await-to-callbacks */
+/* eslint-disable security/detect-object-injection */
/**
* iterate through all fields and replace it with the callback result
* @property data Array
diff --git a/backend/src/jwt/decode.ts b/backend/src/jwt/decode.ts
index e02dcc8d4..45888dead 100644
--- a/backend/src/jwt/decode.ts
+++ b/backend/src/jwt/decode.ts
@@ -1,5 +1,5 @@
import jwt from 'jsonwebtoken'
-import CONFIG from './../config'
+import CONFIG from '../config'
export default async (driver, authorizationHeader) => {
if (!authorizationHeader) return null
@@ -8,6 +8,7 @@ export default async (driver, authorizationHeader) => {
try {
const decoded = await jwt.verify(token, CONFIG.JWT_SECRET)
id = decoded.sub
+ // eslint-disable-next-line no-catch-all/no-catch-all
} catch (err) {
return null
}
diff --git a/backend/src/jwt/encode.spec.ts b/backend/src/jwt/encode.spec.ts
index 21ebdffec..37775eb55 100644
--- a/backend/src/jwt/encode.spec.ts
+++ b/backend/src/jwt/encode.spec.ts
@@ -1,6 +1,6 @@
import encode from './encode'
import jwt from 'jsonwebtoken'
-import CONFIG from './../config'
+import CONFIG from '../config'
describe('encode', () => {
let payload
diff --git a/backend/src/jwt/encode.ts b/backend/src/jwt/encode.ts
index baeb62d3d..0df81fa02 100644
--- a/backend/src/jwt/encode.ts
+++ b/backend/src/jwt/encode.ts
@@ -1,5 +1,5 @@
import jwt from 'jsonwebtoken'
-import CONFIG from './../config'
+import CONFIG from '../config'
// Generate an Access Token for the given User ID
export default function encode(user) {
diff --git a/backend/src/middleware/hashtags/extractHashtags.ts b/backend/src/middleware/hashtags/extractHashtags.ts
index 670673bf4..fc7a93d17 100644
--- a/backend/src/middleware/hashtags/extractHashtags.ts
+++ b/backend/src/middleware/hashtags/extractHashtags.ts
@@ -1,4 +1,5 @@
-import * as cheerio from 'cheerio'
+import { load } from 'cheerio'
+// eslint-disable-next-line import/extensions
import { exec, build } from 'xregexp/xregexp-all.js'
// formats of a Hashtag:
// https://en.wikipedia.org/w/index.php?title=Hashtag&oldid=905141980#Style
@@ -10,7 +11,7 @@ const regX = build('^((\\pL+[\\pL0-9]*)|([0-9]+\\pL+[\\pL0-9]*))$')
export default function (content?) {
if (!content) return []
- const $ = cheerio.load(content)
+ const $ = load(content)
// We can not search for class '.hashtag', because the classes are removed at the 'xss' middleware.
// But we have to know, which Hashtags are removed from the content as well, so we search for the 'a' html-tag.
const ids = $('a[data-hashtag-id]')
diff --git a/backend/src/middleware/hashtags/hashtagsMiddleware.ts b/backend/src/middleware/hashtags/hashtagsMiddleware.ts
index 985cd3c92..76939d59d 100644
--- a/backend/src/middleware/hashtags/hashtagsMiddleware.ts
+++ b/backend/src/middleware/hashtags/hashtagsMiddleware.ts
@@ -1,4 +1,4 @@
-import extractHashtags from '../hashtags/extractHashtags'
+import extractHashtags from './extractHashtags'
const updateHashtagsOfPost = async (postId, hashtags, context) => {
if (!hashtags.length) return
diff --git a/backend/src/middleware/helpers/cleanHtml.ts b/backend/src/middleware/helpers/cleanHtml.ts
index 72129274c..04d6deae4 100644
--- a/backend/src/middleware/helpers/cleanHtml.ts
+++ b/backend/src/middleware/helpers/cleanHtml.ts
@@ -1,3 +1,4 @@
+/* eslint-disable security/detect-unsafe-regex */
import sanitizeHtml from 'sanitize-html'
import linkifyHtml from 'linkify-html'
diff --git a/backend/src/middleware/helpers/email/sendMail.ts b/backend/src/middleware/helpers/email/sendMail.ts
index c0e54e7f7..6c1e0d8ba 100644
--- a/backend/src/middleware/helpers/email/sendMail.ts
+++ b/backend/src/middleware/helpers/email/sendMail.ts
@@ -1,5 +1,5 @@
import CONFIG from '../../../config'
-import { cleanHtml } from '../../../middleware/helpers/cleanHtml'
+import { cleanHtml } from '../cleanHtml'
import nodemailer from 'nodemailer'
import { htmlToText } from 'nodemailer-html-to-text'
diff --git a/backend/src/middleware/helpers/email/templateBuilder.spec.ts b/backend/src/middleware/helpers/email/templateBuilder.spec.ts
index cb516c0a9..437672a9a 100644
--- a/backend/src/middleware/helpers/email/templateBuilder.spec.ts
+++ b/backend/src/middleware/helpers/email/templateBuilder.spec.ts
@@ -6,6 +6,7 @@ import {
resetPasswordTemplate,
wrongAccountTemplate,
notificationTemplate,
+ chatMessageTemplate,
} from './templateBuilder'
const englishHint = 'English version below!'
@@ -34,6 +35,12 @@ const resetPasswordTemplateData = () => ({
name: 'Mr Example',
},
})
+const chatMessageTemplateData = {
+ email: 'test@example.org',
+ variables: {
+ name: 'Mr Example',
+ },
+}
const wrongAccountTemplateData = () => ({
email: 'test@example.org',
variables: {},
@@ -163,6 +170,31 @@ describe('templateBuilder', () => {
})
})
+ describe('chatMessageTemplate', () => {
+ describe('multi language', () => {
+ it('e-mail is build with all data', () => {
+ const subject = 'Neue Chatnachricht | New chat message'
+ const actionUrl = new URL('/chat', CONFIG.CLIENT_URI).toString()
+ const enContent = 'You have received a new chat message.'
+ const deContent = 'Du hast eine neue Chatnachricht erhalten.'
+ testEmailData(null, chatMessageTemplate, chatMessageTemplateData, [
+ ...textsStandard,
+ {
+ templPropName: 'subject',
+ isContaining: false,
+ text: subject,
+ },
+ englishHint,
+ actionUrl,
+ chatMessageTemplateData.variables.name,
+ enContent,
+ deContent,
+ supportUrl,
+ ])
+ })
+ })
+ })
+
describe('wrongAccountTemplate', () => {
describe('multi language', () => {
it('e-mail is build with all data', () => {
diff --git a/backend/src/middleware/helpers/email/templateBuilder.ts b/backend/src/middleware/helpers/email/templateBuilder.ts
index 78d7a9bf9..398cbabf9 100644
--- a/backend/src/middleware/helpers/email/templateBuilder.ts
+++ b/backend/src/middleware/helpers/email/templateBuilder.ts
@@ -1,3 +1,4 @@
+/* eslint-disable import/no-namespace */
import mustache from 'mustache'
import CONFIG from '../../../config'
import metadata from '../../../config/metadata'
@@ -71,6 +72,19 @@ export const resetPasswordTemplate = ({ email, variables: { nonce, name } }) =>
}
}
+export const chatMessageTemplate = ({ email, variables: { name } }) => {
+ const subject = 'Neue Chatnachricht | New chat message'
+ const actionUrl = new URL('/chat', CONFIG.CLIENT_URI)
+ const renderParams = { ...defaultParams, englishHint, actionUrl, name, subject }
+
+ return {
+ from,
+ to: email,
+ subject,
+ html: mustache.render(templates.layout, renderParams, { content: templates.chatMessage }),
+ }
+}
+
export const wrongAccountTemplate = ({ email, _variables = {} }) => {
const subject = 'Falsche Mailadresse? | Wrong E-mail?'
const actionUrl = new URL('/password-reset/request', CONFIG.CLIENT_URI)
diff --git a/backend/src/middleware/helpers/email/templates/chatMessage.html b/backend/src/middleware/helpers/email/templates/chatMessage.html
new file mode 100644
index 000000000..0b1bacb08
--- /dev/null
+++ b/backend/src/middleware/helpers/email/templates/chatMessage.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ Hallo {{ name }}!
+ Du hast eine neue Chatnachricht erhalten.
+ |
+
+
+ |
+
+
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ Hello {{ name }}!
+ You have received a new chat message.
+ |
+
+
+ |
+
+
+
+ |
+
+
+ |
+
+
+
+
+
diff --git a/backend/src/middleware/helpers/email/templates/de/index.ts b/backend/src/middleware/helpers/email/templates/de/index.ts
index 0f9d13c36..f29e2c485 100644
--- a/backend/src/middleware/helpers/email/templates/de/index.ts
+++ b/backend/src/middleware/helpers/email/templates/de/index.ts
@@ -1,3 +1,4 @@
+/* eslint-disable security/detect-non-literal-fs-filename */
import fs from 'fs'
import path from 'path'
diff --git a/backend/src/middleware/helpers/email/templates/en/index.ts b/backend/src/middleware/helpers/email/templates/en/index.ts
index 0f9d13c36..f29e2c485 100644
--- a/backend/src/middleware/helpers/email/templates/en/index.ts
+++ b/backend/src/middleware/helpers/email/templates/en/index.ts
@@ -1,3 +1,4 @@
+/* eslint-disable security/detect-non-literal-fs-filename */
import fs from 'fs'
import path from 'path'
diff --git a/backend/src/middleware/helpers/email/templates/index.ts b/backend/src/middleware/helpers/email/templates/index.ts
index b8ae01bdb..bcb5c2b64 100644
--- a/backend/src/middleware/helpers/email/templates/index.ts
+++ b/backend/src/middleware/helpers/email/templates/index.ts
@@ -1,3 +1,4 @@
+/* eslint-disable security/detect-non-literal-fs-filename */
import fs from 'fs'
import path from 'path'
@@ -7,5 +8,6 @@ export const signup = readFile('./signup.html')
export const passwordReset = readFile('./resetPassword.html')
export const wrongAccount = readFile('./wrongAccount.html')
export const emailVerification = readFile('./emailVerification.html')
+export const chatMessage = readFile('./chatMessage.html')
export const layout = readFile('./layout.html')
diff --git a/backend/src/middleware/helpers/isUserOnline.spec.ts b/backend/src/middleware/helpers/isUserOnline.spec.ts
new file mode 100644
index 000000000..bf2cb8d17
--- /dev/null
+++ b/backend/src/middleware/helpers/isUserOnline.spec.ts
@@ -0,0 +1,46 @@
+import { isUserOnline } from './isUserOnline'
+
+let user
+
+describe('isUserOnline', () => {
+ beforeEach(() => {
+ user = {
+ properties: {
+ lastActiveAt: null,
+ awaySince: null,
+ lastOnlineStatus: null,
+ },
+ }
+ })
+ describe('user has lastOnlineStatus `online`', () => {
+ it('returns true if he was active within the last 90 seconds', () => {
+ user.properties.lastOnlineStatus = 'online'
+ user.properties.lastActiveAt = new Date()
+ expect(isUserOnline(user)).toBe(true)
+ })
+ it('returns false if he was not active within the last 90 seconds', () => {
+ user.properties.lastOnlineStatus = 'online'
+ user.properties.lastActiveAt = new Date().getTime() - 90001
+ expect(isUserOnline(user)).toBe(false)
+ })
+ })
+
+ describe('user has lastOnlineStatus `away`', () => {
+ it('returns true if he went away less then 180 seconds ago', () => {
+ user.properties.lastOnlineStatus = 'away'
+ user.properties.awaySince = new Date()
+ expect(isUserOnline(user)).toBe(true)
+ })
+ it('returns false if he went away more then 180 seconds ago', () => {
+ user.properties.lastOnlineStatus = 'away'
+ user.properties.awaySince = new Date().getTime() - 180001
+ expect(isUserOnline(user)).toBe(false)
+ })
+ })
+
+ describe('user is freshly created and has never logged in', () => {
+ it('returns false', () => {
+ expect(isUserOnline(user)).toBe(false)
+ })
+ })
+})
diff --git a/backend/src/middleware/helpers/isUserOnline.ts b/backend/src/middleware/helpers/isUserOnline.ts
new file mode 100644
index 000000000..679953f81
--- /dev/null
+++ b/backend/src/middleware/helpers/isUserOnline.ts
@@ -0,0 +1,16 @@
+export const isUserOnline = (user) => {
+ // Is Recipient considered online
+ const lastActive = new Date(user.properties.lastActiveAt).getTime()
+ const awaySince = new Date(user.properties.awaySince).getTime()
+ const now = new Date().getTime()
+ const status = user.properties.lastOnlineStatus
+ if (
+ // online & last active less than 1.5min -> online
+ (status === 'online' && now - lastActive < 90000) ||
+ // away for less then 3min -> online
+ (status === 'away' && now - awaySince < 180000)
+ ) {
+ return true
+ }
+ return false
+}
diff --git a/backend/src/middleware/index.ts b/backend/src/middleware/index.ts
index 08c872db7..8eca3c8e8 100644
--- a/backend/src/middleware/index.ts
+++ b/backend/src/middleware/index.ts
@@ -1,5 +1,6 @@
+/* eslint-disable security/detect-object-injection */
import { applyMiddleware } from 'graphql-middleware'
-import CONFIG from './../config'
+import CONFIG from '../config'
import softDelete from './softDelete/softDeleteMiddleware'
import sluggify from './sluggifyMiddleware'
import excerpt from './excerptMiddleware'
@@ -8,6 +9,7 @@ import permissions from './permissionsMiddleware'
import includedFields from './includedFieldsMiddleware'
import orderBy from './orderByMiddleware'
import validation from './validation/validationMiddleware'
+// eslint-disable-next-line import/no-cycle
import notifications from './notifications/notificationsMiddleware'
import hashtags from './hashtags/hashtagsMiddleware'
import login from './login/loginMiddleware'
diff --git a/backend/src/middleware/notifications/mentions/extractMentionedUsers.ts b/backend/src/middleware/notifications/mentions/extractMentionedUsers.ts
index ff80bb77a..b7dc0fed1 100644
--- a/backend/src/middleware/notifications/mentions/extractMentionedUsers.ts
+++ b/backend/src/middleware/notifications/mentions/extractMentionedUsers.ts
@@ -1,8 +1,8 @@
-import * as cheerio from 'cheerio'
+import { load } from 'cheerio'
export default (content?) => {
if (!content) return []
- const $ = cheerio.load(content)
+ const $ = load(content)
const userIds = $('a.mention[data-mention-id]')
.map((_, el) => {
return $(el).attr('data-mention-id')
diff --git a/backend/src/middleware/notifications/notificationsMiddleware.spec.ts b/backend/src/middleware/notifications/notificationsMiddleware.spec.ts
index 57354d13f..50d655484 100644
--- a/backend/src/middleware/notifications/notificationsMiddleware.spec.ts
+++ b/backend/src/middleware/notifications/notificationsMiddleware.spec.ts
@@ -1,5 +1,5 @@
import gql from 'graphql-tag'
-import { cleanDatabase } from '../../db/factories'
+import Factory, { cleanDatabase } from '../../db/factories'
import { createTestClient } from 'apollo-server-testing'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer, { pubsub } from '../../server'
@@ -10,6 +10,23 @@ import {
changeGroupMemberRoleMutation,
removeUserFromGroupMutation,
} from '../../graphql/groups'
+import { createMessageMutation } from '../../graphql/messages'
+import { createRoomMutation } from '../../graphql/rooms'
+
+const sendMailMock = jest.fn()
+jest.mock('../helpers/email/sendMail', () => ({
+ sendMail: () => sendMailMock(),
+}))
+
+const chatMessageTemplateMock = jest.fn()
+jest.mock('../helpers/email/templateBuilder', () => ({
+ chatMessageTemplate: () => chatMessageTemplateMock(),
+}))
+
+let isUserOnlineMock = jest.fn()
+jest.mock('../helpers/isUserOnline', () => ({
+ isUserOnline: () => isUserOnlineMock(),
+}))
let server, query, mutate, notifiedUser, authenticatedUser
let publishSpy
@@ -633,6 +650,115 @@ describe('notifications', () => {
})
})
+ describe('chat email notifications', () => {
+ let chatSender
+ let chatReceiver
+ let roomId
+
+ beforeEach(async () => {
+ jest.clearAllMocks()
+
+ chatSender = await neode.create(
+ 'User',
+ {
+ id: 'chatSender',
+ name: 'chatSender',
+ slug: 'chatSender',
+ },
+ {
+ email: 'chatSender@example.org',
+ password: '1234',
+ },
+ )
+
+ chatReceiver = await Factory.build(
+ 'user',
+ { id: 'chatReceiver', name: 'chatReceiver', slug: 'chatReceiver' },
+ { email: 'user@example.org' },
+ )
+
+ authenticatedUser = await chatSender.toJson()
+
+ const room = await mutate({
+ mutation: createRoomMutation(),
+ variables: {
+ userId: 'chatReceiver',
+ },
+ })
+ roomId = room.data.CreateRoom.id
+ })
+
+ describe('chatReceiver is online', () => {
+ it('sends no email', async () => {
+ isUserOnlineMock = jest.fn().mockReturnValue(true)
+
+ await mutate({
+ mutation: createMessageMutation(),
+ variables: {
+ roomId,
+ content: 'Some nice message to chatReceiver',
+ },
+ })
+
+ expect(sendMailMock).not.toHaveBeenCalled()
+ expect(chatMessageTemplateMock).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('chatReceiver is offline', () => {
+ it('sends an email', async () => {
+ isUserOnlineMock = jest.fn().mockReturnValue(false)
+
+ await mutate({
+ mutation: createMessageMutation(),
+ variables: {
+ roomId,
+ content: 'Some nice message to chatReceiver',
+ },
+ })
+
+ expect(sendMailMock).toHaveBeenCalledTimes(1)
+ expect(chatMessageTemplateMock).toHaveBeenCalledTimes(1)
+ })
+ })
+
+ describe('chatReceiver has blocked chatSender', () => {
+ it('sends no email', async () => {
+ isUserOnlineMock = jest.fn().mockReturnValue(false)
+ await chatReceiver.relateTo(chatSender, 'blocked')
+
+ await mutate({
+ mutation: createMessageMutation(),
+ variables: {
+ roomId,
+ content: 'Some nice message to chatReceiver',
+ },
+ })
+
+ expect(sendMailMock).not.toHaveBeenCalled()
+ expect(chatMessageTemplateMock).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('chatReceiver has disabled email notifications', () => {
+ it('sends no email', async () => {
+ isUserOnlineMock = jest.fn().mockReturnValue(false)
+ await chatReceiver.update({ sendNotificationEmails: false })
+
+ await mutate({
+ mutation: createMessageMutation(),
+ variables: {
+ roomId,
+ content: 'Some nice message to chatReceiver',
+ },
+ })
+
+ expect(sendMailMock).not.toHaveBeenCalled()
+ expect(chatMessageTemplateMock).not.toHaveBeenCalled()
+ })
+ })
+ })
+
describe('group notifications', () => {
let groupOwner
diff --git a/backend/src/middleware/notifications/notificationsMiddleware.ts b/backend/src/middleware/notifications/notificationsMiddleware.ts
index 7b55ac7dd..deca37bf7 100644
--- a/backend/src/middleware/notifications/notificationsMiddleware.ts
+++ b/backend/src/middleware/notifications/notificationsMiddleware.ts
@@ -1,8 +1,11 @@
+/* eslint-disable security/detect-object-injection */
+// eslint-disable-next-line import/no-cycle
import { pubsub, NOTIFICATION_ADDED } from '../../server'
import extractMentionedUsers from './mentions/extractMentionedUsers'
import { validateNotifyUsers } from '../validation/validationMiddleware'
import { sendMail } from '../helpers/email/sendMail'
-import { notificationTemplate } from '../helpers/email/templateBuilder'
+import { chatMessageTemplate, notificationTemplate } from '../helpers/email/templateBuilder'
+import { isUserOnline } from '../helpers/isUserOnline'
const queryNotificationEmails = async (context, notificationUserIds) => {
if (!(notificationUserIds && notificationUserIds.length)) return []
@@ -335,6 +338,56 @@ const notifyUsersOfComment = async (label, commentId, reason, context) => {
}
}
+const handleCreateMessage = async (resolve, root, args, context, resolveInfo) => {
+ // Execute resolver
+ const result = await resolve(root, args, context, resolveInfo)
+
+ // Query Parameters
+ const { roomId } = args
+ const {
+ user: { id: currentUserId },
+ } = context
+
+ // Find Recipient
+ const session = context.driver.session()
+ const messageRecipient = session.readTransaction(async (transaction) => {
+ const messageRecipientCypher = `
+ MATCH (currentUser:User { id: $currentUserId })-[:CHATS_IN]->(room:Room { id: $roomId })
+ MATCH (room)<-[:CHATS_IN]-(recipientUser:User)-[:PRIMARY_EMAIL]->(emailAddress:EmailAddress)
+ WHERE NOT recipientUser.id = $currentUserId
+ AND NOT (recipientUser)-[:BLOCKED]-(currentUser)
+ AND recipientUser.sendNotificationEmails = true
+ RETURN recipientUser, emailAddress {.email}
+ `
+ const txResponse = await transaction.run(messageRecipientCypher, {
+ currentUserId,
+ roomId,
+ })
+
+ return {
+ user: await txResponse.records.map((record) => record.get('recipientUser'))[0],
+ email: await txResponse.records.map((record) => record.get('emailAddress'))[0]?.email,
+ }
+ })
+
+ try {
+ // Execute Query
+ const { user, email } = await messageRecipient
+
+ // Send EMail if we found a user(not blocked) and he is not considered online
+ if (user && !isUserOnline(user)) {
+ void sendMail(chatMessageTemplate({ email, variables: { name: user.properties.name } }))
+ }
+
+ // Return resolver result to client
+ return result
+ } catch (error) {
+ throw new Error(error)
+ } finally {
+ session.close()
+ }
+}
+
export default {
Mutation: {
CreatePost: handleContentDataOfPost,
@@ -345,5 +398,6 @@ export default {
LeaveGroup: handleLeaveGroup,
ChangeGroupMemberRole: handleChangeGroupMemberRole,
RemoveUserFromGroup: handleRemoveUserFromGroup,
+ CreateMessage: handleCreateMessage,
},
}
diff --git a/backend/src/middleware/sentryMiddleware.ts b/backend/src/middleware/sentryMiddleware.ts
index 73f393eef..ace2c4eeb 100644
--- a/backend/src/middleware/sentryMiddleware.ts
+++ b/backend/src/middleware/sentryMiddleware.ts
@@ -1,6 +1,7 @@
import { sentry } from 'graphql-middleware-sentry'
import CONFIG from '../config'
+// eslint-disable-next-line import/no-mutable-exports
let sentryMiddleware: any = (resolve, root, args, context, resolveInfo) =>
resolve(root, args, context, resolveInfo)
diff --git a/backend/src/middleware/xssMiddleware.ts b/backend/src/middleware/xssMiddleware.ts
index c10997e8d..7b1b66145 100644
--- a/backend/src/middleware/xssMiddleware.ts
+++ b/backend/src/middleware/xssMiddleware.ts
@@ -1,5 +1,5 @@
import walkRecursive from '../helpers/walkRecursive'
-import { cleanHtml } from '../middleware/helpers/cleanHtml'
+import { cleanHtml } from './helpers/cleanHtml'
// exclamation mark separetes field names, that should not be sanitized
const fields = [
diff --git a/backend/src/models/index.ts b/backend/src/models/index.ts
index f7d338684..e02cbc242 100644
--- a/backend/src/models/index.ts
+++ b/backend/src/models/index.ts
@@ -1,3 +1,5 @@
+/* eslint-disable n/no-missing-require */
+/* eslint-disable n/global-require */
// NOTE: We cannot use `fs` here to clean up the code. Cypress breaks on any npm
// module that is not browser-compatible. Node's `fs` module is server-side only
declare let Cypress: any | undefined
diff --git a/backend/src/schema/resolvers/emails.ts b/backend/src/schema/resolvers/emails.ts
index d705781ca..ff37948f2 100644
--- a/backend/src/schema/resolvers/emails.ts
+++ b/backend/src/schema/resolvers/emails.ts
@@ -2,6 +2,7 @@ import generateNonce from './helpers/generateNonce'
import Resolver from './helpers/Resolver'
import existingEmailAddress from './helpers/existingEmailAddress'
import { UserInputError } from 'apollo-server'
+// eslint-disable-next-line import/extensions
import Validator from 'neode/build/Services/Validator.js'
import normalizeEmail from './helpers/normalizeEmail'
diff --git a/backend/src/schema/resolvers/embeds/scraper.ts b/backend/src/schema/resolvers/embeds/scraper.ts
index 79dd5a368..afc2b1df6 100644
--- a/backend/src/schema/resolvers/embeds/scraper.ts
+++ b/backend/src/schema/resolvers/embeds/scraper.ts
@@ -1,3 +1,7 @@
+/* eslint-disable n/no-extraneous-require */
+/* eslint-disable n/global-require */
+/* eslint-disable import/no-commonjs */
+/* eslint-disable import/no-named-as-default */
import Metascraper from 'metascraper'
import fetch from 'node-fetch'
@@ -37,6 +41,7 @@ const fetchEmbed = async (url) => {
try {
const response = await fetch(endpointUrl)
json = await response.json()
+ // eslint-disable-next-line no-catch-all/no-catch-all
} catch (err) {
error(`Error fetching embed data: ${err.message}`)
return {}
diff --git a/backend/src/schema/resolvers/helpers/Resolver.ts b/backend/src/schema/resolvers/helpers/Resolver.ts
index 58d1512d7..a21893f7d 100644
--- a/backend/src/schema/resolvers/helpers/Resolver.ts
+++ b/backend/src/schema/resolvers/helpers/Resolver.ts
@@ -1,3 +1,4 @@
+/* eslint-disable security/detect-object-injection */
import log from './databaseLogger'
export const undefinedToNullResolver = (list) => {
diff --git a/backend/src/schema/resolvers/helpers/databaseLogger.ts b/backend/src/schema/resolvers/helpers/databaseLogger.ts
index fac1a5c4a..98544087b 100644
--- a/backend/src/schema/resolvers/helpers/databaseLogger.ts
+++ b/backend/src/schema/resolvers/helpers/databaseLogger.ts
@@ -1,4 +1,6 @@
+/* eslint-disable import/no-named-as-default */
import Debug from 'debug'
+
const debugCypher = Debug('human-connection:neo4j:cypher')
const debugStats = Debug('human-connection:neo4j:stats')
diff --git a/backend/src/schema/resolvers/helpers/generateInviteCode.ts b/backend/src/schema/resolvers/helpers/generateInviteCode.ts
index 5a123ff88..e3f555931 100644
--- a/backend/src/schema/resolvers/helpers/generateInviteCode.ts
+++ b/backend/src/schema/resolvers/helpers/generateInviteCode.ts
@@ -1,4 +1,4 @@
-import CONSTANTS_REGISTRATION from './../../../constants/registration'
+import CONSTANTS_REGISTRATION from '../../../constants/registration'
export default function generateInviteCode() {
// 6 random numbers in [ 0, 35 ] are 36 possible numbers (10 [0-9] + 26 [A-Z])
diff --git a/backend/src/schema/resolvers/helpers/generateNonce.ts b/backend/src/schema/resolvers/helpers/generateNonce.ts
index f08b3ccd6..de1294567 100644
--- a/backend/src/schema/resolvers/helpers/generateNonce.ts
+++ b/backend/src/schema/resolvers/helpers/generateNonce.ts
@@ -1,4 +1,4 @@
-import CONSTANTS_REGISTRATION from './../../../constants/registration'
+import CONSTANTS_REGISTRATION from '../../../constants/registration'
// TODO: why this is not used in resolver 'requestPasswordReset'?
export default function generateNonce() {
diff --git a/backend/src/schema/resolvers/images.ts b/backend/src/schema/resolvers/images.ts
index 111f84888..ea596a183 100644
--- a/backend/src/schema/resolvers/images.ts
+++ b/backend/src/schema/resolvers/images.ts
@@ -1,4 +1,5 @@
import Resolver from './helpers/Resolver'
+
export default {
Image: {
...Resolver('Image', {
diff --git a/backend/src/schema/resolvers/images/images.spec.ts b/backend/src/schema/resolvers/images/images.spec.ts
index d46972ce0..94602ccd8 100644
--- a/backend/src/schema/resolvers/images/images.spec.ts
+++ b/backend/src/schema/resolvers/images/images.spec.ts
@@ -1,3 +1,4 @@
+/* eslint-disable promise/prefer-await-to-callbacks */
import { deleteImage, mergeImage } from './images'
import { getNeode, getDriver } from '../../../db/neo4j'
import Factory, { cleanDatabase } from '../../../db/factories'
@@ -90,6 +91,7 @@ describe('deleteImage', () => {
})
throw new Error('Ouch!')
})
+ // eslint-disable-next-line no-catch-all/no-catch-all
} catch (err) {
// nothing has been deleted
await expect(neode.all('Image')).resolves.toHaveLength(1)
@@ -251,6 +253,7 @@ describe('mergeImage', () => {
})
return transaction.run('Ooops invalid cypher!', { image })
})
+ // eslint-disable-next-line no-catch-all/no-catch-all
} catch (err) {
// nothing has been created
await expect(neode.all('Image')).resolves.toHaveLength(0)
diff --git a/backend/src/schema/resolvers/images/images.ts b/backend/src/schema/resolvers/images/images.ts
index b99b13a10..4566aa5bf 100644
--- a/backend/src/schema/resolvers/images/images.ts
+++ b/backend/src/schema/resolvers/images/images.ts
@@ -1,3 +1,5 @@
+/* eslint-disable promise/avoid-new */
+/* eslint-disable security/detect-non-literal-fs-filename */
import path from 'path'
import { v4 as uuid } from 'uuid'
import { S3 } from 'aws-sdk'
diff --git a/backend/src/schema/resolvers/inviteCodes.spec.ts b/backend/src/schema/resolvers/inviteCodes.spec.ts
index 1df791ba6..bd6a55bc8 100644
--- a/backend/src/schema/resolvers/inviteCodes.spec.ts
+++ b/backend/src/schema/resolvers/inviteCodes.spec.ts
@@ -1,9 +1,10 @@
+/* eslint-disable security/detect-non-literal-regexp */
import Factory, { cleanDatabase } from '../../db/factories'
import { getDriver } from '../../db/neo4j'
import gql from 'graphql-tag'
import createServer from '../../server'
import { createTestClient } from 'apollo-server-testing'
-import CONSTANTS_REGISTRATION from './../../constants/registration'
+import CONSTANTS_REGISTRATION from '../../constants/registration'
let user
let query
diff --git a/backend/src/schema/resolvers/notifications.spec.ts b/backend/src/schema/resolvers/notifications.spec.ts
index 58757c92d..e3bcb9489 100644
--- a/backend/src/schema/resolvers/notifications.spec.ts
+++ b/backend/src/schema/resolvers/notifications.spec.ts
@@ -2,7 +2,7 @@ import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getDriver } from '../../db/neo4j'
import { createTestClient } from 'apollo-server-testing'
-import createServer from '../.././server'
+import createServer from '../../server'
import {
markAsReadMutation,
markAllAsReadMutation,
diff --git a/backend/src/schema/resolvers/passwordReset.spec.ts b/backend/src/schema/resolvers/passwordReset.spec.ts
index 3d17ff481..d0ca3e4a8 100644
--- a/backend/src/schema/resolvers/passwordReset.spec.ts
+++ b/backend/src/schema/resolvers/passwordReset.spec.ts
@@ -1,7 +1,7 @@
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getNeode, getDriver } from '../../db/neo4j'
-import CONSTANTS_REGISTRATION from './../../constants/registration'
+import CONSTANTS_REGISTRATION from '../../constants/registration'
import createPasswordReset from './helpers/createPasswordReset'
import createServer from '../../server'
import { createTestClient } from 'apollo-server-testing'
diff --git a/backend/src/schema/resolvers/passwordReset.ts b/backend/src/schema/resolvers/passwordReset.ts
index 6fea020dd..4adca11d3 100644
--- a/backend/src/schema/resolvers/passwordReset.ts
+++ b/backend/src/schema/resolvers/passwordReset.ts
@@ -1,6 +1,6 @@
import { v4 as uuid } from 'uuid'
import bcrypt from 'bcryptjs'
-import CONSTANTS_REGISTRATION from './../../constants/registration'
+import CONSTANTS_REGISTRATION from '../../constants/registration'
import createPasswordReset from './helpers/createPasswordReset'
export default {
diff --git a/backend/src/schema/resolvers/reports.spec.ts b/backend/src/schema/resolvers/reports.spec.ts
index bc47778c1..2e6b4d302 100644
--- a/backend/src/schema/resolvers/reports.spec.ts
+++ b/backend/src/schema/resolvers/reports.spec.ts
@@ -1,5 +1,5 @@
import { createTestClient } from 'apollo-server-testing'
-import createServer from '../.././server'
+import createServer from '../../server'
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getDriver, getNeode } from '../../db/neo4j'
diff --git a/backend/src/schema/resolvers/statistics.ts b/backend/src/schema/resolvers/statistics.ts
index b454ce8f4..6bf73b0b2 100644
--- a/backend/src/schema/resolvers/statistics.ts
+++ b/backend/src/schema/resolvers/statistics.ts
@@ -1,3 +1,4 @@
+/* eslint-disable security/detect-object-injection */
import log from './helpers/databaseLogger'
export default {
diff --git a/backend/src/schema/resolvers/user_management.spec.ts b/backend/src/schema/resolvers/user_management.spec.ts
index 546c7a748..797f08126 100644
--- a/backend/src/schema/resolvers/user_management.spec.ts
+++ b/backend/src/schema/resolvers/user_management.spec.ts
@@ -1,5 +1,6 @@
+/* eslint-disable promise/prefer-await-to-callbacks */
import jwt from 'jsonwebtoken'
-import CONFIG from './../../config'
+import CONFIG from '../../config'
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { loginMutation } from '../../graphql/userManagement'
diff --git a/backend/src/schema/resolvers/users/location.ts b/backend/src/schema/resolvers/users/location.ts
index 0c3f55595..9a8b5430b 100644
--- a/backend/src/schema/resolvers/users/location.ts
+++ b/backend/src/schema/resolvers/users/location.ts
@@ -1,3 +1,6 @@
+/* eslint-disable promise/avoid-new */
+/* eslint-disable promise/prefer-await-to-callbacks */
+/* eslint-disable import/no-named-as-default */
import request from 'request'
import { UserInputError } from 'apollo-server'
import Debug from 'debug'
diff --git a/backend/src/server.ts b/backend/src/server.ts
index 0522f5fc8..7451e3e4a 100644
--- a/backend/src/server.ts
+++ b/backend/src/server.ts
@@ -1,8 +1,10 @@
+/* eslint-disable import/no-named-as-default-member */
import express from 'express'
import http from 'http'
import helmet from 'helmet'
import { ApolloServer } from 'apollo-server-express'
import CONFIG from './config'
+// eslint-disable-next-line import/no-cycle
import middleware from './middleware'
import { getNeode, getDriver } from './db/neo4j'
import decode from './jwt/decode'
diff --git a/backend/yarn.lock b/backend/yarn.lock
index ab611aea5..41a80a121 100644
--- a/backend/yarn.lock
+++ b/backend/yarn.lock
@@ -1091,6 +1091,14 @@
dependencies:
tslib "^2.4.0"
+"@eslint-community/eslint-plugin-eslint-comments@^4.4.1":
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-4.4.1.tgz#dbfab6f2447c22be8758a0a9a9c80e56d2e2b93f"
+ integrity sha512-lb/Z/MzbTf7CaVYM9WCFNQZ4L1yi3ev2fsFPF99h31ljhSEyUoyEsKsNWiU+qD1glbYTDJdqgyaLKtyTkkqtuQ==
+ dependencies:
+ escape-string-regexp "^4.0.0"
+ ignore "^5.2.4"
+
"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@@ -4606,6 +4614,11 @@ eslint-plugin-n@^16.6.2:
resolve "^1.22.2"
semver "^7.5.3"
+eslint-plugin-no-catch-all@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-no-catch-all/-/eslint-plugin-no-catch-all-1.1.0.tgz#f2e8950cc2b0bdde5faa4ab339d0986c6ae32fb0"
+ integrity sha512-VkP62jLTmccPrFGN/W6V7a3SEwdtTZm+Su2k4T3uyJirtkm0OMMm97h7qd8pRFAHus/jQg9FpUpLRc7sAylBEQ==
+
eslint-plugin-prettier@^5.2.6:
version "5.2.6"
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.6.tgz#be39e3bb23bb3eeb7e7df0927cdb46e4d7945096"
@@ -7353,29 +7366,29 @@ migrate@^2.1.0:
mkdirp "^3.0.1"
slug "^8.2.2"
-mime-db@1.43.0:
- version "1.43.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
- integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
-
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
-mime-types@^2.1.12, mime-types@^2.1.35, mime-types@~2.1.19, mime-types@~2.1.34:
+mime-db@^1.54.0:
+ version "1.54.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5"
+ integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
+
+mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.22, mime-types@~2.1.24, mime-types@~2.1.34:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
-mime-types@~2.1.22, mime-types@~2.1.24:
- version "2.1.26"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
- integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
+mime-types@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce"
+ integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==
dependencies:
- mime-db "1.43.0"
+ mime-db "^1.54.0"
mime@1.6.0:
version "1.6.0"
@@ -7534,10 +7547,10 @@ n-gram@^1.0.0:
resolved "https://registry.yarnpkg.com/n-gram/-/n-gram-1.1.1.tgz#a374dc176a9063a2388d1be18ed7c35828be2a97"
integrity sha512-qibRqvUghLIVsq+RTwVuwOzgOxf0l4DDZKVYAK0bMam5sG9ZzaJ6BUSJyG2Td8kTc7c/HcMUtjiN5ShobZA2bA==
-nan@2.17.0, nan@^2.20.0:
- version "2.17.0"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb"
- integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==
+nan@^2.20.0:
+ version "2.22.2"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.2.tgz#6b504fd029fb8f38c0990e52ad5c26772fdacfbb"
+ integrity sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==
nanoid@^3.3.6:
version "3.3.7"
diff --git a/package-lock.json b/package-lock.json
index 5a083c2c1..0b708bace 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,7 +15,7 @@
"@badeball/cypress-cucumber-preprocessor": "^22.0.1",
"@cucumber/cucumber": "11.2.0",
"@cypress/browserify-preprocessor": "^3.0.2",
- "@faker-js/faker": "9.5.0",
+ "@faker-js/faker": "9.6.0",
"auto-changelog": "^2.5.0",
"bcryptjs": "^2.4.3",
"cross-env": "^7.0.3",
@@ -2786,9 +2786,9 @@
}
},
"node_modules/@faker-js/faker": {
- "version": "9.5.0",
- "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.5.0.tgz",
- "integrity": "sha512-3qbjLv+fzuuCg3umxc9/7YjrEXNaKwHgmig949nfyaTx8eL4FAsvFbu+1JcFUj1YAXofhaDn6JdEUBTYuk0Ssw==",
+ "version": "9.6.0",
+ "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.6.0.tgz",
+ "integrity": "sha512-3vm4by+B5lvsFPSyep3ELWmZfE3kicDtmemVpuwl1yH7tqtnHdsA6hG8fbXedMVdkzgtvzWoRgjSB4Q+FHnZiw==",
"dev": true,
"funding": [
{
diff --git a/package.json b/package.json
index b90501c4b..dd27c53ca 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,7 @@
"@badeball/cypress-cucumber-preprocessor": "^22.0.1",
"@cucumber/cucumber": "11.2.0",
"@cypress/browserify-preprocessor": "^3.0.2",
- "@faker-js/faker": "9.5.0",
+ "@faker-js/faker": "9.6.0",
"auto-changelog": "^2.5.0",
"bcryptjs": "^2.4.3",
"cross-env": "^7.0.3",
diff --git a/webapp/package.json b/webapp/package.json
index edcc620eb..5c1d946fc 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -48,7 +48,7 @@
"nuxt": "~2.12.1",
"nuxt-dropzone": "^1.0.4",
"nuxt-env": "~0.1.0",
- "sass": "^1.85.0",
+ "sass": "^1.86.3",
"stack-utils": "^2.0.3",
"tippy.js": "^4.3.5",
"tiptap": "~1.26.6",
@@ -56,7 +56,7 @@
"trunc-html": "^1.1.2",
"v-mapbox": "^1.11.2",
"v-tooltip": "~2.1.3",
- "validator": "^13.12.0",
+ "validator": "^13.15.0",
"vue-advanced-chat": "^2.0.11",
"vue-count-to": "~1.0.13",
"vue-infinite-loading": "^2.4.5",
@@ -73,7 +73,7 @@
"@babel/core": "^7.25.8",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.25.8",
- "@faker-js/faker": "9.5.0",
+ "@faker-js/faker": "9.6.0",
"@storybook/addon-a11y": "^8.0.8",
"@storybook/addon-actions": "^5.3.21",
"@storybook/addon-notes": "^5.3.18",
diff --git a/webapp/yarn.lock b/webapp/yarn.lock
index f318a66d2..87e849383 100644
--- a/webapp/yarn.lock
+++ b/webapp/yarn.lock
@@ -2447,10 +2447,10 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
-"@faker-js/faker@9.5.0":
- version "9.5.0"
- resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-9.5.0.tgz#ce254c83706250ca8a5a0e05683608160610dd84"
- integrity sha512-3qbjLv+fzuuCg3umxc9/7YjrEXNaKwHgmig949nfyaTx8eL4FAsvFbu+1JcFUj1YAXofhaDn6JdEUBTYuk0Ssw==
+"@faker-js/faker@9.6.0":
+ version "9.6.0"
+ resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-9.6.0.tgz#64235d20330b142eef3d1d1638ba56c083b4bf1d"
+ integrity sha512-3vm4by+B5lvsFPSyep3ELWmZfE3kicDtmemVpuwl1yH7tqtnHdsA6hG8fbXedMVdkzgtvzWoRgjSB4Q+FHnZiw==
"@hapi/address@2.x.x":
version "2.0.0"
@@ -17426,10 +17426,10 @@ sass-resources-loader@^2.2.1:
glob "^7.1.6"
loader-utils "^2.0.0"
-sass@^1.85.0:
- version "1.85.0"
- resolved "https://registry.yarnpkg.com/sass/-/sass-1.85.0.tgz#0127ef697d83144496401553f0a0e87be83df45d"
- integrity sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==
+sass@^1.86.3:
+ version "1.86.3"
+ resolved "https://registry.yarnpkg.com/sass/-/sass-1.86.3.tgz#0a0d9ea97cb6665e73f409639f8533ce057464c9"
+ integrity sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw==
dependencies:
chokidar "^4.0.0"
immutable "^5.0.2"
@@ -17823,12 +17823,7 @@ source-list-map@^2.0.0:
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
-"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
- integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
-
-source-map-js@^1.0.2, source-map-js@^1.2.0:
+"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
@@ -19666,10 +19661,10 @@ validate-npm-package-license@^3.0.1:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
-validator@^13.12.0:
- version "13.12.0"
- resolved "https://registry.yarnpkg.com/validator/-/validator-13.12.0.tgz#7d78e76ba85504da3fee4fd1922b385914d4b35f"
- integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==
+validator@^13.15.0:
+ version "13.15.0"
+ resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.0.tgz#2dc7ce057e7513a55585109eec29b2c8e8c1aefd"
+ integrity sha512-36B2ryl4+oL5QxZ3AzD0t5SsMNGvTtQHpjgFO5tbNxfXbMFkY822ktCDe1MnlqV3301QQI9SLHDNJokDI+Z9pA==
vary@^1, vary@^1.1.2, vary@~1.1.2:
version "1.1.2"
diff --git a/yarn.lock b/yarn.lock
index f01c83a18..4e1450d9a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1543,10 +1543,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz#81fd50d11e2c32b2d6241470e3185b70c7b30699"
integrity sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==
-"@faker-js/faker@9.5.0":
- version "9.5.0"
- resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-9.5.0.tgz#ce254c83706250ca8a5a0e05683608160610dd84"
- integrity sha512-3qbjLv+fzuuCg3umxc9/7YjrEXNaKwHgmig949nfyaTx8eL4FAsvFbu+1JcFUj1YAXofhaDn6JdEUBTYuk0Ssw==
+"@faker-js/faker@9.6.0":
+ version "9.6.0"
+ resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-9.6.0.tgz#64235d20330b142eef3d1d1638ba56c083b4bf1d"
+ integrity sha512-3vm4by+B5lvsFPSyep3ELWmZfE3kicDtmemVpuwl1yH7tqtnHdsA6hG8fbXedMVdkzgtvzWoRgjSB4Q+FHnZiw==
"@fastify/busboy@^2.0.0":
version "2.1.1"