diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..99fb0ab34 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +backend/snapshots/* linguist-generated=true + diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000..543ccf3ad --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,17 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 60 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 30 +# Issues with these labels will never be considered stale +exemptLabels: + - pinned + - security +# Label to use when marking an issue as stale +staleLabel: stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.gitignore b/.gitignore index 45effce57..928dae262 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ cypress.env.json **/coverage release/ +*~ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index f8170d1e9..1cc36fca4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ script: - docker-compose down - docker-compose -f docker-compose.yml up -d - wait-on http://localhost:7474 - - yarn run cypress:run + - yarn run cypress:run --record # Coverage - yarn run codecov diff --git a/SUMMARY.md b/SUMMARY.md index 11c4b0293..f3ed9d515 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -6,6 +6,7 @@ * [Neo4J](neo4j/README.md) * [Backend](backend/README.md) * [GraphQL](backend/graphql.md) + * [neo4j-graphql-js](backend/neo4j-graphql-js.md) * [Webapp](webapp/README.md) * [Components](webapp/components.md) * [HTML](webapp/html.md) diff --git a/VERSION b/VERSION index 1a030947e..9767cc98e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.9 +0.1.10 diff --git a/backend/.env.template b/backend/.env.template index 5ecc5a5c4..b4c91da9a 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -1,7 +1,6 @@ NEO4J_URI=bolt://localhost:7687 NEO4J_USERNAME=neo4j NEO4J_PASSWORD=letmein -GRAPHQL_PORT=4000 GRAPHQL_URI=http://localhost:4000 CLIENT_URI=http://localhost:3000 SMTP_HOST= diff --git a/backend/neo4j-graphql-js.md b/backend/neo4j-graphql-js.md new file mode 100644 index 000000000..280942acd --- /dev/null +++ b/backend/neo4j-graphql-js.md @@ -0,0 +1,16 @@ +# neo4j-graphql.js + +We use an npm package called `neo4j-graphql-js` as a cypher query builder. This +library also generates resolvers for graphql queries, unless we implement them +ourselves. + + +## Debugging + +As you can see in their [documentation](https://github.com/neo4j-graphql/neo4j-graphql-js) +it is possible to log out the generated cypher statements. To do so, run the +backend like this: + +```sh +DEBUG=neo4j-graphql-js yarn run dev +``` diff --git a/backend/package.json b/backend/package.json index 699dc9972..c0f8759a2 100644 --- a/backend/package.json +++ b/backend/package.json @@ -35,12 +35,12 @@ }, "dependencies": { "@hapi/joi": "^16.1.7", - "@sentry/node": "^5.8.0", + "@sentry/node": "^5.9.0", "apollo-cache-inmemory": "~1.6.3", "apollo-client": "~2.6.4", "apollo-link-context": "~1.0.19", "apollo-link-http": "~1.5.16", - "apollo-server": "~2.9.7", + "apollo-server": "~2.9.9", "apollo-server-express": "^2.9.7", "babel-plugin-transform-runtime": "^6.23.0", "bcryptjs": "~2.4.3", @@ -64,26 +64,26 @@ "linkifyjs": "~2.1.8", "lodash": "~4.17.14", "merge-graphql-schemas": "^1.7.3", - "metascraper": "^4.10.3", - "metascraper-audio": "^5.7.17", - "metascraper-author": "^5.7.17", + "metascraper": "^5.8.8", + "metascraper-audio": "^5.8.7", + "metascraper-author": "^5.8.7", "metascraper-clearbit-logo": "^5.3.0", - "metascraper-date": "^5.7.17", - "metascraper-description": "^5.7.17", - "metascraper-image": "^5.7.17", - "metascraper-lang": "^5.7.17", - "metascraper-lang-detector": "^4.8.5", - "metascraper-logo": "^5.7.17", - "metascraper-publisher": "^5.7.17", - "metascraper-soundcloud": "^5.7.17", - "metascraper-title": "^5.7.17", - "metascraper-url": "^5.7.17", - "metascraper-video": "^5.7.17", - "metascraper-youtube": "^5.7.17", + "metascraper-date": "^5.8.7", + "metascraper-description": "^5.8.7", + "metascraper-image": "^5.8.7", + "metascraper-lang": "^5.8.7", + "metascraper-lang-detector": "^4.10.2", + "metascraper-logo": "^5.8.7", + "metascraper-publisher": "^5.8.7", + "metascraper-soundcloud": "^5.8.7", + "metascraper-title": "^5.8.7", + "metascraper-url": "^5.8.7", + "metascraper-video": "^5.8.7", + "metascraper-youtube": "^5.8.7", "minimatch": "^3.0.4", "mustache": "^3.1.0", "neo4j-driver": "~1.7.6", - "neo4j-graphql-js": "^2.8.0", + "neo4j-graphql-js": "^2.9.3", "neode": "^0.3.3", "node-fetch": "~2.6.0", "nodemailer": "^6.3.1", @@ -105,24 +105,24 @@ "@babel/plugin-proposal-throw-expressions": "^7.2.0", "@babel/preset-env": "~7.7.1", "@babel/register": "~7.7.0", - "apollo-server-testing": "~2.9.7", + "apollo-server-testing": "~2.9.9", "babel-core": "~7.0.0-0", "babel-eslint": "~10.0.3", "babel-jest": "~24.9.0", "chai": "~4.2.0", - "cucumber": "~6.0.3", + "cucumber": "~6.0.5", "eslint": "~6.6.0", - "eslint-config-prettier": "~6.5.0", + "eslint-config-prettier": "~6.7.0", "eslint-config-standard": "~14.1.0", "eslint-plugin-import": "~2.18.2", - "eslint-plugin-jest": "~23.0.3", + "eslint-plugin-jest": "~23.0.4", "eslint-plugin-node": "~10.0.0", "eslint-plugin-prettier": "~3.1.1", "eslint-plugin-promise": "~4.2.1", "eslint-plugin-standard": "~4.0.1", "jest": "~24.9.0", "nodemon": "~1.19.4", - "prettier": "~1.18.2", + "prettier": "~1.19.1", "supertest": "~4.0.2" } } diff --git a/backend/snapshots/embeds/HumanConnectionOrg.html b/backend/snapshots/embeds/HumanConnectionOrg.html new file mode 100644 index 000000000..67a7844d2 --- /dev/null +++ b/backend/snapshots/embeds/HumanConnectionOrg.html @@ -0,0 +1,2667 @@ + + + + + + + +Human Connection - Startseite | +Facebook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
Gehe +zu:
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Mehr von Human Connection auf Facebook +anzeigen
+ +
+
+
+
+
+
Mehr von Human Connection auf Facebook +anzeigen
+
+
+ +
+
+
+
+
+
+ + +
+
+
+
+
oder
+
+Neues Konto erstellen + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Willkommen bei Human Connection
+
+
Human Connection +ist ein gemeinnütziges soziales Wissens- und Aktionsnetzwerk mit +Sitz in Weilheim-T...
+
+Mehr anzeigen
+
+
+
CommunityAlle +ansehen +
+
+
+
+
+"Highlights
+
+
24.407 Personen gefällt das
+
+
+
+
+
+
+"Highlights
+
+
25.652 Personen haben das abonniert
+
+
+
+
+
+
+"Highlights
+
+
72 Besuche
+
+
+
+
+
+
InfoAlle ansehen +
+
+
+ +
+
+
+
+"Highlights
+
+
Bahnhofstraße 11 (512,71 km)
+73235 Weilheim an der Teck
+ +
+
+
+
+
+
+"Highlights
+
+
01514 3804222
+
+
+
+ +
+ +
+
+
+ +
+
+
+
+
+"Highlights
+
+
Preisklasse €
+
+
+
+
+ +
+
+
+
SeitentransparenzMehr +anzeigen +
+
+
Facebook liefert +Informationen, mit denen du die Intention von Seiten besser +verstehst. Hier erfährst du mehr zu den Personen, die die Seiten +verwalten und Beiträge darin posten.
+
+
+Seite erstellt – 21. Oktober 2015
+
+
+
+
+
+
+
+
+
+
+
+
+
Personen
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Ähnliche +Seiten
+
+ +
+
+
+
+
+
+
+
+ +
Seiten, die +dieser Seite gefallen
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
Orte +Weilheim an der Teck +Human Connection
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
Beiträge +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+

Human Connection soll mehr als nur ein einfacher Facebookersatz +werden – nämlich vor allem lösungsorientiert und zukunftsfähig. Wir +möchten mit unserem Netzwerk dazu beitragen, dass mehr Menschen +aktiv werden und selbst etwas verändern. Vor allem möchten wir, +dass sie nicht jede negative Neuigkeit in einem sozialen Netzwerk +“schlucken” müssen. Der Gedanke man könne doch eh nichts ändern, +stimmt nur dann, wenn andere Leser genauso denken. Gemeinsam ist so +viel mehr möglich und... +dafür braucht es zunächst erst +einmal jeden Einzelnen.

+
+

Wie kann Human Connection dabei helfen?

+

Das erfahrt ihr im ganzen Beitrag:
+https://human-connection.org/human-connection-loesungsorie…/

+
+Mehr anzeigen
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+

Human Connection ist unser Herzensprojekt, welches allerdings +uns und auch euch sehr viel Geduld abfordert. Warum dauert das +eigentlich so lange?

+

Hier erfahrt ihr die Antwort:

+
+
+
+
+
+
+
+ +
+
+
+
+
human-connection.org
+
+
+
+
+ +
Human Connection ist +unser Herzensprojekt, welches allerdings uns und auch euch sehr +viel Geduld abfordert. Warum dauert das eigentlich so +lange?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
Videos +
+
+
+
+
+
Schau es an und Du +weißt, was zu tun ist
+ +
+
+
+
+
+
+
+
+
+
+
+
10
+
+
+
+
2
+
+
+
+
+
+
+
+
+Messe Fair Handeln: Human Connection beim Hackathon (Stuttgart +26.-28.04.2019)
+ +
+
+
+
+
+
+
+
+
+
+
9
+
+
+
+
1
+
+
+
+
+
+
+
+
In +Nerds We Trust - Open Source - Wir lieben freie +Software!
+ +
+
+
+
+
+
+
+
+
+
+
4
+
+
+
+
1
+
+
+
+
+
+
+
+ +
+
+
+
Fotos +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + diff --git a/backend/snapshots/embeds/babyLovesCat.html b/backend/snapshots/embeds/babyLovesCat.html new file mode 100644 index 000000000..61db8cf72 --- /dev/null +++ b/backend/snapshots/embeds/babyLovesCat.html @@ -0,0 +1,1783 @@ + + + + + + + + + + + + + Baby Loves Cat - YouTube + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+ + +
+
+
+
+
+ DE +
+
+ +
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+

+ + + +Wird geladen... + +

+ +
+
+
+ +
+
+
+
+
+ +
+ +
+
+
+
+ + Du siehst YouTube auf Deutsch. Du kannst diese Einstellung unten ändern. +
+
+ + You're viewing YouTube in German. You can change this preference below. +
+
+
+
+ +
+
+
+ +
+ +
+
+ + +
+
+ + +
+
+
+
+ +
+
+
+
+ + +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

+ + + + + Baby Loves Cat + + +

+
+
+ + +
+
+ + + + + +
+ +
+
+
+
+
30.160.931 Aufrufe
+
+
+
+
+
+ + + + + +
+
+
+ + + +
+
+
+
+

+ + + +Wird geladen... + +

+ +
+
+
+ +
+ +
+
+
+

+ + + +Wird geladen... + +

+ +
+
+
+

+ Transkript +

+
+ +
+ + + +
+
+ Das interaktive Transkript konnte nicht geladen werden. +
+ + +
+
+ +
+ +
+
+

+ + + +Wird geladen... + +

+ +
+
+ + +
+
+ Die Bewertungsfunktion ist nach Ausleihen des Videos verfügbar. +
+ +
+ +
+
+ Diese Funktion ist gerade nicht verfügbar. Bitte versuche es später noch einmal. +
+
+ + +
+ + +
+ + +
+
+
+
+
Am 16.08.2015 veröffentlicht
+
+

She's incapable of controlling her limbs when her kitty is around. The obsession grows every day.

Ps. That's a sleep sack she's in. Not a starfish outfit. Although I wish I were cool enough to dress my daughter in a starfish outfit.

Jukin Media Verified (Original)
*For licensing / permission to use please contact licensing(at)jukinmediadotcom

+
+
+
    +
  • +

    + Kategorie +

    + +
  • + +
+
+
+
+
+ +
+ + +
+
+
+ + +
+ Kommentare sind für dieses Video deaktiviert. +
+ +
+ + + + +
+
+
+
+ +
+ + +
+
+
+ + + +
+
+ +
+ +
+
+
+ Anzeige +
+
+
+
+ + +
+
+
+
+
+ + + + Wenn Autoplay aktiviert ist, wird die Wiedergabe automatisch mit einem der aktuellen Videovorschläge fortgesetzt. + + + + +
+

+ Nächstes Video +

+ + +
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
+
+ + +
+ +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ , um dieses Video zur Playlist "Später ansehen" hinzuzufügen. + +
+
+
+

+ Hinzufügen +

+
+
+

+ + + + Playlists werden geladen... + +

+ +
+
+
+ + + + + + + diff --git a/backend/src/jest/snapshots/embeds/pr960.html b/backend/snapshots/embeds/pr960.html similarity index 100% rename from backend/src/jest/snapshots/embeds/pr960.html rename to backend/snapshots/embeds/pr960.html diff --git a/backend/src/bootstrap/directives.js b/backend/src/bootstrap/directives.js deleted file mode 100644 index 93a7574fb..000000000 --- a/backend/src/bootstrap/directives.js +++ /dev/null @@ -1,12 +0,0 @@ -import { - GraphQLLowerCaseDirective, - GraphQLTrimDirective, - GraphQLDefaultToDirective, -} from 'graphql-custom-directives' - -export default function applyDirectives(augmentedSchema) { - const directives = [GraphQLLowerCaseDirective, GraphQLTrimDirective, GraphQLDefaultToDirective] - augmentedSchema._directives.push.apply(augmentedSchema._directives, directives) - - return augmentedSchema -} diff --git a/backend/src/bootstrap/scalars.js b/backend/src/bootstrap/scalars.js deleted file mode 100644 index eb6d3739b..000000000 --- a/backend/src/bootstrap/scalars.js +++ /dev/null @@ -1,9 +0,0 @@ -import { GraphQLDate, GraphQLTime, GraphQLDateTime } from 'graphql-iso-date' - -export default function applyScalars(augmentedSchema) { - augmentedSchema._typeMap.Date = GraphQLDate - augmentedSchema._typeMap.Time = GraphQLTime - augmentedSchema._typeMap.DateTime = GraphQLDateTime - - return augmentedSchema -} diff --git a/backend/src/config/index.js b/backend/src/config/index.js index 00361ba63..b67cea0f9 100644 --- a/backend/src/config/index.js +++ b/backend/src/config/index.js @@ -16,7 +16,6 @@ const { NEO4J_URI = 'bolt://localhost:7687', NEO4J_USERNAME = 'neo4j', NEO4J_PASSWORD = 'neo4j', - GRAPHQL_PORT = 4000, CLIENT_URI = 'http://localhost:3000', GRAPHQL_URI = 'http://localhost:4000', } = process.env @@ -36,7 +35,6 @@ export const smtpConfigs = { } export const neo4jConfigs = { NEO4J_URI, NEO4J_USERNAME, NEO4J_PASSWORD } export const serverConfigs = { - GRAPHQL_PORT, CLIENT_URI, GRAPHQL_URI, PUBLIC_REGISTRATION: process.env.PUBLIC_REGISTRATION === 'true', diff --git a/backend/src/helpers/jest.js b/backend/src/helpers/jest.js new file mode 100644 index 000000000..201d68c14 --- /dev/null +++ b/backend/src/helpers/jest.js @@ -0,0 +1,5 @@ +//* This is a fake ES2015 template string, just to benefit of syntax +// highlighting of `gql` template strings in certain editors. +export function gql(strings) { + return strings.join('') +} diff --git a/backend/src/index.js b/backend/src/index.js index 0e7fc233c..98354dc1f 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -2,7 +2,8 @@ import createServer from './server' import CONFIG from './config' const { app } = createServer() -app.listen({ port: CONFIG.GRAPHQL_PORT }, () => { +const url = new URL(CONFIG.GRAPHQL_URI) +app.listen({ port: url.port }, () => { /* eslint-disable-next-line no-console */ console.log(`GraphQLServer ready at ${CONFIG.GRAPHQL_URI} 🚀`) }) diff --git a/backend/src/jest/snapshots/embeds/HumanConnectionOrg.html b/backend/src/jest/snapshots/embeds/HumanConnectionOrg.html deleted file mode 100644 index ed3f96cda..000000000 --- a/backend/src/jest/snapshots/embeds/HumanConnectionOrg.html +++ /dev/null @@ -1,38 +0,0 @@ - - -Human Connection - Startseite | Facebook - - - - - - - - - - - - - - - - - - - - - - - -
Mehr von Human Connection auf Facebook anzeigen
Mehr von Human Connection auf Facebook anzeigen
oder
Neues Konto erstellen
Willkommen bei Human Connection
Human Connection ist ein gemeinnütziges soziales Wissens- und Aktionsnetzwerk mit Sitz in Weilheim-T...
Mehr anzeigen
CommunityAlle ansehen
Highlights info row image
24.407 Personen gefällt das
Highlights info row image
25.652 Personen haben das abonniert
Highlights info row image
72 Besuche
Highlights info row image
Bahnhofstraße 11 (512,71 km)
73235 Weilheim an der Teck
Highlights info row image
01514 3804222
Highlights info row image
Preisklasse €
SeitentransparenzMehr anzeigen
Facebook liefert Informationen, mit denen du die Intention von Seiten besser verstehst. Hier erfährst du mehr zu den Personen, die die Seiten verwalten und Beiträge darin posten.
Seite erstellt – 21. Oktober 2015
Ähnliche Seiten
OrteWeilheim an der TeckHuman Connection
Beiträge

Human Connection soll mehr als nur ein einfacher Facebookersatz werden – nämlich vor allem lösungsorientiert und zukunftsfähig. Wir möchten mit unserem Netzwerk dazu beitragen, dass mehr Menschen aktiv werden und selbst etwas verändern. Vor allem möchten wir, dass sie nicht jede negative Neuigkeit in einem sozialen Netzwerk “schlucken” müssen. Der Gedanke man könne doch eh nichts ändern, stimmt nur dann, wenn andere Leser genauso denken. Gemeinsam ist so viel mehr möglich und... dafür braucht es zunächst erst einmal jeden Einzelnen.

Wie kann Human Connection dabei helfen?

Das erfahrt ihr im ganzen Beitrag:
https://human-connection.org/human-connection-loesungsorie…/

Mehr anzeigen
Bild könnte enthalten: Text

Human Connection ist unser Herzensprojekt, welches allerdings uns und auch euch sehr viel Geduld abfordert. Warum dauert das eigentlich so lange?

Hier erfahrt ihr die Antwort:

human-connection.org
Human Connection ist unser Herzensprojekt, welches allerdings uns und auch euch sehr viel Geduld abfordert. Warum dauert das eigentlich so lange?
Videos
Schau es an und Du weißt, was zu tun ist
10
2
Messe Fair Handeln: Human Connection beim Hackathon (Stuttgart 26.-28.04.2019)
9
1
In Nerds We Trust - Open Source - Wir lieben freie Software!
4
1
- - - - \ No newline at end of file diff --git a/backend/src/jest/snapshots/embeds/babyLovesCat.html b/backend/src/jest/snapshots/embeds/babyLovesCat.html deleted file mode 100644 index 88ce2a327..000000000 --- a/backend/src/jest/snapshots/embeds/babyLovesCat.html +++ /dev/null @@ -1,1545 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - -Baby Loves Cat - YouTube - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
-
-
-
- DE -
-
-
- -
-
-
-

- - - -Wird geladen... - -

- -
-
-
- -
- -
-
-
- -Du siehst YouTube auf Deutsch. -Du kannst diese Einstellung unten ändern. -
-
- - You're viewing YouTube in German. - You can change this preference below. -
-
-
- -
-
- -
-
- - -
-
-
- -
-
-
-
- - -
-
-
-
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-

- - - - - Baby Loves Cat - - -

-
-
- - -
- - - - - -
-
30.160.931 Aufrufe
-
-
-
-
-
- - - - - -
-
- - - -
-
-
-
-

- - - -Wird geladen... - -

- -
-
-
- -
- -
-
-
-

- - - -Wird geladen... - -

- -
-
-
-

-Transkript -

-
- -
- - - -
-
-Das interaktive Transkript konnte nicht geladen werden. -
- - -
-
- -
- -
-
-

- - - -Wird geladen... - -

- -
-
- - -
-
- Die Bewertungsfunktion ist nach Ausleihen des Videos verfügbar. -
- -
- -
-
- Diese Funktion ist gerade nicht verfügbar. Bitte versuche es später noch einmal. -
-
- - -
- - -
- - -
Am 16.08.2015 veröffentlicht

She's incapable of controlling her limbs when her kitty is around. The obsession grows every day.

Ps. That's a sleep sack she's in. Not a starfish outfit. Although I wish I were cool enough to dress my daughter in a starfish outfit.

Jukin Media Verified (Original)
*For licensing / permission to use please contact licensing(at)jukinmediadotcom

-
    -
  • -

    - Kategorie -

    - -
  • - -
-
-
- -
- - -
-
-
- - -
- Kommentare sind für dieses Video deaktiviert. -
- -
- - - - -
-
-
-
- -
- - -
-
-
- - - -
-
- -
- -
-
-
-Anzeige -
-
-
-
- - -
-
-
-
-
- - - -Wenn Autoplay aktiviert ist, wird die Wiedergabe automatisch mit einem der aktuellen Videovorschläge fortgesetzt. - - - -
-

- Nächstes Video -

- - -
-
- - -
-
-
- -
-
- -
-
- -
-
-
- - -
- -
- -
-
- - -
-
- - -
- , um dieses Video zur Playlist "Später ansehen" hinzuzufügen. - -
-
-

-Hinzufügen -

-
-
-

- - - - Playlists werden geladen... - -

- -
-
- - - - - - - \ No newline at end of file diff --git a/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js b/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js index 89f1bdd86..6e97f34c4 100644 --- a/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js +++ b/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js @@ -1,4 +1,4 @@ -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import Factory from '../../seed/factories' import { createTestClient } from 'apollo-server-testing' import { neode, getDriver } from '../../bootstrap/neo4j' diff --git a/backend/src/middleware/notifications/notificationsMiddleware.spec.js b/backend/src/middleware/notifications/notificationsMiddleware.spec.js index 18ee998db..502ddaa8e 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.spec.js +++ b/backend/src/middleware/notifications/notificationsMiddleware.spec.js @@ -1,4 +1,4 @@ -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import Factory from '../../seed/factories' import { createTestClient } from 'apollo-server-testing' import { neode, getDriver } from '../../bootstrap/neo4j' diff --git a/backend/src/middleware/orderByMiddleware.spec.js b/backend/src/middleware/orderByMiddleware.spec.js index 7a42166cf..a7b31da0a 100644 --- a/backend/src/middleware/orderByMiddleware.spec.js +++ b/backend/src/middleware/orderByMiddleware.spec.js @@ -1,5 +1,5 @@ +import { gql } from '../helpers/jest' import Factory from '../seed/factories' -import { gql } from '../jest/helpers' import { neode as getNeode, getDriver } from '../bootstrap/neo4j' import { createTestClient } from 'apollo-server-testing' import createServer from '../server' diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index d312bc112..b0d07c8ec 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -41,20 +41,6 @@ const isMySocialMedia = rule({ return socialMedia.ownedBy.node.id === user.id }) -/* TODO: decide if we want to remove this check: the check - * `onlyEnabledContent` throws authorization errors only if you have - * arguments for `disabled` or `deleted` assuming these are filter - * parameters. Soft-delete middleware obfuscates data on its way out - * anyways. Furthermore, `neo4j-graphql-js` offers many ways to filter for - * data so I believe, this is not a good check anyways. - */ -const onlyEnabledContent = rule({ - cache: 'strict', -})(async (parent, args, ctx, info) => { - const { disabled, deleted } = args - return !(disabled || deleted) -}) - const invitationLimitReached = rule({ cache: 'no_cache', })(async (parent, args, { user, driver }) => { @@ -125,7 +111,8 @@ const permissions = shield( reports: isModerator, statistics: allow, currentUser: allow, - Post: or(onlyEnabledContent, isModerator), + Post: allow, + profilePagePosts: allow, Comment: allow, User: or(noEmailFilter, isAdmin), isLoggedIn: allow, @@ -134,7 +121,6 @@ const permissions = shield( PostsEmotionsByCurrentUser: isAuthenticated, blockedUsers: isAuthenticated, notifications: isAuthenticated, - profilePagePosts: or(onlyEnabledContent, isModerator), Donations: isAuthenticated, }, Mutation: { diff --git a/backend/src/middleware/permissionsMiddleware.spec.js b/backend/src/middleware/permissionsMiddleware.spec.js index da703fb11..340766136 100644 --- a/backend/src/middleware/permissionsMiddleware.spec.js +++ b/backend/src/middleware/permissionsMiddleware.spec.js @@ -1,7 +1,7 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../server' import Factory from '../seed/factories' -import { gql } from '../jest/helpers' +import { gql } from '../helpers/jest' import { getDriver, neode as getNeode } from '../bootstrap/neo4j' const factory = Factory() diff --git a/backend/src/middleware/sluggifyMiddleware.js b/backend/src/middleware/sluggifyMiddleware.js index 03d7f8584..fed9b4da7 100644 --- a/backend/src/middleware/sluggifyMiddleware.js +++ b/backend/src/middleware/sluggifyMiddleware.js @@ -25,9 +25,5 @@ export default { args.slug = args.slug || (await uniqueSlug(args.title, isUniqueFor(context, 'Post'))) return resolve(root, args, context, info) }, - CreateCategory: async (resolve, root, args, context, info) => { - args.slug = args.slug || (await uniqueSlug(args.name, isUniqueFor(context, 'Category'))) - return resolve(root, args, context, info) - }, }, } diff --git a/backend/src/middleware/slugifyMiddleware.spec.js b/backend/src/middleware/slugifyMiddleware.spec.js index e65b7ba6c..02699f7b2 100644 --- a/backend/src/middleware/slugifyMiddleware.spec.js +++ b/backend/src/middleware/slugifyMiddleware.spec.js @@ -1,5 +1,5 @@ import Factory from '../seed/factories' -import { gql } from '../jest/helpers' +import { gql } from '../helpers/jest' import { neode as getNeode, getDriver } from '../bootstrap/neo4j' import createServer from '../server' import { createTestClient } from 'apollo-server-testing' diff --git a/backend/src/middleware/softDelete/softDeleteMiddleware.js b/backend/src/middleware/softDelete/softDeleteMiddleware.js index 3360d4085..8be8c3d39 100644 --- a/backend/src/middleware/softDelete/softDeleteMiddleware.js +++ b/backend/src/middleware/softDelete/softDeleteMiddleware.js @@ -3,9 +3,7 @@ const isModerator = ({ user }) => { } const setDefaultFilters = (resolve, root, args, context, info) => { - if (typeof args.deleted !== 'boolean') { - args.deleted = false - } + args.deleted = false if (!isModerator(context)) { args.disabled = false diff --git a/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js b/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js index 5b04abebd..6da080ebb 100644 --- a/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js +++ b/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js @@ -1,5 +1,5 @@ import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { neode as getNeode, getDriver } from '../../bootstrap/neo4j' import createServer from '../../server' import { createTestClient } from 'apollo-server-testing' @@ -341,76 +341,6 @@ describe('softDeleteMiddleware', () => { }) }) }) - - describe('filter (deleted: true)', () => { - beforeEach(() => { - graphqlQuery = gql` - { - Post(deleted: true) { - title - } - } - ` - }) - - describe('as user', () => { - beforeEach(async () => { - authenticatedUser = await user.toJson() - }) - - it('throws authorisation error', async () => { - const { data, errors } = await action() - expect(data).toEqual({ Post: null }) - expect(errors[0]).toHaveProperty('message', 'Not Authorised!') - }) - }) - - describe('as moderator', () => { - beforeEach(async () => { - authenticatedUser = await moderator.toJson() - }) - - it('does not show deleted posts', async () => { - const expected = { data: { Post: [{ title: 'UNAVAILABLE' }] } } - await expect(action()).resolves.toMatchObject(expected) - }) - }) - }) - - describe('filter (disabled: true)', () => { - beforeEach(() => { - graphqlQuery = gql` - { - Post(disabled: true) { - title - } - } - ` - }) - - describe('as user', () => { - beforeEach(async () => { - authenticatedUser = await user.toJson() - }) - - it('throws authorisation error', async () => { - const { data, errors } = await action() - expect(data).toEqual({ Post: null }) - expect(errors[0]).toHaveProperty('message', 'Not Authorised!') - }) - }) - - describe('as moderator', () => { - beforeEach(async () => { - authenticatedUser = await moderator.toJson() - }) - - it('shows disabled posts', async () => { - const expected = { data: { Post: [{ title: 'Disabled post' }] } } - await expect(action()).resolves.toMatchObject(expected) - }) - }) - }) }) }) }) diff --git a/backend/src/models/User.js b/backend/src/models/User.js index b24148f00..fd6e88c27 100644 --- a/backend/src/models/User.js +++ b/backend/src/models/User.js @@ -127,6 +127,10 @@ module.exports = { type: 'boolean', default: false, }, + showShoutsPublicly: { + type: 'boolean', + default: false, + }, locale: { type: 'string', allow: [null], diff --git a/backend/src/schema/helpers.js b/backend/src/schema/helpers.js deleted file mode 100644 index fe61ccf57..000000000 --- a/backend/src/schema/helpers.js +++ /dev/null @@ -1,9 +0,0 @@ -export const undefinedToNull = list => { - const resolvers = {} - list.forEach(key => { - resolvers[key] = async (parent, params, context, resolveInfo) => { - return typeof parent[key] === 'undefined' ? null : parent[key] - } - }) - return resolvers -} diff --git a/backend/src/schema/index.js b/backend/src/schema/index.js index b1bd36451..516f47abd 100644 --- a/backend/src/schema/index.js +++ b/backend/src/schema/index.js @@ -1,56 +1,27 @@ import { makeAugmentedSchema } from 'neo4j-graphql-js' -import CONFIG from './../config' -import applyScalars from './../bootstrap/scalars' -import applyDirectives from './../bootstrap/directives' import typeDefs from './types' import resolvers from './resolvers' -export default applyScalars( - applyDirectives( - makeAugmentedSchema({ - typeDefs, - resolvers, - config: { - query: { - exclude: [ - 'Badge', - 'Embed', - 'InvitationCode', - 'EmailAddress', - 'Notfication', - 'Statistics', - 'LoggedInUser', - 'Location', - 'SocialMedia', - 'NOTIFIED', - 'REPORTED', - 'Donations', - ], - // add 'User' here as soon as possible - }, - mutation: { - exclude: [ - 'Badge', - 'Embed', - 'InvitationCode', - 'EmailAddress', - 'Notfication', - 'Post', - 'Comment', - 'Statistics', - 'LoggedInUser', - 'Location', - 'SocialMedia', - 'User', - 'EMOTED', - 'NOTIFIED', - 'REPORTED', - 'Donations', - ], - // add 'User' here as soon as possible - }, - debug: !!CONFIG.DEBUG, - }, - }), - ), -) +export default makeAugmentedSchema({ + typeDefs, + resolvers, + config: { + query: { + exclude: [ + 'Badge', + 'Embed', + 'InvitationCode', + 'EmailAddress', + 'Notfication', + 'Statistics', + 'LoggedInUser', + 'Location', + 'SocialMedia', + 'NOTIFIED', + 'REPORTED', + 'Donations', + ], + }, + mutation: false, + }, +}) diff --git a/backend/src/schema/resolvers/badges.js b/backend/src/schema/resolvers/badges.js index 19bc24fd6..d10d6b482 100644 --- a/backend/src/schema/resolvers/badges.js +++ b/backend/src/schema/resolvers/badges.js @@ -3,7 +3,7 @@ import { neo4jgraphql } from 'neo4j-graphql-js' export default { Query: { Badge: async (object, args, context, resolveInfo) => { - return neo4jgraphql(object, args, context, resolveInfo, false) + return neo4jgraphql(object, args, context, resolveInfo) }, }, } diff --git a/backend/src/schema/resolvers/comments.spec.js b/backend/src/schema/resolvers/comments.spec.js index ba7364a7f..c0f86ffe3 100644 --- a/backend/src/schema/resolvers/comments.spec.js +++ b/backend/src/schema/resolvers/comments.spec.js @@ -1,5 +1,5 @@ import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { createTestClient } from 'apollo-server-testing' import createServer from '../../server' import { neode as getNeode, getDriver } from '../../bootstrap/neo4j' diff --git a/backend/src/schema/resolvers/donations.spec.js b/backend/src/schema/resolvers/donations.spec.js index 327688d3a..9e701059d 100644 --- a/backend/src/schema/resolvers/donations.spec.js +++ b/backend/src/schema/resolvers/donations.spec.js @@ -1,6 +1,6 @@ import { createTestClient } from 'apollo-server-testing' import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { neode as getNeode, getDriver } from '../../bootstrap/neo4j' import createServer from '../../server' diff --git a/backend/src/schema/resolvers/emails.spec.js b/backend/src/schema/resolvers/emails.spec.js index ea3491d1e..156007435 100644 --- a/backend/src/schema/resolvers/emails.spec.js +++ b/backend/src/schema/resolvers/emails.spec.js @@ -1,5 +1,5 @@ import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { getDriver, neode as getNeode } from '../../bootstrap/neo4j' import createServer from '../../server' import { createTestClient } from 'apollo-server-testing' diff --git a/backend/src/schema/resolvers/embeds.spec.js b/backend/src/schema/resolvers/embeds.spec.js index eabd2553e..7683505eb 100644 --- a/backend/src/schema/resolvers/embeds.spec.js +++ b/backend/src/schema/resolvers/embeds.spec.js @@ -3,7 +3,7 @@ import fs from 'fs' import path from 'path' import { createTestClient } from 'apollo-server-testing' import createServer from '../../server' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' jest.mock('node-fetch') const { Response } = jest.requireActual('node-fetch') @@ -15,15 +15,12 @@ afterEach(() => { let variables = {} const HumanConnectionOrg = fs.readFileSync( - path.join(__dirname, '../../jest/snapshots/embeds/HumanConnectionOrg.html'), - 'utf8', -) -const pr960 = fs.readFileSync( - path.join(__dirname, '../../jest/snapshots/embeds/pr960.html'), + path.join(__dirname, '../../../snapshots/embeds/HumanConnectionOrg.html'), 'utf8', ) +const pr960 = fs.readFileSync(path.join(__dirname, '../../../snapshots/embeds/pr960.html'), 'utf8') const babyLovesCat = fs.readFileSync( - path.join(__dirname, '../../jest/snapshots/embeds/babyLovesCat.html'), + path.join(__dirname, '../../../snapshots/embeds/babyLovesCat.html'), 'utf8', ) @@ -88,7 +85,7 @@ describe('Query', () => { }) it('shows some default data', async () => { - const expected = expect.objectContaining({ + await expect(embedAction(variables)).resolves.toMatchObject({ data: { embed: { audio: null, @@ -98,7 +95,7 @@ describe('Query', () => { html: null, image: null, lang: null, - publisher: 'YouTube', + publisher: null, sources: ['resource'], title: null, type: 'link', @@ -106,8 +103,8 @@ describe('Query', () => { video: null, }, }, + errors: undefined, }) - await expect(embedAction(variables)).resolves.toEqual(expected) }) }) @@ -120,7 +117,7 @@ describe('Query', () => { }) it('does not crash if embed provider returns invalid JSON', async () => { - const expected = expect.objectContaining({ + await expect(embedAction(variables)).resolves.toMatchObject({ data: { embed: { audio: null, @@ -140,8 +137,8 @@ describe('Query', () => { video: null, }, }, + errors: undefined, }) - await expect(embedAction(variables)).resolves.toEqual(expected) }) }) @@ -154,7 +151,7 @@ describe('Query', () => { }) it('returns meta data even if no embed html can be retrieved', async () => { - const expected = expect.objectContaining({ + await expect(embedAction(variables)).resolves.toMatchObject({ data: { embed: { type: 'link', @@ -174,8 +171,8 @@ describe('Query', () => { html: null, }, }, + errors: undefined, }) - await expect(embedAction(variables)).resolves.toEqual(expected) }) }) @@ -188,7 +185,7 @@ describe('Query', () => { }) it('returns meta data plus youtube iframe html', async () => { - const expected = expect.objectContaining({ + await expect(embedAction(variables)).resolves.toMatchObject({ data: { embed: { type: 'video', @@ -208,8 +205,8 @@ describe('Query', () => { '', }, }, + errors: undefined, }) - await expect(embedAction(variables)).resolves.toEqual(expected) }) }) }) diff --git a/backend/src/schema/resolvers/follow.spec.js b/backend/src/schema/resolvers/follow.spec.js index c7da80695..8402842e2 100644 --- a/backend/src/schema/resolvers/follow.spec.js +++ b/backend/src/schema/resolvers/follow.spec.js @@ -2,7 +2,7 @@ import { createTestClient } from 'apollo-server-testing' import Factory from '../../seed/factories' import { getDriver, neode as getNeode } from '../../bootstrap/neo4j' import createServer from '../../server' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' const factory = Factory() const driver = getDriver() diff --git a/backend/src/schema/resolvers/locations.spec.js b/backend/src/schema/resolvers/locations.spec.js index aed2419e0..51dafcc2e 100644 --- a/backend/src/schema/resolvers/locations.spec.js +++ b/backend/src/schema/resolvers/locations.spec.js @@ -1,5 +1,5 @@ import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { neode as getNeode, getDriver } from '../../bootstrap/neo4j' import createServer from '../../server' import { createTestClient } from 'apollo-server-testing' diff --git a/backend/src/schema/resolvers/moderation.spec.js b/backend/src/schema/resolvers/moderation.spec.js index 2ac0dd934..765126c52 100644 --- a/backend/src/schema/resolvers/moderation.spec.js +++ b/backend/src/schema/resolvers/moderation.spec.js @@ -1,6 +1,6 @@ import { createTestClient } from 'apollo-server-testing' import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { neode as getNeode, getDriver } from '../../bootstrap/neo4j' import createServer from '../../server' diff --git a/backend/src/schema/resolvers/notifications.spec.js b/backend/src/schema/resolvers/notifications.spec.js index 1b9cac102..24b8280bd 100644 --- a/backend/src/schema/resolvers/notifications.spec.js +++ b/backend/src/schema/resolvers/notifications.spec.js @@ -1,5 +1,5 @@ import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { getDriver } from '../../bootstrap/neo4j' import { createTestClient } from 'apollo-server-testing' import createServer from '../.././server' diff --git a/backend/src/schema/resolvers/passwordReset.spec.js b/backend/src/schema/resolvers/passwordReset.spec.js index b8633e9c3..8b36b8c85 100644 --- a/backend/src/schema/resolvers/passwordReset.spec.js +++ b/backend/src/schema/resolvers/passwordReset.spec.js @@ -1,5 +1,5 @@ import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { neode as getNeode, getDriver } from '../../bootstrap/neo4j' import createPasswordReset from './helpers/createPasswordReset' import createServer from '../../server' diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index c6b36fe9d..ee6a82d42 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -29,7 +29,7 @@ const filterForBlockedUsers = async (params, context) => { } const maintainPinnedPosts = params => { - const pinnedPostFilter = { pinnedBy_in: { role_in: ['admin'] } } + const pinnedPostFilter = { pinned: true } if (isEmpty(params.filter)) { params.filter = { OR: [pinnedPostFilter, {}] } } else { @@ -43,15 +43,15 @@ export default { Post: async (object, params, context, resolveInfo) => { params = await filterForBlockedUsers(params, context) params = await maintainPinnedPosts(params) - return neo4jgraphql(object, params, context, resolveInfo, false) + return neo4jgraphql(object, params, context, resolveInfo) }, findPosts: async (object, params, context, resolveInfo) => { params = await filterForBlockedUsers(params, context) - return neo4jgraphql(object, params, context, resolveInfo, false) + return neo4jgraphql(object, params, context, resolveInfo) }, profilePagePosts: async (object, params, context, resolveInfo) => { params = await filterForBlockedUsers(params, context) - return neo4jgraphql(object, params, context, resolveInfo, false) + return neo4jgraphql(object, params, context, resolveInfo) }, PostsEmotionsCountByEmotion: async (object, params, context, resolveInfo) => { const session = context.driver.session() diff --git a/backend/src/schema/resolvers/posts.spec.js b/backend/src/schema/resolvers/posts.spec.js index 9106e4eb9..d6a97191d 100644 --- a/backend/src/schema/resolvers/posts.spec.js +++ b/backend/src/schema/resolvers/posts.spec.js @@ -1,6 +1,6 @@ import { createTestClient } from 'apollo-server-testing' import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { neode as getNeode, getDriver } from '../../bootstrap/neo4j' import createServer from '../../server' @@ -210,6 +210,7 @@ describe('Post', () => { data: { Post: expect.arrayContaining(expected), }, + errors: undefined, }) }) }) @@ -229,7 +230,9 @@ describe('Post', () => { await user.relateTo(followedUser, 'following') variables = { filter: { author: { followedBy_some: { id: 'current-user' } } } } - const expected = { + await expect( + query({ query: postQueryFilteredByUsersFollowed, variables }), + ).resolves.toMatchObject({ data: { Post: [ { @@ -238,10 +241,8 @@ describe('Post', () => { }, ], }, - } - await expect( - query({ query: postQueryFilteredByUsersFollowed, variables }), - ).resolves.toMatchObject(expected) + errors: undefined, + }) }) }) }) diff --git a/backend/src/schema/resolvers/registration.spec.js b/backend/src/schema/resolvers/registration.spec.js index c2b83324d..7d53b63c9 100644 --- a/backend/src/schema/resolvers/registration.spec.js +++ b/backend/src/schema/resolvers/registration.spec.js @@ -1,5 +1,5 @@ import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { getDriver, neode as getNeode } from '../../bootstrap/neo4j' import createServer from '../../server' import { createTestClient } from 'apollo-server-testing' diff --git a/backend/src/schema/resolvers/reports.spec.js b/backend/src/schema/resolvers/reports.spec.js index 21b1b4a7b..2ecd1f20d 100644 --- a/backend/src/schema/resolvers/reports.spec.js +++ b/backend/src/schema/resolvers/reports.spec.js @@ -1,7 +1,7 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../.././server' import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { getDriver, neode as getNeode } from '../../bootstrap/neo4j' const factory = Factory() diff --git a/backend/src/schema/resolvers/rewards.spec.js b/backend/src/schema/resolvers/rewards.spec.js index a81133373..2dcdd5b53 100644 --- a/backend/src/schema/resolvers/rewards.spec.js +++ b/backend/src/schema/resolvers/rewards.spec.js @@ -1,6 +1,6 @@ import { createTestClient } from 'apollo-server-testing' import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { neode as getNeode, getDriver } from '../../bootstrap/neo4j' import createServer from '../../server' diff --git a/backend/src/schema/resolvers/shout.spec.js b/backend/src/schema/resolvers/shout.spec.js index 462dc15be..f39e4d137 100644 --- a/backend/src/schema/resolvers/shout.spec.js +++ b/backend/src/schema/resolvers/shout.spec.js @@ -1,6 +1,6 @@ import { createTestClient } from 'apollo-server-testing' import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { neode as getNeode, getDriver } from '../../bootstrap/neo4j' import createServer from '../../server' diff --git a/backend/src/schema/resolvers/socialMedia.spec.js b/backend/src/schema/resolvers/socialMedia.spec.js index 1bbcb8d5b..092139747 100644 --- a/backend/src/schema/resolvers/socialMedia.spec.js +++ b/backend/src/schema/resolvers/socialMedia.spec.js @@ -1,7 +1,7 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../../server' import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { neode, getDriver } from '../../bootstrap/neo4j' const driver = getDriver() diff --git a/backend/src/schema/resolvers/user_management.spec.js b/backend/src/schema/resolvers/user_management.spec.js index 4fe21f92a..9d7dff2a3 100644 --- a/backend/src/schema/resolvers/user_management.spec.js +++ b/backend/src/schema/resolvers/user_management.spec.js @@ -1,7 +1,7 @@ import jwt from 'jsonwebtoken' import CONFIG from './../../config' import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { createTestClient } from 'apollo-server-testing' import createServer, { context } from '../../server' import encode from '../../jwt/encode' diff --git a/backend/src/schema/resolvers/users.js b/backend/src/schema/resolvers/users.js index 06b25b4fa..3024bf5a5 100644 --- a/backend/src/schema/resolvers/users.js +++ b/backend/src/schema/resolvers/users.js @@ -54,7 +54,7 @@ export default { user = await user.toJson() return [user.node] } - return neo4jgraphql(object, args, context, resolveInfo, false) + return neo4jgraphql(object, args, context, resolveInfo) }, }, Mutation: { @@ -177,6 +177,8 @@ export default { 'termsAndConditionsAgreedVersion', 'termsAndConditionsAgreedAt', 'allowEmbedIframes', + 'showShoutsPublicly', + 'locale', ], boolean: { followedByCurrentUser: diff --git a/backend/src/schema/resolvers/users.spec.js b/backend/src/schema/resolvers/users.spec.js index 986f4a41f..36b77d611 100644 --- a/backend/src/schema/resolvers/users.spec.js +++ b/backend/src/schema/resolvers/users.spec.js @@ -1,5 +1,5 @@ import Factory from '../../seed/factories' -import { gql } from '../../jest/helpers' +import { gql } from '../../helpers/jest' import { neode as getNeode, getDriver } from '../../bootstrap/neo4j' import createServer from '../../server' import { createTestClient } from 'apollo-server-testing' diff --git a/backend/src/schema/resolvers/users/blockedUsers.spec.js b/backend/src/schema/resolvers/users/blockedUsers.spec.js index 887c34494..e0ab00448 100644 --- a/backend/src/schema/resolvers/users/blockedUsers.spec.js +++ b/backend/src/schema/resolvers/users/blockedUsers.spec.js @@ -1,7 +1,7 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../../../server' import Factory from '../../../seed/factories' -import { gql } from '../../../jest/helpers' +import { gql } from '../../../helpers/jest' import { neode, getDriver } from '../../../bootstrap/neo4j' const driver = getDriver() diff --git a/backend/src/schema/types/scalar/Date.gql_ b/backend/src/schema/types/scalar/Date.gql_ deleted file mode 100644 index 7b0004ea3..000000000 --- a/backend/src/schema/types/scalar/Date.gql_ +++ /dev/null @@ -1 +0,0 @@ -scalar Date \ No newline at end of file diff --git a/backend/src/schema/types/scalar/DateTime.gql_ b/backend/src/schema/types/scalar/DateTime.gql_ deleted file mode 100644 index af973932f..000000000 --- a/backend/src/schema/types/scalar/DateTime.gql_ +++ /dev/null @@ -1 +0,0 @@ -scalar DateTime \ No newline at end of file diff --git a/backend/src/schema/types/scalar/Time.gql_ b/backend/src/schema/types/scalar/Time.gql_ deleted file mode 100644 index 53becdd66..000000000 --- a/backend/src/schema/types/scalar/Time.gql_ +++ /dev/null @@ -1 +0,0 @@ -scalar Time \ No newline at end of file diff --git a/backend/src/schema/types/type/Badge.gql b/backend/src/schema/types/type/Badge.gql index 99015a518..dff1de89a 100644 --- a/backend/src/schema/types/type/Badge.gql +++ b/backend/src/schema/types/type/Badge.gql @@ -3,8 +3,6 @@ type Badge { type: BadgeType! status: BadgeStatus! icon: String! - #createdAt: DateTime - #updatedAt: DateTime createdAt: String updatedAt: String diff --git a/backend/src/schema/types/type/Category.gql b/backend/src/schema/types/type/Category.gql index 9ee628d76..39efeff9d 100644 --- a/backend/src/schema/types/type/Category.gql +++ b/backend/src/schema/types/type/Category.gql @@ -1,13 +1,41 @@ +enum _CategoryOrdering { + id_asc + id_desc + name_asc + name_desc + slug_asc + slug_desc + icon_asc + icon_desc + createdAt_asc + createdAt_desc + updatedAt_asc + updatedAt_desc + postCount_asc + postCount_desc +} + type Category { id: ID! name: String! slug: String icon: String! - #createdAt: DateTime - #updatedAt: DateTime createdAt: String updatedAt: String - posts: [Post]! @relation(name: "CATEGORIZED", direction: "IN") postCount: Int! @cypher(statement: "MATCH (this)<-[:CATEGORIZED]-(r:Post) RETURN COUNT(r)") } + +type Query { + Category( + id: ID + name: String + slug: String + icon: String + createdAt: String + updatedAt: String + first: Int + offset: Int + orderBy: [_CategoryOrdering] + ): [Category] +} diff --git a/backend/src/schema/types/type/Comment.gql b/backend/src/schema/types/type/Comment.gql index 1ccf617ef..ba9d7a3fc 100644 --- a/backend/src/schema/types/type/Comment.gql +++ b/backend/src/schema/types/type/Comment.gql @@ -1,3 +1,41 @@ +enum _CommentOrdering { + id_asc + id_desc + content_asc + content_desc + createdAt_asc + createdAt_desc + updatedAt_asc + updatedAt_desc +} + +input _CommentFilter { + AND: [_CommentFilter!] + OR: [_CommentFilter!] + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + author: _UserFilter + author_not: _UserFilter + author_in: [_UserFilter!] + author_not_in: [_UserFilter!] + content: String + content_not: String + content_in: [String!] + content_not_in: [String!] + content_contains: String + content_not_contains: String + content_starts_with: String + content_not_starts_with: String + content_ends_with: String + content_not_ends_with: String + post: _PostFilter + post_not: _PostFilter + post_in: [_PostFilter!] + post_not_in: [_PostFilter!] +} + type Comment { id: ID! activityId: String @@ -12,6 +50,19 @@ type Comment { disabledBy: User @relation(name: "DISABLED", direction: "IN") } +type Query { + Comment( + id: ID + content: String + createdAt: String + updatedAt: String + first: Int + offset: Int + orderBy: [_CommentOrdering] + filter: _CommentFilter + ): [Comment] +} + type Mutation { CreateComment( id: ID diff --git a/backend/src/schema/types/type/EMOTED.gql b/backend/src/schema/types/type/EMOTED.gql index ee1576517..7a8b47b73 100644 --- a/backend/src/schema/types/type/EMOTED.gql +++ b/backend/src/schema/types/type/EMOTED.gql @@ -3,8 +3,6 @@ type EMOTED @relation(name: "EMOTED") { to: Post emotion: Emotion - # createdAt: DateTime - # updatedAt: DateTime createdAt: String updatedAt: String } diff --git a/backend/src/schema/types/type/InvitationCode.gql b/backend/src/schema/types/type/InvitationCode.gql index 044967286..61ce0f689 100644 --- a/backend/src/schema/types/type/InvitationCode.gql +++ b/backend/src/schema/types/type/InvitationCode.gql @@ -2,9 +2,6 @@ type InvitationCode { id: ID! token: String generatedBy: User @relation(name: "GENERATED", direction: "IN") - - #createdAt: DateTime - #usedAt: DateTime createdAt: String } diff --git a/backend/src/schema/types/type/Post.gql b/backend/src/schema/types/type/Post.gql index b4d98ec5c..a52558071 100644 --- a/backend/src/schema/types/type/Post.gql +++ b/backend/src/schema/types/type/Post.gql @@ -1,26 +1,101 @@ +input _PostFilter { + AND: [_PostFilter!] + OR: [_PostFilter!] + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + author: _UserFilter + author_not: _UserFilter + author_in: [_UserFilter!] + author_not_in: [_UserFilter!] + title: String + title_not: String + title_in: [String!] + title_not_in: [String!] + title_contains: String + title_not_contains: String + title_starts_with: String + title_not_starts_with: String + title_ends_with: String + title_not_ends_with: String + slug: String + slug_not: String + slug_in: [String!] + slug_not_in: [String!] + slug_contains: String + slug_not_contains: String + slug_starts_with: String + slug_not_starts_with: String + slug_ends_with: String + slug_not_ends_with: String + content: String + content_not: String + content_in: [String!] + content_not_in: [String!] + content_contains: String + content_not_contains: String + content_starts_with: String + content_not_starts_with: String + content_ends_with: String + content_not_ends_with: String + image: String + visibility: Visibility + visibility_not: Visibility + visibility_in: [Visibility!] + visibility_not_in: [Visibility!] + language: String + language_not: String + language_in: [String!] + language_not_in: [String!] + pinned: Boolean # required for `maintainPinnedPost` + tags: _TagFilter + tags_not: _TagFilter + tags_in: [_TagFilter!] + tags_not_in: [_TagFilter!] + tags_some: _TagFilter + tags_none: _TagFilter + tags_single: _TagFilter + tags_every: _TagFilter + categories: _CategoryFilter + categories_not: _CategoryFilter + categories_in: [_CategoryFilter!] + categories_not_in: [_CategoryFilter!] + categories_some: _CategoryFilter + categories_none: _CategoryFilter + categories_single: _CategoryFilter + categories_every: _CategoryFilter + comments: _CommentFilter + comments_not: _CommentFilter + comments_in: [_CommentFilter!] + comments_not_in: [_CommentFilter!] + comments_some: _CommentFilter + comments_none: _CommentFilter + comments_single: _CommentFilter + comments_every: _CommentFilter + emotions: _PostEMOTEDFilter + emotions_not: _PostEMOTEDFilter + emotions_in: [_PostEMOTEDFilter!] + emotions_not_in: [_PostEMOTEDFilter!] + emotions_some: _PostEMOTEDFilter + emotions_none: _PostEMOTEDFilter + emotions_single: _PostEMOTEDFilter + emotions_every: _PostEMOTEDFilter +} + enum _PostOrdering { id_asc id_desc - activityId_asc - activityId_desc - objectId_asc - objectId_desc title_asc title_desc slug_asc slug_desc content_asc content_desc - contentExcerpt_asc - contentExcerpt_desc image_asc image_desc visibility_asc visibility_desc - deleted_asc - deleted_desc - disabled_asc - disabled_desc createdAt_asc createdAt_desc updatedAt_asc @@ -79,7 +154,7 @@ type Post { @cypher( statement: "MATCH (this)<-[:SHOUTED]-(r:User) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)" ) - + # Has the currently logged in user shouted that post? shoutedByCurrentUser: Boolean! @cypher( @@ -128,6 +203,22 @@ type Mutation { } type Query { + Post( + id: ID + title: String + slug: String + content: String + image: String + visibility: Visibility + pinned: Boolean + createdAt: String + updatedAt: String + language: String + first: Int + offset: Int + orderBy: [_PostOrdering] + filter: _PostFilter + ): [Post] PostsEmotionsCountByEmotion(postId: ID!, data: _EMOTEDInput!): Int! PostsEmotionsByCurrentUser(postId: ID!): [String] profilePagePosts(filter: _PostFilter, first: Int, offset: Int, orderBy: [_PostOrdering]): [Post] diff --git a/backend/src/schema/types/type/Tag.gql b/backend/src/schema/types/type/Tag.gql index 84c6ee7e7..41a772e4d 100644 --- a/backend/src/schema/types/type/Tag.gql +++ b/backend/src/schema/types/type/Tag.gql @@ -1,3 +1,20 @@ +input _TagFilter { + AND: [_TagFilter!] + OR: [_TagFilter!] + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + taggedPosts: _PostFilter + taggedPosts_not: _PostFilter + taggedPosts_in: [_PostFilter!] + taggedPosts_not_in: [_PostFilter!] + taggedPosts_some: _PostFilter + taggedPosts_none: _PostFilter + taggedPosts_single: _PostFilter + taggedPosts_every: _PostFilter +} + type Tag { id: ID! taggedPosts: [Post]! @relation(name: "TAGGED", direction: "IN") @@ -6,3 +23,22 @@ type Tag { deleted: Boolean disabled: Boolean } + +enum _TagOrdering { + id_asc + id_desc + taggedCount_asc + taggedCount_desc + taggedCountUnique_asc + taggedCountUnique_desc +} + +type Query { + Tag( + id: ID + first: Int + offset: Int + orderBy: [_TagOrdering] + filter: _TagFilter + ): [Tag] +} diff --git a/backend/src/schema/types/type/User.gql b/backend/src/schema/types/type/User.gql index cce0df058..53e739988 100644 --- a/backend/src/schema/types/type/User.gql +++ b/backend/src/schema/types/type/User.gql @@ -1,3 +1,28 @@ +enum _UserOrdering { + id_asc + id_desc + name_asc + name_desc + slug_asc + slug_desc + avatar_asc + avatar_desc + coverImg_asc + coverImg_desc + role_asc + role_desc + locationName_asc + locationName_desc + about_asc + about_desc + createdAt_asc + createdAt_desc + updatedAt_asc + updatedAt_desc + locale_asc + locale_desc +} + type User { id: ID! actorId: String @@ -28,6 +53,7 @@ type User { termsAndConditionsAgreedAt: String allowEmbedIframes: Boolean + showShoutsPublicly: Boolean locale: String friends: [User]! @relation(name: "FRIENDS", direction: "BOTH") friendsCount: Int! @cypher(statement: "MATCH (this)<-[: FRIENDS]->(r: User) RETURN COUNT(DISTINCT r)") @@ -91,12 +117,6 @@ input _UserFilter { id_not: ID id_in: [ID!] id_not_in: [ID!] - id_contains: ID - id_not_contains: ID - id_starts_with: ID - id_not_starts_with: ID - id_ends_with: ID - id_not_ends_with: ID friends: _UserFilter friends_not: _UserFilter friends_in: [_UserFilter!] @@ -127,8 +147,7 @@ input _UserFilter { type Query { User( id: ID - email: String - actorId: String + email: String # admins need to search for a user sometimes name: String slug: String avatar: String @@ -138,14 +157,6 @@ type Query { about: String createdAt: String updatedAt: String - friendsCount: Int - followingCount: Int - followedByCount: Int - followedByCurrentUser: Boolean - contributionsCount: Int - commentedCount: Int - shoutedCount: Int - badgesCount: Int first: Int offset: Int orderBy: [_UserOrdering] @@ -170,6 +181,8 @@ type Mutation { termsAndConditionsAgreedVersion: String termsAndConditionsAgreedAt: String allowEmbedIframes: Boolean + showShoutsPublicly: Boolean + locale: String ): User diff --git a/backend/src/seed/factories/users.js b/backend/src/seed/factories/users.js index 99e2681c9..d56c42d0a 100644 --- a/backend/src/seed/factories/users.js +++ b/backend/src/seed/factories/users.js @@ -17,6 +17,7 @@ export default function create() { termsAndConditionsAgreedVersion: '0.0.1', termsAndConditionsAgreedAt: '2019-08-01T10:47:19.212Z', allowEmbedIframes: false, + showShoutsPublicly: false, locale: 'en', } defaults.slug = slugify(defaults.name, { lower: true }) diff --git a/backend/src/seed/seed-db.js b/backend/src/seed/seed-db.js index c99f348cf..692d95542 100644 --- a/backend/src/seed/seed-db.js +++ b/backend/src/seed/seed-db.js @@ -4,7 +4,7 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../server' import Factory from './factories' import { neode as getNeode, getDriver } from '../bootstrap/neo4j' -import { gql } from '../jest/helpers' +import { gql } from '../helpers/jest' const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] diff --git a/backend/test/features/support/steps.js b/backend/test/features/support/steps.js index fdbca289c..73d059348 100644 --- a/backend/test/features/support/steps.js +++ b/backend/test/features/support/steps.js @@ -4,7 +4,6 @@ import { expect } from 'chai' // import { client } from '../../../src/activitypub/apollo-client' import { GraphQLClient } from 'graphql-request' import Factory from '../../../src/seed/factories' -import { host } from '../../../src/jest/helpers' const debug = require('debug')('ea:test:steps') const factory = Factory() diff --git a/backend/yarn.lock b/backend/yarn.lock index 7dc7c6503..817cb1657 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -1075,10 +1075,10 @@ url-regex "~4.1.1" video-extensions "~1.1.0" -"@metascraper/helpers@^5.7.17": - version "5.7.17" - resolved "https://registry.yarnpkg.com/@metascraper/helpers/-/helpers-5.7.17.tgz#401897c7239090ca7149b83e581712845bbb3709" - integrity sha512-t21LqfDpaIrWg2JaivXG6mVzUsIVW05cAsKySA5Tj9Hgi9oZXxaaNes5XipOzk6P242RI48SDo7CkSbYiio7Tw== +"@metascraper/helpers@^5.8.7": + version "5.8.7" + resolved "https://registry.yarnpkg.com/@metascraper/helpers/-/helpers-5.8.7.tgz#b05f83f2a90001f7753c18a8b1bb978bd7c2f9d9" + integrity sha512-gDErMAA3d1CdkGxvAG4cDi7D2+fReZpD6lzYNJ/gsq45U3Pdz7ltsAvbp4amK92bGKYYPZtnUq85Wrr+Q+e06Q== dependencies: audio-extensions "0.0.0" chrono-node "~1.3.11" @@ -1093,7 +1093,7 @@ isostring "0.0.1" lodash "~4.17.15" memoize-one "~5.1.1" - mime-types "~2.1.24" + mime-types "~2.1.25" normalize-url "~4.5.0" smartquotes "~2.3.1" title "~3.4.1" @@ -1183,10 +1183,10 @@ "@sentry/types" "5.7.1" tslib "^1.9.3" -"@sentry/node@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.8.0.tgz#68ec032b0e7fb840cc8ccc1b39c09ac6febc1046" - integrity sha512-hIzt1BysyQJez8ChgWpFkLcGq3t/HaLMqzrXF5vu+Uuekl5OfwsvzZ+8Dlv78rI4CvlL9a2EuI/94iqUNwhOSQ== +"@sentry/node@^5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.9.0.tgz#9a8da70990e64c88a391ef86dcf29f43e0a52e59" + integrity sha512-1CWwSGhRfMr4Bvt1i0vIms+BBZd4dBzlDyWpyCboodCXF1rTJRci9roQ+Wh9XWwFEWvgDD2PzuKzfvu638v2Wg== dependencies: "@sentry/core" "5.8.0" "@sentry/hub" "5.8.0" @@ -1764,10 +1764,10 @@ apollo-server-caching@^0.5.0: dependencies: lru-cache "^5.0.0" -apollo-server-core@^2.9.7: - version "2.9.7" - resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.9.7.tgz#0f32344af90dec445ac780be95350bfa736fc416" - integrity sha512-EqKyROy+21sM93YHjGpy6wlnzK/vH0fnZh7RCf3uB69aQ3OjgdP4AQ5oWRQ62NDN+aoic7OLhChSDJeDonq/NQ== +apollo-server-core@^2.9.9: + version "2.9.9" + resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.9.9.tgz#73df4989ac0ad09d20c20ef3e06f8c816bc7a13f" + integrity sha512-JxtYDasqeem5qUwPrCVh2IsBOgSQF4MKrRgy8dpxd+ymWfaaVelCUows1VE8vghgRxqDExnM9ibOxcZeI6mO6g== dependencies: "@apollographql/apollo-tools" "^0.4.0" "@apollographql/graphql-playground-html" "1.6.24" @@ -1804,10 +1804,10 @@ apollo-server-errors@^2.3.4: resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-2.3.4.tgz#b70ef01322f616cbcd876f3e0168a1a86b82db34" integrity sha512-Y0PKQvkrb2Kd18d1NPlHdSqmlr8TgqJ7JQcNIfhNDgdb45CnqZlxL1abuIRhr8tiw8OhVOcFxz2KyglBi8TKdA== -apollo-server-express@^2.9.7: - version "2.9.7" - resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.9.7.tgz#54fbaf93b68f0123ecb1dead26cbfda5b15bd10e" - integrity sha512-+DuJk1oq34Zx0bLYzgBgJH/eXS0JNxw2JycHQvV0+PAQ0Qi01oomJRA2r1S5isnfnSAnHb2E9jyBTptoHdw3MQ== +apollo-server-express@^2.9.7, apollo-server-express@^2.9.9: + version "2.9.9" + resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.9.9.tgz#2a379217d7a7be012f0329be8bf89a63e181d42e" + integrity sha512-qltC3ttGz8zvrut7HzrcqKOUg0vHpvVyYeeOy8jvghZpqXyWFuJhnw6uxAFcKNKCPl3mJ1psji83P1Um2ceJgg== dependencies: "@apollographql/graphql-playground-html" "1.6.24" "@types/accepts" "^1.3.5" @@ -1815,7 +1815,7 @@ apollo-server-express@^2.9.7: "@types/cors" "^2.8.4" "@types/express" "4.17.1" accepts "^1.3.5" - apollo-server-core "^2.9.7" + apollo-server-core "^2.9.9" apollo-server-types "^0.2.5" body-parser "^1.18.3" cors "^2.8.4" @@ -1833,12 +1833,12 @@ apollo-server-plugin-base@^0.6.5: dependencies: apollo-server-types "^0.2.5" -apollo-server-testing@~2.9.7: - version "2.9.7" - resolved "https://registry.yarnpkg.com/apollo-server-testing/-/apollo-server-testing-2.9.7.tgz#8d05058ddda4a715fac2fefb2b8e973e409a7672" - integrity sha512-yy18ceSyX2a9UYcs6X7K0xFZwcS1riEh99zdWU0XB/yzzTIdGZkFYeJmV/zjpGL3CFyXF7Va/muo6otl4nDOsA== +apollo-server-testing@~2.9.9: + version "2.9.9" + resolved "https://registry.yarnpkg.com/apollo-server-testing/-/apollo-server-testing-2.9.9.tgz#451836fa2e077e93f45182dde50ca72c15be2e84" + integrity sha512-ejbFJLrprMDBZWdi4hOZkZUSMzNJvX5NVDXWWUFHAySbY2zDsbHrQ9jE/2KQJrI3Q93jUgmpUTAu6kS0cjxt4Q== dependencies: - apollo-server-core "^2.9.7" + apollo-server-core "^2.9.9" apollo-server-types@^0.2.5: version "0.2.5" @@ -1849,13 +1849,13 @@ apollo-server-types@^0.2.5: apollo-server-caching "^0.5.0" apollo-server-env "^2.4.3" -apollo-server@~2.9.7: - version "2.9.7" - resolved "https://registry.yarnpkg.com/apollo-server/-/apollo-server-2.9.7.tgz#aab337b75c04ddea0fa9b171b30c4e91932c04d8" - integrity sha512-maGGCsK4Ft5ucox5ZJf6oaKhgPvzHY3jXWbA1F/mn0/EYX8e1RVO3Qtj8aQQ0/vCKx8r4vYgj+ctqBVaN/nr4A== +apollo-server@~2.9.9: + version "2.9.9" + resolved "https://registry.yarnpkg.com/apollo-server/-/apollo-server-2.9.9.tgz#f10249fa9884be2a0ad59876e301fdfccb456208" + integrity sha512-b4IfGxZDzhOnfaPTinAD0rx8XpgxkVMjNuwooRULOJEeYG8Vd/OiBYSS7LSGy1g3hdiLBgJhMFC0ce7pjdcyFw== dependencies: - apollo-server-core "^2.9.7" - apollo-server-express "^2.9.7" + apollo-server-core "^2.9.9" + apollo-server-express "^2.9.9" express "^4.0.0" graphql-subscriptions "^1.0.0" graphql-tools "^4.0.0" @@ -2583,6 +2583,11 @@ commander@^2.8.1, commander@~2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== +commander@^2.9.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + commander@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" @@ -2778,6 +2783,11 @@ css-what@2.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== +cssfilter@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae" + integrity sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4= + cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": version "0.3.8" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" @@ -2790,10 +2800,10 @@ cssstyle@^1.0.0: dependencies: cssom "0.3.x" -cucumber-expressions@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/cucumber-expressions/-/cucumber-expressions-8.0.1.tgz#47eb87dcb626e90a4672986da1130f3c470b9e3d" - integrity sha512-g+A+tUEafNofe6ErwvOkqaMvDj9NuOr0GouGotpw4r5yK2d4144o9/6sQpXBr2YXbRy5ItmER/2bzAyDAzhPyQ== +cucumber-expressions@^8.1.0: + version "8.2.1" + resolved "https://registry.yarnpkg.com/cucumber-expressions/-/cucumber-expressions-8.2.1.tgz#e250063993350df106a8664c90a414814f555e2d" + integrity sha512-6n5JKbAzXfIiwyu2UyUcOmO83QmuSme25+Dw2taK6VNOybOfRkh4yNMA9VtuAJHOmsX3/8l0OVjTbE8lHnjOHA== dependencies: becke-ch--regex--s0-0-v1--base--pl--lib "^1.4.0" xregexp "^4.2.4" @@ -2803,17 +2813,17 @@ cucumber-tag-expressions@^2.0.2: resolved "https://registry.yarnpkg.com/cucumber-tag-expressions/-/cucumber-tag-expressions-2.0.2.tgz#aac27aae3690818ec15235bd056282dad8a2d2b8" integrity sha512-DohmT4X641KX/sb96bdb7J2kXNcQBPrYmf3Oc5kiHCLfzFMWx/o2kB4JvjvQPZnYuA9lRt6pqtArM5gvUn4uzw== -cucumber@~6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/cucumber/-/cucumber-6.0.3.tgz#bf69ecc992772e580dabe265b2ed06ddab13d076" - integrity sha512-FSx7xdAQfFjcxp/iRBAuCFSXp2iJP1tF2Q5k/a67YgHiYbnwsD9F+UNv9ZG90LFHNsNQhb+67AmVxHkp4JRDpg== +cucumber@~6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cucumber/-/cucumber-6.0.5.tgz#cdc752ad18b551bcf7bc92774c925302f4408714" + integrity sha512-x+W9Fwk6TvcapQsYMxwFU5AsQJDOIJVGrPKmH15OC7jzb9/Dk7Hb0ZAyw4WcpaDcUDRc8bi2k2yJejDp5eTRlg== dependencies: assertion-error-formatter "^3.0.0" bluebird "^3.4.1" cli-table3 "^0.5.1" colors "^1.1.2" commander "^3.0.1" - cucumber-expressions "^8.0.1" + cucumber-expressions "^8.1.0" cucumber-tag-expressions "^2.0.2" duration "^0.2.1" escape-string-regexp "^2.0.0" @@ -3289,10 +3299,10 @@ escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@~6.5.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.5.0.tgz#aaf9a495e2a816865e541bfdbb73a65cc162b3eb" - integrity sha512-cjXp8SbO9VFGW/Z7mbTydqS9to8Z58E5aYhj3e1+Hx7lS9s6gL5ILKNpCqZAFOVYRcSkWPFYljHrEh8QFEK5EQ== +eslint-config-prettier@~6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.7.0.tgz#9a876952e12df2b284adbd3440994bf1f39dfbb9" + integrity sha512-FamQVKM3jjUVwhG4hEMnbtsq7xOIDm+SY5iBPfR8gKsJoAB2IQnNF+bk1+8Fy44Nq7PPJaLvkRxILYdJWoguKQ== dependencies: get-stdin "^6.0.0" @@ -3342,10 +3352,10 @@ eslint-plugin-import@~2.18.2: read-pkg-up "^2.0.0" resolve "^1.11.0" -eslint-plugin-jest@~23.0.3: - version "23.0.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.0.3.tgz#d3f157f7791f97713372c13259ba1dfc436eb4c1" - integrity sha512-9cNxr66zeOyz1S9AkQL4/ouilR6QHpYj8vKOQZ60fu9hAt5PJWS4KqWqfr1aqN5NFEZSPjFOla2Azn+KTWiGwg== +eslint-plugin-jest@~23.0.4: + version "23.0.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.0.4.tgz#1ab81ffe3b16c5168efa72cbd4db14d335092aa0" + integrity sha512-OaP8hhT8chJNodUPvLJ6vl8gnalcsU/Ww1t9oR3HnGdEWjm/DdCCUXLOral+IPGAeWu/EwgVQCK/QtxALpH1Yw== dependencies: "@typescript-eslint/experimental-utils" "^2.5.0" @@ -3981,7 +3991,7 @@ glob-parent@^5.0.0: dependencies: is-glob "^4.0.1" -glob@7.1.6: +glob@7.1.6, glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -3993,18 +4003,6 @@ glob@7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: - version "7.1.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0" - integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - global-dirs@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" @@ -5689,6 +5687,11 @@ map-cache@^0.2.2: resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= +map-values-deep@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/map-values-deep/-/map-values-deep-1.0.2.tgz#b0176a1c463158ae33e24de0ce8150621a2b30d3" + integrity sha512-br+tp4aANql3WnpDRjD14H7hHopPlJRnzCL0ZlGCRHAQZTU0g0x1rUQFq/ikb3zZQK+lW2AG7RJi+CFfQ8kSPA== + map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -5730,19 +5733,19 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -metascraper-audio@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-audio/-/metascraper-audio-5.7.17.tgz#b8e78a797deb155b02f30bcbe39da554bf1bf898" - integrity sha512-g11lRNVor5Pu4D1j3tL7aakSQM51CUl2Evp8QgFKcuYGjF+a1RiGq6veojiTf/9nWcKX8dUSTUJkQSIzdoJrFQ== +metascraper-audio@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-audio/-/metascraper-audio-5.8.7.tgz#ce27b1f4056c1d1cbaa2cec0e819c3704f38fff4" + integrity sha512-ew9KZKOIl3u0500j7qIR/ZNiVtSohuyyiIWSxJVEeeguEOwAhMpOrpYAEkvKRo5CB89F2PNBIsXJIzMC4BWFrw== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" -metascraper-author@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-author/-/metascraper-author-5.7.17.tgz#0403eaa4d1992152246f01616fac1d52b0583c8a" - integrity sha512-vaMAn6glCr9f2PGvNObqMI7ECtQ7+CMkXSxKyn3fyxRVKnV95fBR+xi4+UJ2DWqTvVQ6t7gZwlzFWA4CwxfniQ== +metascraper-author@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-author/-/metascraper-author-5.8.7.tgz#c29db97a24af801101008a547caea6a33a56e467" + integrity sha512-PwuCZvHnDm10Q1zMQllpCLjtlYR1zSF+rDCRkf/TUuBC/ozz27/JkXDL+ml2nmK8IQGLGRUQKOzrQ0vVMFKvQw== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" lodash "~4.17.15" metascraper-clearbit-logo@^5.3.0: @@ -5752,28 +5755,28 @@ metascraper-clearbit-logo@^5.3.0: dependencies: got "~9.6.0" -metascraper-date@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-date/-/metascraper-date-5.7.17.tgz#8777bc5deaccce1235ed0b2eb8f0746c981ee245" - integrity sha512-OPKXu7S+S6JoZNVV9Dox6OIG2x5hzDx2J3IzMwzQwVdKzulMPSFMLCcJU8zLZ03dajSOszRf8aL1eSBfZscpIw== +metascraper-date@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-date/-/metascraper-date-5.8.7.tgz#146733ecce34f8d4a53c7c6ddcfc51c033287757" + integrity sha512-9+IslaGg+J+4cwPU5qu/MEexkoWj7sBxycmCA6vgfuCQCqNwlQ68vk2a/UVDw8OJOYjwX81JGrzxOqrQP0/kXw== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" -metascraper-description@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-description/-/metascraper-description-5.7.17.tgz#b0daa54d0345546ececcc033065790402aabb5ec" - integrity sha512-cQfg9Spl3FLK2x8O7DvecwSYEBUmRjtdZW2y1EVqHsOKwT13SeUy1kp+lZa8+8vFh4o8oJPzXHxgbLhAfAmVqQ== +metascraper-description@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-description/-/metascraper-description-5.8.7.tgz#e85ce218daf33b74813b1523ad7dc7dc3fb128af" + integrity sha512-KOv5gnQVvGF1CgpUczu7KJm76rWJ7SH5UFcqFST60hRNgR9xy0y3aHbVDOhZkjNN4UKqnxMF6XTS/WaQxCK/AA== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" -metascraper-image@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-image/-/metascraper-image-5.7.17.tgz#186b29979cb8aefc6c21d0342c386a8fef80be55" - integrity sha512-bwAUJrJibJ+fJGxL8T789Ki1z+8sqsz0sqb3W+mfR/ZLkhCu+jWLYqPVtMgTPM9Zaqqqxg5uTQs1uAVrnguKDA== +metascraper-image@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-image/-/metascraper-image-5.8.7.tgz#d24697c5b5a6ba688948c48fadcb5fffeb6c703d" + integrity sha512-OMK+PFnHeavCSuEJY5tFkG5tdl/luYmPys7PKkJIwC8A8q5qoAC0InIUu+c0SDrdf4nzOj083DZTp32YQxYF5A== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" -metascraper-lang-detector@^4.8.5: +metascraper-lang-detector@^4.10.2: version "4.10.2" resolved "https://registry.yarnpkg.com/metascraper-lang-detector/-/metascraper-lang-detector-4.10.2.tgz#45744bc331125c098e8b27716d76740161b121d2" integrity sha512-Lz1d5v/i1j08gQYz7sCdoxjOx94ArLV4UucUhGZeQpR4E6dK47V6aqfYwODRe2XAqhaU+3oLnbAipoHkOeZXiw== @@ -5782,81 +5785,80 @@ metascraper-lang-detector@^4.8.5: franc "~4.0.0" iso-639-3 "~1.1.0" -metascraper-lang@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-lang/-/metascraper-lang-5.7.17.tgz#3952db650bcd909fff0308d1d2254e954a0c0028" - integrity sha512-G/XqySeDpZmoV1rgWeMs/hmX1NFX0IN2w4viNdgdMRXB+lhqeyk5Z20x9ssPAqiJ4Ab6tyR274NkgYa0ZNRMDw== +metascraper-lang@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-lang/-/metascraper-lang-5.8.7.tgz#5214af961d55b7b4c98e679fffe7477a0f3f9c53" + integrity sha512-ASidffvAmnankJtb9BIqVyRRlcz0uJ5mAbkAoWL1xkd9GyUxRLvkCjKq/pvsapASNabfqjwbgSj7hO8mv5hbkQ== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" -metascraper-logo@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-logo/-/metascraper-logo-5.7.17.tgz#b26e2fb38e94cfe9ec9dfc7e28d8da26a0a0689d" - integrity sha512-S4aqxN4Qi3UXDLN4HhinEuQHUopYXbFw0Y5Cwj9TbGKfESeQ1n6Jm4eOgGifEYyyZMSeRR9li189EK3YPnYcFg== +metascraper-logo@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-logo/-/metascraper-logo-5.8.7.tgz#5efb7e6c5f91ccad812e2d9ec3facfef179f40b6" + integrity sha512-QudGVJBBeXLWU54Xw2PmnsTf+qPUnbyYaOl4aFLg2wkLLza1GbuvOYGMiH9Y8k0WcRoesi9sQk+P0a/611blew== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" -metascraper-publisher@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-publisher/-/metascraper-publisher-5.7.17.tgz#38455e035d8d34c42eff529316ee15f31726d641" - integrity sha512-BxiweB0vxXX0UF2YVxzwC7Y8X0A5mU+eaa6TsTrTGHPBWeZCUJaLJ2Ge35c00SIC+USgdu8KFyzF6+pJBObwvQ== +metascraper-publisher@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-publisher/-/metascraper-publisher-5.8.7.tgz#2b67f04db46123f9c6d57eaa3de610921fd28e01" + integrity sha512-vVfoyqGPxKWWQjvBL0gz4Xyol3QYdr5HWSs9DI7cLrlIDExOByPPah5bZVSijeseeKymyf36BvCm54+chOZN5g== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" -metascraper-soundcloud@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-soundcloud/-/metascraper-soundcloud-5.7.17.tgz#925fc91505b69f1e3e7f0c535567c7918f8afbd9" - integrity sha512-yllxXR0AHQmJLXCua+CJtjzmNr9I+mU/H23ED+S2t9Yd07xQDmqL8pkkuD8DAAy7aC6oIL0qghQPwk8qdM97Ug== +metascraper-soundcloud@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-soundcloud/-/metascraper-soundcloud-5.8.7.tgz#a557f070671978730ea06d18be3d5668cf323ab5" + integrity sha512-qzwT7igIUi0k8NYC31lfLBeJEIUSxgJvQX3LC1JMxrEue5YMmE86SZRYASGemhMzhW5LtM/oA9jQECT3a8enJA== dependencies: - "@metascraper/helpers" "^5.7.17" - memoize-one "~5.1.1" + "@metascraper/helpers" "^5.8.7" tldts "~5.6.1" -metascraper-title@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-title/-/metascraper-title-5.7.17.tgz#5b947635361bfb4d7557eadcb623489c812322e6" - integrity sha512-YCEbiU2MbPMLulXmLbSBN/N7ti9tBVr45yqMKSuFsWiNJ98bFsM1IQp1LN5KqRQmNkOg+8JsYgK+R9vqYwaGjg== +metascraper-title@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-title/-/metascraper-title-5.8.7.tgz#aecbbd9515bd74d2aeafa587c83447d926508ba0" + integrity sha512-u+5KeJbsFKpi+pMnG71Gd49OLDQpkjiGIRTddhCZQhb45qHoTlGKN1nZuQ8nqJI6+ARWicFqtquomkaRXfBEnw== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" lodash "~4.17.15" -metascraper-url@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-url/-/metascraper-url-5.7.17.tgz#e8ba40a17a59b54139f42d6e3cf430dc6f32e7d7" - integrity sha512-7OOhCXpxdMiJatrbxa9rqLmUT/t/s34PDgtknoE/2FfmZY7X/xyORamcuqUHjV37sOpCPTun+GcJL4l3ddCi3Q== +metascraper-url@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-url/-/metascraper-url-5.8.7.tgz#8c04a8f9b82af1058145f21788655b7b6b04fd9c" + integrity sha512-K79mT509wV6B1Ak9vSslAbDPQMMRjjWowVgjcby5bOyFpO2j7mQkQIZYobEFpYLHlpb2R9myWJaTKAZe9KrF0A== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" -metascraper-video@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-video/-/metascraper-video-5.7.17.tgz#414d4641fbea667e73c42fe3706d673ee4c4aec5" - integrity sha512-lftJGynCVNfC15eyMW7tN3QWJl9T2sVNCgP0dZsW8OC1hWQM7WY3PW8yYd2PP6nUuwOTjNLL1F4oWNhldWrE8A== +metascraper-video@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-video/-/metascraper-video-5.8.7.tgz#7a5d1e8955f9a65891908eef319683b6176765a2" + integrity sha512-J4OJlB+nla8ITwqH2H6dgQ+nrecYILVhsGFKG54p2qsSokXwgZrQ4P7WhUMd0VpBsYuebcRgdzY8OGUDb+7l0Q== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" lodash "~4.17.15" -metascraper-youtube@^5.7.17: - version "5.7.17" - resolved "https://registry.yarnpkg.com/metascraper-youtube/-/metascraper-youtube-5.7.17.tgz#a3bdf06bbc9aa3766f08a779fa880d8a3fda9f8c" - integrity sha512-CZX03wX8ui8fjx+iBZCiAGdSKy4dMFiDrVSPmTMK2W8sn2guYv2QQ41g8gruFJgrF+m+mCOUG6KYgy3B/v5LdQ== +metascraper-youtube@^5.8.7: + version "5.8.7" + resolved "https://registry.yarnpkg.com/metascraper-youtube/-/metascraper-youtube-5.8.7.tgz#8a799602788d90ed34a885f4754fc98aa5e917ca" + integrity sha512-00b+KNoRxDYc+Pbx25a74ZV2hX4ARqKY9J70AFZm/kstmxh2VOApyuIkuNkQM8PgTqEMXm3lAFiz6aYMnPcVMg== dependencies: - "@metascraper/helpers" "^5.7.17" + "@metascraper/helpers" "^5.8.7" get-video-id "~3.1.4" is-reachable "~4.0.0" - memoize-one "~5.1.1" p-locate "~4.1.0" -metascraper@^4.10.3: - version "4.10.3" - resolved "https://registry.yarnpkg.com/metascraper/-/metascraper-4.10.3.tgz#8a97ed2e914e81d1dbc1f17a5b1e64f1b804493f" - integrity sha512-wNQm5A/PIxWcahaMwI+b3rOmmXRDNmjyF6Q15dHYXEqYoGl3dFaaT4lnTTm8yntvE+fOj8+o51ON2FBdstxbsA== +metascraper@^5.8.8: + version "5.8.8" + resolved "https://registry.yarnpkg.com/metascraper/-/metascraper-5.8.8.tgz#9fbf6913f55bb448a9195e40e38f3599bc5a818f" + integrity sha512-z4G3SXGBVnd0+FSHqR3LJF+6emO03GlY2KoOTqsFCnRuY0B72nJyR/NRRYLn4PRX6PMQ6QZ+GWKa7oxBX6hZqQ== dependencies: - "@metascraper/helpers" "^4.10.2" + "@metascraper/helpers" "^5.8.7" cheerio "~1.0.0-rc.2" cheerio-advanced-selectors "~2.0.1" - lodash "~4.17.11" - p-reduce "~2.0.0" + lodash "~4.17.15" + map-values-deep "~1.0.2" whoops "~4.0.2" + xss "~1.0.6" methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: version "1.1.2" @@ -5887,6 +5889,11 @@ mime-db@1.40.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== +mime-db@1.42.0: + version "1.42.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac" + integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ== + mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.22, mime-types@~2.1.24: version "2.1.24" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" @@ -5894,6 +5901,13 @@ mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.22, mime-types@~2.1.24: dependencies: mime-db "1.40.0" +mime-types@~2.1.25: + version "2.1.25" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.25.tgz#39772d46621f93e2a80a856c53b86a62156a6437" + integrity sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg== + dependencies: + mime-db "1.42.0" + mime@1.6.0, mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -6070,10 +6084,10 @@ neo4j-driver@^1.7.3, neo4j-driver@^1.7.5, neo4j-driver@~1.7.6: text-encoding-utf-8 "^1.0.2" uri-js "^4.2.2" -neo4j-graphql-js@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/neo4j-graphql-js/-/neo4j-graphql-js-2.8.0.tgz#58035b9213656e17b6ed4c6cbf4dfe1c56a8a219" - integrity sha512-nDuzmi6W/YGIIVm+GAXCr/8CLABsU/RfeLebLH32vqeKViFATMfm4eT66aOq/GwHJ0838+o20yCbIFdx5rTP/A== +neo4j-graphql-js@^2.9.3: + version "2.9.3" + resolved "https://registry.yarnpkg.com/neo4j-graphql-js/-/neo4j-graphql-js-2.9.3.tgz#91afb0631eb35014110022a74e572c9eb065d281" + integrity sha512-SzIX3BYE3EsKp/XU8Wog97TzfsrQdrKp/t7le7tnODojcBd5eSVJyKPrbaKqcnWMkLzKzO/SRX9PMQ2cDdXUKw== dependencies: "@babel/runtime" "^7.5.5" "@babel/runtime-corejs2" "^7.5.5" @@ -6532,11 +6546,6 @@ p-reduce@^1.0.0: resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= -p-reduce@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.0.0.tgz#365a26916213650711124881a6bdc4e32c2bfe36" - integrity sha512-VcNNEqiYIkRCGeUHELY5dUrnQHCRwL6eIH/L9oSbl/PsvyHQXD1ws/MFwuEb+6dgH/URCfROVUqOYL37eHi2kQ== - p-some@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/p-some/-/p-some-4.1.0.tgz#28e73bc1e0d62db54c2ed513acd03acba30d5c04" @@ -6784,10 +6793,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@~1.18.2: - version "1.18.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" - integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== +prettier@~1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== pretty-format@^24.9.0: version "24.9.0" @@ -8625,6 +8634,14 @@ xregexp@^4.2.4: dependencies: "@babel/runtime-corejs2" "^7.2.0" +xss@~1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.6.tgz#eaf11e9fc476e3ae289944a1009efddd8a124b51" + integrity sha512-6Q9TPBeNyoTRxgZFk5Ggaepk/4vUOYdOsIUYvLehcsIZTFjaavbVnsuAkLA5lIFuug5hw8zxcB9tm01gsjph2A== + dependencies: + commander "^2.9.0" + cssfilter "0.0.10" + xtend@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" diff --git a/cypress/integration/common/steps.js b/cypress/integration/common/steps.js index 493c54e38..c51c863d1 100644 --- a/cypress/integration/common/steps.js +++ b/cypress/integration/common/steps.js @@ -5,9 +5,12 @@ import { } from "cypress-cucumber-preprocessor/steps"; import helpers from "../../support/helpers"; import { VERSION } from '../../constants/terms-and-conditions-version.js' +import locales from '../../../webapp/locales' +import orderBy from 'lodash/orderBy' /* global cy */ +const languages = orderBy(locales, 'name') let lastPost = {}; let loginCredentials = { @@ -245,6 +248,12 @@ Then("I select a category", () => { .click(); }); +When("I choose {string} as the language for the post", (languageCode) => { + cy.get('.ds-flex-item > .ds-form-item .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`; @@ -536,4 +545,4 @@ Then("I see only one post with the title {string}", title => { .find(".post-link") .should("have.length", 1); cy.get(".main-container").contains(".post-link", title); -}); \ No newline at end of file +}); diff --git a/cypress/integration/notifications/Mentions.feature b/cypress/integration/notifications/Mentions.feature index 7523e3d05..ef2694abc 100644 --- a/cypress/integration/notifications/Mentions.feature +++ b/cypress/integration/notifications/Mentions.feature @@ -20,6 +20,7 @@ Feature: Notification for a mention """ And mention "@matt-rider" in the text 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 with the following credentials: diff --git a/cypress/integration/post/WritePost.feature b/cypress/integration/post/WritePost.feature index 461766532..0d74606ad 100644 --- a/cypress/integration/post/WritePost.feature +++ b/cypress/integration/post/WritePost.feature @@ -17,7 +17,8 @@ Feature: Create a post Human Connection is a free and open-source social network for active citizenship. """ - Then I select a category + And I select a category + And I choose "en" as the language for the post And I click on "Save" Then I get redirected to ".../my-first-post" And the post was saved successfully diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 51ba950a6..f8bc76d50 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -17,7 +17,7 @@ import "cypress-file-upload"; import helpers from "./helpers"; import users from "../fixtures/users.json"; import { GraphQLClient, request } from 'graphql-request' -import { gql } from '../../backend/src/jest/helpers' +import { gql } from '../../backend/src/helpers/jest' const backendHost = Cypress.env('BACKEND_HOST') const switchLang = name => { diff --git a/deployment/human-connection/templates/configmap.template.yaml b/deployment/human-connection/templates/configmap.template.yaml index 07c0bb53f..ae093e4bd 100644 --- a/deployment/human-connection/templates/configmap.template.yaml +++ b/deployment/human-connection/templates/configmap.template.yaml @@ -4,7 +4,6 @@ data: SMTP_HOST: "mailserver.human-connection" SMTP_PORT: "25" - GRAPHQL_PORT: "4000" GRAPHQL_URI: "http://nitro-backend.human-connection:4000" NEO4J_URI: "bolt://nitro-neo4j.human-connection:7687" NEO4J_AUTH: "none" diff --git a/docker-compose.build-and-test.yml b/docker-compose.build-and-test.yml index e8e79644f..27aa9fc6b 100644 --- a/docker-compose.build-and-test.yml +++ b/docker-compose.build-and-test.yml @@ -2,11 +2,15 @@ version: "3.4" services: webapp: + environment: + - "CI=${CI}" image: humanconnection/nitro-web:build-and-test build: context: webapp target: build-and-test backend: + environment: + - "CI=${CI}" image: humanconnection/nitro-backend:build-and-test build: context: backend diff --git a/docker-compose.maintenance.yml b/docker-compose.maintenance.yml index 52168c221..b6a869c57 100644 --- a/docker-compose.maintenance.yml +++ b/docker-compose.maintenance.yml @@ -15,7 +15,6 @@ services: environment: - NEO4J_dbms_security_auth__enabled=false - NEO4J_dbms_memory_heap_max__size=2G - - GRAPHQL_PORT=4000 - GRAPHQL_URI=http://localhost:4000 - CLIENT_URI=http://localhost:3000 - JWT_SECRET=b/&&7b78BF&fv/Vd diff --git a/docker-compose.yml b/docker-compose.yml index c5ce3a20f..7b0c00163 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,7 +39,6 @@ services: - uploads:/nitro-backend/public/uploads environment: - NEO4J_URI=bolt://neo4j:7687 - - GRAPHQL_PORT=4000 - GRAPHQL_URI=http://backend:4000 - CLIENT_URI=http://localhost:3000 - JWT_SECRET=b/&&7b78BF&fv/Vd diff --git a/package.json b/package.json index 38509a631..26bb61c27 100644 --- a/package.json +++ b/package.json @@ -8,15 +8,14 @@ "nonGlobalStepDefinitions": true }, "scripts": { + "install:all": "yarn install && cd backend && yarn install && cd ../webapp && yarn install", "db:seed": "cd backend && yarn run db:seed", "db:reset": "cd backend && yarn run db:reset", - "cypress:backend:server": "cd backend && yarn run test:before:server", - "cypress:backend:seeder": "cd backend && yarn run test:before:seeder", - "cypress:webapp": "cd webapp && cross-env GRAPHQL_URI=http://localhost:4123 yarn run dev", - "cypress:setup": "run-p cypress:backend:* cypress:webapp", - "cypress:run": "cypress run --browser chromium", - "cypress:open": "cypress open --browser chromium", - "test:jest": "cd webapp && yarn test && cd ../backend && yarn test:jest && codecov", + "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 --browser chromium", + "cypress:open": "cross-env cypress open --browser chromium", "version": "auto-changelog -p" }, "devDependencies": { diff --git a/webapp/Dockerfile b/webapp/Dockerfile index ae951273d..37a31d6f4 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -1,4 +1,4 @@ -FROM node:13.0.1-alpine as base +FROM node:13.1.0-alpine as base LABEL Description="Web Frontend of the Social Network Human-Connection.org" Vendor="Human-Connection gGmbH" Version="0.0.1" Maintainer="Human-Connection gGmbH (developer@human-connection.org)" EXPOSE 3000 diff --git a/webapp/Dockerfile.maintenance b/webapp/Dockerfile.maintenance index 8e95ada57..7195d0f1c 100644 --- a/webapp/Dockerfile.maintenance +++ b/webapp/Dockerfile.maintenance @@ -1,4 +1,4 @@ -FROM node:13.0.1-alpine as build +FROM node:13.1.0-alpine as build LABEL Description="Maintenance page of the Social Network Human-Connection.org" Vendor="Human-Connection gGmbH" Version="0.0.1" Maintainer="Human-Connection gGmbH (developer@human-connection.org)" EXPOSE 3000 diff --git a/webapp/components/AvatarMenu/AvatarMenu.vue b/webapp/components/AvatarMenu/AvatarMenu.vue index a7f31bfef..54426852e 100644 --- a/webapp/components/AvatarMenu/AvatarMenu.vue +++ b/webapp/components/AvatarMenu/AvatarMenu.vue @@ -69,7 +69,7 @@ export default { if (!this.user.slug) { return [] } - let routes = [ + const routes = [ { name: this.$t('profile.name'), path: `/profile/${this.user.id}/${this.user.slug}`, diff --git a/webapp/components/CategoriesSelect/CategoriesSelect.spec.js b/webapp/components/CategoriesSelect/CategoriesSelect.spec.js index 4e9fa52d0..b633e5811 100644 --- a/webapp/components/CategoriesSelect/CategoriesSelect.spec.js +++ b/webapp/components/CategoriesSelect/CategoriesSelect.spec.js @@ -6,10 +6,12 @@ const localVue = global.localVue describe('CategoriesSelect.vue', () => { let wrapper let mocks + let provide let democracyAndPolitics let environmentAndNature let consumptionAndSustainablity + const propsData = { model: 'categoryIds' } const categories = [ { id: 'cat9', @@ -33,6 +35,11 @@ describe('CategoriesSelect.vue', () => { }, ] beforeEach(() => { + provide = { + $parentForm: { + update: jest.fn(), + }, + } mocks = { $t: jest.fn(), } @@ -40,7 +47,7 @@ describe('CategoriesSelect.vue', () => { describe('shallowMount', () => { const Wrapper = () => { - return mount(CategoriesSelect, { mocks, localVue }) + return mount(CategoriesSelect, { propsData, mocks, localVue, provide }) } beforeEach(() => { @@ -58,8 +65,8 @@ describe('CategoriesSelect.vue', () => { expect(wrapper.vm.selectedCategoryIds).toEqual([categories[0].id]) }) - it('emits an updateCategories event when the selectedCategoryIds changes', () => { - expect(wrapper.emitted().updateCategories[0][0]).toEqual([categories[0].id]) + it('calls $parent.update with selected category ids', () => { + expect(provide.$parentForm.update).toHaveBeenCalledWith('categoryIds', ['cat9']) }) it('removes categories when clicked a second time', () => { diff --git a/webapp/components/CategoriesSelect/CategoriesSelect.vue b/webapp/components/CategoriesSelect/CategoriesSelect.vue index ab6108419..493256546 100644 --- a/webapp/components/CategoriesSelect/CategoriesSelect.vue +++ b/webapp/components/CategoriesSelect/CategoriesSelect.vue @@ -5,6 +5,7 @@ import CategoryQuery from '~/graphql/CategoryQuery' +import xor from 'lodash/xor' export default { + inject: { + $parentForm: { + default: null, + }, + }, props: { existingCategoryIds: { type: Array, default: () => [] }, + model: { type: String, required: true }, }, data() { return { categories: null, selectedMax: 3, - selectedCategoryIds: [], + selectedCategoryIds: this.existingCategoryIds, } }, computed: { @@ -48,39 +56,22 @@ export default { return this.selectedCount >= this.selectedMax }, }, - watch: { - selectedCategoryIds(categoryIds) { - this.$emit('updateCategories', categoryIds) - }, - existingCategoryIds: { - immediate: true, - handler: function(existingCategoryIds) { - if (!existingCategoryIds || !existingCategoryIds.length) { - return - } - this.selectedCategoryIds = existingCategoryIds - }, - }, - }, methods: { toggleCategory(id) { - const index = this.selectedCategoryIds.indexOf(id) - if (index > -1) { - this.selectedCategoryIds.splice(index, 1) - } else { - this.selectedCategoryIds.push(id) + this.selectedCategoryIds = xor(this.selectedCategoryIds, [id]) + if (this.$parentForm) { + this.$parentForm.update(this.model, this.selectedCategoryIds) } }, isActive(id) { - const index = this.selectedCategoryIds.indexOf(id) - if (index > -1) { - return true - } - return false + return this.selectedCategoryIds.includes(id) }, isDisabled(id) { return !!(this.reachedMaximum && !this.isActive(id)) }, + categoryButtonsId(categoryId) { + return `category-buttons-${categoryId}` + }, }, apollo: { Category: { diff --git a/webapp/components/Category/index.spec.js b/webapp/components/Category/index.spec.js index ee2e1d80d..9abb8a11d 100644 --- a/webapp/components/Category/index.spec.js +++ b/webapp/components/Category/index.spec.js @@ -8,7 +8,7 @@ describe('Category', () => { let icon let name - let Wrapper = () => { + const Wrapper = () => { return shallowMount(Category, { localVue, propsData: { diff --git a/webapp/components/ContentMenu.vue b/webapp/components/ContentMenu.vue index 03303f7ec..f0d9dc8d3 100644 --- a/webapp/components/ContentMenu.vue +++ b/webapp/components/ContentMenu.vue @@ -53,7 +53,7 @@ export default { }, computed: { routes() { - let routes = [] + const routes = [] if (this.resourceType === 'contribution') { if (this.isOwner) { diff --git a/webapp/components/ContributionForm/ContributionForm.spec.js b/webapp/components/ContributionForm/ContributionForm.spec.js index 124c38206..3ec538bde 100644 --- a/webapp/components/ContributionForm/ContributionForm.spec.js +++ b/webapp/components/ContributionForm/ContributionForm.spec.js @@ -16,15 +16,45 @@ config.stubs['client-only'] = '' config.stubs['nuxt-link'] = '' config.stubs['v-popover'] = '' +const categories = [ + { + id: 'cat3', + slug: 'health-wellbeing', + icon: 'medkit', + }, + { + id: 'cat12', + slug: 'it-internet-data-privacy', + icon: 'mouse-pointer', + }, + { + id: 'cat9', + slug: 'democracy-politics', + icon: 'university', + }, + { + id: 'cat15', + slug: 'consumption-sustainability', + icon: 'shopping-cart', + }, + { + id: 'cat4', + slug: 'environment-nature', + icon: 'tree', + }, +] + describe('ContributionForm.vue', () => { - let wrapper - let postTitleInput - let expectedParams - let deutschOption - let cancelBtn - let mocks - let propsData - let categoryIds + let wrapper, + postTitleInput, + expectedParams, + cancelBtn, + mocks, + propsData, + categoryIds, + englishLanguage, + deutschLanguage, + dataPrivacyButton const postTitle = 'this is a title for a post' const postTitleTooShort = 'xx' let postTitleTooLong = '' @@ -32,11 +62,6 @@ describe('ContributionForm.vue', () => { postTitleTooLong += 'x' } const postContent = 'this is a post' - const postContentTooShort = 'xx' - let postContentTooLong = '' - for (let i = 0; i < 2001; i++) { - postContentTooLong += 'x' - } const imageUpload = { file: { filename: 'avataar.svg', @@ -105,90 +130,59 @@ describe('ContributionForm.vue', () => { beforeEach(() => { wrapper = Wrapper() - wrapper.setData({ - form: { - languageOptions: [ - { - label: 'Deutsch', - value: 'de', - }, - ], - }, - }) }) describe('CreatePost', () => { - describe('language placeholder', () => { - it("displays the name that corresponds with the user's location code", () => { - expect(wrapper.find('.ds-select-placeholder').text()).toEqual('English') - }) - }) - describe('invalid form submission', () => { - it('title and content should not be empty ', async () => { - wrapper.find('.submit-button-for-test').trigger('click') - expect(mocks.$apollo.mutate).not.toHaveBeenCalled() + beforeEach(async () => { + wrapper.find(CategoriesSelect).setData({ categories }) + postTitleInput = wrapper.find('.ds-input') + postTitleInput.setValue(postTitle) + await wrapper.vm.updateEditorContent(postContent) + englishLanguage = wrapper.findAll('li').filter(language => language.text() === 'English') + englishLanguage.trigger('click') + dataPrivacyButton = await wrapper + .find(CategoriesSelect) + .find('[data-test="category-buttons-cat12"]') + dataPrivacyButton.trigger('click') }) it('title should not be empty', async () => { - await wrapper.vm.updateEditorContent(postContent) - wrapper.find('.submit-button-for-test').trigger('click') + postTitleInput.setValue('') + wrapper.find('form').trigger('submit') expect(mocks.$apollo.mutate).not.toHaveBeenCalled() }) it('title should not be too long', async () => { - postTitleInput = wrapper.find('.ds-input') postTitleInput.setValue(postTitleTooLong) - await wrapper.vm.updateEditorContent(postContent) - wrapper.find('.submit-button-for-test').trigger('click') + wrapper.find('form').trigger('submit') expect(mocks.$apollo.mutate).not.toHaveBeenCalled() }) it('title should not be too short', async () => { - postTitleInput = wrapper.find('.ds-input') postTitleInput.setValue(postTitleTooShort) - await wrapper.vm.updateEditorContent(postContent) - wrapper.find('.submit-button-for-test').trigger('click') + wrapper.find('form').trigger('submit') expect(mocks.$apollo.mutate).not.toHaveBeenCalled() }) it('content should not be empty', async () => { - postTitleInput = wrapper.find('.ds-input') - postTitleInput.setValue(postTitle) - await wrapper.find('.submit-button-for-test').trigger('click') - expect(mocks.$apollo.mutate).not.toHaveBeenCalled() - }) - - it('content should not be too short', async () => { - postTitleInput = wrapper.find('.ds-input') - postTitleInput.setValue(postTitle) - await wrapper.vm.updateEditorContent(postContentTooShort) - wrapper.find('.submit-button-for-test').trigger('click') - expect(mocks.$apollo.mutate).not.toHaveBeenCalled() - }) - - it('content should not be too long', async () => { - postTitleInput = wrapper.find('.ds-input') - postTitleInput.setValue(postTitle) - await wrapper.vm.updateEditorContent(postContentTooLong) - wrapper.find('.submit-button-for-test').trigger('click') + await wrapper.vm.updateEditorContent('') + await wrapper.find('form').trigger('submit') expect(mocks.$apollo.mutate).not.toHaveBeenCalled() }) it('should have at least one category', async () => { - postTitleInput = wrapper.find('.ds-input') - postTitleInput.setValue(postTitle) - await wrapper.vm.updateEditorContent(postContent) - wrapper.find('.submit-button-for-test').trigger('click') + dataPrivacyButton = await wrapper + .find(CategoriesSelect) + .find('[data-test="category-buttons-cat12"]') + dataPrivacyButton.trigger('click') + wrapper.find('form').trigger('submit') expect(mocks.$apollo.mutate).not.toHaveBeenCalled() }) it('should have not have more than three categories', async () => { - postTitleInput = wrapper.find('.ds-input') - postTitleInput.setValue(postTitle) - await wrapper.vm.updateEditorContent(postContent) wrapper.vm.form.categoryIds = ['cat4', 'cat9', 'cat15', 'cat27'] - wrapper.find('.submit-button-for-test').trigger('click') + wrapper.find('form').trigger('submit') expect(mocks.$apollo.mutate).not.toHaveBeenCalled() }) }) @@ -210,43 +204,51 @@ describe('ContributionForm.vue', () => { postTitleInput = wrapper.find('.ds-input') postTitleInput.setValue(postTitle) await wrapper.vm.updateEditorContent(postContent) - categoryIds = ['cat12'] - wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds) + wrapper.find(CategoriesSelect).setData({ categories }) + englishLanguage = wrapper.findAll('li').filter(language => language.text() === 'English') + englishLanguage.trigger('click') + dataPrivacyButton = await wrapper + .find(CategoriesSelect) + .find('[data-test="category-buttons-cat12"]') + dataPrivacyButton.trigger('click') }) it('creates a post with valid title, content, and at least one category', async () => { - await wrapper.find('.submit-button-for-test').trigger('click') - expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams)) - }) - - it("sends a fallback language based on a user's locale", () => { - wrapper.find('.submit-button-for-test').trigger('click') + await wrapper.find('form').trigger('submit') expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams)) }) it('supports changing the language', async () => { expectedParams.variables.language = 'de' - deutschOption = wrapper.findAll('li').at(0) - deutschOption.trigger('click') - wrapper.find('.submit-button-for-test').trigger('click') + deutschLanguage = wrapper.findAll('li').filter(language => language.text() === 'Deutsch') + deutschLanguage.trigger('click') + wrapper.find('form').trigger('submit') expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams)) }) it('supports adding a teaser image', async () => { expectedParams.variables.imageUpload = imageUpload wrapper.find(TeaserImage).vm.$emit('addTeaserImage', imageUpload) - await wrapper.find('.submit-button-for-test').trigger('click') + await wrapper.find('form').trigger('submit') expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams)) }) + it('content is valid with just a link', async () => { + await wrapper.vm.updateEditorContent( + '', + ) + wrapper.find('form').trigger('submit') + expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1) + }) + it("pushes the user to the post's page", async () => { - wrapper.find('.submit-button-for-test').trigger('click') + wrapper.find('form').trigger('submit') await mocks.$apollo.mutate expect(mocks.$router.push).toHaveBeenCalledTimes(1) }) it('shows a success toaster', async () => { - wrapper.find('.submit-button-for-test').trigger('click') + wrapper.find('form').trigger('submit') await mocks.$apollo.mutate expect(mocks.$toast.success).toHaveBeenCalledTimes(1) }) @@ -271,11 +273,17 @@ describe('ContributionForm.vue', () => { postTitleInput.setValue(postTitle) await wrapper.vm.updateEditorContent(postContent) categoryIds = ['cat12'] - wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds) + wrapper.find(CategoriesSelect).setData({ categories }) + englishLanguage = wrapper.findAll('li').filter(language => language.text() === 'English') + englishLanguage.trigger('click') + dataPrivacyButton = await wrapper + .find(CategoriesSelect) + .find('[data-test="category-buttons-cat12"]') + dataPrivacyButton.trigger('click') }) it('shows an error toaster when apollo mutation rejects', async () => { - await wrapper.find('.submit-button-for-test').trigger('click') + await wrapper.find('form').trigger('submit') await mocks.$apollo.mutate await expect(mocks.$toast.error).toHaveBeenCalledWith('Not Authorised!') }) @@ -337,11 +345,11 @@ describe('ContributionForm.vue', () => { expectedParams = { mutation: PostMutations().UpdatePost, variables: { - title: postTitle, - content: postContent, + title: propsData.contribution.title, + content: propsData.contribution.content, language: propsData.contribution.language, id: propsData.contribution.id, - categoryIds, + categoryIds: ['cat12'], image, imageUpload: null, }, @@ -349,22 +357,20 @@ describe('ContributionForm.vue', () => { }) it('calls the UpdatePost apollo mutation', async () => { - postTitleInput = wrapper.find('.ds-input') - postTitleInput.setValue(postTitle) + expectedParams.variables.content = postContent wrapper.vm.updateEditorContent(postContent) - wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds) - wrapper.find('.submit-button-for-test').trigger('click') + await wrapper.find('form').trigger('submit') expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams)) }) it('supports updating categories', async () => { - const categoryIds = ['cat3', 'cat51', 'cat37'] - postTitleInput = wrapper.find('.ds-input') - postTitleInput.setValue(postTitle) - wrapper.vm.updateEditorContent(postContent) - expectedParams.variables.categoryIds = categoryIds - wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds) - await wrapper.find('.submit-button-for-test').trigger('click') + expectedParams.variables.categoryIds.push('cat3') + wrapper.find(CategoriesSelect).setData({ categories }) + const healthWellbeingButton = await wrapper + .find(CategoriesSelect) + .find('[data-test="category-buttons-cat3"]') + healthWellbeingButton.trigger('click') + await wrapper.find('form').trigger('submit') expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams)) }) }) diff --git a/webapp/components/ContributionForm/ContributionForm.vue b/webapp/components/ContributionForm/ContributionForm.vue index eb849c71f..734e3be81 100644 --- a/webapp/components/ContributionForm/ContributionForm.vue +++ b/webapp/components/ContributionForm/ContributionForm.vue @@ -1,5 +1,11 @@