import { UserInputError } from 'apollo-server' const COMMENT_MIN_LENGTH = 1 const NO_POST_ERR_MESSAGE = 'Comment cannot be created without a post!' const NO_CATEGORIES_ERR_MESSAGE = 'You cannot save a post without at least one category or more than three' const validateCreateComment = async (resolve, root, args, context, info) => { const content = args.content.replace(/<(?:.|\n)*?>/gm, '').trim() const { postId } = args if (!args.content || content.length < COMMENT_MIN_LENGTH) { throw new UserInputError(`Comment must be at least ${COMMENT_MIN_LENGTH} character long!`) } const session = context.driver.session() try { const postQueryRes = await session.run( ` MATCH (post:Post {id: $postId}) RETURN post`, { postId, }, ) const [post] = postQueryRes.records.map(record => { return record.get('post') }) if (!post) { throw new UserInputError(NO_POST_ERR_MESSAGE) } else { return resolve(root, args, context, info) } } finally { session.close() } } const validateUpdateComment = async (resolve, root, args, context, info) => { const content = args.content.replace(/<(?:.|\n)*?>/gm, '').trim() if (!args.content || content.length < COMMENT_MIN_LENGTH) { throw new UserInputError(`Comment must be at least ${COMMENT_MIN_LENGTH} character long!`) } return resolve(root, args, context, info) } const validatePost = async (resolve, root, args, context, info) => { const { categoryIds } = args if (!Array.isArray(categoryIds) || !categoryIds.length || categoryIds.length > 3) { throw new UserInputError(NO_CATEGORIES_ERR_MESSAGE) } return resolve(root, args, context, info) } const validateUpdatePost = async (resolve, root, args, context, info) => { const { categoryIds } = args if (typeof categoryIds === 'undefined') return resolve(root, args, context, info) return validatePost(resolve, root, args, context, info) } const validateReport = async (resolve, root, args, context, info) => { const { resourceId } = args const { user } = context if (resourceId === user.id) throw new Error('You cannot report yourself!') return resolve(root, args, context, info) } const validateReview = async (resolve, root, args, context, info) => { const { resourceId } = args let existingReportedResource const { user, driver } = context if (resourceId === user.id) throw new Error('You cannot review yourself!') const session = driver.session() const reportReadTxPromise = session.writeTransaction(async txc => { const validateReviewTransactionResponse = await txc.run( ` MATCH (resource {id: $resourceId}) WHERE resource:User OR resource:Post OR resource:Comment OPTIONAL MATCH (:User)-[filed:FILED]->(:Report {closed: false})-[:BELONGS_TO]->(resource) OPTIONAL MATCH (resource)<-[:WROTE]-(author:User) RETURN labels(resource)[0] AS label, author, filed `, { resourceId, submitterId: user.id, }, ) return validateReviewTransactionResponse.records.map(record => ({ label: record.get('label'), author: record.get('author'), filed: record.get('filed'), })) }) try { const txResult = await reportReadTxPromise existingReportedResource = txResult if (!existingReportedResource || !existingReportedResource.length) throw new Error(`Resource not found or is not a Post|Comment|User!`) existingReportedResource = existingReportedResource[0] if (!existingReportedResource.filed) throw new Error( `Before starting the review process, please report the ${existingReportedResource.label}!`, ) const authorId = existingReportedResource.label !== 'User' && existingReportedResource.author ? existingReportedResource.author.properties.id : null if (authorId && authorId === user.id) throw new Error(`You cannot review your own ${existingReportedResource.label}!`) } finally { session.close() } return resolve(root, args, context, info) } export default { Mutation: { CreateComment: validateCreateComment, UpdateComment: validateUpdateComment, CreatePost: validatePost, UpdatePost: validateUpdatePost, fileReport: validateReport, review: validateReview, }, }