diff --git a/backend/package.json b/backend/package.json index 83fad31c4..a253419c2 100644 --- a/backend/package.json +++ b/backend/package.json @@ -68,7 +68,7 @@ "helmet": "~3.18.0", "jsonwebtoken": "~8.5.1", "linkifyjs": "~2.1.8", - "lodash": "~4.17.13", + "lodash": "~4.17.14", "merge-graphql-schemas": "^1.5.8", "neo4j-driver": "~1.7.4", "neo4j-graphql-js": "^2.6.3", @@ -88,7 +88,7 @@ "@babel/core": "~7.5.4", "@babel/node": "~7.5.0", "@babel/plugin-proposal-throw-expressions": "^7.2.0", - "@babel/preset-env": "~7.5.2", + "@babel/preset-env": "~7.5.4", "@babel/register": "~7.4.4", "apollo-server-testing": "~2.6.8", "babel-core": "~7.0.0-0", diff --git a/backend/src/schema/types/enum/Emotion.gql b/backend/src/schema/types/enum/Emotion.gql new file mode 100644 index 000000000..88a436f98 --- /dev/null +++ b/backend/src/schema/types/enum/Emotion.gql @@ -0,0 +1,7 @@ +enum Emotion { + surprised + cry + happy + angry + funny +} \ No newline at end of file diff --git a/backend/src/schema/types/type/EMOTED.gql b/backend/src/schema/types/type/EMOTED.gql new file mode 100644 index 000000000..80d655b5c --- /dev/null +++ b/backend/src/schema/types/type/EMOTED.gql @@ -0,0 +1,10 @@ +type EMOTED @relation(name: "EMOTED") { + from: User + to: Post + + emotion: Emotion + #createdAt: DateTime + #updatedAt: DateTime + createdAt: String + updatedAt: String +} \ No newline at end of file diff --git a/backend/src/schema/types/type/Post.gql b/backend/src/schema/types/type/Post.gql index deb1d8f85..d254a9a9c 100644 --- a/backend/src/schema/types/type/Post.gql +++ b/backend/src/schema/types/type/Post.gql @@ -48,6 +48,8 @@ type Post { RETURN COUNT(u) >= 1 """ ) + + emotions: [EMOTED] } type Mutation { diff --git a/backend/src/schema/types/type/User.gql b/backend/src/schema/types/type/User.gql index b984f2d79..e5c43aad4 100644 --- a/backend/src/schema/types/type/User.gql +++ b/backend/src/schema/types/type/User.gql @@ -73,6 +73,8 @@ type User { badges: [Badge]! @relation(name: "REWARDED", direction: "IN") badgesCount: Int! @cypher(statement: "MATCH (this)<-[:REWARDED]-(r:Badge) RETURN COUNT(r)") + + emotions: [EMOTED] } diff --git a/backend/yarn.lock b/backend/yarn.lock index 109a2cf0e..d34e05c38 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -320,10 +320,10 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings" "^7.2.0" -"@babel/plugin-proposal-object-rest-spread@^7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.2.tgz#ec92b0c6419074ea7af77c78b7c5d42041f2f5a9" - integrity sha512-C/JU3YOx5J4d9s0GGlJlYXVwsbd5JmqQ0AvB7cIDAx7nN57aDTnlJEsZJPuSskeBtMGFWSWU5Q+piTiDe0s7FQ== +"@babel/plugin-proposal-object-rest-spread@^7.5.4": + version "7.5.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.4.tgz#250de35d867ce8260a31b1fdac6c4fc1baa99331" + integrity sha512-KCx0z3y7y8ipZUMAEEJOyNi11lMb/FOPUjjB113tfowgw0c16EGYos7worCKBcUAh2oG+OBnoUhsnTSoLpV9uA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" @@ -649,17 +649,17 @@ core-js "^2.5.7" regenerator-runtime "^0.12.0" -"@babel/preset-env@~7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.2.tgz#34a46f01aed617b174b8dbaf8fed9239300343d0" - integrity sha512-7rRJLaUqJhQ+8xGrWtMROAgOi/+udIzyK2ES9NHhDIUvR2zfx/ON5lRR8ACUGehIYst8KVbl4vpkgOqn08gBxA== +"@babel/preset-env@~7.5.4": + version "7.5.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.4.tgz#64bc15041a3cbb0798930319917e70fcca57713d" + integrity sha512-hFnFnouyRNiH1rL8YkX1ANCNAUVC8Djwdqfev8i1415tnAG+7hlA5zhZ0Q/3Q5gkop4HioIPbCEWAalqcbxRoQ== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-async-generator-functions" "^7.2.0" "@babel/plugin-proposal-dynamic-import" "^7.5.0" "@babel/plugin-proposal-json-strings" "^7.2.0" - "@babel/plugin-proposal-object-rest-spread" "^7.5.2" + "@babel/plugin-proposal-object-rest-spread" "^7.5.4" "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" "@babel/plugin-syntax-async-generators" "^7.2.0" @@ -5382,9 +5382,9 @@ lodash.isstring@^4.0.1: integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= lodash.mergewith@^4.6.1: - version "4.6.1" - resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927" - integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ== + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== lodash.once@^4.0.0: version "4.1.1" @@ -5401,10 +5401,10 @@ lodash@=3.10.1: resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= -lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.13: - version "4.17.13" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.13.tgz#0bdc3a6adc873d2f4e0c4bac285df91b64fc7b93" - integrity sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA== +lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.14: + version "4.17.14" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba" + integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw== long@^4.0.0: version "4.0.0" diff --git a/cypress/integration/common/steps.js b/cypress/integration/common/steps.js index f8d18baa0..f996db992 100644 --- a/cypress/integration/common/steps.js +++ b/cypress/integration/common/steps.js @@ -276,9 +276,9 @@ When("I fill the password form with:", table => { table = table.rowsHash(); cy.get("input[id=oldPassword]") .type(table["Your old password"]) - .get("input[id=newPassword]") + .get("input[id=password]") .type(table["Your new passsword"]) - .get("input[id=confirmPassword]") + .get("input[id=passwordConfirmation]") .type(table["Confirm new password"]); }); diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/emotions/delete.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/emotions/delete.cql index e69de29bb..18fb6699f 100644 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/emotions/delete.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/emotions/delete.cql @@ -0,0 +1 @@ +MATCH (u:User)-[e:EMOTED]->(c:Post) DETACH DELETE e; \ No newline at end of file diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/emotions/emotions.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/emotions/emotions.cql index 8aad9e923..06341f277 100644 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/emotions/emotions.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/emotions/emotions.cql @@ -5,31 +5,54 @@ // [-] Omitted in Nitro // [?] Unclear / has work to be done for Nitro { -[ ] userId: { -[ ] type: String, -[ ] required: true, +[X] userId: { +[X] type: String, +[X] required: true, [-] index: true }, -[ ] contributionId: { -[ ] type: String, -[ ] required: true, +[X] contributionId: { +[X] type: String, +[X] required: true, [-] index: true }, -[ ] rated: { -[ ] type: String, +[?] rated: { +[X] type: String, [ ] required: true, -[ ] enum: ['funny', 'happy', 'surprised', 'cry', 'angry'] +[?] enum: ['funny', 'happy', 'surprised', 'cry', 'angry'] }, -[ ] createdAt: { -[ ] type: Date, -[ ] default: Date.now +[X] createdAt: { +[X] type: Date, +[X] default: Date.now }, -[ ] updatedAt: { -[ ] type: Date, -[ ] default: Date.now +[X] updatedAt: { +[X] type: Date, +[X] default: Date.now }, -[ ] wasSeeded: { type: Boolean } +[-] wasSeeded: { type: Boolean } } */ -CALL apoc.load.json("file:${IMPORT_CHUNK_PATH_CQL_FILE}") YIELD value as emotion; +CALL apoc.load.json("file:${IMPORT_CHUNK_PATH_CQL_FILE}") YIELD value as emotion +MATCH (u:User {id: emotion.userId}), + (c:Post {id: emotion.contributionId}) +MERGE (u)-[e:EMOTED { + id: emotion._id["$oid"], + emotion: emotion.rated, + createdAt: datetime(emotion.createdAt.`$date`), + updatedAt: datetime(emotion.updatedAt.`$date`) + }]->(c) +RETURN e; +/* + // Queries + // user sets an emotion emotion: + // MERGE (u)-[e:EMOTED {id: ..., emotion: "funny", createdAt: ..., updatedAt: ...}]->(c) + // user removes emotion + // MATCH (u)-[e:EMOTED]->(c) DELETE e + // contribution distributions over every `emotion` property value for one post + // MATCH (u:User)-[e:EMOTED]->(c:Post {id: "5a70bbc8508f5b000b443b1a"}) RETURN e.emotion,COUNT(e.emotion) + // contribution distributions over every `emotion` property value for one user (advanced - "whats the primary emotion used by the user?") + // MATCH (u:User{id:"5a663b1ac64291000bf302a1"})-[e:EMOTED]->(c:Post) RETURN e.emotion,COUNT(e.emotion) + // contribution distributions over every `emotion` property value for all posts created by one user (advanced - "how do others react to my contributions?") + // MATCH (u:User)-[e:EMOTED]->(c:Post)<-[w:WROTE]-(a:User{id:"5a663b1ac64291000bf302a1"}) RETURN e.emotion,COUNT(e.emotion) + // if we can filter the above an a variable timescale that would be great (should be possible on createdAt and updatedAt fields) +*/ \ No newline at end of file diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/follows/delete.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/follows/delete.cql index 3624448c3..3de01f8ea 100644 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/follows/delete.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/follows/delete.cql @@ -1 +1 @@ -// this is just a relation between users(?) - no need to delete \ No newline at end of file +MATCH (u1:User)-[f:FOLLOWS]->(u2:User) DETACH DELETE f; \ No newline at end of file diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/import.sh b/deployment/legacy-migration/maintenance-worker/migration/neo4j/import.sh index 8eef68c92..cef2846a7 100755 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/import.sh +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/import.sh @@ -60,8 +60,8 @@ delete_collection "contributions" "contributions_post" delete_collection "contributions" "contributions_cando" delete_collection "shouts" "shouts" delete_collection "comments" "comments" +delete_collection "emotions" "emotions" -#delete_collection "emotions" #delete_collection "invites" #delete_collection "notifications" #delete_collection "organizations" @@ -82,12 +82,12 @@ import_collection "users" "users/users.cql" import_collection "follows_users" "follows/follows.cql" #import_collection "follows_organizations" "follows/follows.cql" import_collection "contributions_post" "contributions/contributions.cql" -import_collection "contributions_cando" "contributions/contributions.cql" +#import_collection "contributions_cando" "contributions/contributions.cql" #import_collection "contributions_DELETED" "contributions/contributions.cql" import_collection "shouts" "shouts/shouts.cql" import_collection "comments" "comments/comments.cql" +import_collection "emotions" "emotions/emotions.cql" -# import_collection "emotions" # import_collection "invites" # import_collection "notifications" # import_collection "organizations" diff --git a/webapp/components/Password/Change.spec.js b/webapp/components/Password/Change.spec.js index a15695a55..ef89c34f7 100644 --- a/webapp/components/Password/Change.spec.js +++ b/webapp/components/Password/Change.spec.js @@ -54,7 +54,7 @@ describe('ChangePassword.vue', () => { describe('match', () => { beforeEach(() => { wrapper.find('input#oldPassword').setValue('some secret') - wrapper.find('input#newPassword').setValue('some secret') + wrapper.find('input#password').setValue('some secret') }) it('invalid', () => { @@ -90,8 +90,8 @@ describe('ChangePassword.vue', () => { describe('given valid input', () => { beforeEach(() => { wrapper.find('input#oldPassword').setValue('supersecret') - wrapper.find('input#newPassword').setValue('superdupersecret') - wrapper.find('input#confirmPassword').setValue('superdupersecret') + wrapper.find('input#password').setValue('superdupersecret') + wrapper.find('input#passwordConfirmation').setValue('superdupersecret') }) describe('submit form', () => { @@ -109,8 +109,8 @@ describe('ChangePassword.vue', () => { expect.objectContaining({ variables: { oldPassword: 'supersecret', - newPassword: 'superdupersecret', - confirmPassword: 'superdupersecret', + password: 'superdupersecret', + passwordConfirmation: 'superdupersecret', }, }), ) @@ -135,8 +135,8 @@ describe('ChangePassword.vue', () => { /* describe('mutation rejects', () => { beforeEach(async () => { await wrapper.find('input#oldPassword').setValue('supersecret') - await wrapper.find('input#newPassword').setValue('supersecret') - await wrapper.find('input#confirmPassword').setValue('supersecret') + await wrapper.find('input#password').setValue('supersecret') + await wrapper.find('input#passwordConfirmation').setValue('supersecret') }) it('displays error message', async () => { diff --git a/webapp/components/Password/Change.vue b/webapp/components/Password/Change.vue index 63c797157..dabc53d6f 100644 --- a/webapp/components/Password/Change.vue +++ b/webapp/components/Password/Change.vue @@ -1,12 +1,6 @@