Merge branch 'master' into chat-message-notification-e2e-tests

This commit is contained in:
mahula 2025-04-10 09:14:59 +02:00 committed by GitHub
commit 41e77f5473
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
144 changed files with 2302 additions and 618 deletions

View File

@ -23,7 +23,7 @@ module.exports = {
},
'import/resolver': {
typescript: {
project: ['./tsconfig.json'],
project: ['./tsconfig.json', './backend/tsconfig.json'],
},
node: true,
},
@ -52,16 +52,16 @@ module.exports = {
'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/unambiguous': 'off', // not compatible with .eslintrc.cjs
'import/default': 'error',
// 'import/named': 'error',
'import/named': 'off', // has false positives
'import/namespace': 'error',
'import/no-absolute-path': 'error',
'import/no-cycle': 'error',
'import/no-dynamic-require': 'error',
'import/no-internal-modules': 'off',
'import/no-relative-packages': 'error',
// 'import/no-relative-parent-imports': ['error', { ignore: ['@/*'] }],
'import/no-relative-parent-imports': ['error', { ignore: ['@/*'] }],
'import/no-self-import': 'error',
'import/no-unresolved': 'error',
'import/no-useless-path-segments': 'error',
@ -72,36 +72,36 @@ module.exports = {
'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-anonymous-default-export': 'off', // not compatible with neode
'import/no-default-export': 'off', // not compatible with neode
'import/no-duplicates': 'error',
'import/no-named-default': 'error',
'import/no-namespace': 'error',
'import/no-unassigned-import': 'error',
// 'import/order': [
// 'error',
// {
// groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
// 'newlines-between': 'always',
// pathGroups: [
// {
// pattern: '@?*/**',
// group: 'external',
// position: 'after',
// },
// {
// pattern: '@/**',
// group: 'external',
// position: 'after',
// },
// ],
// alphabetize: {
// order: 'asc' /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */,
// caseInsensitive: true /* ignore case. Options: [true, false] */,
// },
// distinctGroup: true,
// },
// ],
'import/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
@ -128,7 +128,10 @@ module.exports = {
'n/no-restricted-require': 'error',
// 'n/no-sync': 'error',
// 'n/no-unpublished-bin': 'error', // part of n/recommended
'n/no-unpublished-import': ['error', { 'allowModules': ['apollo-server-testing', 'rosie', '@faker-js/faker'] }], // part of n/recommended
'n/no-unpublished-import': [
'error',
{ allowModules: ['apollo-server-testing', 'rosie', '@faker-js/faker', 'ts-jest'] },
], // part of n/recommended
// 'n/no-unpublished-require': 'error', // part of n/recommended
// 'n/no-unsupported-features/es-builtins': 'error', // part of n/recommended
// 'n/no-unsupported-features/es-syntax': 'error', // part of n/recommended
@ -148,7 +151,7 @@ module.exports = {
// promise
// 'promise/always-return': 'error', // part of promise/recommended
'promise/avoid-new': 'error',
'promise/avoid-new': 'error',
// 'promise/catch-or-return': 'error', // part of promise/recommended
// 'promise/no-callback-in-promise': 'warn', // part of promise/recommended
'promise/no-multiple-resolved': 'error',
@ -163,7 +166,7 @@ module.exports = {
'promise/prefer-catch': 'error',
'promise/spec-only': 'error',
// 'promise/valid-params': 'error', // part of promise/recommended
// eslint comments
'@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],
'@eslint-community/eslint-comments/no-restricted-disable': 'error',

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

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

View File

@ -1,20 +0,0 @@
module.exports = {
verbose: true,
preset: 'ts-jest',
collectCoverage: true,
collectCoverageFrom: [
'**/*.ts',
'!**/node_modules/**',
'!**/test/**',
'!**/build/**',
'!**/src/**/?(*.)+(spec|test).ts?(x)',
'!**/src/db/**'
],
coverageThreshold: {
global: {
lines: 90,
},
},
testMatch: ['**/src/**/?(*.)+(spec|test).ts?(x)'],
setupFilesAfterEnv: ['<rootDir>/test/setup.ts']
}

View File

@ -11,14 +11,14 @@
"__migrate": "migrate --compiler 'ts:./src/db/compiler.ts' --migrations-dir ./src/db/migrations",
"prod:migrate": "migrate --migrations-dir ./build/src/db/migrations --store ./build/src/db/migrate/store.js",
"start": "node build/src/",
"build": "tsc && ./scripts/build.copy.files.sh",
"dev": "nodemon --exec ts-node src/ -e js,ts,gql",
"build": "tsc && tsc-alias && ./scripts/build.copy.files.sh",
"dev": "nodemon --exec ts-node --require tsconfig-paths/register src/ -e js,ts,gql",
"dev:debug": "nodemon --exec babel-node --inspect=0.0.0.0:9229 src/ -e js,ts,gql",
"lint": "eslint --max-warnings=0 --ext .js,.ts ./src",
"test": "cross-env NODE_ENV=test NODE_OPTIONS=--max-old-space-size=8192 jest --runInBand --coverage --forceExit --detectOpenHandles",
"db:clean": "ts-node src/db/clean.ts",
"db:clean": "ts-node --require tsconfig-paths/register src/db/clean.ts",
"db:reset": "yarn run db:clean",
"db:seed": "ts-node src/db/seed.ts",
"db:seed": "ts-node --require tsconfig-paths/register src/db/seed.ts",
"db:migrate": "yarn run __migrate --store ./src/db/migrate/store.ts",
"db:migrate:create": "yarn run __migrate --template-file ./src/db/migrate/template.ts --date-format 'yyyymmddHHmmss' create"
},
@ -119,9 +119,12 @@
"jest": "^29.7.0",
"nodemon": "~3.1.9",
"prettier": "^3.5.3",
"require-json5": "^1.3.0",
"rosie": "^2.1.1",
"ts-jest": "^29.3.1",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.14",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.8.3"
},
"resolutions": {

View File

@ -1,5 +1,8 @@
#!/bin/sh
# public
cp -r public/ build/public/
# html files
mkdir -p build/src/middleware/helpers/email/templates/
cp -r src/middleware/helpers/email/templates/*.html build/src/middleware/helpers/email/templates/

View File

@ -2,6 +2,7 @@
/* eslint-disable n/no-unpublished-require */
/* eslint-disable n/no-missing-require */
import { config } from 'dotenv'
import emails from './emails'
import metadata from './metadata'

View File

@ -1,5 +1,6 @@
/* eslint-disable n/no-process-exit */
import CONFIG from '../config'
import CONFIG from '@config/index'
import { cleanDatabase } from './factories'
if (CONFIG.PRODUCTION && !CONFIG.PRODUCTION_DB_CLEAN_ALLOW) {

View File

@ -1,5 +1,7 @@
/* eslint-disable import/no-commonjs */
// eslint-disable-next-line n/no-unpublished-require
const tsNode = require('ts-node')
// eslint-disable-next-line import/no-unassigned-import, import/no-extraneous-dependencies, n/no-unpublished-require
require('tsconfig-paths/register')
module.exports = tsNode.register

View File

@ -1,11 +1,13 @@
import { v4 as uuid } from 'uuid'
import slugify from 'slug'
import { faker } from '@faker-js/faker'
import { hashSync } from 'bcryptjs'
import { Factory } from 'rosie'
import { faker } from '@faker-js/faker'
import slugify from 'slug'
import { v4 as uuid } from 'uuid'
import CONFIG from '@config/index'
import generateInviteCode from '@schema/resolvers/helpers/generateInviteCode'
import { getDriver, getNeode } from './neo4j'
import CONFIG from '../config/index'
import generateInviteCode from '../schema/resolvers/helpers/generateInviteCode'
const neode = getNeode()
@ -70,7 +72,6 @@ Factory.define('basicUser')
termsAndConditionsAgreedAt: '2019-08-01T10:47:19.212Z',
allowEmbedIframes: false,
showShoutsPublicly: false,
sendNotificationEmails: true,
locale: 'en',
})
.attr('slug', ['slug', 'name'], (slug, name) => {
@ -173,6 +174,7 @@ Factory.define('post')
])
await Promise.all([
post.relateTo(author, 'author'),
post.relateTo(author, 'observes'),
// Promise.all(categories.map((c) => c.relateTo(post, 'post'))),
Promise.all(tags.map((t) => t.relateTo(post, 'post'))),
])
@ -208,7 +210,11 @@ Factory.define('comment')
options.author,
options.post,
])
await Promise.all([comment.relateTo(author, 'author'), comment.relateTo(post, 'post')])
await Promise.all([
comment.relateTo(author, 'author'),
comment.relateTo(post, 'post'),
post.relateTo(author, 'observes'),
])
return comment
})

View File

@ -1,8 +1,9 @@
import { getDriver, getNeode } from '../neo4j'
import { hashSync } from 'bcryptjs'
import { v4 as uuid } from 'uuid'
import { categories } from '../../constants/categories'
import CONFIG from '../../config'
import CONFIG from '@config/index'
import { categories } from '@constants/categories'
import { getDriver, getNeode } from '@db/neo4j'
const defaultAdmin = {
email: 'admin@example.org',
@ -55,19 +56,18 @@ const createDefaultAdminUser = async (session) => {
`MERGE (e:EmailAddress {
email: "${defaultAdmin.email}",
createdAt: toString(datetime())
})-[:BELONGS_TO]->(u:User {
name: "${defaultAdmin.name}",
encryptedPassword: "${defaultAdmin.password}",
role: "admin",
id: "${defaultAdmin.id}",
slug: "${defaultAdmin.slug}",
createdAt: toString(datetime()),
allowEmbedIframes: false,
showShoutsPublicly: false,
sendNotificationEmails: true,
deleted: false,
disabled: false
})-[:PRIMARY_EMAIL]->(e)`,
})-[:BELONGS_TO]->(u:User {
name: "${defaultAdmin.name}",
encryptedPassword: "${defaultAdmin.password}",
role: "admin",
id: "${defaultAdmin.id}",
slug: "${defaultAdmin.slug}",
createdAt: toString(datetime()),
allowEmbedIframes: false,
showShoutsPublicly: false,
deleted: false,
disabled: false
})-[:PRIMARY_EMAIL]->(e)`,
)
})
try {

View File

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

View File

@ -2,8 +2,9 @@
/* eslint-disable promise/prefer-await-to-callbacks */
import { throwError, concat } from 'rxjs'
import { flatMap, mergeMap, map, catchError, filter } from 'rxjs/operators'
import { getDriver } from '../neo4j'
import normalizeEmail from '../../schema/resolvers/helpers/normalizeEmail'
import { getDriver } from '@db/neo4j'
import normalizeEmail from '@schema/resolvers/helpers/normalizeEmail'
export const description = `
This migration merges duplicate :User and :EmailAddress nodes. It became

View File

@ -2,7 +2,8 @@
/* eslint-disable promise/prefer-await-to-callbacks */
import { throwError, concat } from 'rxjs'
import { flatMap, mergeMap, map, catchError } from 'rxjs/operators'
import { getDriver } from '../neo4j'
import { getDriver } from '@db/neo4j'
export const description = `
This migration merges duplicate :Location nodes. It became

View File

@ -1,4 +1,4 @@
import { getDriver } from '../neo4j'
import { getDriver } from '@db/neo4j'
export const description = `
This migration creates a MUTED relationship between two edges(:User) that have a pre-existing BLOCKED relationship.

View File

@ -1,4 +1,4 @@
import { getDriver } from '../neo4j'
import { getDriver } from '@db/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 '../neo4j'
import { getDriver } from '@db/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 '../neo4j'
import { getDriver } from '@db/neo4j'
export const description = `
We introduced a new node label 'Image' and we need a primary key for it. Best

View File

@ -1,11 +1,13 @@
/* eslint-disable security/detect-non-literal-fs-filename */
import { getDriver } from '../neo4j'
import https from 'https'
import { existsSync, createReadStream } from 'node:fs'
import path from 'node:path'
import { S3 } from 'aws-sdk'
import mime from 'mime-types'
import s3Configs from '../../config'
import https from 'https'
import s3Configs from '@config/index'
import { getDriver } from '@db/neo4j'
export const description = `
Upload all image files to a S3 compatible object storage in order to reduce

View File

@ -1,5 +1,5 @@
/* eslint-disable no-console */
import { getDriver } from '../neo4j'
import { getDriver } from '@db/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 '../neo4j'
import { getDriver } from '@db/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 '../neo4j'
import { getDriver } from '@db/neo4j'
export const description =
'We should not maintain obsolete attributes for posts which have been deleted.'

View File

@ -1,7 +1,8 @@
/* eslint-disable security/detect-non-literal-fs-filename */
import { getDriver } from '../neo4j'
import { existsSync } from 'node:fs'
import { getDriver } from '@db/neo4j'
export const description = `
In this review:
https://github.com/Human-Connection/Human-Connection/pull/3262#discussion_r398634249

View File

@ -1,4 +1,4 @@
import { getDriver } from '../neo4j'
import { getDriver } from '@db/neo4j'
export const description = `
This migration adds the clickedCount property to all posts, setting it to 0.

View File

@ -1,4 +1,4 @@
import { getDriver } from '../neo4j'
import { getDriver } from '@db/neo4j'
export const description = `
This migration adds the viewedTeaserCount property to all posts, setting it to 0.

View File

@ -1,6 +1,7 @@
import { getDriver } from '../neo4j'
import { v4 as uuid } from 'uuid'
import { getDriver } from '@db/neo4j'
export const description =
'This migration adds a Donations node with default settings to the database.'

View File

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

View File

@ -1,4 +1,4 @@
import { getDriver } from '../neo4j'
import { getDriver } from '@db/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 '../neo4j'
import { getDriver } from '@db/neo4j'
export const description = ''

View File

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

View File

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

View File

@ -1,4 +1,4 @@
import { getDriver } from '../neo4j'
import { getDriver } from '@db/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 '../neo4j'
import { getDriver } from '@db/neo4j'
export const description = `
All authors observe their posts.

View File

@ -0,0 +1,68 @@
import { getDriver } from '@db/neo4j'
export const description =
'Transforms the `sendNotificationEmails` property on User to a multi value system'
export async function up(next) {
const driver = getDriver()
const session = driver.session()
const transaction = session.beginTransaction()
try {
// Implement your migration here.
await transaction.run(`
MATCH (user:User)
SET user.emailNotificationsCommentOnObservedPost = user.sendNotificationEmails
SET user.emailNotificationsMention = user.sendNotificationEmails
SET user.emailNotificationsChatMessage = user.sendNotificationEmails
SET user.emailNotificationsGroupMemberJoined = user.sendNotificationEmails
SET user.emailNotificationsGroupMemberLeft = user.sendNotificationEmails
SET user.emailNotificationsGroupMemberRemoved = user.sendNotificationEmails
SET user.emailNotificationsGroupMemberRoleChanged = user.sendNotificationEmails
REMOVE user.sendNotificationEmails
`)
await transaction.commit()
next()
} catch (error) {
// eslint-disable-next-line no-console
console.log(error)
await transaction.rollback()
// eslint-disable-next-line no-console
console.log('rolled back')
throw new Error(error)
} finally {
session.close()
}
}
export async function down(next) {
const driver = getDriver()
const session = driver.session()
const transaction = session.beginTransaction()
try {
// Implement your migration here.
await transaction.run(`
MATCH (user:User)
SET user.sendNotificationEmails = true
REMOVE user.emailNotificationsCommentOnObservedPost
REMOVE user.emailNotificationsMention
REMOVE user.emailNotificationsChatMessage
REMOVE user.emailNotificationsGroupMemberJoined
REMOVE user.emailNotificationsGroupMemberLeft
REMOVE user.emailNotificationsGroupMemberRemoved
REMOVE user.emailNotificationsGroupMemberRoleChanged
`)
await transaction.commit()
next()
} catch (error) {
// eslint-disable-next-line no-console
console.log(error)
await transaction.rollback()
// eslint-disable-next-line no-console
console.log('rolled back')
throw new Error(error)
} finally {
session.close()
}
}

View File

@ -1,8 +1,9 @@
/* eslint-disable import/no-named-as-default-member */
import neo4j from 'neo4j-driver'
import CONFIG from '../config'
import Neode from 'neode'
import models from '../models'
import CONFIG from '@config/index'
import models from '@models/index'
let driver
const defaultOptions = {

View File

@ -1,21 +1,23 @@
/* 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 './factories'
import { getNeode, getDriver } from './neo4j'
import { createTestClient } from 'apollo-server-testing'
import sample from 'lodash/sample'
import CONFIG from '@config/index'
import { categories } from '@constants/categories'
import { createCommentMutation } from '@graphql/comments'
import {
createGroupMutation,
joinGroupMutation,
changeGroupMemberRoleMutation,
} from '../graphql/groups'
import { createPostMutation } from '../graphql/posts'
import { createRoomMutation } from '../graphql/rooms'
import { createMessageMutation } from '../graphql/messages'
import { createCommentMutation } from '../graphql/comments'
import { categories } from '../constants/categories'
} from '@graphql/groups'
import { createMessageMutation } from '@graphql/messages'
import { createPostMutation } from '@graphql/posts'
import { createRoomMutation } from '@graphql/rooms'
import createServer from '@src/server'
import Factory from './factories'
import { getNeode, getDriver } from './neo4j'
if (CONFIG.PRODUCTION && !CONFIG.PRODUCTION_DB_CLEAN_ALLOW) {
throw new Error(`You cannot seed the database in a non-staging and real production environment!`)

View File

@ -1,5 +1,5 @@
import createServer from './server'
import CONFIG from './config'
import createServer from './server'
const { server, httpServer } = createServer()
const url = new URL(CONFIG.GRAPHQL_URI)

View File

@ -1,5 +1,6 @@
import Factory, { cleanDatabase } from '../db/factories'
import { getDriver, getNeode } from '../db/neo4j'
import Factory, { cleanDatabase } from '@db/factories'
import { getDriver, getNeode } from '@db/neo4j'
import decode from './decode'
import encode from './encode'

View File

@ -1,5 +1,6 @@
import jwt from 'jsonwebtoken'
import CONFIG from '../config'
import CONFIG from '@config/index'
export default async (driver, authorizationHeader) => {
if (!authorizationHeader) return null

View File

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

View File

@ -1,5 +1,6 @@
import jwt from 'jsonwebtoken'
import CONFIG from '../config'
import CONFIG from '@config/index'
// Generate an Access Token for the given User ID
export default function encode(user) {

View File

@ -1,5 +1,6 @@
import trunc from 'trunc-html'
import { DESCRIPTION_EXCERPT_HTML_LENGTH } from '../constants/groups'
import { DESCRIPTION_EXCERPT_HTML_LENGTH } from '@constants/groups'
export default {
Mutation: {

View File

@ -1,8 +1,9 @@
import gql from 'graphql-tag'
import { cleanDatabase } from '../../db/factories'
import { createTestClient } from 'apollo-server-testing'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import gql from 'graphql-tag'
import { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
let server
let query

View File

@ -1,6 +1,6 @@
/* eslint-disable security/detect-unsafe-regex */
import sanitizeHtml from 'sanitize-html'
import linkifyHtml from 'linkify-html'
import sanitizeHtml from 'sanitize-html'
export const removeHtmlTags = (input) => {
return sanitizeHtml(input, {

View File

@ -1,8 +1,9 @@
import CONFIG from '../../../config'
import { cleanHtml } from '../cleanHtml'
import nodemailer from 'nodemailer'
import { htmlToText } from 'nodemailer-html-to-text'
import CONFIG from '@config/index'
import { cleanHtml } from '@middleware/helpers/cleanHtml'
const hasEmailConfig = CONFIG.SMTP_HOST && CONFIG.SMTP_PORT
const hasAuthData = CONFIG.SMTP_USERNAME && CONFIG.SMTP_PASSWORD
const hasDKIMData =

View File

@ -1,5 +1,6 @@
import CONFIG from '../../../config'
import logosWebapp from '../../../config/logos'
import CONFIG from '@config/index'
import logosWebapp from '@config/logos'
import {
signupTemplate,
emailVerificationTemplate,

View File

@ -1,12 +1,13 @@
/* eslint-disable import/no-namespace */
import mustache from 'mustache'
import CONFIG from '../../../config'
import metadata from '../../../config/metadata'
import logosWebapp from '../../../config/logos'
import logosWebapp from '@config//logos'
import metadata from '@config//metadata'
import CONFIG from '@config/index'
import * as templates from './templates'
import * as templatesEN from './templates/en'
import * as templatesDE from './templates/de'
import * as templatesEN from './templates/en'
const from = CONFIG.EMAIL_DEFAULT_SENDER
const welcomeImageUrl = new URL(logosWebapp.LOGO_WELCOME_PATH, CONFIG.CLIENT_URI)

View File

@ -1,22 +1,24 @@
/* eslint-disable security/detect-object-injection */
import { applyMiddleware } from 'graphql-middleware'
import CONFIG from '../config'
import softDelete from './softDelete/softDeleteMiddleware'
import sluggify from './sluggifyMiddleware'
import CONFIG from '@config/index'
import chatMiddleware from './chatMiddleware'
import excerpt from './excerptMiddleware'
import xss from './xssMiddleware'
import permissions from './permissionsMiddleware'
import hashtags from './hashtags/hashtagsMiddleware'
import includedFields from './includedFieldsMiddleware'
import orderBy from './orderByMiddleware'
import validation from './validation/validationMiddleware'
import languages from './languages/languages'
import login from './login/loginMiddleware'
// eslint-disable-next-line import/no-cycle
import notifications from './notifications/notificationsMiddleware'
import hashtags from './hashtags/hashtagsMiddleware'
import login from './login/loginMiddleware'
import orderBy from './orderByMiddleware'
import permissions from './permissionsMiddleware'
import sentry from './sentryMiddleware'
import languages from './languages/languages'
import sluggify from './sluggifyMiddleware'
import softDelete from './softDelete/softDeleteMiddleware'
import userInteractions from './userInteractions'
import chatMiddleware from './chatMiddleware'
import validation from './validation/validationMiddleware'
import xss from './xssMiddleware'
export default (schema) => {
const middlewares = {

View File

@ -1,8 +1,9 @@
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import { createTestClient } from 'apollo-server-testing'
import gql from 'graphql-tag'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
let mutate
let authenticatedUser

View File

@ -1,5 +1,6 @@
import LanguageDetect from 'languagedetect'
import { removeHtmlTags } from '../helpers/cleanHtml'
import { removeHtmlTags } from '@middleware/helpers/cleanHtml'
const setPostLanguage = (text, defaultLanguage) => {
const lngDetector = new LanguageDetect()

View File

@ -1,10 +1,10 @@
import { sendMail } from '../helpers/email/sendMail'
import { sendMail } from '@middleware/helpers/email/sendMail'
import {
signupTemplate,
resetPasswordTemplate,
wrongAccountTemplate,
emailVerificationTemplate,
} from '../helpers/email/templateBuilder'
} from '@middleware/helpers/email/templateBuilder'
const sendSignupMail = async (resolve, root, args, context, resolveInfo) => {
const { inviteCode } = args

View File

@ -1,17 +1,18 @@
import gql from 'graphql-tag'
import Factory, { cleanDatabase } from '../../db/factories'
import { createTestClient } from 'apollo-server-testing'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer, { pubsub } from '../../server'
import gql from 'graphql-tag'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import {
createGroupMutation,
joinGroupMutation,
leaveGroupMutation,
changeGroupMemberRoleMutation,
removeUserFromGroupMutation,
} from '../../graphql/groups'
import { createMessageMutation } from '../../graphql/messages'
import { createRoomMutation } from '../../graphql/rooms'
} from '@graphql/groups'
import { createMessageMutation } from '@graphql/messages'
import { createRoomMutation } from '@graphql/rooms'
import createServer, { pubsub } from '@src/server'
const sendMailMock = jest.fn()
jest.mock('../helpers/email/sendMail', () => ({
@ -19,8 +20,10 @@ jest.mock('../helpers/email/sendMail', () => ({
}))
const chatMessageTemplateMock = jest.fn()
const notificationTemplateMock = jest.fn()
jest.mock('../helpers/email/templateBuilder', () => ({
chatMessageTemplate: () => chatMessageTemplateMock(),
notificationTemplate: () => notificationTemplateMock(),
}))
let isUserOnlineMock = jest.fn()
@ -85,8 +88,8 @@ afterAll(async () => {
beforeEach(async () => {
publishSpy.mockClear()
notifiedUser = await neode.create(
'User',
notifiedUser = await Factory.build(
'user',
{
id: 'you',
name: 'Al Capone',
@ -186,6 +189,7 @@ describe('notifications', () => {
describe('commenter is not me', () => {
beforeEach(async () => {
jest.clearAllMocks()
commentContent = 'Commenters comment.'
commentAuthor = await neode.create(
'User',
@ -201,25 +205,8 @@ describe('notifications', () => {
)
})
it('sends me a notification', async () => {
it('sends me a notification and email', async () => {
await createCommentOnPostAction()
const expected = expect.objectContaining({
data: {
notifications: [
{
read: false,
createdAt: expect.any(String),
reason: 'commented_on_post',
from: {
__typename: 'Comment',
id: 'c47',
content: commentContent,
},
relatedUser: null,
},
],
},
})
await expect(
query({
query: notificationQuery,
@ -227,24 +214,85 @@ describe('notifications', () => {
read: false,
},
}),
).resolves.toEqual(expected)
).resolves.toMatchObject(
expect.objectContaining({
data: {
notifications: [
{
read: false,
createdAt: expect.any(String),
reason: 'commented_on_post',
from: {
__typename: 'Comment',
id: 'c47',
content: commentContent,
},
relatedUser: null,
},
],
},
}),
)
// Mail
expect(sendMailMock).toHaveBeenCalledTimes(1)
expect(notificationTemplateMock).toHaveBeenCalledTimes(1)
})
it('sends me no notification if I have blocked the comment author', async () => {
await notifiedUser.relateTo(commentAuthor, 'blocked')
await createCommentOnPostAction()
const expected = expect.objectContaining({
data: { notifications: [] },
})
describe('if I have disabled `emailNotificationsCommentOnObservedPost`', () => {
it('sends me a notification but no email', async () => {
await notifiedUser.update({ emailNotificationsCommentOnObservedPost: false })
await createCommentOnPostAction()
await expect(
query({
query: notificationQuery,
variables: {
read: false,
},
}),
).resolves.toMatchObject(
expect.objectContaining({
data: {
notifications: [
{
read: false,
createdAt: expect.any(String),
reason: 'commented_on_post',
from: {
__typename: 'Comment',
id: 'c47',
content: commentContent,
},
relatedUser: null,
},
],
},
}),
)
await expect(
query({
query: notificationQuery,
variables: {
read: false,
},
}),
).resolves.toEqual(expected)
// No Mail
expect(sendMailMock).not.toHaveBeenCalled()
expect(notificationTemplateMock).not.toHaveBeenCalled()
})
})
describe('if I have blocked the comment author', () => {
it('sends me no notification', async () => {
await notifiedUser.relateTo(commentAuthor, 'blocked')
await createCommentOnPostAction()
const expected = expect.objectContaining({
data: { notifications: [] },
})
await expect(
query({
query: notificationQuery,
variables: {
read: false,
},
}),
).resolves.toEqual(expected)
})
})
})
@ -273,6 +321,7 @@ describe('notifications', () => {
})
beforeEach(async () => {
jest.clearAllMocks()
postAuthor = await neode.create(
'User',
{
@ -295,7 +344,7 @@ describe('notifications', () => {
'Hey <a class="mention" data-mention-id="you" href="/profile/you/al-capone">@al-capone</a> how do you do?'
})
it('sends me a notification', async () => {
it('sends me a notification and email', async () => {
await createPostAction()
const expectedContent =
'Hey <a class="mention" data-mention-id="you" href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do?'
@ -323,6 +372,47 @@ describe('notifications', () => {
],
},
})
// Mail
expect(sendMailMock).toHaveBeenCalledTimes(1)
expect(notificationTemplateMock).toHaveBeenCalledTimes(1)
})
describe('if I have disabled `emailNotificationsMention`', () => {
it('sends me a notification but no email', async () => {
await notifiedUser.update({ emailNotificationsMention: false })
await createPostAction()
const expectedContent =
'Hey <a class="mention" data-mention-id="you" href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do?'
await expect(
query({
query: notificationQuery,
variables: {
read: false,
},
}),
).resolves.toMatchObject({
errors: undefined,
data: {
notifications: [
{
read: false,
createdAt: expect.any(String),
reason: 'mentioned_in_post',
from: {
__typename: 'Post',
id: 'p47',
content: expectedContent,
},
},
],
},
})
// Mail
expect(sendMailMock).not.toHaveBeenCalled()
expect(notificationTemplateMock).not.toHaveBeenCalled()
})
})
it('publishes `NOTIFICATION_ADDED` to me', async () => {
@ -688,7 +778,7 @@ describe('notifications', () => {
roomId = room.data.CreateRoom.id
})
describe('chatReceiver is online', () => {
describe('if the chatReceiver is online', () => {
it('sends no email', async () => {
isUserOnlineMock = jest.fn().mockReturnValue(true)
@ -705,7 +795,7 @@ describe('notifications', () => {
})
})
describe('chatReceiver is offline', () => {
describe('if the chatReceiver is offline', () => {
it('sends an email', async () => {
isUserOnlineMock = jest.fn().mockReturnValue(false)
@ -722,7 +812,7 @@ describe('notifications', () => {
})
})
describe('chatReceiver has blocked chatSender', () => {
describe('if the chatReceiver has blocked chatSender', () => {
it('sends no email', async () => {
isUserOnlineMock = jest.fn().mockReturnValue(false)
await chatReceiver.relateTo(chatSender, 'blocked')
@ -740,10 +830,10 @@ describe('notifications', () => {
})
})
describe('chatReceiver has disabled email notifications', () => {
describe('if the chatReceiver has disabled `emailNotificationsChatMessage`', () => {
it('sends no email', async () => {
isUserOnlineMock = jest.fn().mockReturnValue(false)
await chatReceiver.update({ sendNotificationEmails: false })
await chatReceiver.update({ emailNotificationsChatMessage: false })
await mutate({
mutation: createMessageMutation(),
@ -763,8 +853,8 @@ describe('notifications', () => {
let groupOwner
beforeEach(async () => {
groupOwner = await neode.create(
'User',
groupOwner = await Factory.build(
'user',
{
id: 'group-owner',
name: 'Group Owner',
@ -791,7 +881,7 @@ describe('notifications', () => {
})
describe('user joins group', () => {
beforeEach(async () => {
const joinGroupAction = async () => {
authenticatedUser = await notifiedUser.toJson()
await mutate({
mutation: joinGroupMutation(),
@ -801,9 +891,14 @@ describe('notifications', () => {
},
})
authenticatedUser = await groupOwner.toJson()
}
beforeEach(async () => {
jest.clearAllMocks()
})
it('has the notification in database', async () => {
it('sends the group owner a notification and email', async () => {
await joinGroupAction()
await expect(
query({
query: notificationQuery,
@ -827,19 +922,50 @@ describe('notifications', () => {
},
errors: undefined,
})
// Mail
expect(sendMailMock).toHaveBeenCalledTimes(1)
expect(notificationTemplateMock).toHaveBeenCalledTimes(1)
})
describe('if the group owner has disabled `emailNotificationsGroupMemberJoined`', () => {
it('sends the group owner a notification but no email', async () => {
await groupOwner.update({ emailNotificationsGroupMemberJoined: false })
await joinGroupAction()
await expect(
query({
query: notificationQuery,
}),
).resolves.toMatchObject({
data: {
notifications: [
{
read: false,
reason: 'user_joined_group',
createdAt: expect.any(String),
from: {
__typename: 'Group',
id: 'closed-group',
},
relatedUser: {
id: 'you',
},
},
],
},
errors: undefined,
})
// Mail
expect(sendMailMock).not.toHaveBeenCalled()
expect(notificationTemplateMock).not.toHaveBeenCalled()
})
})
})
describe('user leaves group', () => {
beforeEach(async () => {
describe('user joins and leaves group', () => {
const leaveGroupAction = async () => {
authenticatedUser = await notifiedUser.toJson()
await mutate({
mutation: joinGroupMutation(),
variables: {
groupId: 'closed-group',
userId: authenticatedUser.id,
},
})
await mutate({
mutation: leaveGroupMutation(),
variables: {
@ -848,9 +974,22 @@ describe('notifications', () => {
},
})
authenticatedUser = await groupOwner.toJson()
}
beforeEach(async () => {
jest.clearAllMocks()
authenticatedUser = await notifiedUser.toJson()
await mutate({
mutation: joinGroupMutation(),
variables: {
groupId: 'closed-group',
userId: authenticatedUser.id,
},
})
})
it('has two the notification in database', async () => {
it('sends the group owner two notifications and emails', async () => {
await leaveGroupAction()
await expect(
query({
query: notificationQuery,
@ -886,19 +1025,61 @@ describe('notifications', () => {
},
errors: undefined,
})
// Mail
expect(sendMailMock).toHaveBeenCalledTimes(2)
expect(notificationTemplateMock).toHaveBeenCalledTimes(2)
})
describe('if the group owner has disabled `emailNotificationsGroupMemberLeft`', () => {
it('sends the group owner two notification but only only one email', async () => {
await groupOwner.update({ emailNotificationsGroupMemberLeft: false })
await leaveGroupAction()
await expect(
query({
query: notificationQuery,
}),
).resolves.toMatchObject({
data: {
notifications: [
{
read: false,
reason: 'user_left_group',
createdAt: expect.any(String),
from: {
__typename: 'Group',
id: 'closed-group',
},
relatedUser: {
id: 'you',
},
},
{
read: false,
reason: 'user_joined_group',
createdAt: expect.any(String),
from: {
__typename: 'Group',
id: 'closed-group',
},
relatedUser: {
id: 'you',
},
},
],
},
errors: undefined,
})
// Mail
expect(sendMailMock).toHaveBeenCalledTimes(1)
expect(notificationTemplateMock).toHaveBeenCalledTimes(1)
})
})
})
describe('user role in group changes', () => {
beforeEach(async () => {
authenticatedUser = await notifiedUser.toJson()
await mutate({
mutation: joinGroupMutation(),
variables: {
groupId: 'closed-group',
userId: authenticatedUser.id,
},
})
const changeGroupMemberRoleAction = async () => {
authenticatedUser = await groupOwner.toJson()
await mutate({
mutation: changeGroupMemberRoleMutation(),
@ -909,9 +1090,23 @@ describe('notifications', () => {
},
})
authenticatedUser = await notifiedUser.toJson()
}
beforeEach(async () => {
authenticatedUser = await notifiedUser.toJson()
await mutate({
mutation: joinGroupMutation(),
variables: {
groupId: 'closed-group',
userId: authenticatedUser.id,
},
})
// Clear after because the above generates a notification not related
jest.clearAllMocks()
})
it('has notification in database', async () => {
it('sends the group member a notification and email', async () => {
await changeGroupMemberRoleAction()
await expect(
query({
query: notificationQuery,
@ -935,19 +1130,49 @@ describe('notifications', () => {
},
errors: undefined,
})
// Mail
expect(sendMailMock).toHaveBeenCalledTimes(1)
expect(notificationTemplateMock).toHaveBeenCalledTimes(1)
})
describe('if the group member has disabled `emailNotificationsGroupMemberRoleChanged`', () => {
it('sends the group member a notification but no email', async () => {
notifiedUser.update({ emailNotificationsGroupMemberRoleChanged: false })
await changeGroupMemberRoleAction()
await expect(
query({
query: notificationQuery,
}),
).resolves.toMatchObject({
data: {
notifications: [
{
read: false,
reason: 'changed_group_member_role',
createdAt: expect.any(String),
from: {
__typename: 'Group',
id: 'closed-group',
},
relatedUser: {
id: 'group-owner',
},
},
],
},
errors: undefined,
})
// Mail
expect(sendMailMock).not.toHaveBeenCalled()
expect(notificationTemplateMock).not.toHaveBeenCalled()
})
})
})
describe('user is removed from group', () => {
beforeEach(async () => {
authenticatedUser = await notifiedUser.toJson()
await mutate({
mutation: joinGroupMutation(),
variables: {
groupId: 'closed-group',
userId: authenticatedUser.id,
},
})
const removeUserFromGroupAction = async () => {
authenticatedUser = await groupOwner.toJson()
await mutate({
mutation: removeUserFromGroupMutation(),
@ -957,9 +1182,23 @@ describe('notifications', () => {
},
})
authenticatedUser = await notifiedUser.toJson()
}
beforeEach(async () => {
authenticatedUser = await notifiedUser.toJson()
await mutate({
mutation: joinGroupMutation(),
variables: {
groupId: 'closed-group',
userId: authenticatedUser.id,
},
})
// Clear after because the above generates a notification not related
jest.clearAllMocks()
})
it('has notification in database', async () => {
it('sends the previous group member a notification and email', async () => {
await removeUserFromGroupAction()
await expect(
query({
query: notificationQuery,
@ -983,6 +1222,44 @@ describe('notifications', () => {
},
errors: undefined,
})
// Mail
expect(sendMailMock).toHaveBeenCalledTimes(1)
expect(notificationTemplateMock).toHaveBeenCalledTimes(1)
})
describe('if the previous group member has disabled `emailNotificationsGroupMemberRemoved`', () => {
it('sends the previous group member a notification but no email', async () => {
notifiedUser.update({ emailNotificationsGroupMemberRemoved: false })
await removeUserFromGroupAction()
await expect(
query({
query: notificationQuery,
}),
).resolves.toMatchObject({
data: {
notifications: [
{
read: false,
reason: 'removed_user_from_group',
createdAt: expect.any(String),
from: {
__typename: 'Group',
id: 'closed-group',
},
relatedUser: {
id: 'group-owner',
},
},
],
},
errors: undefined,
})
// Mail
expect(sendMailMock).not.toHaveBeenCalled()
expect(notificationTemplateMock).not.toHaveBeenCalled()
})
})
})
})

View File

@ -1,11 +1,15 @@
/* eslint-disable security/detect-object-injection */
import { sendMail } from '@middleware/helpers/email/sendMail'
import {
chatMessageTemplate,
notificationTemplate,
} from '@middleware/helpers/email/templateBuilder'
import { isUserOnline } from '@middleware/helpers/isUserOnline'
import { validateNotifyUsers } from '@middleware/validation/validationMiddleware'
// eslint-disable-next-line import/no-cycle
import { pubsub, NOTIFICATION_ADDED } from '../../server'
import { pubsub, NOTIFICATION_ADDED } from '@src/server'
import extractMentionedUsers from './mentions/extractMentionedUsers'
import { validateNotifyUsers } from '../validation/validationMiddleware'
import { sendMail } from '../helpers/email/sendMail'
import { chatMessageTemplate, notificationTemplate } from '../helpers/email/templateBuilder'
import { isUserOnline } from '../helpers/isUserOnline'
const queryNotificationEmails = async (context, notificationUserIds) => {
if (!(notificationUserIds && notificationUserIds.length)) return []
@ -34,7 +38,7 @@ const queryNotificationEmails = async (context, notificationUserIds) => {
}
}
const publishNotifications = async (context, promises) => {
const publishNotifications = async (context, promises, emailNotificationSetting: string) => {
let notifications = await Promise.all(promises)
notifications = notifications.flat()
const notificationsEmailAddresses = await queryNotificationEmails(
@ -43,7 +47,7 @@ const publishNotifications = async (context, promises) => {
)
notifications.forEach((notificationAdded, index) => {
pubsub.publish(NOTIFICATION_ADDED, { notificationAdded })
if (notificationAdded.to.sendNotificationEmails) {
if (notificationAdded.to[emailNotificationSetting] ?? true) {
sendMail(
notificationTemplate({
email: notificationsEmailAddresses[index].email,
@ -58,9 +62,11 @@ const handleJoinGroup = async (resolve, root, args, context, resolveInfo) => {
const { groupId, userId } = args
const user = await resolve(root, args, context, resolveInfo)
if (user) {
await publishNotifications(context, [
notifyOwnersOfGroup(groupId, userId, 'user_joined_group', context),
])
await publishNotifications(
context,
[notifyOwnersOfGroup(groupId, userId, 'user_joined_group', context)],
'emailNotificationsGroupMemberJoined',
)
}
return user
}
@ -69,9 +75,11 @@ const handleLeaveGroup = async (resolve, root, args, context, resolveInfo) => {
const { groupId, userId } = args
const user = await resolve(root, args, context, resolveInfo)
if (user) {
await publishNotifications(context, [
notifyOwnersOfGroup(groupId, userId, 'user_left_group', context),
])
await publishNotifications(
context,
[notifyOwnersOfGroup(groupId, userId, 'user_left_group', context)],
'emailNotificationsGroupMemberLeft',
)
}
return user
}
@ -80,9 +88,11 @@ const handleChangeGroupMemberRole = async (resolve, root, args, context, resolve
const { groupId, userId } = args
const user = await resolve(root, args, context, resolveInfo)
if (user) {
await publishNotifications(context, [
notifyMemberOfGroup(groupId, userId, 'changed_group_member_role', context),
])
await publishNotifications(
context,
[notifyMemberOfGroup(groupId, userId, 'changed_group_member_role', context)],
'emailNotificationsGroupMemberRoleChanged',
)
}
return user
}
@ -91,9 +101,11 @@ const handleRemoveUserFromGroup = async (resolve, root, args, context, resolveIn
const { groupId, userId } = args
const user = await resolve(root, args, context, resolveInfo)
if (user) {
await publishNotifications(context, [
notifyMemberOfGroup(groupId, userId, 'removed_user_from_group', context),
])
await publishNotifications(
context,
[notifyMemberOfGroup(groupId, userId, 'removed_user_from_group', context)],
'emailNotificationsGroupMemberRemoved',
)
}
return user
}
@ -102,9 +114,11 @@ const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo
const idsOfUsers = extractMentionedUsers(args.content)
const post = await resolve(root, args, context, resolveInfo)
if (post) {
await publishNotifications(context, [
notifyUsersOfMention('Post', post.id, idsOfUsers, 'mentioned_in_post', context),
])
await publishNotifications(
context,
[notifyUsersOfMention('Post', post.id, idsOfUsers, 'mentioned_in_post', context)],
'emailNotificationsMention',
)
}
return post
}
@ -115,16 +129,26 @@ const handleContentDataOfComment = async (resolve, root, args, context, resolveI
const comment = await resolve(root, args, context, resolveInfo)
const [postAuthor] = await postAuthorOfComment(comment.id, { context })
idsOfMentionedUsers = idsOfMentionedUsers.filter((id) => id !== postAuthor.id)
await publishNotifications(context, [
notifyUsersOfMention(
'Comment',
comment.id,
idsOfMentionedUsers,
'mentioned_in_comment',
context,
),
notifyUsersOfComment('Comment', comment.id, 'commented_on_post', context),
])
await publishNotifications(
context,
[
notifyUsersOfMention(
'Comment',
comment.id,
idsOfMentionedUsers,
'mentioned_in_comment',
context,
),
],
'emailNotificationsMention',
)
await publishNotifications(
context,
[notifyUsersOfComment('Comment', comment.id, 'commented_on_post', context)],
'emailNotificationsCommentOnObservedPost',
)
return comment
}
@ -335,7 +359,7 @@ const handleCreateMessage = async (resolve, root, args, context, resolveInfo) =>
MATCH (room)<-[:CHATS_IN]-(recipientUser:User)-[:PRIMARY_EMAIL]->(emailAddress:EmailAddress)
WHERE NOT recipientUser.id = $currentUserId
AND NOT (recipientUser)-[:BLOCKED]-(currentUser)
AND recipientUser.sendNotificationEmails = true
AND NOT recipientUser.emailNotificationsChatMessage = false
RETURN recipientUser, emailAddress {.email}
`
const txResponse = await transaction.run(messageRecipientCypher, {

View File

@ -1,10 +1,10 @@
import gql from 'graphql-tag'
import { cleanDatabase } from '../../db/factories'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import { createTestClient } from 'apollo-server-testing'
import gql from 'graphql-tag'
import CONFIG from '../../config'
import CONFIG from '@config/index'
import { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
CONFIG.CATEGORIES_ACTIVE = false

View File

@ -1,8 +1,9 @@
import gql from 'graphql-tag'
import { cleanDatabase } from '../db/factories'
import { getNeode, getDriver } from '../db/neo4j'
import { createTestClient } from 'apollo-server-testing'
import createServer from '../server'
import gql from 'graphql-tag'
import { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
const neode = getNeode()
const driver = getDriver()

View File

@ -1,9 +1,10 @@
import { createTestClient } from 'apollo-server-testing'
import createServer from '../server'
import Factory, { cleanDatabase } from '../db/factories'
import gql from 'graphql-tag'
import { getDriver, getNeode } from '../db/neo4j'
import CONFIG from '../config'
import CONFIG from '@config/index'
import Factory, { cleanDatabase } from '@db/factories'
import { getDriver, getNeode } from '@db/neo4j'
import createServer from '@src/server'
const instance = getNeode()
const driver = getDriver()

View File

@ -1,7 +1,8 @@
import { rule, shield, deny, allow, or, and } from 'graphql-shield'
import { getNeode } from '../db/neo4j'
import CONFIG from '../config'
import { validateInviteCode } from '../schema/resolvers/transactions/inviteCodes'
import CONFIG from '@config/index'
import { getNeode } from '@db/neo4j'
import { validateInviteCode } from '@schema/resolvers/transactions/inviteCodes'
const debug = !!CONFIG.DEBUG
const allowExternalErrors = true
@ -470,6 +471,7 @@ export default shield(
},
User: {
email: or(isMyOwn, isAdmin),
emailNotificationSettings: isMyOwn,
},
Report: isModerator,
},

View File

@ -1,5 +1,6 @@
import { sentry } from 'graphql-middleware-sentry'
import CONFIG from '../config'
import CONFIG from '@config/index'
// eslint-disable-next-line import/no-mutable-exports
let sentryMiddleware: any = (resolve, root, args, context, resolveInfo) =>

View File

@ -1,10 +1,11 @@
import { getNeode, getDriver } from '../db/neo4j'
import createServer from '../server'
import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../db/factories'
import { createGroupMutation, updateGroupMutation } from '../graphql/groups'
import { createPostMutation } from '../graphql/posts'
import { signupVerificationMutation } from '../graphql/authentications'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import { signupVerificationMutation } from '@graphql/authentications'
import { createGroupMutation, updateGroupMutation } from '@graphql/groups'
import { createPostMutation } from '@graphql/posts'
import createServer from '@src/server'
let authenticatedUser
let variables

View File

@ -1,8 +1,9 @@
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import { createTestClient } from 'apollo-server-testing'
import gql from 'graphql-tag'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
const neode = getNeode()
const driver = getDriver()

View File

@ -1,8 +1,9 @@
import Factory, { cleanDatabase } from '../db/factories'
import gql from 'graphql-tag'
import { getNeode, getDriver } from '../db/neo4j'
import createServer from '../server'
import { createTestClient } from 'apollo-server-testing'
import gql from 'graphql-tag'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
let query, aUser, bUser, post, authenticatedUser, variables

View File

@ -1,8 +1,9 @@
import gql from 'graphql-tag'
import Factory, { cleanDatabase } from '../../db/factories'
import { getNeode, getDriver } from '../../db/neo4j'
import { createTestClient } from 'apollo-server-testing'
import createServer from '../../server'
import gql from 'graphql-tag'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
const neode = getNeode()
const driver = getDriver()

View File

@ -1,4 +1,5 @@
import walkRecursive from '../helpers/walkRecursive'
import walkRecursive from '@helpers/walkRecursive'
import { cleanHtml } from './helpers/cleanHtml'
// exclamation mark separetes field names, that should not be sanitized

View File

@ -58,4 +58,15 @@ export default {
},
pinned: { type: 'boolean', default: null, valid: [null, true] },
postType: { type: 'string', default: 'Article', valid: ['Article', 'Event'] },
observes: {
type: 'relationship',
relationship: 'OBSERVES',
target: 'User',
direction: 'in',
properties: {
createdAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() },
updatedAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() },
active: { type: 'boolean', default: true },
},
},
}

View File

@ -1,5 +1,5 @@
import { cleanDatabase } from '../db/factories'
import { getNeode, getDriver } from '../db/neo4j'
import { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
const driver = getDriver()
const neode = getNeode()

View File

@ -155,12 +155,50 @@ export default {
type: 'boolean',
default: false,
},
sendNotificationEmails: {
// emailNotifications
emailNotificationsCommentOnObservedPost: {
type: 'boolean',
default: true,
},
emailNotificationsMention: {
type: 'boolean',
default: true,
},
emailNotificationsChatMessage: {
type: 'boolean',
default: true,
},
emailNotificationsGroupMemberJoined: {
type: 'boolean',
default: true,
},
emailNotificationsGroupMemberLeft: {
type: 'boolean',
default: true,
},
emailNotificationsGroupMemberRemoved: {
type: 'boolean',
default: true,
},
emailNotificationsGroupMemberRoleChanged: {
type: 'boolean',
default: true,
},
locale: {
type: 'string',
allow: [null],
},
observes: {
type: 'relationship',
relationship: 'OBSERVES',
target: 'Post',
direction: 'out',
properties: {
createdAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() },
updatedAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() },
active: { type: 'boolean', default: true },
},
},
}

View File

@ -1,6 +1,7 @@
import { makeAugmentedSchema } from 'neo4j-graphql-js'
import typeDefs from './types'
import resolvers from './resolvers'
import typeDefs from './types'
export default makeAugmentedSchema({
typeDefs,
@ -10,6 +11,8 @@ export default makeAugmentedSchema({
exclude: [
'Badge',
'Embed',
'EmailNotificationSettings',
'EmailNotificationSettingsOption',
'EmailAddress',
'Notification',
'Statistics',

View File

@ -1,8 +1,9 @@
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { createTestClient } from 'apollo-server-testing'
import createServer from '../../server'
import { getNeode, getDriver } from '../../db/neo4j'
import gql from 'graphql-tag'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
const driver = getDriver()
const neode = getNeode()

View File

@ -1,4 +1,5 @@
import { v4 as uuid } from 'uuid'
import Resolver from './helpers/Resolver'
export default {

View File

@ -1,8 +1,9 @@
import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
let mutate, query, authenticatedUser, variables
const instance = getNeode()

View File

@ -1,8 +1,9 @@
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getDriver, getNeode } from '../../db/neo4j'
import createServer from '../../server'
import { createTestClient } from 'apollo-server-testing'
import gql from 'graphql-tag'
import Factory, { cleanDatabase } from '@db/factories'
import { getDriver, getNeode } from '@db/neo4j'
import createServer from '@src/server'
const neode = getNeode()

View File

@ -1,10 +1,11 @@
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 existingEmailAddress from './helpers/existingEmailAddress'
import generateNonce from './helpers/generateNonce'
import normalizeEmail from './helpers/normalizeEmail'
import Resolver from './helpers/Resolver'
export default {
Query: {

View File

@ -1,9 +1,11 @@
import fetch from 'node-fetch'
import fs from 'node:fs'
import path from 'node:path'
import { createTestClient } from 'apollo-server-testing'
import createServer from '../../server'
import gql from 'graphql-tag'
import fetch from 'node-fetch'
import createServer from '@src/server'
jest.mock('node-fetch')
const mockedFetch = jest.mocked(fetch)

View File

@ -1,5 +1,6 @@
import fs from 'node:fs'
import path from 'node:path'
import { minimatch } from 'minimatch'
let oEmbedProvidersFile = fs.readFileSync(

View File

@ -2,13 +2,14 @@
/* eslint-disable n/global-require */
/* eslint-disable import/no-commonjs */
/* eslint-disable import/no-named-as-default */
import { ApolloError } from 'apollo-server'
import isArray from 'lodash/isArray'
import isEmpty from 'lodash/isEmpty'
import mergeWith from 'lodash/mergeWith'
import Metascraper from 'metascraper'
import fetch from 'node-fetch'
import { ApolloError } from 'apollo-server'
import isEmpty from 'lodash/isEmpty'
import isArray from 'lodash/isArray'
import mergeWith from 'lodash/mergeWith'
import findProvider from './findProvider'
// eslint-disable-next-line import/no-extraneous-dependencies

View File

@ -1,9 +1,10 @@
import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../../db/factories'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import CONFIG from '../../config'
import { filterPosts, createPostMutation } from '../../graphql/posts'
import CONFIG from '@config/index'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import { filterPosts, createPostMutation } from '@graphql/posts'
import createServer from '@src/server'
CONFIG.CATEGORIES_ACTIVE = false

View File

@ -1,9 +1,10 @@
import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../../db/factories'
import { getDriver, getNeode } from '../../db/neo4j'
import createServer from '../../server'
import gql from 'graphql-tag'
import Factory, { cleanDatabase } from '@db/factories'
import { getDriver, getNeode } from '@db/neo4j'
import createServer from '@src/server'
const driver = getDriver()
const neode = getNeode()

View File

@ -1,4 +1,4 @@
import { getNeode } from '../../db/neo4j'
import { getNeode } from '@db/neo4j'
const neode = getNeode()

View File

@ -1,5 +1,8 @@
import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../../db/factories'
import CONFIG from '@config/index'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import {
createGroupMutation,
updateGroupMutation,
@ -9,10 +12,8 @@ import {
removeUserFromGroupMutation,
groupMembersQuery,
groupQuery,
} from '../../graphql/groups'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import CONFIG from '../../config'
} from '@graphql/groups'
import createServer from '@src/server'
const driver = getDriver()
const neode = getNeode()

View File

@ -1,9 +1,11 @@
import { v4 as uuid } from 'uuid'
import { UserInputError } from 'apollo-server'
import CONFIG from '../../config'
import { CATEGORIES_MIN, CATEGORIES_MAX } from '../../constants/categories'
import { DESCRIPTION_WITHOUT_HTML_LENGTH_MIN } from '../../constants/groups'
import { removeHtmlTags } from '../../middleware/helpers/cleanHtml'
import { v4 as uuid } from 'uuid'
import CONFIG from '@config/index'
import { CATEGORIES_MIN, CATEGORIES_MAX } from '@constants/categories'
import { DESCRIPTION_WITHOUT_HTML_LENGTH_MIN } from '@constants/groups'
import { removeHtmlTags } from '@middleware/helpers/cleanHtml'
import Resolver, {
removeUndefinedNullValuesFromObject,
convertObjectToCypherMapLiteral,

View File

@ -1,6 +1,7 @@
import { getMutedUsers } from '../users'
import { mergeWith, isArray } from 'lodash'
import { getMutedUsers } from '@schema/resolvers/users'
export const filterForMutedUsers = async (params, context) => {
if (!context.user) return params
const [mutedUsers] = await Promise.all([getMutedUsers(context)])

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,9 +1,11 @@
/* eslint-disable promise/prefer-await-to-callbacks */
import { deleteImage, mergeImage } from './images'
import { getNeode, getDriver } from '../../../db/neo4j'
import Factory, { cleanDatabase } from '../../../db/factories'
import { UserInputError } from 'apollo-server'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import { deleteImage, mergeImage } from './images'
const driver = getDriver()
const neode = getNeode()
const uuid = '[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}'

View File

@ -1,13 +1,15 @@
/* eslint-disable promise/avoid-new */
/* eslint-disable security/detect-non-literal-fs-filename */
import { existsSync, unlinkSync, createWriteStream } from 'node:fs'
import path from 'node:path'
import { v4 as uuid } from 'uuid'
import { UserInputError } from 'apollo-server'
import { S3 } from 'aws-sdk'
import slug from 'slug'
import { existsSync, unlinkSync, createWriteStream } from 'node:fs'
import { UserInputError } from 'apollo-server'
import { getDriver } from '../../../db/neo4j'
import CONFIG from '../../../config'
import { v4 as uuid } from 'uuid'
import CONFIG from '@config/index'
import { getDriver } from '@db/neo4j'
// const widths = [34, 160, 320, 640, 1024]
const { AWS_ENDPOINT: endpoint, AWS_REGION: region, AWS_BUCKET: Bucket, S3_CONFIGURED } = CONFIG

View File

@ -1,4 +1,5 @@
import path from 'node:path'
import { fileLoader, mergeResolvers } from 'merge-graphql-schemas'
// the files must be correctly evaluated in built and dev state - therefore accept both js & ts files

View File

@ -1,10 +1,11 @@
/* 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 gql from 'graphql-tag'
import CONSTANTS_REGISTRATION from '@constants/registration'
import Factory, { cleanDatabase } from '@db/factories'
import { getDriver } from '@db/neo4j'
import createServer from '@src/server'
let user
let query

View File

@ -1,8 +1,9 @@
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import { createTestClient } from 'apollo-server-testing'
import gql from 'graphql-tag'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
let mutate, authenticatedUser

View File

@ -1,4 +1,5 @@
import { UserInputError } from 'apollo-server'
import Resolver from './helpers/Resolver'
import { queryLocations } from './users/location'

View File

@ -1,9 +1,10 @@
import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../../db/factories'
import { getNeode, getDriver } from '../../db/neo4j'
import { createRoomMutation, roomQuery } from '../../graphql/rooms'
import { createMessageMutation, messageQuery, markMessagesAsSeen } from '../../graphql/messages'
import createServer, { pubsub } from '../../server'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import { createMessageMutation, messageQuery, markMessagesAsSeen } from '@graphql/messages'
import { createRoomMutation, roomQuery } from '@graphql/rooms'
import createServer, { pubsub } from '@src/server'
const driver = getDriver()
const neode = getNeode()

View File

@ -1,9 +1,10 @@
import { neo4jgraphql } from 'neo4j-graphql-js'
import Resolver from './helpers/Resolver'
import { getUnreadRoomsCount } from './rooms'
import { pubsub, ROOM_COUNT_UPDATED, CHAT_MESSAGE_ADDED } from '../../server'
import { withFilter } from 'graphql-subscriptions'
import { neo4jgraphql } from 'neo4j-graphql-js'
import { pubsub, ROOM_COUNT_UPDATED, CHAT_MESSAGE_ADDED } from '@src/server'
import Resolver from './helpers/Resolver'
import { getUnreadRoomsCount } from './rooms'
const setMessagesAsDistributed = async (undistributedMessagesIds, session) => {
return session.writeTransaction(async (transaction) => {

View File

@ -1,8 +1,9 @@
import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
const neode = getNeode()
const driver = getDriver()

View File

@ -1,13 +1,14 @@
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 gql from 'graphql-tag'
import Factory, { cleanDatabase } from '@db/factories'
import { getDriver } from '@db/neo4j'
import {
markAsReadMutation,
markAllAsReadMutation,
notificationQuery,
} from '../../graphql/notifications'
} from '@graphql/notifications'
import createServer from '@src/server'
const driver = getDriver()
let authenticatedUser

View File

@ -1,6 +1,8 @@
import log from './helpers/databaseLogger'
import { withFilter } from 'graphql-subscriptions'
import { pubsub, NOTIFICATION_ADDED } from '../../server'
import { pubsub, NOTIFICATION_ADDED } from '@src/server'
import log from './helpers/databaseLogger'
export default {
Subscription: {

View File

@ -1,11 +1,11 @@
import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import { createPostMutation } from '../../graphql/posts'
import CONFIG from '../../config'
import CONFIG from '@config/index'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import { createPostMutation } from '@graphql/posts'
import createServer from '@src/server'
CONFIG.CATEGORIES_ACTIVE = false

View File

@ -1,10 +1,12 @@
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getNeode, getDriver } from '../../db/neo4j'
import CONSTANTS_REGISTRATION from '../../constants/registration'
import createPasswordReset from './helpers/createPasswordReset'
import createServer from '../../server'
import { createTestClient } from 'apollo-server-testing'
import gql from 'graphql-tag'
import CONSTANTS_REGISTRATION from '@constants/registration'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import createServer from '@src/server'
import createPasswordReset from './helpers/createPasswordReset'
const neode = getNeode()
const driver = getDriver()

View File

@ -1,6 +1,8 @@
import { v4 as uuid } from 'uuid'
import bcrypt from 'bcryptjs'
import CONSTANTS_REGISTRATION from '../../constants/registration'
import { v4 as uuid } from 'uuid'
import CONSTANTS_REGISTRATION from '@constants/registration'
import createPasswordReset from './helpers/createPasswordReset'
export default {

View File

@ -1,10 +1,11 @@
import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import { createPostMutation } from '../../graphql/posts'
import CONFIG from '../../config'
import CONFIG from '@config/index'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import { createPostMutation } from '@graphql/posts'
import createServer from '@src/server'
CONFIG.CATEGORIES_ACTIVE = true

View File

@ -1,15 +1,17 @@
import { v4 as uuid } from 'uuid'
import { neo4jgraphql } from 'neo4j-graphql-js'
import { isEmpty } from 'lodash'
import { UserInputError } from 'apollo-server'
import { mergeImage, deleteImage } from './images/images'
import Resolver from './helpers/Resolver'
import { isEmpty } from 'lodash'
import { neo4jgraphql } from 'neo4j-graphql-js'
import { v4 as uuid } from 'uuid'
import CONFIG from '@config/index'
import { validateEventParams } from './helpers/events'
import { filterForMutedUsers } from './helpers/filterForMutedUsers'
import { filterInvisiblePosts } from './helpers/filterInvisiblePosts'
import { filterPostsOfMyGroups } from './helpers/filterPostsOfMyGroups'
import { validateEventParams } from './helpers/events'
import Resolver from './helpers/Resolver'
import { mergeImage, deleteImage } from './images/images'
import { createOrUpdateLocations } from './users/location'
import CONFIG from '../../config'
const maintainPinnedPosts = (params) => {
const pinnedPostFilter = { pinned: true }

View File

@ -1,28 +1,27 @@
import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../../db/factories'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
import CONFIG from '@config/index'
import Factory, { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
import { signupVerificationMutation } from '@graphql/authentications'
import { createCommentMutation } from '@graphql/comments'
import {
createGroupMutation,
changeGroupMemberRoleMutation,
leaveGroupMutation,
} from '../../graphql/groups'
} from '@graphql/groups'
import {
createPostMutation,
postQuery,
filterPosts,
profilePagePosts,
searchPosts,
} from '../../graphql/posts'
import { createCommentMutation } from '../../graphql/comments'
// eslint-disable-next-line no-unused-vars
import { DESCRIPTION_WITHOUT_HTML_LENGTH_MIN } from '../../constants/groups'
import CONFIG from '../../config'
import { signupVerificationMutation } from '../../graphql/authentications'
} from '@graphql/posts'
import createServer from '@src/server'
CONFIG.CATEGORIES_ACTIVE = false
jest.mock('../../constants/groups', () => {
jest.mock('@constants/groups', () => {
return {
__esModule: true,
DESCRIPTION_WITHOUT_HTML_LENGTH_MIN: 5,

View File

@ -1,9 +1,10 @@
import Factory, { cleanDatabase } from '../../db/factories'
import gql from 'graphql-tag'
import { getDriver, getNeode } from '../../db/neo4j'
import createServer from '../../server'
import { createTestClient } from 'apollo-server-testing'
import CONFIG from '../../config'
import gql from 'graphql-tag'
import CONFIG from '@config/index'
import Factory, { cleanDatabase } from '@db/factories'
import { getDriver, getNeode } from '@db/neo4j'
import createServer from '@src/server'
const neode = getNeode()

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