diff --git a/src/graphql-schema.js b/src/graphql-schema.js index c2d96ce..e5b810a 100644 --- a/src/graphql-schema.js +++ b/src/graphql-schema.js @@ -2,6 +2,7 @@ import fs from 'fs' import path from 'path' import userManagement from './resolvers/user_management.js' import statistics from './resolvers/statistics.js' +import rewards from './resolvers/rewards.js' import reports from './resolvers/reports.js' import posts from './resolvers/posts.js' import moderation from './resolvers/moderation.js' @@ -17,6 +18,7 @@ export const resolvers = { }, Mutation: { ...userManagement.Mutation, + ...rewards.Mutation, ...reports.Mutation, ...moderation.Mutation, ...posts.Mutation diff --git a/src/middleware/permissionsMiddleware.js b/src/middleware/permissionsMiddleware.js index 89d615e..d4d2155 100644 --- a/src/middleware/permissionsMiddleware.js +++ b/src/middleware/permissionsMiddleware.js @@ -52,7 +52,6 @@ const permissions = shield({ CreatePost: isAuthenticated, UpdatePost: isAuthor, DeletePost: isAuthor, - report: isAuthenticated, CreateBadge: isAdmin, UpdateBadge: isAdmin, DeleteBadge: isAdmin, diff --git a/src/resolvers/rewards.js b/src/resolvers/rewards.js new file mode 100644 index 0000000..a03c52b --- /dev/null +++ b/src/resolvers/rewards.js @@ -0,0 +1,57 @@ +import isEmpty from 'lodash/isEmpty' + +export default { + Mutation: { + reward: async (parent, { userId, badgeId }, { driver, req, user }, resolveInfo) => { + const session = driver.session() + + let data = { + userId, + badgeId, + rewarderId: user.id, + rewardedBy: null + } + + let reward = await session.run( + 'MATCH (b:Badge {id: $badgeId})-[r:REWARDED]->(u:User {id: $userId}), (by:User {id: $rewarderId}) ' + + 'RETURN r.rewarderId, r.createdAt, by.role, by.deleted, by.name, by.disabled, by.avatar, by.id, by.slug', data + ) + if (isEmpty(reward.records)) { + reward = await session.run( + 'MATCH (u:User {id: $userId}), (b:Badge {id: $badgeId}), (by:User {id: $rewarderId}) ' + + 'MERGE (b)-[r:REWARDED {rewarderId: $rewarderId, createdAt: DateTime()}]->(u) ' + + 'RETURN r.rewarderId, r.createdAt, by.role, by.deleted, by.name, by.disabled, by.avatar, by.id, by.slug', data + ) + } + + session.close() + + const [res] = reward.records.map(record => { + return { + rewarderId: record.get('r.rewarderId'), + rewardedBy: { + role: record.get('by.role'), + deleted: record.get('by.deleted'), + name: record.get('by.name'), + disabled: record.get('by.disabled'), + avatar: record.get('by.avatar'), + id: record.get('by.id'), + slug: record.get('by.slug') + }, + createdAt: record.get('r.createdAt') + } + }) + data.rewarderId = res.rewarderId + data.rewardedBy = res.rewardedBy + data.createdAt = res.createdAt + + return { + from: { id: badgeId }, + to: { id: userId }, + rewarderId: data.rewarderId, + rewardedBy: data.rewardedBy, + createdAt: data.createdAt + } + } + } +} diff --git a/src/schema.graphql b/src/schema.graphql index 69644e2..b01416e 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -58,9 +58,9 @@ type Statistics { countShouts: Int! } -scalar Date -scalar Time -scalar DateTime +# scalar Date +# scalar Time +# scalar DateTime enum VisibilityEnum { public @@ -151,8 +151,8 @@ type User { categories: [Category]! @relation(name: "CATEGORIZED", direction: "OUT") - badges: [Badge]! @relation(name: "REWARDED", direction: "IN") - badgesCount: Int! @cypher(statement: "MATCH (this)<-[:REWARDED]-(r:Badge) RETURN COUNT(r)") + rewards: [Reward]! @cypher(statement: "MATCH (this)<-[r:REWARDED]-(:Badge) RETURN r") + rewardsCount: Int! @cypher(statement: "MATCH (this)<-[:REWARDED]-(b:Badge) RETURN COUNT(b)") } type Post { @@ -232,7 +232,7 @@ type Badge { status: BadgeStatusEnum! icon: String! - rewarded: [User]! @relation(name: "REWARDED", direction: "OUT") + rewarded: [Reward]! @cypher(statement: "MATCH (this)-[r:REWARDED]->(:User) RETURN r") } enum BadgeTypeEnum { @@ -255,11 +255,10 @@ enum FollowTypeEnum { } type Reward { - id: ID! - user: User @relation(name: "REWARDED", direction: "IN") - rewarderId: ID - createdAt: String - badge: Badge @relation(name: "REWARDED", direction: "OUT") + from: Badge @cypher(statement: "MATCH (b:Badge)-[:REWARDED]->(:User) RETURN b") + to: User @cypher(statement: "MATCH (:Badge)-[:REWARDED]->(u:User) RETURN u") + rewardedBy: User + createdAt: DateTime } type Organization { diff --git a/src/server.js b/src/server.js index 8e1cd36..d25d608 100644 --- a/src/server.js +++ b/src/server.js @@ -5,8 +5,8 @@ import express from 'express' import dotenv from 'dotenv' import mocks from './mocks' import middleware from './middleware' -import applyDirectives from './bootstrap/directives' -import applyScalars from './bootstrap/scalars' +// import applyDirectives from './bootstrap/directives' +// import applyScalars from './bootstrap/scalars' import { getDriver } from './bootstrap/neo4j' import decode from './jwt/decode' @@ -27,15 +27,18 @@ let schema = makeAugmentedSchema({ resolvers, config: { query: { - exclude: ['Statistics', 'LoggedInUser'] + exclude: ['Statistics', 'LoggedInUser', '_RewardInput'] }, mutation: { - exclude: ['Statistics', 'LoggedInUser'] + exclude: [ + 'Statistics', + 'LoggedInUser' + ] }, debug: debug } }) -schema = applyScalars(applyDirectives(schema)) +// schema = applyScalars(applyDirectives(schema)) const createServer = (options) => { const defaults = {