feat(backend): lint rules (#8339)

* eslint import

* eslint comments

* eslint security

* eslint import - rules

* eslint n

* eslint promise

* eslint no-catch-all

* eslint jest

* missing ignore

* disable import/unambiguous as conflicting
This commit is contained in:
Ulf Gebhardt 2025-04-07 12:53:44 +02:00 committed by GitHub
parent 2eaaa7af39
commit d6cb9b51c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
71 changed files with 353 additions and 279 deletions

209
backend/.eslintrc.cjs Normal file
View File

@ -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',
},
},
],
};

View File

@ -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',
},
},
],
};

View File

@ -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"
}
}

View File

@ -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') {

View File

@ -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)

View File

@ -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

View File

@ -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
}
@ -71,6 +73,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
}
@ -93,6 +96,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)
@ -122,6 +126,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)
@ -157,6 +162,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)
@ -166,4 +172,4 @@ class Store {
}
}
module.exports = Store
export default Store

View File

@ -1,4 +1,4 @@
import { getDriver } from '../../db/neo4j'
import { getDriver } from '../neo4j'
export const description = ''

View File

@ -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

View File

@ -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'

View File

@ -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 {

View File

@ -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

View File

@ -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.'

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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.'

View File

@ -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.'

View File

@ -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 = `

View File

@ -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()
}

View File

@ -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()

View File

@ -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()

View File

@ -1,4 +1,4 @@
import { getDriver } from '../../db/neo4j'
import { getDriver } from '../neo4j'
import { v4 as uuid } from 'uuid'
export const description =

View File

@ -1,4 +1,4 @@
import { getDriver } from '../../db/neo4j'
import { getDriver } from '../neo4j'
export const description = ''

View File

@ -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.

View File

@ -1,4 +1,4 @@
import { getDriver } from '../../db/neo4j'
import { getDriver } from '../neo4j'
export const description = ''

View File

@ -1,4 +1,4 @@
import { getDriver } from '../../db/neo4j'
import { getDriver } from '../neo4j'
export const description = 'Add to all existing posts the Article label'

View File

@ -1,4 +1,4 @@
import { getDriver } from '../../db/neo4j'
import { getDriver } from '../neo4j'
export const description = 'Add postType property Article to all posts'

View File

@ -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

View File

@ -1,4 +1,4 @@
import { getDriver } from '../../db/neo4j'
import { getDriver } from '../neo4j'
export const description = `
All authors observe their posts.

View File

@ -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'

View File

@ -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)

View File

@ -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
*

View File

@ -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/

View File

@ -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

View File

@ -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
}

View File

@ -1,6 +1,6 @@
import encode from './encode'
import jwt from 'jsonwebtoken'
import CONFIG from './../config'
import CONFIG from '../config'
describe('encode', () => {
let payload

View File

@ -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) {

View File

@ -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]')

View File

@ -1,4 +1,4 @@
import extractHashtags from '../hashtags/extractHashtags'
import extractHashtags from './extractHashtags'
const updateHashtagsOfPost = async (postId, hashtags, context) => {
if (!hashtags.length) return

View File

@ -1,3 +1,4 @@
/* eslint-disable security/detect-unsafe-regex */
import sanitizeHtml from 'sanitize-html'
import linkifyHtml from 'linkify-html'

View File

@ -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'

View File

@ -1,3 +1,4 @@
/* eslint-disable import/no-namespace */
import mustache from 'mustache'
import CONFIG from '../../../config'
import metadata from '../../../config/metadata'

View File

@ -1,3 +1,4 @@
/* eslint-disable security/detect-non-literal-fs-filename */
import fs from 'fs'
import path from 'path'

View File

@ -1,3 +1,4 @@
/* eslint-disable security/detect-non-literal-fs-filename */
import fs from 'fs'
import path from 'path'

View File

@ -1,3 +1,4 @@
/* eslint-disable security/detect-non-literal-fs-filename */
import fs from 'fs'
import path from 'path'

View File

@ -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'

View File

@ -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')

View File

@ -1,3 +1,5 @@
/* 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'

View File

@ -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)

View File

@ -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 = [

View File

@ -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

View File

@ -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'

View File

@ -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 {}

View File

@ -1,3 +1,4 @@
/* eslint-disable security/detect-object-injection */
import log from './databaseLogger'
export const undefinedToNullResolver = (list) => {

View File

@ -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')

View File

@ -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])

View File

@ -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() {

View File

@ -1,4 +1,5 @@
import Resolver from './helpers/Resolver'
export default {
Image: {
...Resolver('Image', {

View File

@ -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)

View File

@ -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'

View File

@ -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

View File

@ -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,

View File

@ -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'

View File

@ -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 {

View File

@ -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'

View File

@ -1,3 +1,4 @@
/* eslint-disable security/detect-object-injection */
import log from './helpers/databaseLogger'
export default {

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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"
@ -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"