From 97707f7a203d98ea7673ae41fea3128014bfcf95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 4 Apr 2019 18:29:50 +0200 Subject: [PATCH 1/5] Added file "backend/src/resolvers/follow.js" WIP !!! In development! Not able to run now! --- backend/src/resolvers/follow.js | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 backend/src/resolvers/follow.js diff --git a/backend/src/resolvers/follow.js b/backend/src/resolvers/follow.js new file mode 100644 index 000000000..860ee777d --- /dev/null +++ b/backend/src/resolvers/follow.js @@ -0,0 +1,49 @@ +export default { + Mutation: { + follow: async (_object, params, context, _resolveInfo) => { + const { followedId, followedType } = params + const session = context.driver.session() + + let sessionRes = await session.run( + `MATCH (n {id: $id}), (u:User {id: $cypherParams.currentUserId}) + WHERE $type IN labels(n) AND NOT $id = $cypherParams.currentUserId + MERGE (u)-[r:FOLLOWS]->(n) + RETURN COUNT(r) > 0`, + { + badgeId: fromBadgeId, + rewardedUserId: toUserId + } + ) + + const [rewardedUser] = sessionRes.records.map(record => { + return record.get('rewardedUser') + }) + + session.close() + + return rewardedUser.id + }, + + unfollow: async (_object, params, context, _resolveInfo) => { + const { fromBadgeId, toUserId } = params + const session = context.driver.session() + + let sessionRes = await session.run( + `MATCH (badge:Badge {id: $badgeId})-[reward:REWARDED]->(rewardedUser:User {id: $rewardedUserId}) + DELETE reward + RETURN rewardedUser {.id}`, + { + badgeId: fromBadgeId, + rewardedUserId: toUserId + } + ) + const [rewardedUser] = sessionRes.records.map(record => { + return record.get('rewardedUser') + }) + session.close() + + return rewardedUser.id + } + } + } + \ No newline at end of file From 587025e4d33326dd0ee93815f6f132487686b6c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 10 Apr 2019 11:15:45 +0200 Subject: [PATCH 2/5] Start refactoring follow --- backend/src/resolvers/follow.js | 92 ++++++++++++++++----------------- backend/src/schema.graphql | 7 +-- 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/backend/src/resolvers/follow.js b/backend/src/resolvers/follow.js index 860ee777d..2a835f636 100644 --- a/backend/src/resolvers/follow.js +++ b/backend/src/resolvers/follow.js @@ -1,49 +1,49 @@ +import gql from 'graphql-tag' +import { neo4jgraphql } from 'neo4j-graphql-js' + export default { - Mutation: { - follow: async (_object, params, context, _resolveInfo) => { - const { followedId, followedType } = params - const session = context.driver.session() - - let sessionRes = await session.run( - `MATCH (n {id: $id}), (u:User {id: $cypherParams.currentUserId}) - WHERE $type IN labels(n) AND NOT $id = $cypherParams.currentUserId - MERGE (u)-[r:FOLLOWS]->(n) - RETURN COUNT(r) > 0`, - { - badgeId: fromBadgeId, - rewardedUserId: toUserId - } - ) - - const [rewardedUser] = sessionRes.records.map(record => { - return record.get('rewardedUser') - }) - - session.close() - - return rewardedUser.id - }, - - unfollow: async (_object, params, context, _resolveInfo) => { - const { fromBadgeId, toUserId } = params - const session = context.driver.session() - - let sessionRes = await session.run( - `MATCH (badge:Badge {id: $badgeId})-[reward:REWARDED]->(rewardedUser:User {id: $rewardedUserId}) - DELETE reward - RETURN rewardedUser {.id}`, - { - badgeId: fromBadgeId, - rewardedUserId: toUserId - } - ) - const [rewardedUser] = sessionRes.records.map(record => { - return record.get('rewardedUser') - }) - session.close() - - return rewardedUser.id - } + Mutation: { + follow: async (object, params, context, resolveInfo) => { + const result = await neo4jgraphql(object, params, context, resolveInfo, true) + const { followedId, followedType } = params + + const session = context.driver.session() + await session.run( + gql` + MATCH (n {id: $followedId}), (u:User {id: $userId}) + WHERE $type IN labels(n) AND NOT $id = $userId + MERGE (u)-[r:FOLLOWS]->(n) + RETURN COUNT(r) > 0`, + { + followedId: followedId, + type: followedType, + userId: context.user.id + } + ) + session.close() + + return result } + + // unfollow: async (_object, params, context, _resolveInfo) => { + // const { fromBadgeId, toUserId } = params + // const session = context.driver.session() + + // let sessionRes = await session.run( + // `MATCH (badge:Badge {id: $badgeId})-[reward:REWARDED]->(rewardedUser:User {id: $rewardedUserId}) + // DELETE reward + // RETURN rewardedUser {.id}`, + // { + // badgeId: fromBadgeId, + // rewardedUserId: toUserId + // } + // ) + // const [rewardedUser] = sessionRes.records.map(record => { + // return record.get('rewardedUser') + // }) + // session.close() + + // return rewardedUser.id + // } } - \ No newline at end of file +} diff --git a/backend/src/schema.graphql b/backend/src/schema.graphql index db468471a..107e134fa 100644 --- a/backend/src/schema.graphql +++ b/backend/src/schema.graphql @@ -42,12 +42,7 @@ type Mutation { RETURN COUNT(r) > 0 """) "Follow the given Type and ID" - follow(id: ID!, type: FollowTypeEnum): Boolean! @cypher(statement: """ - MATCH (n {id: $id}), (u:User {id: $cypherParams.currentUserId}) - WHERE $type IN labels(n) AND NOT $id = $cypherParams.currentUserId - MERGE (u)-[r:FOLLOWS]->(n) - RETURN COUNT(r) > 0 - """) + follow(id: ID!, type: FollowTypeEnum): Boolean! "Unfollow the given Type and ID" unfollow(id: ID!, type: FollowTypeEnum): Boolean! @cypher(statement: """ MATCH (:User {id: $cypherParams.currentUserId})-[r:FOLLOWS]->(n {id: $id}) From 6a0114664756f0f1b63245977c380107499e084f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 10 Apr 2019 14:11:13 +0200 Subject: [PATCH 3/5] Refactored mutation "follow" Done by @Tirokk and @mattwr18 . --- backend/src/graphql-schema.js | 2 ++ backend/src/resolvers/follow.js | 30 +++++++++++++++++------------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/backend/src/graphql-schema.js b/backend/src/graphql-schema.js index 57b2ffb6c..7760ae62c 100644 --- a/backend/src/graphql-schema.js +++ b/backend/src/graphql-schema.js @@ -6,6 +6,7 @@ import statistics from './resolvers/statistics.js' import reports from './resolvers/reports.js' import posts from './resolvers/posts.js' import moderation from './resolvers/moderation.js' +import follow from './resolvers/follow.js' import rewards from './resolvers/rewards.js' export const typeDefs = fs @@ -24,6 +25,7 @@ export const resolvers = { ...reports.Mutation, ...posts.Mutation, ...moderation.Mutation, + ...follow.Mutation, ...rewards.Mutation } } diff --git a/backend/src/resolvers/follow.js b/backend/src/resolvers/follow.js index 2a835f636..8938703a7 100644 --- a/backend/src/resolvers/follow.js +++ b/backend/src/resolvers/follow.js @@ -1,28 +1,32 @@ -import gql from 'graphql-tag' -import { neo4jgraphql } from 'neo4j-graphql-js' +// import gql from 'graphql-tag' +// import { neo4jgraphql } from 'neo4j-graphql-js' export default { Mutation: { follow: async (object, params, context, resolveInfo) => { - const result = await neo4jgraphql(object, params, context, resolveInfo, true) - const { followedId, followedType } = params + // const result = await neo4jgraphql(object, params, context, resolveInfo, true) + const { id, type } = params const session = context.driver.session() - await session.run( - gql` - MATCH (n {id: $followedId}), (u:User {id: $userId}) - WHERE $type IN labels(n) AND NOT $id = $userId - MERGE (u)-[r:FOLLOWS]->(n) - RETURN COUNT(r) > 0`, + let sessionRes = await session.run( + `MATCH (node {id: $id}), (user:User {id: $userId}) + WHERE $type IN labels(node) AND NOT $id = $userId + MERGE (user)-[relation:FOLLOWS]->(node) + RETURN COUNT(relation) > 0 as isFollowed`, { - followedId: followedId, - type: followedType, + id, + type, userId: context.user.id } ) + + const [ isFollowed ] = sessionRes.records.map(record => { + return record.get('isFollowed') + }) + session.close() - return result + return isFollowed } // unfollow: async (_object, params, context, _resolveInfo) => { From c636d031bebc4d51b9c16fcd2af991dee8347784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 10 Apr 2019 15:24:58 +0200 Subject: [PATCH 4/5] Refactored mutations "shout", "unshout" Formated "schema.graphql" for better readability. " --- backend/src/graphql-schema.js | 2 + backend/src/resolvers/shout.js | 51 ++++++++++++++++++++++ backend/src/schema.graphql | 77 +++++++++++++++++----------------- 3 files changed, 91 insertions(+), 39 deletions(-) create mode 100644 backend/src/resolvers/shout.js diff --git a/backend/src/graphql-schema.js b/backend/src/graphql-schema.js index c39882fb3..4685586f8 100644 --- a/backend/src/graphql-schema.js +++ b/backend/src/graphql-schema.js @@ -7,6 +7,7 @@ import reports from './resolvers/reports.js' import posts from './resolvers/posts.js' import moderation from './resolvers/moderation.js' import follow from './resolvers/follow.js' +import shout from './resolvers/shout.js' import rewards from './resolvers/rewards.js' import notifications from './resolvers/notifications' @@ -28,6 +29,7 @@ export const resolvers = { ...posts.Mutation, ...moderation.Mutation, ...follow.Mutation, + ...shout.Mutation, ...rewards.Mutation, ...notifications.Mutation } diff --git a/backend/src/resolvers/shout.js b/backend/src/resolvers/shout.js new file mode 100644 index 000000000..f190c5d0b --- /dev/null +++ b/backend/src/resolvers/shout.js @@ -0,0 +1,51 @@ +export default { + Mutation: { + shout: async (_object, params, context, _resolveInfo) => { + const { id, type } = params + + const session = context.driver.session() + let sessionRes = await session.run( + `MATCH (node {id: $id})<-[:WROTE]-(userWritten:User), (user:User {id: $userId}) + WHERE $type IN labels(node) AND NOT userWritten.id = $userId + MERGE (user)-[relation:SHOUTED]->(node) + RETURN COUNT(relation) > 0 as isShouted`, + { + id, + type, + userId: context.user.id + } + ) + + const [isShouted] = sessionRes.records.map(record => { + return record.get('isShouted') + }) + + session.close() + + return isShouted + }, + + unshout: async (_object, params, context, _resolveInfo) => { + const { id, type } = params + const session = context.driver.session() + + let sessionRes = await session.run( + `MATCH (user:User {id: $userId})-[relation:SHOUTED]->(node {id: $id}) + WHERE $type IN labels(node) + DELETE relation + RETURN COUNT(relation) > 0 as isShouted`, + { + id, + type, + userId: context.user.id + } + ) + const [isShouted] = sessionRes.records.map(record => { + return record.get('isShouted') + }) + session.close() + + return isShouted + } + } +} diff --git a/backend/src/schema.graphql b/backend/src/schema.graphql index aef8bd9d6..d94c8e329 100644 --- a/backend/src/schema.graphql +++ b/backend/src/schema.graphql @@ -1,8 +1,8 @@ type Query { isLoggedIn: Boolean! - "Get the currently logged in User based on the given JWT Token" + # Get the currently logged in User based on the given JWT Token currentUser: User - "Get the latest Network Statistics" + # Get the latest Network Statistics statistics: Statistics! findPosts(filter: String!, limit: Int = 10): [Post]! @cypher( statement: """ @@ -18,7 +18,7 @@ type Query { ) } type Mutation { - "Get a JWT Token for the given Email and password" + # Get a JWT Token for the given Email and password login(email: String!, password: String!): String! signup(email: String!, password: String!): Boolean! changePassword(oldPassword:String!, newPassword: String!): String! @@ -27,23 +27,13 @@ type Mutation { enable(id: ID!): ID reward(fromBadgeId: ID!, toUserId: ID!): ID unreward(fromBadgeId: ID!, toUserId: ID!): ID - "Shout the given Type and ID" - shout(id: ID!, type: ShoutTypeEnum): Boolean! @cypher(statement: """ - MATCH (n {id: $id})<-[:WROTE]-(wu:User), (u:User {id: $cypherParams.currentUserId}) - WHERE $type IN labels(n) AND NOT wu.id = $cypherParams.currentUserId - MERGE (u)-[r:SHOUTED]->(n) - RETURN COUNT(r) > 0 - """) - "Unshout the given Type and ID" - unshout(id: ID!, type: ShoutTypeEnum): Boolean! @cypher(statement: """ - MATCH (:User {id: $cypherParams.currentUserId})-[r:SHOUTED]->(n {id: $id}) - WHERE $type IN labels(n) - DELETE r - RETURN COUNT(r) > 0 - """) - "Follow the given Type and ID" + # Shout the given Type and ID + shout(id: ID!, type: ShoutTypeEnum): Boolean! + # Unshout the given Type and ID + unshout(id: ID!, type: ShoutTypeEnum): Boolean! + # Follow the given Type and ID follow(id: ID!, type: FollowTypeEnum): Boolean! - "Unfollow the given Type and ID" + # Unfollow the given Type and ID unfollow(id: ID!, type: FollowTypeEnum): Boolean! } @@ -133,11 +123,13 @@ type User { followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN") followedByCount: Int! @cypher(statement: "MATCH (this)<-[:FOLLOWS]-(r:User) RETURN COUNT(DISTINCT r)") - "Is the currently logged in user following that user?" - followedByCurrentUser: Boolean! @cypher(statement: """ - MATCH (this)<-[:FOLLOWS]-(u:User {id: $cypherParams.currentUserId}) - RETURN COUNT(u) >= 1 - """) + # Is the currently logged in user following that user? + followedByCurrentUser: Boolean! @cypher( + statement: """ + MATCH (this)<-[:FOLLOWS]-(u:User {id: $cypherParams.currentUserId}) + RETURN COUNT(u) >= 1 + """ + ) #contributions: [WrittenPost]! #contributions2(first: Int = 10, offset: Int = 0): [WrittenPost2]! @@ -145,11 +137,13 @@ type User { # statement: "MATCH (this)-[w:WROTE]->(p:Post) RETURN p as Post, w.timestamp as timestamp" # ) contributions: [Post]! @relation(name: "WROTE", direction: "OUT") - contributionsCount: Int! @cypher(statement: """ - MATCH (this)-[:WROTE]->(r:Post) - WHERE (NOT exists(r.deleted) OR r.deleted = false) - AND (NOT exists(r.disabled) OR r.disabled = false) - RETURN COUNT(r)""" + contributionsCount: Int! @cypher( + statement: """ + MATCH (this)-[:WROTE]->(r:Post) + WHERE (NOT exists(r.deleted) OR r.deleted = false) + AND (NOT exists(r.disabled) OR r.disabled = false) + RETURN COUNT(r) + """ ) comments: [Comment]! @relation(name: "WROTE", direction: "OUT") @@ -186,11 +180,13 @@ type Post { createdAt: String updatedAt: String - relatedContributions: [Post]! @cypher(statement: """ - MATCH (this)-[:TAGGED|CATEGORIZED]->(categoryOrTag)<-[:TAGGED|CATEGORIZED]-(post:Post) - RETURN DISTINCT post - LIMIT 10 - """) + relatedContributions: [Post]! @cypher( + statement: """ + MATCH (this)-[:TAGGED|CATEGORIZED]->(categoryOrTag)<-[:TAGGED|CATEGORIZED]-(post:Post) + RETURN DISTINCT post + LIMIT 10 + """ + ) tags: [Tag]! @relation(name: "TAGGED", direction: "OUT") categories: [Category]! @relation(name: "CATEGORIZED", direction: "OUT") @@ -201,11 +197,13 @@ type Post { shoutedBy: [User]! @relation(name: "SHOUTED", direction: "IN") shoutedCount: Int! @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(statement: """ - MATCH (this)<-[:SHOUTED]-(u:User {id: $cypherParams.currentUserId}) - RETURN COUNT(u) >= 1 - """) + # Has the currently logged in user shouted that post? + shoutedByCurrentUser: Boolean! @cypher( + statement: """ + MATCH (this)<-[:SHOUTED]-(u:User {id: $cypherParams.currentUserId}) + RETURN COUNT(u) >= 1 + """ + ) } type Comment { @@ -304,6 +302,7 @@ type Tag { deleted: Boolean disabled: Boolean } + type SharedInboxEndpoint { id: ID! uri: String From 9929aa462635dbcaf025ea8c7e2ea12dfafff98c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 12 Apr 2019 08:41:53 +0200 Subject: [PATCH 5/5] Rnamed "sessionRes" to "transactionRes" Even in the rewards mutation. --- backend/src/resolvers/follow.js | 8 ++++---- backend/src/resolvers/rewards.js | 8 ++++---- backend/src/resolvers/shout.js | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/backend/src/resolvers/follow.js b/backend/src/resolvers/follow.js index a26ae5997..df7b58891 100644 --- a/backend/src/resolvers/follow.js +++ b/backend/src/resolvers/follow.js @@ -4,7 +4,7 @@ export default { const { id, type } = params const session = context.driver.session() - let sessionRes = await session.run( + let transactionRes = await session.run( `MATCH (node {id: $id}), (user:User {id: $userId}) WHERE $type IN labels(node) AND NOT $id = $userId MERGE (user)-[relation:FOLLOWS]->(node) @@ -16,7 +16,7 @@ export default { } ) - const [isFollowed] = sessionRes.records.map(record => { + const [isFollowed] = transactionRes.records.map(record => { return record.get('isFollowed') }) @@ -29,7 +29,7 @@ export default { const { id, type } = params const session = context.driver.session() - let sessionRes = await session.run( + let transactionRes = await session.run( `MATCH (user:User {id: $userId})-[relation:FOLLOWS]->(node {id: $id}) WHERE $type IN labels(node) DELETE relation @@ -40,7 +40,7 @@ export default { userId: context.user.id } ) - const [isFollowed] = sessionRes.records.map(record => { + const [isFollowed] = transactionRes.records.map(record => { return record.get('isFollowed') }) session.close() diff --git a/backend/src/resolvers/rewards.js b/backend/src/resolvers/rewards.js index 6bf6ddeea..a7a8c1ab7 100644 --- a/backend/src/resolvers/rewards.js +++ b/backend/src/resolvers/rewards.js @@ -4,7 +4,7 @@ export default { const { fromBadgeId, toUserId } = params const session = context.driver.session() - let sessionRes = await session.run( + let transactionRes = await session.run( `MATCH (badge:Badge {id: $badgeId}), (rewardedUser:User {id: $rewardedUserId}) MERGE (badge)-[:REWARDED]->(rewardedUser) RETURN rewardedUser {.id}`, @@ -14,7 +14,7 @@ export default { } ) - const [rewardedUser] = sessionRes.records.map(record => { + const [rewardedUser] = transactionRes.records.map(record => { return record.get('rewardedUser') }) @@ -27,7 +27,7 @@ export default { const { fromBadgeId, toUserId } = params const session = context.driver.session() - let sessionRes = await session.run( + let transactionRes = await session.run( `MATCH (badge:Badge {id: $badgeId})-[reward:REWARDED]->(rewardedUser:User {id: $rewardedUserId}) DELETE reward RETURN rewardedUser {.id}`, @@ -36,7 +36,7 @@ export default { rewardedUserId: toUserId } ) - const [rewardedUser] = sessionRes.records.map(record => { + const [rewardedUser] = transactionRes.records.map(record => { return record.get('rewardedUser') }) session.close() diff --git a/backend/src/resolvers/shout.js b/backend/src/resolvers/shout.js index f190c5d0b..69c39a3a9 100644 --- a/backend/src/resolvers/shout.js +++ b/backend/src/resolvers/shout.js @@ -4,7 +4,7 @@ export default { const { id, type } = params const session = context.driver.session() - let sessionRes = await session.run( + let transactionRes = await session.run( `MATCH (node {id: $id})<-[:WROTE]-(userWritten:User), (user:User {id: $userId}) WHERE $type IN labels(node) AND NOT userWritten.id = $userId MERGE (user)-[relation:SHOUTED]->(node) @@ -16,7 +16,7 @@ export default { } ) - const [isShouted] = sessionRes.records.map(record => { + const [isShouted] = transactionRes.records.map(record => { return record.get('isShouted') }) @@ -29,7 +29,7 @@ export default { const { id, type } = params const session = context.driver.session() - let sessionRes = await session.run( + let transactionRes = await session.run( `MATCH (user:User {id: $userId})-[relation:SHOUTED]->(node {id: $id}) WHERE $type IN labels(node) DELETE relation @@ -40,7 +40,7 @@ export default { userId: context.user.id } ) - const [isShouted] = sessionRes.records.map(record => { + const [isShouted] = transactionRes.records.map(record => { return record.get('isShouted') }) session.close()