mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Merge in master/refactor
- Add cypress test for DeleteImage - remove unnecessary ref and function call - use tokens - simplify logic to showDeleteImageButton - emit event when cropInProgress
This commit is contained in:
commit
44652a34a7
24
.github/ISSUE_TEMPLATE/devops_ticket.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/devops_ticket.md
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
name: 💥 DevOps ticket
|
||||
about: Help us manage our deployed App.
|
||||
labels: devops
|
||||
title: 💥 [DevOps]
|
||||
---
|
||||
|
||||
## :fire: DevOps ticket
|
||||
<!-- Describe your issue in detail. Include screenshots if needed. Give us as much information as possible. Use a clear and concise description of what the problem is.-->
|
||||
|
||||
### Motive
|
||||
<!-- Why does this task need to be done? What can we benefit from this? -->
|
||||
|
||||
### Related issues
|
||||
<!-- Are there any related issues to link to? Please paste them below for reference. -->
|
||||
|
||||
### Implementation
|
||||
<!-- Please, document any ideas of how the task can be performed. -->
|
||||
|
||||
### Validation
|
||||
<!-- How can we make sure that this task was successful? -->
|
||||
|
||||
### Additional context
|
||||
<!-- Add other context or background about the feature request here.-->
|
||||
63
CHANGELOG.md
63
CHANGELOG.md
@ -4,10 +4,67 @@ All notable changes to this project will be documented in this file. Dates are d
|
||||
|
||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
|
||||
#### [v0.3.1](https://github.com/Human-Connection/Human-Connection/compare/v0.3.0...v0.3.1)
|
||||
|
||||
> 10 February 2020
|
||||
|
||||
- fix: Display unblock feature only for blocking user [`#3034`](https://github.com/Human-Connection/Human-Connection/pull/3034)
|
||||
- refactor(factories): Refactor test factories with rosie.js [`#2921`](https://github.com/Human-Connection/Human-Connection/pull/2921)
|
||||
- build(deps-dev): bump @vue/cli-shared-utils from 4.1.2 to 4.2.2 in /webapp [`#3031`](https://github.com/Human-Connection/Human-Connection/pull/3031)
|
||||
- build(deps): bump graphql-shield from 7.0.10 to 7.0.11 in /backend [`#3028`](https://github.com/Human-Connection/Human-Connection/pull/3028)
|
||||
- build(deps-dev): bump codecov from 3.6.4 to 3.6.5 [`#3027`](https://github.com/Human-Connection/Human-Connection/pull/3027)
|
||||
- chore: Add DevOps issue template [`#2999`](https://github.com/Human-Connection/Human-Connection/pull/2999)
|
||||
- fix: Error pages can be translated [`#2826`](https://github.com/Human-Connection/Human-Connection/pull/2826)
|
||||
- build(deps-dev): bump apollo-server-testing from 2.9.16 to 2.10.0 in /backend [`#3020`](https://github.com/Human-Connection/Human-Connection/pull/3020)
|
||||
- build(deps): bump apollo-server from 2.9.16 to 2.10.0 in /backend [`#3019`](https://github.com/Human-Connection/Human-Connection/pull/3019)
|
||||
- build(deps): bump graphql-tag from 2.10.2 to 2.10.3 in /backend [`#3011`](https://github.com/Human-Connection/Human-Connection/pull/3011)
|
||||
- build(deps): bump graphql-shield from 7.0.9 to 7.0.10 in /backend [`#3010`](https://github.com/Human-Connection/Human-Connection/pull/3010)
|
||||
- build(deps-dev): bump @storybook/addon-actions from 5.3.10 to 5.3.12 in /webapp [`#2998`](https://github.com/Human-Connection/Human-Connection/pull/2998)
|
||||
- build(deps-dev): bump @storybook/addon-notes from 5.3.10 to 5.3.12 in /webapp [`#2997`](https://github.com/Human-Connection/Human-Connection/pull/2997)
|
||||
- build(deps-dev): bump @storybook/addon-a11y from 5.3.10 to 5.3.12 in /webapp [`#2996`](https://github.com/Human-Connection/Human-Connection/pull/2996)
|
||||
- build(deps): bump metascraper-author from 5.10.6 to 5.10.7 in /backend [`#2994`](https://github.com/Human-Connection/Human-Connection/pull/2994)
|
||||
- build(deps): bump metascraper-title from 5.10.6 to 5.10.7 in /backend [`#2978`](https://github.com/Human-Connection/Human-Connection/pull/2978)
|
||||
- build(deps-dev): bump @storybook/vue from 5.3.10 to 5.3.12 in /webapp [`#2995`](https://github.com/Human-Connection/Human-Connection/pull/2995)
|
||||
- build(deps): bump metascraper-audio from 5.10.6 to 5.10.7 in /backend [`#2993`](https://github.com/Human-Connection/Human-Connection/pull/2993)
|
||||
- build(deps): bump graphql-tag from 2.10.1 to 2.10.2 in /backend [`#2992`](https://github.com/Human-Connection/Human-Connection/pull/2992)
|
||||
- build(deps): bump metascraper-url from 5.10.6 to 5.10.7 in /backend [`#2991`](https://github.com/Human-Connection/Human-Connection/pull/2991)
|
||||
- build(deps): bump @sentry/node from 5.12.0 to 5.12.3 in /backend [`#2990`](https://github.com/Human-Connection/Human-Connection/pull/2990)
|
||||
- build(deps-dev): bump @storybook/addon-notes from 5.3.9 to 5.3.10 in /webapp [`#2951`](https://github.com/Human-Connection/Human-Connection/pull/2951)
|
||||
- build(deps): bump metascraper from 5.10.6 to 5.11.0 in /backend [`#2976`](https://github.com/Human-Connection/Human-Connection/pull/2976)
|
||||
- build(deps): bump metascraper-logo from 5.10.6 to 5.10.7 in /backend [`#2975`](https://github.com/Human-Connection/Human-Connection/pull/2975)
|
||||
- chore: Add issue template for Refactoring tickets [`#2983`](https://github.com/Human-Connection/Human-Connection/pull/2983)
|
||||
- build(deps): bump @nuxtjs/sentry from 3.1.0 to 3.2.2 in /webapp [`#2974`](https://github.com/Human-Connection/Human-Connection/pull/2974)
|
||||
- build(deps): bump metascraper-video from 5.10.6 to 5.10.7 in /backend [`#2952`](https://github.com/Human-Connection/Human-Connection/pull/2952)
|
||||
- build(deps): bump metascraper-lang from 5.10.6 to 5.10.7 in /backend [`#2950`](https://github.com/Human-Connection/Human-Connection/pull/2950)
|
||||
- build(deps): bump metascraper-description from 5.10.6 to 5.11.0 in /backend [`#2948`](https://github.com/Human-Connection/Human-Connection/pull/2948)
|
||||
- build(deps): bump @sentry/node from 5.11.2 to 5.12.0 in /backend [`#2977`](https://github.com/Human-Connection/Human-Connection/pull/2977)
|
||||
- build(deps): bump @nuxtjs/pwa from 3.0.0-beta.19 to 3.0.0-beta.20 in /webapp [`#2959`](https://github.com/Human-Connection/Human-Connection/pull/2959)
|
||||
- build(deps-dev): bump @storybook/addon-a11y from 5.3.9 to 5.3.10 in /webapp [`#2956`](https://github.com/Human-Connection/Human-Connection/pull/2956)
|
||||
- build(deps-dev): bump eslint-plugin-import from 2.20.0 to 2.20.1 in /webapp [`#2949`](https://github.com/Human-Connection/Human-Connection/pull/2949)
|
||||
- build(deps): bump metascraper-soundcloud from 5.10.6 to 5.10.7 in /backend [`#2945`](https://github.com/Human-Connection/Human-Connection/pull/2945)
|
||||
- build(deps): bump metascraper-date from 5.10.6 to 5.10.7 in /backend [`#2944`](https://github.com/Human-Connection/Human-Connection/pull/2944)
|
||||
- build(deps-dev): bump codecov from 3.6.2 to 3.6.4 [`#2943`](https://github.com/Human-Connection/Human-Connection/pull/2943)
|
||||
- build(deps-dev): bump @storybook/addon-actions in /webapp [`#2953`](https://github.com/Human-Connection/Human-Connection/pull/2953)
|
||||
- build(deps): bump metascraper-publisher in /backend [`#2954`](https://github.com/Human-Connection/Human-Connection/pull/2954)
|
||||
- build(deps-dev): bump eslint-plugin-import in /backend [`#2955`](https://github.com/Human-Connection/Human-Connection/pull/2955)
|
||||
- build(deps): bump metascraper-youtube from 5.10.6 to 5.10.7 in /backend [`#2957`](https://github.com/Human-Connection/Human-Connection/pull/2957)
|
||||
- build(deps): bump metascraper-image from 5.10.6 to 5.10.7 in /backend [`#2960`](https://github.com/Human-Connection/Human-Connection/pull/2960)
|
||||
- build(deps-dev): bump @storybook/vue from 5.3.9 to 5.3.10 in /webapp [`#2961`](https://github.com/Human-Connection/Human-Connection/pull/2961)
|
||||
- build(deps): bump @nuxtjs/axios from 5.9.4 to 5.9.5 in /webapp [`#2962`](https://github.com/Human-Connection/Human-Connection/pull/2962)
|
||||
- fix: Update mute/unmute icon to unused icon [`#2973`](https://github.com/Human-Connection/Human-Connection/pull/2973)
|
||||
- fix: Remove github release script breaking build [`#2971`](https://github.com/Human-Connection/Human-Connection/pull/2971)
|
||||
- Use original createdAt for merged users/emails [`#2969`](https://github.com/Human-Connection/Human-Connection/pull/2969)
|
||||
- Fix typo [`#2966`](https://github.com/Human-Connection/Human-Connection/pull/2966)
|
||||
- chore: Update to v0.3.0 [`#2941`](https://github.com/Human-Connection/Human-Connection/pull/2941)
|
||||
- Replace buildList with array of Promises [`46edc3f`](https://github.com/Human-Connection/Human-Connection/commit/46edc3fdd5b83c2f00506f595b1254d7597767e0)
|
||||
- build(deps-dev): bump @storybook/addon-notes in /webapp [`75137ce`](https://github.com/Human-Connection/Human-Connection/commit/75137ce716dadcc6f0ceeed6a2b0fe5c50fa7b8f)
|
||||
- Update to v0.3.0 [`dbe2c4c`](https://github.com/Human-Connection/Human-Connection/commit/dbe2c4cdd5bab2195c6369b84989507b9f7da768)
|
||||
|
||||
#### [v0.3.0](https://github.com/Human-Connection/Human-Connection/compare/v0.2.1...v0.3.0)
|
||||
|
||||
> 31 January 2020
|
||||
|
||||
- build(deps-dev): bump @babel/core from 7.8.3 to 7.8.4 in /webapp [`#2939`](https://github.com/Human-Connection/Human-Connection/pull/2939)
|
||||
- feat: 🍰 Direct Reply On Comment [`#2608`](https://github.com/Human-Connection/Human-Connection/pull/2608)
|
||||
- build(deps-dev): bump @babel/core from 7.8.3 to 7.8.4 in /backend [`#2938`](https://github.com/Human-Connection/Human-Connection/pull/2938)
|
||||
- fix: deploy script with new naming convention [`#2930`](https://github.com/Human-Connection/Human-Connection/pull/2930)
|
||||
@ -181,9 +238,9 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
- refactor(modules): Various import fixes [`#2773`](https://github.com/Human-Connection/Human-Connection/issues/2773) [`#2774`](https://github.com/Human-Connection/Human-Connection/issues/2774)
|
||||
- feat(webapp): Display deployed version in footer [`#1831`](https://github.com/Human-Connection/Human-Connection/issues/1831)
|
||||
- fix #2229 [`#2229`](https://github.com/Human-Connection/Human-Connection/issues/2229)
|
||||
- refactor: Make `db:setup` init stage of `migrate` [`b063847`](https://github.com/Human-Connection/Human-Connection/commit/b063847849a84db885337dc8e84e75ddaf87011f)
|
||||
- Improve styling per @alina-beck review [`bcc1ab1`](https://github.com/Human-Connection/Human-Connection/commit/bcc1ab167e8b1dfdac1ec0a05a0c14e8234bcabc)
|
||||
- test(cypress): Cover "Pinned post" feature [`d49afc2`](https://github.com/Human-Connection/Human-Connection/commit/d49afc25cfa1c1f98ed04f78dd3ff826cd85ae25)
|
||||
- Get rid of different factory files [`fc36729`](https://github.com/Human-Connection/Human-Connection/commit/fc367297e3e054f09b7f8f31788ab68d87f6babf)
|
||||
- Refactor factory for comments [`2fc71d7`](https://github.com/Human-Connection/Human-Connection/commit/2fc71d75a5d5eab9c3467e94e00257ef6dd7d8a0)
|
||||
- Refactor user factory [`2a79c53`](https://github.com/Human-Connection/Human-Connection/commit/2a79c53765b73f9b91691eb75f55cf8c9e48306e)
|
||||
|
||||
#### [v0.2.1](https://github.com/Human-Connection/Human-Connection/compare/v0.2.0...v0.2.1)
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "human-connection-backend",
|
||||
"version": "0.2.2",
|
||||
"version": "0.3.1",
|
||||
"description": "GraphQL Backend for Human Connection",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
@ -38,12 +38,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@hapi/joi": "^17.1.0",
|
||||
"@sentry/node": "^5.12.0",
|
||||
"@sentry/node": "^5.12.3",
|
||||
"apollo-cache-inmemory": "~1.6.5",
|
||||
"apollo-client": "~2.6.8",
|
||||
"apollo-link-context": "~1.0.19",
|
||||
"apollo-link-http": "~1.5.16",
|
||||
"apollo-server": "~2.9.16",
|
||||
"apollo-server": "~2.10.0",
|
||||
"apollo-server-express": "^2.9.16",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"bcryptjs": "~2.4.3",
|
||||
@ -60,27 +60,29 @@
|
||||
"graphql-iso-date": "~3.6.1",
|
||||
"graphql-middleware": "~4.0.2",
|
||||
"graphql-middleware-sentry": "^3.2.1",
|
||||
"graphql-shield": "~7.0.9",
|
||||
"graphql-tag": "~2.10.1",
|
||||
"graphql-redis-subscriptions": "^2.1.2",
|
||||
"graphql-shield": "~7.0.11",
|
||||
"graphql-tag": "~2.10.3",
|
||||
"helmet": "~3.21.2",
|
||||
"ioredis": "^4.14.1",
|
||||
"jsonwebtoken": "~8.5.1",
|
||||
"linkifyjs": "~2.1.8",
|
||||
"lodash": "~4.17.14",
|
||||
"merge-graphql-schemas": "^1.7.6",
|
||||
"metascraper": "^5.11.0",
|
||||
"metascraper-audio": "^5.10.6",
|
||||
"metascraper-author": "^5.10.6",
|
||||
"metascraper-audio": "^5.10.7",
|
||||
"metascraper-author": "^5.10.7",
|
||||
"metascraper-clearbit-logo": "^5.3.0",
|
||||
"metascraper-date": "^5.10.7",
|
||||
"metascraper-description": "^5.11.0",
|
||||
"metascraper-image": "^5.10.7",
|
||||
"metascraper-image": "^5.11.1",
|
||||
"metascraper-lang": "^5.10.7",
|
||||
"metascraper-lang-detector": "^4.10.2",
|
||||
"metascraper-logo": "^5.10.7",
|
||||
"metascraper-publisher": "^5.10.7",
|
||||
"metascraper-soundcloud": "^5.10.7",
|
||||
"metascraper-title": "^5.10.6",
|
||||
"metascraper-url": "^5.10.6",
|
||||
"metascraper-title": "^5.10.7",
|
||||
"metascraper-url": "^5.10.7",
|
||||
"metascraper-video": "^5.10.7",
|
||||
"metascraper-youtube": "^5.10.7",
|
||||
"migrate": "^1.6.2",
|
||||
@ -93,9 +95,10 @@
|
||||
"nodemailer": "^6.4.2",
|
||||
"nodemailer-html-to-text": "^3.1.0",
|
||||
"npm-run-all": "~4.1.5",
|
||||
"request": "~2.88.0",
|
||||
"request": "~2.88.2",
|
||||
"sanitize-html": "~1.21.1",
|
||||
"slug": "~2.1.1",
|
||||
"subscriptions-transport-ws": "^0.9.16",
|
||||
"trunc-html": "~1.1.2",
|
||||
"uuid": "~3.4.0",
|
||||
"validator": "^12.2.0",
|
||||
@ -109,7 +112,7 @@
|
||||
"@babel/plugin-proposal-throw-expressions": "^7.8.3",
|
||||
"@babel/preset-env": "~7.8.4",
|
||||
"@babel/register": "^7.8.3",
|
||||
"apollo-server-testing": "~2.9.16",
|
||||
"apollo-server-testing": "~2.10.0",
|
||||
"babel-core": "~7.0.0-0",
|
||||
"babel-eslint": "~10.0.3",
|
||||
"babel-jest": "~25.1.0",
|
||||
@ -119,7 +122,7 @@
|
||||
"eslint-config-prettier": "~6.10.0",
|
||||
"eslint-config-standard": "~14.1.0",
|
||||
"eslint-plugin-import": "~2.20.1",
|
||||
"eslint-plugin-jest": "~23.6.0",
|
||||
"eslint-plugin-jest": "~23.7.0",
|
||||
"eslint-plugin-node": "~11.0.0",
|
||||
"eslint-plugin-prettier": "~3.1.2",
|
||||
"eslint-plugin-promise": "~4.2.1",
|
||||
@ -127,6 +130,10 @@
|
||||
"jest": "~25.1.0",
|
||||
"nodemon": "~2.0.2",
|
||||
"prettier": "~1.19.1",
|
||||
"rosie": "^2.0.1",
|
||||
"supertest": "~4.0.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"fs-capacitor": "6.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { handler } from './webfinger'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
|
||||
let resource, res, json, status, contentType
|
||||
|
||||
const factory = Factory()
|
||||
const driver = getDriver()
|
||||
|
||||
const request = () => {
|
||||
@ -28,7 +27,7 @@ const request = () => {
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('webfinger', () => {
|
||||
@ -90,7 +89,7 @@ describe('webfinger', () => {
|
||||
|
||||
describe('given a user for acct', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('User', { slug: 'some-user' })
|
||||
await Factory.build('user', { slug: 'some-user' })
|
||||
})
|
||||
|
||||
it('returns user object', async () => {
|
||||
|
||||
@ -4,6 +4,9 @@ if (require.resolve) {
|
||||
dotenv.config({ path: require.resolve('../../.env') })
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const env = typeof Cypress !== 'undefined' ? Cypress.env() : process.env
|
||||
|
||||
const {
|
||||
MAPBOX_TOKEN,
|
||||
JWT_SECRET,
|
||||
@ -20,7 +23,10 @@ const {
|
||||
NEO4J_PASSWORD = 'neo4j',
|
||||
CLIENT_URI = 'http://localhost:3000',
|
||||
GRAPHQL_URI = 'http://localhost:4000',
|
||||
} = process.env
|
||||
REDIS_DOMAIN,
|
||||
REDIS_PORT,
|
||||
REDIS_PASSWORD,
|
||||
} = env
|
||||
|
||||
export const requiredConfigs = {
|
||||
MAPBOX_TOKEN,
|
||||
@ -58,7 +64,7 @@ export const developmentConfigs = {
|
||||
}
|
||||
|
||||
export const sentryConfigs = { SENTRY_DSN_BACKEND, COMMIT }
|
||||
|
||||
export const redisConfiig = { REDIS_DOMAIN, REDIS_PORT, REDIS_PASSWORD }
|
||||
export default {
|
||||
...requiredConfigs,
|
||||
...smtpConfigs,
|
||||
@ -66,4 +72,5 @@ export default {
|
||||
...serverConfigs,
|
||||
...developmentConfigs,
|
||||
...sentryConfigs,
|
||||
...redisConfiig,
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { cleanDatabase } from '../factories'
|
||||
import { cleanDatabase } from '../db/factories'
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
throw new Error(`You cannot clean the database in production environment!`)
|
||||
|
||||
229
backend/src/db/factories.js
Normal file
229
backend/src/db/factories.js
Normal file
@ -0,0 +1,229 @@
|
||||
import uuid from 'uuid/v4'
|
||||
import faker from 'faker'
|
||||
import slugify from 'slug'
|
||||
import { hashSync } from 'bcryptjs'
|
||||
import { Factory } from 'rosie'
|
||||
import { getDriver, getNeode } from './neo4j'
|
||||
|
||||
const neode = getNeode()
|
||||
|
||||
export const cleanDatabase = async (options = {}) => {
|
||||
const { driver = getDriver() } = options
|
||||
const session = driver.session()
|
||||
try {
|
||||
await session.writeTransaction(transaction => {
|
||||
return transaction.run(
|
||||
`
|
||||
MATCH (everything)
|
||||
DETACH DELETE everything
|
||||
`,
|
||||
)
|
||||
})
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
}
|
||||
|
||||
Factory.define('category')
|
||||
.attr('id', uuid)
|
||||
.attr('icon', 'globe')
|
||||
.attr('name', 'Global Peace & Nonviolence')
|
||||
.after((buildObject, options) => {
|
||||
return neode.create('Category', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('badge')
|
||||
.attr('type', 'crowdfunding')
|
||||
.attr('status', 'permanent')
|
||||
.after((buildObject, options) => {
|
||||
return neode.create('Badge', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('userWithoutEmailAddress')
|
||||
.option('password', '1234')
|
||||
.attrs({
|
||||
id: uuid,
|
||||
name: faker.name.findName,
|
||||
password: '1234',
|
||||
role: 'user',
|
||||
avatar: faker.internet.avatar,
|
||||
about: faker.lorem.paragraph,
|
||||
termsAndConditionsAgreedVersion: '0.0.1',
|
||||
termsAndConditionsAgreedAt: '2019-08-01T10:47:19.212Z',
|
||||
allowEmbedIframes: false,
|
||||
showShoutsPublicly: false,
|
||||
locale: 'en',
|
||||
})
|
||||
.attr('slug', ['slug', 'name'], (slug, name) => {
|
||||
return slug || slugify(name, { lower: true })
|
||||
})
|
||||
.attr('encryptedPassword', ['password'], password => {
|
||||
return hashSync(password, 10)
|
||||
})
|
||||
.after(async (buildObject, options) => {
|
||||
return neode.create('User', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('user')
|
||||
.extend('userWithoutEmailAddress')
|
||||
.option('email', faker.internet.exampleEmail)
|
||||
.after(async (buildObject, options) => {
|
||||
const [user, email] = await Promise.all([
|
||||
buildObject,
|
||||
neode.create('EmailAddress', { email: options.email }),
|
||||
])
|
||||
await Promise.all([user.relateTo(email, 'primaryEmail'), email.relateTo(user, 'belongsTo')])
|
||||
return user
|
||||
})
|
||||
|
||||
Factory.define('post')
|
||||
.option('categoryIds', [])
|
||||
.option('categories', ['categoryIds'], categoryIds => {
|
||||
if (categoryIds.length) return Promise.all(categoryIds.map(id => neode.find('Category', id)))
|
||||
// there must be at least one category
|
||||
return Promise.all([Factory.build('category')])
|
||||
})
|
||||
.option('tagIds', [])
|
||||
.option('tags', ['tagIds'], tagIds => {
|
||||
return Promise.all(tagIds.map(id => neode.find('Tag', id)))
|
||||
})
|
||||
.option('authorId', null)
|
||||
.option('author', ['authorId'], authorId => {
|
||||
if (authorId) return neode.find('User', authorId)
|
||||
return Factory.build('user')
|
||||
})
|
||||
.option('pinnedBy', null)
|
||||
.attrs({
|
||||
id: uuid,
|
||||
title: faker.lorem.sentence,
|
||||
content: faker.lorem.paragraphs,
|
||||
image: faker.image.unsplash.imageUrl,
|
||||
visibility: 'public',
|
||||
deleted: false,
|
||||
imageBlurred: false,
|
||||
imageAspectRatio: 1.333,
|
||||
})
|
||||
.attr('pinned', ['pinned'], pinned => {
|
||||
// Convert false to null
|
||||
return pinned || null
|
||||
})
|
||||
.attr('contentExcerpt', ['contentExcerpt', 'content'], (contentExcerpt, content) => {
|
||||
return contentExcerpt || content
|
||||
})
|
||||
.attr('slug', ['slug', 'title'], (slug, title) => {
|
||||
return slug || slugify(title, { lower: true })
|
||||
})
|
||||
.attr('language', ['language'], language => {
|
||||
return language || 'en'
|
||||
})
|
||||
.after(async (buildObject, options) => {
|
||||
const [post, author, categories, tags] = await Promise.all([
|
||||
neode.create('Post', buildObject),
|
||||
options.author,
|
||||
options.categories,
|
||||
options.tags,
|
||||
])
|
||||
await Promise.all([
|
||||
post.relateTo(author, 'author'),
|
||||
Promise.all(categories.map(c => c.relateTo(post, 'post'))),
|
||||
Promise.all(tags.map(t => t.relateTo(post, 'post'))),
|
||||
])
|
||||
if (buildObject.pinned) {
|
||||
const pinnedBy = await (options.pinnedBy || Factory.build('user', { role: 'admin' }))
|
||||
await pinnedBy.relateTo(post, 'pinned')
|
||||
}
|
||||
return post
|
||||
})
|
||||
|
||||
Factory.define('comment')
|
||||
.option('postId', null)
|
||||
.option('post', ['postId'], postId => {
|
||||
if (postId) return neode.find('Post', postId)
|
||||
return Factory.build('post')
|
||||
})
|
||||
.option('authorId', null)
|
||||
.option('author', ['authorId'], authorId => {
|
||||
if (authorId) return neode.find('User', authorId)
|
||||
return Factory.build('user')
|
||||
})
|
||||
.attrs({
|
||||
id: uuid,
|
||||
content: faker.lorem.sentence,
|
||||
})
|
||||
.attr('contentExcerpt', ['contentExcerpt', 'content'], (contentExcerpt, content) => {
|
||||
return contentExcerpt || content
|
||||
})
|
||||
.after(async (buildObject, options) => {
|
||||
const [comment, author, post] = await Promise.all([
|
||||
neode.create('Comment', buildObject),
|
||||
options.author,
|
||||
options.post,
|
||||
])
|
||||
await Promise.all([comment.relateTo(author, 'author'), comment.relateTo(post, 'post')])
|
||||
return comment
|
||||
})
|
||||
|
||||
Factory.define('donations')
|
||||
.attr('id', uuid)
|
||||
.attr('goal', 15000)
|
||||
.attr('progress', 0)
|
||||
.after((buildObject, options) => {
|
||||
return neode.create('Donations', buildObject)
|
||||
})
|
||||
|
||||
const emailDefaults = {
|
||||
email: faker.internet.email,
|
||||
verifiedAt: () => new Date().toISOString(),
|
||||
}
|
||||
|
||||
Factory.define('emailAddress')
|
||||
.attr(emailDefaults)
|
||||
.after((buildObject, options) => {
|
||||
return neode.create('EmailAddress', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('unverifiedEmailAddress')
|
||||
.attr(emailDefaults)
|
||||
.after((buildObject, options) => {
|
||||
return neode.create('UnverifiedEmailAddress', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('location')
|
||||
.attrs({
|
||||
name: 'Germany',
|
||||
namePT: 'Alemanha',
|
||||
nameDE: 'Deutschland',
|
||||
nameES: 'Alemania',
|
||||
nameNL: 'Duitsland',
|
||||
namePL: 'Niemcy',
|
||||
nameFR: 'Allemagne',
|
||||
nameIT: 'Germania',
|
||||
nameEN: 'Germany',
|
||||
id: 'country.10743216036480410',
|
||||
type: 'country',
|
||||
})
|
||||
.after((buildObject, options) => {
|
||||
return neode.create('Location', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('report').after((buildObject, options) => {
|
||||
return neode.create('Report', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('tag')
|
||||
.attrs({
|
||||
name: '#human-connection',
|
||||
})
|
||||
.after((buildObject, options) => {
|
||||
return neode.create('Tag', buildObject)
|
||||
})
|
||||
|
||||
Factory.define('socialMedia')
|
||||
.attrs({
|
||||
url: 'https://mastodon.social/@Gargron',
|
||||
})
|
||||
.after((buildObject, options) => {
|
||||
return neode.create('SocialMedia', buildObject)
|
||||
})
|
||||
|
||||
export default Factory
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,15 +0,0 @@
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance }) => {
|
||||
const defaults = {
|
||||
type: 'crowdfunding',
|
||||
status: 'permanent',
|
||||
}
|
||||
args = {
|
||||
...defaults,
|
||||
...args,
|
||||
}
|
||||
return neodeInstance.create('Badge', args)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
import uuid from 'uuid/v4'
|
||||
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance }) => {
|
||||
const defaults = {
|
||||
id: uuid(),
|
||||
icon: 'img/badges/fundraisingbox_de_airship.svg',
|
||||
name: 'Some category name',
|
||||
}
|
||||
args = {
|
||||
...defaults,
|
||||
...args,
|
||||
}
|
||||
return neodeInstance.create('Category', args)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
import faker from 'faker'
|
||||
import uuid from 'uuid/v4'
|
||||
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance, factoryInstance }) => {
|
||||
const defaults = {
|
||||
id: uuid(),
|
||||
content: [faker.lorem.sentence(), faker.lorem.sentence()].join('. '),
|
||||
}
|
||||
args = {
|
||||
...defaults,
|
||||
...args,
|
||||
}
|
||||
args.contentExcerpt = args.contentExcerpt || args.content
|
||||
|
||||
let { post, postId } = args
|
||||
delete args.post
|
||||
delete args.postId
|
||||
if (post && postId) throw new Error('You provided both post and postId')
|
||||
if (postId) post = await neodeInstance.find('Post', postId)
|
||||
post = post || (await factoryInstance.create('Post'))
|
||||
|
||||
let { author, authorId } = args
|
||||
delete args.author
|
||||
delete args.authorId
|
||||
if (author && authorId) throw new Error('You provided both author and authorId')
|
||||
if (authorId) author = await neodeInstance.find('User', authorId)
|
||||
author = author || (await factoryInstance.create('User'))
|
||||
|
||||
delete args.author
|
||||
const comment = await neodeInstance.create('Comment', args)
|
||||
await comment.relateTo(post, 'post')
|
||||
await comment.relateTo(author, 'author')
|
||||
return comment
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
import uuid from 'uuid/v4'
|
||||
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance }) => {
|
||||
const defaults = {
|
||||
id: uuid(),
|
||||
goal: 15000,
|
||||
progress: 0,
|
||||
}
|
||||
args = {
|
||||
...defaults,
|
||||
...args,
|
||||
}
|
||||
return neodeInstance.create('Donations', args)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
import faker from 'faker'
|
||||
|
||||
export function defaults({ args }) {
|
||||
const defaults = {
|
||||
email: faker.internet.email(),
|
||||
verifiedAt: new Date().toISOString(),
|
||||
}
|
||||
args = {
|
||||
...defaults,
|
||||
...args,
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance }) => {
|
||||
args = defaults({ args })
|
||||
return neodeInstance.create('EmailAddress', args)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
import { getDriver, getNeode } from '../db/neo4j'
|
||||
|
||||
const factories = {
|
||||
Badge: require('./badges.js').default,
|
||||
User: require('./users.js').default,
|
||||
Post: require('./posts.js').default,
|
||||
Comment: require('./comments.js').default,
|
||||
Category: require('./categories.js').default,
|
||||
Tag: require('./tags.js').default,
|
||||
SocialMedia: require('./socialMedia.js').default,
|
||||
Location: require('./locations.js').default,
|
||||
EmailAddress: require('./emailAddresses.js').default,
|
||||
UnverifiedEmailAddress: require('./unverifiedEmailAddresses.js').default,
|
||||
Donations: require('./donations.js').default,
|
||||
Report: require('./reports.js').default,
|
||||
}
|
||||
|
||||
export const cleanDatabase = async (options = {}) => {
|
||||
const { driver = getDriver() } = options
|
||||
const session = driver.session()
|
||||
try {
|
||||
await session.writeTransaction(transaction => {
|
||||
return transaction.run(
|
||||
`
|
||||
MATCH (everything)
|
||||
DETACH DELETE everything
|
||||
`,
|
||||
)
|
||||
})
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
}
|
||||
|
||||
export default function Factory(options = {}) {
|
||||
const { neo4jDriver = getDriver(), neodeInstance = getNeode() } = options
|
||||
|
||||
const result = {
|
||||
neo4jDriver,
|
||||
factories,
|
||||
lastResponse: null,
|
||||
neodeInstance,
|
||||
async create(node, args = {}) {
|
||||
const { factory } = this.factories[node](args)
|
||||
this.lastResponse = await factory({
|
||||
args,
|
||||
neodeInstance,
|
||||
factoryInstance: this,
|
||||
})
|
||||
return this.lastResponse
|
||||
},
|
||||
|
||||
async cleanDatabase() {
|
||||
this.lastResponse = await cleanDatabase({
|
||||
driver: this.neo4jDriver,
|
||||
})
|
||||
return this
|
||||
},
|
||||
}
|
||||
result.create.bind(result)
|
||||
result.cleanDatabase.bind(result)
|
||||
return result
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance }) => {
|
||||
const defaults = {
|
||||
name: 'Germany',
|
||||
namePT: 'Alemanha',
|
||||
nameDE: 'Deutschland',
|
||||
nameES: 'Alemania',
|
||||
nameNL: 'Duitsland',
|
||||
namePL: 'Niemcy',
|
||||
nameFR: 'Allemagne',
|
||||
nameIT: 'Germania',
|
||||
nameEN: 'Germany',
|
||||
id: 'country.10743216036480410',
|
||||
type: 'country',
|
||||
}
|
||||
args = {
|
||||
...defaults,
|
||||
...args,
|
||||
}
|
||||
return neodeInstance.create('Location', args)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,89 +0,0 @@
|
||||
import faker from 'faker'
|
||||
import slugify from 'slug'
|
||||
import uuid from 'uuid/v4'
|
||||
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance, factoryInstance }) => {
|
||||
const defaults = {
|
||||
id: uuid(),
|
||||
title: faker.lorem.sentence(),
|
||||
content: [
|
||||
faker.lorem.sentence(),
|
||||
faker.lorem.sentence(),
|
||||
faker.lorem.sentence(),
|
||||
faker.lorem.sentence(),
|
||||
faker.lorem.sentence(),
|
||||
].join('. '),
|
||||
image: faker.image.unsplash.imageUrl(),
|
||||
visibility: 'public',
|
||||
deleted: false,
|
||||
categoryIds: [],
|
||||
imageBlurred: false,
|
||||
imageAspectRatio: 1.333,
|
||||
pinned: null,
|
||||
}
|
||||
args = {
|
||||
...defaults,
|
||||
...args,
|
||||
}
|
||||
// Convert false to null
|
||||
args.pinned = args.pinned || null
|
||||
|
||||
args.slug = args.slug || slugify(args.title, { lower: true })
|
||||
args.contentExcerpt = args.contentExcerpt || args.content
|
||||
|
||||
let { categories, categoryIds } = args
|
||||
delete args.categories
|
||||
delete args.categoryIds
|
||||
if (categories && categoryIds) throw new Error('You provided both categories and categoryIds')
|
||||
if (categoryIds)
|
||||
categories = await Promise.all(categoryIds.map(id => neodeInstance.find('Category', id)))
|
||||
categories = categories || (await Promise.all([factoryInstance.create('Category')]))
|
||||
const { tagIds = [] } = args
|
||||
delete args.tags
|
||||
const tags = await Promise.all(
|
||||
tagIds.map(t => {
|
||||
return neodeInstance.find('Tag', t)
|
||||
}),
|
||||
)
|
||||
|
||||
let { author, authorId } = args
|
||||
delete args.author
|
||||
delete args.authorId
|
||||
if (author && authorId) throw new Error('You provided both author and authorId')
|
||||
if (authorId) author = await neodeInstance.find('User', authorId)
|
||||
author = author || (await factoryInstance.create('User'))
|
||||
const post = await neodeInstance.create('Post', args)
|
||||
|
||||
const { commentContent } = args
|
||||
let comment
|
||||
delete args.commentContent
|
||||
if (commentContent)
|
||||
comment = await factoryInstance.create('Comment', {
|
||||
contentExcerpt: commentContent,
|
||||
post,
|
||||
author,
|
||||
})
|
||||
|
||||
await post.relateTo(author, 'author')
|
||||
if (comment) await post.relateTo(comment, 'comments')
|
||||
|
||||
if (args.pinned) {
|
||||
args.pinnedAt = args.pinnedAt || new Date().toISOString()
|
||||
if (!args.pinnedBy) {
|
||||
const admin = await factoryInstance.create('User', {
|
||||
role: 'admin',
|
||||
updatedAt: new Date().toISOString(),
|
||||
})
|
||||
await admin.relateTo(post, 'pinned')
|
||||
args.pinnedBy = admin
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(categories.map(c => c.relateTo(post, 'post')))
|
||||
await Promise.all(tags.map(t => t.relateTo(post, 'post')))
|
||||
return post
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance }) => {
|
||||
return neodeInstance.create('Report', args)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance }) => {
|
||||
const defaults = {
|
||||
url: 'https://mastodon.social/@Gargron',
|
||||
}
|
||||
args = {
|
||||
...defaults,
|
||||
...args,
|
||||
}
|
||||
return neodeInstance.create('SocialMedia', args)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance }) => {
|
||||
const defaults = { name: '#human-connection' }
|
||||
args = {
|
||||
...defaults,
|
||||
...args,
|
||||
}
|
||||
return neodeInstance.create('Tag', args)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
import { defaults } from './emailAddresses.js'
|
||||
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance }) => {
|
||||
args = defaults({ args })
|
||||
return neodeInstance.create('UnverifiedEmailAddress', args)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
import faker from 'faker'
|
||||
import uuid from 'uuid/v4'
|
||||
import encryptPassword from '../helpers/encryptPassword'
|
||||
import slugify from 'slug'
|
||||
|
||||
export default function create() {
|
||||
return {
|
||||
factory: async ({ args, neodeInstance, factoryInstance }) => {
|
||||
const defaults = {
|
||||
id: uuid(),
|
||||
name: faker.name.findName(),
|
||||
email: faker.internet.email(),
|
||||
password: '1234',
|
||||
role: 'user',
|
||||
avatar: faker.internet.avatar(),
|
||||
about: faker.lorem.paragraph(),
|
||||
termsAndConditionsAgreedVersion: '0.0.1',
|
||||
termsAndConditionsAgreedAt: '2019-08-01T10:47:19.212Z',
|
||||
allowEmbedIframes: false,
|
||||
showShoutsPublicly: false,
|
||||
locale: 'en',
|
||||
}
|
||||
defaults.slug = slugify(defaults.name, { lower: true })
|
||||
args = {
|
||||
...defaults,
|
||||
...args,
|
||||
}
|
||||
args = await encryptPassword(args)
|
||||
const user = await neodeInstance.create('User', args)
|
||||
|
||||
let email
|
||||
if (typeof args.email === 'object') {
|
||||
// probably a neode node
|
||||
email = args.email
|
||||
} else {
|
||||
email = await factoryInstance.create('EmailAddress', { email: args.email })
|
||||
}
|
||||
|
||||
await user.relateTo(email, 'primaryEmail')
|
||||
await email.relateTo(user, 'belongsTo')
|
||||
return user
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,11 @@
|
||||
import createServer from './server'
|
||||
import CONFIG from './config'
|
||||
|
||||
const { app } = createServer()
|
||||
const { server, httpServer } = createServer()
|
||||
const url = new URL(CONFIG.GRAPHQL_URI)
|
||||
app.listen({ port: url.port }, () => {
|
||||
httpServer.listen({ port: url.port }, () => {
|
||||
/* eslint-disable-next-line no-console */
|
||||
console.log(`GraphQLServer ready at ${CONFIG.GRAPHQL_URI} 🚀`)
|
||||
console.log(`🚀 Server ready at http://localhost:${url.port}${server.graphqlPath}`)
|
||||
/* eslint-disable-next-line no-console */
|
||||
console.log(`🚀 Subscriptions ready at ws://localhost:${url.port}${server.subscriptionsPath}`)
|
||||
})
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import Factory from '../factories/index'
|
||||
import Factory, { cleanDatabase } from '../db/factories'
|
||||
import { getDriver, getNeode } from '../db/neo4j'
|
||||
import decode from './decode'
|
||||
|
||||
const factory = Factory()
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
|
||||
@ -26,7 +25,7 @@ export const validAuthorizationHeader =
|
||||
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc'
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('decode', () => {
|
||||
@ -65,14 +64,19 @@ describe('decode', () => {
|
||||
describe('and corresponding user in the database', () => {
|
||||
let user
|
||||
beforeEach(async () => {
|
||||
user = await factory.create('User', {
|
||||
role: 'user',
|
||||
name: 'Jenny Rostock',
|
||||
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/sasha_shestakov/128.jpg',
|
||||
id: 'u3',
|
||||
email: 'user@example.org',
|
||||
slug: 'jenny-rostock',
|
||||
})
|
||||
user = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
role: 'user',
|
||||
name: 'Jenny Rostock',
|
||||
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/sasha_shestakov/128.jpg',
|
||||
id: 'u3',
|
||||
slug: 'jenny-rostock',
|
||||
},
|
||||
{
|
||||
email: 'user@example.org',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it('returns user object except email', async () => {
|
||||
|
||||
@ -3,14 +3,12 @@ import CONFIG from './../config'
|
||||
|
||||
// Generate an Access Token for the given User ID
|
||||
export default function encode(user) {
|
||||
const token = jwt.sign(user, CONFIG.JWT_SECRET, {
|
||||
const { id, name, slug } = user
|
||||
const token = jwt.sign({ id, name, slug }, CONFIG.JWT_SECRET, {
|
||||
expiresIn: '1d',
|
||||
issuer: CONFIG.GRAPHQL_URI,
|
||||
audience: CONFIG.CLIENT_URI,
|
||||
subject: user.id.toString(),
|
||||
})
|
||||
// jwt.verifySignature(token, CONFIG.JWT_SECRET, (err, data) => {
|
||||
// console.log('token verification:', err, data)
|
||||
// })
|
||||
return token
|
||||
}
|
||||
|
||||
62
backend/src/jwt/encode.spec.js
Normal file
62
backend/src/jwt/encode.spec.js
Normal file
@ -0,0 +1,62 @@
|
||||
import encode from './encode'
|
||||
import jwt from 'jsonwebtoken'
|
||||
import CONFIG from './../config'
|
||||
|
||||
describe('encode', () => {
|
||||
let payload
|
||||
beforeEach(() => {
|
||||
payload = {
|
||||
name: 'Some body',
|
||||
slug: 'some-body',
|
||||
id: 'some-id',
|
||||
}
|
||||
})
|
||||
|
||||
it('encodes a valided JWT bearer token', () => {
|
||||
const token = encode(payload)
|
||||
expect(token.split('.')).toHaveLength(3)
|
||||
const decoded = jwt.verify(token, CONFIG.JWT_SECRET)
|
||||
expect(decoded).toEqual({
|
||||
name: 'Some body',
|
||||
slug: 'some-body',
|
||||
id: 'some-id',
|
||||
sub: 'some-id',
|
||||
aud: expect.any(String),
|
||||
iss: expect.any(String),
|
||||
iat: expect.any(Number),
|
||||
exp: expect.any(Number),
|
||||
})
|
||||
})
|
||||
|
||||
describe('given sensitive data', () => {
|
||||
beforeEach(() => {
|
||||
payload = {
|
||||
...payload,
|
||||
email: 'none-of-your-business@example.org',
|
||||
password: 'topsecret',
|
||||
}
|
||||
})
|
||||
|
||||
it('does not encode sensitive data', () => {
|
||||
const token = encode(payload)
|
||||
expect(payload).toEqual({
|
||||
email: 'none-of-your-business@example.org',
|
||||
password: 'topsecret',
|
||||
name: 'Some body',
|
||||
slug: 'some-body',
|
||||
id: 'some-id',
|
||||
})
|
||||
const decoded = jwt.verify(token, CONFIG.JWT_SECRET)
|
||||
expect(decoded).toEqual({
|
||||
name: 'Some body',
|
||||
slug: 'some-body',
|
||||
id: 'some-id',
|
||||
sub: 'some-id',
|
||||
aud: expect.any(String),
|
||||
iss: expect.any(String),
|
||||
iat: expect.any(Number),
|
||||
exp: expect.any(Number),
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,5 +1,5 @@
|
||||
import { gql } from '../../helpers/jest'
|
||||
import Factory from '../../factories'
|
||||
import { cleanDatabase } from '../../db/factories'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
@ -9,7 +9,6 @@ let query
|
||||
let mutate
|
||||
let hashtagingUser
|
||||
let authenticatedUser
|
||||
const factory = Factory()
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
const categoryIds = ['cat9']
|
||||
@ -48,13 +47,18 @@ beforeAll(() => {
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
hashtagingUser = await neode.create('User', {
|
||||
id: 'you',
|
||||
name: 'Al Capone',
|
||||
slug: 'al-capone',
|
||||
email: 'test@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
hashtagingUser = await neode.create(
|
||||
'User',
|
||||
{
|
||||
id: 'you',
|
||||
name: 'Al Capone',
|
||||
slug: 'al-capone',
|
||||
},
|
||||
{
|
||||
password: '1234',
|
||||
email: 'test@example.org',
|
||||
},
|
||||
)
|
||||
await neode.create('Category', {
|
||||
id: 'cat9',
|
||||
name: 'Democracy & Politics',
|
||||
@ -63,7 +67,7 @@ beforeEach(async () => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('hashtags', () => {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import extractMentionedUsers from './mentions/extractMentionedUsers'
|
||||
import { validateNotifyUsers } from '../validation/validationMiddleware'
|
||||
import { pubsub, NOTIFICATION_ADDED } from '../../server'
|
||||
|
||||
const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo) => {
|
||||
const idsOfUsers = extractMentionedUsers(args.content)
|
||||
@ -52,34 +53,48 @@ const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => {
|
||||
WHERE user.id in $idsOfUsers
|
||||
AND NOT (user)-[:BLOCKED]-(author)
|
||||
MERGE (post)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
WITH post AS resource, notification, user
|
||||
`
|
||||
break
|
||||
}
|
||||
case 'mentioned_in_comment': {
|
||||
mentionedCypher = `
|
||||
MATCH (postAuthor: User)-[:WROTE]->(post: Post)<-[:COMMENTS]-(comment: Comment { id: $id })<-[:WROTE]-(author: User)
|
||||
MATCH (postAuthor: User)-[:WROTE]->(post: Post)<-[:COMMENTS]-(comment: Comment { id: $id })<-[:WROTE]-(commenter: User)
|
||||
MATCH (user: User)
|
||||
WHERE user.id in $idsOfUsers
|
||||
AND NOT (user)-[:BLOCKED]-(author)
|
||||
AND NOT (user)-[:BLOCKED]-(commenter)
|
||||
AND NOT (user)-[:BLOCKED]-(postAuthor)
|
||||
MERGE (comment)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
WITH comment AS resource, notification, user
|
||||
`
|
||||
break
|
||||
}
|
||||
}
|
||||
mentionedCypher += `
|
||||
WITH notification, user, resource,
|
||||
[(resource)<-[:WROTE]-(author:User) | author {.*}] AS authors,
|
||||
[(resource)-[:COMMENTS]->(post:Post)<-[:WROTE]-(author:User) | post{.*, author: properties(author)} ] AS posts
|
||||
WITH resource, user, notification, authors, posts,
|
||||
resource {.*, __typename: labels(resource)[0], author: authors[0], post: posts[0]} AS finalResource
|
||||
SET notification.read = FALSE
|
||||
SET (
|
||||
CASE
|
||||
WHEN notification.createdAt IS NULL
|
||||
THEN notification END ).createdAt = toString(datetime())
|
||||
SET notification.createdAt = COALESCE(notification.createdAt, toString(datetime()))
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
RETURN notification {.*, from: finalResource, to: properties(user)}
|
||||
`
|
||||
const session = context.driver.session()
|
||||
try {
|
||||
await session.writeTransaction(transaction => {
|
||||
return transaction.run(mentionedCypher, { id, idsOfUsers, reason })
|
||||
const writeTxResultPromise = session.writeTransaction(async transaction => {
|
||||
const notificationTransactionResponse = await transaction.run(mentionedCypher, {
|
||||
id,
|
||||
idsOfUsers,
|
||||
reason,
|
||||
})
|
||||
return notificationTransactionResponse.records.map(record => record.get('notification'))
|
||||
})
|
||||
try {
|
||||
const [notification] = await writeTxResultPromise
|
||||
return pubsub.publish(NOTIFICATION_ADDED, { notificationAdded: notification })
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
@ -88,24 +103,26 @@ const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => {
|
||||
const notifyUsersOfComment = async (label, commentId, postAuthorId, reason, context) => {
|
||||
await validateNotifyUsers(label, reason)
|
||||
const session = context.driver.session()
|
||||
|
||||
const writeTxResultPromise = await session.writeTransaction(async transaction => {
|
||||
const notificationTransactionResponse = await transaction.run(
|
||||
`
|
||||
MATCH (postAuthor:User {id: $postAuthorId})-[:WROTE]->(post:Post)<-[:COMMENTS]-(comment:Comment { id: $commentId })<-[:WROTE]-(commenter:User)
|
||||
WHERE NOT (postAuthor)-[:BLOCKED]-(commenter)
|
||||
MERGE (comment)-[notification:NOTIFIED {reason: $reason}]->(postAuthor)
|
||||
SET notification.read = FALSE
|
||||
SET notification.createdAt = COALESCE(notification.createdAt, toString(datetime()))
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
WITH notification, postAuthor, post,
|
||||
comment {.*, __typename: labels(comment)[0], author: properties(commenter), post: post {.*, author: properties(postAuthor) } } AS finalResource
|
||||
RETURN notification {.*, from: finalResource, to: properties(postAuthor)}
|
||||
`,
|
||||
{ commentId, postAuthorId, reason },
|
||||
)
|
||||
return notificationTransactionResponse.records.map(record => record.get('notification'))
|
||||
})
|
||||
try {
|
||||
await session.writeTransaction(async transaction => {
|
||||
await transaction.run(
|
||||
`
|
||||
MATCH (postAuthor:User {id: $postAuthorId})-[:WROTE]->(post:Post)<-[:COMMENTS]-(comment:Comment { id: $commentId })<-[:WROTE]-(commenter:User)
|
||||
WHERE NOT (postAuthor)-[:BLOCKED]-(commenter)
|
||||
MERGE (comment)-[notification:NOTIFIED {reason: $reason}]->(postAuthor)
|
||||
SET notification.read = FALSE
|
||||
SET (
|
||||
CASE
|
||||
WHEN notification.createdAt IS NULL
|
||||
THEN notification END ).createdAt = toString(datetime())
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
`,
|
||||
{ commentId, postAuthorId, reason },
|
||||
)
|
||||
})
|
||||
const [notification] = await writeTxResultPromise
|
||||
return pubsub.publish(NOTIFICATION_ADDED, { notificationAdded: notification })
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import { gql } from '../../helpers/jest'
|
||||
import Factory from '../../factories'
|
||||
import { cleanDatabase } from '../../db/factories'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
|
||||
let server, query, mutate, notifiedUser, authenticatedUser
|
||||
const factory = Factory()
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
const categoryIds = ['cat9']
|
||||
@ -36,7 +35,7 @@ const createCommentMutation = gql`
|
||||
`
|
||||
|
||||
beforeAll(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
const createServerResult = createServer({
|
||||
context: () => {
|
||||
return {
|
||||
@ -53,13 +52,18 @@ beforeAll(async () => {
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
notifiedUser = await neode.create('User', {
|
||||
id: 'you',
|
||||
name: 'Al Capone',
|
||||
slug: 'al-capone',
|
||||
email: 'test@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
notifiedUser = await neode.create(
|
||||
'User',
|
||||
{
|
||||
id: 'you',
|
||||
name: 'Al Capone',
|
||||
slug: 'al-capone',
|
||||
},
|
||||
{
|
||||
email: 'test@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
await neode.create('Category', {
|
||||
id: 'cat9',
|
||||
name: 'Democracy & Politics',
|
||||
@ -68,7 +72,7 @@ beforeEach(async () => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('notifications', () => {
|
||||
@ -143,13 +147,18 @@ describe('notifications', () => {
|
||||
describe('commenter is not me', () => {
|
||||
beforeEach(async () => {
|
||||
commentContent = 'Commenters comment.'
|
||||
commentAuthor = await neode.create('User', {
|
||||
id: 'commentAuthor',
|
||||
name: 'Mrs Comment',
|
||||
slug: 'mrs-comment',
|
||||
email: 'commentauthor@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
commentAuthor = await neode.create(
|
||||
'User',
|
||||
{
|
||||
id: 'commentAuthor',
|
||||
name: 'Mrs Comment',
|
||||
slug: 'mrs-comment',
|
||||
},
|
||||
{
|
||||
email: 'commentauthor@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it('sends me a notification', async () => {
|
||||
@ -224,13 +233,18 @@ describe('notifications', () => {
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
postAuthor = await neode.create('User', {
|
||||
id: 'postAuthor',
|
||||
name: 'Mrs Post',
|
||||
slug: 'mrs-post',
|
||||
email: 'post-author@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
postAuthor = await neode.create(
|
||||
'User',
|
||||
{
|
||||
id: 'postAuthor',
|
||||
name: 'Mrs Post',
|
||||
slug: 'mrs-post',
|
||||
},
|
||||
{
|
||||
email: 'post-author@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
describe('mentions me in a post', () => {
|
||||
@ -428,23 +442,33 @@ describe('notifications', () => {
|
||||
beforeEach(async () => {
|
||||
commentContent =
|
||||
'One mention about me with <a data-mention-id="you" class="mention" href="/profile/you" target="_blank">@al-capone</a>.'
|
||||
commentAuthor = await neode.create('User', {
|
||||
id: 'commentAuthor',
|
||||
name: 'Mrs Comment',
|
||||
slug: 'mrs-comment',
|
||||
email: 'comment-author@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
commentAuthor = await neode.create(
|
||||
'User',
|
||||
{
|
||||
id: 'commentAuthor',
|
||||
name: 'Mrs Comment',
|
||||
slug: 'mrs-comment',
|
||||
},
|
||||
{
|
||||
email: 'comment-author@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it('sends only one notification with reason mentioned_in_comment', async () => {
|
||||
postAuthor = await neode.create('User', {
|
||||
id: 'MrPostAuthor',
|
||||
name: 'Mr Author',
|
||||
slug: 'mr-author',
|
||||
email: 'post-author@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
postAuthor = await neode.create(
|
||||
'User',
|
||||
{
|
||||
id: 'MrPostAuthor',
|
||||
name: 'Mr Author',
|
||||
slug: 'mr-author',
|
||||
},
|
||||
{
|
||||
email: 'post-author@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
|
||||
await createCommentOnPostAction()
|
||||
const expected = expect.objectContaining({
|
||||
@ -514,13 +538,18 @@ describe('notifications', () => {
|
||||
await postAuthor.relateTo(notifiedUser, 'blocked')
|
||||
commentContent =
|
||||
'One mention about me with <a data-mention-id="you" class="mention" href="/profile/you" target="_blank">@al-capone</a>.'
|
||||
commentAuthor = await neode.create('User', {
|
||||
id: 'commentAuthor',
|
||||
name: 'Mrs Comment',
|
||||
slug: 'mrs-comment',
|
||||
email: 'comment-author@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
commentAuthor = await neode.create(
|
||||
'User',
|
||||
{
|
||||
id: 'commentAuthor',
|
||||
name: 'Mrs Comment',
|
||||
slug: 'mrs-comment',
|
||||
},
|
||||
{
|
||||
email: 'comment-author@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it('sends no notification', async () => {
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { gql } from '../helpers/jest'
|
||||
import Factory from '../factories'
|
||||
import { cleanDatabase } from '../db/factories'
|
||||
import { getNeode, getDriver } from '../db/neo4j'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '../server'
|
||||
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
const driver = getDriver()
|
||||
|
||||
@ -27,7 +26,7 @@ beforeEach(async () => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('Query', () => {
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '../server'
|
||||
import Factory from '../factories'
|
||||
import Factory, { cleanDatabase } from '../db/factories'
|
||||
import { gql } from '../helpers/jest'
|
||||
import { getDriver, getNeode } from '../db/neo4j'
|
||||
|
||||
const factory = Factory()
|
||||
const instance = getNeode()
|
||||
const driver = getDriver()
|
||||
|
||||
@ -20,7 +19,7 @@ const userQuery = gql`
|
||||
|
||||
describe('authorization', () => {
|
||||
beforeAll(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
const { server } = createServer({
|
||||
context: () => ({
|
||||
driver,
|
||||
@ -34,34 +33,54 @@ describe('authorization', () => {
|
||||
describe('given two existing users', () => {
|
||||
beforeEach(async () => {
|
||||
;[owner, anotherRegularUser, administrator, moderator] = await Promise.all([
|
||||
factory.create('User', {
|
||||
email: 'owner@example.org',
|
||||
name: 'Owner',
|
||||
password: 'iamtheowner',
|
||||
}),
|
||||
factory.create('User', {
|
||||
email: 'another.regular.user@example.org',
|
||||
name: 'Another Regular User',
|
||||
password: 'else',
|
||||
}),
|
||||
factory.create('User', {
|
||||
email: 'admin@example.org',
|
||||
name: 'Admin',
|
||||
password: 'admin',
|
||||
role: 'admin',
|
||||
}),
|
||||
factory.create('User', {
|
||||
email: 'moderator@example.org',
|
||||
name: 'Moderator',
|
||||
password: 'moderator',
|
||||
role: 'moderator',
|
||||
}),
|
||||
Factory.build(
|
||||
'user',
|
||||
{
|
||||
name: 'Owner',
|
||||
},
|
||||
{
|
||||
email: 'owner@example.org',
|
||||
password: 'iamtheowner',
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'user',
|
||||
{
|
||||
name: 'Another Regular User',
|
||||
},
|
||||
{
|
||||
email: 'another.regular.user@example.org',
|
||||
password: 'else',
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'user',
|
||||
{
|
||||
name: 'Admin',
|
||||
role: 'admin',
|
||||
},
|
||||
{
|
||||
email: 'admin@example.org',
|
||||
password: 'admin',
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'user',
|
||||
{
|
||||
name: 'Moderator',
|
||||
role: 'moderator',
|
||||
},
|
||||
{
|
||||
email: 'moderator@example.org',
|
||||
password: 'moderator',
|
||||
},
|
||||
),
|
||||
])
|
||||
variables = {}
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('access email address', () => {
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
import Factory from '../factories'
|
||||
import Factory, { cleanDatabase } from '../db/factories'
|
||||
import { gql } from '../helpers/jest'
|
||||
import { getNeode, getDriver } from '../db/neo4j'
|
||||
import createServer from '../server'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
|
||||
const factory = Factory()
|
||||
|
||||
let mutate
|
||||
let authenticatedUser
|
||||
let variables
|
||||
@ -28,14 +26,18 @@ beforeAll(() => {
|
||||
|
||||
beforeEach(async () => {
|
||||
variables = {}
|
||||
const admin = await factory.create('User', {
|
||||
const admin = await Factory.build('user', {
|
||||
role: 'admin',
|
||||
})
|
||||
await factory.create('User', {
|
||||
email: 'someone@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
await factory.create('Category', {
|
||||
await Factory.build(
|
||||
'user',
|
||||
{},
|
||||
{
|
||||
email: 'someone@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
await Factory.build('category', {
|
||||
id: 'cat9',
|
||||
name: 'Democracy & Politics',
|
||||
icon: 'university',
|
||||
@ -44,7 +46,7 @@ beforeEach(async () => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('slugifyMiddleware', () => {
|
||||
@ -84,12 +86,17 @@ describe('slugifyMiddleware', () => {
|
||||
|
||||
describe('if slug exists', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('Post', {
|
||||
title: 'Pre-existing post',
|
||||
slug: 'pre-existing-post',
|
||||
content: 'as Someone else content',
|
||||
categoryIds,
|
||||
})
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
title: 'Pre-existing post',
|
||||
slug: 'pre-existing-post',
|
||||
content: 'as Someone else content',
|
||||
},
|
||||
{
|
||||
categoryIds,
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it('chooses another slug', async () => {
|
||||
@ -190,7 +197,7 @@ describe('slugifyMiddleware', () => {
|
||||
|
||||
describe('given a user has signed up with their email address', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('EmailAddress', {
|
||||
await Factory.build('emailAddress', {
|
||||
email: '123@example.org',
|
||||
nonce: '123456',
|
||||
verifiedAt: null,
|
||||
@ -214,7 +221,7 @@ describe('slugifyMiddleware', () => {
|
||||
|
||||
describe('if slug exists', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('User', {
|
||||
await Factory.build('user', {
|
||||
name: 'I am a user',
|
||||
slug: 'i-am-a-user',
|
||||
})
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
const driver = getDriver()
|
||||
|
||||
@ -18,13 +17,18 @@ const action = () => {
|
||||
beforeAll(async () => {
|
||||
// For performance reasons we do this only once
|
||||
const users = await Promise.all([
|
||||
factory.create('User', { id: 'u1', role: 'user' }),
|
||||
factory.create('User', {
|
||||
id: 'm1',
|
||||
role: 'moderator',
|
||||
password: '1234',
|
||||
}),
|
||||
factory.create('User', {
|
||||
Factory.build('user', { id: 'u1', role: 'user' }),
|
||||
Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'm1',
|
||||
role: 'moderator',
|
||||
},
|
||||
{
|
||||
password: '1234',
|
||||
},
|
||||
),
|
||||
Factory.build('user', {
|
||||
id: 'u2',
|
||||
role: 'user',
|
||||
name: 'Offensive Name',
|
||||
@ -45,48 +49,73 @@ beforeAll(async () => {
|
||||
|
||||
await Promise.all([
|
||||
user.relateTo(troll, 'following'),
|
||||
factory.create('Post', {
|
||||
author: user,
|
||||
id: 'p1',
|
||||
title: 'Deleted post',
|
||||
slug: 'deleted-post',
|
||||
deleted: true,
|
||||
categoryIds,
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author: user,
|
||||
id: 'p3',
|
||||
title: 'Publicly visible post',
|
||||
slug: 'publicly-visible-post',
|
||||
deleted: false,
|
||||
categoryIds,
|
||||
}),
|
||||
Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'p1',
|
||||
title: 'Deleted post',
|
||||
slug: 'deleted-post',
|
||||
deleted: true,
|
||||
},
|
||||
{
|
||||
author: user,
|
||||
categoryIds,
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'p3',
|
||||
title: 'Publicly visible post',
|
||||
slug: 'publicly-visible-post',
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
author: user,
|
||||
categoryIds,
|
||||
},
|
||||
),
|
||||
])
|
||||
|
||||
const resources = await Promise.all([
|
||||
factory.create('Comment', {
|
||||
author: user,
|
||||
id: 'c2',
|
||||
postId: 'p3',
|
||||
content: 'Enabled comment on public post',
|
||||
}),
|
||||
factory.create('Post', {
|
||||
id: 'p2',
|
||||
author: troll,
|
||||
title: 'Disabled post',
|
||||
content: 'This is an offensive post content',
|
||||
contentExcerpt: 'This is an offensive post content',
|
||||
image: '/some/offensive/image.jpg',
|
||||
deleted: false,
|
||||
categoryIds,
|
||||
}),
|
||||
factory.create('Comment', {
|
||||
id: 'c1',
|
||||
author: troll,
|
||||
postId: 'p3',
|
||||
content: 'Disabled comment',
|
||||
contentExcerpt: 'Disabled comment',
|
||||
}),
|
||||
Factory.build(
|
||||
'comment',
|
||||
{
|
||||
id: 'c2',
|
||||
content: 'Enabled comment on public post',
|
||||
},
|
||||
{
|
||||
author: user,
|
||||
postId: 'p3',
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'p2',
|
||||
title: 'Disabled post',
|
||||
content: 'This is an offensive post content',
|
||||
contentExcerpt: 'This is an offensive post content',
|
||||
image: '/some/offensive/image.jpg',
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
author: troll,
|
||||
categoryIds,
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'comment',
|
||||
{
|
||||
id: 'c1',
|
||||
content: 'Disabled comment',
|
||||
contentExcerpt: 'Disabled comment',
|
||||
},
|
||||
{
|
||||
author: troll,
|
||||
postId: 'p3',
|
||||
},
|
||||
),
|
||||
])
|
||||
|
||||
const { server } = createServer({
|
||||
@ -105,9 +134,9 @@ beforeAll(async () => {
|
||||
const trollingComment = resources[2]
|
||||
|
||||
const reports = await Promise.all([
|
||||
factory.create('Report'),
|
||||
factory.create('Report'),
|
||||
factory.create('Report'),
|
||||
Factory.build('report'),
|
||||
Factory.build('report'),
|
||||
Factory.build('report'),
|
||||
])
|
||||
const reportAgainstTroll = reports[0]
|
||||
const reportAgainstTrollingPost = reports[1]
|
||||
@ -154,7 +183,7 @@ beforeAll(async () => {
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('softDeleteMiddleware', () => {
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { gql } from '../../helpers/jest'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '../../server'
|
||||
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
const driver = getDriver()
|
||||
let authenticatedUser,
|
||||
@ -94,14 +93,14 @@ beforeAll(() => {
|
||||
|
||||
beforeEach(async () => {
|
||||
users = await Promise.all([
|
||||
factory.create('User', {
|
||||
Factory.build('user', {
|
||||
id: 'reporting-user',
|
||||
}),
|
||||
factory.create('User', {
|
||||
Factory.build('user', {
|
||||
id: 'moderating-user',
|
||||
role: 'moderator',
|
||||
}),
|
||||
factory.create('User', {
|
||||
Factory.build('user', {
|
||||
id: 'commenting-user',
|
||||
}),
|
||||
])
|
||||
@ -119,20 +118,30 @@ beforeEach(async () => {
|
||||
moderatingUser = users[1]
|
||||
commentingUser = users[2]
|
||||
const posts = await Promise.all([
|
||||
factory.create('Post', {
|
||||
id: 'offensive-post',
|
||||
authorId: 'moderating-user',
|
||||
}),
|
||||
factory.create('Post', {
|
||||
id: 'post-4-commenting',
|
||||
authorId: 'commenting-user',
|
||||
}),
|
||||
Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'offensive-post',
|
||||
},
|
||||
{
|
||||
authorId: 'moderating-user',
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'post-4-commenting',
|
||||
},
|
||||
{
|
||||
authorId: 'commenting-user',
|
||||
},
|
||||
),
|
||||
])
|
||||
offensivePost = posts[0]
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('validateCreateComment', () => {
|
||||
@ -182,10 +191,15 @@ describe('validateCreateComment', () => {
|
||||
describe('validateUpdateComment', () => {
|
||||
let updateCommentVariables
|
||||
beforeEach(async () => {
|
||||
await factory.create('Comment', {
|
||||
id: 'comment-id',
|
||||
authorId: 'commenting-user',
|
||||
})
|
||||
await Factory.build(
|
||||
'comment',
|
||||
{
|
||||
id: 'comment-id',
|
||||
},
|
||||
{
|
||||
authorId: 'commenting-user',
|
||||
},
|
||||
)
|
||||
updateCommentVariables = {
|
||||
id: 'whatever',
|
||||
content: '',
|
||||
@ -328,7 +342,7 @@ describe('validateReport', () => {
|
||||
|
||||
describe('validateReview', () => {
|
||||
beforeEach(async () => {
|
||||
const reportAgainstModerator = await factory.create('Report')
|
||||
const reportAgainstModerator = await Factory.build('report')
|
||||
await Promise.all([
|
||||
reportAgainstModerator.relateTo(reportingUser, 'filed', {
|
||||
...reportVariables,
|
||||
@ -370,7 +384,7 @@ describe('validateReview', () => {
|
||||
})
|
||||
|
||||
it('throws an error if a moderator tries to review their own resource(Post|Comment)', async () => {
|
||||
const reportAgainstOffensivePost = await factory.create('Report')
|
||||
const reportAgainstOffensivePost = await Factory.build('report')
|
||||
await Promise.all([
|
||||
reportAgainstOffensivePost.relateTo(reportingUser, 'filed', {
|
||||
...reportVariables,
|
||||
@ -389,7 +403,7 @@ describe('validateReview', () => {
|
||||
|
||||
describe('moderate a resource that is not a (Comment|Post|User) ', () => {
|
||||
beforeEach(async () => {
|
||||
await Promise.all([factory.create('Tag', { id: 'tag-id' })])
|
||||
await Promise.all([Factory.build('tag', { id: 'tag-id' })])
|
||||
})
|
||||
|
||||
it('returns null', async () => {
|
||||
@ -419,7 +433,7 @@ describe('validateReview', () => {
|
||||
id: 'updating-user',
|
||||
name: 'John Doughnut',
|
||||
}
|
||||
updatingUser = await factory.create('User', userParams)
|
||||
updatingUser = await Factory.build('user', userParams)
|
||||
authenticatedUser = await updatingUser.toJson()
|
||||
})
|
||||
|
||||
|
||||
@ -52,5 +52,4 @@ export default {
|
||||
},
|
||||
},
|
||||
pinned: { type: 'boolean', default: null, valid: [null, true] },
|
||||
pinnedAt: { type: 'string', isoDate: true },
|
||||
}
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import Factory from '../factories'
|
||||
import { cleanDatabase } from '../db/factories'
|
||||
import { getNeode } from '../db/neo4j'
|
||||
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('role', () => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '../../server'
|
||||
@ -6,12 +6,11 @@ import { getNeode, getDriver } from '../../db/neo4j'
|
||||
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
const factory = Factory()
|
||||
|
||||
let variables, mutate, authenticatedUser, commentAuthor, newlyCreatedComment
|
||||
|
||||
beforeAll(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
const { server } = createServer({
|
||||
context: () => {
|
||||
return {
|
||||
@ -33,7 +32,7 @@ beforeEach(async () => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
const createCommentMutation = gql`
|
||||
@ -48,18 +47,28 @@ const createCommentMutation = gql`
|
||||
}
|
||||
`
|
||||
const setupPostAndComment = async () => {
|
||||
commentAuthor = await factory.create('User')
|
||||
await factory.create('Post', {
|
||||
id: 'p1',
|
||||
content: 'Post to be commented',
|
||||
categoryIds: ['cat9'],
|
||||
})
|
||||
newlyCreatedComment = await factory.create('Comment', {
|
||||
id: 'c456',
|
||||
postId: 'p1',
|
||||
author: commentAuthor,
|
||||
content: 'Comment to be deleted',
|
||||
})
|
||||
commentAuthor = await Factory.build('user')
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'p1',
|
||||
content: 'Post to be commented',
|
||||
},
|
||||
{
|
||||
categoryIds: ['cat9'],
|
||||
},
|
||||
)
|
||||
newlyCreatedComment = await Factory.build(
|
||||
'comment',
|
||||
{
|
||||
id: 'c456',
|
||||
content: 'Comment to be deleted',
|
||||
},
|
||||
{
|
||||
postId: 'p1',
|
||||
author: commentAuthor,
|
||||
},
|
||||
)
|
||||
variables = {
|
||||
...variables,
|
||||
id: 'c456',
|
||||
@ -88,7 +97,7 @@ describe('CreateComment', () => {
|
||||
|
||||
describe('given a post', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('Post', { categoryIds: ['cat9'], id: 'p1' })
|
||||
await Factory.build('post', { id: 'p1' }, { categoryIds: ['cat9'] })
|
||||
variables = {
|
||||
...variables,
|
||||
postId: 'p1',
|
||||
@ -141,7 +150,7 @@ describe('UpdateComment', () => {
|
||||
|
||||
describe('authenticated but not the author', () => {
|
||||
beforeEach(async () => {
|
||||
const randomGuy = await factory.create('User')
|
||||
const randomGuy = await Factory.build('user')
|
||||
authenticatedUser = await randomGuy.toJson()
|
||||
})
|
||||
|
||||
@ -233,7 +242,7 @@ describe('DeleteComment', () => {
|
||||
|
||||
describe('authenticated but not the author', () => {
|
||||
beforeEach(async () => {
|
||||
const randomGuy = await factory.create('User')
|
||||
const randomGuy = await Factory.build('user')
|
||||
authenticatedUser = await randomGuy.toJson()
|
||||
})
|
||||
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
|
||||
let mutate, query, authenticatedUser, variables
|
||||
const factory = Factory()
|
||||
const instance = getNeode()
|
||||
const driver = getDriver()
|
||||
|
||||
@ -33,7 +32,7 @@ const donationsQuery = gql`
|
||||
describe('donations', () => {
|
||||
let currentUser, newlyCreatedDonations
|
||||
beforeAll(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
authenticatedUser = undefined
|
||||
const { server } = createServer({
|
||||
context: () => {
|
||||
@ -50,11 +49,11 @@ describe('donations', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
variables = {}
|
||||
newlyCreatedDonations = await factory.create('Donations')
|
||||
newlyCreatedDonations = await Factory.build('donations')
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('query for donations', () => {
|
||||
@ -68,7 +67,7 @@ describe('donations', () => {
|
||||
|
||||
describe('authenticated', () => {
|
||||
beforeEach(async () => {
|
||||
currentUser = await factory.create('User', {
|
||||
currentUser = await Factory.build('user', {
|
||||
id: 'normal-user',
|
||||
role: 'user',
|
||||
})
|
||||
@ -102,7 +101,7 @@ describe('donations', () => {
|
||||
describe('authenticated', () => {
|
||||
describe('as a normal user', () => {
|
||||
beforeEach(async () => {
|
||||
currentUser = await factory.create('User', {
|
||||
currentUser = await Factory.build('user', {
|
||||
id: 'normal-user',
|
||||
role: 'user',
|
||||
})
|
||||
@ -121,7 +120,7 @@ describe('donations', () => {
|
||||
|
||||
describe('as a moderator', () => {
|
||||
beforeEach(async () => {
|
||||
currentUser = await factory.create('User', {
|
||||
currentUser = await Factory.build('user', {
|
||||
id: 'moderator',
|
||||
role: 'moderator',
|
||||
})
|
||||
@ -140,7 +139,7 @@ describe('donations', () => {
|
||||
|
||||
describe('as an admin', () => {
|
||||
beforeEach(async () => {
|
||||
currentUser = await factory.create('User', {
|
||||
currentUser = await Factory.build('user', {
|
||||
id: 'admin',
|
||||
role: 'admin',
|
||||
})
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getDriver, getNeode } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
|
||||
let mutate
|
||||
@ -31,7 +30,7 @@ beforeAll(() => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('AddEmailAddress', () => {
|
||||
@ -63,7 +62,7 @@ describe('AddEmailAddress', () => {
|
||||
|
||||
describe('authenticated', () => {
|
||||
beforeEach(async () => {
|
||||
user = await factory.create('User', { id: '567', email: 'user@example.org' })
|
||||
user = await Factory.build('user', { id: '567' }, { email: 'user@example.org' })
|
||||
authenticatedUser = await user.toJson()
|
||||
})
|
||||
|
||||
@ -110,7 +109,7 @@ describe('AddEmailAddress', () => {
|
||||
|
||||
describe('if another `UnverifiedEmailAddress` node already exists with that email', () => {
|
||||
it('throws no unique constraint violation error', async () => {
|
||||
await factory.create('UnverifiedEmailAddress', {
|
||||
await Factory.build('unverifiedEmailAddress', {
|
||||
createdAt: '2019-09-24T14:00:01.565Z',
|
||||
email: 'new-email@example.org',
|
||||
})
|
||||
@ -128,7 +127,7 @@ describe('AddEmailAddress', () => {
|
||||
|
||||
describe('but if another user owns an `EmailAddress` already with that email', () => {
|
||||
it('throws UserInputError because of unique constraints', async () => {
|
||||
await factory.create('User', { email: 'new-email@example.org' })
|
||||
await Factory.build('user', {}, { email: 'new-email@example.org' })
|
||||
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
|
||||
data: { AddEmailAddress: null },
|
||||
errors: [{ message: 'A user account with this email already exists.' }],
|
||||
@ -169,7 +168,7 @@ describe('VerifyEmailAddress', () => {
|
||||
|
||||
describe('authenticated', () => {
|
||||
beforeEach(async () => {
|
||||
user = await factory.create('User', { id: '567', email: 'user@example.org' })
|
||||
user = await Factory.build('user', { id: '567' }, { email: 'user@example.org' })
|
||||
authenticatedUser = await user.toJson()
|
||||
})
|
||||
|
||||
@ -185,7 +184,7 @@ describe('VerifyEmailAddress', () => {
|
||||
describe('given a `UnverifiedEmailAddress`', () => {
|
||||
let emailAddress
|
||||
beforeEach(async () => {
|
||||
emailAddress = await factory.create('UnverifiedEmailAddress', {
|
||||
emailAddress = await Factory.build('unverifiedEmailAddress', {
|
||||
nonce: 'abcdef',
|
||||
verifiedAt: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
@ -281,7 +280,7 @@ describe('VerifyEmailAddress', () => {
|
||||
|
||||
describe('Edge case: In the meantime someone created an `EmailAddress` node with the given email', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('EmailAddress', { email: 'to-be-verified@example.org' })
|
||||
await Factory.build('emailAddress', { email: 'to-be-verified@example.org' })
|
||||
})
|
||||
|
||||
it('throws UserInputError because of unique constraints', async () => {
|
||||
|
||||
@ -1,24 +1,27 @@
|
||||
import { createWriteStream } from 'fs'
|
||||
import path from 'path'
|
||||
import slug from 'slug'
|
||||
import uuid from 'uuid/v4'
|
||||
|
||||
const storeUpload = ({ createReadStream, fileLocation }) =>
|
||||
new Promise((resolve, reject) =>
|
||||
const localFileUpload = async ({ createReadStream, uniqueFilename }) => {
|
||||
await new Promise((resolve, reject) =>
|
||||
createReadStream()
|
||||
.pipe(createWriteStream(`public${fileLocation}`))
|
||||
.pipe(createWriteStream(`public${uniqueFilename}`))
|
||||
.on('finish', resolve)
|
||||
.on('error', reject),
|
||||
)
|
||||
return uniqueFilename
|
||||
}
|
||||
|
||||
export default async function fileUpload(params, { file, url }, uploadCallback = storeUpload) {
|
||||
export default async function fileUpload(params, { file, url }, uploadCallback = localFileUpload) {
|
||||
const upload = params[file]
|
||||
if (upload) {
|
||||
const { createReadStream, filename } = await upload
|
||||
const { name } = path.parse(filename)
|
||||
const fileLocation = `/uploads/${Date.now()}-${slug(name)}`
|
||||
await uploadCallback({ createReadStream, fileLocation })
|
||||
const { name, ext } = path.parse(filename)
|
||||
const uniqueFilename = `/uploads/${uuid()}-${slug(name)}${ext}`
|
||||
const location = await uploadCallback({ createReadStream, uniqueFilename })
|
||||
delete params[file]
|
||||
params[url] = fileLocation
|
||||
params[url] = location
|
||||
}
|
||||
|
||||
return params
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import fileUpload from '.'
|
||||
|
||||
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}'
|
||||
|
||||
describe('fileUpload', () => {
|
||||
let params
|
||||
let uploadCallback
|
||||
@ -13,7 +15,7 @@ describe('fileUpload', () => {
|
||||
createReadStream: jest.fn(),
|
||||
},
|
||||
}
|
||||
uploadCallback = jest.fn()
|
||||
uploadCallback = jest.fn(({ uniqueFilename }) => uniqueFilename)
|
||||
})
|
||||
|
||||
it('calls uploadCallback', async () => {
|
||||
@ -24,20 +26,13 @@ describe('fileUpload', () => {
|
||||
describe('file name', () => {
|
||||
it('saves the upload url in params[url]', async () => {
|
||||
await fileUpload(params, { file: 'uploadAttribute', url: 'attribute' }, uploadCallback)
|
||||
expect(params.attribute).toMatch(/^\/uploads\/\d+-avatar$/)
|
||||
})
|
||||
|
||||
it('uses the name without file ending', async () => {
|
||||
params.uploadAttribute.filename = 'somePng.png'
|
||||
await fileUpload(params, { file: 'uploadAttribute', url: 'attribute' }, uploadCallback)
|
||||
expect(params.attribute).toMatch(/^\/uploads\/\d+-somePng/)
|
||||
expect(params.attribute).toMatch(new RegExp(`^/uploads/${uuid}-avatar.jpg`))
|
||||
})
|
||||
|
||||
it('creates a url safe name', async () => {
|
||||
params.uploadAttribute.filename =
|
||||
'/path/to/awkward?/ file-location/?foo- bar-avatar.jpg?foo- bar'
|
||||
params.uploadAttribute.filename = '/path/to/awkward?/ file-location/?foo- bar-avatar.jpg'
|
||||
await fileUpload(params, { file: 'uploadAttribute', url: 'attribute' }, uploadCallback)
|
||||
expect(params.attribute).toMatch(/^\/uploads\/\d+-foo-bar-avatar$/)
|
||||
expect(params.attribute).toMatch(new RegExp(`/uploads/${uuid}-foo-bar-avatar.jpg$`))
|
||||
})
|
||||
|
||||
describe('in case of duplicates', () => {
|
||||
@ -50,7 +45,6 @@ describe('fileUpload', () => {
|
||||
uploadCallback,
|
||||
)
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
const { attribute: second } = await fileUpload(
|
||||
{
|
||||
...params,
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { getDriver, getNeode } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
import { gql } from '../../helpers/jest'
|
||||
|
||||
const factory = Factory()
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
|
||||
@ -54,7 +53,7 @@ const userQuery = gql`
|
||||
`
|
||||
|
||||
beforeAll(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
const { server } = createServer({
|
||||
context: () => ({
|
||||
driver,
|
||||
@ -72,29 +71,35 @@ beforeAll(async () => {
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
user1 = await factory
|
||||
.create('User', {
|
||||
user1 = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'u1',
|
||||
name: 'user1',
|
||||
},
|
||||
{
|
||||
email: 'test@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
.then(user => user.toJson())
|
||||
user2 = await factory
|
||||
.create('User', {
|
||||
},
|
||||
).then(user => user.toJson())
|
||||
user2 = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'u2',
|
||||
name: 'user2',
|
||||
},
|
||||
{
|
||||
email: 'test2@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
.then(user => user.toJson())
|
||||
},
|
||||
).then(user => user.toJson())
|
||||
|
||||
authenticatedUser = user1
|
||||
variables = { id: user2.id }
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('follow', () => {
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
|
||||
const factory = Factory()
|
||||
|
||||
let mutate, authenticatedUser
|
||||
|
||||
const driver = getDriver()
|
||||
@ -25,7 +23,7 @@ beforeAll(() => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('resolvers', () => {
|
||||
@ -49,7 +47,7 @@ describe('resolvers', () => {
|
||||
id: 'u47',
|
||||
name: 'John Doughnut',
|
||||
}
|
||||
const Paris = await factory.create('Location', {
|
||||
const Paris = await Factory.build('location', {
|
||||
id: 'region.9397217726497330',
|
||||
name: 'Paris',
|
||||
type: 'region',
|
||||
@ -58,7 +56,7 @@ describe('resolvers', () => {
|
||||
nameEN: 'Paris',
|
||||
})
|
||||
|
||||
const user = await factory.create('User', {
|
||||
const user = await Factory.build('user', {
|
||||
id: 'u47',
|
||||
name: 'John Doe',
|
||||
})
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
const driver = getDriver()
|
||||
|
||||
@ -54,7 +53,7 @@ const reviewMutation = gql`
|
||||
|
||||
describe('moderate resources', () => {
|
||||
beforeAll(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
authenticatedUser = undefined
|
||||
const { server } = createServer({
|
||||
context: () => {
|
||||
@ -80,23 +79,33 @@ describe('moderate resources', () => {
|
||||
closed: false,
|
||||
}
|
||||
authenticatedUser = null
|
||||
moderator = await factory.create('User', {
|
||||
id: 'moderator-id',
|
||||
name: 'Moderator',
|
||||
email: 'moderator@example.org',
|
||||
password: '1234',
|
||||
role: 'moderator',
|
||||
})
|
||||
nonModerator = await factory.create('User', {
|
||||
id: 'non-moderator',
|
||||
name: 'Non Moderator',
|
||||
email: 'non.moderator@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
moderator = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'moderator-id',
|
||||
name: 'Moderator',
|
||||
role: 'moderator',
|
||||
},
|
||||
{
|
||||
email: 'moderator@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
nonModerator = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'non-moderator',
|
||||
name: 'Non Moderator',
|
||||
},
|
||||
{
|
||||
email: 'non.moderator@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('review to close report, leaving resource enabled', () => {
|
||||
@ -127,10 +136,10 @@ describe('moderate resources', () => {
|
||||
describe('moderator', () => {
|
||||
beforeEach(async () => {
|
||||
authenticatedUser = await moderator.toJson()
|
||||
const questionablePost = await factory.create('Post', {
|
||||
const questionablePost = await Factory.build('post', {
|
||||
id: 'should-i-be-disabled',
|
||||
})
|
||||
const reportAgainstQuestionablePost = await factory.create('Report')
|
||||
const reportAgainstQuestionablePost = await Factory.build('report')
|
||||
await Promise.all([
|
||||
reportAgainstQuestionablePost.relateTo(nonModerator, 'filed', {
|
||||
resourceId: 'should-i-be-disabled',
|
||||
@ -229,10 +238,10 @@ describe('moderate resources', () => {
|
||||
|
||||
describe('moderate a comment', () => {
|
||||
beforeEach(async () => {
|
||||
const trollingComment = await factory.create('Comment', {
|
||||
const trollingComment = await Factory.build('comment', {
|
||||
id: 'comment-id',
|
||||
})
|
||||
const reportAgainstTrollingComment = await factory.create('Report')
|
||||
const reportAgainstTrollingComment = await Factory.build('report')
|
||||
await Promise.all([
|
||||
reportAgainstTrollingComment.relateTo(nonModerator, 'filed', {
|
||||
resourceId: 'comment-id',
|
||||
@ -307,10 +316,10 @@ describe('moderate resources', () => {
|
||||
|
||||
describe('moderate a post', () => {
|
||||
beforeEach(async () => {
|
||||
const trollingPost = await factory.create('Post', {
|
||||
const trollingPost = await Factory.build('post', {
|
||||
id: 'post-id',
|
||||
})
|
||||
const reportAgainstTrollingPost = await factory.create('Report')
|
||||
const reportAgainstTrollingPost = await Factory.build('report')
|
||||
await Promise.all([
|
||||
reportAgainstTrollingPost.relateTo(nonModerator, 'filed', {
|
||||
resourceId: 'post-id',
|
||||
@ -387,10 +396,10 @@ describe('moderate resources', () => {
|
||||
|
||||
describe('moderate a user', () => {
|
||||
beforeEach(async () => {
|
||||
const troll = await factory.create('User', {
|
||||
const troll = await Factory.build('user', {
|
||||
id: 'user-id',
|
||||
})
|
||||
const reportAgainstTroll = await factory.create('Report')
|
||||
const reportAgainstTroll = await Factory.build('report')
|
||||
await Promise.all([
|
||||
reportAgainstTroll.relateTo(nonModerator, 'filed', {
|
||||
resourceId: 'user-id',
|
||||
@ -504,10 +513,10 @@ describe('moderate resources', () => {
|
||||
|
||||
describe('moderate a comment', () => {
|
||||
beforeEach(async () => {
|
||||
const trollingComment = await factory.create('Comment', {
|
||||
const trollingComment = await Factory.build('comment', {
|
||||
id: 'comment-id',
|
||||
})
|
||||
const reportAgainstTrollingComment = await factory.create('Report')
|
||||
const reportAgainstTrollingComment = await Factory.build('report')
|
||||
await Promise.all([
|
||||
reportAgainstTrollingComment.relateTo(nonModerator, 'filed', {
|
||||
resourceId: 'comment-id',
|
||||
@ -568,10 +577,10 @@ describe('moderate resources', () => {
|
||||
|
||||
describe('moderate a post', () => {
|
||||
beforeEach(async () => {
|
||||
const trollingPost = await factory.create('Post', {
|
||||
const trollingPost = await Factory.build('post', {
|
||||
id: 'post-id',
|
||||
})
|
||||
const reportAgainstTrollingPost = await factory.create('Report')
|
||||
const reportAgainstTrollingPost = await Factory.build('report')
|
||||
await Promise.all([
|
||||
reportAgainstTrollingPost.relateTo(nonModerator, 'filed', {
|
||||
resourceId: 'post-id',
|
||||
@ -633,10 +642,10 @@ describe('moderate resources', () => {
|
||||
|
||||
describe('moderate a user', () => {
|
||||
beforeEach(async () => {
|
||||
const troll = await factory.create('User', {
|
||||
const troll = await Factory.build('user', {
|
||||
id: 'user-id',
|
||||
})
|
||||
const reportAgainstTroll = await factory.create('Report')
|
||||
const reportAgainstTroll = await Factory.build('report')
|
||||
await Promise.all([
|
||||
reportAgainstTroll.relateTo(nonModerator, 'filed', {
|
||||
resourceId: 'user-id',
|
||||
|
||||
@ -1,21 +1,18 @@
|
||||
import log from './helpers/databaseLogger'
|
||||
|
||||
const resourceTypes = ['Post', 'Comment']
|
||||
|
||||
const transformReturnType = record => {
|
||||
return {
|
||||
...record.get('notification').properties,
|
||||
from: {
|
||||
__typename: record.get('resource').labels.find(l => resourceTypes.includes(l)),
|
||||
...record.get('resource').properties,
|
||||
},
|
||||
to: {
|
||||
...record.get('user').properties,
|
||||
},
|
||||
}
|
||||
}
|
||||
import { withFilter } from 'graphql-subscriptions'
|
||||
import { pubsub, NOTIFICATION_ADDED } from '../../server'
|
||||
|
||||
export default {
|
||||
Subscription: {
|
||||
notificationAdded: {
|
||||
subscribe: withFilter(
|
||||
() => pubsub.asyncIterator(NOTIFICATION_ADDED),
|
||||
(payload, variables) => {
|
||||
return payload.notificationAdded.to.id === variables.userId
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
Query: {
|
||||
notifications: async (_parent, args, context, _resolveInfo) => {
|
||||
const { user: currentUser } = context
|
||||
@ -51,10 +48,10 @@ export default {
|
||||
MATCH (resource {deleted: false, disabled: false})-[notification:NOTIFIED]->(user:User {id:$id})
|
||||
${whereClause}
|
||||
WITH user, notification, resource,
|
||||
[(resource)<-[:WROTE]-(author:User) | author {.*}] as authors,
|
||||
[(resource)-[:COMMENTS]->(post:Post)<-[:WROTE]-(author:User) | post{.*, author: properties(author)} ] as posts
|
||||
[(resource)<-[:WROTE]-(author:User) | author {.*}] AS authors,
|
||||
[(resource)-[:COMMENTS]->(post:Post)<-[:WROTE]-(author:User) | post{.*, author: properties(author)} ] AS posts
|
||||
WITH resource, user, notification, authors, posts,
|
||||
resource {.*, __typename: labels(resource)[0], author: authors[0], post: posts[0]} as finalResource
|
||||
resource {.*, __typename: labels(resource)[0], author: authors[0], post: posts[0]} AS finalResource
|
||||
RETURN notification {.*, from: finalResource, to: properties(user)}
|
||||
${orderByClause}
|
||||
${offset} ${limit}
|
||||
@ -81,12 +78,19 @@ export default {
|
||||
`
|
||||
MATCH (resource {id: $resourceId})-[notification:NOTIFIED {read: FALSE}]->(user:User {id:$id})
|
||||
SET notification.read = TRUE
|
||||
RETURN resource, notification, user
|
||||
WITH user, notification, resource,
|
||||
[(resource)<-[:WROTE]-(author:User) | author {.*}] AS authors,
|
||||
[(resource)-[:COMMENTS]->(post:Post)<-[:WROTE]-(author:User) | post{.*, author: properties(author)} ] AS posts
|
||||
WITH resource, user, notification, authors, posts,
|
||||
resource {.*, __typename: labels(resource)[0], author: authors[0], post: posts[0]} AS finalResource
|
||||
RETURN notification {.*, from: finalResource, to: properties(user)}
|
||||
`,
|
||||
{ resourceId: args.id, id: currentUser.id },
|
||||
)
|
||||
log(markNotificationAsReadTransactionResponse)
|
||||
return markNotificationAsReadTransactionResponse.records.map(transformReturnType)
|
||||
return markNotificationAsReadTransactionResponse.records.map(record =>
|
||||
record.get('notification'),
|
||||
)
|
||||
})
|
||||
try {
|
||||
const [notifications] = await writeTxResultPromise
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '../.././server'
|
||||
|
||||
const factory = Factory()
|
||||
const driver = getDriver()
|
||||
let authenticatedUser
|
||||
let user
|
||||
@ -32,52 +31,77 @@ beforeEach(async () => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('given some notifications', () => {
|
||||
beforeEach(async () => {
|
||||
const categoryIds = ['cat1']
|
||||
author = await factory.create('User', { id: 'author' })
|
||||
user = await factory.create('User', { id: 'you' })
|
||||
author = await Factory.build('user', { id: 'author' })
|
||||
user = await Factory.build('user', { id: 'you' })
|
||||
const [neighbor] = await Promise.all([
|
||||
factory.create('User', { id: 'neighbor' }),
|
||||
factory.create('Category', { id: 'cat1' }),
|
||||
Factory.build('user', { id: 'neighbor' }),
|
||||
Factory.build('category', { id: 'cat1' }),
|
||||
])
|
||||
const [post1, post2, post3] = await Promise.all([
|
||||
factory.create('Post', { author, id: 'p1', categoryIds, content: 'Not for you' }),
|
||||
factory.create('Post', {
|
||||
author,
|
||||
id: 'p2',
|
||||
categoryIds,
|
||||
content: 'Already seen post mention',
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author,
|
||||
id: 'p3',
|
||||
categoryIds,
|
||||
content: 'You have been mentioned in a post',
|
||||
}),
|
||||
Factory.build('post', { id: 'p1', content: 'Not for you' }, { author, categoryIds }),
|
||||
Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'p2',
|
||||
content: 'Already seen post mention',
|
||||
},
|
||||
{
|
||||
author,
|
||||
categoryIds,
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'p3',
|
||||
content: 'You have been mentioned in a post',
|
||||
},
|
||||
{
|
||||
author,
|
||||
categoryIds,
|
||||
},
|
||||
),
|
||||
])
|
||||
const [comment1, comment2, comment3] = await Promise.all([
|
||||
factory.create('Comment', {
|
||||
author,
|
||||
postId: 'p3',
|
||||
id: 'c1',
|
||||
content: 'You have seen this comment mentioning already',
|
||||
}),
|
||||
factory.create('Comment', {
|
||||
author,
|
||||
postId: 'p3',
|
||||
id: 'c2',
|
||||
content: 'You have been mentioned in a comment',
|
||||
}),
|
||||
factory.create('Comment', {
|
||||
author,
|
||||
postId: 'p3',
|
||||
id: 'c3',
|
||||
content: 'Somebody else was mentioned in a comment',
|
||||
}),
|
||||
Factory.build(
|
||||
'comment',
|
||||
{
|
||||
id: 'c1',
|
||||
content: 'You have seen this comment mentioning already',
|
||||
},
|
||||
{
|
||||
author,
|
||||
postId: 'p3',
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'comment',
|
||||
{
|
||||
id: 'c2',
|
||||
content: 'You have been mentioned in a comment',
|
||||
},
|
||||
{
|
||||
author,
|
||||
postId: 'p3',
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'comment',
|
||||
{
|
||||
id: 'c3',
|
||||
content: 'Somebody else was mentioned in a comment',
|
||||
},
|
||||
{
|
||||
author,
|
||||
postId: 'p3',
|
||||
},
|
||||
),
|
||||
])
|
||||
await Promise.all([
|
||||
post1.relateTo(neighbor, 'notified', {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createPasswordReset from './helpers/createPasswordReset'
|
||||
@ -7,7 +7,6 @@ import { createTestClient } from 'apollo-server-testing'
|
||||
|
||||
const neode = getNeode()
|
||||
const driver = getDriver()
|
||||
const factory = Factory()
|
||||
|
||||
let mutate
|
||||
let authenticatedUser
|
||||
@ -39,15 +38,19 @@ beforeAll(() => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('passwordReset', () => {
|
||||
describe('given a user', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('User', {
|
||||
email: 'user@example.org',
|
||||
})
|
||||
await Factory.build(
|
||||
'user',
|
||||
{},
|
||||
{
|
||||
email: 'user@example.org',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
describe('requestPasswordReset', () => {
|
||||
@ -123,11 +126,16 @@ describe('resetPassword', () => {
|
||||
|
||||
describe('given a user', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('User', {
|
||||
email: 'user@example.org',
|
||||
role: 'user',
|
||||
password: '1234',
|
||||
})
|
||||
await Factory.build(
|
||||
'user',
|
||||
{
|
||||
role: 'user',
|
||||
},
|
||||
{
|
||||
email: 'user@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
describe('invalid email', () => {
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
|
||||
const driver = getDriver()
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
|
||||
let query
|
||||
@ -40,7 +39,7 @@ const createPostMutation = gql`
|
||||
`
|
||||
|
||||
beforeAll(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
const { server } = createServer({
|
||||
context: () => {
|
||||
return {
|
||||
@ -56,12 +55,17 @@ beforeAll(async () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
variables = {}
|
||||
user = await factory.create('User', {
|
||||
id: 'current-user',
|
||||
name: 'TestUser',
|
||||
email: 'test@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
user = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'current-user',
|
||||
name: 'TestUser',
|
||||
},
|
||||
{
|
||||
email: 'test@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
await Promise.all([
|
||||
neode.create('Category', {
|
||||
id: 'cat9',
|
||||
@ -88,7 +92,7 @@ beforeEach(async () => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('Post', () => {
|
||||
@ -96,21 +100,31 @@ describe('Post', () => {
|
||||
let followedUser, happyPost, cryPost
|
||||
beforeEach(async () => {
|
||||
;[followedUser] = await Promise.all([
|
||||
factory.create('User', {
|
||||
id: 'followed-by-me',
|
||||
email: 'followed@example.org',
|
||||
name: 'Followed User',
|
||||
password: '1234',
|
||||
}),
|
||||
Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'followed-by-me',
|
||||
name: 'Followed User',
|
||||
},
|
||||
{
|
||||
email: 'followed@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
),
|
||||
])
|
||||
;[happyPost, cryPost] = await Promise.all([
|
||||
factory.create('Post', { id: 'happy-post', categoryIds: ['cat4'] }),
|
||||
factory.create('Post', { id: 'cry-post', categoryIds: ['cat15'] }),
|
||||
factory.create('Post', {
|
||||
id: 'post-by-followed-user',
|
||||
categoryIds: ['cat9'],
|
||||
author: followedUser,
|
||||
}),
|
||||
Factory.build('post', { id: 'happy-post' }, { categoryIds: ['cat4'] }),
|
||||
Factory.build('post', { id: 'cry-post' }, { categoryIds: ['cat15'] }),
|
||||
Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'post-by-followed-user',
|
||||
},
|
||||
{
|
||||
categoryIds: ['cat9'],
|
||||
author: followedUser,
|
||||
},
|
||||
),
|
||||
])
|
||||
})
|
||||
|
||||
@ -340,14 +354,19 @@ describe('UpdatePost', () => {
|
||||
}
|
||||
`
|
||||
beforeEach(async () => {
|
||||
author = await factory.create('User', { slug: 'the-author' })
|
||||
newlyCreatedPost = await factory.create('Post', {
|
||||
author,
|
||||
id: 'p9876',
|
||||
title: 'Old title',
|
||||
content: 'Old content',
|
||||
categoryIds,
|
||||
})
|
||||
author = await Factory.build('user', { slug: 'the-author' })
|
||||
newlyCreatedPost = await Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'p9876',
|
||||
title: 'Old title',
|
||||
content: 'Old content',
|
||||
},
|
||||
{
|
||||
author,
|
||||
categoryIds,
|
||||
},
|
||||
)
|
||||
|
||||
variables = {
|
||||
id: 'p9876',
|
||||
@ -529,10 +548,15 @@ describe('UpdatePost', () => {
|
||||
|
||||
describe('are allowed to pin posts', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('Post', {
|
||||
id: 'created-and-pinned-by-same-admin',
|
||||
author: admin,
|
||||
})
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'created-and-pinned-by-same-admin',
|
||||
},
|
||||
{
|
||||
author: admin,
|
||||
},
|
||||
)
|
||||
variables = { ...variables, id: 'created-and-pinned-by-same-admin' }
|
||||
})
|
||||
|
||||
@ -589,15 +613,20 @@ describe('UpdatePost', () => {
|
||||
describe('post created by another admin', () => {
|
||||
let otherAdmin
|
||||
beforeEach(async () => {
|
||||
otherAdmin = await factory.create('User', {
|
||||
otherAdmin = await Factory.build('user', {
|
||||
role: 'admin',
|
||||
name: 'otherAdmin',
|
||||
})
|
||||
authenticatedUser = await otherAdmin.toJson()
|
||||
await factory.create('Post', {
|
||||
id: 'created-by-one-admin-pinned-by-different-one',
|
||||
author: otherAdmin,
|
||||
})
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'created-by-one-admin-pinned-by-different-one',
|
||||
},
|
||||
{
|
||||
author: otherAdmin,
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it('responds with the updated Post', async () => {
|
||||
@ -654,10 +683,15 @@ describe('UpdatePost', () => {
|
||||
describe('pinned post already exists', () => {
|
||||
let pinnedPost
|
||||
beforeEach(async () => {
|
||||
await factory.create('Post', {
|
||||
id: 'only-pinned-post',
|
||||
author: admin,
|
||||
})
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'only-pinned-post',
|
||||
},
|
||||
{
|
||||
author: admin,
|
||||
},
|
||||
)
|
||||
await mutate({ mutation: pinPostMutation, variables })
|
||||
})
|
||||
|
||||
@ -683,12 +717,12 @@ describe('UpdatePost', () => {
|
||||
|
||||
describe('PostOrdering', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('Post', {
|
||||
await Factory.build('post', {
|
||||
id: 'im-a-pinned-post',
|
||||
createdAt: '2019-11-22T17:26:29.070Z',
|
||||
pinned: true,
|
||||
})
|
||||
await factory.create('Post', {
|
||||
await Factory.build('post', {
|
||||
id: 'i-was-created-before-pinned-post',
|
||||
// fairly old, so this should be 3rd
|
||||
createdAt: '2019-10-22T17:26:29.070Z',
|
||||
@ -807,7 +841,7 @@ describe('UpdatePost', () => {
|
||||
describe('admin can unpin posts', () => {
|
||||
let admin, pinnedPost
|
||||
beforeEach(async () => {
|
||||
pinnedPost = await factory.create('Post', { id: 'post-to-be-unpinned' })
|
||||
pinnedPost = await Factory.build('post', { id: 'post-to-be-unpinned' })
|
||||
admin = await user.update({
|
||||
role: 'admin',
|
||||
name: 'Admin',
|
||||
@ -874,15 +908,20 @@ describe('DeletePost', () => {
|
||||
`
|
||||
|
||||
beforeEach(async () => {
|
||||
author = await factory.create('User')
|
||||
await factory.create('Post', {
|
||||
id: 'p4711',
|
||||
author,
|
||||
title: 'I will be deleted',
|
||||
content: 'To be deleted',
|
||||
image: 'path/to/some/image',
|
||||
categoryIds,
|
||||
})
|
||||
author = await Factory.build('user')
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'p4711',
|
||||
title: 'I will be deleted',
|
||||
content: 'To be deleted',
|
||||
image: 'path/to/some/image',
|
||||
},
|
||||
{
|
||||
author,
|
||||
categoryIds,
|
||||
},
|
||||
)
|
||||
variables = { ...variables, id: 'p4711' }
|
||||
})
|
||||
|
||||
@ -929,11 +968,16 @@ describe('DeletePost', () => {
|
||||
|
||||
describe('if there are comments on the post', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('Comment', {
|
||||
postId: 'p4711',
|
||||
content: 'to be deleted comment content',
|
||||
contentExcerpt: 'to be deleted comment content',
|
||||
})
|
||||
await Factory.build(
|
||||
'comment',
|
||||
{
|
||||
content: 'to be deleted comment content',
|
||||
contentExcerpt: 'to be deleted comment content',
|
||||
},
|
||||
{
|
||||
postId: 'p4711',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it('marks the comments as deleted', async () => {
|
||||
@ -988,11 +1032,16 @@ describe('emotions', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
author = await neode.create('User', { id: 'u257' })
|
||||
postToEmote = await factory.create('Post', {
|
||||
author,
|
||||
id: 'p1376',
|
||||
categoryIds,
|
||||
})
|
||||
postToEmote = await Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'p1376',
|
||||
},
|
||||
{
|
||||
author,
|
||||
categoryIds,
|
||||
},
|
||||
)
|
||||
|
||||
variables = {
|
||||
...variables,
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getDriver, getNeode } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
|
||||
let mutate
|
||||
@ -30,7 +29,7 @@ beforeAll(() => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('Signup', () => {
|
||||
@ -58,11 +57,16 @@ describe('Signup', () => {
|
||||
|
||||
describe('as admin', () => {
|
||||
beforeEach(async () => {
|
||||
const admin = await factory.create('User', {
|
||||
role: 'admin',
|
||||
email: 'admin@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
const admin = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
role: 'admin',
|
||||
},
|
||||
{
|
||||
email: 'admin@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
authenticatedUser = await admin.toJson()
|
||||
})
|
||||
|
||||
@ -90,9 +94,9 @@ describe('Signup', () => {
|
||||
})
|
||||
|
||||
describe('if the email already exists', () => {
|
||||
let email
|
||||
let emailAddress
|
||||
beforeEach(async () => {
|
||||
email = await factory.create('EmailAddress', {
|
||||
emailAddress = await Factory.build('emailAddress', {
|
||||
email: 'someuser@example.org',
|
||||
verifiedAt: null,
|
||||
})
|
||||
@ -100,7 +104,8 @@ describe('Signup', () => {
|
||||
|
||||
describe('and the user has registered already', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('User', { email })
|
||||
const user = await Factory.build('userWithoutEmailAddress')
|
||||
await emailAddress.relateTo(user, 'belongsTo')
|
||||
})
|
||||
|
||||
it('throws UserInputError error because of unique constraint violation', async () => {
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '../.././server'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getDriver, getNeode } from '../../db/neo4j'
|
||||
|
||||
const factory = Factory()
|
||||
const instance = getNeode()
|
||||
const driver = getDriver()
|
||||
|
||||
@ -53,7 +52,7 @@ describe('file a report on a resource', () => {
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
const { server } = createServer({
|
||||
context: () => {
|
||||
return {
|
||||
@ -68,7 +67,7 @@ describe('file a report on a resource', () => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('report a resource', () => {
|
||||
@ -84,24 +83,39 @@ describe('file a report on a resource', () => {
|
||||
|
||||
describe('authenticated', () => {
|
||||
beforeEach(async () => {
|
||||
currentUser = await factory.create('User', {
|
||||
id: 'current-user-id',
|
||||
role: 'user',
|
||||
email: 'test@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
otherReportingUser = await factory.create('User', {
|
||||
id: 'other-reporting-user-id',
|
||||
role: 'user',
|
||||
email: 'reporting@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
await factory.create('User', {
|
||||
id: 'abusive-user-id',
|
||||
role: 'user',
|
||||
name: 'abusive-user',
|
||||
email: 'abusive-user@example.org',
|
||||
})
|
||||
currentUser = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'current-user-id',
|
||||
role: 'user',
|
||||
},
|
||||
{
|
||||
email: 'test@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
otherReportingUser = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'other-reporting-user-id',
|
||||
role: 'user',
|
||||
},
|
||||
{
|
||||
email: 'reporting@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'abusive-user-id',
|
||||
role: 'user',
|
||||
name: 'abusive-user',
|
||||
},
|
||||
{
|
||||
email: 'abusive-user@example.org',
|
||||
},
|
||||
)
|
||||
await instance.create('Category', {
|
||||
id: 'cat9',
|
||||
name: 'Democracy & Politics',
|
||||
@ -341,12 +355,17 @@ describe('file a report on a resource', () => {
|
||||
|
||||
describe('reported resource is a post', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('Post', {
|
||||
author: currentUser,
|
||||
id: 'post-to-report-id',
|
||||
title: 'This is a post that is going to be reported',
|
||||
categoryIds,
|
||||
})
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'post-to-report-id',
|
||||
title: 'This is a post that is going to be reported',
|
||||
},
|
||||
{
|
||||
author: currentUser,
|
||||
categoryIds,
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it('returns type "Post"', async () => {
|
||||
@ -394,21 +413,30 @@ describe('file a report on a resource', () => {
|
||||
})
|
||||
|
||||
describe('reported resource is a comment', () => {
|
||||
let createPostVariables
|
||||
beforeEach(async () => {
|
||||
createPostVariables = {
|
||||
id: 'p1',
|
||||
title: 'post to comment on',
|
||||
content: 'please comment on me',
|
||||
categoryIds,
|
||||
}
|
||||
await factory.create('Post', { ...createPostVariables, author: currentUser })
|
||||
await factory.create('Comment', {
|
||||
author: currentUser,
|
||||
postId: 'p1',
|
||||
id: 'comment-to-report-id',
|
||||
content: 'Post comment to be reported.',
|
||||
})
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'p1',
|
||||
title: 'post to comment on',
|
||||
content: 'please comment on me',
|
||||
},
|
||||
{
|
||||
categoryIds,
|
||||
author: currentUser,
|
||||
},
|
||||
)
|
||||
await Factory.build(
|
||||
'comment',
|
||||
{
|
||||
id: 'comment-to-report-id',
|
||||
content: 'Post comment to be reported.',
|
||||
},
|
||||
{
|
||||
author: currentUser,
|
||||
postId: 'p1',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it('returns type "Comment"', async () => {
|
||||
@ -457,7 +485,7 @@ describe('file a report on a resource', () => {
|
||||
|
||||
describe('reported resource is a tag', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('Tag', {
|
||||
await Factory.build('tag', {
|
||||
id: 'tag-to-report-id',
|
||||
})
|
||||
})
|
||||
@ -515,24 +543,39 @@ describe('file a report on a resource', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
authenticatedUser = null
|
||||
moderator = await factory.create('User', {
|
||||
id: 'moderator-1',
|
||||
role: 'moderator',
|
||||
email: 'moderator@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
currentUser = await factory.create('User', {
|
||||
id: 'current-user-id',
|
||||
role: 'user',
|
||||
email: 'current.user@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
abusiveUser = await factory.create('User', {
|
||||
id: 'abusive-user-1',
|
||||
role: 'user',
|
||||
name: 'abusive-user',
|
||||
email: 'abusive-user@example.org',
|
||||
})
|
||||
moderator = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'moderator-1',
|
||||
role: 'moderator',
|
||||
},
|
||||
{
|
||||
email: 'moderator@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
currentUser = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'current-user-id',
|
||||
role: 'user',
|
||||
},
|
||||
{
|
||||
email: 'current.user@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
abusiveUser = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'abusive-user-1',
|
||||
role: 'user',
|
||||
name: 'abusive-user',
|
||||
},
|
||||
{
|
||||
email: 'abusive-user@example.org',
|
||||
},
|
||||
)
|
||||
await instance.create('Category', {
|
||||
id: 'cat9',
|
||||
name: 'Democracy & Politics',
|
||||
@ -540,31 +583,51 @@ describe('file a report on a resource', () => {
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
factory.create('Post', {
|
||||
author: abusiveUser,
|
||||
id: 'abusive-post-1',
|
||||
categoryIds,
|
||||
content: 'Interesting Knowledge',
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author: moderator,
|
||||
id: 'post-2',
|
||||
categoryIds,
|
||||
content: 'More things to do …',
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author: currentUser,
|
||||
id: 'post-3',
|
||||
categoryIds,
|
||||
content: 'I am at school …',
|
||||
}),
|
||||
Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'abusive-post-1',
|
||||
content: 'Interesting Knowledge',
|
||||
},
|
||||
{
|
||||
categoryIds,
|
||||
author: abusiveUser,
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'post-2',
|
||||
content: 'More things to do …',
|
||||
},
|
||||
{
|
||||
author: moderator,
|
||||
categoryIds,
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'post-3',
|
||||
content: 'I am at school …',
|
||||
},
|
||||
{
|
||||
categoryIds,
|
||||
author: currentUser,
|
||||
},
|
||||
),
|
||||
])
|
||||
await Promise.all([
|
||||
factory.create('Comment', {
|
||||
author: currentUser,
|
||||
id: 'abusive-comment-1',
|
||||
postId: 'post-1',
|
||||
}),
|
||||
Factory.build(
|
||||
'comment',
|
||||
{
|
||||
id: 'abusive-comment-1',
|
||||
},
|
||||
{
|
||||
postId: 'post-2',
|
||||
author: currentUser,
|
||||
},
|
||||
),
|
||||
])
|
||||
authenticatedUser = await currentUser.toJson()
|
||||
await Promise.all([
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
|
||||
const factory = Factory()
|
||||
const driver = getDriver()
|
||||
const instance = getNeode()
|
||||
|
||||
@ -31,23 +30,38 @@ describe('rewards', () => {
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
regularUser = await factory.create('User', {
|
||||
id: 'regular-user-id',
|
||||
role: 'user',
|
||||
email: 'user@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
moderator = await factory.create('User', {
|
||||
id: 'moderator-id',
|
||||
role: 'moderator',
|
||||
email: 'moderator@example.org',
|
||||
})
|
||||
administrator = await factory.create('User', {
|
||||
id: 'admin-id',
|
||||
role: 'admin',
|
||||
email: 'admin@example.org',
|
||||
})
|
||||
badge = await factory.create('Badge', {
|
||||
regularUser = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'regular-user-id',
|
||||
role: 'user',
|
||||
},
|
||||
{
|
||||
email: 'user@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
moderator = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'moderator-id',
|
||||
role: 'moderator',
|
||||
},
|
||||
{
|
||||
email: 'moderator@example.org',
|
||||
},
|
||||
)
|
||||
administrator = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'admin-id',
|
||||
role: 'admin',
|
||||
},
|
||||
{
|
||||
email: 'admin@example.org',
|
||||
},
|
||||
)
|
||||
badge = await Factory.build('badge', {
|
||||
id: 'indiegogo_en_rhino',
|
||||
type: 'crowdfunding',
|
||||
status: 'permanent',
|
||||
@ -56,7 +70,7 @@ describe('rewards', () => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('reward', () => {
|
||||
@ -130,7 +144,7 @@ describe('rewards', () => {
|
||||
})
|
||||
|
||||
it('rewards a second different badge to same user', async () => {
|
||||
await factory.create('Badge', {
|
||||
await Factory.build('badge', {
|
||||
id: 'indiegogo_en_racoon',
|
||||
icon: '/img/badges/indiegogo_en_racoon.svg',
|
||||
})
|
||||
@ -172,10 +186,15 @@ describe('rewards', () => {
|
||||
},
|
||||
errors: undefined,
|
||||
}
|
||||
await factory.create('User', {
|
||||
id: 'regular-user-2-id',
|
||||
email: 'regular2@email.com',
|
||||
})
|
||||
await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'regular-user-2-id',
|
||||
},
|
||||
{
|
||||
email: 'regular2@email.com',
|
||||
},
|
||||
)
|
||||
await mutate({
|
||||
mutation: rewardMutation,
|
||||
variables,
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
|
||||
let mutate, query, authenticatedUser, variables
|
||||
const factory = Factory()
|
||||
const instance = getNeode()
|
||||
const driver = getDriver()
|
||||
|
||||
@ -47,22 +46,32 @@ describe('shout and unshout posts', () => {
|
||||
query = createTestClient(server).query
|
||||
})
|
||||
beforeEach(async () => {
|
||||
currentUser = await factory.create('User', {
|
||||
id: 'current-user-id',
|
||||
name: 'Current User',
|
||||
email: 'current.user@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
currentUser = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'current-user-id',
|
||||
name: 'Current User',
|
||||
},
|
||||
{
|
||||
email: 'current.user@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
|
||||
postAuthor = await factory.create('User', {
|
||||
id: 'id-of-another-user',
|
||||
name: 'Another User',
|
||||
email: 'another.user@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
postAuthor = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'id-of-another-user',
|
||||
name: 'Another User',
|
||||
},
|
||||
{
|
||||
email: 'another.user@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
})
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('shout', () => {
|
||||
@ -78,16 +87,26 @@ describe('shout and unshout posts', () => {
|
||||
describe('authenticated', () => {
|
||||
beforeEach(async () => {
|
||||
authenticatedUser = await currentUser.toJson()
|
||||
await factory.create('Post', {
|
||||
name: 'Other user post',
|
||||
id: 'another-user-post-id',
|
||||
author: postAuthor,
|
||||
})
|
||||
await factory.create('Post', {
|
||||
name: 'current user post',
|
||||
id: 'current-user-post-id',
|
||||
author: currentUser,
|
||||
})
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
name: 'Other user post',
|
||||
id: 'another-user-post-id',
|
||||
},
|
||||
{
|
||||
author: postAuthor,
|
||||
},
|
||||
)
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
name: 'current user post',
|
||||
id: 'current-user-post-id',
|
||||
},
|
||||
{
|
||||
author: currentUser,
|
||||
},
|
||||
)
|
||||
variables = {}
|
||||
})
|
||||
|
||||
@ -144,11 +163,16 @@ describe('shout and unshout posts', () => {
|
||||
describe('authenticated', () => {
|
||||
beforeEach(async () => {
|
||||
authenticatedUser = await currentUser.toJson()
|
||||
await factory.create('Post', {
|
||||
name: 'Posted By Another User',
|
||||
id: 'posted-by-another-user',
|
||||
author: postAuthor,
|
||||
})
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
name: 'Posted By Another User',
|
||||
id: 'posted-by-another-user',
|
||||
},
|
||||
{
|
||||
author: postAuthor,
|
||||
},
|
||||
)
|
||||
await mutate({
|
||||
mutation: mutationShoutPost,
|
||||
variables: { id: 'posted-by-another-user' },
|
||||
|
||||
@ -1,41 +1,46 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '../../server'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import { getDriver } from '../../db/neo4j'
|
||||
|
||||
const driver = getDriver()
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
|
||||
describe('SocialMedia', () => {
|
||||
let socialMediaAction, someUser, ownerNode, owner
|
||||
|
||||
const ownerParams = {
|
||||
email: 'pippi@example.com',
|
||||
password: '1234',
|
||||
name: 'Pippi Langstrumpf',
|
||||
}
|
||||
|
||||
const userParams = {
|
||||
email: 'kalle@example.com',
|
||||
password: 'abcd',
|
||||
name: 'Kalle Blomqvist',
|
||||
}
|
||||
|
||||
const url = 'https://twitter.com/pippi-langstrumpf'
|
||||
const newUrl = 'https://twitter.com/bullerby'
|
||||
|
||||
const setUpSocialMedia = async () => {
|
||||
const socialMediaNode = await neode.create('SocialMedia', { url })
|
||||
const socialMediaNode = await Factory.build('socialMedia', { url })
|
||||
await socialMediaNode.relateTo(ownerNode, 'ownedBy')
|
||||
return socialMediaNode.toJson()
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
const someUserNode = await neode.create('User', userParams)
|
||||
const someUserNode = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
name: 'Kalle Blomqvist',
|
||||
},
|
||||
{
|
||||
email: 'kalle@example.com',
|
||||
password: 'abcd',
|
||||
},
|
||||
)
|
||||
|
||||
someUser = await someUserNode.toJson()
|
||||
ownerNode = await neode.create('User', ownerParams)
|
||||
ownerNode = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
name: 'Pippi Langstrumpf',
|
||||
},
|
||||
{
|
||||
email: 'pippi@example.com',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
owner = await ownerNode.toJson()
|
||||
|
||||
socialMediaAction = async (user, mutation, variables) => {
|
||||
@ -57,7 +62,7 @@ describe('SocialMedia', () => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('create social media', () => {
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
|
||||
let query, authenticatedUser
|
||||
const factory = Factory()
|
||||
const instance = getNeode()
|
||||
const driver = getDriver()
|
||||
|
||||
@ -37,7 +36,7 @@ beforeAll(() => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('statistics', () => {
|
||||
@ -45,7 +44,7 @@ describe('statistics', () => {
|
||||
beforeEach(async () => {
|
||||
await Promise.all(
|
||||
[...Array(6).keys()].map(() => {
|
||||
return factory.create('User')
|
||||
return Factory.build('user')
|
||||
}),
|
||||
)
|
||||
})
|
||||
@ -62,7 +61,7 @@ describe('statistics', () => {
|
||||
beforeEach(async () => {
|
||||
await Promise.all(
|
||||
[...Array(3).keys()].map(() => {
|
||||
return factory.create('Post')
|
||||
return Factory.build('post')
|
||||
}),
|
||||
)
|
||||
})
|
||||
@ -79,7 +78,7 @@ describe('statistics', () => {
|
||||
beforeEach(async () => {
|
||||
await Promise.all(
|
||||
[...Array(2).keys()].map(() => {
|
||||
return factory.create('Comment')
|
||||
return Factory.build('comment')
|
||||
}),
|
||||
)
|
||||
})
|
||||
@ -97,7 +96,7 @@ describe('statistics', () => {
|
||||
beforeEach(async () => {
|
||||
users = await Promise.all(
|
||||
[...Array(2).keys()].map(() => {
|
||||
return factory.create('User')
|
||||
return Factory.build('user')
|
||||
}),
|
||||
)
|
||||
await users[0].relateTo(users[1], 'following')
|
||||
@ -116,12 +115,12 @@ describe('statistics', () => {
|
||||
beforeEach(async () => {
|
||||
users = await Promise.all(
|
||||
[...Array(2).keys()].map(() => {
|
||||
return factory.create('User')
|
||||
return Factory.build('user')
|
||||
}),
|
||||
)
|
||||
posts = await Promise.all(
|
||||
[...Array(3).keys()].map(() => {
|
||||
return factory.create('Post')
|
||||
return Factory.build('post')
|
||||
}),
|
||||
)
|
||||
await Promise.all([
|
||||
|
||||
@ -1,20 +1,19 @@
|
||||
import jwt from 'jsonwebtoken'
|
||||
import CONFIG from './../../config'
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer, { context } from '../../server'
|
||||
import encode from '../../jwt/encode'
|
||||
import { getNeode } from '../../db/neo4j'
|
||||
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
let query, mutate, variables, req, user
|
||||
|
||||
const disable = async id => {
|
||||
const moderator = await factory.create('User', { id: 'u2', role: 'moderator' })
|
||||
const moderator = await Factory.build('user', { id: 'u2', role: 'moderator' })
|
||||
const user = await neode.find('User', id)
|
||||
const reportAgainstUser = await factory.create('Report')
|
||||
const reportAgainstUser = await Factory.build('report')
|
||||
await Promise.all([
|
||||
reportAgainstUser.relateTo(moderator, 'filed', {
|
||||
resourceId: id,
|
||||
@ -48,7 +47,7 @@ beforeAll(() => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('isLoggedIn', () => {
|
||||
@ -69,7 +68,7 @@ describe('isLoggedIn', () => {
|
||||
|
||||
describe('authenticated', () => {
|
||||
beforeEach(async () => {
|
||||
user = await factory.create('User', { id: 'u3' })
|
||||
user = await Factory.build('user', { id: 'u3' })
|
||||
const userBearerToken = encode({ id: 'u3' })
|
||||
req = { headers: { authorization: `Bearer ${userBearerToken}` } }
|
||||
})
|
||||
@ -127,15 +126,20 @@ describe('currentUser', () => {
|
||||
describe('authenticated', () => {
|
||||
describe('and corresponding user in the database', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('User', {
|
||||
id: 'u3',
|
||||
// the `id` is the only thing that has to match the decoded JWT bearer token
|
||||
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
|
||||
email: 'test@example.org',
|
||||
name: 'Matilde Hermiston',
|
||||
slug: 'matilde-hermiston',
|
||||
role: 'user',
|
||||
})
|
||||
await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'u3',
|
||||
// the `id` is the only thing that has to match the decoded JWT bearer token
|
||||
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
|
||||
name: 'Matilde Hermiston',
|
||||
slug: 'matilde-hermiston',
|
||||
role: 'user',
|
||||
},
|
||||
{
|
||||
email: 'test@example.org',
|
||||
},
|
||||
)
|
||||
const userBearerToken = encode({ id: 'u3' })
|
||||
req = { headers: { authorization: `Bearer ${userBearerToken}` } }
|
||||
})
|
||||
@ -172,10 +176,13 @@ describe('login', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
variables = { email: 'test@example.org', password: '1234' }
|
||||
user = await factory.create('User', {
|
||||
...variables,
|
||||
id: 'acb2d923-f3af-479e-9f00-61b12e864666',
|
||||
})
|
||||
user = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'acb2d923-f3af-479e-9f00-61b12e864666',
|
||||
},
|
||||
variables,
|
||||
)
|
||||
})
|
||||
|
||||
describe('ask for a `token`', () => {
|
||||
@ -185,7 +192,9 @@ describe('login', () => {
|
||||
data: { login: token },
|
||||
} = await mutate({ mutation: loginMutation, variables })
|
||||
jwt.verify(token, CONFIG.JWT_SECRET, (err, data) => {
|
||||
expect(data.email).toEqual('test@example.org')
|
||||
expect(data).toMatchObject({
|
||||
id: 'acb2d923-f3af-479e-9f00-61b12e864666',
|
||||
})
|
||||
expect(err).toBeNull()
|
||||
done()
|
||||
})
|
||||
@ -295,7 +304,7 @@ describe('change password', () => {
|
||||
|
||||
describe('authenticated', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('User', { id: 'u3' })
|
||||
await Factory.build('user', { id: 'u3' })
|
||||
const userBearerToken = encode({ id: 'u3' })
|
||||
req = { headers: { authorization: `Bearer ${userBearerToken}` } }
|
||||
})
|
||||
|
||||
@ -252,9 +252,11 @@ export default {
|
||||
followedByCurrentUser:
|
||||
'MATCH (this)<-[:FOLLOWS]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1',
|
||||
blocked:
|
||||
'MATCH (this)<-[:BLOCKED]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1',
|
||||
'MATCH (this)-[:BLOCKED]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1',
|
||||
isMuted:
|
||||
'MATCH (this)<-[:MUTED]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1',
|
||||
isBlocked:
|
||||
'MATCH (this)<-[:BLOCKED]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1',
|
||||
},
|
||||
count: {
|
||||
contributionsCount:
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import Factory from '../../factories'
|
||||
import Factory, { cleanDatabase } from '../../db/factories'
|
||||
import { gql } from '../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../db/neo4j'
|
||||
import createServer from '../../server'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
|
||||
const factory = Factory()
|
||||
const categoryIds = ['cat9']
|
||||
let user
|
||||
|
||||
@ -31,13 +30,13 @@ beforeAll(() => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('User', () => {
|
||||
describe('query by email address', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('User', { name: 'Johnny', email: 'any-email-address@example.org' })
|
||||
await Factory.build('user', { name: 'Johnny' }, { email: 'any-email-address@example.org' })
|
||||
})
|
||||
|
||||
const userQuery = gql`
|
||||
@ -57,11 +56,16 @@ describe('User', () => {
|
||||
|
||||
describe('as admin', () => {
|
||||
beforeEach(async () => {
|
||||
const admin = await factory.create('User', {
|
||||
role: 'admin',
|
||||
email: 'admin@example.org',
|
||||
password: '1234',
|
||||
})
|
||||
const admin = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
role: 'admin',
|
||||
},
|
||||
{
|
||||
email: 'admin@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
authenticatedUser = await admin.toJson()
|
||||
})
|
||||
|
||||
@ -91,19 +95,9 @@ describe('User', () => {
|
||||
})
|
||||
|
||||
describe('UpdateUser', () => {
|
||||
let userParams, variables
|
||||
let variables
|
||||
|
||||
beforeEach(async () => {
|
||||
userParams = {
|
||||
email: 'user@example.org',
|
||||
password: '1234',
|
||||
id: 'u47',
|
||||
name: 'John Doe',
|
||||
termsAndConditionsAgreedVersion: null,
|
||||
termsAndConditionsAgreedAt: null,
|
||||
allowEmbedIframes: false,
|
||||
}
|
||||
|
||||
variables = {
|
||||
id: 'u47',
|
||||
name: 'John Doughnut',
|
||||
@ -133,18 +127,33 @@ describe('UpdateUser', () => {
|
||||
`
|
||||
|
||||
beforeEach(async () => {
|
||||
user = await factory.create('User', userParams)
|
||||
user = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'u47',
|
||||
name: 'John Doe',
|
||||
termsAndConditionsAgreedVersion: null,
|
||||
termsAndConditionsAgreedAt: null,
|
||||
allowEmbedIframes: false,
|
||||
},
|
||||
{
|
||||
email: 'user@example.org',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
describe('as another user', () => {
|
||||
beforeEach(async () => {
|
||||
const someoneElseParams = {
|
||||
email: 'someone-else@example.org',
|
||||
password: '1234',
|
||||
name: 'James Doe',
|
||||
}
|
||||
const someoneElse = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
name: 'James Doe',
|
||||
},
|
||||
{
|
||||
email: 'someone-else@example.org',
|
||||
},
|
||||
)
|
||||
|
||||
const someoneElse = await factory.create('User', someoneElseParams)
|
||||
authenticatedUser = await someoneElse.toJson()
|
||||
})
|
||||
|
||||
@ -267,16 +276,20 @@ describe('DeleteUser', () => {
|
||||
beforeEach(async () => {
|
||||
variables = { id: ' u343', resource: [] }
|
||||
|
||||
user = await factory.create('User', {
|
||||
user = await Factory.build('user', {
|
||||
name: 'My name should be deleted',
|
||||
about: 'along with my about',
|
||||
id: 'u343',
|
||||
})
|
||||
await factory.create('User', {
|
||||
email: 'friends-account@example.org',
|
||||
password: '1234',
|
||||
id: 'not-my-account',
|
||||
})
|
||||
await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'not-my-account',
|
||||
},
|
||||
{
|
||||
email: 'friends-account@example.org',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
describe('unauthenticated', () => {
|
||||
@ -309,27 +322,42 @@ describe('DeleteUser', () => {
|
||||
|
||||
describe('given posts and comments', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.create('Category', {
|
||||
await Factory.build('category', {
|
||||
id: 'cat9',
|
||||
name: 'Democracy & Politics',
|
||||
icon: 'university',
|
||||
})
|
||||
await factory.create('Post', {
|
||||
author: user,
|
||||
id: 'p139',
|
||||
content: 'Post by user u343',
|
||||
categoryIds,
|
||||
})
|
||||
await factory.create('Comment', {
|
||||
author: user,
|
||||
id: 'c155',
|
||||
content: 'Comment by user u343',
|
||||
})
|
||||
await factory.create('Comment', {
|
||||
postId: 'p139',
|
||||
id: 'c156',
|
||||
content: "A comment by someone else on user u343's post",
|
||||
})
|
||||
await Factory.build(
|
||||
'post',
|
||||
{
|
||||
id: 'p139',
|
||||
content: 'Post by user u343',
|
||||
},
|
||||
{
|
||||
author: user,
|
||||
categoryIds,
|
||||
},
|
||||
)
|
||||
await Factory.build(
|
||||
'comment',
|
||||
{
|
||||
id: 'c155',
|
||||
content: 'Comment by user u343',
|
||||
},
|
||||
{
|
||||
author: user,
|
||||
},
|
||||
)
|
||||
await Factory.build(
|
||||
'comment',
|
||||
{
|
||||
id: 'c156',
|
||||
content: "A comment by someone else on user u343's post",
|
||||
},
|
||||
{
|
||||
postId: 'p139',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it("deletes my account, but doesn't delete posts or comments by default", async () => {
|
||||
@ -527,7 +555,7 @@ describe('DeleteUser', () => {
|
||||
|
||||
describe('connected `SocialMedia` nodes', () => {
|
||||
beforeEach(async () => {
|
||||
const socialMedia = await factory.create('SocialMedia')
|
||||
const socialMedia = await Factory.build('socialMedia')
|
||||
await socialMedia.relateTo(user, 'ownedBy')
|
||||
})
|
||||
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { gql } from '../../../helpers/jest'
|
||||
import Factory from '../../../factories'
|
||||
import Factory, { cleanDatabase } from '../../../db/factories'
|
||||
import { getNeode, getDriver } from '../../../db/neo4j'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '../../../server'
|
||||
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
const driver = getDriver()
|
||||
let authenticatedUser, mutate, variables
|
||||
@ -107,7 +106,7 @@ beforeEach(() => {
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
factory.cleanDatabase()
|
||||
cleanDatabase()
|
||||
})
|
||||
|
||||
describe('userMiddleware', () => {
|
||||
@ -146,7 +145,7 @@ describe('userMiddleware', () => {
|
||||
})
|
||||
|
||||
describe('UpdateUser', () => {
|
||||
let user, userParams
|
||||
let user
|
||||
beforeEach(async () => {
|
||||
newlyCreatedNodesWithLocales = [
|
||||
{
|
||||
@ -182,10 +181,9 @@ describe('userMiddleware', () => {
|
||||
},
|
||||
},
|
||||
]
|
||||
userParams = {
|
||||
user = await Factory.build('user', {
|
||||
id: 'updating-user',
|
||||
}
|
||||
user = await factory.create('User', userParams)
|
||||
})
|
||||
authenticatedUser = await user.toJson()
|
||||
})
|
||||
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '../../../server'
|
||||
import Factory from '../../../factories'
|
||||
import { cleanDatabase } from '../../../db/factories'
|
||||
import { gql } from '../../../helpers/jest'
|
||||
import { getNeode, getDriver } from '../../../db/neo4j'
|
||||
|
||||
const driver = getDriver()
|
||||
const factory = Factory()
|
||||
const neode = getNeode()
|
||||
|
||||
let currentUser
|
||||
@ -30,7 +29,7 @@ beforeEach(() => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('mutedUsers', () => {
|
||||
|
||||
@ -30,3 +30,7 @@ type Query {
|
||||
type Mutation {
|
||||
markAsRead(id: ID!): NOTIFIED
|
||||
}
|
||||
|
||||
type Subscription {
|
||||
notificationAdded(userId: ID!): NOTIFIED
|
||||
}
|
||||
|
||||
@ -68,7 +68,12 @@ type User {
|
||||
RETURN COUNT(u) >= 1
|
||||
"""
|
||||
)
|
||||
|
||||
isBlocked: Boolean! @cypher(
|
||||
statement: """
|
||||
MATCH (this)<-[:BLOCKED]-(user:User {id: $cypherParams.currentUserId})
|
||||
RETURN COUNT(user) >= 1
|
||||
"""
|
||||
)
|
||||
blocked: Boolean! @cypher(
|
||||
statement: """
|
||||
MATCH (this)-[:BLOCKED]-(user:User {id: $cypherParams.currentUserId})
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import express from 'express'
|
||||
import http from 'http'
|
||||
import helmet from 'helmet'
|
||||
import { ApolloServer } from 'apollo-server-express'
|
||||
import CONFIG from './config'
|
||||
@ -7,11 +8,35 @@ import { getNeode, getDriver } from './db/neo4j'
|
||||
import decode from './jwt/decode'
|
||||
import schema from './schema'
|
||||
import webfinger from './activitypub/routes/webfinger'
|
||||
import { RedisPubSub } from 'graphql-redis-subscriptions'
|
||||
import { PubSub } from 'graphql-subscriptions'
|
||||
import Redis from 'ioredis'
|
||||
import bodyParser from 'body-parser'
|
||||
|
||||
export const NOTIFICATION_ADDED = 'NOTIFICATION_ADDED'
|
||||
const { REDIS_DOMAIN, REDIS_PORT, REDIS_PASSWORD } = CONFIG
|
||||
let prodPubsub, devPubsub
|
||||
const options = {
|
||||
host: REDIS_DOMAIN,
|
||||
port: REDIS_PORT,
|
||||
password: REDIS_PASSWORD,
|
||||
retryStrategy: times => {
|
||||
return Math.min(times * 50, 2000)
|
||||
},
|
||||
}
|
||||
if (options.host && options.port && options.password) {
|
||||
prodPubsub = new RedisPubSub({
|
||||
publisher: new Redis(options),
|
||||
subscriber: new Redis(options),
|
||||
})
|
||||
} else {
|
||||
devPubsub = new PubSub()
|
||||
}
|
||||
export const pubsub = prodPubsub || devPubsub
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
|
||||
export const context = async ({ req }) => {
|
||||
const getContext = async req => {
|
||||
const user = await decode(driver, req.headers.authorization)
|
||||
return {
|
||||
driver,
|
||||
@ -23,11 +48,24 @@ export const context = async ({ req }) => {
|
||||
},
|
||||
}
|
||||
}
|
||||
export const context = async options => {
|
||||
const { connection, req } = options
|
||||
if (connection) {
|
||||
return connection.context
|
||||
} else {
|
||||
return getContext(req)
|
||||
}
|
||||
}
|
||||
|
||||
const createServer = options => {
|
||||
const defaults = {
|
||||
context,
|
||||
schema: middleware(schema),
|
||||
subscriptions: {
|
||||
onConnect: (connectionParams, webSocket) => {
|
||||
return getContext(connectionParams)
|
||||
},
|
||||
},
|
||||
debug: !!CONFIG.DEBUG,
|
||||
tracing: !!CONFIG.DEBUG,
|
||||
formatError: error => {
|
||||
@ -45,9 +83,13 @@ const createServer = options => {
|
||||
app.use(helmet())
|
||||
app.use('/.well-known/', webfinger())
|
||||
app.use(express.static('public'))
|
||||
app.use(bodyParser.json({ limit: '10mb' }))
|
||||
app.use(bodyParser.urlencoded({ limit: '10mb', extended: true }))
|
||||
server.applyMiddleware({ app, path: '/' })
|
||||
const httpServer = http.createServer(app)
|
||||
server.installSubscriptionHandlers(httpServer)
|
||||
|
||||
return { server, app }
|
||||
return { server, httpServer, app }
|
||||
}
|
||||
|
||||
export default createServer
|
||||
|
||||
@ -3,18 +3,18 @@ import { Given, When, Then, AfterAll } from 'cucumber'
|
||||
import { expect } from 'chai'
|
||||
// import { client } from '../../../src/activitypub/apollo-client'
|
||||
import { GraphQLClient } from 'graphql-request'
|
||||
import Factory from '../../../src/factories'
|
||||
import Factory from '../../../src/db/factories'
|
||||
const debug = require('debug')('ea:test:steps')
|
||||
|
||||
const factory = Factory()
|
||||
const client = new GraphQLClient(host)
|
||||
|
||||
function createUser (slug) {
|
||||
debug(`creating user ${slug}`)
|
||||
return factory.create('User', {
|
||||
return Factory.build('user', {
|
||||
name: slug,
|
||||
}, {
|
||||
password: '1234',
|
||||
email: 'example@test.org',
|
||||
password: '1234'
|
||||
})
|
||||
// await login({ email: 'example@test.org', password: '1234' })
|
||||
}
|
||||
|
||||
@ -1175,13 +1175,13 @@
|
||||
url-regex "~4.1.1"
|
||||
video-extensions "~1.1.0"
|
||||
|
||||
"@metascraper/helpers@^5.10.6", "@metascraper/helpers@^5.10.7":
|
||||
version "5.10.7"
|
||||
resolved "https://registry.yarnpkg.com/@metascraper/helpers/-/helpers-5.10.7.tgz#4d330204372ce5c1afedfc3ac891fb373f72c085"
|
||||
integrity sha512-YkL4vTF4grgNTFhe9t4qsD0c5aEjxWoC0cpvMICs6JriRtedwjVfiwWhaGiTbU3pGFhmLgE9fV42wXOXGUGjMQ==
|
||||
"@metascraper/helpers@^5.10.7", "@metascraper/helpers@^5.11.1":
|
||||
version "5.11.1"
|
||||
resolved "https://registry.yarnpkg.com/@metascraper/helpers/-/helpers-5.11.1.tgz#227fdd0caf1d33f4b24a85298a355ce7ebb451df"
|
||||
integrity sha512-oES/e6bwKBlT7WGa2ni3xbJMDx2rbFxSzbUhRX8D+Kylb8H2ThP07c7f+VXMPXWx5CPrNMai/Oyp5IczCf3v8g==
|
||||
dependencies:
|
||||
audio-extensions "0.0.0"
|
||||
chrono-node "~1.4.2"
|
||||
chrono-node "~1.4.3"
|
||||
condense-whitespace "~2.0.0"
|
||||
entities "~2.0.0"
|
||||
file-extension "~4.0.5"
|
||||
@ -1275,22 +1275,22 @@
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
|
||||
|
||||
"@sentry/apm@5.12.0":
|
||||
version "5.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/apm/-/apm-5.12.0.tgz#6ec9c11d2754ab597bd0752b55fbbf2537f1d96b"
|
||||
integrity sha512-tpD6c0dVKkG+QPEubTTr54TDFdR/FWldnHwkhq4CST2uwkEm26o95iuNhMx9WE7EJhpXjaFKpZB0TB8frFIqkg==
|
||||
"@sentry/apm@5.12.3":
|
||||
version "5.12.3"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/apm/-/apm-5.12.3.tgz#23a5e9c771a8748f59426a1d0f8b1fbb9b72a717"
|
||||
integrity sha512-OSGEeo4b1Gsu/TUcWMx9vmgSnQvR+zM+1Iwq5xFQAK2ET3Y4gBFqZ1iRt2hxlzr8KCQmQTQc1mao1X0tmidFQg==
|
||||
dependencies:
|
||||
"@sentry/browser" "5.12.0"
|
||||
"@sentry/browser" "5.12.1"
|
||||
"@sentry/hub" "5.12.0"
|
||||
"@sentry/minimal" "5.12.0"
|
||||
"@sentry/types" "5.12.0"
|
||||
"@sentry/utils" "5.12.0"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/browser@5.12.0":
|
||||
version "5.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.12.0.tgz#d2c5b683eca6d5489a2c5b237712a8c9de9d4427"
|
||||
integrity sha512-e8uQML/1Wz2A6610yEvTdICf7L2IH15z6kcjwEqTsaD5uBCmpCiebGZABb45OSe9u8J0xccqi5G7M8lcxj1L7w==
|
||||
"@sentry/browser@5.12.1":
|
||||
version "5.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.12.1.tgz#dc1f268595269fb7277f55eb625c7e92d76dc01b"
|
||||
integrity sha512-Zl7VdppUxctyaoqMSEhnDJp2rrupx8n8N2n3PSooH74yhB2Z91nt84mouczprBsw3JU1iggGyUw9seRFzDI1hw==
|
||||
dependencies:
|
||||
"@sentry/core" "5.12.0"
|
||||
"@sentry/types" "5.12.0"
|
||||
@ -1326,12 +1326,12 @@
|
||||
"@sentry/types" "5.12.0"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/node@^5.12.0":
|
||||
version "5.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.12.0.tgz#9781d3cf4d7f664acacb9775912f67a3a465c259"
|
||||
integrity sha512-Q059wrvv7JDTfdlnI4GCAOW9BLeRxxx8P+TYK/t41ZgEbwTob/VU+rn+p7zQm8beHMM3IBtUKE54AmpHYnhJ/A==
|
||||
"@sentry/node@^5.12.3":
|
||||
version "5.12.3"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.12.3.tgz#4a4934b04c5163fc340312eaf0d152990aa7140f"
|
||||
integrity sha512-QwqN+i6IC3/YrNq7kqxH7YiXtZYY8tBuJqFi84WbiMHF7MAqxMSPNQJGfX2GJuMHKHwn6IZdgSE8+FkfN9zGLQ==
|
||||
dependencies:
|
||||
"@sentry/apm" "5.12.0"
|
||||
"@sentry/apm" "5.12.3"
|
||||
"@sentry/core" "5.12.0"
|
||||
"@sentry/hub" "5.12.0"
|
||||
"@sentry/types" "5.12.0"
|
||||
@ -1607,10 +1607,10 @@
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
"@types/yup@0.26.29":
|
||||
version "0.26.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.29.tgz#5a533ad6f74e442436698e20b1441c68a7a1c931"
|
||||
integrity sha512-M81oZOgLap0b0I/BySnpLwHjOj1BFxUKV1ytG2Kqj3jmkh8F3H11PEnk658UniftpjTXdueloOL+KZYn+SMQ9w==
|
||||
"@types/yup@0.26.30":
|
||||
version "0.26.30"
|
||||
resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.30.tgz#0d6066505bb67e7b9b161b2082c4cdfcdafd6a6b"
|
||||
integrity sha512-b/uklO68T/eShWnxjlgwOJlEFOQ11ib3i1wQQiLmHqFJTxDMvz+tb4XzThGQISzOcelMnoSdb1Po4s69YkEQeg==
|
||||
|
||||
"@types/zen-observable@^0.8.0":
|
||||
version "0.8.0"
|
||||
@ -1845,10 +1845,10 @@ apollo-client@~2.6.8:
|
||||
tslib "^1.10.0"
|
||||
zen-observable "^0.8.0"
|
||||
|
||||
apollo-datasource@^0.6.4:
|
||||
version "0.6.4"
|
||||
resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-0.6.4.tgz#c0d1604b1a97e004844d4b61bd819a9a6b0a409f"
|
||||
integrity sha512-u4eu6Q94q6KuZacZfdo4vCevA81F4QWeTYEXUvoksQMJpiacPHHe0DJrofKVKvxngUp5kCi1RnPXSc6kBY+/oA==
|
||||
apollo-datasource@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-0.7.0.tgz#2a6d82edb2eba21b4ddf21877009ba39ff821945"
|
||||
integrity sha512-Yja12BgNQhzuFGG/5Nw2MQe0hkuQy2+9er09HxeEyAf2rUDIPnhPrn1MDoZTB8MU7UGfjwITC+1ofzKkkrZobA==
|
||||
dependencies:
|
||||
apollo-server-caching "^0.5.1"
|
||||
apollo-server-env "^2.4.3"
|
||||
@ -1860,13 +1860,13 @@ apollo-engine-reporting-protobuf@^0.4.4:
|
||||
dependencies:
|
||||
"@apollo/protobufjs" "^1.0.3"
|
||||
|
||||
apollo-engine-reporting@^1.4.14:
|
||||
version "1.4.14"
|
||||
resolved "https://registry.yarnpkg.com/apollo-engine-reporting/-/apollo-engine-reporting-1.4.14.tgz#71a6509ebe86385da43df500cd0940525a3e8674"
|
||||
integrity sha512-cCG9qDOPwbh87ZjQGHgmnP3oPqhqjIZcNmm/lNtWkWXGTlxV/jmUEqpVi+wsDbE5gR7d1OFk6GqSy2ZQh+S+Bw==
|
||||
apollo-engine-reporting@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/apollo-engine-reporting/-/apollo-engine-reporting-1.5.0.tgz#6e3746de14fc87e14c289c0776a2d350e6f50918"
|
||||
integrity sha512-Pe2DelijZ2QHqkqv8E97iOb32l+FIMT2nxpQsuH+nWi+96cCFJJJHjm3RLAPEUuvGOgW9dFYQP3J91EyC5O0tQ==
|
||||
dependencies:
|
||||
apollo-engine-reporting-protobuf "^0.4.4"
|
||||
apollo-graphql "^0.3.7"
|
||||
apollo-graphql "^0.4.0"
|
||||
apollo-server-caching "^0.5.1"
|
||||
apollo-server-env "^2.4.3"
|
||||
apollo-server-errors "^2.3.4"
|
||||
@ -1892,10 +1892,10 @@ apollo-errors@^1.9.0:
|
||||
assert "^1.4.1"
|
||||
extendable-error "^0.1.5"
|
||||
|
||||
apollo-graphql@^0.3.7:
|
||||
version "0.3.7"
|
||||
resolved "https://registry.yarnpkg.com/apollo-graphql/-/apollo-graphql-0.3.7.tgz#533232ed48b0b6dbcf5635f65e66cf8677a5b768"
|
||||
integrity sha512-ghW16xx9tRcyL38Pw6G5OidMnYn+CNUGZWmvqQgEO2nRy4T0ONPZZBOvGrIMtJQ70oEykNMKGm0zm6PdHdxd8Q==
|
||||
apollo-graphql@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/apollo-graphql/-/apollo-graphql-0.4.0.tgz#dd0afe31a6241b8e2ded20b906c9ee8dfbe03497"
|
||||
integrity sha512-abCHcKln1EGbzSItW087EjBI5wnluikyUqEn4VsdeWHCtdENWpHCn/MnM0+jJa1prNasxN7tCukp4nMpJYYVqg==
|
||||
dependencies:
|
||||
apollo-env "^0.6.1"
|
||||
lodash.sortby "^4.7.0"
|
||||
@ -1943,18 +1943,18 @@ apollo-server-caching@^0.5.1:
|
||||
dependencies:
|
||||
lru-cache "^5.0.0"
|
||||
|
||||
apollo-server-core@^2.9.16:
|
||||
version "2.9.16"
|
||||
resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.9.16.tgz#b4c869a6babfa6906fbbf1e6facf3b7231dbf777"
|
||||
integrity sha512-4ftdjSfs/3aEare9QNTVSF0yUvXETxiohuDLZ7gmMIQxNnZhUjVXiZL1rYKuIZ12uH7xLvh/DwkXRt6nLG/lZA==
|
||||
apollo-server-core@^2.10.0:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.10.0.tgz#b8d51bdffe6529f0e3ca670ee8f1238765cfade4"
|
||||
integrity sha512-x/UK6XvU307W8D/pzTclU04JIjRarcbg5mFPe0nVmO4OTc26uQgKi1WlZkcewXsAUnn+nDwKVn2c2G3dHEgXzQ==
|
||||
dependencies:
|
||||
"@apollographql/apollo-tools" "^0.4.3"
|
||||
"@apollographql/graphql-playground-html" "1.6.24"
|
||||
"@types/graphql-upload" "^8.0.0"
|
||||
"@types/ws" "^6.0.0"
|
||||
apollo-cache-control "^0.8.11"
|
||||
apollo-datasource "^0.6.4"
|
||||
apollo-engine-reporting "^1.4.14"
|
||||
apollo-datasource "^0.7.0"
|
||||
apollo-engine-reporting "^1.5.0"
|
||||
apollo-server-caching "^0.5.1"
|
||||
apollo-server-env "^2.4.3"
|
||||
apollo-server-errors "^2.3.4"
|
||||
@ -1983,10 +1983,10 @@ apollo-server-errors@^2.3.4:
|
||||
resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-2.3.4.tgz#b70ef01322f616cbcd876f3e0168a1a86b82db34"
|
||||
integrity sha512-Y0PKQvkrb2Kd18d1NPlHdSqmlr8TgqJ7JQcNIfhNDgdb45CnqZlxL1abuIRhr8tiw8OhVOcFxz2KyglBi8TKdA==
|
||||
|
||||
apollo-server-express@^2.9.16:
|
||||
version "2.9.16"
|
||||
resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.9.16.tgz#4c30b1769426c010b37943c0fb7766e5825973a0"
|
||||
integrity sha512-ZDc7GP+piUm67alJ0DIE9f36tHcCiNm3PHMLIVJlVE/rcGwzRjV5rardRqeslljQiO2J+1IwXKwJ0/kRrZ4JvQ==
|
||||
apollo-server-express@^2.10.0, apollo-server-express@^2.9.16:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.10.0.tgz#7d87ff54e378cdcb135eb3d093f20fca7fc0d1bc"
|
||||
integrity sha512-adDQts4QmkX2ENU7JibV1EwRl3ESnpnpImXIMvg8Cm7kX2wSbzwm8LecQNujwWJtkAPTCEAcnPBDyKwWjTQ6/g==
|
||||
dependencies:
|
||||
"@apollographql/graphql-playground-html" "1.6.24"
|
||||
"@types/accepts" "^1.3.5"
|
||||
@ -1994,7 +1994,7 @@ apollo-server-express@^2.9.16:
|
||||
"@types/cors" "^2.8.4"
|
||||
"@types/express" "4.17.2"
|
||||
accepts "^1.3.5"
|
||||
apollo-server-core "^2.9.16"
|
||||
apollo-server-core "^2.10.0"
|
||||
apollo-server-types "^0.2.10"
|
||||
body-parser "^1.18.3"
|
||||
cors "^2.8.4"
|
||||
@ -2012,12 +2012,12 @@ apollo-server-plugin-base@^0.6.10:
|
||||
dependencies:
|
||||
apollo-server-types "^0.2.10"
|
||||
|
||||
apollo-server-testing@~2.9.16:
|
||||
version "2.9.16"
|
||||
resolved "https://registry.yarnpkg.com/apollo-server-testing/-/apollo-server-testing-2.9.16.tgz#35e9b0b102a11bac8db2fce04281cb43e7993d45"
|
||||
integrity sha512-CLfYZY2Htwzw6iPlFO32/SNXNstWQsvGd5/FQ8KEwRpNfYM4g0rAE98y/THEQTvTh0xPH+qWxA7CVQcc7/FMbQ==
|
||||
apollo-server-testing@~2.10.0:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/apollo-server-testing/-/apollo-server-testing-2.10.0.tgz#c8d7fc2d4e6eaf84232aaa7c125d9fae691fbcf4"
|
||||
integrity sha512-wBJ/CT3ZN5nmSySMqgpAFwX/I3yzsQhRGR8MCK/16MjhEZH6svNaJWzoif6gaocj0NyVBJvOIijuMTecG9+6vg==
|
||||
dependencies:
|
||||
apollo-server-core "^2.9.16"
|
||||
apollo-server-core "^2.10.0"
|
||||
|
||||
apollo-server-types@^0.2.10:
|
||||
version "0.2.10"
|
||||
@ -2028,13 +2028,13 @@ apollo-server-types@^0.2.10:
|
||||
apollo-server-caching "^0.5.1"
|
||||
apollo-server-env "^2.4.3"
|
||||
|
||||
apollo-server@~2.9.16:
|
||||
version "2.9.16"
|
||||
resolved "https://registry.yarnpkg.com/apollo-server/-/apollo-server-2.9.16.tgz#c0054ed70ecb637cb3f585ff46fb4a060730076f"
|
||||
integrity sha512-dqB1shkjl9ne7DfSHXDH5sT70llr9zswLL+/g/4zt4/H+k+2pkD1BShQkNIK7PBYcVa8KvRAHXiHTXZ36GCspA==
|
||||
apollo-server@~2.10.0:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/apollo-server/-/apollo-server-2.10.0.tgz#93b924b089f7c4070e88aa29a8b9472c1d5d0f82"
|
||||
integrity sha512-ITXkklSgrNfohFh4juvHWrtLz/82iw9CkBUW+G5T8NxHaqxm1Lpus1Ck2VsXmCgNplYi6mODRjUl087qdlU2Rw==
|
||||
dependencies:
|
||||
apollo-server-core "^2.9.16"
|
||||
apollo-server-express "^2.9.16"
|
||||
apollo-server-core "^2.10.0"
|
||||
apollo-server-express "^2.10.0"
|
||||
express "^4.0.0"
|
||||
graphql-subscriptions "^1.0.0"
|
||||
graphql-tools "^4.0.0"
|
||||
@ -2691,10 +2691,10 @@ chrono-node@~1.3.11:
|
||||
dependencies:
|
||||
moment "2.21.0"
|
||||
|
||||
chrono-node@~1.4.2:
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chrono-node/-/chrono-node-1.4.2.tgz#0c7fc1f264e60a660c2b2dab753a3f285dbfd8c9"
|
||||
integrity sha512-fsb82wPDHVZl3xtche8k4ZZtNwf81/ZMueil2ANpSfogUAEa3BuzZAar7ObLXi1ptMjBzdzA6ys/bFq1oBjO8w==
|
||||
chrono-node@~1.4.3:
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/chrono-node/-/chrono-node-1.4.3.tgz#4c8e24643ec5e576f6f8fe0429370c3b554491b4"
|
||||
integrity sha512-ZyKcnTcr8i7Mt9p4+ixMHEuR6+eMTrjYCL9Rm9TZHviLleCtcZoVzmr2uSc+Vg8MX1YbNCnPbEd4rfV8WvzLcw==
|
||||
dependencies:
|
||||
dayjs "^1.8.19"
|
||||
|
||||
@ -2774,6 +2774,11 @@ clone-response@^1.0.2:
|
||||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
cluster-key-slot@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
|
||||
integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==
|
||||
|
||||
co@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
|
||||
@ -3254,6 +3259,11 @@ delegates@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
||||
|
||||
denque@^1.1.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf"
|
||||
integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==
|
||||
|
||||
depd@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||
@ -3643,13 +3653,12 @@ eslint-plugin-import@~2.20.1:
|
||||
read-pkg-up "^2.0.0"
|
||||
resolve "^1.12.0"
|
||||
|
||||
eslint-plugin-jest@~23.6.0:
|
||||
version "23.6.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.6.0.tgz#508b32f80d44058c8c01257c0ee718cfbd521e9d"
|
||||
integrity sha512-GH8AhcFXspOLqak7fqnddLXEJsrFyvgO8Bm60SexvKSn1+3rWYESnCiWUOCUcBTprNSDSE4CtAZdM4EyV6gPPw==
|
||||
eslint-plugin-jest@~23.7.0:
|
||||
version "23.7.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.7.0.tgz#84d5603b6e745b59898cb6750df6a44782a39b04"
|
||||
integrity sha512-zkiyGlvJeHNjAEz8FaIxTXNblJJ/zj3waNbYbgflK7K6uy0cpE5zJBt/JpJtOBGM/UGkC6BqsQ4n0y7kQ2HA8w==
|
||||
dependencies:
|
||||
"@typescript-eslint/experimental-utils" "^2.5.0"
|
||||
micromatch "^4.0.2"
|
||||
|
||||
eslint-plugin-node@~11.0.0:
|
||||
version "11.0.0"
|
||||
@ -4202,10 +4211,10 @@ fresh@0.5.2:
|
||||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
||||
|
||||
fs-capacitor@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-2.0.4.tgz#5a22e72d40ae5078b4fe64fe4d08c0d3fc88ad3c"
|
||||
integrity sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA==
|
||||
fs-capacitor@6.0.0, fs-capacitor@^2.0.4:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-6.0.0.tgz#b4b89e3281d61df1c573e788d9ee6ec4c7c94da4"
|
||||
integrity sha512-I+jZLV2q+ivQK/+Mu5FIYAECHgjoo8GBYJsBBQbNeU0aW1m25LU4E+MkLNq0kcJBjrp8Z6fhxpSeS8SyJyGkrw==
|
||||
|
||||
fs-minipass@^1.2.5:
|
||||
version "1.2.6"
|
||||
@ -4476,12 +4485,21 @@ graphql-middleware@~4.0.2:
|
||||
dependencies:
|
||||
graphql-tools "^4.0.5"
|
||||
|
||||
graphql-shield@~7.0.9:
|
||||
version "7.0.9"
|
||||
resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-7.0.9.tgz#8248916e9636a7e3c05719a52fd13f2d37ccaeb2"
|
||||
integrity sha512-2Dfddd2hcObCSqAj64c/Aaxvs7gaoD2QU14crj7H486QjS8jIAtEPUyLVyv8SmJ1ZD7jT6wqx6wrB15Npn5Sgw==
|
||||
graphql-redis-subscriptions@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/graphql-redis-subscriptions/-/graphql-redis-subscriptions-2.1.2.tgz#9c1b744bace0c6ba99dd0ebafe0148cad1df3301"
|
||||
integrity sha512-l69KbGxyYfVHxvE+Dzv9/hXg/q+Xnjfx1JsrJD6ikePuSsNaCSNxr+MubSTNF3Gt3C/+JZs4FaWImFeK/+X2og==
|
||||
dependencies:
|
||||
"@types/yup" "0.26.29"
|
||||
iterall "^1.2.2"
|
||||
optionalDependencies:
|
||||
ioredis "^4.6.3"
|
||||
|
||||
graphql-shield@~7.0.11:
|
||||
version "7.0.11"
|
||||
resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-7.0.11.tgz#78d49f346326be71090d35d8f5843da9ee8136e2"
|
||||
integrity sha512-iWn/aiom2c8NuOj60euWTmsKKUjX1DB4ynBcDitQOLXG3WrWgss2Iolzr553qooJvkR5czeAFgPlZgI+nUgwsQ==
|
||||
dependencies:
|
||||
"@types/yup" "0.26.30"
|
||||
object-hash "^2.0.0"
|
||||
yup "^0.28.0"
|
||||
|
||||
@ -4492,10 +4510,10 @@ graphql-subscriptions@^1.0.0:
|
||||
dependencies:
|
||||
iterall "^1.2.1"
|
||||
|
||||
graphql-tag@^2.9.2, graphql-tag@~2.10.1:
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.1.tgz#10aa41f1cd8fae5373eaf11f1f67260a3cad5e02"
|
||||
integrity sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==
|
||||
graphql-tag@^2.9.2, graphql-tag@~2.10.3:
|
||||
version "2.10.3"
|
||||
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.3.tgz#ea1baba5eb8fc6339e4c4cf049dabe522b0edf03"
|
||||
integrity sha512-4FOv3ZKfA4WdOKJeHdz6B3F/vxBLSgmBcGeAFPf4n1F64ltJUvOOerNj0rsJxONQGdhUMynQIvd6LzB+1J5oKA==
|
||||
|
||||
graphql-tools@^4.0.0, graphql-tools@^4.0.4, graphql-tools@^4.0.5:
|
||||
version "4.0.5"
|
||||
@ -4535,7 +4553,7 @@ har-schema@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
|
||||
|
||||
har-validator@~5.1.0:
|
||||
har-validator@~5.1.3:
|
||||
version "5.1.3"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
|
||||
integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
|
||||
@ -4920,6 +4938,21 @@ invariant@^2.2.2, invariant@^2.2.4:
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
ioredis@^4.14.1, ioredis@^4.6.3:
|
||||
version "4.14.1"
|
||||
resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.14.1.tgz#b73ded95fcf220f106d33125a92ef6213aa31318"
|
||||
integrity sha512-94W+X//GHM+1GJvDk6JPc+8qlM7Dul+9K+lg3/aHixPN7ZGkW6qlvX0DG6At9hWtH2v3B32myfZqWoANUJYGJA==
|
||||
dependencies:
|
||||
cluster-key-slot "^1.1.0"
|
||||
debug "^4.1.1"
|
||||
denque "^1.1.0"
|
||||
lodash.defaults "^4.2.0"
|
||||
lodash.flatten "^4.4.0"
|
||||
redis-commands "1.5.0"
|
||||
redis-errors "^1.2.0"
|
||||
redis-parser "^3.0.0"
|
||||
standard-as-callback "^2.0.1"
|
||||
|
||||
ip-regex@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-1.0.3.tgz#dc589076f659f419c222039a33316f1c7387effd"
|
||||
@ -5960,11 +5993,21 @@ lodash.clonedeep@^4.5.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
|
||||
|
||||
lodash.defaults@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
|
||||
integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
|
||||
|
||||
lodash.escaperegexp@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347"
|
||||
integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=
|
||||
|
||||
lodash.flatten@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
|
||||
integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
|
||||
|
||||
lodash.includes@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
|
||||
@ -6154,19 +6197,19 @@ merge2@^1.3.0:
|
||||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81"
|
||||
integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==
|
||||
|
||||
metascraper-audio@^5.10.6:
|
||||
version "5.10.6"
|
||||
resolved "https://registry.yarnpkg.com/metascraper-audio/-/metascraper-audio-5.10.6.tgz#095892445b90d40bc54e54f69536a80e36fd9e4c"
|
||||
integrity sha512-wTVtYK8Ico82caIi6HlkyGgUaBC21X/vhT2aQ4LKcg+gHoOhJcmWNd5me9VhaRJ7gTV/7yKkL5A54fBcjcn8Kg==
|
||||
metascraper-audio@^5.10.7:
|
||||
version "5.10.7"
|
||||
resolved "https://registry.yarnpkg.com/metascraper-audio/-/metascraper-audio-5.10.7.tgz#ba9f8333a7b71d388a0bf88dff64fc4f06595566"
|
||||
integrity sha512-VHZlT21bh/TWnHOQMGret3UcMdJOsyWvagK7MG8rLczYmrPEtvxnJjwPhyrEj1oJC+fz2P//bfQ6gyrD4HrmEQ==
|
||||
dependencies:
|
||||
"@metascraper/helpers" "^5.10.6"
|
||||
"@metascraper/helpers" "^5.10.7"
|
||||
|
||||
metascraper-author@^5.10.6:
|
||||
version "5.10.6"
|
||||
resolved "https://registry.yarnpkg.com/metascraper-author/-/metascraper-author-5.10.6.tgz#1ceaacec776d46629300db25e17657fe35a14a20"
|
||||
integrity sha512-L2P/Fp0npaQcowbwi1vHKJbSYc99cio58/yYRm205xGfgMCRMpYOrYB+ecizXgeSSRiv8G8SXLrLXOLJ5K+SdA==
|
||||
metascraper-author@^5.10.7:
|
||||
version "5.10.7"
|
||||
resolved "https://registry.yarnpkg.com/metascraper-author/-/metascraper-author-5.10.7.tgz#99b3a2b982b7a63feea41554659be3db7bf7035c"
|
||||
integrity sha512-AdNkcqy+eqs2Eeh+6odhIWArR4pWVlrCx3jMaho0BDY6ZnKgJP44HtlPNkghQpBaueoKX6CycGKraITzwjGj1w==
|
||||
dependencies:
|
||||
"@metascraper/helpers" "^5.10.6"
|
||||
"@metascraper/helpers" "^5.10.7"
|
||||
lodash "~4.17.15"
|
||||
|
||||
metascraper-clearbit-logo@^5.3.0:
|
||||
@ -6190,12 +6233,12 @@ metascraper-description@^5.11.0:
|
||||
dependencies:
|
||||
"@metascraper/helpers" "^5.10.7"
|
||||
|
||||
metascraper-image@^5.10.7:
|
||||
version "5.10.7"
|
||||
resolved "https://registry.yarnpkg.com/metascraper-image/-/metascraper-image-5.10.7.tgz#9b1da02f2e748fd388dea6394d29b6e43c367924"
|
||||
integrity sha512-xrR4Rl8UNwwyzMfrKH3RtaC775aHDXVT0TQEzn5p5uYfd4evLI2O+jr1CIBIl1d3CXqVxWCQWBY3gA7RtcjgWQ==
|
||||
metascraper-image@^5.11.1:
|
||||
version "5.11.1"
|
||||
resolved "https://registry.yarnpkg.com/metascraper-image/-/metascraper-image-5.11.1.tgz#e63e9ff045441783f9aa8c684e04927cac289e44"
|
||||
integrity sha512-Nz2ZTecj2V0KgK2QE390dOSedppaG2PtUBrTz/oaFLMZEReBtMVrcygYm9VuuTpa6XwkubvuBaouCRah12zdfg==
|
||||
dependencies:
|
||||
"@metascraper/helpers" "^5.10.7"
|
||||
"@metascraper/helpers" "^5.11.1"
|
||||
|
||||
metascraper-lang-detector@^4.10.2:
|
||||
version "4.10.2"
|
||||
@ -6235,20 +6278,20 @@ metascraper-soundcloud@^5.10.7:
|
||||
"@metascraper/helpers" "^5.10.7"
|
||||
tldts "~5.6.3"
|
||||
|
||||
metascraper-title@^5.10.6:
|
||||
version "5.10.6"
|
||||
resolved "https://registry.yarnpkg.com/metascraper-title/-/metascraper-title-5.10.6.tgz#0fd9a9bed7a0b990663086cdab45d11cd8cd3c7d"
|
||||
integrity sha512-x4P8zr0x6Gh3gt26tf2xfjikG9xNS9MC3z4N2VP+OrYNuCc7Vz6TU+DR/DLAeZphsb1flgTd3P4iUfPUcWVTEQ==
|
||||
metascraper-title@^5.10.7:
|
||||
version "5.10.7"
|
||||
resolved "https://registry.yarnpkg.com/metascraper-title/-/metascraper-title-5.10.7.tgz#037aaa8cbdc79d1dde186887eb2bba542281315e"
|
||||
integrity sha512-iQYaMdGpBPj6dyk7rbP+zYo7EroC/1yY27jocAqUnMRTfrHXTR7kGucR0vi4y14BiFRLBTLSNbZbM4KAUQsFjg==
|
||||
dependencies:
|
||||
"@metascraper/helpers" "^5.10.6"
|
||||
"@metascraper/helpers" "^5.10.7"
|
||||
lodash "~4.17.15"
|
||||
|
||||
metascraper-url@^5.10.6:
|
||||
version "5.10.6"
|
||||
resolved "https://registry.yarnpkg.com/metascraper-url/-/metascraper-url-5.10.6.tgz#45f0ea173fecfe56d60b3cddd3c018f9f4fd9b92"
|
||||
integrity sha512-7F6uAsI27iVXxUMwwzXH0ret81CX1jgtoGCMz+TvZkyS0z4aUs0r8QpYRYEQuXrW+JawRVik0up54F/ScslObQ==
|
||||
metascraper-url@^5.10.7:
|
||||
version "5.10.7"
|
||||
resolved "https://registry.yarnpkg.com/metascraper-url/-/metascraper-url-5.10.7.tgz#42b71c8540c13baafb7757972ea672721d63e019"
|
||||
integrity sha512-z1LBPTupU5cF36/i/iGe0rzLbO7iGBSdbgEOztLcnIhnMC8Nl9xjvIrlvNciKTMxDyr3JGrvFFWugFzwMzVoQg==
|
||||
dependencies:
|
||||
"@metascraper/helpers" "^5.10.6"
|
||||
"@metascraper/helpers" "^5.10.7"
|
||||
|
||||
metascraper-video@^5.10.7:
|
||||
version "5.10.7"
|
||||
@ -6325,24 +6368,12 @@ migrate@^1.6.2:
|
||||
mkdirp "^0.5.1"
|
||||
slug "^0.9.2"
|
||||
|
||||
mime-db@1.40.0:
|
||||
version "1.40.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
|
||||
integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
|
||||
|
||||
mime-db@1.43.0:
|
||||
version "1.43.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
|
||||
integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
|
||||
|
||||
mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.22, mime-types@~2.1.24:
|
||||
version "2.1.24"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
|
||||
integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
|
||||
dependencies:
|
||||
mime-db "1.40.0"
|
||||
|
||||
mime-types@~2.1.26:
|
||||
mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.22, mime-types@~2.1.24, mime-types@~2.1.26:
|
||||
version "2.1.26"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
|
||||
integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
|
||||
@ -7328,7 +7359,7 @@ pseudomap@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
|
||||
|
||||
psl@^1.1.24, psl@^1.1.28:
|
||||
psl@^1.1.28:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.3.0.tgz#e1ebf6a3b5564fa8376f3da2275da76d875ca1bd"
|
||||
integrity sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag==
|
||||
@ -7351,11 +7382,6 @@ punycode2@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/punycode2/-/punycode2-1.0.0.tgz#e2b4b9a9a8ff157d0b84438e203181ee7892dfd8"
|
||||
integrity sha1-4rS5qaj/FX0LhEOOIDGB7niS39g=
|
||||
|
||||
punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
|
||||
|
||||
punycode@^2.1.0, punycode@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
@ -7506,6 +7532,23 @@ realpath-native@^1.1.0:
|
||||
dependencies:
|
||||
util.promisify "^1.0.0"
|
||||
|
||||
redis-commands@1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.5.0.tgz#80d2e20698fe688f227127ff9e5164a7dd17e785"
|
||||
integrity sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg==
|
||||
|
||||
redis-errors@^1.0.0, redis-errors@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad"
|
||||
integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=
|
||||
|
||||
redis-parser@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4"
|
||||
integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=
|
||||
dependencies:
|
||||
redis-errors "^1.0.0"
|
||||
|
||||
referrer-policy@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.2.0.tgz#b99cfb8b57090dc454895ef897a4cc35ef67a98e"
|
||||
@ -7628,10 +7671,10 @@ request-promise-native@^1.0.7, request-promise-native@^1.0.8:
|
||||
stealthy-require "^1.1.1"
|
||||
tough-cookie "^2.3.3"
|
||||
|
||||
request@^2.88.0, request@~2.88.0:
|
||||
version "2.88.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
|
||||
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
|
||||
request@^2.88.0, request@~2.88.2:
|
||||
version "2.88.2"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
@ -7640,7 +7683,7 @@ request@^2.88.0, request@~2.88.0:
|
||||
extend "~3.0.2"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.2"
|
||||
har-validator "~5.1.0"
|
||||
har-validator "~5.1.3"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
@ -7650,7 +7693,7 @@ request@^2.88.0, request@~2.88.0:
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "~2.4.3"
|
||||
tough-cookie "~2.5.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
@ -7754,6 +7797,11 @@ rimraf@^3.0.0:
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
rosie@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/rosie/-/rosie-2.0.1.tgz#c250c4787ce450b72aa9eff26509f68589814fa2"
|
||||
integrity sha1-wlDEeHzkULcqqe/yZQn2hYmBT6I=
|
||||
|
||||
router-ips@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/router-ips/-/router-ips-1.0.0.tgz#44e00858ebebc0133d58e40b2cd8a1fbb04203f5"
|
||||
@ -7918,6 +7966,11 @@ serve-static@1.14.1:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
|
||||
integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
|
||||
dependencies:
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
parseurl "~1.3.3"
|
||||
send "0.17.1"
|
||||
|
||||
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
||||
version "2.0.0"
|
||||
@ -8203,6 +8256,11 @@ stacktrace-js@^2.0.0:
|
||||
stack-generator "^2.0.1"
|
||||
stacktrace-gps "^3.0.1"
|
||||
|
||||
standard-as-callback@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.0.1.tgz#ed8bb25648e15831759b6023bdb87e6b60b38126"
|
||||
integrity sha512-NQOxSeB8gOI5WjSaxjBgog2QFw55FV8TkS6Y07BiB3VJ8xNTvUYm0wl0s8ObgQ5NhdpnNfigMIKjgPESzgr4tg==
|
||||
|
||||
static-extend@^0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
|
||||
@ -8668,7 +8726,7 @@ touch@^3.1.0:
|
||||
dependencies:
|
||||
nopt "~1.0.10"
|
||||
|
||||
tough-cookie@^2.3.3:
|
||||
tough-cookie@^2.3.3, tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
||||
@ -8685,14 +8743,6 @@ tough-cookie@^3.0.1:
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tough-cookie@~2.4.3:
|
||||
version "2.4.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
|
||||
integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
|
||||
dependencies:
|
||||
psl "^1.1.24"
|
||||
punycode "^1.4.1"
|
||||
|
||||
tr46@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
|
||||
|
||||
BIN
cypress/fixtures/humanconnection.png
Normal file
BIN
cypress/fixtures/humanconnection.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
@ -14,9 +14,8 @@ Feature: Tags and Categories
|
||||
looking at the popularity of a tag.
|
||||
|
||||
Background:
|
||||
Given my user account has the role "admin"
|
||||
Given I am logged in with a "admin" role
|
||||
And we have a selection of tags and categories as well as posts
|
||||
And I am logged in
|
||||
|
||||
Scenario: See an overview of categories
|
||||
When I navigate to the administration dashboard
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import { When, Then } from "cypress-cucumber-preprocessor/steps";
|
||||
import locales from '../../../webapp/locales'
|
||||
import orderBy from 'lodash/orderBy'
|
||||
|
||||
const languages = orderBy(locales, 'name')
|
||||
const narratorAvatar =
|
||||
"https://s3.amazonaws.com/uifaces/faces/twitter/nerrsoft/128.jpg";
|
||||
|
||||
@ -83,3 +86,82 @@ And("the post with title {string} has a ribbon for pinned posts", (title) => {
|
||||
Then("I see a toaster with {string}", (title) => {
|
||||
cy.get(".iziToast-message").should("contain", title);
|
||||
})
|
||||
|
||||
Then("I should be able to {string} a teaser image", condition => {
|
||||
cy.reload()
|
||||
const teaserImageUpload = (condition === 'change') ? "humanconnection.png" : "onourjourney.png";
|
||||
cy.fixture(teaserImageUpload).as('postTeaserImage').then(function() {
|
||||
cy.get("#postdropzone").upload(
|
||||
{ fileContent: this.postTeaserImage, fileName: teaserImageUpload, mimeType: "image/png" },
|
||||
{ subjectType: "drag-n-drop", force: true }
|
||||
);
|
||||
})
|
||||
})
|
||||
|
||||
Then('confirm crop', () => {
|
||||
cy.get('.crop-confirm')
|
||||
.click()
|
||||
})
|
||||
|
||||
Then("I add all required fields", () => {
|
||||
cy.get('input[name="title"]')
|
||||
.type('new post')
|
||||
.get(".editor .ProseMirror")
|
||||
.type('new post content')
|
||||
.get(".categories-select .base-button")
|
||||
.first()
|
||||
.click()
|
||||
.get('.ds-flex-item > .ds-form-item .ds-select ')
|
||||
.click()
|
||||
.get('.ds-select-option')
|
||||
.eq(languages.findIndex(l => l.code === 'en'))
|
||||
.click()
|
||||
})
|
||||
|
||||
Then("the post was saved successfully with the {string} teaser image", condition => {
|
||||
cy.get(".ds-card-content > .ds-heading")
|
||||
.should("contain", condition === 'updated' ? 'to be updated' : 'new post')
|
||||
.get(".content")
|
||||
.should("contain", condition === 'updated' ? 'successfully updated' : 'new post content')
|
||||
.get('.post-page img')
|
||||
.should("have.attr", "src")
|
||||
.and("contains", condition === 'updated' ? 'humanconnection' : 'onourjourney')
|
||||
})
|
||||
|
||||
Then("the first image should be removed from the preview", () => {
|
||||
cy.fixture("humanconnection.png").as('postTeaserImage').then(function() {
|
||||
cy.get("#postdropzone")
|
||||
.children()
|
||||
.get('img.thumbnail-preview')
|
||||
.should('have.length', 1)
|
||||
.and('have.attr', 'src')
|
||||
.and('contain', this.postTeaserImage)
|
||||
})
|
||||
})
|
||||
|
||||
Then('the {string} post was saved successfully without a teaser image', condition => {
|
||||
cy.get(".ds-card-content > .ds-heading")
|
||||
.should("contain", condition === 'updated' ? 'to be updated' : 'new post')
|
||||
.get(".content")
|
||||
.should("contain", condition === 'updated' ? 'successfully updated' : 'new post content')
|
||||
.get('.post-page')
|
||||
.should('exist')
|
||||
.get('.post-page img.ds-card-image')
|
||||
.should('not.exist')
|
||||
})
|
||||
|
||||
Then('I should be able to remove it', () => {
|
||||
cy.get('.crop-cancel')
|
||||
.click()
|
||||
})
|
||||
|
||||
When('my post has a teaser image', () => {
|
||||
cy.get('.contribution-image')
|
||||
.should('exist')
|
||||
.and('have.attr', 'src')
|
||||
})
|
||||
|
||||
Then('I should be able to remove the image', () => {
|
||||
cy.get('.delete-image')
|
||||
.click()
|
||||
})
|
||||
@ -30,16 +30,24 @@ Given("I see David Irving's post on the post page", page => {
|
||||
})
|
||||
|
||||
Given('I am logged in with a {string} role', role => {
|
||||
cy.factory().create('User', {
|
||||
cy.factory().build('user', {
|
||||
termsAndConditionsAgreedVersion: VERSION,
|
||||
role,
|
||||
name: `${role} is my name`
|
||||
}, {
|
||||
email: `${role}@example.org`,
|
||||
password: '1234',
|
||||
termsAndConditionsAgreedVersion: VERSION,
|
||||
role
|
||||
})
|
||||
cy.login({
|
||||
email: `${role}@example.org`,
|
||||
password: '1234'
|
||||
})
|
||||
cy.neode()
|
||||
.first("User", {
|
||||
name: `${role} is my name`,
|
||||
})
|
||||
.then(user => {
|
||||
return new Cypress.Promise((resolve, reject) => {
|
||||
return user.toJson().then((user) => resolve(user))
|
||||
})
|
||||
})
|
||||
.then(user => cy.login(user))
|
||||
})
|
||||
|
||||
When('I click on "Report Post" from the content menu of the post', () => {
|
||||
@ -127,7 +135,7 @@ Given('somebody reported the following posts:', table => {
|
||||
password: '1234'
|
||||
}
|
||||
cy.factory()
|
||||
.create('User', submitter)
|
||||
.build('user', {}, submitter)
|
||||
.authenticateAs(submitter)
|
||||
.mutate(gql`mutation($resourceId: ID!, $reasonCategory: ReasonCategory!, $reasonDescription: String!) {
|
||||
fileReport(resourceId: $resourceId, reasonCategory: $reasonCategory, reasonDescription: $reasonDescription) {
|
||||
@ -166,8 +174,9 @@ Then('I can visit the post page', () => {
|
||||
|
||||
When("they have a post someone has reported", () => {
|
||||
cy.factory()
|
||||
.create("Post", {
|
||||
authorId: 'annnoying-user',
|
||||
.build("post", {
|
||||
title,
|
||||
}, {
|
||||
authorId: 'annnoying-user',
|
||||
});
|
||||
})
|
||||
|
||||
@ -25,7 +25,6 @@ const narratorParams = {
|
||||
name: "Peter Pan",
|
||||
slug: "peter-pan",
|
||||
avatar: "https://s3.amazonaws.com/uifaces/faces/twitter/nerrsoft/128.jpg",
|
||||
...loginCredentials,
|
||||
...termsAndConditionsAgreedVersion,
|
||||
};
|
||||
|
||||
@ -33,65 +32,82 @@ const annoyingParams = {
|
||||
email: "spammy-spammer@example.org",
|
||||
slug: 'spammy-spammer',
|
||||
password: "1234",
|
||||
...termsAndConditionsAgreedVersion
|
||||
};
|
||||
|
||||
Given("I am logged in", () => {
|
||||
cy.login(loginCredentials);
|
||||
cy.neode()
|
||||
.first("User", {
|
||||
name: narratorParams.name
|
||||
})
|
||||
.then(user => {
|
||||
return new Cypress.Promise((resolve, reject) => {
|
||||
return user.toJson().then((user) => resolve(user))
|
||||
})
|
||||
})
|
||||
.then(user => cy.login(user))
|
||||
});
|
||||
|
||||
Given("I log in as {string}", name => {
|
||||
cy.logout()
|
||||
cy.neode()
|
||||
.first("User", {
|
||||
name
|
||||
})
|
||||
.then(user => {
|
||||
return new Cypress.Promise((resolve, reject) => {
|
||||
return user.toJson().then((user) => resolve(user))
|
||||
})
|
||||
})
|
||||
.then(user => cy.login(user))
|
||||
})
|
||||
|
||||
Given("the {string} user searches for {string}", (_, postTitle) => {
|
||||
cy.logout()
|
||||
.login({ email: annoyingParams.email, password: '1234' })
|
||||
.get(".searchable-input .ds-select-search")
|
||||
cy.neode()
|
||||
.first("User", {
|
||||
id: "annoying-user"
|
||||
})
|
||||
.then(user => {
|
||||
return new Cypress.Promise((resolve, reject) => {
|
||||
return user.toJson().then((user) => resolve(user))
|
||||
})
|
||||
})
|
||||
.then(user => cy.login(user))
|
||||
cy.get(".searchable-input .ds-select-search")
|
||||
.focus()
|
||||
.type(postTitle);
|
||||
});
|
||||
|
||||
Given("we have a selection of categories", () => {
|
||||
cy.createCategories("cat0", "just-for-fun");
|
||||
cy.factory().build('category', { id: "cat0", slug: "just-for-fun" });
|
||||
});
|
||||
|
||||
Given("we have a selection of tags and categories as well as posts", () => {
|
||||
cy.createCategories("cat12")
|
||||
.factory()
|
||||
.create("Tag", {
|
||||
id: "Ecology"
|
||||
})
|
||||
.create("Tag", {
|
||||
id: "Nature"
|
||||
})
|
||||
.create("Tag", {
|
||||
id: "Democracy"
|
||||
});
|
||||
|
||||
cy.factory()
|
||||
.create("User", {
|
||||
id: 'a1'
|
||||
})
|
||||
.create("Post", {
|
||||
.build('category', { id: 'cat12', name: "Just For Fun", icon: "smile", })
|
||||
.build('category', { id: 'cat121', name: "Happiness & Values", icon: "heart-o"})
|
||||
.build('category', { id: 'cat122', name: "Health & Wellbeing", icon: "medkit"})
|
||||
.build("tag", { id: "Ecology" })
|
||||
.build("tag", { id: "Nature" })
|
||||
.build("tag", { id: "Democracy" })
|
||||
.build("user", { id: 'a1' })
|
||||
.build("post", {}, {
|
||||
authorId: 'a1',
|
||||
tagIds: ["Ecology", "Nature", "Democracy"],
|
||||
categoryIds: ["cat12"]
|
||||
})
|
||||
.create("Post", {
|
||||
.build("post", {}, {
|
||||
authorId: 'a1',
|
||||
tagIds: ["Nature", "Democracy"],
|
||||
categoryIds: ["cat121"]
|
||||
});
|
||||
|
||||
cy.factory()
|
||||
.create("User", {
|
||||
id: 'a2'
|
||||
})
|
||||
.create("Post", {
|
||||
.build("user", { id: 'a2' })
|
||||
.build("post", {}, {
|
||||
authorId: 'a2',
|
||||
tagIds: ['Nature', 'Democracy'],
|
||||
categoryIds: ["cat12"]
|
||||
});
|
||||
cy.factory()
|
||||
.create("Post", {
|
||||
authorId: narratorParams.id,
|
||||
})
|
||||
.build("post", {}, {
|
||||
tagIds: ['Democracy'],
|
||||
categoryIds: ["cat122"]
|
||||
})
|
||||
@ -99,23 +115,22 @@ Given("we have a selection of tags and categories as well as posts", () => {
|
||||
|
||||
Given("we have the following user accounts:", table => {
|
||||
table.hashes().forEach(params => {
|
||||
cy.factory().create("User", {
|
||||
cy.factory().build("user", {
|
||||
...params,
|
||||
...termsAndConditionsAgreedVersion
|
||||
});
|
||||
}, params);
|
||||
});
|
||||
});
|
||||
|
||||
Given("I have a user account", () => {
|
||||
cy.factory().create("User", narratorParams);
|
||||
cy.factory().build("user", narratorParams, loginCredentials);
|
||||
});
|
||||
|
||||
Given("my user account has the role {string}", role => {
|
||||
cy.factory().create("User", {
|
||||
cy.factory().build("user", {
|
||||
role,
|
||||
...loginCredentials,
|
||||
...termsAndConditionsAgreedVersion,
|
||||
});
|
||||
}, loginCredentials);
|
||||
});
|
||||
|
||||
When("I log out", cy.logout);
|
||||
@ -130,8 +145,17 @@ When("I visit the {string} page", page => {
|
||||
|
||||
When("a blocked user visits the post page of one of my authored posts", () => {
|
||||
cy.logout()
|
||||
.login({ email: annoyingParams.email, password: annoyingParams.password })
|
||||
.openPage('/post/previously-created-post')
|
||||
cy.neode()
|
||||
.first("User", {
|
||||
name: 'Harassing User'
|
||||
})
|
||||
.then(user => {
|
||||
return new Cypress.Promise((resolve, reject) => {
|
||||
return user.toJson().then((user) => resolve(user))
|
||||
})
|
||||
})
|
||||
.then(user => cy.login(user))
|
||||
cy.openPage('post/previously-created-post')
|
||||
})
|
||||
|
||||
Given("I am on the {string} page", page => {
|
||||
@ -139,7 +163,7 @@ Given("I am on the {string} page", page => {
|
||||
});
|
||||
|
||||
When("I fill in my email and password combination and click submit", () => {
|
||||
cy.login(loginCredentials);
|
||||
cy.manualLogin(loginCredentials);
|
||||
});
|
||||
|
||||
When(/(?:when )?I refresh the page/, () => {
|
||||
@ -203,33 +227,29 @@ When("I press {string}", label => {
|
||||
cy.contains(label).click();
|
||||
});
|
||||
|
||||
Given("we have this user in our database:", table => {
|
||||
const [firstRow] = table.hashes()
|
||||
cy.factory().create('User', firstRow)
|
||||
})
|
||||
|
||||
Given("we have the following posts in our database:", table => {
|
||||
cy.factory().create('Category', {
|
||||
id: `cat-456`,
|
||||
name: "Just For Fun",
|
||||
slug: `just-for-fun`,
|
||||
icon: "smile"
|
||||
})
|
||||
|
||||
table.hashes().forEach(({
|
||||
...postAttributes
|
||||
}, i) => {
|
||||
postAttributes = {
|
||||
...postAttributes,
|
||||
deleted: Boolean(postAttributes.deleted),
|
||||
disabled: Boolean(postAttributes.disabled),
|
||||
pinned: Boolean(postAttributes.pinned),
|
||||
categoryIds: ['cat-456']
|
||||
}
|
||||
cy.factory().create("Post", postAttributes);
|
||||
Given("we have the following comments in our database:", table => {
|
||||
table.hashes().forEach((attributesOrOptions, i) => {
|
||||
cy.factory().build("comment", {
|
||||
...attributesOrOptions,
|
||||
}, {
|
||||
...attributesOrOptions,
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
Given("we have the following posts in our database:", table => {
|
||||
table.hashes().forEach((attributesOrOptions, i) => {
|
||||
cy.factory().build("post", {
|
||||
...attributesOrOptions,
|
||||
deleted: Boolean(attributesOrOptions.deleted),
|
||||
disabled: Boolean(attributesOrOptions.disabled),
|
||||
pinned: Boolean(attributesOrOptions.pinned),
|
||||
}, {
|
||||
...attributesOrOptions,
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
Then("I see a success message:", message => {
|
||||
cy.contains(message);
|
||||
});
|
||||
@ -242,15 +262,20 @@ When(
|
||||
"I click on the big plus icon in the bottom right corner to create post",
|
||||
() => {
|
||||
cy.get(".post-add-button").click();
|
||||
cy.location("pathname").should('eq', '/post/create')
|
||||
}
|
||||
);
|
||||
|
||||
Given("I previously created a post", () => {
|
||||
lastPost.authorId = narratorParams.id
|
||||
lastPost.title = "previously created post";
|
||||
lastPost.content = "with some content";
|
||||
lastPost = {
|
||||
lastPost,
|
||||
title: "previously created post",
|
||||
content: "with some content",
|
||||
};
|
||||
cy.factory()
|
||||
.create("Post", lastPost);
|
||||
.build("post", lastPost, {
|
||||
authorId: narratorParams.id
|
||||
});
|
||||
});
|
||||
|
||||
When("I choose {string} as the title of the post", title => {
|
||||
@ -311,17 +336,27 @@ Then(
|
||||
cy.visit(route, {
|
||||
failOnStatusCode: false
|
||||
});
|
||||
cy.get(".error").should("contain", message);
|
||||
cy.get(".error-message").should("contain", message);
|
||||
}
|
||||
);
|
||||
|
||||
Given("my user account has the following login credentials:", table => {
|
||||
Given("I am logged in with these credentials:", table => {
|
||||
loginCredentials = table.hashes()[0];
|
||||
cy.debug();
|
||||
cy.factory().create("User", {
|
||||
cy.factory().build("user", {
|
||||
...termsAndConditionsAgreedVersion,
|
||||
...loginCredentials
|
||||
});
|
||||
name: loginCredentials.email,
|
||||
}, loginCredentials);
|
||||
cy.neode()
|
||||
.first("User", {
|
||||
name: loginCredentials.email,
|
||||
})
|
||||
.then(user => {
|
||||
return new Cypress.Promise((resolve, reject) => {
|
||||
return user.toJson().then((user) => resolve(user))
|
||||
})
|
||||
})
|
||||
.then(user => cy.login(user))
|
||||
});
|
||||
|
||||
When("I fill the password form with:", table => {
|
||||
@ -340,45 +375,16 @@ When("submit the form", () => {
|
||||
|
||||
Then("I cannot login anymore with password {string}", password => {
|
||||
cy.reload();
|
||||
const {
|
||||
email
|
||||
} = loginCredentials;
|
||||
cy.visit(`/login`);
|
||||
cy.get("input[name=email]")
|
||||
.trigger("focus")
|
||||
.type(email);
|
||||
cy.get("input[name=password]")
|
||||
.trigger("focus")
|
||||
.type(password);
|
||||
cy.get("button[name=submit]")
|
||||
.as("submitButton")
|
||||
.click();
|
||||
cy.get(".iziToast-wrapper").should(
|
||||
"contain",
|
||||
"Incorrect email address or password."
|
||||
);
|
||||
const { email } = loginCredentials
|
||||
cy.manualLogin({ email, password })
|
||||
.get(".iziToast-wrapper").should("contain", "Incorrect email address or password.");
|
||||
});
|
||||
|
||||
Then("I can login successfully with password {string}", password => {
|
||||
cy.reload();
|
||||
cy.login({
|
||||
...loginCredentials,
|
||||
...{
|
||||
password
|
||||
}
|
||||
});
|
||||
cy.get(".iziToast-wrapper").should("contain", "You are logged in!");
|
||||
});
|
||||
|
||||
When("I log in with the following credentials:", table => {
|
||||
const {
|
||||
email,
|
||||
password
|
||||
} = table.hashes()[0];
|
||||
cy.login({
|
||||
email,
|
||||
password
|
||||
});
|
||||
const { email } = loginCredentials
|
||||
cy.manualLogin({ email, password })
|
||||
.get(".iziToast-wrapper").should("contain", "You are logged in!");
|
||||
});
|
||||
|
||||
When("open the notification menu and click on the first item", () => {
|
||||
@ -428,12 +434,11 @@ Then("there are no notifications in the top menu", () => {
|
||||
});
|
||||
|
||||
Given("there is an annoying user called {string}", name => {
|
||||
cy.factory().create("User", {
|
||||
...annoyingParams,
|
||||
cy.factory().build("user", {
|
||||
id: "annoying-user",
|
||||
name,
|
||||
...termsAndConditionsAgreedVersion,
|
||||
});
|
||||
}, annoyingParams);
|
||||
});
|
||||
|
||||
Given("there is an annoying user who has muted me", () => {
|
||||
@ -451,15 +456,15 @@ Given("there is an annoying user who has muted me", () => {
|
||||
});
|
||||
|
||||
Given("I am on the profile page of the annoying user", name => {
|
||||
cy.openPage("/profile/annoying-user/spammy-spammer");
|
||||
cy.openPage("profile/annoying-user/spammy-spammer");
|
||||
});
|
||||
|
||||
When("I visit the profile page of the annoying user", name => {
|
||||
cy.openPage("/profile/annoying-user");
|
||||
cy.openPage("profile/annoying-user");
|
||||
});
|
||||
|
||||
When("I ", name => {
|
||||
cy.openPage("/profile/annoying-user");
|
||||
cy.openPage("profile/annoying-user");
|
||||
});
|
||||
|
||||
When(
|
||||
@ -498,12 +503,11 @@ Given("I follow the user {string}", name => {
|
||||
});
|
||||
|
||||
Given('{string} wrote a post {string}', (_, title) => {
|
||||
cy.createCategories("cat21")
|
||||
.factory()
|
||||
.create("Post", {
|
||||
authorId: 'annoying-user',
|
||||
cy.factory()
|
||||
.build("post", {
|
||||
title,
|
||||
categoryIds: ["cat21"]
|
||||
}, {
|
||||
authorId: 'annoying-user',
|
||||
});
|
||||
});
|
||||
|
||||
@ -521,12 +525,11 @@ Then("I get removed from his follower collection", () => {
|
||||
});
|
||||
|
||||
Given("I wrote a post {string}", title => {
|
||||
cy.createCategories(`cat213`, title)
|
||||
.factory()
|
||||
.create("Post", {
|
||||
authorId: narratorParams.id,
|
||||
cy.factory()
|
||||
.build("post", {
|
||||
title,
|
||||
categoryIds: ["cat213"]
|
||||
}, {
|
||||
authorId: narratorParams.id,
|
||||
});
|
||||
});
|
||||
|
||||
@ -552,22 +555,24 @@ When("I block the user {string}", name => {
|
||||
.then(blockedUser => {
|
||||
cy.neode()
|
||||
.first("User", {
|
||||
name: narratorParams.name
|
||||
id: narratorParams.id
|
||||
})
|
||||
.relateTo(blockedUser, "blocked");
|
||||
});
|
||||
});
|
||||
|
||||
When("I log in with:", table => {
|
||||
const [firstRow] = table.hashes();
|
||||
const {
|
||||
Email,
|
||||
Password
|
||||
} = firstRow;
|
||||
cy.login({
|
||||
email: Email,
|
||||
password: Password
|
||||
});
|
||||
When("a user has blocked me", () => {
|
||||
cy.neode()
|
||||
.first("User", {
|
||||
name: narratorParams.name
|
||||
})
|
||||
.then(blockedUser => {
|
||||
cy.neode()
|
||||
.first("User", {
|
||||
name: 'Harassing User'
|
||||
})
|
||||
.relateTo(blockedUser, "blocked");
|
||||
});
|
||||
});
|
||||
|
||||
Then("I see only one post with the title {string}", title => {
|
||||
@ -577,10 +582,31 @@ Then("I see only one post with the title {string}", title => {
|
||||
cy.get(".main-container").contains(".post-link", title);
|
||||
});
|
||||
|
||||
Then("they should not see the comment from", () => {
|
||||
Then("they should not see the comment form", () => {
|
||||
cy.get(".ds-card-footer").children().should('not.have.class', 'comment-form')
|
||||
})
|
||||
|
||||
Then("they should see a text explaining commenting is not possible", () => {
|
||||
Then("they should see a text explaining why commenting is not possible", () => {
|
||||
cy.get('.ds-placeholder').should('contain', "Commenting is not possible at this time on this post.")
|
||||
})
|
||||
})
|
||||
|
||||
Then("I should see no users in my blocked users list", () => {
|
||||
cy.get('.ds-placeholder')
|
||||
.should('contain', "So far, you have not blocked anybody.")
|
||||
})
|
||||
|
||||
Then("I {string} see {string} from the content menu in the user info box", (condition, link) => {
|
||||
cy.get(".user-content-menu .base-button").click()
|
||||
cy.get(".popover .ds-menu-item-link")
|
||||
.should(condition === 'should' ? 'contain' : 'not.contain', link)
|
||||
})
|
||||
|
||||
Then('I should not see {string} button', button => {
|
||||
cy.get('.ds-card-content .action-buttons')
|
||||
.should('have.length', 1)
|
||||
})
|
||||
|
||||
Then('I should see the {string} button', button => {
|
||||
cy.get('.ds-card-content .action-buttons .base-button')
|
||||
.should('contain', button)
|
||||
})
|
||||
|
||||
@ -62,9 +62,8 @@ Feature: Report and Moderate
|
||||
Given somebody reported the following posts:
|
||||
| submitterEmail | resourceId | reasonCategory | reasonDescription |
|
||||
| p2.submitter@example.org | p2 | other | Offensive content |
|
||||
And my user account has the role "moderator"
|
||||
And I am logged in with a "moderator" role
|
||||
And there is an annoying user who has muted me
|
||||
And I am logged in
|
||||
When I click on the avatar menu in the top right corner
|
||||
And I click on "Moderation"
|
||||
Then I see all the reported posts including from the user who muted me
|
||||
|
||||
@ -11,9 +11,7 @@ Feature: Notification for a mention
|
||||
| Matt Rider | matt-rider | matt@example.org | 4321 |
|
||||
|
||||
Scenario: Mention another user, re-login as this user and see notifications
|
||||
Given I log in with the following credentials:
|
||||
| email | password |
|
||||
| wolle@example.org | 1234 |
|
||||
Given I log in as "Wolle aus Hamburg"
|
||||
And I start to write a new post with the title "Hey Matt" beginning with:
|
||||
"""
|
||||
Big shout to our fellow contributor
|
||||
@ -23,9 +21,7 @@ Feature: Notification for a mention
|
||||
And I choose "en" as the language for the post
|
||||
And I click on "Save"
|
||||
When I log out
|
||||
And I log in with the following credentials:
|
||||
| email | password |
|
||||
| matt@example.org | 4321 |
|
||||
And I log in as "Matt Rider"
|
||||
And see 1 unread notifications in the top menu
|
||||
And open the notification menu and click on the first item
|
||||
Then I get to the post page of ".../hey-matt"
|
||||
|
||||
@ -6,8 +6,11 @@ Feature: Post Comment
|
||||
Background:
|
||||
Given I have a user account
|
||||
And we have the following posts in our database:
|
||||
| id | title | slug | authorId | commentContent |
|
||||
| bWBjpkTKZp | 101 Essays that will change the way you think | 101-essays | id-of-peter-pan | @peter-pan reply to me |
|
||||
| id | title | slug | authorId |
|
||||
| bWBjpkTKZp | 101 Essays that will change the way you think | 101-essays | id-of-peter-pan |
|
||||
And we have the following comments in our database:
|
||||
| postId | content | authorId |
|
||||
| bWBjpkTKZp | @peter-pan reply to me | id-of-peter-pan |
|
||||
And I am logged in
|
||||
|
||||
Scenario: Comment creation
|
||||
|
||||
19
cypress/integration/post/DeleteImage.feature
Normal file
19
cypress/integration/post/DeleteImage.feature
Normal file
@ -0,0 +1,19 @@
|
||||
Feature: Delete Teaser Image
|
||||
As a user
|
||||
I would like to be able to remove an image I have previously added to my Post
|
||||
So that I have control over the content of my Post
|
||||
|
||||
Background:
|
||||
Given I have a user account
|
||||
Given I am logged in
|
||||
Given we have the following posts in our database:
|
||||
| authorId | id | title | content |
|
||||
| id-of-peter-pan | p1 | Post to be updated | successfully updated |
|
||||
|
||||
Scenario: Delete existing image
|
||||
Given I am on the 'post/edit/p1' page
|
||||
And my post has a teaser image
|
||||
Then I should be able to remove the image
|
||||
And I click on "Save"
|
||||
Then I get redirected to ".../post-to-be-updated"
|
||||
And the "updated" post was saved successfully without a teaser image
|
||||
47
cypress/integration/post/ImageUploader.feature
Normal file
47
cypress/integration/post/ImageUploader.feature
Normal file
@ -0,0 +1,47 @@
|
||||
Feature: Upload Teaser Image
|
||||
As a user
|
||||
I would like to be able to add a teaser image to my Post
|
||||
So that I can personalize my posts
|
||||
|
||||
|
||||
Background:
|
||||
Given I have a user account
|
||||
Given I am logged in
|
||||
Given we have the following posts in our database:
|
||||
| authorId | id | title | content |
|
||||
| id-of-peter-pan | p1 | Post to be updated | successfully updated |
|
||||
|
||||
Scenario: Create a Post with a Teaser Image
|
||||
When I click on the big plus icon in the bottom right corner to create post
|
||||
Then I should be able to "add" a teaser image
|
||||
And confirm crop
|
||||
And I add all required fields
|
||||
And I click on "Save"
|
||||
Then I get redirected to ".../new-post"
|
||||
And the post was saved successfully with the "new" teaser image
|
||||
|
||||
Scenario: Update a Post to add an image
|
||||
Given I am on the 'post/edit/p1' page
|
||||
And I should be able to "change" a teaser image
|
||||
And confirm crop
|
||||
And I click on "Save"
|
||||
Then I see a toaster with "Saved!"
|
||||
And I get redirected to ".../post-to-be-updated"
|
||||
Then the post was saved successfully with the "updated" teaser image
|
||||
|
||||
Scenario: Add image, then add a different image
|
||||
When I click on the big plus icon in the bottom right corner to create post
|
||||
Then I should be able to "add" a teaser image
|
||||
And confirm crop
|
||||
And I should be able to "change" a teaser image
|
||||
And confirm crop
|
||||
And the first image should be removed from the preview
|
||||
|
||||
Scenario: Add image, then delete it
|
||||
When I click on the big plus icon in the bottom right corner to create post
|
||||
Then I should be able to "add" a teaser image
|
||||
And I should be able to remove it
|
||||
And I add all required fields
|
||||
And I click on "Save"
|
||||
Then I get redirected to ".../new-post"
|
||||
And the "new" post was saved successfully without a teaser image
|
||||
@ -9,10 +9,9 @@ Feature: Change password
|
||||
password or just out of an good habit, you want to change your password.
|
||||
|
||||
Background:
|
||||
Given my user account has the following login credentials:
|
||||
Given I am logged in with these credentials:
|
||||
| email | password |
|
||||
| user@example.org | exposed |
|
||||
And I am logged in
|
||||
|
||||
Scenario: Change my password
|
||||
Given I am on the "settings" page
|
||||
|
||||
@ -7,7 +7,7 @@ Feature: Authentication
|
||||
Given I have a user account
|
||||
|
||||
Scenario: Log in
|
||||
When I visit the "/login" page
|
||||
When I visit the "login" page
|
||||
And I fill in my email and password combination and click submit
|
||||
Then I can click on my profile picture in the top right corner
|
||||
And I can see my name "Peter Lustig" in the dropdown menu
|
||||
|
||||
@ -11,6 +11,7 @@ Feature: Block a User
|
||||
Scenario: Block a user
|
||||
Given I am on the profile page of the annoying user
|
||||
When I click on "Block user" from the content menu in the user info box
|
||||
And I "should" see "Unblock user" from the content menu in the user info box
|
||||
And I navigate to my "Blocked users" settings page
|
||||
Then I can see the following table:
|
||||
| Avatar | Name |
|
||||
@ -20,14 +21,15 @@ Feature: Block a User
|
||||
Given I block the user "Harassing User"
|
||||
And I previously created a post
|
||||
And a blocked user visits the post page of one of my authored posts
|
||||
Then they should not see the comment from
|
||||
And they should see a text explaining commenting is not possible
|
||||
Then they should see a text explaining why commenting is not possible
|
||||
And they should not see the comment form
|
||||
|
||||
Scenario: Block a previously followed user
|
||||
Given I follow the user "Harassing User"
|
||||
When I visit the profile page of the annoying user
|
||||
And I click on "Block user" from the content menu in the user info box
|
||||
And I get removed from his follower collection
|
||||
And I "should" see "Unblock user" from the content menu in the user info box
|
||||
|
||||
Scenario: Posts of blocked users are not filtered from search results
|
||||
Given "Harassing User" wrote a post "You can still see my posts"
|
||||
@ -44,3 +46,15 @@ Feature: Block a User
|
||||
Then I should see the following posts in the select dropdown:
|
||||
| title |
|
||||
| previously created post |
|
||||
|
||||
Scenario: Blocked users cannot see they are blocked in their list
|
||||
Given a user has blocked me
|
||||
And I navigate to my "Blocked users" settings page
|
||||
Then I should see no users in my blocked users list
|
||||
|
||||
Scenario: Blocked users should not see link or button to unblock, only blocking users
|
||||
Given a user has blocked me
|
||||
When I visit the profile page of the annoying user
|
||||
And I "should not" see "Unblock user" from the content menu in the user info box
|
||||
And I should see the "Follow" button
|
||||
And I should not see "Unblock user" button
|
||||
@ -23,7 +23,7 @@ module.exports = (on, config) => {
|
||||
config.env.NEO4J_URI = parsed.NEO4J_URI
|
||||
config.env.NEO4J_USERNAME = parsed.NEO4J_USERNAME
|
||||
config.env.NEO4J_PASSWORD = parsed.NEO4J_PASSWORD
|
||||
|
||||
config.env.JWT_SECRET = parsed.JWT_SECRET
|
||||
on('file:preprocessor', cucumber())
|
||||
return config
|
||||
}
|
||||
|
||||
@ -18,20 +18,24 @@ import helpers from "./helpers";
|
||||
import { GraphQLClient, request } from 'graphql-request'
|
||||
import { gql } from '../../backend/src/helpers/jest'
|
||||
import config from '../../backend/src/config'
|
||||
import encode from '../../backend/src/jwt/encode'
|
||||
|
||||
const switchLang = name => {
|
||||
cy.get(".locale-menu").click();
|
||||
cy.contains(".locale-menu-popover a", name).click();
|
||||
};
|
||||
|
||||
const authenticatedHeaders = async (variables) => {
|
||||
const authenticatedHeaders = (variables) => {
|
||||
const mutation = gql`
|
||||
mutation($email: String!, $password: String!) {
|
||||
login(email: $email, password: $password)
|
||||
}
|
||||
`
|
||||
const response = await request(config.GRAPHQL_URI, mutation, variables)
|
||||
return { authorization: `Bearer ${response.login}` }
|
||||
return new Cypress.Promise((resolve, reject) => {
|
||||
request(config.GRAPHQL_URI, mutation, variables).then((response) => {
|
||||
resolve({ authorization: `Bearer ${response.login}` })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Cypress.Commands.add("switchLanguage", (name, force) => {
|
||||
@ -47,7 +51,13 @@ Cypress.Commands.add("switchLanguage", (name, force) => {
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add("login", ({ email, password }) => {
|
||||
Cypress.Commands.add("login", user => {
|
||||
const token = encode(user)
|
||||
cy.setCookie('human-connection-token', token)
|
||||
.visit("/")
|
||||
});
|
||||
|
||||
Cypress.Commands.add("manualLogin", ({ email, password }) => {
|
||||
cy.visit(`/login`);
|
||||
cy.get("input[name=email]")
|
||||
.trigger("focus")
|
||||
@ -58,11 +68,9 @@ Cypress.Commands.add("login", ({ email, password }) => {
|
||||
cy.get("button[name=submit]")
|
||||
.as("submitButton")
|
||||
.click();
|
||||
cy.get(".iziToast-message").should("contain", "You are logged in!");
|
||||
cy.location("pathname").should("eq", "/");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("logout", (email, password) => {
|
||||
Cypress.Commands.add("logout", () => {
|
||||
cy.visit(`/logout`);
|
||||
cy.location("pathname").should("contain", "/login"); // we're out
|
||||
});
|
||||
@ -74,43 +82,24 @@ Cypress.Commands.add("openPage", page => {
|
||||
cy.visit(`/${page}`);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("createCategories", (id, slug) => {
|
||||
cy.neode()
|
||||
.create("Category", {
|
||||
id: `${id}`,
|
||||
name: "Just For Fun",
|
||||
slug: `${slug}`,
|
||||
icon: "smile"
|
||||
})
|
||||
.create("Category", {
|
||||
id: `${id}1`,
|
||||
name: "Happiness & Values",
|
||||
icon: "heart-o"
|
||||
})
|
||||
.create("Category", {
|
||||
id: `${id}2`,
|
||||
name: "Health & Wellbeing",
|
||||
icon: "medkit"
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Cypress.Commands.add(
|
||||
'authenticateAs',
|
||||
async ({email, password}) => {
|
||||
const headers = await authenticatedHeaders({ email, password })
|
||||
return new GraphQLClient(config.GRAPHQL_URI, { headers })
|
||||
}
|
||||
)
|
||||
({email, password}) => {
|
||||
return new Cypress.Promise((resolve, reject) => {
|
||||
authenticatedHeaders({ email, password }).then((headers) => {
|
||||
resolve(new GraphQLClient(config.GRAPHQL_URI, { headers }))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Cypress.Commands.add(
|
||||
'mutate',
|
||||
{ prevSubject: true },
|
||||
async (graphQLClient, mutation, variables) => {
|
||||
await graphQLClient.request(mutation, variables)
|
||||
return graphQLClient
|
||||
}
|
||||
)
|
||||
(graphQLClient, mutation, variables) => {
|
||||
return new Cypress.Promise((resolve, reject) => {
|
||||
graphQLClient.request(mutation, variables).then(() => resolve(graphQLClient))
|
||||
})
|
||||
})
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import Factory from '../../backend/src/factories'
|
||||
import Factory, { cleanDatabase } from '../../backend/src/db/factories'
|
||||
import { getDriver, getNeode } from '../../backend/src/db/neo4j'
|
||||
|
||||
const neo4jConfigs = {
|
||||
@ -6,51 +6,38 @@ const neo4jConfigs = {
|
||||
username: Cypress.env('NEO4J_USERNAME'),
|
||||
password: Cypress.env('NEO4J_PASSWORD')
|
||||
}
|
||||
const neo4jDriver = getDriver(neo4jConfigs)
|
||||
const neodeInstance = getNeode(neo4jConfigs)
|
||||
const factoryOptions = { neo4jDriver, neodeInstance }
|
||||
const factory = Factory(factoryOptions)
|
||||
|
||||
beforeEach(async () => {
|
||||
await factory.cleanDatabase()
|
||||
})
|
||||
beforeEach(() => cleanDatabase())
|
||||
|
||||
Cypress.Commands.add('neode', () => {
|
||||
return neodeInstance
|
||||
})
|
||||
|
||||
Cypress.Commands.add(
|
||||
'first',
|
||||
{ prevSubject: true },
|
||||
async (neode, model, properties) => {
|
||||
(neode, model, properties) => {
|
||||
return neode.first(model, properties)
|
||||
}
|
||||
)
|
||||
Cypress.Commands.add(
|
||||
'relateTo',
|
||||
{ prevSubject: true },
|
||||
async (node, otherNode, relationship) => {
|
||||
(node, otherNode, relationship) => {
|
||||
return node.relateTo(otherNode, relationship)
|
||||
}
|
||||
)
|
||||
|
||||
Cypress.Commands.add('factory', () => {
|
||||
return Factory(factoryOptions)
|
||||
})
|
||||
Cypress.Commands.add('factory', () => Factory)
|
||||
|
||||
Cypress.Commands.add(
|
||||
'create',
|
||||
'build',
|
||||
{ prevSubject: true },
|
||||
async (factory, node, properties) => {
|
||||
await factory.create(node, properties)
|
||||
return factory
|
||||
(factory, name, atrributes, options) => {
|
||||
return new Cypress.Promise((resolve, reject) => {
|
||||
return factory.build(name, atrributes, options).then(() => resolve(factory))
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
Cypress.Commands.add(
|
||||
'relate',
|
||||
{ prevSubject: true },
|
||||
async (factory, node, relationship, properties) => {
|
||||
await factory.relate(node, relationship, properties)
|
||||
return factory
|
||||
}
|
||||
)
|
||||
|
||||
2
deployment/.gitignore
vendored
2
deployment/.gitignore
vendored
@ -2,3 +2,5 @@ secrets.yaml
|
||||
configmap.yaml
|
||||
**/secrets.yaml
|
||||
**/configmap.yaml
|
||||
**/staging-values.yaml
|
||||
**/production-values.yaml
|
||||
@ -1,11 +1,10 @@
|
||||
# Human-Connection Nitro \| Deployment Configuration
|
||||
|
||||
We deploy with [kubernetes](https://kubernetes.io/). In order to deploy your own
|
||||
network you have to [install kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
|
||||
and get a kubernetes cluster.
|
||||
There are a couple different ways we have tested to deploy an instance of Human Connection, with [kubernetes](https://kubernetes.io/) and via [Helm](https://helm.sh/docs/). In order to manage your own
|
||||
network, you have to [install kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/), [install Helm](https://helm.sh/docs/intro/install/) (optional, but the preferred way),
|
||||
and set up a kubernetes cluster. Since there are many different options to host your cluster, we won't go into specifics here.
|
||||
|
||||
We have tested two different kubernetes providers: [Minikube](./minikube/README.md)
|
||||
and [Digital Ocean](./digital-ocean/README.md).
|
||||
|
||||
Check out the specific documentation for your provider. After that, learn how
|
||||
to apply the specific kubernetes configuration for [Human Connection](./human-connection/README.md).
|
||||
Check out the specific documentation for your provider. After that, choose whether you want to go with the recommended deploy option [Helm](./helm/README.md), or use kubernetes to apply the configuration for [Human Connection](./human-connection/README.md).
|
||||
|
||||
22
deployment/helm/human-connection/.helmignore
Normal file
22
deployment/helm/human-connection/.helmignore
Normal file
@ -0,0 +1,22 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
5
deployment/helm/human-connection/Chart.yaml
Normal file
5
deployment/helm/human-connection/Chart.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
apiVersion: v1
|
||||
appVersion: "0.3.1"
|
||||
description: A Helm chart for Human Connection
|
||||
name: human-connection
|
||||
version: 0.1.0
|
||||
72
deployment/helm/human-connection/README.md
Normal file
72
deployment/helm/human-connection/README.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Helm installation of Human Connection
|
||||
|
||||
Deploying Human Connection with Helm is very straight forward. All you have to
|
||||
do is to change certain parameters, like domain names and API keys, then you
|
||||
just install our provided Helm chart to your cluster.
|
||||
|
||||
## Configuration
|
||||
|
||||
You can customize the network with your configuration by changing the `values.yaml`, all variables will be available as
|
||||
environment variables in your deployed kubernetes pods.
|
||||
|
||||
Probably you want to change this environment variable to your actual domain:
|
||||
|
||||
```bash
|
||||
# in folder /deployment/helm
|
||||
CLIENT_URI: "https://develop.human-connection.org"
|
||||
```
|
||||
|
||||
If you want to edit secrets, you have to `base64` encode them. See [kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/secret/#creating-a-secret-manually). You can also use `helm-secrets`, but we have yet to test it.
|
||||
|
||||
```bash
|
||||
# example how to base64 a string:
|
||||
$ echo -n 'admin' | base64
|
||||
YWRtaW4=
|
||||
```
|
||||
Those secrets get `base64` decoded and are available as environment variables in
|
||||
your deployed kubernetes pods.
|
||||
|
||||
# https
|
||||
If you start with setting up the `https`, when you install the app, it will automatically take care of the certificates for you.
|
||||
|
||||
First check that you are using `Helm v3`, this is important since it removes the need for `Tiller`. See, [FAQ](https://helm.sh/docs/faq/#removal-of-tiller)
|
||||
|
||||
```bash
|
||||
$ helm version
|
||||
# output should look similar to this:
|
||||
#version.BuildInfo{Version:"v3.0.2", GitCommit:"19e47ee3283ae98139d98460de796c1be1e3975f", GitTreeState:"clean", GoVersion:"go1.13.5"}
|
||||
```
|
||||
|
||||
Apply cert-manager CRDs before installing (or it will fail)
|
||||
|
||||
```bash
|
||||
$ kubectl apply --validate=false -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.13.0/deploy/manifests/00-crds.yaml
|
||||
```
|
||||
|
||||
Next, create the `cert-manager` namespace
|
||||
```bash
|
||||
$ kubectl create namespace cert-manager
|
||||
```
|
||||
Add the `jetstack` repo and update
|
||||
|
||||
```bash
|
||||
$ helm repo add jetstack https://charts.jetstack.io
|
||||
$ helm repo update
|
||||
```
|
||||
|
||||
Install cert-manager
|
||||
```bash
|
||||
$ helm install cert-manager --namespace cert-manager --version v0.13.0 jetstack/cert-manager
|
||||
```
|
||||
|
||||
# Deploy
|
||||
|
||||
Once you are satisfied with the configuration, you can install the app.
|
||||
|
||||
```bash
|
||||
# in folder /deployment/helm/human-connection
|
||||
$ helm install develop ./ --namespace human-connection
|
||||
```
|
||||
Where `develop` is the release name, in this case develop for our develop server and `human-connection` is the namespace, again customize for your needs. The release name can be anything you want. Just keep in mind that it is used in the templates to prepend the `CLIENT_URI` and other places.
|
||||
|
||||
This will set up everything you need for the network, including `deployments`, and their `pods`, `services`, `ingress`, `volumes`(PersitentVolumes), `PersistentVolumeClaims`, and even `ClusterIssuers` for https certificates.
|
||||
@ -0,0 +1,20 @@
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: letsencrypt-prod
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
acme:
|
||||
server: https://acme-v02.api.letsencrypt.org/directory
|
||||
email: {{ .Values.supportEmail }}
|
||||
privateKeySecretRef:
|
||||
name: letsencrypt-prod
|
||||
solvers:
|
||||
- http01:
|
||||
ingress:
|
||||
class: nginx
|
||||
@ -0,0 +1,20 @@
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: letsencrypt-staging
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
acme:
|
||||
server: https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
email: {{ .Values.supportEmail }}
|
||||
privateKeySecretRef:
|
||||
name: letsencrypt-staging
|
||||
solvers:
|
||||
- http01:
|
||||
ingress:
|
||||
class: nginx
|
||||
@ -0,0 +1,58 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-backend
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
replicas: 1
|
||||
minReadySeconds: 15
|
||||
progressDeadlineSeconds: 60
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 0
|
||||
maxUnavailable: "100%"
|
||||
selector:
|
||||
matchLabels:
|
||||
human-connection.org/selector: deployment-backend
|
||||
template:
|
||||
metadata:
|
||||
name: deployment-backend
|
||||
annotations:
|
||||
backup.velero.io/backup-volumes: uploads
|
||||
labels:
|
||||
human-connection.org/commit: {{ .Values.commit }}
|
||||
human-connection.org/selector: deployment-backend
|
||||
spec:
|
||||
containers:
|
||||
- name: backend
|
||||
image: "{{ .Values.backendImage }}:{{ .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ .Release.Name }}-configmap
|
||||
- secretRef:
|
||||
name: {{ .Release.Name }}-secrets
|
||||
ports:
|
||||
- containerPort: 4000
|
||||
protocol: TCP
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
volumeMounts:
|
||||
- mountPath: /nitro-backend/public/uploads
|
||||
name: uploads
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
volumes:
|
||||
- name: uploads
|
||||
persistentVolumeClaim:
|
||||
claimName: uploads-claim
|
||||
status: {}
|
||||
@ -0,0 +1,40 @@
|
||||
{{- if .Values.developmentMailserverDomain }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-mailserver
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
replicas: 1
|
||||
minReadySeconds: 15
|
||||
progressDeadlineSeconds: 60
|
||||
selector:
|
||||
matchLabels:
|
||||
human-connection.org/selector: deployment-mailserver
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
human-connection.org/selector: deployment-mailserver
|
||||
name: mailserver
|
||||
spec:
|
||||
containers:
|
||||
- name: mailserver
|
||||
image: djfarrelly/maildev
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- containerPort: 80
|
||||
- containerPort: 25
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ .Release.Name }}-configmap
|
||||
- secretRef:
|
||||
name: {{ .Release.Name }}-secrets
|
||||
restartPolicy: Always
|
||||
terminationGracePeriodSeconds: 30
|
||||
status: {}
|
||||
{{- end}}
|
||||
@ -0,0 +1,32 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-maintenance
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
human-connection.org/selector: deployment-maintenance
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
human-connection.org/commit: {{ .Values.commit }}
|
||||
human-connection.org/selector: deployment-maintenance
|
||||
name: maintenance
|
||||
spec:
|
||||
containers:
|
||||
- name: maintenance
|
||||
env:
|
||||
- name: HOST
|
||||
value: 0.0.0.0
|
||||
image: "{{ .Values.maintenanceImage }}:{{ .Chart.AppVersion }}"
|
||||
ports:
|
||||
- containerPort: 80
|
||||
imagePullPolicy: Always
|
||||
restartPolicy: Always
|
||||
terminationGracePeriodSeconds: 30
|
||||
@ -0,0 +1,52 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-neo4j
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 0
|
||||
maxUnavailable: "100%"
|
||||
selector:
|
||||
matchLabels:
|
||||
human-connection.org/selector: deployment-neo4j
|
||||
template:
|
||||
metadata:
|
||||
name: neo4j
|
||||
annotations:
|
||||
backup.velero.io/backup-volumes: neo4j-data
|
||||
labels:
|
||||
human-connection.org/commit: {{ .Values.commit }}
|
||||
human-connection.org/selector: deployment-neo4j
|
||||
spec:
|
||||
containers:
|
||||
- name: neo4j
|
||||
image: "{{ .Values.neo4jImage }}:{{ .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- containerPort: 7687
|
||||
- containerPort: 7474
|
||||
resources:
|
||||
requests:
|
||||
memory: {{ .Values.neo4jResourceRequestsMemory | default "1G" | quote }}
|
||||
limits:
|
||||
memory: {{ .Values.neo4jResourceLimitsMemory | default "1G" | quote }}
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ .Release.Name }}-configmap
|
||||
volumeMounts:
|
||||
- mountPath: /data/
|
||||
name: neo4j-data
|
||||
volumes:
|
||||
- name: neo4j-data
|
||||
persistentVolumeClaim:
|
||||
claimName: neo4j-data-claim
|
||||
restartPolicy: Always
|
||||
terminationGracePeriodSeconds: 30
|
||||
@ -0,0 +1,43 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-webapp
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
replicas: 2
|
||||
minReadySeconds: 15
|
||||
progressDeadlineSeconds: 60
|
||||
selector:
|
||||
matchLabels:
|
||||
human-connection.org/selector: deployment-webapp
|
||||
template:
|
||||
metadata:
|
||||
name: webapp
|
||||
labels:
|
||||
human-connection.org/commit: {{ .Values.commit }}
|
||||
human-connection.org/selector: deployment-webapp
|
||||
spec:
|
||||
containers:
|
||||
- name: webapp
|
||||
image: "{{ .Values.webappImage }}:{{ .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ .Release.Name }}-configmap
|
||||
- secretRef:
|
||||
name: {{ .Release.Name }}-secrets
|
||||
env:
|
||||
- name: HOST
|
||||
value: 0.0.0.0
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
resources: {}
|
||||
imagePullPolicy: Always
|
||||
restartPolicy: Always
|
||||
terminationGracePeriodSeconds: 30
|
||||
status: {}
|
||||
@ -0,0 +1,36 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-ingress
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
cert-manager.io/cluster-issuer: {{ .Values.letsencryptIssuer }}
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: 10m
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ .Values.domain }}
|
||||
secretName: tls
|
||||
rules:
|
||||
- host: {{ .Values.domain }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: {{ .Release.Name }}-webapp
|
||||
servicePort: 3000
|
||||
{{- if .Values.developmentMailserverDomain }}
|
||||
- host: {{ .Values.developmentMailserverDomain }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: {{ .Release.Name }}-mailserver
|
||||
servicePort: 80
|
||||
{{- end }}
|
||||
@ -0,0 +1,29 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-db-migrations
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
annotations:
|
||||
"helm.sh/hook": post-upgrade
|
||||
"helm.sh/hook-weight": "5"
|
||||
"helm.sh/hook-delete-policy": hook-succeeded, hook-failed
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
name: {{ .Release.Name }}
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: db-migrations-job
|
||||
image: "{{ .Values.backendImage }}:latest"
|
||||
command: ["/bin/sh", "-c", "{{ .Values.dbMigrations }}"]
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ .Release.Name }}-configmap
|
||||
- secretRef:
|
||||
name: {{ .Release.Name }}-secrets
|
||||
@ -0,0 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-backend
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
ports:
|
||||
- name: graphql
|
||||
port: 4000
|
||||
targetPort: 4000
|
||||
selector:
|
||||
human-connection.org/selector: deployment-backend
|
||||
@ -0,0 +1,22 @@
|
||||
{{- if .Values.developmentMailserverDomain }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-mailserver
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
targetPort: 80
|
||||
- name: smtp
|
||||
port: 25
|
||||
targetPort: 25
|
||||
selector:
|
||||
human-connection.org/selector: deployment-mailserver
|
||||
{{- end}}
|
||||
@ -0,0 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-maintenance
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
targetPort: 80
|
||||
selector:
|
||||
human-connection.org/selector: deployment-maintenance
|
||||
@ -0,0 +1,20 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-neo4j
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
ports:
|
||||
- name: bolt
|
||||
port: 7687
|
||||
targetPort: 7687
|
||||
- name: web
|
||||
port: 7474
|
||||
targetPort: 7474
|
||||
selector:
|
||||
human-connection.org/selector: deployment-neo4j
|
||||
@ -0,0 +1,18 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-webapp
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: human-connection
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
|
||||
spec:
|
||||
ports:
|
||||
- name: {{ .Release.Name }}-webapp
|
||||
port: 3000
|
||||
protocol: TCP
|
||||
targetPort: 3000
|
||||
selector:
|
||||
human-connection.org/selector: deployment-webapp
|
||||
@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: neo4j-data-claim
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.neo4jStorage }}
|
||||
@ -0,0 +1,16 @@
|
||||
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: uploads-claim
|
||||
spec:
|
||||
dataSource:
|
||||
name: uploads-snapshot
|
||||
kind: VolumeSnapshot
|
||||
apiGroup: snapshot.storage.k8s.io
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.uploadsStorage }}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user