diff --git a/.travis.yml b/.travis.yml index 7cfb983cd..f6fdffebf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,8 @@ addons: - libgconf-2-4 snaps: - docker - + firefox: "latest-esr" + install: - yarn global add wait-on # Install Codecov diff --git a/CHANGELOG.md b/CHANGELOG.md index 8067daad4..664c6cbe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,63 @@ 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.4.0](https://github.com/Human-Connection/Human-Connection/compare/v0.3.1...v0.4.0) + +> 21 February 2020 + +- fix: Favor Cypress.Promise over async/await in e2e tests [`#3115`](https://github.com/Human-Connection/Human-Connection/pull/3115) +- docs(setup): Fix links in tests [`#3120`](https://github.com/Human-Connection/Human-Connection/pull/3120) +- feat: 🍰 Expose sensitive report type to moderators only [`#3075`](https://github.com/Human-Connection/Human-Connection/pull/3075) +- refactor: migrate card component [`#2870`](https://github.com/Human-Connection/Human-Connection/pull/2870) +- build(deps): bump metascraper-youtube from 5.10.7 to 5.11.1 in /backend [`#3114`](https://github.com/Human-Connection/Human-Connection/pull/3114) +- fix(cypress): Upgrade cypress, remove log out step [`#3119`](https://github.com/Human-Connection/Human-Connection/pull/3119) +- build(deps): bump metascraper-date from 5.10.7 to 5.11.1 in /backend [`#3069`](https://github.com/Human-Connection/Human-Connection/pull/3069) +- build(deps): bump metascraper-author from 5.10.7 to 5.11.1 in /backend [`#3070`](https://github.com/Human-Connection/Human-Connection/pull/3070) +- build(deps): bump xregexp from 4.2.4 to 4.3.0 in /webapp [`#3047`](https://github.com/Human-Connection/Human-Connection/pull/3047) +- build(deps): bump metascraper-publisher from 5.10.7 to 5.11.1 in /backend [`#3068`](https://github.com/Human-Connection/Human-Connection/pull/3068) +- build(deps): bump @sentry/node from 5.12.3 to 5.12.4 in /backend [`#3113`](https://github.com/Human-Connection/Human-Connection/pull/3113) +- feat: German Translations Update By Andreas Plank [`#3109`](https://github.com/Human-Connection/Human-Connection/pull/3109) +- fix(frontend): Remove Hover Menu from User Teaser [`#3093`](https://github.com/Human-Connection/Human-Connection/pull/3093) +- build(deps-dev): bump eslint-plugin-jest from 23.6.0 to 23.7.0 in /webapp [`#3030`](https://github.com/Human-Connection/Human-Connection/pull/3030) +- fix(frontend): Post page won't crash on anonymous user [`#2981`](https://github.com/Human-Connection/Human-Connection/pull/2981) +- chore(cypress): Remove debug statements [`#3110`](https://github.com/Human-Connection/Human-Connection/pull/3110) +- build(deps): bump metascraper-audio from 5.10.7 to 5.11.1 in /backend [`#3066`](https://github.com/Human-Connection/Human-Connection/pull/3066) +- build(deps): bump @nuxtjs/sentry from 3.2.3 to 3.2.4 in /webapp [`#3081`](https://github.com/Human-Connection/Human-Connection/pull/3081) +- build(deps-dev): bump apollo-server-testing from 2.10.0 to 2.10.1 in /backend [`#3078`](https://github.com/Human-Connection/Human-Connection/pull/3078) +- fix(subscriptions): Don't publish undefined [`#3101`](https://github.com/Human-Connection/Human-Connection/pull/3101) +- build(deps): [security] bump yarn from 1.17.3 to 1.22.0 in /webapp [`#3077`](https://github.com/Human-Connection/Human-Connection/pull/3077) +- feat: Normalize locales/json files [`#3003`](https://github.com/Human-Connection/Human-Connection/pull/3003) +- 🍰feat: Delete teaser image [`#2585`](https://github.com/Human-Connection/Human-Connection/pull/2585) +- fix: swap lat and lng [`#2589`](https://github.com/Human-Connection/Human-Connection/pull/2589) +- fix(frontend): avatar image covers full circle [`#3102`](https://github.com/Human-Connection/Human-Connection/pull/3102) +- fix(jwt): Whitelist encoded JWT attributes [`#3090`](https://github.com/Human-Connection/Human-Connection/pull/3090) +- test: Write cypress tests for ImageUploader [`#3056`](https://github.com/Human-Connection/Human-Connection/pull/3056) +- build(deps-dev): bump eslint-plugin-vue from 6.1.2 to 6.2.1 in /webapp [`#3092`](https://github.com/Human-Connection/Human-Connection/pull/3092) +- build: Fix intermittent failing tests [`#3087`](https://github.com/Human-Connection/Human-Connection/pull/3087) +- fix(nuxt-env): Configuration issue with websockets [`#3089`](https://github.com/Human-Connection/Human-Connection/pull/3089) +- build(deps-dev): bump eslint-plugin-jest from 23.6.0 to 23.7.0 in /backend [`#3029`](https://github.com/Human-Connection/Human-Connection/pull/3029) +- build(deps): bump cookie-universal-nuxt from 2.1.1 to 2.1.2 in /webapp [`#3073`](https://github.com/Human-Connection/Human-Connection/pull/3073) +- build(deps): bump @nuxtjs/sentry from 3.2.2 to 3.2.3 in /webapp [`#3072`](https://github.com/Human-Connection/Human-Connection/pull/3072) +- build(deps): bump metascraper-image from 5.10.7 to 5.11.1 in /backend [`#3067`](https://github.com/Human-Connection/Human-Connection/pull/3067) +- build(deps-dev): bump vue-loader from 15.8.3 to 15.9.0 in /webapp [`#3060`](https://github.com/Human-Connection/Human-Connection/pull/3060) +- build(deps-dev): bump @storybook/addon-actions from 5.3.12 to 5.3.13 in /webapp [`#3049`](https://github.com/Human-Connection/Human-Connection/pull/3049) +- refactor(cypress): Speed up builds, avoid login through UI [`#3042`](https://github.com/Human-Connection/Human-Connection/pull/3042) +- feat: 🍰 Set up Vue-Apollo Subscriptions [`#1705`](https://github.com/Human-Connection/Human-Connection/pull/1705) +- fix: Update devops_ticket.md [`#3053`](https://github.com/Human-Connection/Human-Connection/pull/3053) +- build(deps-dev): bump @storybook/addon-notes from 5.3.12 to 5.3.13 in /webapp [`#3048`](https://github.com/Human-Connection/Human-Connection/pull/3048) +- build(deps-dev): bump @storybook/addon-a11y from 5.3.12 to 5.3.13 in /webapp [`#3050`](https://github.com/Human-Connection/Human-Connection/pull/3050) +- build(deps): Node v13 compatbility [`#3041`](https://github.com/Human-Connection/Human-Connection/pull/3041) +- build(deps): bump request from 2.88.0 to 2.88.2 in /backend [`#3045`](https://github.com/Human-Connection/Human-Connection/pull/3045) +- build(deps-dev): bump @storybook/vue from 5.3.12 to 5.3.13 in /webapp [`#3046`](https://github.com/Human-Connection/Human-Connection/pull/3046) +- feat(deployment): Add helm charts for deploy [`#1613`](https://github.com/Human-Connection/Human-Connection/pull/1613) +- build(deps-dev): bump vue-svg-loader from 0.15.0 to 0.16.0 in /webapp [`#3039`](https://github.com/Human-Connection/Human-Connection/pull/3039) +- fix: Increase body parser limit [`#3037`](https://github.com/Human-Connection/Human-Connection/pull/3037) +- chore: Update to v0.3.1 [`#3035`](https://github.com/Human-Connection/Human-Connection/pull/3035) +- fix(subscriptions): Don't publish undefined [`#3088`](https://github.com/Human-Connection/Human-Connection/issues/3088) +- locales sorted. [`fa906ef`](https://github.com/Human-Connection/Human-Connection/commit/fa906efb1f40dc5bd80c9678f33c7b607a320099) +- Upgrade cypress, remove log out step [`0df4038`](https://github.com/Human-Connection/Human-Connection/commit/0df40386dd866c6b9ce540b966dfe00089507d31) +- Refactor GQL and tests, first approach [`f380915`](https://github.com/Human-Connection/Human-Connection/commit/f380915b2c679d42e5db136ea1d923cf00bbcf10) + #### [v0.3.1](https://github.com/Human-Connection/Human-Connection/compare/v0.3.0...v0.3.1) > 10 February 2020 @@ -57,8 +114,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - 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) +- refactor TeaserImage component [`e14cbf8`](https://github.com/Human-Connection/Human-Connection/commit/e14cbf8173e3040b5285ba6a5c73e2d2d2a47860) +- refactor DeleteData template and CSS [`509892b`](https://github.com/Human-Connection/Human-Connection/commit/509892b6caee6c4ca8384fb0090122ced98edfd4) #### [v0.3.0](https://github.com/Human-Connection/Human-Connection/compare/v0.2.1...v0.3.0) @@ -349,7 +406,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - fixes #2659 [`#2659`](https://github.com/Human-Connection/Human-Connection/issues/2659) - Convert block/unblock to blacklist/whitelist [`c297b83`](https://github.com/Human-Connection/Human-Connection/commit/c297b83f873edc61ddec370633b9b65896c56591) - Rename blacklist/whitelist to mute/unmute [`ba3e9e1`](https://github.com/Human-Connection/Human-Connection/commit/ba3e9e1025bf432151c9bf1002045179b338ff7f) -- build(deps-dev): bump storybook-design-token in /webapp [`88d39c4`](https://github.com/Human-Connection/Human-Connection/commit/88d39c4a427cb86527b06201f3f5e96d53ac09a0) +- manage button states and color schemes with mixin [`1b9249c`](https://github.com/Human-Connection/Human-Connection/commit/1b9249c685e34eb2e94b31ee0ec22421c6aa6a73) #### [v0.2.0](https://github.com/Human-Connection/Human-Connection/compare/v0.1.13...v0.2.0) diff --git a/backend/package.json b/backend/package.json index ba09981b0..9396cdaa9 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "human-connection-backend", - "version": "0.3.1", + "version": "0.4.0", "description": "GraphQL Backend for Human Connection", "main": "src/index.js", "scripts": { @@ -38,19 +38,19 @@ }, "dependencies": { "@hapi/joi": "^17.1.0", - "@sentry/node": "^5.12.3", + "@sentry/node": "^5.13.1", "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.10.0", + "apollo-server": "~2.10.1", "apollo-server-express": "^2.9.16", "babel-plugin-transform-runtime": "^6.23.0", "bcryptjs": "~2.4.3", "cheerio": "~1.0.0-rc.3", "cors": "~2.8.5", "cross-env": "~7.0.0", - "date-fns": "2.9.0", + "date-fns": "2.10.0", "debug": "~4.1.1", "dotenv": "~8.2.0", "express": "^4.17.1", @@ -61,30 +61,30 @@ "graphql-middleware": "~4.0.2", "graphql-middleware-sentry": "^3.2.1", "graphql-redis-subscriptions": "^2.1.2", - "graphql-shield": "~7.0.11", + "graphql-shield": "~7.0.14", "graphql-tag": "~2.10.3", - "helmet": "~3.21.2", - "ioredis": "^4.14.1", + "helmet": "~3.21.3", + "ioredis": "^4.16.0", "jsonwebtoken": "~8.5.1", "linkifyjs": "~2.1.8", "lodash": "~4.17.14", "merge-graphql-schemas": "^1.7.6", - "metascraper": "^5.11.0", + "metascraper": "^5.11.4", "metascraper-audio": "^5.11.1", - "metascraper-author": "^5.10.7", + "metascraper-author": "^5.11.1", "metascraper-clearbit-logo": "^5.3.0", - "metascraper-date": "^5.10.7", - "metascraper-description": "^5.11.0", + "metascraper-date": "^5.11.1", + "metascraper-description": "^5.11.1", "metascraper-image": "^5.11.1", - "metascraper-lang": "^5.10.7", + "metascraper-lang": "^5.11.1", "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.7", - "metascraper-url": "^5.10.7", - "metascraper-video": "^5.10.7", - "metascraper-youtube": "^5.10.7", + "metascraper-logo": "^5.11.1", + "metascraper-publisher": "^5.11.1", + "metascraper-soundcloud": "^5.11.4", + "metascraper-title": "^5.11.1", + "metascraper-url": "^5.11.1", + "metascraper-video": "^5.11.1", + "metascraper-youtube": "^5.11.1", "migrate": "^1.6.2", "minimatch": "^3.0.4", "mustache": "^4.0.0", @@ -92,29 +92,29 @@ "neo4j-graphql-js": "^2.11.5", "neode": "^0.3.7", "node-fetch": "~2.6.0", - "nodemailer": "^6.4.2", + "nodemailer": "^6.4.4", "nodemailer-html-to-text": "^3.1.0", "npm-run-all": "~4.1.5", "request": "~2.88.2", - "sanitize-html": "~1.21.1", + "sanitize-html": "~1.22.0", "slug": "~2.1.1", "subscriptions-transport-ws": "^0.9.16", "trunc-html": "~1.1.2", - "uuid": "~3.4.0", + "uuid": "~7.0.1", "validator": "^12.2.0", - "wait-on": "~4.0.0", - "xregexp": "^4.2.4" + "wait-on": "~4.0.1", + "xregexp": "^4.3.0" }, "devDependencies": { "@babel/cli": "~7.8.4", - "@babel/core": "~7.8.4", + "@babel/core": "~7.8.6", "@babel/node": "~7.8.4", "@babel/plugin-proposal-throw-expressions": "^7.8.3", - "@babel/preset-env": "~7.8.4", - "@babel/register": "^7.8.3", + "@babel/preset-env": "~7.8.6", + "@babel/register": "^7.8.6", "apollo-server-testing": "~2.10.1", "babel-core": "~7.0.0-0", - "babel-eslint": "~10.0.3", + "babel-eslint": "~10.1.0", "babel-jest": "~25.1.0", "chai": "~4.2.0", "cucumber": "~6.0.5", @@ -122,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.7.0", + "eslint-plugin-jest": "~23.8.1", "eslint-plugin-node": "~11.0.0", "eslint-plugin-prettier": "~3.1.2", "eslint-plugin-promise": "~4.2.1", diff --git a/backend/src/db/factories.js b/backend/src/db/factories.js index 754f84dec..159a71a62 100644 --- a/backend/src/db/factories.js +++ b/backend/src/db/factories.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' import faker from 'faker' import slugify from 'slug' import { hashSync } from 'bcryptjs' diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 755ddabf8..10dc98845 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -152,6 +152,7 @@ export default shield( User: { email: or(isMyOwn, isAdmin), }, + Report: isModerator, }, { debug, diff --git a/backend/src/middleware/permissionsMiddleware.spec.js b/backend/src/middleware/permissionsMiddleware.spec.js index 3c307348d..775533867 100644 --- a/backend/src/middleware/permissionsMiddleware.spec.js +++ b/backend/src/middleware/permissionsMiddleware.spec.js @@ -9,14 +9,6 @@ const driver = getDriver() let query, authenticatedUser, owner, anotherRegularUser, administrator, variables, moderator -const userQuery = gql` - query($name: String) { - User(name: $name) { - email - } - } -` - describe('authorization', () => { beforeAll(async () => { await cleanDatabase() @@ -30,7 +22,11 @@ describe('authorization', () => { query = createTestClient(server).query }) - describe('given two existing users', () => { + afterEach(async () => { + await cleanDatabase() + }) + + describe('given an owner, an other user, an admin, a moderator', () => { beforeEach(async () => { ;[owner, anotherRegularUser, administrator, moderator] = await Promise.all([ Factory.build( @@ -79,15 +75,20 @@ describe('authorization', () => { variables = {} }) - afterEach(async () => { - await cleanDatabase() - }) - describe('access email address', () => { + const userQuery = gql` + query($name: String) { + User(name: $name) { + email + } + } + ` + describe('unauthenticated', () => { beforeEach(() => { authenticatedUser = null }) + it("throws an error and does not expose the owner's email address", async () => { await expect( query({ query: userQuery, variables: { name: 'Owner' } }), @@ -143,7 +144,7 @@ describe('authorization', () => { }) }) - describe('administrator', () => { + describe('as an administrator', () => { beforeEach(async () => { authenticatedUser = await administrator.toJson() }) diff --git a/backend/src/middleware/slugifyMiddleware.spec.js b/backend/src/middleware/slugifyMiddleware.spec.js index e522136d6..df011b0a5 100644 --- a/backend/src/middleware/slugifyMiddleware.spec.js +++ b/backend/src/middleware/slugifyMiddleware.spec.js @@ -153,7 +153,7 @@ describe('slugifyMiddleware', () => { \`\`\` Learn how to setup the database here: - https://docs.human-connection.org/human-connection/neo4j + https://docs.human-connection.org/human-connection/backend#database-indices-and-constraints `) } }) diff --git a/backend/src/middleware/validation/validationMiddleware.spec.js b/backend/src/middleware/validation/validationMiddleware.spec.js index b2c669369..74a343eeb 100644 --- a/backend/src/middleware/validation/validationMiddleware.spec.js +++ b/backend/src/middleware/validation/validationMiddleware.spec.js @@ -58,7 +58,7 @@ const reportMutation = gql` reasonCategory: $reasonCategory reasonDescription: $reasonDescription ) { - id + reportId } } ` diff --git a/backend/src/models/Category.js b/backend/src/models/Category.js index 223bb4f87..ea617adc8 100644 --- a/backend/src/models/Category.js +++ b/backend/src/models/Category.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' export default { id: { type: 'string', primary: true, default: uuid }, diff --git a/backend/src/models/Comment.js b/backend/src/models/Comment.js index 773152541..f4548f0c2 100644 --- a/backend/src/models/Comment.js +++ b/backend/src/models/Comment.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' export default { id: { type: 'string', primary: true, default: uuid }, diff --git a/backend/src/models/Donations.js b/backend/src/models/Donations.js index 45d737f85..1409c85d4 100644 --- a/backend/src/models/Donations.js +++ b/backend/src/models/Donations.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' export default { id: { type: 'string', primary: true, default: uuid }, diff --git a/backend/src/models/Post.js b/backend/src/models/Post.js index 63a36d3a2..15eedbf64 100644 --- a/backend/src/models/Post.js +++ b/backend/src/models/Post.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' export default { id: { type: 'string', primary: true, default: uuid }, diff --git a/backend/src/models/Report.js b/backend/src/models/Report.js index 93876f404..3e001746b 100644 --- a/backend/src/models/Report.js +++ b/backend/src/models/Report.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' export default { id: { type: 'string', primary: true, default: uuid }, diff --git a/backend/src/models/SocialMedia.js b/backend/src/models/SocialMedia.js index abdb12b02..6010c97bb 100644 --- a/backend/src/models/SocialMedia.js +++ b/backend/src/models/SocialMedia.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' export default { id: { type: 'string', primary: true, default: uuid }, diff --git a/backend/src/models/User.js b/backend/src/models/User.js index 055cbfc83..d79fb79b9 100644 --- a/backend/src/models/User.js +++ b/backend/src/models/User.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' export default { id: { type: 'string', primary: true, default: uuid }, // TODO: should be type: 'uuid' but simplified for our tests diff --git a/backend/src/models/User.spec.js b/backend/src/models/User.spec.js index f448cbf08..a45a629e5 100644 --- a/backend/src/models/User.spec.js +++ b/backend/src/models/User.spec.js @@ -46,7 +46,7 @@ describe('slug', () => { \`\`\` Learn how to setup the database here: - https://docs.human-connection.org/human-connection/neo4j + https://docs.human-connection.org/human-connection/backend#database-indices-and-constraints `) } }) diff --git a/backend/src/schema/resolvers/comments.js b/backend/src/schema/resolvers/comments.js index 864d9412c..67a6675c9 100644 --- a/backend/src/schema/resolvers/comments.js +++ b/backend/src/schema/resolvers/comments.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' import Resolver from './helpers/Resolver' export default { diff --git a/backend/src/schema/resolvers/fileUpload/index.js b/backend/src/schema/resolvers/fileUpload/index.js index df0145057..3c41a5d11 100644 --- a/backend/src/schema/resolvers/fileUpload/index.js +++ b/backend/src/schema/resolvers/fileUpload/index.js @@ -1,7 +1,7 @@ import { createWriteStream } from 'fs' import path from 'path' import slug from 'slug' -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' const localFileUpload = async ({ createReadStream, uniqueFilename }) => { await new Promise((resolve, reject) => diff --git a/backend/src/schema/resolvers/helpers/generateNonce.js b/backend/src/schema/resolvers/helpers/generateNonce.js index 4dde1df04..e9b758774 100644 --- a/backend/src/schema/resolvers/helpers/generateNonce.js +++ b/backend/src/schema/resolvers/helpers/generateNonce.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' export default function generateNonce() { return uuid().substring(0, 6) } diff --git a/backend/src/schema/resolvers/moderation.js b/backend/src/schema/resolvers/moderation.js index 4bdf82d50..07054d3a3 100644 --- a/backend/src/schema/resolvers/moderation.js +++ b/backend/src/schema/resolvers/moderation.js @@ -1,20 +1,10 @@ -const transformReturnType = record => { - return { - ...record.get('review').properties, - report: record.get('report').properties, - resource: { - __typename: record.get('type'), - ...record.get('resource').properties, - }, - } -} +import log from './helpers/databaseLogger' export default { Mutation: { review: async (_object, params, context, _resolveInfo) => { const { user: moderator, driver } = context - let createdRelationshipWithNestedAttributes = null // return value const session = driver.session() try { const cypher = ` @@ -25,10 +15,11 @@ export default { ON CREATE SET review.createdAt = $dateTime, review.updatedAt = review.createdAt ON MATCH SET review.updatedAt = $dateTime SET review.disable = $params.disable - SET report.updatedAt = $dateTime, report.closed = $params.closed - SET resource.disabled = review.disable + SET report.updatedAt = $dateTime, report.disable = review.disable, report.closed = $params.closed + SET resource.disabled = report.disable - RETURN review, report, resource, labels(resource)[0] AS type + WITH review, report, resource {.*, __typename: labels(resource)[0]} AS finalResource + RETURN review {.*, report: properties(report), resource: properties(finalResource)} ` const reviewWriteTxResultPromise = session.writeTransaction(async txc => { const reviewTransactionResponse = await txc.run(cypher, { @@ -36,16 +27,14 @@ export default { moderatorId: moderator.id, dateTime: new Date().toISOString(), }) - return reviewTransactionResponse.records.map(transformReturnType) + log(reviewTransactionResponse) + return reviewTransactionResponse.records.map(record => record.get('review')) }) - const txResult = await reviewWriteTxResultPromise - if (!txResult[0]) return null - createdRelationshipWithNestedAttributes = txResult[0] + const [reviewed] = await reviewWriteTxResultPromise + return reviewed || null } finally { session.close() } - - return createdRelationshipWithNestedAttributes }, }, } diff --git a/backend/src/schema/resolvers/passwordReset.js b/backend/src/schema/resolvers/passwordReset.js index 74c71e011..b3fc9f5c3 100644 --- a/backend/src/schema/resolvers/passwordReset.js +++ b/backend/src/schema/resolvers/passwordReset.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' import bcrypt from 'bcryptjs' import createPasswordReset from './helpers/createPasswordReset' @@ -22,6 +22,7 @@ export default { WHERE duration.between(passwordReset.issuedAt, datetime()).days <= 0 AND passwordReset.usedAt IS NULL SET passwordReset.usedAt = datetime() SET user.encryptedPassword = $encryptedNewPassword + SET user.updatedAt = toString(datetime()) RETURN passwordReset `, { diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index af8165997..1d4c4bfaa 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -1,4 +1,4 @@ -import uuid from 'uuid/v4' +import { v4 as uuid } from 'uuid' import { neo4jgraphql } from 'neo4j-graphql-js' import { isEmpty } from 'lodash' import { UserInputError } from 'apollo-server' diff --git a/backend/src/schema/resolvers/reports.js b/backend/src/schema/resolvers/reports.js index 0565c4d8a..f7a2addc4 100644 --- a/backend/src/schema/resolvers/reports.js +++ b/backend/src/schema/resolvers/reports.js @@ -1,23 +1,13 @@ import log from './helpers/databaseLogger' -const transformReturnType = record => { - return { - ...record.get('report').properties, - resource: { - __typename: record.get('type'), - ...record.get('resource').properties, - }, - } -} - export default { Mutation: { fileReport: async (_parent, params, context, _resolveInfo) => { const { resourceId, reasonCategory, reasonDescription } = params const { driver, user } = context const session = driver.session() - const reportWriteTxResultPromise = session.writeTransaction(async transaction => { - const reportTransactionResponse = await transaction.run( + const fileReportWriteTxResultPromise = session.writeTransaction(async transaction => { + const fileReportTransactionResponse = await transaction.run( ` MATCH (submitter:User {id: $submitterId}) MATCH (resource {id: $resourceId}) @@ -27,7 +17,8 @@ export default { WITH submitter, resource, report CREATE (report)<-[filed:FILED {createdAt: $createdAt, reasonCategory: $reasonCategory, reasonDescription: $reasonDescription}]-(submitter) - RETURN report, resource, labels(resource)[0] AS type + WITH filed, report, resource {.*, __typename: labels(resource)[0]} AS finalResource + RETURN filed {.*, reportId: report.id, resource: properties(finalResource)} AS filedReport `, { resourceId, @@ -37,13 +28,12 @@ export default { reasonDescription, }, ) - log(reportTransactionResponse) - return reportTransactionResponse.records.map(transformReturnType) + log(fileReportTransactionResponse) + return fileReportTransactionResponse.records.map(record => record.get('filedReport')) }) try { - const [createdRelationshipWithNestedAttributes] = await reportWriteTxResultPromise - if (!createdRelationshipWithNestedAttributes) return null - return createdRelationshipWithNestedAttributes + const [filedReport] = await fileReportWriteTxResultPromise + return filedReport || null } finally { session.close() } @@ -76,14 +66,24 @@ export default { filterClause = '' } - if (params.closed) filterClause = 'AND report.closed = true' + switch (params.closed) { + case true: + filterClause = 'AND report.closed = true' + break + case false: + filterClause = 'AND report.closed = false' + break + default: + break + } const offset = params.offset && typeof params.offset === 'number' ? `SKIP ${params.offset}` : '' const limit = params.first && typeof params.first === 'number' ? `LIMIT ${params.first}` : '' - const reportReadTxPromise = session.readTransaction(async transaction => { - const allReportsTransactionResponse = await transaction.run( + const reportsReadTxPromise = session.readTransaction(async transaction => { + const reportsTransactionResponse = await transaction.run( + // !!! this Cypher query returns multiple reports on the same resource! i will create an issue for refactoring (bug fixing) ` MATCH (report:Report)-[:BELONGS_TO]->(resource) WHERE (resource:User OR resource:Post OR resource:Comment) @@ -101,11 +101,11 @@ export default { ${offset} ${limit} `, ) - log(allReportsTransactionResponse) - return allReportsTransactionResponse.records.map(record => record.get('report')) + log(reportsTransactionResponse) + return reportsTransactionResponse.records.map(record => record.get('report')) }) try { - const reports = await reportReadTxPromise + const reports = await reportsReadTxPromise return reports } finally { session.close() diff --git a/backend/src/schema/resolvers/reports.spec.js b/backend/src/schema/resolvers/reports.spec.js index 0e690c19e..5e1156f0c 100644 --- a/backend/src/schema/resolvers/reports.spec.js +++ b/backend/src/schema/resolvers/reports.spec.js @@ -10,18 +10,17 @@ const driver = getDriver() describe('file a report on a resource', () => { let authenticatedUser, currentUser, mutate, query, moderator, abusiveUser, otherReportingUser const categoryIds = ['cat9'] - const reportMutation = gql` + const fileReportMutation = gql` mutation($resourceId: ID!, $reasonCategory: ReasonCategory!, $reasonDescription: String!) { fileReport( resourceId: $resourceId reasonCategory: $reasonCategory reasonDescription: $reasonDescription ) { - id createdAt - updatedAt - closed - rule + reasonCategory + reasonDescription + reportId resource { __typename ... on User { @@ -34,6 +33,35 @@ describe('file a report on a resource', () => { content } } + } + } + ` + const variables = { + resourceId: 'invalid', + reasonCategory: 'other', + reasonDescription: 'Violates code of conduct !!!', + } + const reportsQuery = gql` + query($closed: Boolean) { + reports(orderBy: createdAt_desc, closed: $closed) { + id + createdAt + updatedAt + rule + disable + closed + resource { + __typename + ... on User { + id + } + ... on Post { + id + } + ... on Comment { + id + } + } filed { submitter { id @@ -45,11 +73,31 @@ describe('file a report on a resource', () => { } } ` - const variables = { - resourceId: 'whatever', - reasonCategory: 'other', - reasonDescription: 'Violates code of conduct !!!', - } + const reviewMutation = gql` + mutation($resourceId: ID!, $disable: Boolean, $closed: Boolean) { + review(resourceId: $resourceId, disable: $disable, closed: $closed) { + createdAt + resource { + __typename + ... on User { + id + disabled + } + ... on Post { + id + disabled + } + ... on Comment { + id + disabled + } + } + report { + disable + } + } + } + ` beforeAll(async () => { await cleanDatabase() @@ -74,7 +122,7 @@ describe('file a report on a resource', () => { describe('unauthenticated', () => { it('throws authorization error', async () => { authenticatedUser = null - await expect(mutate({ mutation: reportMutation, variables })).resolves.toMatchObject({ + await expect(mutate({ mutation: fileReportMutation, variables })).resolves.toMatchObject({ data: { fileReport: null }, errors: [{ message: 'Not Authorised!' }], }) @@ -94,6 +142,17 @@ describe('file a report on a resource', () => { password: '1234', }, ) + moderator = await Factory.build( + 'user', + { + id: 'moderator-id', + role: 'moderator', + }, + { + email: 'moderator@example.org', + password: '1234', + }, + ) otherReportingUser = await Factory.build( 'user', { @@ -127,7 +186,7 @@ describe('file a report on a resource', () => { describe('invalid resource id', () => { it('returns null', async () => { - await expect(mutate({ mutation: reportMutation, variables })).resolves.toMatchObject({ + await expect(mutate({ mutation: fileReportMutation, variables })).resolves.toMatchObject({ data: { fileReport: null }, errors: undefined, }) @@ -139,47 +198,112 @@ describe('file a report on a resource', () => { it('which belongs to resource', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'abusive-user-id' }, }), ).resolves.toMatchObject({ data: { fileReport: { - id: expect.any(String), + reportId: expect.any(String), + resource: { + name: 'abusive-user', + }, }, }, errors: undefined, }) }) - it('creates only one report for multiple reports on the same resource', async () => { + it('only one report for multiple reports on the same resource', async () => { const firstReport = await mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'abusive-user-id' }, }) authenticatedUser = await otherReportingUser.toJson() const secondReport = await mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'abusive-user-id' }, }) - expect(firstReport.data.fileReport.id).toEqual(secondReport.data.fileReport.id) + + expect(firstReport.data.fileReport.reportId).toEqual( + secondReport.data.fileReport.reportId, + ) }) - it('returns the rule for how the report was decided', async () => { - await expect( - mutate({ - mutation: reportMutation, + describe('report properties are set correctly', () => { + const reportsCypherQuery = + 'MATCH (resource:User {id: $resourceId})<-[:BELONGS_TO]-(report:Report {closed: false})<-[filed:FILED]-(user:User {id: $currentUserId}) RETURN report' + + it('with the rule for how the report will be decided', async () => { + await mutate({ + mutation: fileReportMutation, variables: { ...variables, resourceId: 'abusive-user-id' }, - }), - ).resolves.toMatchObject({ - data: { - fileReport: { - rule: 'latestReviewUpdatedAtRules', - }, - }, - errors: undefined, + }) + + const reportsCypherQueryResponse = await instance.cypher(reportsCypherQuery, { + resourceId: 'abusive-user-id', + currentUserId: authenticatedUser.id, + }) + expect(reportsCypherQueryResponse.records).toHaveLength(1) + const [reportProperties] = reportsCypherQueryResponse.records.map( + record => record.get('report').properties, + ) + expect(reportProperties).toMatchObject({ rule: 'latestReviewUpdatedAtRules' }) + }) + + describe('with overtaken disabled from resource in disable property', () => { + it('disable is false', async () => { + await mutate({ + mutation: fileReportMutation, + variables: { ...variables, resourceId: 'abusive-user-id' }, + }) + + const reportsCypherQueryResponse = await instance.cypher(reportsCypherQuery, { + resourceId: 'abusive-user-id', + currentUserId: authenticatedUser.id, + }) + expect(reportsCypherQueryResponse.records).toHaveLength(1) + const [reportProperties] = reportsCypherQueryResponse.records.map( + record => record.get('report').properties, + ) + expect(reportProperties).toMatchObject({ disable: false }) + }) + + it('disable is true', async () => { + // first time filling a report to enable a moderator the disable the resource + await mutate({ + mutation: fileReportMutation, + variables: { ...variables, resourceId: 'abusive-user-id' }, + }) + authenticatedUser = await moderator.toJson() + await mutate({ + mutation: reviewMutation, + variables: { + resourceId: 'abusive-user-id', + disable: true, + closed: true, + }, + }) + authenticatedUser = await currentUser.toJson() + // second time filling a report to see if the "disable is true" of the resource is overtaken + await mutate({ + mutation: fileReportMutation, + variables: { ...variables, resourceId: 'abusive-user-id' }, + }) + + const reportsCypherQueryResponse = await instance.cypher(reportsCypherQuery, { + resourceId: 'abusive-user-id', + currentUserId: authenticatedUser.id, + }) + expect(reportsCypherQueryResponse.records).toHaveLength(1) + const [reportProperties] = reportsCypherQueryResponse.records.map( + record => record.get('report').properties, + ) + expect(reportProperties).toMatchObject({ disable: true }) + }) }) }) + it.todo('creates multiple filed reports') }) @@ -187,7 +311,7 @@ describe('file a report on a resource', () => { it('returns __typename "User"', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'abusive-user-id' }, }), ).resolves.toMatchObject({ @@ -205,7 +329,7 @@ describe('file a report on a resource', () => { it('returns user attribute info', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'abusive-user-id' }, }), ).resolves.toMatchObject({ @@ -221,32 +345,10 @@ describe('file a report on a resource', () => { }) }) - it('returns the submitter', async () => { + it('returns a createdAt', async () => { await expect( mutate({ - mutation: reportMutation, - variables: { ...variables, resourceId: 'abusive-user-id' }, - }), - ).resolves.toMatchObject({ - data: { - fileReport: { - filed: [ - { - submitter: { - id: 'current-user-id', - }, - }, - ], - }, - }, - errors: undefined, - }) - }) - - it('returns a date', async () => { - await expect( - mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'abusive-user-id' }, }), ).resolves.toMatchObject({ @@ -262,7 +364,7 @@ describe('file a report on a resource', () => { it('returns the reason category', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'abusive-user-id', @@ -272,11 +374,7 @@ describe('file a report on a resource', () => { ).resolves.toMatchObject({ data: { fileReport: { - filed: [ - { - reasonCategory: 'criminal_behavior_violation_german_law', - }, - ], + reasonCategory: 'criminal_behavior_violation_german_law', }, }, errors: undefined, @@ -286,7 +384,7 @@ describe('file a report on a resource', () => { it('gives an error if the reason category is not in enum "ReasonCategory"', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'abusive-user-id', @@ -307,7 +405,7 @@ describe('file a report on a resource', () => { it('returns the reason description', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'abusive-user-id', @@ -317,11 +415,7 @@ describe('file a report on a resource', () => { ).resolves.toMatchObject({ data: { fileReport: { - filed: [ - { - reasonDescription: 'My reason!', - }, - ], + reasonDescription: 'My reason!', }, }, errors: undefined, @@ -331,7 +425,7 @@ describe('file a report on a resource', () => { it('sanitizes the reason description', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'abusive-user-id', @@ -341,11 +435,7 @@ describe('file a report on a resource', () => { ).resolves.toMatchObject({ data: { fileReport: { - filed: [ - { - reasonDescription: 'My reason !', - }, - ], + reasonDescription: 'My reason !', }, }, errors: undefined, @@ -371,7 +461,7 @@ describe('file a report on a resource', () => { it('returns type "Post"', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'post-to-report-id', @@ -392,7 +482,7 @@ describe('file a report on a resource', () => { it('returns resource in post attribute', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'post-to-report-id', @@ -442,7 +532,7 @@ describe('file a report on a resource', () => { it('returns type "Comment"', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'comment-to-report-id', @@ -463,7 +553,7 @@ describe('file a report on a resource', () => { it('returns resource in comment attribute', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'comment-to-report-id', @@ -493,7 +583,7 @@ describe('file a report on a resource', () => { it('returns null', async () => { await expect( mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { ...variables, resourceId: 'tag-to-report-id', @@ -510,37 +600,6 @@ describe('file a report on a resource', () => { }) describe('query for reported resource', () => { - const reportsQuery = gql` - query { - reports(orderBy: createdAt_desc) { - id - createdAt - updatedAt - closed - resource { - __typename - ... on User { - id - } - ... on Post { - id - } - ... on Comment { - id - } - } - filed { - submitter { - id - } - createdAt - reasonCategory - reasonDescription - } - } - } - ` - beforeEach(async () => { authenticatedUser = null moderator = await Factory.build( @@ -632,7 +691,7 @@ describe('file a report on a resource', () => { authenticatedUser = await currentUser.toJson() await Promise.all([ mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { resourceId: 'abusive-post-1', reasonCategory: 'other', @@ -640,7 +699,7 @@ describe('file a report on a resource', () => { }, }), mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { resourceId: 'abusive-comment-1', reasonCategory: 'discrimination_etc', @@ -648,7 +707,7 @@ describe('file a report on a resource', () => { }, }), mutate({ - mutation: reportMutation, + mutation: fileReportMutation, variables: { resourceId: 'abusive-user-1', reasonCategory: 'doxing', diff --git a/backend/src/schema/resolvers/users.js b/backend/src/schema/resolvers/users.js index cbdc683e8..a1b68e20d 100644 --- a/backend/src/schema/resolvers/users.js +++ b/backend/src/schema/resolvers/users.js @@ -251,12 +251,12 @@ export default { boolean: { followedByCurrentUser: 'MATCH (this)<-[:FOLLOWS]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1', + isBlocked: + 'MATCH (this)<-[:BLOCKED]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1', blocked: '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: diff --git a/backend/src/schema/types/type/FILED.gql b/backend/src/schema/types/type/FILED.gql index cdce62116..85eca951e 100644 --- a/backend/src/schema/types/type/FILED.gql +++ b/backend/src/schema/types/type/FILED.gql @@ -16,3 +16,15 @@ enum ReasonCategory { advert_products_services_commercial criminal_behavior_violation_german_law } + +type FiledReport { + createdAt: String! + reasonCategory: ReasonCategory! + reasonDescription: String! + reportId: ID! + resource: ReportedResource! +} + +type Mutation { + fileReport(resourceId: ID!, reasonCategory: ReasonCategory!, reasonDescription: String!): FiledReport +} \ No newline at end of file diff --git a/backend/src/schema/types/type/REVIEWED.gql b/backend/src/schema/types/type/REVIEWED.gql index aea005abe..086d73815 100644 --- a/backend/src/schema/types/type/REVIEWED.gql +++ b/backend/src/schema/types/type/REVIEWED.gql @@ -4,7 +4,6 @@ type REVIEWED { disable: Boolean! closed: Boolean! report: Report - # @cypher(statement: "MATCH (report:Report)<-[this:REVIEWED]-(:User) RETURN report") moderator: User resource: ReviewedResource } diff --git a/backend/src/schema/types/type/Report.gql b/backend/src/schema/types/type/Report.gql index ad0015d01..9a4a48c4b 100644 --- a/backend/src/schema/types/type/Report.gql +++ b/backend/src/schema/types/type/Report.gql @@ -5,9 +5,9 @@ type Report { rule: ReportRule! disable: Boolean! closed: Boolean! - filed: [FILED] + filed: [FILED]! reviewed: [REVIEWED]! - resource: ReportedResource + resource: ReportedResource! } union ReportedResource = User | Post | Comment @@ -16,10 +16,6 @@ enum ReportRule { latestReviewUpdatedAtRules } -type Mutation { - fileReport(resourceId: ID!, reasonCategory: ReasonCategory!, reasonDescription: String!): Report -} - type Query { reports(orderBy: ReportOrdering, first: Int, offset: Int, reviewed: Boolean, closed: Boolean): [Report] } diff --git a/backend/src/schema/types/type/User.gql b/backend/src/schema/types/type/User.gql index baefc9d29..948d8e7d3 100644 --- a/backend/src/schema/types/type/User.gql +++ b/backend/src/schema/types/type/User.gql @@ -64,10 +64,11 @@ type User { # Is the currently logged in user following that user? followedByCurrentUser: Boolean! @cypher( statement: """ - MATCH (this)<-[: FOLLOWS]-(u: User { id: $cypherParams.currentUserId}) + MATCH (this)<-[:FOLLOWS]-(u:User { id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1 """ ) + isBlocked: Boolean! @cypher( statement: """ MATCH (this)<-[:BLOCKED]-(user:User {id: $cypherParams.currentUserId}) diff --git a/backend/yarn.lock b/backend/yarn.lock index b4d497ac5..46367d580 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -56,27 +56,27 @@ dependencies: "@babel/highlight" "^7.8.3" -"@babel/compat-data@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.8.4.tgz#bbe65d05a291667a8394fe8a0e0e277ef22b0d2a" - integrity sha512-lHLhlsvFjJAqNU71b7k6Vv9ewjmTXKvqaMv7n0G1etdCabWLw3nEYE8mmgoVOxMIFE07xOvo7H7XBASirX6Rrg== +"@babel/compat-data@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.8.6.tgz#7eeaa0dfa17e50c7d9c0832515eee09b56f04e35" + integrity sha512-CurCIKPTkS25Mb8mz267vU95vy+TyUpnctEX2lV33xWNmHAfjruztgiPBbXZRh3xZZy1CYvGx6XfxyTVS+sk7Q== dependencies: browserslist "^4.8.5" invariant "^2.2.4" semver "^5.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.7.5", "@babel/core@~7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e" - integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA== +"@babel/core@^7.1.0", "@babel/core@^7.7.5", "@babel/core@~7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.6.tgz#27d7df9258a45c2e686b6f18b6c659e563aa4636" + integrity sha512-Sheg7yEJD51YHAvLEV/7Uvw95AeWqYPL3Vk3zGujJKIhJ+8oLw2ALaf3hbucILhKsgSoADOvtKRJuNVdcJkOrg== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.4" + "@babel/generator" "^7.8.6" "@babel/helpers" "^7.8.4" - "@babel/parser" "^7.8.4" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.4" - "@babel/types" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/template" "^7.8.6" + "@babel/traverse" "^7.8.6" + "@babel/types" "^7.8.6" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" @@ -86,12 +86,12 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e" - integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA== +"@babel/generator@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.6.tgz#57adf96d370c9a63c241cd719f9111468578537a" + integrity sha512-4bpOR5ZBz+wWcMeVtcf7FbjcFzCp+817z2/gHNncIRcM9MmKzUhtWCYAq27RAfUrAFwb+OCG1s9WEaVxfi6cjg== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.8.6" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" @@ -120,12 +120,12 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helper-compilation-targets@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.4.tgz#03d7ecd454b7ebe19a254f76617e61770aed2c88" - integrity sha512-3k3BsKMvPp5bjxgMdrFyq0UaEO48HciVrOVF0+lon8pp95cyJ2ujAh0TrBHNMnJGT2rr0iKOJPFFbSqjDyf/Pg== +"@babel/helper-compilation-targets@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.6.tgz#015b85db69e3a34240d5c2b761fc53eb9695f09c" + integrity sha512-UrJdk27hKVJSnibFcUWYLkCL0ZywTUoot8yii1lsHJcvwrypagmYKjHLMWivQPm4s6GdyygCL8fiH5EYLxhQwQ== dependencies: - "@babel/compat-data" "^7.8.4" + "@babel/compat-data" "^7.8.6" browserslist "^4.8.5" invariant "^2.2.4" levenary "^1.1.1" @@ -245,6 +245,16 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/helper-replace-supers@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" + integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.8.6" + "@babel/types" "^7.8.6" + "@babel/helper-simple-access@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" @@ -302,10 +312,10 @@ resolve "^1.13.1" v8flags "^3.1.1" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.7.5", "@babel/parser@^7.8.3", "@babel/parser@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8" - integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw== +"@babel/parser@^7.1.0", "@babel/parser@^7.7.0", "@babel/parser@^7.7.5", "@babel/parser@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.6.tgz#ba5c9910cddb77685a008e3c587af8d27b67962c" + integrity sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g== "@babel/plugin-proposal-async-generator-functions@^7.8.3": version "7.8.3" @@ -481,17 +491,17 @@ "@babel/helper-plugin-utils" "^7.8.3" lodash "^4.17.13" -"@babel/plugin-transform-classes@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8" - integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w== +"@babel/plugin-transform-classes@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.6.tgz#77534447a477cbe5995ae4aee3e39fbc8090c46d" + integrity sha512-k9r8qRay/R6v5aWZkrEclEhKO6mc1CCQr2dLsVHBmOQiMpN6I2bpjX3vgnldUWeEI1GHVNByULVxZ4BdP4Hmdg== dependencies: "@babel/helper-annotate-as-pure" "^7.8.3" "@babel/helper-define-map" "^7.8.3" "@babel/helper-function-name" "^7.8.3" "@babel/helper-optimise-call-expression" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" "@babel/helper-split-export-declaration" "^7.8.3" globals "^11.1.0" @@ -532,10 +542,10 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-for-of@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz#6fe8eae5d6875086ee185dd0b098a8513783b47d" - integrity sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A== +"@babel/plugin-transform-for-of@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.6.tgz#a051bd1b402c61af97a27ff51b468321c7c2a085" + integrity sha512-M0pw4/1/KI5WAxPsdcUL/w2LJ7o89YHN3yLkzNjg7Yl15GlVGgzHyCU+FMeAxevHGsLVmUqbirlUIKTafPmzdw== dependencies: "@babel/helper-plugin-utils" "^7.8.3" @@ -695,13 +705,13 @@ "@babel/helper-create-regexp-features-plugin" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/preset-env@~7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.4.tgz#9dac6df5f423015d3d49b6e9e5fa3413e4a72c4e" - integrity sha512-HihCgpr45AnSOHRbS5cWNTINs0TwaR8BS8xIIH+QwiW8cKL0llV91njQMpeMReEPVs+1Ao0x3RLEBLtt1hOq4w== +"@babel/preset-env@~7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.6.tgz#2a0773b08589ecba4995fc71b1965e4f531af40b" + integrity sha512-M5u8llV9DIVXBFB/ArIpqJuvXpO+ymxcJ6e8ZAmzeK3sQeBNOD1y+rHvHCGG4TlEmsNpIrdecsHGHT8ZCoOSJg== dependencies: - "@babel/compat-data" "^7.8.4" - "@babel/helper-compilation-targets" "^7.8.4" + "@babel/compat-data" "^7.8.6" + "@babel/helper-compilation-targets" "^7.8.6" "@babel/helper-module-imports" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-proposal-async-generator-functions" "^7.8.3" @@ -724,13 +734,13 @@ "@babel/plugin-transform-async-to-generator" "^7.8.3" "@babel/plugin-transform-block-scoped-functions" "^7.8.3" "@babel/plugin-transform-block-scoping" "^7.8.3" - "@babel/plugin-transform-classes" "^7.8.3" + "@babel/plugin-transform-classes" "^7.8.6" "@babel/plugin-transform-computed-properties" "^7.8.3" "@babel/plugin-transform-destructuring" "^7.8.3" "@babel/plugin-transform-dotall-regex" "^7.8.3" "@babel/plugin-transform-duplicate-keys" "^7.8.3" "@babel/plugin-transform-exponentiation-operator" "^7.8.3" - "@babel/plugin-transform-for-of" "^7.8.4" + "@babel/plugin-transform-for-of" "^7.8.6" "@babel/plugin-transform-function-name" "^7.8.3" "@babel/plugin-transform-literals" "^7.8.3" "@babel/plugin-transform-member-expression-literals" "^7.8.3" @@ -751,17 +761,17 @@ "@babel/plugin-transform-template-literals" "^7.8.3" "@babel/plugin-transform-typeof-symbol" "^7.8.4" "@babel/plugin-transform-unicode-regex" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/types" "^7.8.6" browserslist "^4.8.5" core-js-compat "^3.6.2" invariant "^2.2.2" levenary "^1.1.1" semver "^5.5.0" -"@babel/register@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.8.3.tgz#5d5d30cfcc918437535d724b8ac1e4a60c5db1f8" - integrity sha512-t7UqebaWwo9nXWClIPLPloa5pN33A2leVs8Hf0e9g9YwUP8/H9NeR7DJU+4CXo23QtjChQv5a3DjEtT83ih1rg== +"@babel/register@^7.8.3", "@babel/register@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.8.6.tgz#a1066aa6168a73a70c35ef28cc5865ccc087ea69" + integrity sha512-7IDO93fuRsbyml7bAafBQb3RcBGlCpU4hh5wADA2LJEEcYk92WkwFZ0pHyIi2fb5Auoz1714abETdZKCOxN0CQ== dependencies: find-cache-dir "^2.0.0" lodash "^4.17.13" @@ -769,7 +779,7 @@ pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/runtime-corejs2@^7.2.0", "@babel/runtime-corejs2@^7.5.5": +"@babel/runtime-corejs2@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.5.5.tgz#c3214c08ef20341af4187f1c9fbdc357fbec96b2" integrity sha512-FYATQVR00NSNi7mUfpPDp7E8RYMXDuO8gaix7u/w3GekfUinKgX1AcTxs7SoiEmoEW9mbpjrwqWSW6zCmw5h8A== @@ -777,6 +787,14 @@ core-js "^2.6.5" regenerator-runtime "^0.13.2" +"@babel/runtime-corejs3@^7.8.3": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.8.4.tgz#ccc4e042e2fae419c67fa709567e5d2179ed3940" + integrity sha512-+wpLqy5+fbQhvbllvlJEVRIpYj+COUWnnsm+I4jZlA8Lo7/MJmBhGTCHyk1/RWfOqBRJ2MbadddG6QltTKTlrg== + dependencies: + core-js-pure "^3.0.0" + regenerator-runtime "^0.13.2" + "@babel/runtime@^7.0.0", "@babel/runtime@^7.5.5": version "7.6.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.2.tgz#c3d6e41b304ef10dcf13777a33e7694ec4a9a6dd" @@ -784,34 +802,34 @@ dependencies: regenerator-runtime "^0.13.2" -"@babel/template@^7.7.4", "@babel/template@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" - integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ== +"@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" + integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/types" "^7.8.6" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.7.4", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c" - integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.4", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4", "@babel/traverse@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.6.tgz#acfe0c64e1cd991b3e32eae813a6eb564954b5ff" + integrity sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.4" + "@babel/generator" "^7.8.6" "@babel/helper-function-name" "^7.8.3" "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.8.4" - "@babel/types" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/types" "^7.8.6" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.13" -"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" - integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== +"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.6.tgz#629ecc33c2557fcde7126e58053127afdb3e6d01" + integrity sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA== dependencies: esutils "^2.0.2" lodash "^4.17.13" @@ -862,11 +880,6 @@ resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.2.tgz#1c794cd6dbf2354d1eb1ef10e0303f573e1c7222" integrity sha512-O4QDrx+JoGKZc6aN64L04vqa7e41tIiLU+OvKdcYaEMP97UttL0f9GIi9/0A4WAMx0uBd6SidDIhktZhgOcN8Q== -"@hapi/address@^2.1.2": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" - integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== - "@hapi/address@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-4.0.0.tgz#36affb4509b5a6adc628bcc394450f2a7d51d111" @@ -879,11 +892,6 @@ resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a" integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== -"@hapi/formula@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@hapi/formula/-/formula-1.2.0.tgz#994649c7fea1a90b91a0a1e6d983523f680e10cd" - integrity sha512-UFbtbGPjstz0eWHb+ga/GM3Z9EzqKXFWIbSOFURU0A/Gku0Bky4bCk9/h//K2Xr3IrCfjFNhMm4jyZ5dbCewGA== - "@hapi/formula@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@hapi/formula/-/formula-2.0.0.tgz#edade0619ed58c8e4f164f233cda70211e787128" @@ -894,11 +902,6 @@ resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.2.4.tgz#684a14f4ca35d46f44abc87dfc696e5e4fe8a020" integrity sha512-Ze5SDNt325yZvNO7s5C4fXDscjJ6dcqLFXJQ/M7dZRQCewuDj2iDUuBi6jLQt+APbW9RjjVEvLr35FXuOEqjow== -"@hapi/hoek@^8.2.4", "@hapi/hoek@^8.3.0": - version "8.5.0" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.0.tgz#2f9ce301c8898e1c3248b0a8564696b24d1a9a5a" - integrity sha512-7XYT10CZfPsH7j9F1Jmg1+d0ezOux2oM2GfArAzLwWe4mE2Dr3hVjsAL6+TFY49RRJlCdJDMw3nJsLFroTc8Kw== - "@hapi/hoek@^9.0.0": version "9.0.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.0.0.tgz#ba83436edfac1d1ffd0e94797d43419c20ad49b8" @@ -914,17 +917,6 @@ "@hapi/hoek" "8.x.x" "@hapi/topo" "3.x.x" -"@hapi/joi@^16.1.8": - version "16.1.8" - resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-16.1.8.tgz#84c1f126269489871ad4e2decc786e0adef06839" - integrity sha512-wAsVvTPe+FwSrsAurNt5vkg3zo+TblvC5Bb1zMVK6SJzZqw9UrJnexxR+76cpePmtUZKHAPxcQ2Bf7oVHyahhg== - dependencies: - "@hapi/address" "^2.1.2" - "@hapi/formula" "^1.2.0" - "@hapi/hoek" "^8.2.4" - "@hapi/pinpoint" "^1.0.2" - "@hapi/topo" "^3.1.3" - "@hapi/joi@^17.1.0": version "17.1.0" resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-17.1.0.tgz#cc4000b6c928a6a39b9bef092151b6bdee10ce55" @@ -936,11 +928,6 @@ "@hapi/pinpoint" "^2.0.0" "@hapi/topo" "^5.0.0" -"@hapi/pinpoint@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@hapi/pinpoint/-/pinpoint-1.0.2.tgz#025b7a36dbbf4d35bf1acd071c26b20ef41e0d13" - integrity sha512-dtXC/WkZBfC5vxscazuiJ6iq4j9oNx1SHknmIr8hofarpKUZKmlUVYVIhNVzIEgK5Wrc4GMHL5lZtt1uS2flmQ== - "@hapi/pinpoint@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@hapi/pinpoint/-/pinpoint-2.0.0.tgz#805b40d4dbec04fc116a73089494e00f073de8df" @@ -953,13 +940,6 @@ dependencies: "@hapi/hoek" "8.x.x" -"@hapi/topo@^3.1.3": - version "3.1.6" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29" - integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ== - dependencies: - "@hapi/hoek" "^8.3.0" - "@hapi/topo@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.0.0.tgz#c19af8577fa393a06e9c77b60995af959be721e7" @@ -1175,7 +1155,7 @@ url-regex "~4.1.1" video-extensions "~1.1.0" -"@metascraper/helpers@^5.10.7", "@metascraper/helpers@^5.11.1": +"@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== @@ -1275,83 +1255,83 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= -"@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== +"@sentry/apm@5.13.1": + version "5.13.1" + resolved "https://registry.yarnpkg.com/@sentry/apm/-/apm-5.13.1.tgz#152a7a54b06f344112477cb376e8554860a6af86" + integrity sha512-be6M8/TOA/K7jQNZEm1YC0Y9+LdM0jyX5LMwy9NWwhneE6Iq8xvsU/pYZByj6+AAs0tIpiFd9QFxFKNUtKIRUQ== dependencies: - "@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" + "@sentry/browser" "5.13.0" + "@sentry/hub" "5.13.0" + "@sentry/minimal" "5.13.0" + "@sentry/types" "5.12.4" + "@sentry/utils" "5.13.0" tslib "^1.9.3" -"@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== +"@sentry/browser@5.13.0": + version "5.13.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.13.0.tgz#399b0a09d6603726d787b746bcc70659010bc50c" + integrity sha512-adiW9gG/gCrl6FQAA6Fk8osXMHxP3pYltszRK0mr55O7GcTC8RQNI3mEW/YuQV9IySUL8dFWQ0v8n0lfssHf/A== dependencies: - "@sentry/core" "5.12.0" - "@sentry/types" "5.12.0" - "@sentry/utils" "5.12.0" + "@sentry/core" "5.13.0" + "@sentry/types" "5.12.4" + "@sentry/utils" "5.13.0" tslib "^1.9.3" -"@sentry/core@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.12.0.tgz#d6380c4ef7beee5f418ac1d0e5be86a2de2af449" - integrity sha512-wY4rsoX71QsGpcs9tF+OxKgDPKzIFMRvFiSRcJoPMfhFsTilQ/CBMn/c3bDtWQd9Bnr/ReQIL6NbnIjUsPHA4Q== +"@sentry/core@5.13.0": + version "5.13.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.13.0.tgz#144beb2d48b53244774a7fd809f9b5b672920971" + integrity sha512-e0olbaHBmANO1RIBc7xynSkBZ6BsK7drycz0TawLUnx+0H3aEau3K9U2QVdbjwLNPdydcIS+UgYfTBtXfe0E+A== dependencies: - "@sentry/hub" "5.12.0" - "@sentry/minimal" "5.12.0" - "@sentry/types" "5.12.0" - "@sentry/utils" "5.12.0" + "@sentry/hub" "5.13.0" + "@sentry/minimal" "5.13.0" + "@sentry/types" "5.12.4" + "@sentry/utils" "5.13.0" tslib "^1.9.3" -"@sentry/hub@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.12.0.tgz#5e8c8f249f5bdbeb8cc4ec02c2ccc53a67f2cc02" - integrity sha512-3k7yE8BEVJsKx8mR4LcI4IN0O8pngmq44OcJ/fRUUBAPqsT38jsJdP2CaWhdlM1jiNUzUDB1ktBv6/lY+VgcoQ== +"@sentry/hub@5.13.0": + version "5.13.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.13.0.tgz#f48e3e4e273f40316391cd6190e22ea69cb20c7e" + integrity sha512-MeytooJ5g91zxq4/LU1LHj7KxpggAEn1dybEsWG31QVy67J4a40zIGfYgGGIVAFSv0WVlk5Ei5C159LhgW59/w== dependencies: - "@sentry/types" "5.12.0" - "@sentry/utils" "5.12.0" + "@sentry/types" "5.12.4" + "@sentry/utils" "5.13.0" tslib "^1.9.3" -"@sentry/minimal@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.12.0.tgz#2611e2aa520c1edb7999e6de51bd65ec66341757" - integrity sha512-fk73meyz4k4jCg9yzbma+WkggsfEIQWI2e2TWfYsRGcrV3RnlSrXyM4D91/A8Bjx10SNezHPUFHjasjlHXOkyA== +"@sentry/minimal@5.13.0": + version "5.13.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.13.0.tgz#ee906191e3c2a1f7d0925fbfa0a4e96261013764" + integrity sha512-6D2Mu4TrmJmGlvb+z1Pp6yI2fUmdY1RvwK0MqmBP+QJdrd0as7cpGuwFSXgUs6CLUflDzlpn3n6WcgGV8oEDYA== dependencies: - "@sentry/hub" "5.12.0" - "@sentry/types" "5.12.0" + "@sentry/hub" "5.13.0" + "@sentry/types" "5.12.4" tslib "^1.9.3" -"@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== +"@sentry/node@^5.13.1": + version "5.13.1" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.13.1.tgz#41d2eec02bc718a0f5aa59698635242d585470f2" + integrity sha512-6/HaewN2kX0za3LncYwp6nlvm/6i0S0/D/HO7VDHMSpc8z/8/Em6xTZy7hLV3phosMoLIa5P3CRXvLVybBTrpg== dependencies: - "@sentry/apm" "5.12.3" - "@sentry/core" "5.12.0" - "@sentry/hub" "5.12.0" - "@sentry/types" "5.12.0" - "@sentry/utils" "5.12.0" + "@sentry/apm" "5.13.1" + "@sentry/core" "5.13.0" + "@sentry/hub" "5.13.0" + "@sentry/types" "5.12.4" + "@sentry/utils" "5.13.0" cookie "^0.3.1" https-proxy-agent "^4.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/types@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.12.0.tgz#5367e53c74261beea01502e3f7b6f3d822682a31" - integrity sha512-aZbBouBLrKB8wXlztriIagZNmsB+wegk1Jkl6eprqRW/w24Sl/47tiwH8c5S4jYTxdAiJk+SAR10AAuYmIN3zg== +"@sentry/types@5.12.4": + version "5.12.4" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.12.4.tgz#6e52639bc3b4e136e9a0da5385890f8f78bb7697" + integrity sha512-JoN3YIp7Z+uxUZArj2B6NcEoXFQDhd0kqO0QpfiHZyg4Dhx2/E2aHuVx0H6Fndk+60iEZSECaCBXe2MOPo4fqA== -"@sentry/utils@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.12.0.tgz#62967f934a3ee6d21472eac0219084e37225933e" - integrity sha512-fYUadGLbfTCbs4OG5hKCOtv2jrNE4/8LHNABy9DwNJ/t5DVtGqWAZBnxsC+FG6a3nVqCpxjFI9AHlYsJ2wsf7Q== +"@sentry/utils@5.13.0": + version "5.13.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.13.0.tgz#6463e53b6178dbbd3b90e671517cbca82744b055" + integrity sha512-BcmNQN+IfFbVWGnEwXHku69zqJc97sjBRYVxpStKMaO/4aLVIQcOJCMWxVJtVoSVAHQaigBZmFutWH7EJMRJxg== dependencies: - "@sentry/types" "5.12.0" + "@sentry/types" "5.12.4" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": @@ -1607,10 +1587,10 @@ dependencies: "@types/yargs-parser" "*" -"@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/yup@0.26.32": + version "0.26.32" + resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.32.tgz#bd356fb405f3d641eff963854edf7ad854a8e829" + integrity sha512-55WFAq8lNYXdRzSP1cenMFFXtPRe7PWsqn5y9ibqKHOQZ/cSLErkcnB1LE89M7W2TSXVDFtx+T7eFePkGoB+xw== "@types/zen-observable@^0.8.0": version "0.8.0" @@ -1943,7 +1923,7 @@ apollo-server-caching@^0.5.1: dependencies: lru-cache "^5.0.0" -apollo-server-core@^2.10.0, apollo-server-core@^2.10.1: +apollo-server-core@^2.10.1: version "2.10.1" resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.10.1.tgz#5fa4ce7992d0bf1cce616dedf1a22a41c7589c7c" integrity sha512-BVITSJRMnj+CWFkjt7FMcaoqg/Ni9gfyVE9iu8bUc1IebBfFDcQj652Iolr7dTqyUziN2jbf0wfcybKYJLQHQQ== @@ -1983,10 +1963,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.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== +apollo-server-express@^2.10.1, apollo-server-express@^2.9.16: + version "2.10.1" + resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.10.1.tgz#f48b3c59ebb904d1048c80d2bc23ad8878579457" + integrity sha512-NkuWGBOCTiju/aDjfvDImm+4yzfrM0dwiRxu9fKwwh2h1oYBUKJNqjQ1mzJRi0ks6Sn1egwl/fQkTBTkWwGx7Q== dependencies: "@apollographql/graphql-playground-html" "1.6.24" "@types/accepts" "^1.3.5" @@ -1994,7 +1974,7 @@ apollo-server-express@^2.10.0, apollo-server-express@^2.9.16: "@types/cors" "^2.8.4" "@types/express" "4.17.2" accepts "^1.3.5" - apollo-server-core "^2.10.0" + apollo-server-core "^2.10.1" apollo-server-types "^0.2.10" body-parser "^1.18.3" cors "^2.8.4" @@ -2028,13 +2008,13 @@ apollo-server-types@^0.2.10: apollo-server-caching "^0.5.1" apollo-server-env "^2.4.3" -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== +apollo-server@~2.10.1: + version "2.10.1" + resolved "https://registry.yarnpkg.com/apollo-server/-/apollo-server-2.10.1.tgz#54245d772fab146fa1f5fd78d65ae5d4aa573e55" + integrity sha512-YZrujwOPCr5zqpoMfG/NB0dwOISLqzArChBre3o9xwGYXS5DQwfFDiSLTXBYhT9JSYIkDPZ8SJKeEWS961Pavw== dependencies: - apollo-server-core "^2.10.0" - apollo-server-express "^2.10.0" + apollo-server-core "^2.10.1" + apollo-server-express "^2.10.1" express "^4.0.0" graphql-subscriptions "^1.0.0" graphql-tools "^4.0.0" @@ -2125,11 +2105,6 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-uniq@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -2250,15 +2225,15 @@ babel-core@~7.0.0-0: resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg== -babel-eslint@~10.0.3: - version "10.0.3" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" - integrity sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA== +babel-eslint@~10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" + integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" + "@babel/parser" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" eslint-visitor-keys "^1.0.0" resolve "^1.12.0" @@ -2400,10 +2375,10 @@ boolbase@~1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= -bowser@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.7.0.tgz#96eab1fa07fab08c1ec4c75977a7c8ddf8e0fe1f" - integrity sha512-aIlMvstvu8x+34KEiOHD3AsBgdrzg6sxALYiukOWhFvGMbQI6TRP/iY0LMhUrHs56aD6P1G0Z7h45PUJaa5m9w== +bowser@2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.9.0.tgz#3bed854233b419b9a7422d9ee3e85504373821c9" + integrity sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA== boxen@^1.2.1: version "1.3.0" @@ -2962,6 +2937,11 @@ core-js-compat@^3.6.2: browserslist "^4.8.3" semver "7.0.0" +core-js-pure@^3.0.0: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.4.tgz#4bf1ba866e25814f149d4e9aaa08c36173506e3a" + integrity sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw== + core-js@^2.4.0, core-js@^2.6.5: version "2.6.9" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" @@ -3140,10 +3120,10 @@ data-urls@^1.1.0: whatwg-mimetype "^2.2.0" whatwg-url "^7.0.0" -date-fns@2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.9.0.tgz#d0b175a5c37ed5f17b97e2272bbc1fa5aec677d2" - integrity sha512-khbFLu/MlzLjEzy9Gh8oY1hNt/Dvxw3J6Rbc28cVoYWQaC1S3YI4xwkF9ZWcjDLscbZlY9hISMr66RFzZagLsA== +date-fns@2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.10.0.tgz#abd10604d8bafb0bcbd2ba2e9b0563b922ae4b6b" + integrity sha512-EhfEKevYGWhWlZbNeplfhIU/+N+x0iCIx7VzKlXma2EdQyznVlZhCptXUY+BegNpPW2kjdx15Rvq503YcXXrcA== dateformat@^2.0.0: version "2.2.0" @@ -3346,6 +3326,14 @@ dom-serializer@0: domelementtype "^2.0.1" entities "^2.0.0" +dom-serializer@^0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + dom-serializer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" @@ -3378,6 +3366,13 @@ domhandler@^2.3.0: dependencies: domelementtype "1" +domhandler@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.0.0.tgz#51cd13efca31da95bbb0c5bee3a48300e333b3e9" + integrity sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw== + dependencies: + domelementtype "^2.0.1" + domutils@1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" @@ -3394,6 +3389,15 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" +domutils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.0.0.tgz#15b8278e37bfa8468d157478c58c367718133c08" + integrity sha512-n5SelJ1axbO636c2yUtOGia/IcJtVtlhQbFiVDBZHKV5ReJO1ViX7sFEemtuyoAnBxk5meNSYgA8V4s0271efg== + dependencies: + dom-serializer "^0.2.1" + domelementtype "^2.0.1" + domhandler "^3.0.0" + dont-sniff-mimetype@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz#c7d0427f8bcb095762751252af59d148b0a623b2" @@ -3653,10 +3657,10 @@ eslint-plugin-import@~2.20.1: read-pkg-up "^2.0.0" resolve "^1.12.0" -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== +eslint-plugin-jest@~23.8.1: + version "23.8.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.8.1.tgz#247025e8a51b3a25a4cc41166369b0bfb4db83b7" + integrity sha512-OycLNqPo/2EfO6kTqnmsu1khz1gTIOxGl3ThIVwL5/oycDF4pm5uNDyvFelNLdpr4COUuM8PVi3963NEG1Efpw== dependencies: "@typescript-eslint/experimental-utils" "^2.5.0" @@ -4494,14 +4498,14 @@ graphql-redis-subscriptions@^2.1.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== +graphql-shield@~7.0.14: + version "7.0.14" + resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-7.0.14.tgz#3cbbf2722f2e3393fed7f47d866a1324bc3ce76a" + integrity sha512-YVedaL+4pITisSGRqMVeGX8ydOLSTQlHQN6o0Jly7z2cSy1wOzGJIRpfofETJtGLhBnPHHy1otINzuAyjGJO/g== dependencies: - "@types/yup" "0.26.30" - object-hash "^2.0.0" - yup "^0.28.0" + "@types/yup" "0.26.32" + object-hash "^2.0.3" + yup "^0.28.1" graphql-subscriptions@^1.0.0: version "1.1.0" @@ -4658,20 +4662,20 @@ helmet-crossdomain@0.4.0: resolved "https://registry.yarnpkg.com/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz#5f1fe5a836d0325f1da0a78eaa5fd8429078894e" integrity sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA== -helmet-csp@2.9.4: - version "2.9.4" - resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.9.4.tgz#801382bac98f2f88706dc5c89d95c7e31af3a4a9" - integrity sha512-qUgGx8+yk7Xl8XFEGI4MFu1oNmulxhQVTlV8HP8tV3tpfslCs30OZz/9uQqsWPvDISiu/NwrrCowsZBhFADYqg== +helmet-csp@2.9.5: + version "2.9.5" + resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.9.5.tgz#ea1ebec6d481e8f9aa5f48cc4ca2714e031f627d" + integrity sha512-w9nps5adqFQwgktVPDbXkARmZot/nr8aegzQas9AXdBSwBFBBefPpDSTV0wtgHlAUdDwY6MZo7qAl9yts3ppJg== dependencies: - bowser "^2.7.0" + bowser "2.9.0" camelize "1.0.0" content-security-policy-builder "2.1.0" dasherize "2.0.0" -helmet@~3.21.2: - version "3.21.2" - resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.21.2.tgz#7e2a19d5f6d898a77b5d2858e8e4bb2cda59f19f" - integrity sha512-okUo+MeWgg00cKB8Csblu8EXgcIoDyb5ZS/3u0W4spCimeVuCUvVZ6Vj3O2VJ1Sxpyb8jCDvzu0L1KKT11pkIg== +helmet@~3.21.3: + version "3.21.3" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.21.3.tgz#15777aae82a4d2678c104fd18195a4012f429b67" + integrity sha512-8OjGNdpG3WQhPO71fSy2fT4X3FSNutU1LDeAf+YS+Vil6r+fE7w8per5mNed6egGYbZl3QhKXgFzMYSwys+YQw== dependencies: depd "2.0.0" dns-prefetch-control "0.2.0" @@ -4680,7 +4684,7 @@ helmet@~3.21.2: feature-policy "0.3.0" frameguard "3.1.0" helmet-crossdomain "0.4.0" - helmet-csp "2.9.4" + helmet-csp "2.9.5" hide-powered-by "1.1.0" hpkp "2.0.0" hsts "2.2.0" @@ -4740,7 +4744,7 @@ html-to-text@^5.1.1: lodash "^4.17.11" minimist "^1.2.0" -htmlparser2@^3.10.0, htmlparser2@^3.10.1, htmlparser2@^3.9.1: +htmlparser2@^3.10.1, htmlparser2@^3.9.1: version "3.10.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== @@ -4752,6 +4756,16 @@ htmlparser2@^3.10.0, htmlparser2@^3.10.1, htmlparser2@^3.9.1: inherits "^2.0.1" readable-stream "^3.1.1" +htmlparser2@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.1.0.tgz#9a4ef161f2e4625ebf7dfbe6c0a2f52d18a59e78" + integrity sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q== + dependencies: + domelementtype "^2.0.1" + domhandler "^3.0.0" + domutils "^2.0.0" + entities "^2.0.0" + http-cache-semantics@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5" @@ -4938,10 +4952,10 @@ 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== +ioredis@^4.16.0, ioredis@^4.6.3: + version "4.16.0" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.16.0.tgz#44d51288e20da14e5b6f687b2db0312e69106556" + integrity sha512-tlalhtuvnxXJNtrPjec1nGicuOCpi9ErYV/fRfwaWSzktX9ESrzHlcFwj1pVAL326E8dmt7h9pPQZyyVPPksRA== dependencies: cluster-key-slot "^1.1.0" debug "^4.1.1" @@ -5988,6 +6002,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash-es@^4.17.11: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" + integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== + lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -6204,12 +6223,12 @@ metascraper-audio@^5.11.1: dependencies: "@metascraper/helpers" "^5.11.1" -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== +metascraper-author@^5.11.1: + version "5.11.1" + resolved "https://registry.yarnpkg.com/metascraper-author/-/metascraper-author-5.11.1.tgz#8abe6bcc21f5a72e481d6b4ff33b008ec740fdb0" + integrity sha512-VkduGrQd3baLoypCZV0zJwutdj7Dqpj3Oi8sdM6wSo0AJDiUD1oUbeQafJ6W616zqXFIeEANS35gARBFtHupog== dependencies: - "@metascraper/helpers" "^5.10.7" + "@metascraper/helpers" "^5.11.1" lodash "~4.17.15" metascraper-clearbit-logo@^5.3.0: @@ -6219,19 +6238,19 @@ metascraper-clearbit-logo@^5.3.0: dependencies: got "~9.6.0" -metascraper-date@^5.10.7: - version "5.10.7" - resolved "https://registry.yarnpkg.com/metascraper-date/-/metascraper-date-5.10.7.tgz#580891d98f14438658610d951e5454a0658eb5f3" - integrity sha512-S1ZsvYrOccS6EGvlAJT7Ph08uRgIE+aYlTRSCR8wG8P0j0Ta/srUKbPySxv+xXqDXuRIChtErSIsBgORg8uNjg== +metascraper-date@^5.11.1: + version "5.11.1" + resolved "https://registry.yarnpkg.com/metascraper-date/-/metascraper-date-5.11.1.tgz#30aee414aca075fb671069abc3423b39e5972af3" + integrity sha512-lIvUPFaLkW0A7LTuoaaz3sVxk7SYvt8+sDWGxiRAOiN2nJJJkg2H7xN6SFDiFafBFjipeOglveGAhe8Ktc//qg== dependencies: - "@metascraper/helpers" "^5.10.7" + "@metascraper/helpers" "^5.11.1" -metascraper-description@^5.11.0: - version "5.11.0" - resolved "https://registry.yarnpkg.com/metascraper-description/-/metascraper-description-5.11.0.tgz#1f7edfae7ffc353512975cafaa5b862fc5141709" - integrity sha512-or62L9EbIwBxjsu6gShTKi1z1XQ4Hvml8MrdydL4tiSUJpwf+lXc6gVOP8+nlKPPRkiAhXt2M9k4mfkGoX0erQ== +metascraper-description@^5.11.1: + version "5.11.1" + resolved "https://registry.yarnpkg.com/metascraper-description/-/metascraper-description-5.11.1.tgz#55a90f165e73dae9289fb922e5269f902cc57d6b" + integrity sha512-xClk2kxYYeAY5yHgrUXQXiSz8I6qa3JNPietWIk4dtUQ+DxHyUOBo6B6pQmlbfX/BjCLh35m0srAqzZ7+r1s2g== dependencies: - "@metascraper/helpers" "^5.10.7" + "@metascraper/helpers" "^5.11.1" metascraper-image@^5.11.1: version "5.11.1" @@ -6249,74 +6268,74 @@ metascraper-lang-detector@^4.10.2: franc "~4.0.0" iso-639-3 "~1.1.0" -metascraper-lang@^5.10.7: - version "5.10.7" - resolved "https://registry.yarnpkg.com/metascraper-lang/-/metascraper-lang-5.10.7.tgz#fe07c359b757ef3c5ba0a330da97173945196fde" - integrity sha512-ulLq7g+X4F9XzoScNflkhwWUuoSycbOqJ8j7vT6E/sHYPid+BdUnw2yaxAqXOdsrsbUEWzkiDwrJiq37XWCpDA== +metascraper-lang@^5.11.1: + version "5.11.1" + resolved "https://registry.yarnpkg.com/metascraper-lang/-/metascraper-lang-5.11.1.tgz#494d080f30c76bfe2d10ce2c50a55f64bd534e1d" + integrity sha512-g0XjUFbaMwKa5ws09/gJj5WOM6FsB2v0P9gWLIj2bYo9+QXXGZqn9MusYXGMHiCNELkesPyFXQY8oTjJ7z2hMA== dependencies: - "@metascraper/helpers" "^5.10.7" + "@metascraper/helpers" "^5.11.1" -metascraper-logo@^5.10.7: - version "5.10.7" - resolved "https://registry.yarnpkg.com/metascraper-logo/-/metascraper-logo-5.10.7.tgz#335812b9aae5d814b22294cdd402d62fa14a46f1" - integrity sha512-Ic9WgvRqm3pUlsMfSirzCK9+qmQ9pbv/u9APn8PM5y66zNJoSCOVWbEIoEA0bVPHbGKGKFvsgrOm3VkMoVUF0Q== +metascraper-logo@^5.11.1: + version "5.11.1" + resolved "https://registry.yarnpkg.com/metascraper-logo/-/metascraper-logo-5.11.1.tgz#09a2c3c3c29a8447efbf4971370a6ec68494c1f5" + integrity sha512-B2QwyNea5dIZc3oSm2pfxEPaMeDeri0kLOumgNayGykSnqNHcCNpGhJUKxh6oeWOELcWc8nPv74a96xvz9YX3Q== dependencies: - "@metascraper/helpers" "^5.10.7" + "@metascraper/helpers" "^5.11.1" -metascraper-publisher@^5.10.7: - version "5.10.7" - resolved "https://registry.yarnpkg.com/metascraper-publisher/-/metascraper-publisher-5.10.7.tgz#7add40be1625a4215e2ec36dedaaaf213c1870e2" - integrity sha512-aRws5ksH+gzb49nc41oJdoJS2jG/2vC3GCi68n4Evy/TL7TYCnbZXqcgT5U0ne1kFxCZlHB6rl0DcXkx/JlT5Q== +metascraper-publisher@^5.11.1: + version "5.11.1" + resolved "https://registry.yarnpkg.com/metascraper-publisher/-/metascraper-publisher-5.11.1.tgz#997ffca0efb27f616cbab1c065bf5912037f1980" + integrity sha512-NaZQtdwDT6s5eZyD7p+L/9JcEBMH6bqrKOzJEChGK+cz0ZCdrj1az4lecB9T9FeQsD6PD1h40K0xuTYgn81Iuw== dependencies: - "@metascraper/helpers" "^5.10.7" + "@metascraper/helpers" "^5.11.1" -metascraper-soundcloud@^5.10.7: - version "5.10.7" - resolved "https://registry.yarnpkg.com/metascraper-soundcloud/-/metascraper-soundcloud-5.10.7.tgz#64a5518324ea69576ab9c206f29a60160fb89e91" - integrity sha512-KPM/g+l1m0tp4YOu8qF1RUT7yondaY1S/0aieUUFck/iE3VA1i3MJTLLygIc+67fcbHqcz60qfPTOvYbl6sIPw== +metascraper-soundcloud@^5.11.4: + version "5.11.4" + resolved "https://registry.yarnpkg.com/metascraper-soundcloud/-/metascraper-soundcloud-5.11.4.tgz#aeb94ca0d2fe48f8e8baedb3c13024dfc363cfad" + integrity sha512-aQCriI0WXd2Ow+cwXc3DLXE5BljbjqqTrfrcZvA0k11LGRh3ChD4EI3JxGXBYGusW/fsC19ya+JJ9C54H6lKcA== dependencies: - "@metascraper/helpers" "^5.10.7" - tldts "~5.6.3" + "@metascraper/helpers" "^5.11.1" + tldts "~5.6.8" -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== +metascraper-title@^5.11.1: + version "5.11.1" + resolved "https://registry.yarnpkg.com/metascraper-title/-/metascraper-title-5.11.1.tgz#fb32da17e71b2c64dc45d12c3602ca9330ab4bd5" + integrity sha512-fZ8qjf+d5ntwz/75X2r3BYD8X+tioZS1s+k9G3gfc+6ByJvrL9/ey6YzlDlU4zYqX73Vdx7+zUyy2ct0aJqWFA== dependencies: - "@metascraper/helpers" "^5.10.7" + "@metascraper/helpers" "^5.11.1" lodash "~4.17.15" -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== +metascraper-url@^5.11.1: + version "5.11.1" + resolved "https://registry.yarnpkg.com/metascraper-url/-/metascraper-url-5.11.1.tgz#c0687c09889d81cf9317083eab289067328b4ca6" + integrity sha512-+BMkCEQA3+6gwklgeNclhVImDfmwPKMzVNzM2KcioD7sRUpm6+7cbcPFcf1VhGENxxz1TmHY2ZaLdRat/lsRDg== dependencies: - "@metascraper/helpers" "^5.10.7" + "@metascraper/helpers" "^5.11.1" -metascraper-video@^5.10.7: - version "5.10.7" - resolved "https://registry.yarnpkg.com/metascraper-video/-/metascraper-video-5.10.7.tgz#2892819a3613ddac115ada7fb1b28d74a646f974" - integrity sha512-+fjiL/Vq0DGd7dMvBTdFKrOK2YH2myHssSChRZVZLl3gzyo4YEWpnOWBhfuoky0caOcs9+RVAxF9pE1TdTFmbA== +metascraper-video@^5.11.1: + version "5.11.1" + resolved "https://registry.yarnpkg.com/metascraper-video/-/metascraper-video-5.11.1.tgz#4018a635d816f3123c7ba97fe7669e4d61af2196" + integrity sha512-g8x6R4ntX7pt7ntuRCzL1+xIRd0JFAp/LoVPYFvdwn/D78u9GMJi+JvrNuLIEcrmtb6re6rE9MIOy8qMo1g3qA== dependencies: - "@metascraper/helpers" "^5.10.7" + "@metascraper/helpers" "^5.11.1" lodash "~4.17.15" -metascraper-youtube@^5.10.7: - version "5.10.7" - resolved "https://registry.yarnpkg.com/metascraper-youtube/-/metascraper-youtube-5.10.7.tgz#6c3313563ee57cb71c496fa99c129ad41fe22291" - integrity sha512-T4ZawYpW/2lyoVUY9RM92YCxkuyhNDXFxg8XAG9u2hoNZ5elrHLOv67ao5zMHa7IXZY3A7IGDOBd1NfoShnToA== +metascraper-youtube@^5.11.1: + version "5.11.1" + resolved "https://registry.yarnpkg.com/metascraper-youtube/-/metascraper-youtube-5.11.1.tgz#475f2d7e9a4866fabaa955dc4f9f20015e20780e" + integrity sha512-Z7p/grewIuYhJKlemW28CN8q1w6sD6CvQaIS/ACvnU3sSoiWbiblfb4iQwP1NKpwGuuw/Vp+9kvauFYbojLh7w== dependencies: - "@metascraper/helpers" "^5.10.7" + "@metascraper/helpers" "^5.11.1" get-video-id "~3.1.4" is-reachable "~4.0.0" p-locate "~4.1.0" -metascraper@^5.11.0: - version "5.11.0" - resolved "https://registry.yarnpkg.com/metascraper/-/metascraper-5.11.0.tgz#bbb25eb055c0ec03992df99c10c48057751ee56b" - integrity sha512-IocQqdSQnOpbai0X9Cu37w/AKeSfU513MCfaFzzcvWgI8s6mGQ1DWRFPvkx0ahtixpP0/ifE4t7ycODrtepRxQ== +metascraper@^5.11.4: + version "5.11.4" + resolved "https://registry.yarnpkg.com/metascraper/-/metascraper-5.11.4.tgz#91f13c9f39fd824cdd9bfe8d771576b9b856598e" + integrity sha512-GNYAwYuGwSm3P0p2Yi3OgYqttoYj1wgUDqbfnleN7tQRMKnTFinYw6YNYVfOniuNYl+CiJH4gg9ll2QpG8tzTw== dependencies: - "@metascraper/helpers" "^5.10.7" + "@metascraper/helpers" "^5.11.1" cheerio "~1.0.0-rc.3" cheerio-advanced-selectors "~2.0.1" lodash "~4.17.15" @@ -6665,10 +6684,10 @@ nodemailer-html-to-text@^3.1.0: dependencies: html-to-text "^5.1.1" -nodemailer@^6.4.2: - version "6.4.2" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.2.tgz#7147550e32cdc37453380ab78d2074533966090a" - integrity sha512-g0n4nH1ONGvqYo1v72uSWvF/MRNnnq1LzmSzXb/6EPF3LFb51akOhgG3K2+aETAsJx90/Q5eFNTntu4vBCwyQQ== +nodemailer@^6.4.4: + version "6.4.4" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.4.tgz#f4bb26a833786e8908b3ac8afbf2d0382ac24feb" + integrity sha512-2GqGu5o3FBmDibczU3+LZh9lCEiKmNx7LvHl512p8Kj+Kn5FQVOICZv85MDFz/erK0BDd5EJp3nqQLpWCZD1Gg== nodemon@~2.0.2: version "2.0.2" @@ -6831,10 +6850,10 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-hash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.0.0.tgz#7c4cc341eb8b53367312a7c546142f00c9e0ea20" - integrity sha512-I7zGBH0rDKwVGeGZpZoFaDhIwvJa3l1CZE+8VchylXbInNiCj7sxxea9P5dTM4ftKR5//nrqxrdeGSTWL2VpBA== +object-hash@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.0.3.tgz#d12db044e03cd2ca3d77c0570d87225b02e1e6ea" + integrity sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg== object-inspect@^1.7.0: version "1.7.0" @@ -7258,10 +7277,10 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= -postcss@^7.0.5: - version "7.0.17" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f" - integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ== +postcss@^7.0.27: + version "7.0.27" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.27.tgz#cc67cdc6b0daa375105b7c424a85567345fc54d9" + integrity sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ== dependencies: chalk "^2.4.2" source-map "^0.6.1" @@ -7868,20 +7887,20 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sanitize-html@~1.21.1: - version "1.21.1" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.21.1.tgz#1647d15c0c672901aa41eac1b86d0c38146d30ce" - integrity sha512-W6enXSVphVaVbmVbzVngBthR5f5sMmhq3EfPfBlzBzp2WnX8Rnk7NGpP7KmHUc0Y3MVk9tv/+CbpdHchX9ai7g== +sanitize-html@~1.22.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.22.0.tgz#9df779c53cf5755adb2322943c21c1c1dffca7bf" + integrity sha512-3RPo65mbTKpOAdAYWU496MSty1YbB3Y5bjwL5OclgaSSMtv65xvM7RW/EHRumzaZ1UddEJowCbSdK0xl5sAu0A== dependencies: chalk "^2.4.1" - htmlparser2 "^3.10.0" + htmlparser2 "^4.1.0" lodash.clonedeep "^4.5.0" lodash.escaperegexp "^4.1.2" lodash.isplainobject "^4.0.6" lodash.isstring "^4.0.1" lodash.mergewith "^4.6.1" - postcss "^7.0.5" - srcset "^1.0.0" + postcss "^7.0.27" + srcset "^2.0.1" xtend "^4.0.1" sax@>=0.6.0, sax@^1.2.4: @@ -8194,13 +8213,10 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -srcset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/srcset/-/srcset-1.0.0.tgz#a5669de12b42f3b1d5e83ed03c71046fc48f41ef" - integrity sha1-pWad4StC87HV6D7QPHEEb8SPQe8= - dependencies: - array-uniq "^1.0.2" - number-is-nan "^1.0.0" +srcset@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/srcset/-/srcset-2.0.1.tgz#8f842d357487eb797f413d9c309de7a5149df5ac" + integrity sha512-00kZI87TdRKwt+P8jj8UZxbfp7mK2ufxcIMWvhAOZNJTRROimpHeruWrGvCZneiuVDLqdyHefVp748ECTnyUBQ== sshpk@^1.7.0: version "1.16.1" @@ -8643,17 +8659,17 @@ tlds@^1.187.0, tlds@^1.203.0: resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.203.1.tgz#4dc9b02f53de3315bc98b80665e13de3edfc1dfc" integrity sha512-7MUlYyGJ6rSitEZ3r1Q1QNV8uSIzapS8SmmhSusBuIc7uIxPPwsKllEP0GRp1NS6Ik6F+fRZvnjDWm3ecv2hDw== -tldts-core@^5.6.3: - version "5.6.3" - resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-5.6.3.tgz#d80ce1e93b58ba0614701c28450360fc6986aaf1" - integrity sha512-E7Jtwgy5ZKXuKm3tb2Z73t0AgiGTnGnVrGfBAJj0nS2tENCclb/Ym5yt+wOdDW+8uJg0bI/BxHmbvUyLAYpcPQ== +tldts-core@^5.6.8: + version "5.6.8" + resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-5.6.8.tgz#0652cc445c835df6b3e22983884a984782a3ff94" + integrity sha512-fEAkTMPviMVie2+KIxIZ9A3WzraFC4z7E+jtMRwTmvAWJDcAH2pwPAp2ai4VvLJM3NuUcoPCJBQggvUbxxbBHw== -tldts@~5.6.3: - version "5.6.3" - resolved "https://registry.yarnpkg.com/tldts/-/tldts-5.6.3.tgz#89159b2180bf18d807bcf38438ef6e35fafa8d9f" - integrity sha512-h17D3Q9iRTeEdqncCR5MfRvwPxRbGFwx/g51ky2s6+2i9BicZOPFikc5FE2jG0Se+0bAPaaoZLytQ1kGhH1U0g== +tldts@~5.6.8: + version "5.6.8" + resolved "https://registry.yarnpkg.com/tldts/-/tldts-5.6.8.tgz#1a38eb36818b56e2448678eef74d3abe77be3486" + integrity sha512-b7dBujq9RqpwYe/sNDyPp51YCLpLjCY+cSYrke4uxlRhhTe1qpZdalx9BK7fPj0yKaW6NbweKJlVlBAyZ45g/A== dependencies: - tldts-core "^5.6.3" + tldts-core "^5.6.8" tmp@^0.0.33: version "0.0.33" @@ -9047,11 +9063,16 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@^3.1.0, uuid@^3.3.2, uuid@~3.4.0: +uuid@^3.1.0, uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@~7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.1.tgz#95ed6ff3d8c881cbf85f0f05cc3915ef994818ef" + integrity sha512-yqjRXZzSJm9Dbl84H2VDHpM3zMjzSJQ+hn6C4zqd5ilW+7P4ZmLEEqwho9LjP+tGuZlF4xrHQXT0h9QZUS/pWA== + v8-compile-cache@^2.0.3: version "2.1.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" @@ -9121,12 +9142,12 @@ w3c-xmlserializer@^1.1.2: webidl-conversions "^4.0.2" xml-name-validator "^3.0.0" -wait-on@~4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-4.0.0.tgz#4d7e4485ca759968897fd3b0cc50720c0b4ca959" - integrity sha512-QrW3J8LzS5ADPfD9Rx5S6KJck66xkqyiFKQs9jmUTkIhiEOmkzU7WRZc+MjsnmkrgjitS2xQ4bb13hnlQnKBUQ== +wait-on@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-4.0.1.tgz#c49ca18b1ea60580404feed9df76ab3af2425a56" + integrity sha512-x83fmTH2X0KL7vXoGt9aV5x4SMCvO8A/NbwWpaYYh4NJ16d3KSgbHwBy9dVdHj0B30cEhOFRvDob4fnpUmZxvA== dependencies: - "@hapi/joi" "^16.1.8" + "@hapi/joi" "^17.1.0" lodash "^4.17.15" minimist "^1.2.0" request "^2.88.0" @@ -9304,12 +9325,12 @@ xmlchars@^2.1.1: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xregexp@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.2.4.tgz#02a4aea056d65a42632c02f0233eab8e4d7e57ed" - integrity sha512-sO0bYdYeJAJBcJA8g7MJJX7UrOZIfJPd8U2SC7B2Dd/J24U0aQNoGp33shCaBSWeb0rD5rh6VBUIXOkGal1TZA== +xregexp@^4.2.4, xregexp@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50" + integrity sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g== dependencies: - "@babel/runtime-corejs2" "^7.2.0" + "@babel/runtime-corejs3" "^7.8.3" xtend@^4.0.1: version "4.0.2" @@ -9356,14 +9377,15 @@ yargs@^15.0.0: y18n "^4.0.0" yargs-parser "^16.1.0" -yup@^0.28.0: - version "0.28.0" - resolved "https://registry.yarnpkg.com/yup/-/yup-0.28.0.tgz#fdc04d1a495465c83d3757a80c47616884baeddc" - integrity sha512-9ZmsB/PT6/m+oUKF8rT9lWhMMGfx5s/aNCCf8pMu/GEQA0Ro2tLOc+aX12GjfL67Vif5a3c7eZVuxGFqFScnJQ== +yup@^0.28.1: + version "0.28.1" + resolved "https://registry.yarnpkg.com/yup/-/yup-0.28.1.tgz#60c0725be7057ed7a9ae61561333809332a63d47" + integrity sha512-xSHMZA7UyecSG/CCTDCtnYZMjBrYDR/C7hu0fMsZ6UcS/ngko4qCVFbw+CAmNtHlbItKkvQ3YXITODeTj/dUkw== dependencies: "@babel/runtime" "^7.0.0" fn-name "~2.0.1" lodash "^4.17.11" + lodash-es "^4.17.11" property-expr "^1.5.0" synchronous-promise "^2.0.6" toposort "^2.0.2" diff --git a/cypress.json b/cypress.json index f41489007..284bdbd34 100644 --- a/cypress.json +++ b/cypress.json @@ -1,5 +1,8 @@ { "projectId": "qa7fe2", "ignoreTestFiles": "*.js", - "baseUrl": "http://localhost:3000" + "baseUrl": "http://localhost:3000", + "env": { + "RETRIES": 2 + } } diff --git a/cypress/constants/terms-and-conditions-version.js b/cypress/constants/terms-and-conditions-version.js index 87b00b8dc..7b2a8fb5d 100644 --- a/cypress/constants/terms-and-conditions-version.js +++ b/cypress/constants/terms-and-conditions-version.js @@ -1,2 +1,2 @@ // please change also version in file "webapp/constants/terms-and-conditions-version.js" -export const VERSION = '0.0.3' \ No newline at end of file +export const VERSION = '0.0.4' \ No newline at end of file diff --git a/cypress/integration/common/post.js b/cypress/integration/common/post.js index 7a47c116e..d0298c5a3 100644 --- a/cypress/integration/common/post.js +++ b/cypress/integration/common/post.js @@ -30,7 +30,7 @@ Then("my comment should be successfully created", () => { }); Then("I should see my comment", () => { - cy.get("div.comment p") + cy.get("article.comment-card p") .should("contain", "Human Connection rocks") .get(".user-avatar img") .should("have.attr", "src") @@ -40,12 +40,12 @@ Then("I should see my comment", () => { }); Then("I should see the entirety of my comment", () => { - cy.get("div.comment") + cy.get("article.comment-card") .should("not.contain", "show more") }); Then("I should see an abreviated version of my comment", () => { - cy.get("div.comment") + cy.get("article.comment-card") .should("contain", "show more") }); @@ -60,7 +60,7 @@ Then("it should create a mention in the CommentForm", () => { }) When("I open the content menu of post {string}", (title)=> { - cy.contains('.post-card', title) + cy.contains('.post-teaser', title) .find('.content-menu .base-button') .click() }) @@ -77,9 +77,10 @@ Then("there is no button to pin a post", () => { }) And("the post with title {string} has a ribbon for pinned posts", (title) => { - cy.get("article.post-card").contains(title) + cy.get(".post-teaser").contains(title) .parent() - .find("div.ribbon.ribbon--pinned") + .parent() + .find(".ribbon.--pinned") .should("contain", "Announcement") }) @@ -111,7 +112,7 @@ Then("I add all required fields", () => { .get(".categories-select .base-button") .first() .click() - .get('.ds-flex-item > .ds-form-item .ds-select ') + .get('.base-card > .select-field input') .click() .get('.ds-select-option') .eq(languages.findIndex(l => l.code === 'en')) @@ -119,7 +120,7 @@ Then("I add all required fields", () => { }) Then("the post was saved successfully with the {string} teaser image", condition => { - cy.get(".ds-card-content > .ds-heading") + cy.get(".base-card > .title") .should("contain", condition === 'updated' ? 'to be updated' : 'new post') .get(".content") .should("contain", condition === 'updated' ? 'successfully updated' : 'new post content') @@ -128,25 +129,22 @@ Then("the post was saved successfully with the {string} teaser image", condition .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 first image should not be displayed anymore", () => { + cy.get(".hero-image") + .children() + .get('.hero-image > .image') + .should('have.length', 1) + .and('have.attr', 'src') }) Then('the {string} post was saved successfully without a teaser image', condition => { - cy.get(".ds-card-content > .ds-heading") + cy.get(".base-card > .title") .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') + .get('.hero-image > .image') .should('not.exist') }) @@ -156,12 +154,12 @@ Then('I should be able to remove it', () => { }) When('my post has a teaser image', () => { - cy.get('.contribution-image') + cy.get('.contribution-form .image') .should('exist') .and('have.attr', 'src') }) Then('I should be able to remove the image', () => { - cy.get('.delete-image') + cy.get('.dz-message > .base-button') .click() -}) \ No newline at end of file +}) diff --git a/cypress/integration/common/profile.js b/cypress/integration/common/profile.js index c22c20392..a0be8a2cf 100644 --- a/cypress/integration/common/profile.js +++ b/cypress/integration/common/profile.js @@ -29,7 +29,7 @@ When("I visit another user's profile page", () => { }); Then("I cannot upload a picture", () => { - cy.get(".ds-card-content") + cy.get(".base-card") .children() .should("not.have.id", "customdropzone") .should("have.class", "user-avatar"); diff --git a/cypress/integration/common/report.js b/cypress/integration/common/report.js index f209ceef7..4c6d2f6c3 100644 --- a/cypress/integration/common/report.js +++ b/cypress/integration/common/report.js @@ -12,7 +12,7 @@ let annoyingUserWhoMutedModeratorTitle = 'Fake news' const savePostTitle = $post => { return $post .first() - .find('.ds-heading') + .find('.title') .first() .invoke('text') .then(title => { @@ -51,7 +51,7 @@ Given('I am logged in with a {string} role', role => { }) When('I click on "Report Post" from the content menu of the post', () => { - cy.contains('.ds-card', davidIrvingPostTitle) + cy.contains('.base-card', davidIrvingPostTitle) .find('.content-menu .base-button') .click({force: true}) @@ -61,7 +61,7 @@ When('I click on "Report Post" from the content menu of the post', () => { }) When('I click on "Report User" from the content menu in the user info box', () => { - cy.contains('.ds-card', davidIrvingPostTitle) + cy.contains('.base-card', davidIrvingPostTitle) .get('.user-content-menu .base-button') .click({ force: true }) @@ -78,7 +78,7 @@ When('I click on the author', () => { When('I report the author', () => { cy.get('.page-name-profile-id-slug').then(() => { - invokeReportOnElement('.ds-card').then(() => { + invokeReportOnElement('.base-card').then(() => { cy.get('button') .contains('Send') .click() @@ -139,7 +139,7 @@ Given('somebody reported the following posts:', table => { .authenticateAs(submitter) .mutate(gql`mutation($resourceId: ID!, $reasonCategory: ReasonCategory!, $reasonDescription: String!) { fileReport(resourceId: $resourceId, reasonCategory: $reasonCategory, reasonDescription: $reasonDescription) { - id + reportId } }`, { resourceId, @@ -169,7 +169,7 @@ Then('each list item links to the post page', () => { Then('I can visit the post page', () => { cy.contains(annoyingUserWhoMutedModeratorTitle).click() cy.location('pathname').should('contain', '/post') - .get('h3').should('contain', annoyingUserWhoMutedModeratorTitle) + .get('.base-card .title').should('contain', annoyingUserWhoMutedModeratorTitle) }) When("they have a post someone has reported", () => { diff --git a/cypress/integration/common/search.js b/cypress/integration/common/search.js index c42ec3ff0..1feece77e 100644 --- a/cypress/integration/common/search.js +++ b/cypress/integration/common/search.js @@ -1,6 +1,6 @@ import { When, Then } from "cypress-cucumber-preprocessor/steps"; When("I search for {string}", value => { - cy.get(".searchable-input .ds-select-search") + cy.get(".searchable-input .ds-select input") .focus() .type(value); }); @@ -25,7 +25,7 @@ Then("the search should contain the annoying user", () => { expect($li).to.have.length(1); }) cy.get(".ds-select-dropdown .user-teaser .slug").should("contain", '@spammy-spammer'); - cy.get(".searchable-input .ds-select-search") + cy.get(".searchable-input .ds-select input") .focus() .type("{esc}"); }) @@ -44,21 +44,21 @@ Then("I should see the following users in the select dropdown:", table => { }); When("I type {string} and press Enter", value => { - cy.get(".searchable-input .ds-select-search") + cy.get(".searchable-input .ds-select input") .focus() .type(value) .type("{enter}", { force: true }); }); When("I type {string} and press escape", value => { - cy.get(".searchable-input .ds-select-search") + cy.get(".searchable-input .ds-select input") .focus() .type(value) .type("{esc}"); }); Then("the search field should clear", () => { - cy.get(".searchable-input .ds-select-search").should("have.text", ""); + cy.get(".searchable-input .ds-select input").should("have.text", ""); }); When("I select a post entry", () => { diff --git a/cypress/integration/common/settings.js b/cypress/integration/common/settings.js index e8e968a5e..3dcff141d 100644 --- a/cypress/integration/common/settings.js +++ b/cypress/integration/common/settings.js @@ -80,7 +80,7 @@ Then('I should be on the {string} page', page => { .should(loc => { expect(loc.pathname).to.eq(page) }) - .get('h3') + .get('h2') .should('contain', 'Social media') }) @@ -112,7 +112,7 @@ Given('I have added a social media link', () => { }) Then('they should be able to see my social media links', () => { - cy.get('.ds-card-content') + cy.get('.base-card') .contains('Where else can I find Peter Pan?') .get('a[href="https://freeradical.zone/peter-pan"]') .should('have.length', 1) diff --git a/cypress/integration/common/steps.js b/cypress/integration/common/steps.js index f411efa90..c02829b25 100644 --- a/cypress/integration/common/steps.js +++ b/cypress/integration/common/steps.js @@ -73,7 +73,7 @@ Given("the {string} user searches for {string}", (_, postTitle) => { }) }) .then(user => cy.login(user)) - cy.get(".searchable-input .ds-select-search") + cy.get(".searchable-input .ds-select input") .focus() .type(postTitle); }); @@ -167,7 +167,8 @@ When("I fill in my email and password combination and click submit", () => { }); When(/(?:when )?I refresh the page/, () => { - cy.reload(); + cy.visit('/') + .reload(); }); When("I log out through the menu in the top right corner", () => { @@ -238,16 +239,16 @@ Given("we have the following comments in our database:", table => { }); 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, - }); - }) + 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 => { @@ -295,14 +296,14 @@ Then("I select a category", () => { }); When("I choose {string} as the language for the post", (languageCode) => { - cy.get('.ds-flex-item > .ds-form-item .ds-select ') + cy.get('.contribution-form .ds-select') .click().get('.ds-select-option') .eq(languages.findIndex(l => l.code === languageCode)).click() }) Then("the post shows up on the landing page at position {int}", index => { cy.openPage("landing"); - const selector = `.post-card:nth-child(${index}) > .ds-card-content`; + const selector = `.post-teaser:nth-child(${index}) > .base-card`; cy.get(selector).should("contain", lastPost.title); cy.get(selector).should("contain", lastPost.content); }); @@ -312,16 +313,16 @@ Then("I get redirected to {string}", route => { }); Then("the post was saved successfully", () => { - cy.get(".ds-card-content > .ds-heading").should("contain", lastPost.title); + cy.get(".base-card > .title").should("contain", lastPost.title); cy.get(".content").should("contain", lastPost.content); }); Then(/^I should see only ([0-9]+) posts? on the landing page/, postCount => { - cy.get(".post-card").should("have.length", postCount); + cy.get(".post-teaser").should("have.length", postCount); }); Then("the first post on the landing page has the title:", title => { - cy.get(".post-card:first").should("contain", title); + cy.get(".post-teaser:first").should("contain", title); }); Then( @@ -388,7 +389,7 @@ Then("I can login successfully with password {string}", password => { When("open the notification menu and click on the first item", () => { cy.get(".notifications-menu").invoke('show').click(); // "invoke('show')" because of the delay for show the menu - cy.get(".notification-mention-post") + cy.get(".notification .link") .first() .click({ force: true @@ -424,7 +425,7 @@ When("mention {string} in the text", mention => { Then("the notification gets marked as read", () => { cy.get(".notifications-menu-popover .notification") .first() - .should("have.class", "read"); + .should("have.class", "--read"); }); Then("there are no notifications in the top menu", () => { @@ -510,14 +511,14 @@ Given('{string} wrote a post {string}', (_, title) => { }); Then("the list of posts of this user is empty", () => { - cy.get(".ds-card-content").not(".post-link"); + cy.get(".base-card").not(".post-link"); cy.get(".main-container").find(".ds-space.hc-empty"); }); Then("I get removed from his follower collection", () => { - cy.get(".ds-card-content").not(".post-link"); + cy.get(".base-card").not(".post-link"); cy.get(".main-container").contains( - ".ds-card-content", + ".base-card", "is not followed by anyone" ); }); @@ -581,7 +582,7 @@ Then("I see only one post with the title {string}", title => { }); Then("they should not see the comment form", () => { - cy.get(".ds-card-footer").children().should('not.have.class', 'comment-form') + cy.get(".base-card").children().should('not.have.class', 'comment-form') }) Then("they should see a text explaining why commenting is not possible", () => { @@ -600,11 +601,11 @@ Then("I {string} see {string} from the content menu in the user info box", (cond }) Then('I should not see {string} button', button => { - cy.get('.ds-card-content .action-buttons') + cy.get('.base-card .action-buttons') .should('have.length', 1) }) Then('I should see the {string} button', button => { - cy.get('.ds-card-content .action-buttons .base-button') + cy.get('.base-card .action-buttons .base-button') .should('contain', button) }) diff --git a/cypress/integration/notifications/Mentions.feature b/cypress/integration/notifications/Mentions.feature index 02dc0abd2..08eddcacd 100644 --- a/cypress/integration/notifications/Mentions.feature +++ b/cypress/integration/notifications/Mentions.feature @@ -20,7 +20,6 @@ Feature: Notification for a mention And I select a category And I choose "en" as the language for the post And I click on "Save" - When I log out 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 diff --git a/cypress/integration/post/ImageUploader.feature b/cypress/integration/post/ImageUploader.feature index 2e9f1f5b9..1bbd80c78 100644 --- a/cypress/integration/post/ImageUploader.feature +++ b/cypress/integration/post/ImageUploader.feature @@ -35,7 +35,7 @@ Feature: Upload 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 + And the first image should not be displayed anymore Scenario: Add image, then delete it When I click on the big plus icon in the bottom right corner to create post @@ -44,4 +44,4 @@ Feature: Upload Teaser Image 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 \ No newline at end of file + And the "new" post was saved successfully without a teaser image diff --git a/cypress/integration/user_profile/BlockUser.feature b/cypress/integration/user_profile/BlockUser.feature index 256d79dfb..b5c510286 100644 --- a/cypress/integration/user_profile/BlockUser.feature +++ b/cypress/integration/user_profile/BlockUser.feature @@ -55,6 +55,6 @@ Feature: Block a User 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 \ No newline at end of file + And I should not see "Unblock user" button + And I "should not" see "Unblock user" from the content menu in the user info box diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 75f27d0f7..a15e57007 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -58,14 +58,14 @@ Cypress.Commands.add("login", user => { }); Cypress.Commands.add("manualLogin", ({ email, password }) => { - cy.visit(`/login`); - cy.get("input[name=email]") + cy.visit(`/login`) + .get("input[name=email]") .trigger("focus") - .type(email); - cy.get("input[name=password]") + .type(email) + .get("input[name=password]") .trigger("focus") - .type(password); - cy.get("button[name=submit]") + .type(password) + .get("button[name=submit]") .as("submitButton") .click(); }); diff --git a/cypress/support/factories.js b/cypress/support/factories.js index d2a8d87ad..2ca46c483 100644 --- a/cypress/support/factories.js +++ b/cypress/support/factories.js @@ -1,5 +1,6 @@ -import Factory, { cleanDatabase } from '../../backend/src/db/factories' -import { getDriver, getNeode } from '../../backend/src/db/neo4j' +import Factory from '../../backend/src/db/factories' +import { getNeode } from '../../backend/src/db/neo4j' + const neo4jConfigs = { uri: Cypress.env('NEO4J_URI'), @@ -8,7 +9,7 @@ const neo4jConfigs = { } const neodeInstance = getNeode(neo4jConfigs) -beforeEach(() => cleanDatabase()) +beforeEach(() => cy.then(() => neodeInstance.cypher('MATCH (everything) DETACH DELETE everything;'))) Cypress.Commands.add('neode', () => { return neodeInstance diff --git a/cypress/support/index.js b/cypress/support/index.js index 195b0de7d..3290d2a5a 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -23,4 +23,11 @@ import 'cypress-plugin-retries' // Alternatively you can use CommonJS syntax: // require('./commands') - +import { WebSocket } from 'mock-socket' +before(() => { + cy.visit('/', { + onBeforeLoad(win) { + cy.stub(win, "WebSocket", url => new WebSocket(url)) + } + }) +}) diff --git a/package.json b/package.json index 79798391c..35fc79c1b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "human-connection", - "version": "0.3.1", + "version": "0.4.0", "description": "Fullstack and API tests with cypress and cucumber for Human Connection", "author": "Human Connection gGmbh", "license": "MIT", @@ -18,32 +18,34 @@ "cypress:backend": "cd backend && yarn run dev", "cypress:webapp": "cd webapp && yarn run dev", "cypress:setup": "run-p cypress:backend cypress:webapp", - "cypress:run": "cross-env cypress run", - "cypress:open": "cross-env cypress open", + "cypress:run": "cross-env cypress run --browser firefox", + "cypress:open": "cross-env cypress open --browser firefox", "cucumber:setup": "cd backend && yarn run dev", "cucumber": "wait-on tcp:4000 && cucumber-js --require-module @babel/register --exit", "release": "standard-version", "generate:changelog": "yarn version && auto-changelog" }, "devDependencies": { - "@babel/core": "^7.8.4", + "@babel/core": "^7.8.6", "@babel/preset-env": "^7.8.4", - "@babel/register": "^7.8.3", + "@babel/register": "^7.8.6", "auto-changelog": "^1.16.2", "bcryptjs": "^2.4.3", "codecov": "^3.6.5", "cross-env": "^6.0.3", "cucumber": "^6.0.5", - "cypress": "^3.8.3", + "cypress": "^4.0.0", "cypress-cucumber-preprocessor": "^2.0.1", "cypress-file-upload": "^3.5.3", "cypress-plugin-retries": "^1.5.2", - "date-fns": "^2.9.0", + "date-fns": "^2.10.0", "dotenv": "^8.2.0", "expect": "^25.1.0", "faker": "Marak/faker.js#master", "graphql-request": "^1.8.2", + "import": "^0.0.6", "jsonwebtoken": "^8.5.1", + "mock-socket": "^9.0.3", "neo4j-driver": "^4.0.1", "neode": "^0.3.7", "npm-run-all": "^4.1.5", diff --git a/webapp/assets/_new/styles/resets.scss b/webapp/assets/_new/styles/resets.scss index 2784add5f..144f22d10 100644 --- a/webapp/assets/_new/styles/resets.scss +++ b/webapp/assets/_new/styles/resets.scss @@ -9,3 +9,13 @@ button { font-family: inherit; font-size: inherit; } + +h1, +h2, +h3, +h4, +h5, +h6, +p { + margin: 0; +} diff --git a/webapp/assets/_new/styles/tokens.scss b/webapp/assets/_new/styles/tokens.scss index 90ec527ea..9e86b3c70 100644 --- a/webapp/assets/_new/styles/tokens.scss +++ b/webapp/assets/_new/styles/tokens.scss @@ -132,6 +132,7 @@ $border-size-x-large: 6px; $border-radius-x-large: 5px; $border-radius-large: 4px; $border-radius-base: 4px; +$border-radius-small: 2px; $border-radius-rounded: 2em; $border-radius-circle: 50%; @@ -211,7 +212,8 @@ $letter-spacing-x-small: -0.015em; * @presenter Opacity */ -$opacity-soft: 0.65; +$opacity-base: 1; +$opacity-soft: 0.7; $opacity-disabled: 0.5; /** @@ -239,6 +241,7 @@ $size-height-large: 50px; $size-height-xlarge: 60px; $size-height-footer: 64px; $size-tappable-square: 44px; +$size-ribbon: 6px; /** * @tokens Size Width @@ -264,12 +267,23 @@ $size-avatar-large: 114px; $size-button-base: 36px; $size-button-small: 26px; +/** + * @tokens Size Images + * @presenter Spacing + */ + +$size-image-max-height: 2000px; +$size-image-cropper-max-height: 600px; +$size-image-cropper-min-height: 400px; +$size-image-uploader-min-height: 200px; + /** * @tokens Size Icons * @presenter Spacing */ $size-icon-base: 16px; + $size-icon-large: 60px; /** * @tokens Shadow @@ -285,6 +299,12 @@ $box-shadow-active: 0 0 6px 1px rgba(20, 100, 160, 0.5); $box-shadow-inset: inset 0 0 20px 1px rgba(0,0,0,.15); $box-shadow-small-inset: inset 0 0 0 1px rgba(0,0,0,.05); +/** + * @tokens Effects + */ + +$blur-radius: 22px; + /** * @tokens Animation Duration */ @@ -316,7 +336,8 @@ $z-index-page-submenu: 2500; $z-index-page-header: 2000; $z-index-page-sidebar: 1500; $z-index-sticky: 100; -$z-index-post-card-link: 5; +$z-index-post-teaser-link: 5; +$z-index-surface: 1; /** * @tokens Media Query diff --git a/webapp/assets/styles/main.scss b/webapp/assets/styles/main.scss index fbab1d78f..d6821e013 100644 --- a/webapp/assets/styles/main.scss +++ b/webapp/assets/styles/main.scss @@ -13,6 +13,8 @@ $easeOut: cubic-bezier(0.19, 1, 0.22, 1); content: ''; display: block; position: absolute; + top: 0; + left: 0; width: 100%; height: 100%; z-index: 2; @@ -141,10 +143,9 @@ hr { } } -.ds-card .ds-section { +.base-card > .ds-section { padding: 0; - margin-left: -$space-base; - margin-right: -$space-base; + margin: -$space-base; .ds-container { padding: $space-base; diff --git a/webapp/components/CategoriesSelect/CategoriesSelect.vue b/webapp/components/CategoriesSelect/CategoriesSelect.vue index 54c0d3524..b7d71de2d 100644 --- a/webapp/components/CategoriesSelect/CategoriesSelect.vue +++ b/webapp/components/CategoriesSelect/CategoriesSelect.vue @@ -1,30 +1,18 @@ + + diff --git a/webapp/components/Comment/Comment.vue b/webapp/components/Comment/Comment.vue deleted file mode 100644 index 5c47a3656..000000000 --- a/webapp/components/Comment/Comment.vue +++ /dev/null @@ -1,230 +0,0 @@ - - - - diff --git a/webapp/components/Comment/Comment.spec.js b/webapp/components/CommentCard/CommentCard.spec.js similarity index 95% rename from webapp/components/Comment/Comment.spec.js rename to webapp/components/CommentCard/CommentCard.spec.js index 1ba238bf5..b18ab67c0 100644 --- a/webapp/components/Comment/Comment.spec.js +++ b/webapp/components/CommentCard/CommentCard.spec.js @@ -1,5 +1,5 @@ import { config, mount } from '@vue/test-utils' -import Comment from './Comment.vue' +import CommentCard from './CommentCard.vue' import Vuex from 'vuex' const localVue = global.localVue @@ -8,11 +8,17 @@ localVue.directive('scrollTo', jest.fn()) config.stubs['client-only'] = '' config.stubs['nuxt-link'] = '' -describe('Comment.vue', () => { +describe('CommentCard.vue', () => { let propsData, mocks, stubs, getters, wrapper, Wrapper beforeEach(() => { - propsData = {} + propsData = { + comment: { + id: 'comment007', + author: { id: 'some-user' }, + }, + postId: 'post42', + } mocks = { $t: jest.fn(), $toast: { @@ -26,6 +32,7 @@ describe('Comment.vue', () => { truncate: a => a, removeHtml: a => a, }, + $route: { hash: '' }, $scrollTo: jest.fn(), $apollo: { mutate: jest.fn().mockResolvedValue({ @@ -55,7 +62,7 @@ describe('Comment.vue', () => { const store = new Vuex.Store({ getters, }) - return mount(Comment, { + return mount(CommentCard, { store, propsData, mocks, diff --git a/webapp/components/Comment/Comment.story.js b/webapp/components/CommentCard/CommentCard.story.js similarity index 92% rename from webapp/components/Comment/Comment.story.js rename to webapp/components/CommentCard/CommentCard.story.js index 291b6cb11..1749999f3 100644 --- a/webapp/components/Comment/Comment.story.js +++ b/webapp/components/CommentCard/CommentCard.story.js @@ -1,6 +1,6 @@ import { storiesOf } from '@storybook/vue' import { withA11y } from '@storybook/addon-a11y' -import Comment from './Comment' +import CommentCard from './CommentCard' import helpers from '~/storybook/helpers' helpers.init() @@ -41,14 +41,14 @@ const comment = { __typename: 'Comment', } -storiesOf('Comment', module) +storiesOf('CommentCard', module) .addDecorator(withA11y) .addDecorator(helpers.layout) .add('Basic comment', () => ({ - components: { Comment }, + components: { CommentCard }, store: helpers.store, data: () => ({ comment, }), - template: ``, + template: ``, })) diff --git a/webapp/components/CommentCard/CommentCard.vue b/webapp/components/CommentCard/CommentCard.vue new file mode 100644 index 000000000..d805d26ee --- /dev/null +++ b/webapp/components/CommentCard/CommentCard.vue @@ -0,0 +1,216 @@ + + + + diff --git a/webapp/components/CommentForm/CommentForm.spec.js b/webapp/components/CommentForm/CommentForm.spec.js index 420ab26fb..b940c561d 100644 --- a/webapp/components/CommentForm/CommentForm.spec.js +++ b/webapp/components/CommentForm/CommentForm.spec.js @@ -153,10 +153,10 @@ describe('CommentForm.vue', () => { expect(closeMethodSpy).toHaveBeenCalledTimes(1) }) - it('emits `showEditCommentMenu` event', async () => { + it('emits `finishEditing` event', async () => { wrapper.vm.updateEditorContent('ok') await wrapper.find('form').trigger('submit') - expect(wrapper.emitted('showEditCommentMenu')).toEqual([[false]]) + expect(wrapper.emitted('finishEditing')).toBeTruthy() }) }) @@ -167,10 +167,10 @@ describe('CommentForm.vue', () => { expect(closeMethodSpy).toHaveBeenCalledTimes(1) }) - it('emits `showEditCommentMenu` event', async () => { + it('emits `finishEditing` event', async () => { wrapper.vm.updateEditorContent('ok') await wrapper.find('[data-test="cancel-button"]').trigger('submit') - expect(wrapper.emitted('showEditCommentMenu')).toEqual([[false]]) + expect(wrapper.emitted('finishEditing')).toBeTruthy() }) }) diff --git a/webapp/components/CommentForm/CommentForm.vue b/webapp/components/CommentForm/CommentForm.vue index 9e4158876..422530259 100644 --- a/webapp/components/CommentForm/CommentForm.vue +++ b/webapp/components/CommentForm/CommentForm.vue @@ -1,8 +1,7 @@ @@ -72,7 +71,7 @@ export default { this.$refs.editor.clear() }, closeEditWindow() { - this.$emit('showEditCommentMenu', false) + this.$emit('finishEditing') }, handleCancel() { if (!this.update) { @@ -146,10 +145,13 @@ export default { diff --git a/webapp/components/DeleteData/DeleteData.spec.js b/webapp/components/DeleteData/DeleteData.spec.js index 3529c1b7b..e9205fa5a 100644 --- a/webapp/components/DeleteData/DeleteData.spec.js +++ b/webapp/components/DeleteData/DeleteData.spec.js @@ -88,7 +88,7 @@ describe('DeleteData.vue', () => { describe('calls the delete user mutation', () => { beforeEach(() => { - enableDeletionInput = wrapper.find('.enable-deletion-input input') + enableDeletionInput = wrapper.find('.ds-input') enableDeletionInput.setValue(deleteAccountName) deleteAccountBtn = wrapper.find('[data-test="delete-button"]') }) @@ -107,7 +107,7 @@ describe('DeleteData.vue', () => { it("deletes a user's posts if requested", () => { mocks.$t.mockImplementation(() => deleteContributionsMessage) - enableContributionDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(0) + enableContributionDeletionCheckbox = wrapper.findAll('input[type="checkbox"]').at(0) enableContributionDeletionCheckbox.trigger('click') deleteAccountBtn.trigger('click') expect(mocks.$apollo.mutate).toHaveBeenCalledWith( @@ -122,7 +122,7 @@ describe('DeleteData.vue', () => { it("deletes a user's comments if requested", () => { mocks.$t.mockImplementation(() => deleteCommentsMessage) - enableCommentDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(1) + enableCommentDeletionCheckbox = wrapper.findAll('input[type="checkbox"]').at(1) enableCommentDeletionCheckbox.trigger('click') deleteAccountBtn.trigger('click') expect(mocks.$apollo.mutate).toHaveBeenCalledWith( @@ -137,10 +137,10 @@ describe('DeleteData.vue', () => { it("deletes a user's posts and comments if requested", () => { mocks.$t.mockImplementation(() => deleteContributionsMessage) - enableContributionDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(0) + enableContributionDeletionCheckbox = wrapper.findAll('input[type="checkbox"]').at(0) enableContributionDeletionCheckbox.trigger('click') mocks.$t.mockImplementation(() => deleteCommentsMessage) - enableCommentDeletionCheckbox = wrapper.findAll('.checkbox-container input').at(1) + enableCommentDeletionCheckbox = wrapper.findAll('input[type="checkbox"]').at(1) enableCommentDeletionCheckbox.trigger('click') deleteAccountBtn.trigger('click') expect(mocks.$apollo.mutate).toHaveBeenCalledWith( @@ -166,7 +166,7 @@ describe('DeleteData.vue', () => { describe('error handling', () => { it('shows an error toaster when the mutation rejects', async () => { - enableDeletionInput = wrapper.find('.enable-deletion-input input') + enableDeletionInput = wrapper.find('.ds-input') enableDeletionInput.setValue(deleteAccountName) await Vue.nextTick() deleteAccountBtn = wrapper.find('[data-test="delete-button"]') diff --git a/webapp/components/DeleteData/DeleteData.vue b/webapp/components/DeleteData/DeleteData.vue index 66a31205a..1157fc922 100644 --- a/webapp/components/DeleteData/DeleteData.vue +++ b/webapp/components/DeleteData/DeleteData.vue @@ -1,80 +1,46 @@ + + diff --git a/webapp/components/Editor/Editor.story.js b/webapp/components/Editor/Editor.story.js index 8efcf3f4c..381c2e7ea 100644 --- a/webapp/components/Editor/Editor.story.js +++ b/webapp/components/Editor/Editor.story.js @@ -40,9 +40,9 @@ storiesOf('Editor', module) return { components: { ctx }, template: ` - + - + `, } }) diff --git a/webapp/components/Editor/SuggestionList.vue b/webapp/components/Editor/SuggestionList.vue index 3d480d187..5e9c146a0 100644 --- a/webapp/components/Editor/SuggestionList.vue +++ b/webapp/components/Editor/SuggestionList.vue @@ -89,7 +89,7 @@ export default { } &.hint { - opacity: 0.7; + opacity: $opacity-soft; pointer-events: none; } } diff --git a/webapp/components/FilterMenu/FilterMenu.spec.js b/webapp/components/FilterMenu/FilterMenu.spec.js index d70af323f..283db979e 100644 --- a/webapp/components/FilterMenu/FilterMenu.spec.js +++ b/webapp/components/FilterMenu/FilterMenu.spec.js @@ -12,10 +12,10 @@ describe('FilterMenu.vue', () => { mocks = { $t: () => {} } }) - describe('given a user', () => { + describe('given a hashtag', () => { beforeEach(() => { propsData = { - hashtag: null, + hashtag: 'Frieden', } }) @@ -27,19 +27,14 @@ describe('FilterMenu.vue', () => { wrapper = Wrapper() }) - it('does not render a card if there are no hashtags', () => { - expect(wrapper.is('.ds-card')).toBe(true) - }) - - it('renders a card if there are hashtags', () => { - propsData.hashtag = 'Frieden' + it('renders a card', () => { wrapper = Wrapper() - expect(wrapper.is('.ds-card')).toBe(true) + expect(wrapper.is('.base-card')).toBe(true) }) - describe('click "clear-search-button" button', () => { + describe('click clear search button', () => { it('emits clearSearch', () => { - wrapper.find('[name="clear-search-button"]').trigger('click') + wrapper.find('.base-button').trigger('click') expect(wrapper.emitted().clearSearch).toHaveLength(1) }) }) diff --git a/webapp/components/FilterMenu/FilterMenu.vue b/webapp/components/FilterMenu/FilterMenu.vue index e56925e56..afe6a3d7a 100644 --- a/webapp/components/FilterMenu/FilterMenu.vue +++ b/webapp/components/FilterMenu/FilterMenu.vue @@ -1,32 +1,22 @@ diff --git a/webapp/components/TeaserImage/TeaserImage.spec.js b/webapp/components/ImageUploader/ImageUploader.spec.js similarity index 56% rename from webapp/components/TeaserImage/TeaserImage.spec.js rename to webapp/components/ImageUploader/ImageUploader.spec.js index dd89c8cfd..e2e9f8d05 100644 --- a/webapp/components/TeaserImage/TeaserImage.spec.js +++ b/webapp/components/ImageUploader/ImageUploader.spec.js @@ -1,9 +1,9 @@ import { mount } from '@vue/test-utils' -import TeaserImage from './TeaserImage.vue' +import ImageUploader from './ImageUploader.vue' const localVue = global.localVue -describe('TeaserImage.vue', () => { +describe('ImageUploader.vue', () => { let wrapper let mocks @@ -17,7 +17,7 @@ describe('TeaserImage.vue', () => { }) describe('mount', () => { const Wrapper = () => { - return mount(TeaserImage, { mocks, localVue }) + return mount(ImageUploader, { mocks, localVue }) } beforeEach(() => { wrapper = Wrapper() @@ -28,21 +28,10 @@ describe('TeaserImage.vue', () => { const message = 'File upload failed' const fileError = { status: 'error' } - it('defaults to error false', () => { - expect(wrapper.vm.error).toEqual(false) - }) - it('shows an error toaster when verror is called', () => { - wrapper.vm.verror(fileError, message) + wrapper.vm.onDropzoneError(fileError, message) expect(mocks.$toast.error).toHaveBeenCalledWith(fileError.status, message) }) - - it('changes error status from false to true to false', () => { - wrapper.vm.verror(fileError, message) - expect(wrapper.vm.error).toEqual(true) - jest.runAllTimers() - expect(wrapper.vm.error).toEqual(false) - }) }) }) }) diff --git a/webapp/components/ImageUploader/ImageUploader.vue b/webapp/components/ImageUploader/ImageUploader.vue new file mode 100644 index 000000000..36f9b8485 --- /dev/null +++ b/webapp/components/ImageUploader/ImageUploader.vue @@ -0,0 +1,200 @@ + + + + diff --git a/webapp/components/LocaleSwitch/LocaleSwitch.spec.js b/webapp/components/LocaleSwitch/LocaleSwitch.spec.js index ee28b742a..812ff9253 100644 --- a/webapp/components/LocaleSwitch/LocaleSwitch.spec.js +++ b/webapp/components/LocaleSwitch/LocaleSwitch.spec.js @@ -1,10 +1,12 @@ -import { mount } from '@vue/test-utils' +import { config, mount } from '@vue/test-utils' import LocaleSwitch from './LocaleSwitch.vue' import Vuex from 'vuex' const localVue = global.localVue +config.stubs['client-only'] = '' + describe('LocaleSwitch.vue', () => { let wrapper, mocks, computed, deutschLanguageItem, getters diff --git a/webapp/components/LocaleSwitch/LocaleSwitch.vue b/webapp/components/LocaleSwitch/LocaleSwitch.vue index 564de20f7..5c0d901c9 100644 --- a/webapp/components/LocaleSwitch/LocaleSwitch.vue +++ b/webapp/components/LocaleSwitch/LocaleSwitch.vue @@ -1,35 +1,37 @@ diff --git a/webapp/components/Notification/Notification.spec.js b/webapp/components/Notification/Notification.spec.js index 750f59b3a..537babfae 100644 --- a/webapp/components/Notification/Notification.spec.js +++ b/webapp/components/Notification/Notification.spec.js @@ -63,7 +63,7 @@ describe('Notification', () => { it('renders reason', () => { wrapper = Wrapper() - expect(wrapper.find('.reason-text-for-test').text()).toEqual( + expect(wrapper.find('.notification > .description').text()).toEqual( 'notifications.reason.commented_on_post', ) }) @@ -79,9 +79,9 @@ describe('Notification', () => { wrapper = Wrapper() expect(wrapper.text()).toContain('@dagobert-duck is the best on this comment.') }) - it('has no class "read"', () => { + it('has no class "--read"', () => { wrapper = Wrapper() - expect(wrapper.classes()).not.toContain('read') + expect(wrapper.classes()).not.toContain('--read') }) describe('that is read', () => { @@ -90,8 +90,8 @@ describe('Notification', () => { wrapper = Wrapper() }) - it('has class "read"', () => { - expect(wrapper.classes()).toContain('read') + it('has class "--read"', () => { + expect(wrapper.classes()).toContain('--read') }) }) }) @@ -113,7 +113,7 @@ describe('Notification', () => { it('renders reason', () => { wrapper = Wrapper() - expect(wrapper.find('.reason-text-for-test').text()).toEqual( + expect(wrapper.find('.notification > .description').text()).toEqual( 'notifications.reason.mentioned_in_post', ) }) @@ -125,9 +125,9 @@ describe('Notification', () => { wrapper = Wrapper() expect(wrapper.text()).toContain('@jenny-rostock is the best on this post.') }) - it('has no class "read"', () => { + it('has no class "--read"', () => { wrapper = Wrapper() - expect(wrapper.classes()).not.toContain('read') + expect(wrapper.classes()).not.toContain('--read') }) describe('that is read', () => { @@ -136,8 +136,8 @@ describe('Notification', () => { wrapper = Wrapper() }) - it('has class "read"', () => { - expect(wrapper.classes()).toContain('read') + it('has class "--read"', () => { + expect(wrapper.classes()).toContain('--read') }) }) }) @@ -163,7 +163,7 @@ describe('Notification', () => { it('renders reason', () => { wrapper = Wrapper() - expect(wrapper.find('.reason-text-for-test').text()).toEqual( + expect(wrapper.find('.notification > .description').text()).toEqual( 'notifications.reason.mentioned_in_comment', ) }) @@ -182,9 +182,9 @@ describe('Notification', () => { expect(wrapper.text()).toContain('@dagobert-duck is the best on this comment.') }) - it('has no class "read"', () => { + it('has no class "--read"', () => { wrapper = Wrapper() - expect(wrapper.classes()).not.toContain('read') + expect(wrapper.classes()).not.toContain('--read') }) describe('that is read', () => { @@ -193,8 +193,8 @@ describe('Notification', () => { wrapper = Wrapper() }) - it('has class "read"', () => { - expect(wrapper.classes()).toContain('read') + it('has class "--read"', () => { + expect(wrapper.classes()).toContain('--read') }) }) }) diff --git a/webapp/components/Notification/Notification.vue b/webapp/components/Notification/Notification.vue index 2a4942716..acb83b028 100644 --- a/webapp/components/Notification/Notification.vue +++ b/webapp/components/Notification/Notification.vue @@ -1,37 +1,23 @@ diff --git a/webapp/components/NotificationList/NotificationList.spec.js b/webapp/components/NotificationList/NotificationList.spec.js index f70b7a482..075891f14 100644 --- a/webapp/components/NotificationList/NotificationList.spec.js +++ b/webapp/components/NotificationList/NotificationList.spec.js @@ -73,7 +73,7 @@ describe('NotificationList.vue', () => { describe('click on a notification', () => { beforeEach(() => { - wrapper.find('.notification-mention-post').trigger('click') + wrapper.find('.notification > .link').trigger('click') }) it("emits 'markAsRead' with the id of the notification source", () => { diff --git a/webapp/components/NotificationsTable/NotificationsTable.story.js b/webapp/components/NotificationsTable/NotificationsTable.story.js index 84deb31c9..1d27f6532 100644 --- a/webapp/components/NotificationsTable/NotificationsTable.story.js +++ b/webapp/components/NotificationsTable/NotificationsTable.story.js @@ -3,7 +3,7 @@ import { withA11y } from '@storybook/addon-a11y' import { action } from '@storybook/addon-actions' import NotificationsTable from '~/components/NotificationsTable/NotificationsTable' import helpers from '~/storybook/helpers' -import { post } from '~/components/PostCard/PostCard.story.js' +import { post } from '~/components/PostTeaser/PostTeaser.story.js' import { user } from '~/components/UserTeaser/UserTeaser.story.js' helpers.init() diff --git a/webapp/components/PostCard/PostCard.vue b/webapp/components/PostCard/PostCard.vue deleted file mode 100644 index d5a6d509b..000000000 --- a/webapp/components/PostCard/PostCard.vue +++ /dev/null @@ -1,219 +0,0 @@ - - - - diff --git a/webapp/components/PostCard/PostCard.spec.js b/webapp/components/PostTeaser/PostTeaser.spec.js similarity index 85% rename from webapp/components/PostCard/PostCard.spec.js rename to webapp/components/PostTeaser/PostTeaser.spec.js index 28ce10b9e..1e90cd1cf 100644 --- a/webapp/components/PostCard/PostCard.spec.js +++ b/webapp/components/PostTeaser/PostTeaser.spec.js @@ -2,14 +2,14 @@ import { config, shallowMount, mount, RouterLinkStub } from '@vue/test-utils' import Vuex from 'vuex' -import PostCard from './PostCard.vue' +import PostTeaser from './PostTeaser.vue' const localVue = global.localVue config.stubs['client-only'] = '' config.stubs['v-popover'] = '' -describe('PostCard', () => { +describe('PostTeaser', () => { let store let stubs let mocks @@ -22,11 +22,13 @@ describe('PostCard', () => { propsData = { post: { id: 'p23', + disabled: false, + shoutedCount: 0, + commentsCount: 0, name: 'It is a post', author: { id: 'u1', }, - disabled: false, }, } stubs = { @@ -55,7 +57,7 @@ describe('PostCard', () => { describe('shallowMount', () => { Wrapper = () => { store = new Vuex.Store({ getters }) - return shallowMount(PostCard, { + return shallowMount(PostTeaser, { store, propsData, mocks, @@ -63,6 +65,13 @@ describe('PostCard', () => { }) } + it('has no validation errors', () => { + const spy = jest.spyOn(global.console, 'error') + Wrapper() + expect(spy).not.toBeCalled() + spy.mockReset() + }) + beforeEach(jest.useFakeTimers) describe('test Post callbacks', () => { @@ -99,7 +108,7 @@ describe('PostCard', () => { const store = new Vuex.Store({ getters, }) - return mount(PostCard, { + return mount(PostTeaser, { stubs, mocks, propsData, @@ -111,6 +120,7 @@ describe('PostCard', () => { describe('given a post', () => { beforeEach(() => { propsData.post = { + ...propsData.post, title: "It's a title", } }) diff --git a/webapp/components/PostCard/PostCard.story.js b/webapp/components/PostTeaser/PostTeaser.story.js similarity index 85% rename from webapp/components/PostCard/PostCard.story.js rename to webapp/components/PostTeaser/PostTeaser.story.js index 5857167f3..db3350c5b 100644 --- a/webapp/components/PostCard/PostCard.story.js +++ b/webapp/components/PostTeaser/PostTeaser.story.js @@ -1,6 +1,6 @@ import { storiesOf } from '@storybook/vue' import { withA11y } from '@storybook/addon-a11y' -import HcPostCard from './PostCard.vue' +import PostTeaser from './PostTeaser.vue' import helpers from '~/storybook/helpers' helpers.init() @@ -44,24 +44,24 @@ export const post = { __typename: 'Post', } -storiesOf('Post Card', module) +storiesOf('PostTeaser', module) .addDecorator(withA11y) .addDecorator(helpers.layout) .add('without image', () => ({ - components: { HcPostCard }, + components: { PostTeaser }, store: helpers.store, data: () => ({ post, }), template: ` - `, })) .add('with image', () => ({ - components: { HcPostCard }, + components: { PostTeaser }, store: helpers.store, data: () => ({ post: { @@ -70,27 +70,23 @@ storiesOf('Post Card', module) }, }), template: ` - `, })) .add('pinned by admin', () => ({ - components: { HcPostCard }, + components: { PostTeaser }, store: helpers.store, data: () => ({ post: { ...post, - pinnedBy: { - id: '4711', - name: 'Ad Min', - role: 'admin', - }, + pinned: true, }, }), template: ` - diff --git a/webapp/components/PostTeaser/PostTeaser.vue b/webapp/components/PostTeaser/PostTeaser.vue new file mode 100644 index 000000000..851ee4f2c --- /dev/null +++ b/webapp/components/PostTeaser/PostTeaser.vue @@ -0,0 +1,207 @@ + + + + diff --git a/webapp/components/Ribbon/index.vue b/webapp/components/Ribbon/index.vue index c8c09c194..f54b456e5 100644 --- a/webapp/components/Ribbon/index.vue +++ b/webapp/components/Ribbon/index.vue @@ -1,7 +1,7 @@ - diff --git a/webapp/components/UserTeaser/UserTeaser.story.js b/webapp/components/UserTeaser/UserTeaser.story.js index 488576bd5..73b34cb76 100644 --- a/webapp/components/UserTeaser/UserTeaser.story.js +++ b/webapp/components/UserTeaser/UserTeaser.story.js @@ -80,7 +80,7 @@ storiesOf('UserTeaser', module) }), template: ` - + + diff --git a/webapp/components/features/ReportList/ReportList.story.js b/webapp/components/features/ReportList/ReportList.story.js index 33ec06120..44b06d8fb 100644 --- a/webapp/components/features/ReportList/ReportList.story.js +++ b/webapp/components/features/ReportList/ReportList.story.js @@ -1,7 +1,7 @@ import { storiesOf } from '@storybook/vue' import { withA11y } from '@storybook/addon-a11y' import { action } from '@storybook/addon-actions' -import { post } from '~/components/PostCard/PostCard.story.js' +import { post } from '~/components/PostTeaser/PostTeaser.story.js' import { user } from '~/components/UserTeaser/UserTeaser.story.js' import helpers from '~/storybook/helpers' import ReportList from './ReportList' @@ -183,11 +183,11 @@ storiesOf('ReportList', module) openModal: action('openModal'), filter: action('filter'), }, - template: ` + template: `

Reports

-
`, + `, })) diff --git a/webapp/components/features/ReportList/ReportList.vue b/webapp/components/features/ReportList/ReportList.vue index 62a29e66b..a6b1d9f5b 100644 --- a/webapp/components/features/ReportList/ReportList.vue +++ b/webapp/components/features/ReportList/ReportList.vue @@ -1,5 +1,5 @@ + + + diff --git a/webapp/pages/index.vue b/webapp/pages/index.vue index 609c3d800..2f2f14c1e 100644 --- a/webapp/pages/index.vue +++ b/webapp/pages/index.vue @@ -1,7 +1,7 @@