Prepare backend for next implementation step

This commit is contained in:
Wolfgang Huß 2019-10-30 13:51:00 +01:00
parent 8db667c1eb
commit 7b3224327e
5 changed files with 183 additions and 55 deletions

View File

@ -82,6 +82,31 @@ const validateReport = async (resolve, root, args, context, info) => {
return resolve(root, args, context, info)
}
// const validateDecide = async (resolve, root, args, context, info) => {
// const { resourceId } = args
// const { user, driver } = context
// if (resourceId === user.id) throw new Error('You cannot report yourself!')
// const session = driver.session()
// const reportQueryRes = await session.run(
// `
// MATCH (:User {id:$submitterId})-[:REPORTED]->(resource {id:$resourceId})
// RETURN labels(resource)[0] as label
// `,
// {
// resourceId,
// submitterId: user.id,
// },
// )
// const [existingReportedResource] = reportQueryRes.records.map(record => {
// return {
// label: record.get('label'),
// }
// })
// if (existingReportedResource) throw new Error(`${existingReportedResource.label}`)
// return resolve(root, args, context, info)
// }
export default {
Mutation: {
CreateComment: validateCommentCreation,
@ -89,5 +114,6 @@ export default {
CreatePost: validatePost,
UpdatePost: validateUpdatePost,
report: validateReport,
// decide: validateDecide,
},
}

View File

@ -24,6 +24,7 @@ export default applyScalars(
'SocialMedia',
'NOTIFIED',
'REPORTED',
'DECIDED',
],
// add 'User' here as soon as possible
},
@ -44,6 +45,7 @@ export default applyScalars(
'EMOTED',
'NOTIFIED',
'REPORTED',
'DECIDED',
],
// add 'User' here as soon as possible
},

View File

@ -8,16 +8,17 @@ export default {
MATCH (resource {id: $resourceId})
WHERE resource:User OR resource:Comment OR resource:Post
SET resource.disabled = true
MERGE (resource)<-[decided:DECIDED]-(u)
MERGE (resource)<-[decision:DECIDED]-(u)
SET (
CASE
WHEN decided.createdAt IS NOT NULL
THEN decided END).updatedAt = toString(datetime())
WHEN decision.createdAt IS NOT NULL
THEN decision END).updatedAt = toString(datetime())
SET (
CASE
WHEN decided.createdAt IS NULL
THEN decided END).createdAt = toString(datetime())
SET decided.disabled = true
WHEN decision.createdAt IS NULL
THEN decision END).createdAt = toString(datetime())
SET decision.disabled = true
SET decision.closed = false
RETURN resource {.id}
`
const session = driver.session()
@ -32,14 +33,14 @@ export default {
enable: async (object, params, { user, driver }) => {
const { id: resourceId } = params
const cypher = `
MATCH (resource {id: $resourceId})<-[decided:DECIDED]-(:User)
MATCH (resource {id: $resourceId})<-[decision:DECIDED]-(:User)
SET resource.disabled = false
DELETE decided
DELETE decision
RETURN resource {.id}
`
// Wolle
// SET decided.updatedAt = toString(datetime())
// SET decided.disabled = false
// SET decision.updatedAt = toString(datetime())
// SET decision.disabled = false
const session = driver.session()
const res = await session.run(cypher, { resourceId })
session.close()
@ -49,50 +50,125 @@ export default {
if (!resource) return null
return resource.id
},
decide: async (object, params, { user, driver }) => {
const { resourceId, disabled } = params
const { id: userId } = user
// is there an open decision then set params
const cypher = `
MATCH (u:User {id: $userId})-[decision:DECIDED {closed: false}]->(resource {id: $resourceId})
WHERE NOT decision AND (resource: User OR resource: Comment OR resource: Post)
RETURN decision
`
const session = driver.session()
const res = await session.run(cypher, { resourceId, userId })
session.close()
const [decision] = res.records.map(record => {
return record.get('decision')
})
if (!resource) return null
// is there no open decision then create one
decide: async (object, params, context, _resolveInfo) => {
let createdRelationshipWithNestedAttributes = null
const { resourceId, disabled, closed } = params
const { user: moderator, driver } = context
const cypher = `
MATCH (u:User {id: $userId})
MATCH (resource {id: $resourceId})
WHERE resource:User OR resource:Comment OR resource:Post
SET resource.disabled = true
MERGE (resource)<-[decided:DECIDED]-(u)
SET (
CASE
WHEN decided.createdAt IS NOT NULL
THEN decided END).updatedAt = toString(datetime())
SET (
CASE
WHEN decided.createdAt IS NULL
THEN decided END).createdAt = toString(datetime())
SET decided.disabled = true
RETURN resource {.id}
`
const session = driver.session()
const res = await session.run(cypher, { resourceId, userId })
session.close()
const [resource] = res.records.map(record => {
return record.get('resource')
const existingDecisionWriteTxResultPromise = session.writeTransaction(async txc => {
const decisionRelationshipTransactionResponse = await txc.run(
`
MATCH (moderator:User)-[decision:DECIDED {closed: false}]->(resource {id: $resourceId})
WHERE resource:User OR resource:Comment OR resource:Post
RETURN decision, moderator {.id} AS decisionModerator
`, { resourceId },
)
return decisionRelationshipTransactionResponse.records.map(record => ({
decision: record.get('decision'),
decisionModerator: record.get('decisionModerator'),
}))
})
if (!resource) return null
return resource.id
try {
const cypherHeader = ''
// is there an open decision?
const existingDecisionTxResult = await existingDecisionWriteTxResultPromise
if (!existingDecisionTxResult[0]) {
// no open decision, then create one
if (!disabled) disabled = false // default for creation
if (!disabled) closed = false // default for creation
cypherHeader = `
MATCH (moderator:User {id: $moderatorId})
MATCH (resource {id: $resourceId})
WHERE resource:User OR resource:Comment OR resource:Post
CREATE (resource)<-[decision:DECIDED]-(moderator)
`
} else {
// an open decision …
if (!disabled) disabled = existingDecisionTxResult[0].decision.properties.disabled // default set to existing
if (!disabled) closed = existingDecisionTxResult[0].decision.properties.closed // default set to existing
// current moderator is not the same as old
if (moderator.id !== existingDecisionTxResult[0].decisionModerator.id) {
// an open decision from different moderator, then change relation and properties
cypherHeader = `
MATCH (moderator:User)-[oldDecision:DECIDED {closed: false}]->(resource {id: $resourceId})
WHERE resource:User OR resource:Comment OR resource:Post
DELETE oldDecision
MATCH (moderator:User {id: $moderatorId})
MATCH (resource {id: $resourceId})
WHERE resource:User OR resource:Comment OR resource:Post
CREATE (resource)<-[decision:DECIDED]-(moderator)
SET decision = oldDecision
`
} else {
// an open decision from same moderator, then change properties
cypherHeader = `
MATCH (moderator:User)-[decision:DECIDED {closed: false}]->(resource {id: $resourceId})
WHERE resource:User OR resource:Comment OR resource:Post
`
}
}
const newDecisionWriteTxResultPromise = session.writeTransaction(async txc => {
const decisionRelationshipTransactionResponse = await txc.run(
cypherHeader + `
SET (
CASE
WHEN decision.createdAt IS NOT NULL
THEN decision END).updatedAt = toString(datetime())
SET (
CASE
WHEN decision.createdAt IS NULL
THEN decision END).createdAt = toString(datetime())
SET decision.disabled = $disabled
SET decision.closed = $closed
SET resource.disabled = $disabled
RETURN decision, resource, moderator, labels(resource)[0] AS type
`, {
resourceId,
moderatorId: moderator.id,
disabled,
closed,
},
)
return decisionRelationshipTransactionResponse.records.map(record => ({
decision: record.get('decision'),
resource: record.get('resource'),
moderator: record.get('moderator'),
type: record.get('type'),
}))
})
const txResult = await newDecisionWriteTxResultPromise
if (!txResult[0]) return null
const { decision, resource, moderator: moderatorInResult, type } = txResult[0]
createdRelationshipWithNestedAttributes = {
...decision.properties,
moderator: moderatorInResult.properties,
type,
post: null,
comment: null,
user: null,
}
switch (type) {
case 'Post':
createdRelationshipWithNestedAttributes.post = resource.properties
break
case 'Comment':
createdRelationshipWithNestedAttributes.comment = resource.properties
break
case 'User':
createdRelationshipWithNestedAttributes.user = resource.properties
break
}
} finally {
session.close()
}
return createdRelationshipWithNestedAttributes
},
},
}

View File

@ -0,0 +1,23 @@
type DECIDED {
createdAt: String!
updatedAt: String
# reasonCategory: ReasonCategory
# reasonDescription: String
disabled: Boolean!
closed: Boolean!
moderator: User
@cypher(statement: "MATCH (resource)<-[:DECIDED]-(moderator:User) RETURN moderator")
# not yet supported
# resource: ReportResource
# @cypher(statement: "MATCH (resource)<-[:DECIDED]-(:User) RETURN resource")
type: String
@cypher(statement: "MATCH (resource)<-[:DECIDED]-(:User) RETURN labels(resource)[0]")
user: User
post: Post
comment: Comment
}
type Mutation {
decide(resourceId: ID!, disabled: Boolean, closed: Boolean): DECIDED
}

View File

@ -18,8 +18,9 @@ done
echo "
MATCH (moderator:User)-[disabled:DISABLED]->(resource)
DELETE disabled
CREATE (moderator)-[decided:DECIDED]->(resource)
SET decided.createdAt = toString(datetime())
SET decided.disabled = true
RETURN decided;
CREATE (moderator)-[decision:DECIDED]->(resource)
SET decision.createdAt = toString(datetime())
SET decision.disabled = true
SET decision.closed = false
RETURN decision;
" | cypher-shell