From 16f077fe65260f56e9fc95d7619cee7217940adb Mon Sep 17 00:00:00 2001 From: Matt Rider Date: Tue, 16 Jul 2019 11:02:43 -0300 Subject: [PATCH 01/54] Add authentication tests for AddPostEmotions, emotionsCount --- .../src/middleware/permissionsMiddleware.js | 2 + backend/src/schema/resolvers/posts.js | 1 + backend/src/schema/resolvers/posts.spec.js | 74 +++++++++++++++++++ backend/src/schema/types/type/Post.gql | 4 + 4 files changed, 81 insertions(+) diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 31c373fc7..8e3e2311a 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -167,6 +167,7 @@ const permissions = shield( // RemoveBadgeRewarded: isAdmin, reward: isAdmin, unreward: isAdmin, + // why is this here? will we support buying/selling fruit?? // addFruitToBasket: isAuthenticated follow: isAuthenticated, unfollow: isAuthenticated, @@ -180,6 +181,7 @@ const permissions = shield( DeleteUser: isDeletingOwnAccount, requestPasswordReset: allow, resetPassword: allow, + AddPostEmotions: isAuthenticated, }, User: { email: isMyOwn, diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index 0c8dfb7f0..74f88d62e 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -44,6 +44,7 @@ export default { delete params.categoryIds params = await fileUpload(params, { file: 'imageUpload', url: 'image' }) params.id = params.id || uuid() + let createPostCypher = `CREATE (post:Post {params}) WITH post MATCH (author:User {id: $userId}) diff --git a/backend/src/schema/resolvers/posts.spec.js b/backend/src/schema/resolvers/posts.spec.js index 233be450a..49cb2123b 100644 --- a/backend/src/schema/resolvers/posts.spec.js +++ b/backend/src/schema/resolvers/posts.spec.js @@ -383,3 +383,77 @@ describe('DeletePost', () => { }) }) }) + +describe('AddPostEmotions', () => { + let addPostEmotionsVariables + const addPostEmotionsMutation = ` + mutation($from: _UserInput!, $to: _PostInput!, $data: _EMOTEDInput!) { + AddPostEmotions(from: $from, to: $to, data: $data) { + from { + id + } + to { + id + } + emotion + } + } + ` + describe('emotions', () => { + beforeEach(async () => { + const asAuthor = Factory() + authorParams = { + id: 'u25', + email: 'wanna-add-emotions@example.org', + password: '1234', + } + await asAuthor.create('User', authorParams) + await asAuthor.authenticateAs(authorParams) + await asAuthor.create('Post', { + id: 'p1376', + title: postTitle, + content: postContent, + }) + addPostEmotionsVariables = { + from: { id: authorParams.id }, + to: { id: 'p1376' }, + data: { emotion: 'happy' }, + } + }) + // it('supports setting emotions for a post', () => {}) + + describe('unauthenticated', () => { + it('throws authorization error', async () => { + client = new GraphQLClient(host) + await expect( + client.request(addPostEmotionsMutation, { + from: { id: 'u25' }, + to: { id: 'p1376' }, + data: { emotion: 'happy' }, + }), + ).rejects.toThrow('Not Authorised') + }) + }) + + describe('authenticated as author', () => { + let headers + beforeEach(async () => { + headers = await login(authorParams) + client = new GraphQLClient(host, { headers }) + }) + + it('adds an emotion to the post', async () => { + const expected = { + AddPostEmotions: { + from: addPostEmotionsVariables.from, + to: addPostEmotionsVariables.to, + emotion: 'happy', + }, + } + await expect( + client.request(addPostEmotionsMutation, addPostEmotionsVariables), + ).resolves.toEqual(expected) + }) + }) + }) +}) diff --git a/backend/src/schema/types/type/Post.gql b/backend/src/schema/types/type/Post.gql index d254a9a9c..30cdd71d4 100644 --- a/backend/src/schema/types/type/Post.gql +++ b/backend/src/schema/types/type/Post.gql @@ -50,6 +50,10 @@ type Post { ) emotions: [EMOTED] + emotionsCount: Int! + @cypher( + statement: "MATCH (this)<-[emoted:EMOTED]-(:User) RETURN COUNT(DISTINCT emoted)" + ) } type Mutation { From 3e43539e23b874fa884d890b79a708e41b86cd5b Mon Sep 17 00:00:00 2001 From: Matt Rider Date: Mon, 29 Jul 2019 17:08:07 +0200 Subject: [PATCH 02/54] Set up some backend tests for emotions --- .../src/middleware/permissionsMiddleware.js | 1 + backend/src/schema/resolvers/posts.js | 34 ++++ backend/src/schema/resolvers/posts.spec.js | 151 ++++++++++++++---- backend/src/schema/types/type/Post.gql | 5 +- backend/yarn.lock | 104 ------------ 5 files changed, 154 insertions(+), 141 deletions(-) diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index fe33cd4c4..fe001d676 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -184,6 +184,7 @@ const permissions = shield( requestPasswordReset: allow, resetPassword: allow, AddPostEmotions: isAuthenticated, + RemovePostEmotions: isAuthenticated, }, User: { email: isMyOwn, diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index 74f88d62e..c4ed494b7 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -71,5 +71,39 @@ export default { return post.properties }, + AddPostEmotions: async (object, params, context, resolveInfo) => { + const session = context.driver.session() + const { from, to, data } = params + const transactionRes = await session.run( + `MATCH (userFrom:User {id: $from.id}), (postTo:Post {id: $to.id}) + MERGE (userFrom)-[emotedRelation:EMOTED {emotion: $data.emotion}]->(postTo) + RETURN userFrom, postTo, emotedRelation`, + { from, to, data }, + ) + session.close() + const [emoted] = transactionRes.records.map(record => { + return { + from: { id: record.get('userFrom').properties.id }, + to: { id: record.get('postTo').properties.id }, + emotion: record.get('emotedRelation').properties.emotion, + } + }) + return emoted + }, + RemovePostEmotions: async (object, params, context, resolveInfo) => { + const session = context.driver.session() + const { from, to, data } = params + const transactionRes = await session.run( + `MATCH (userFrom:User {id: $from.id})-[emotedRelation:EMOTED {emotion: $data.emotion}]->(postTo:Post {id: $to.id}) + DELETE emotedRelation + RETURN emotedRelation`, + { from, to, data }, + ) + session.close() + const [removed] = transactionRes.records.map(record => { + return record.get('emotedRelation') + }) + return !!removed + }, }, } diff --git a/backend/src/schema/resolvers/posts.spec.js b/backend/src/schema/resolvers/posts.spec.js index 49cb2123b..e1c85974b 100644 --- a/backend/src/schema/resolvers/posts.spec.js +++ b/backend/src/schema/resolvers/posts.spec.js @@ -58,6 +58,7 @@ const postQueryFilteredByCategoryVariables = { } beforeEach(async () => { userParams = { + id: 'u198', name: 'TestUser', email: 'test@example.org', password: '1234', @@ -384,43 +385,59 @@ describe('DeletePost', () => { }) }) -describe('AddPostEmotions', () => { +describe('emotions', () => { let addPostEmotionsVariables - const addPostEmotionsMutation = ` - mutation($from: _UserInput!, $to: _PostInput!, $data: _EMOTEDInput!) { - AddPostEmotions(from: $from, to: $to, data: $data) { - from { - id - } - to { - id - } - emotion - } + let postEmotionsVariables + beforeEach(async () => { + const asAuthor = Factory() + authorParams = { + id: 'u25', + email: 'wanna-add-emotions@example.org', + password: '1234', } - ` - describe('emotions', () => { - beforeEach(async () => { - const asAuthor = Factory() - authorParams = { - id: 'u25', - email: 'wanna-add-emotions@example.org', - password: '1234', - } - await asAuthor.create('User', authorParams) - await asAuthor.authenticateAs(authorParams) - await asAuthor.create('Post', { - id: 'p1376', - title: postTitle, - content: postContent, - }) - addPostEmotionsVariables = { - from: { id: authorParams.id }, - to: { id: 'p1376' }, - data: { emotion: 'happy' }, - } + await asAuthor.create('User', authorParams) + await asAuthor.authenticateAs(authorParams) + await asAuthor.create('Post', { + id: 'p1376', + title: postTitle, + content: postContent, }) - // it('supports setting emotions for a post', () => {}) + addPostEmotionsVariables = { + from: { id: authorParams.id }, + to: { id: 'p1376' }, + data: { emotion: 'happy' }, + } + postEmotionsVariables = { + id: 'p1376', + } + }) + + describe('AddPostEmotions', () => { + const addPostEmotionsMutation = ` + mutation($from: _UserInput!, $to: _PostInput!, $data: _EMOTEDInput!) { + AddPostEmotions(from: $from, to: $to, data: $data) { + from { id } + to { id } + emotion + } + } + ` + const postEmotionsCountQuery = ` + query($id: ID!) { + Post(id: $id) { + emotionsCount + } + } + ` + const postEmotionsQuery = ` + query($id: ID!) { + Post(id: $id) { + emotions { + emotion + } + } + } + ` describe('unauthenticated', () => { it('throws authorization error', async () => { @@ -435,6 +452,52 @@ describe('AddPostEmotions', () => { }) }) + describe('authenticated and not the author', () => { + let headers + beforeEach(async () => { + headers = await login(userParams) + client = new GraphQLClient(host, { headers }) + }) + + it('adds an emotion to the post', async () => { + addPostEmotionsVariables.from.id = userParams.id + const expected = { + AddPostEmotions: { + from: addPostEmotionsVariables.from, + to: addPostEmotionsVariables.to, + emotion: 'happy', + }, + } + await expect( + client.request(addPostEmotionsMutation, addPostEmotionsVariables), + ).resolves.toEqual(expected) + }) + it('limits the addition of the same emotion to 1', async () => { + const expected = { + Post: [ + { + emotionsCount: 1, + }, + ], + } + await client.request(addPostEmotionsMutation, addPostEmotionsVariables) + await client.request(addPostEmotionsMutation, addPostEmotionsVariables) + await expect( + client.request(postEmotionsCountQuery, postEmotionsVariables), + ).resolves.toEqual(expected) + }) + + it('allows a user to add more than one emotion', async () => { + const expected = [{ emotion: 'happy' }, { emotion: 'surprised' }] + await client.request(addPostEmotionsMutation, addPostEmotionsVariables) + addPostEmotionsVariables.data.emotion = 'surprised' + await client.request(addPostEmotionsMutation, addPostEmotionsVariables) + await expect(client.request(postEmotionsQuery, postEmotionsVariables)).resolves.toEqual({ + Post: [{ emotions: expect.arrayContaining(expected) }], + }) + }) + }) + describe('authenticated as author', () => { let headers beforeEach(async () => { @@ -456,4 +519,24 @@ describe('AddPostEmotions', () => { }) }) }) + + describe('RemovePostEmotions', () => { + const removePostEmotionsMutation = ` + mutation($from: _UserInput!, $to: _PostInput!, $data: _EMOTEDInput!) { + RemovePostEmotions(from: $from, to: $to, data: $data) + } + ` + describe('unauthenticated', () => { + it('throws authorization error', async () => { + client = new GraphQLClient(host) + await expect( + client.request(removePostEmotionsMutation, { + from: { id: 'u25' }, + to: { id: 'p1376' }, + data: { emotion: 'happy' }, + }), + ).rejects.toThrow('Not Authorised') + }) + }) + }) }) diff --git a/backend/src/schema/types/type/Post.gql b/backend/src/schema/types/type/Post.gql index 30cdd71d4..422ab2867 100644 --- a/backend/src/schema/types/type/Post.gql +++ b/backend/src/schema/types/type/Post.gql @@ -51,9 +51,7 @@ type Post { emotions: [EMOTED] emotionsCount: Int! - @cypher( - statement: "MATCH (this)<-[emoted:EMOTED]-(:User) RETURN COUNT(DISTINCT emoted)" - ) + @cypher(statement: "MATCH (this)<-[emoted:EMOTED]-(:User) RETURN COUNT(DISTINCT emoted)") } type Mutation { @@ -93,4 +91,5 @@ type Mutation { language: String categoryIds: [ID] ): Post + RemovePostEmotions(from: _UserInput!, to: _PostInput!, data: _EMOTEDInput!): Boolean! } diff --git a/backend/yarn.lock b/backend/yarn.lock index beeaa91e1..e799968b3 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -2,13 +2,6 @@ # yarn lockfile v1 -"@apollographql/apollo-tools@^0.3.6": - version "0.3.7" - resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.3.7.tgz#3bc9c35b9fff65febd4ddc0c1fc04677693a3d40" - integrity sha512-+ertvzAwzkYmuUtT8zH3Zi6jPdyxZwOgnYaZHY7iLnMVJDhQKWlkyjLMF8wyzlPiEdDImVUMm5lOIBZo7LkGlg== - dependencies: - apollo-env "0.5.1" - "@apollographql/apollo-tools@^0.4.0": version "0.4.0" resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.4.0.tgz#8a1a0ab7a0bb12ccc03b72e4a104cfa5d969fd5f" @@ -1454,14 +1447,6 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -apollo-cache-control@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.8.0.tgz#08b157e5f8cd86f63608b05d45222de0725ebd5a" - integrity sha512-BBnfUmSWRws5dRSDD+R56RLJCE9v6xQuob+i/1Ju9EX4LZszU5JKVmxEvnkJ1bk/BkihjoQXTnP6fJCnt6fCmA== - dependencies: - apollo-server-env "2.4.0" - graphql-extensions "0.8.0" - apollo-cache-control@0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.8.1.tgz#707c0b958c02c5b47ddf49a02f60ea88a64783fb" @@ -1503,14 +1488,6 @@ apollo-client@~2.6.3: tslib "^1.9.3" zen-observable "^0.8.0" -apollo-datasource@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-0.6.0.tgz#823d6be8a3804613b5c56d2972c07db662293fc6" - integrity sha512-DOzzYWEOReYRu2vWPKEulqlTb9Xjg67sjVCzve5MXa7GUXjfr8IKioljvfoBMlqm/PpbJVk2ci4n5NIFqoYsrQ== - dependencies: - apollo-server-caching "0.5.0" - apollo-server-env "2.4.0" - apollo-datasource@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-0.6.1.tgz#697870f564da90bee53fa30d07875cb46c4d6b06" @@ -1526,18 +1503,6 @@ apollo-engine-reporting-protobuf@0.4.0: dependencies: protobufjs "^6.8.6" -apollo-engine-reporting@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/apollo-engine-reporting/-/apollo-engine-reporting-1.4.0.tgz#3a9bd011b271593e16d7057044898d0a817b197d" - integrity sha512-NMiO3h1cuEBt6QZNGHxivwuyZQnoU/2MMx0gUA8Gyy1ERBhK6P235qoMnvoi34rLmqJuyGPX6tXcab8MpMIzYQ== - dependencies: - apollo-engine-reporting-protobuf "0.4.0" - apollo-graphql "^0.3.3" - apollo-server-env "2.4.0" - apollo-server-types "0.2.0" - async-retry "^1.2.1" - graphql-extensions "0.8.0" - apollo-engine-reporting@1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/apollo-engine-reporting/-/apollo-engine-reporting-1.4.2.tgz#f6c1e964c3c2c09bdb25c449f6b7ab05952ff459" @@ -1618,34 +1583,6 @@ apollo-server-caching@0.5.0: dependencies: lru-cache "^5.0.0" -apollo-server-core@2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.7.0.tgz#c444347dea11149b5b453890506e43dc7e711257" - integrity sha512-CXjXAkgcMBCJZpsZgfAY5W7f5thdxUhn75UgzeH28RTUZ2aKi/LjoCixPWRSF1lU4vuEWneAnM8Vg/KCD+29lQ== - dependencies: - "@apollographql/apollo-tools" "^0.3.6" - "@apollographql/graphql-playground-html" "1.6.24" - "@types/ws" "^6.0.0" - apollo-cache-control "0.8.0" - apollo-datasource "0.6.0" - apollo-engine-reporting "1.4.0" - apollo-engine-reporting-protobuf "0.4.0" - apollo-server-caching "0.5.0" - apollo-server-env "2.4.0" - apollo-server-errors "2.3.1" - apollo-server-plugin-base "0.6.0" - apollo-server-types "0.2.0" - apollo-tracing "0.8.0" - fast-json-stable-stringify "^2.0.0" - graphql-extensions "0.8.0" - graphql-subscriptions "^1.0.0" - graphql-tag "^2.9.2" - graphql-tools "^4.0.0" - graphql-upload "^8.0.2" - sha.js "^2.4.11" - subscriptions-transport-ws "^0.9.11" - ws "^6.0.0" - apollo-server-core@2.7.2: version "2.7.2" resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.7.2.tgz#4acd9f4d0d235bef0e596e2a821326dfc07ae7b2" @@ -1672,14 +1609,6 @@ apollo-server-core@2.7.2: subscriptions-transport-ws "^0.9.11" ws "^6.0.0" -apollo-server-env@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/apollo-server-env/-/apollo-server-env-2.4.0.tgz#6611556c6b627a1636eed31317d4f7ea30705872" - integrity sha512-7ispR68lv92viFeu5zsRUVGP+oxsVI3WeeBNniM22Cx619maBUwcYTIC3+Y3LpXILhLZCzA1FASZwusgSlyN9w== - dependencies: - node-fetch "^2.1.2" - util.promisify "^1.0.0" - apollo-server-env@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/apollo-server-env/-/apollo-server-env-2.4.1.tgz#58264ecfeb151919e0f480320b4e3769be9f18f3" @@ -1713,13 +1642,6 @@ apollo-server-express@2.7.2, apollo-server-express@^2.7.2: subscriptions-transport-ws "^0.9.16" type-is "^1.6.16" -apollo-server-plugin-base@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-0.6.0.tgz#4186296ea5d52cfe613961d252a8a2f9e13e6ba6" - integrity sha512-BjfyWpHyKwHOe819gk3wEFwbnVp9Xvos03lkkYTTcXS/8G7xO78aUcE65mmyAC56/ZQ0aodNFkFrhwNtWBQWUQ== - dependencies: - apollo-server-types "0.2.0" - apollo-server-plugin-base@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-0.6.1.tgz#b9c209aa2102a26c6134f51bfa1e4a8307b63b11" @@ -1734,15 +1656,6 @@ apollo-server-testing@~2.7.2: dependencies: apollo-server-core "2.7.2" -apollo-server-types@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-0.2.0.tgz#270d7298f709fd8237ebfa48753249e5286df5f2" - integrity sha512-5dgiyXsM90vnfmdXO1ixHvsLn0d9NP4tWufmr3ZmjKv00r4JAQNUaUdgOSGbRIKoHELQGwxUuTySTZ/tYfGaNQ== - dependencies: - apollo-engine-reporting-protobuf "0.4.0" - apollo-server-caching "0.5.0" - apollo-server-env "2.4.0" - apollo-server-types@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-0.2.1.tgz#553da40ea1ad779ef0390c250ddad7eb782fdf64" @@ -1763,14 +1676,6 @@ apollo-server@~2.7.2: graphql-subscriptions "^1.0.0" graphql-tools "^4.0.0" -apollo-tracing@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.8.0.tgz#28cd9c61a4db12b2c24dad67fdedd309806c1650" - integrity sha512-cNOtOlyZ56iJRsCjnxjM1V0SnQ2ZZttuyoeOejdat6llPfk5bfYTVOKMjdbSfDvU33LS9g9sqNJCT0MwrEPFKQ== - dependencies: - apollo-server-env "2.4.0" - graphql-extensions "0.8.0" - apollo-tracing@0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.8.1.tgz#220aeac6ad598c67f9333739155b7a56bd63ccab" @@ -4071,15 +3976,6 @@ graphql-custom-directives@~0.2.14: moment "^2.22.2" numeral "^2.0.6" -graphql-extensions@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.8.0.tgz#b3fe7915aa84eef5a39135840840cc4d2e700c46" - integrity sha512-zV9RefkusIXqi9ZJtl7IJ5ecjDKdb7PLAb5E3CmxX3OK1GwNCIubp0vE7Fp4fXlCUKgTB1Woubs0zj71JT8o0A== - dependencies: - "@apollographql/apollo-tools" "^0.3.6" - apollo-server-env "2.4.0" - apollo-server-types "0.2.0" - graphql-extensions@0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.8.1.tgz#f5f1fed5fe49620c4e70c5d08bdbd0039e91c402" From 0a98113c2df5afcd3d0a184f4ca3c2ae1961539a Mon Sep 17 00:00:00 2001 From: Matt Rider Date: Tue, 30 Jul 2019 13:28:30 +0200 Subject: [PATCH 03/54] Add backend tests for RemovePostEmotions --- .../src/middleware/permissionsMiddleware.js | 8 +- backend/src/schema/resolvers/posts.js | 9 +- backend/src/schema/resolvers/posts.spec.js | 118 +++++++++++++----- backend/src/seed/factories/index.js | 17 +++ backend/src/seed/seed-db.js | 80 ++++++++++++ 5 files changed, 199 insertions(+), 33 deletions(-) diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index fe001d676..8a7aced85 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -24,6 +24,12 @@ const onlyYourself = rule({ return context.user.id === args.id }) +const isMyEmotion = rule({ + cache: 'no_cache', +})(async (parent, args, context, info) => { + return context.user.id === args.from.id +}) + const isMyOwn = rule({ cache: 'no_cache', })(async (parent, args, context, info) => { @@ -184,7 +190,7 @@ const permissions = shield( requestPasswordReset: allow, resetPassword: allow, AddPostEmotions: isAuthenticated, - RemovePostEmotions: isAuthenticated, + RemovePostEmotions: isMyEmotion, }, User: { email: isMyOwn, diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index c4ed494b7..754d9a6ed 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -96,14 +96,15 @@ export default { const transactionRes = await session.run( `MATCH (userFrom:User {id: $from.id})-[emotedRelation:EMOTED {emotion: $data.emotion}]->(postTo:Post {id: $to.id}) DELETE emotedRelation - RETURN emotedRelation`, + `, { from, to, data }, ) session.close() - const [removed] = transactionRes.records.map(record => { - return record.get('emotedRelation') + const [emoted] = transactionRes.records.map(record => { + return record.get('emotedRelation').properties.emotion }) - return !!removed + + return !emoted }, }, } diff --git a/backend/src/schema/resolvers/posts.spec.js b/backend/src/schema/resolvers/posts.spec.js index e1c85974b..68de51e79 100644 --- a/backend/src/schema/resolvers/posts.spec.js +++ b/backend/src/schema/resolvers/posts.spec.js @@ -64,6 +64,7 @@ beforeEach(async () => { password: '1234', } authorParams = { + id: 'u25', email: 'author@example.org', password: '1234', } @@ -387,11 +388,23 @@ describe('DeletePost', () => { describe('emotions', () => { let addPostEmotionsVariables - let postEmotionsVariables + let postEmotionsQueryVariables + const postEmotionsQuery = ` + query($id: ID!) { + Post(id: $id) { + emotions { + emotion + User { + id + } + } + } + } + ` beforeEach(async () => { const asAuthor = Factory() authorParams = { - id: 'u25', + id: authorParams.id, email: 'wanna-add-emotions@example.org', password: '1234', } @@ -402,17 +415,18 @@ describe('emotions', () => { title: postTitle, content: postContent, }) - addPostEmotionsVariables = { - from: { id: authorParams.id }, - to: { id: 'p1376' }, - data: { emotion: 'happy' }, - } - postEmotionsVariables = { - id: 'p1376', - } + postEmotionsQueryVariables = { id: 'p1376' } }) describe('AddPostEmotions', () => { + beforeEach(() => { + addPostEmotionsVariables = { + from: { id: authorParams.id }, + to: { id: 'p1376' }, + data: { emotion: 'happy' }, + } + }) + const addPostEmotionsMutation = ` mutation($from: _UserInput!, $to: _PostInput!, $data: _EMOTEDInput!) { AddPostEmotions(from: $from, to: $to, data: $data) { @@ -429,22 +443,13 @@ describe('emotions', () => { } } ` - const postEmotionsQuery = ` - query($id: ID!) { - Post(id: $id) { - emotions { - emotion - } - } - } - ` describe('unauthenticated', () => { it('throws authorization error', async () => { client = new GraphQLClient(host) await expect( client.request(addPostEmotionsMutation, { - from: { id: 'u25' }, + from: { id: authorParams.id }, to: { id: 'p1376' }, data: { emotion: 'happy' }, }), @@ -472,6 +477,7 @@ describe('emotions', () => { client.request(addPostEmotionsMutation, addPostEmotionsVariables), ).resolves.toEqual(expected) }) + it('limits the addition of the same emotion to 1', async () => { const expected = { Post: [ @@ -483,16 +489,21 @@ describe('emotions', () => { await client.request(addPostEmotionsMutation, addPostEmotionsVariables) await client.request(addPostEmotionsMutation, addPostEmotionsVariables) await expect( - client.request(postEmotionsCountQuery, postEmotionsVariables), + client.request(postEmotionsCountQuery, postEmotionsQueryVariables), ).resolves.toEqual(expected) }) it('allows a user to add more than one emotion', async () => { - const expected = [{ emotion: 'happy' }, { emotion: 'surprised' }] + const expected = [ + { emotion: 'happy', User: { id: authorParams.id } }, + { emotion: 'surprised', User: { id: authorParams.id } }, + ] await client.request(addPostEmotionsMutation, addPostEmotionsVariables) addPostEmotionsVariables.data.emotion = 'surprised' await client.request(addPostEmotionsMutation, addPostEmotionsVariables) - await expect(client.request(postEmotionsQuery, postEmotionsVariables)).resolves.toEqual({ + await expect( + client.request(postEmotionsQuery, postEmotionsQueryVariables), + ).resolves.toEqual({ Post: [{ emotions: expect.arrayContaining(expected) }], }) }) @@ -521,22 +532,73 @@ describe('emotions', () => { }) describe('RemovePostEmotions', () => { + let removePostEmotionsVariables const removePostEmotionsMutation = ` mutation($from: _UserInput!, $to: _PostInput!, $data: _EMOTEDInput!) { RemovePostEmotions(from: $from, to: $to, data: $data) } ` + beforeEach(() => { + removePostEmotionsVariables = { + from: { id: authorParams.id }, + to: { id: 'p1376' }, + data: { emotion: 'cry' }, + } + }) + describe('unauthenticated', () => { it('throws authorization error', async () => { client = new GraphQLClient(host) await expect( - client.request(removePostEmotionsMutation, { - from: { id: 'u25' }, - to: { id: 'p1376' }, - data: { emotion: 'happy' }, - }), + client.request(removePostEmotionsMutation, removePostEmotionsVariables), ).rejects.toThrow('Not Authorised') }) }) + + describe('authenticated', () => { + let headers + beforeEach(async () => { + headers = await login(authorParams) + client = new GraphQLClient(host, { headers }) + await factory.emote({ + from: authorParams.id, + to: 'p1376', + data: 'cry', + }) + await factory.emote({ + from: authorParams.id, + to: 'p1376', + data: 'happy', + }) + }) + + describe('but not the emoter', () => { + it('throws an authorization error', async () => { + removePostEmotionsVariables.from.id = userParams.id + await expect( + client.request(removePostEmotionsMutation, removePostEmotionsVariables), + ).rejects.toThrow('Not Authorised') + }) + }) + + describe('as the emoter', () => { + it('removes an emotion from a post', async () => { + const expected = { RemovePostEmotions: true } + await expect( + client.request(removePostEmotionsMutation, removePostEmotionsVariables), + ).resolves.toEqual(expected) + }) + + it('removes only the requested emotion, not all emotions', async () => { + const expected = [{ emotion: 'happy', User: { id: authorParams.id } }] + await client.request(removePostEmotionsMutation, removePostEmotionsVariables) + await expect( + client.request(postEmotionsQuery, postEmotionsQueryVariables), + ).resolves.toEqual({ + Post: [{ emotions: expect.arrayContaining(expected) }], + }) + }) + }) + }) }) }) diff --git a/backend/src/seed/factories/index.js b/backend/src/seed/factories/index.js index e841b0beb..6dd04f64b 100644 --- a/backend/src/seed/factories/index.js +++ b/backend/src/seed/factories/index.js @@ -130,6 +130,23 @@ export default function Factory(options = {}) { this.lastResponse = await cleanDatabase({ driver: this.neo4jDriver }) return this }, + async emote({ from, to, data }) { + const mutation = ` + mutation { + AddPostEmotions( + from: { id: "${from}" }, + to: { id: "${to}" }, + data: { emotion: ${data} } + ) { + from { id } + to { id } + emotion + } + } + ` + this.lastResponse = await this.graphQLClient.request(mutation) + return this + }, } result.authenticateAs.bind(result) result.create.bind(result) diff --git a/backend/src/seed/seed-db.js b/backend/src/seed/seed-db.js index 8f693cfd3..1d63e1958 100644 --- a/backend/src/seed/seed-db.js +++ b/backend/src/seed/seed-db.js @@ -487,6 +487,86 @@ import Factory from './factories' from: 'p15', to: 'Demokratie', }), + f.emote({ + from: 'u1', + to: 'p15', + data: 'surprised', + }), + f.emote({ + from: 'u2', + to: 'p14', + data: 'cry', + }), + f.emote({ + from: 'u3', + to: 'p13', + data: 'angry', + }), + f.emote({ + from: 'u4', + to: 'p12', + data: 'funny', + }), + f.emote({ + from: 'u5', + to: 'p11', + data: 'surprised', + }), + f.emote({ + from: 'u6', + to: 'p10', + data: 'cry', + }), + f.emote({ + from: 'u5', + to: 'p9', + data: 'happy', + }), + f.emote({ + from: 'u4', + to: 'p8', + data: 'angry', + }), + f.emote({ + from: 'u3', + to: 'p7', + data: 'funny', + }), + f.emote({ + from: 'u2', + to: 'p6', + data: 'surprised', + }), + f.emote({ + from: 'u1', + to: 'p5', + data: 'cry', + }), + f.emote({ + from: 'u2', + to: 'p4', + data: 'happy', + }), + f.emote({ + from: 'u3', + to: 'p3', + data: 'angry', + }), + f.emote({ + from: 'u4', + to: 'p2', + data: 'funny', + }), + f.emote({ + from: 'u5', + to: 'p1', + data: 'surprised', + }), + f.emote({ + from: 'u6', + to: 'p0', + data: 'cry', + }), ]) await Promise.all([ From 54234129580118ef60c35b2732081bf4bba9330b Mon Sep 17 00:00:00 2001 From: Matt Rider Date: Wed, 31 Jul 2019 14:58:05 +0200 Subject: [PATCH 04/54] Set up UI --- .../src/middleware/permissionsMiddleware.js | 1 + backend/src/schema/resolvers/posts.js | 18 +++ backend/src/schema/types/type/EMOTED.gql | 2 +- backend/src/schema/types/type/Post.gql | 4 + .../EmotionsButtons/EmotionsButtons.vue | 126 ++++++++++++++++++ webapp/graphql/PostQuery.js | 1 + webapp/pages/post/_id/_slug/index.vue | 26 ++-- webapp/static/img/svg/emoji/angry.svg | 1 + webapp/static/img/svg/emoji/angry_color.svg | 1 + webapp/static/img/svg/emoji/cry.svg | 1 + webapp/static/img/svg/emoji/cry_color.svg | 1 + webapp/static/img/svg/emoji/funny.svg | 1 + webapp/static/img/svg/emoji/funny_color.svg | 1 + webapp/static/img/svg/emoji/happy.svg | 1 + webapp/static/img/svg/emoji/happy_color.svg | 1 + webapp/static/img/svg/emoji/surprised.svg | 1 + .../static/img/svg/emoji/surprised_color.svg | 1 + 17 files changed, 179 insertions(+), 9 deletions(-) create mode 100644 webapp/components/EmotionsButtons/EmotionsButtons.vue create mode 100644 webapp/static/img/svg/emoji/angry.svg create mode 100644 webapp/static/img/svg/emoji/angry_color.svg create mode 100644 webapp/static/img/svg/emoji/cry.svg create mode 100644 webapp/static/img/svg/emoji/cry_color.svg create mode 100644 webapp/static/img/svg/emoji/funny.svg create mode 100644 webapp/static/img/svg/emoji/funny_color.svg create mode 100644 webapp/static/img/svg/emoji/happy.svg create mode 100644 webapp/static/img/svg/emoji/happy_color.svg create mode 100644 webapp/static/img/svg/emoji/surprised.svg create mode 100644 webapp/static/img/svg/emoji/surprised_color.svg diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 8a7aced85..29a171f29 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -154,6 +154,7 @@ const permissions = shield( User: or(noEmailFilter, isAdmin), isLoggedIn: allow, Badge: allow, + postsEmotionsCountByEmotion: allow, }, Mutation: { '*': deny, diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index 754d9a6ed..54351ffbb 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -107,4 +107,22 @@ export default { return !emoted }, }, + Query: { + postsEmotionsCountByEmotion: async (object, params, context, resolveInfo) => { + const session = context.driver.session() + const { id, data } = params + const transactionRes = await session.run( + `MATCH (post:Post {id: $id})<-[emoted:EMOTED {emotion: $data.emotion}]-() + RETURN COUNT(DISTINCT emoted) as emotionsCount + `, + { id, data }, + ) + session.close() + + const [emotionsCount] = transactionRes.records.map(record => { + return record.get('emotionsCount').low + }) + return emotionsCount + }, + }, } diff --git a/backend/src/schema/types/type/EMOTED.gql b/backend/src/schema/types/type/EMOTED.gql index 80d655b5c..d40eed0c4 100644 --- a/backend/src/schema/types/type/EMOTED.gql +++ b/backend/src/schema/types/type/EMOTED.gql @@ -7,4 +7,4 @@ type EMOTED @relation(name: "EMOTED") { #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 422ab2867..8aa2aee92 100644 --- a/backend/src/schema/types/type/Post.gql +++ b/backend/src/schema/types/type/Post.gql @@ -93,3 +93,7 @@ type Mutation { ): Post RemovePostEmotions(from: _UserInput!, to: _PostInput!, data: _EMOTEDInput!): Boolean! } + +type Query { + postsEmotionsCountByEmotion(id: ID!, data: _EMOTEDInput!): Int! +} diff --git a/webapp/components/EmotionsButtons/EmotionsButtons.vue b/webapp/components/EmotionsButtons/EmotionsButtons.vue new file mode 100644 index 000000000..0bc217f64 --- /dev/null +++ b/webapp/components/EmotionsButtons/EmotionsButtons.vue @@ -0,0 +1,126 @@ + + + diff --git a/webapp/graphql/PostQuery.js b/webapp/graphql/PostQuery.js index d2bba23ef..34a874d35 100644 --- a/webapp/graphql/PostQuery.js +++ b/webapp/graphql/PostQuery.js @@ -71,6 +71,7 @@ export default i18n => { } shoutedCount shoutedByCurrentUser + emotionsCount } } ` diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index d5e79f4b8..a4b7b37e3 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -43,14 +43,22 @@ - - + + + + + + + + + + @@ -71,6 +79,7 @@ import HcCommentForm from '~/components/comments/CommentForm' import HcCommentList from '~/components/comments/CommentList' import { postMenuModalsData, deletePostMutation } from '~/components/utils/PostHelpers' import PostQuery from '~/graphql/PostQuery.js' +import HcEmotionsButtons from '~/components/EmotionsButtons/EmotionsButtons' export default { name: 'PostSlug', @@ -86,6 +95,7 @@ export default { ContentMenu, HcCommentForm, HcCommentList, + HcEmotionsButtons, }, head() { return { diff --git a/webapp/static/img/svg/emoji/angry.svg b/webapp/static/img/svg/emoji/angry.svg new file mode 100644 index 000000000..74abe161f --- /dev/null +++ b/webapp/static/img/svg/emoji/angry.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/static/img/svg/emoji/angry_color.svg b/webapp/static/img/svg/emoji/angry_color.svg new file mode 100644 index 000000000..f6b4bd9a8 --- /dev/null +++ b/webapp/static/img/svg/emoji/angry_color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/static/img/svg/emoji/cry.svg b/webapp/static/img/svg/emoji/cry.svg new file mode 100644 index 000000000..d375fd2fd --- /dev/null +++ b/webapp/static/img/svg/emoji/cry.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/static/img/svg/emoji/cry_color.svg b/webapp/static/img/svg/emoji/cry_color.svg new file mode 100644 index 000000000..6a32bc2c5 --- /dev/null +++ b/webapp/static/img/svg/emoji/cry_color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/static/img/svg/emoji/funny.svg b/webapp/static/img/svg/emoji/funny.svg new file mode 100644 index 000000000..d23792d8c --- /dev/null +++ b/webapp/static/img/svg/emoji/funny.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/static/img/svg/emoji/funny_color.svg b/webapp/static/img/svg/emoji/funny_color.svg new file mode 100644 index 000000000..3ac2087e8 --- /dev/null +++ b/webapp/static/img/svg/emoji/funny_color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/static/img/svg/emoji/happy.svg b/webapp/static/img/svg/emoji/happy.svg new file mode 100644 index 000000000..d0d8a4e80 --- /dev/null +++ b/webapp/static/img/svg/emoji/happy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/static/img/svg/emoji/happy_color.svg b/webapp/static/img/svg/emoji/happy_color.svg new file mode 100644 index 000000000..d541639e3 --- /dev/null +++ b/webapp/static/img/svg/emoji/happy_color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/static/img/svg/emoji/surprised.svg b/webapp/static/img/svg/emoji/surprised.svg new file mode 100644 index 000000000..8a02a5a50 --- /dev/null +++ b/webapp/static/img/svg/emoji/surprised.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/static/img/svg/emoji/surprised_color.svg b/webapp/static/img/svg/emoji/surprised_color.svg new file mode 100644 index 000000000..398c34f35 --- /dev/null +++ b/webapp/static/img/svg/emoji/surprised_color.svg @@ -0,0 +1 @@ + \ No newline at end of file From fb9a632d558d9e6eb8a4d1b3f499ce91a093645e Mon Sep 17 00:00:00 2001 From: Matt Rider Date: Thu, 1 Aug 2019 15:11:41 +0200 Subject: [PATCH 05/54] Query a currentUsers emotions for a post, translations --- .../src/middleware/permissionsMiddleware.js | 1 + backend/src/schema/resolvers/posts.js | 23 ++++- backend/src/schema/types/type/Post.gql | 3 +- .../EmotionsButtons/EmotionsButtons.vue | 83 ++++++++++++------- webapp/locales/de.json | 8 ++ webapp/locales/en.json | 8 ++ 6 files changed, 93 insertions(+), 33 deletions(-) diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 9e8f5dacb..dc685e20c 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -166,6 +166,7 @@ const permissions = shield( isLoggedIn: allow, Badge: allow, postsEmotionsCountByEmotion: allow, + postsEmotionsCountByCurrentUser: allow, }, Mutation: { '*': deny, diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index 54351ffbb..cca2ba463 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -110,12 +110,12 @@ export default { Query: { postsEmotionsCountByEmotion: async (object, params, context, resolveInfo) => { const session = context.driver.session() - const { id, data } = params + const { postId, data } = params const transactionRes = await session.run( - `MATCH (post:Post {id: $id})<-[emoted:EMOTED {emotion: $data.emotion}]-() + `MATCH (post:Post {id: $postId})<-[emoted:EMOTED {emotion: $data.emotion}]-() RETURN COUNT(DISTINCT emoted) as emotionsCount `, - { id, data }, + { postId, data }, ) session.close() @@ -124,5 +124,22 @@ export default { }) return emotionsCount }, + postsEmotionsCountByCurrentUser: async (object, params, context, resolveInfo) => { + const session = context.driver.session() + const { postId } = params + const transactionRes = await session.run( + `MATCH (user:User {id: $userId})-[emoted:EMOTED]->(post:Post {id: $postId}) + RETURN emoted.emotion as emotion`, + { userId: context.user.id, postId }, + ) + + session.close() + let emotionsArray = [] + transactionRes.records.map(record => { + emotionsArray.push(record.get('emotion')) + }) + + return emotionsArray + }, }, } diff --git a/backend/src/schema/types/type/Post.gql b/backend/src/schema/types/type/Post.gql index 8aa2aee92..ba2b6ceef 100644 --- a/backend/src/schema/types/type/Post.gql +++ b/backend/src/schema/types/type/Post.gql @@ -95,5 +95,6 @@ type Mutation { } type Query { - postsEmotionsCountByEmotion(id: ID!, data: _EMOTEDInput!): Int! + postsEmotionsCountByEmotion(postId: ID!, data: _EMOTEDInput!): Int! + postsEmotionsCountByCurrentUser(postId: ID!): [String] } diff --git a/webapp/components/EmotionsButtons/EmotionsButtons.vue b/webapp/components/EmotionsButtons/EmotionsButtons.vue index 0bc217f64..b115e4bf3 100644 --- a/webapp/components/EmotionsButtons/EmotionsButtons.vue +++ b/webapp/components/EmotionsButtons/EmotionsButtons.vue @@ -1,7 +1,7 @@ diff --git a/webapp/components/FilterPosts/FilterPostsMenuItems.vue b/webapp/components/FilterPosts/FilterPostsMenuItems.vue index ab7e5d491..4db44aa41 100644 --- a/webapp/components/FilterPosts/FilterPostsMenuItems.vue +++ b/webapp/components/FilterPosts/FilterPostsMenuItems.vue @@ -15,8 +15,8 @@ @@ -40,7 +40,7 @@ @@ -78,7 +78,7 @@ name="filter-by-followed-authors-only" icon="user-plus" :primary="filteredByUsersFollowed" - @click="toggleOnlyFollowed" + @click="toggleFilteredByFollowed(user.id)" /> @@ -107,56 +107,16 @@ export default { }, computed: { ...mapGetters({ - filteredByUsersFollowed: 'posts/filteredByUsersFollowed', - filteredByCategories: 'posts/filteredByCategories', - usersFollowedFilter: 'posts/usersFollowedFilter', - categoriesFilter: 'posts/categoriesFilter', - selectedCategoryIds: 'posts/selectedCategoryIds', + filteredCategoryIds: 'postsFilter/filteredCategoryIds', + filteredByUsersFollowed: 'postsFilter/filteredByUsersFollowed', }), }, methods: { ...mapMutations({ - setFilteredByFollowers: 'posts/SET_FILTERED_BY_FOLLOWERS', - setFilteredByCategories: 'posts/SET_FILTERED_BY_CATEGORIES', - setUsersFollowedFilter: 'posts/SET_USERS_FOLLOWED_FILTER', - setCategoriesFilter: 'posts/SET_CATEGORIES_FILTER', - setSelectedCategoryIds: 'posts/SET_SELECTED_CATEGORY_IDS', + toggleFilteredByFollowed: 'postsFilter/TOGGLE_FILTER_BY_FOLLOWED', + resetCategories: 'postsFilter/RESET_CATEGORIES', + toggleCategory: 'postsFilter/TOGGLE_CATEGORY', }), - isActive(id) { - const index = this.selectedCategoryIds.indexOf(id) - if (index > -1 && this.setFilteredByCategories) { - return true - } - return false - }, - toggleCategory(categoryId) { - if (!categoryId) { - this.setSelectedCategoryIds() - } else { - this.setSelectedCategoryIds(categoryId) - } - this.setFilteredByCategories(!!this.selectedCategoryIds.length) - this.setCategoriesFilter( - this.selectedCategoryIds.length - ? { categories_some: { id_in: this.selectedCategoryIds } } - : {}, - ) - this.toggleFilter() - }, - toggleOnlyFollowed() { - this.setFilteredByFollowers(!this.filteredByUsersFollowed) - this.setUsersFollowedFilter( - this.filteredByUsersFollowed ? { author: { followedBy_some: { id: this.user.id } } } : {}, - ) - this.toggleFilter() - }, - toggleFilter() { - this.filter = { - ...this.usersFollowedFilter, - ...this.categoriesFilter, - } - this.$emit('filterPosts', this.filter) - }, }, } diff --git a/webapp/pages/index.spec.js b/webapp/pages/index.spec.js index fc2555411..805640ef6 100644 --- a/webapp/pages/index.spec.js +++ b/webapp/pages/index.spec.js @@ -26,22 +26,10 @@ describe('PostIndex', () => { beforeEach(() => { store = new Vuex.Store({ getters: { - 'posts/posts': () => { - return [ - { - id: 'p23', - name: 'It is a post', - author: { - id: 'u1', - }, - }, - ] - }, + 'postsFilter/postsFilter': () => ({}), 'auth/user': () => { return { id: 'u23' } }, - 'posts/usersFollowedFilter': () => {}, - 'posts/categoriesFilter': () => {}, }, }) mocks = { @@ -102,12 +90,6 @@ describe('PostIndex', () => { expect(wrapper.vm.hashtag).toBeNull() }) - it('calls the changeFilterBubble if there are hasthags in the route query', () => { - mocks.$route.query.hashtag = { id: 'hashtag' } - wrapper = Wrapper() - expect(mocks.$apollo.queries.Post.refetch).toHaveBeenCalledTimes(1) - }) - describe('mount', () => { beforeEach(() => { wrapper = mount(PostIndex, { @@ -125,12 +107,9 @@ describe('PostIndex', () => { expect(wrapper.vm.sorting).toEqual('createdAt_desc') }) - it('loads more posts when a user clicks on the load more button', () => { - wrapper - .findAll('button') - .at(2) - .trigger('click') - expect(mocks.$apollo.queries.Post.fetchMore).toHaveBeenCalledTimes(1) + it('updates offset when a user clicks on the load more button', () => { + wrapper.find('.load-more button').trigger('click') + expect(wrapper.vm.offset).toEqual(12) }) }) }) diff --git a/webapp/pages/index.vue b/webapp/pages/index.vue index c85354d73..5f0e9c115 100644 --- a/webapp/pages/index.vue +++ b/webapp/pages/index.vue @@ -16,7 +16,7 @@ tag.name) : '-' - }, - offset() { - return (this.page - 1) * this.pageSize - }, - }, - methods: { - ...mapMutations({ - setPosts: 'posts/SET_POSTS', - }), - changeFilterBubble(filter) { + finalFilters() { + let filter = this.postsFilter if (this.hashtag) { filter = { ...filter, tags_some: { name: this.hashtag }, } } - this.filter = filter - this.$apollo.queries.Post.refetch() + return filter }, + }, + watch: { + postsFilter() { + this.offset = 0 + this.posts = [] + }, + }, + methods: { toggleOnlySorting(x) { - this.filter = { - ...this.usersFollowedFilter, - ...this.categoriesFilter, - } - + this.offset = 0 + this.posts = [] this.sortingIcon = x.icons this.sorting = x.order - this.$apollo.queries.Post.refetch() }, clearSearch() { this.$router.push({ path: '/' }) this.hashtag = null - delete this.filter.tags_some - this.changeFilterBubble(this.filter) - }, - uniq(items, field = 'id') { - return uniqBy(items, field) }, href(post) { return this.$router.resolve({ @@ -155,31 +130,12 @@ export default { }).href }, showMoreContributions() { - // this.page++ - // Fetch more data and transform the original result - this.page++ - this.$apollo.queries.Post.fetchMore({ - variables: { - filter: this.filter, - first: this.pageSize, - offset: this.offset, - }, - // Transform the previous result with new data - updateQuery: (previousResult, { fetchMoreResult }) => { - let output = { Post: this.Post } - output.Post = [...previousResult.Post, ...fetchMoreResult.Post] - return output - }, - fetchPolicy: 'cache-and-network', - }) + this.offset += this.pageSize }, deletePost(_index, postId) { - this.Post = this.Post.filter(post => { + this.posts = this.posts.filter(post => { return post.id !== postId }) - // Why "uniq(Post)" is used in the array for list creation? - // Ideal solution here: - // this.Post.splice(index, 1) }, }, apollo: { @@ -188,16 +144,20 @@ export default { return filterPosts(this.$i18n) }, variables() { - return { - filter: { - ...this.usersFollowedFilter, - ...this.categoriesFilter, - ...this.filter, - }, + const result = { + filter: this.finalFilters, first: this.pageSize, - offset: 0, + offset: this.offset, orderBy: this.sorting, } + return result + }, + update({ Post }) { + // TODO: find out why `update` gets called twice initially. + // We have to filter for uniq posts only because we get the same + // result set twice. + const posts = uniqBy([...this.posts, ...Post], 'id') + this.posts = posts }, fetchPolicy: 'cache-and-network', }, From 0b96b300d39bc215a64a94f15621982f234335c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Sat, 10 Aug 2019 03:50:24 +0200 Subject: [PATCH 35/54] Implement hasMore feature on the index page --- webapp/pages/index.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/webapp/pages/index.vue b/webapp/pages/index.vue index 5f0e9c115..9c9e61070 100644 --- a/webapp/pages/index.vue +++ b/webapp/pages/index.vue @@ -33,7 +33,7 @@ primary /> - + @@ -55,6 +55,7 @@ export default { const { hashtag = null } = this.$route.query return { posts: [], + hasMore: true, // Initialize your apollo data offset: 0, pageSize: 12, @@ -156,6 +157,7 @@ export default { // TODO: find out why `update` gets called twice initially. // We have to filter for uniq posts only because we get the same // result set twice. + this.hasMore = !!Post.length const posts = uniqBy([...this.posts, ...Post], 'id') this.posts = posts }, From dcb7af1aef14bac50c2cad5f86155fcbda1b1a7b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2019 04:28:15 +0000 Subject: [PATCH 36/54] Bump cypress-cucumber-preprocessor from 1.13.0 to 1.13.1 Bumps [cypress-cucumber-preprocessor](https://github.com/TheBrainFamily/cypress-cucumber-preprocessor) from 1.13.0 to 1.13.1. - [Release notes](https://github.com/TheBrainFamily/cypress-cucumber-preprocessor/releases) - [Changelog](https://github.com/TheBrainFamily/cypress-cucumber-preprocessor/blob/master/CHANGELOG.md) - [Commits](https://github.com/TheBrainFamily/cypress-cucumber-preprocessor/compare/v1.13.0...v1.13.1) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0941d3e64..790365b6e 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "codecov": "^3.5.0", "cross-env": "^5.2.0", "cypress": "^3.4.1", - "cypress-cucumber-preprocessor": "^1.13.0", + "cypress-cucumber-preprocessor": "^1.13.1", "cypress-file-upload": "^3.3.3", "cypress-plugin-retries": "^1.2.2", "dotenv": "^8.0.0", diff --git a/yarn.lock b/yarn.lock index f7bbe5974..fa538a245 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1847,10 +1847,10 @@ cucumber@^4.2.1: util-arity "^1.0.2" verror "^1.9.0" -cypress-cucumber-preprocessor@^1.13.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/cypress-cucumber-preprocessor/-/cypress-cucumber-preprocessor-1.13.0.tgz#efacd70ce21c7d0adc60e25af166f5fb2e990fb8" - integrity sha512-Y3B4El3oYqKUvEhfn7k7NrX/hMJvOCJIO+sgMbvvPXsUngzLWUdiS2LOAaSxpV4t2BCyFuvfzGH0j+C3tu4UvA== +cypress-cucumber-preprocessor@^1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/cypress-cucumber-preprocessor/-/cypress-cucumber-preprocessor-1.13.1.tgz#d33350343a617c7579e1fed16e169d0a23b18d7a" + integrity sha512-gNmSVTmSVbUftvdTk0MnGGERwKTxtEQ1CwUOK4ujv5kANX29eV3XH9MYMe6gZQlVbLZN9kxz1EhopRF2bqmcwg== dependencies: "@cypress/browserify-preprocessor" "^1.1.2" chai "^4.1.2" From 0fa3333d8638368c2477e60d7b54cc473b9eb940 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2019 04:28:25 +0000 Subject: [PATCH 37/54] Bump apollo-client from 2.6.3 to 2.6.4 in /backend Bumps [apollo-client](https://github.com/apollographql/apollo-client) from 2.6.3 to 2.6.4. - [Release notes](https://github.com/apollographql/apollo-client/releases) - [Changelog](https://github.com/apollographql/apollo-client/blob/master/CHANGELOG.md) - [Commits](https://github.com/apollographql/apollo-client/compare/apollo-client@2.6.3...apollo-client@2.6.4) Signed-off-by: dependabot-preview[bot] --- backend/package.json | 2 +- backend/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/package.json b/backend/package.json index 508040b6b..4313a940c 100644 --- a/backend/package.json +++ b/backend/package.json @@ -45,7 +45,7 @@ "@hapi/joi": "^15.1.0", "activitystrea.ms": "~2.1.3", "apollo-cache-inmemory": "~1.6.2", - "apollo-client": "~2.6.3", + "apollo-client": "~2.6.4", "apollo-link-context": "~1.0.18", "apollo-link-http": "~1.5.15", "apollo-server": "~2.8.1", diff --git a/backend/yarn.lock b/backend/yarn.lock index d327c1bd0..4e1836ed6 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -1512,10 +1512,10 @@ apollo-cache@1.3.2, apollo-cache@^1.3.2: apollo-utilities "^1.3.2" tslib "^1.9.3" -apollo-client@~2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.6.3.tgz#9bb2d42fb59f1572e51417f341c5f743798d22db" - integrity sha512-DS8pmF5CGiiJ658dG+mDn8pmCMMQIljKJSTeMNHnFuDLV0uAPZoeaAwVFiAmB408Ujqt92oIZ/8yJJAwSIhd4A== +apollo-client@~2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.6.4.tgz#872c32927263a0d34655c5ef8a8949fbb20b6140" + integrity sha512-oWOwEOxQ9neHHVZrQhHDbI6bIibp9SHgxaLRVPoGvOFy7OH5XUykZE7hBQAVxq99tQjBzgytaZffQkeWo1B4VQ== dependencies: "@types/zen-observable" "^0.8.0" apollo-cache "1.3.2" From 8741ed567d06fd711da7eac907f9f93541304136 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2019 04:33:06 +0000 Subject: [PATCH 38/54] Bump sass-loader from 7.1.0 to 7.2.0 in /webapp Bumps [sass-loader](https://github.com/webpack-contrib/sass-loader) from 7.1.0 to 7.2.0. - [Release notes](https://github.com/webpack-contrib/sass-loader/releases) - [Changelog](https://github.com/webpack-contrib/sass-loader/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack-contrib/sass-loader/compare/v7.1.0...v7.2.0) Signed-off-by: dependabot-preview[bot] --- webapp/package.json | 2 +- webapp/yarn.lock | 72 ++++++++++++--------------------------------- 2 files changed, 20 insertions(+), 54 deletions(-) diff --git a/webapp/package.json b/webapp/package.json index 711ed8221..5be475278 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -117,7 +117,7 @@ "node-sass": "~4.12.0", "nodemon": "~1.19.1", "prettier": "~1.18.2", - "sass-loader": "~7.1.0", + "sass-loader": "~7.2.0", "style-loader": "~0.23.1", "style-resources-loader": "~1.2.1", "tippy.js": "^4.3.5", diff --git a/webapp/yarn.lock b/webapp/yarn.lock index e4ae26349..f6ebd7d10 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -4764,15 +4764,14 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" -clone-deep@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" - integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ== +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== dependencies: - for-own "^1.0.0" is-plain-object "^2.0.4" - kind-of "^6.0.0" - shallow-clone "^1.0.0" + kind-of "^6.0.2" + shallow-clone "^3.0.0" clone-response@1.0.2: version "1.0.2" @@ -6918,23 +6917,11 @@ follow-redirects@^1.0.0: dependencies: debug "^3.2.6" -for-in@^0.1.3: - version "0.1.8" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" - integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE= - -for-in@^1.0.1, for-in@^1.0.2: +for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= -for-own@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" - integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= - dependencies: - for-in "^1.0.1" - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -9574,11 +9561,6 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash.tail@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" - integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ= - lodash.template@^4.2.4, lodash.template@^4.4.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" @@ -10046,14 +10028,6 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mixin-object@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" - integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4= - dependencies: - for-in "^0.1.3" - is-extendable "^0.1.1" - mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -10149,12 +10123,7 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -neo-async@^2.5.0, neo-async@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" - integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== - -neo-async@^2.6.1: +neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== @@ -13121,16 +13090,15 @@ sass-graph@^2.2.4: scss-tokenizer "^0.2.3" yargs "^7.0.0" -sass-loader@^7.1.0, sass-loader@~7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.1.0.tgz#16fd5138cb8b424bf8a759528a1972d72aad069d" - integrity sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w== +sass-loader@^7.1.0, sass-loader@~7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.2.0.tgz#e34115239309d15b2527cb62b5dfefb62a96ff7f" + integrity sha512-h8yUWaWtsbuIiOCgR9fd9c2lRXZ2uG+h8Dzg/AGNj+Hg/3TO8+BBAW9mEP+mh8ei+qBKqSJ0F1FLlYjNBc61OA== dependencies: - clone-deep "^2.0.1" + clone-deep "^4.0.1" loader-utils "^1.0.1" - lodash.tail "^4.1.1" neo-async "^2.5.0" - pify "^3.0.0" + pify "^4.0.1" semver "^5.5.0" sass-resources-loader@^2.0.0: @@ -13313,14 +13281,12 @@ sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" -shallow-clone@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571" - integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA== +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== dependencies: - is-extendable "^0.1.1" - kind-of "^5.0.0" - mixin-object "^2.0.1" + kind-of "^6.0.2" shallow-equal@^1.1.0: version "1.2.0" From b02321b80d9880311acd157a3eb46d0d7f065682 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2019 04:34:10 +0000 Subject: [PATCH 39/54] Bump apollo-client from 2.6.3 to 2.6.4 in /webapp Bumps [apollo-client](https://github.com/apollographql/apollo-client) from 2.6.3 to 2.6.4. - [Release notes](https://github.com/apollographql/apollo-client/releases) - [Changelog](https://github.com/apollographql/apollo-client/blob/master/CHANGELOG.md) - [Commits](https://github.com/apollographql/apollo-client/compare/apollo-client@2.6.3...apollo-client@2.6.4) Signed-off-by: dependabot-preview[bot] --- webapp/package.json | 2 +- webapp/yarn.lock | 35 ++++++----------------------------- 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/webapp/package.json b/webapp/package.json index 711ed8221..c0625b814 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -57,7 +57,7 @@ "@nuxtjs/style-resources": "~1.0.0", "accounting": "~0.4.1", "apollo-cache-inmemory": "~1.6.2", - "apollo-client": "~2.6.3", + "apollo-client": "~2.6.4", "cookie-universal-nuxt": "~2.0.17", "cross-env": "~5.2.0", "date-fns": "2.0.0-beta.4", diff --git a/webapp/yarn.lock b/webapp/yarn.lock index e4ae26349..d33f23db5 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -2796,10 +2796,10 @@ apollo-cache@1.3.2, apollo-cache@^1.3.2: apollo-utilities "^1.3.2" tslib "^1.9.3" -apollo-client@^2.6.3, apollo-client@~2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.6.3.tgz#9bb2d42fb59f1572e51417f341c5f743798d22db" - integrity sha512-DS8pmF5CGiiJ658dG+mDn8pmCMMQIljKJSTeMNHnFuDLV0uAPZoeaAwVFiAmB408Ujqt92oIZ/8yJJAwSIhd4A== +apollo-client@^2.6.3, apollo-client@~2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.6.4.tgz#872c32927263a0d34655c5ef8a8949fbb20b6140" + integrity sha512-oWOwEOxQ9neHHVZrQhHDbI6bIibp9SHgxaLRVPoGvOFy7OH5XUykZE7hBQAVxq99tQjBzgytaZffQkeWo1B4VQ== dependencies: "@types/zen-observable" "^0.8.0" apollo-cache "1.3.2" @@ -3014,17 +3014,7 @@ apollo-link-ws@^1.0.18: apollo-link "^1.2.12" tslib "^1.9.3" -apollo-link@^1.0.0, apollo-link@^1.2.1, apollo-link@^1.2.11, apollo-link@^1.2.3: - version "1.2.11" - resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.11.tgz#493293b747ad3237114ccd22e9f559e5e24a194d" - integrity sha512-PQvRCg13VduLy3X/0L79M6uOpTh5iHdxnxYuo8yL7sJlWybKRJwsv4IcRBJpMFbChOOaHY7Og9wgPo6DLKDKDA== - dependencies: - apollo-utilities "^1.2.1" - ts-invariant "^0.3.2" - tslib "^1.9.3" - zen-observable-ts "^0.8.18" - -apollo-link@^1.2.12: +apollo-link@^1.0.0, apollo-link@^1.2.1, apollo-link@^1.2.11, apollo-link@^1.2.12, apollo-link@^1.2.3: version "1.2.12" resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.12.tgz#014b514fba95f1945c38ad4c216f31bcfee68429" integrity sha512-fsgIAXPKThyMVEMWQsUN22AoQI+J/pVXcjRGAShtk97h7D8O+SPskFinCGEkxPeQpE83uKaqafB2IyWdjN+J3Q== @@ -14459,16 +14449,11 @@ tsconfig@^7.0.0: strip-bom "^3.0.0" strip-json-comments "^2.0.0" -tslib@^1: +tslib@^1, tslib@^1.9.0, tslib@^1.9.3: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== -tslib@^1.9.0, tslib@^1.9.3: - version "1.9.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" - integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== - tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -15607,14 +15592,6 @@ yn@^3.0.0: resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.0.tgz#fcbe2db63610361afcc5eb9e0ac91e976d046114" integrity sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg== -zen-observable-ts@^0.8.18: - version "0.8.18" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.18.tgz#ade44b1060cc4a800627856ec10b9c67f5f639c8" - integrity sha512-q7d05s75Rn1j39U5Oapg3HI2wzriVwERVo4N7uFGpIYuHB9ff02P/E92P9B8T7QVC93jCMHpbXH7X0eVR5LA7A== - dependencies: - tslib "^1.9.3" - zen-observable "^0.8.0" - zen-observable-ts@^0.8.19: version "0.8.19" resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.19.tgz#c094cd20e83ddb02a11144a6e2a89706946b5694" From 902615701803ce07783f326a0f886aa751e6841d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Mon, 12 Aug 2019 11:50:23 +0200 Subject: [PATCH 40/54] Better `hasMore`: Don't wait until length == 0 follow @Tirokk --- webapp/pages/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/pages/index.vue b/webapp/pages/index.vue index 9c9e61070..683e5eb65 100644 --- a/webapp/pages/index.vue +++ b/webapp/pages/index.vue @@ -157,7 +157,7 @@ export default { // TODO: find out why `update` gets called twice initially. // We have to filter for uniq posts only because we get the same // result set twice. - this.hasMore = !!Post.length + this.hasMore = Post.length >= this.pageSize const posts = uniqBy([...this.posts, ...Post], 'id') this.posts = posts }, From 5932d184d7c5dc18e31189a555470d7a058bd9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 12 Aug 2019 13:27:14 +0200 Subject: [PATCH 41/54] Corrected namings and countings --- webapp/locales/de.json | 10 +++++----- webapp/locales/en.json | 6 +++--- webapp/pages/admin/tags.vue | 2 +- webapp/pages/admin/users.vue | 6 ++---- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/webapp/locales/de.json b/webapp/locales/de.json index 5a2b77131..4a1400e4d 100644 --- a/webapp/locales/de.json +++ b/webapp/locales/de.json @@ -235,7 +235,7 @@ "postCount": "Beiträge" }, "tags": { - "name": "Schlagworte", + "name": "Hashtags", "tagCountUnique": "Benutzer", "tagCount": "Beiträge" }, @@ -543,12 +543,12 @@ "description": "Sollte Dir die Alphaversion unseres Netzwerks wider Erwarten, egal aus welchen Gründen, nicht gefallen, überweisen wir Dir Deine gespendeten Monatsbeiträge innerhalb der ersten 2 Monate gerne zurück. Einfach Mail an: info@human-connection.org Achtung: Viele Funktionen werden erst nach und nach eingebaut." }, "questions": { - "title": "Fragen", - "description": "Die Termine und Links zu den Zoom-Räumen findest Du hier: https://human-connection.org/veranstaltungen/ " + "title": "Fragen", + "description": "Die Termine und Links zu den Zoom-Räumen findest Du hier: https://human-connection.org/veranstaltungen/ " }, "human-connection": { - "title": "Von Menschen für Menschen:", - "description": "Bitte hilf uns weitere monatlichen Spender für Human Connection zu bekommen, damit das Netzwerk so schnell wie möglich offiziell an den Start gehen kann. https://human-connection.org " + "title": "Von Menschen für Menschen:", + "description": "Bitte hilf uns weitere monatlichen Spender für Human Connection zu bekommen, damit das Netzwerk so schnell wie möglich offiziell an den Start gehen kann. https://human-connection.org " }, "have-fun": "Jetzt aber viel Spaß mit der Alpha von Human Connection! Für den ersten Weltfrieden. ♥︎", "closing": "Herzlichst

Euer Human Connection Team" diff --git a/webapp/locales/en.json b/webapp/locales/en.json index fe0f1c99c..31c1af8f6 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -107,7 +107,7 @@ "follow": "Follow", "followers": "Followers", "following": "Following", - "shouted": "Recommended", + "shouted": "Shouted", "commented": "Commented", "userAnonym": "Anonymous", "socialMedia": "Where else can I find", @@ -203,7 +203,7 @@ "projects": "Projects", "invites": "Invites", "follows": "Follows", - "shouts": "Recommended" + "shouts": "Shouts" }, "organizations": { "name": "Organizations" @@ -235,7 +235,7 @@ "postCount": "Posts" }, "tags": { - "name": "Tags", + "name": "Hashtags", "tagCountUnique": "Users", "tagCount": "Posts" }, diff --git a/webapp/pages/admin/tags.vue b/webapp/pages/admin/tags.vue index 53808fc53..06b32a508 100644 --- a/webapp/pages/admin/tags.vue +++ b/webapp/pages/admin/tags.vue @@ -2,7 +2,7 @@ diff --git a/webapp/pages/admin/users.vue b/webapp/pages/admin/users.vue index 0d737cfc0..3da484fe6 100644 --- a/webapp/pages/admin/users.vue +++ b/webapp/pages/admin/users.vue @@ -21,7 +21,7 @@ From 1d180480c4d10573f231d1e32c333d63b393e2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 12 Aug 2019 15:35:09 +0200 Subject: [PATCH 42/54] Translated several texts and corrected and added some functionalities --- webapp/locales/de.json | 10 ++++++- webapp/locales/en.json | 10 ++++++- webapp/pages/admin/categories.vue | 4 +-- webapp/pages/admin/index.vue | 4 +-- webapp/pages/admin/tags.vue | 13 ++++++--- webapp/pages/admin/users.vue | 34 +++++++++++++---------- webapp/pages/post/_id/_slug/more-info.vue | 18 ++++++------ 7 files changed, 60 insertions(+), 33 deletions(-) diff --git a/webapp/locales/de.json b/webapp/locales/de.json index 4a1400e4d..8bc336bf6 100644 --- a/webapp/locales/de.json +++ b/webapp/locales/de.json @@ -215,6 +215,7 @@ }, "table": { "columns": { + "number": "Nr.", "name": "Name", "slug": "Slug", "role": "Rolle", @@ -236,6 +237,8 @@ }, "tags": { "name": "Hashtags", + "number": "Nr.", + "nameOfHashtag": "Name", "tagCountUnique": "Benutzer", "tagCount": "Beiträge" }, @@ -251,7 +254,12 @@ "post": { "name": "Beitrag", "moreInfo": { - "name": "Mehr Info" + "name": "Mehr Info", + "title": "Mehr Informationen", + "description": "Hier findest du weitere infos zum Thema.", + "titleOfCategoriesSection": "Kategorien", + "titleOfHashtagsSection": "Hashtags", + "titleOfRelatedContributionsSection": "Verwandte Beiträge" }, "takeAction": { "name": "Aktiv werden" diff --git a/webapp/locales/en.json b/webapp/locales/en.json index 31c1af8f6..faf440899 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -215,6 +215,7 @@ }, "table": { "columns": { + "number": "#", "name": "Name", "slug": "Slug", "role": "Role", @@ -236,6 +237,8 @@ }, "tags": { "name": "Hashtags", + "number": "#", + "nameOfHashtag": "Name", "tagCountUnique": "Users", "tagCount": "Posts" }, @@ -251,7 +254,12 @@ "post": { "name": "Post", "moreInfo": { - "name": "More info" + "name": "More info", + "title": "More Informations", + "description": "Here you can find more information about this topic.", + "titleOfCategoriesSection": "Categories", + "titleOfHashtagsSection": "Hashtags", + "titleOfRelatedContributionsSection": "Related Posts" }, "takeAction": { "name": "Take action" diff --git a/webapp/pages/admin/categories.vue b/webapp/pages/admin/categories.vue index ce795feaf..23aa4d606 100644 --- a/webapp/pages/admin/categories.vue +++ b/webapp/pages/admin/categories.vue @@ -31,7 +31,7 @@ export default { }, apollo: { Category: { - query: gql(` + query: gql` query { Category(orderBy: postCount_desc) { id @@ -41,7 +41,7 @@ export default { postCount } } - `), + `, }, }, } diff --git a/webapp/pages/admin/index.vue b/webapp/pages/admin/index.vue index 6732b2137..7790ed849 100644 --- a/webapp/pages/admin/index.vue +++ b/webapp/pages/admin/index.vue @@ -133,7 +133,7 @@ export default { }, apollo: { statistics: { - query: gql(` + query: gql` query { statistics { countUsers @@ -147,7 +147,7 @@ export default { countShouts } } - `), + `, }, }, } diff --git a/webapp/pages/admin/tags.vue b/webapp/pages/admin/tags.vue index 06b32a508..c5a28dc11 100644 --- a/webapp/pages/admin/tags.vue +++ b/webapp/pages/admin/tags.vue @@ -4,6 +4,11 @@ + @@ -20,8 +25,8 @@ export default { computed: { fields() { return { - id: '#', - name: 'Name', + id: this.$t('admin.tags.number'), + name: this.$t('admin.tags.name'), taggedCountUnique: { label: this.$t('admin.tags.tagCountUnique'), align: 'right', @@ -35,7 +40,7 @@ export default { }, apollo: { Tag: { - query: gql(` + query: gql` query { Tag(first: 20, orderBy: taggedCountUnique_desc) { id @@ -44,7 +49,7 @@ export default { taggedCountUnique } } - `), + `, }, }, } diff --git a/webapp/pages/admin/users.vue b/webapp/pages/admin/users.vue index 3da484fe6..e58b413aa 100644 --- a/webapp/pages/admin/users.vue +++ b/webapp/pages/admin/users.vue @@ -90,7 +90,7 @@ export default { }, fields() { return { - index: '#', + index: this.$t('admin.users.table.columns.number'), name: this.$t('admin.users.table.columns.name'), slug: this.$t('admin.users.table.columns.slug'), createdAt: this.$t('admin.users.table.columns.createdAt'), @@ -116,20 +116,26 @@ export default { apollo: { User: { query() { - return gql(` - query($filter: _UserFilter, $first: Int, $offset: Int, $email: String) { - User(email: $email, filter: $filter, first: $first, offset: $offset, orderBy: createdAt_desc) { - id - name - slug - role - createdAt - contributionsCount - commentedCount - shoutedCount + return gql` + query($filter: _UserFilter, $first: Int, $offset: Int, $email: String) { + User( + email: $email + filter: $filter + first: $first + offset: $offset + orderBy: createdAt_desc + ) { + id + name + slug + role + createdAt + contributionsCount + commentedCount + shoutedCount + } } - } - `) + ` }, variables() { const { offset, first, email, filter } = this diff --git a/webapp/pages/post/_id/_slug/more-info.vue b/webapp/pages/post/_id/_slug/more-info.vue index c7d1a5f0e..ef442b7d6 100644 --- a/webapp/pages/post/_id/_slug/more-info.vue +++ b/webapp/pages/post/_id/_slug/more-info.vue @@ -1,11 +1,11 @@