Merge branch 'master' into 142993479-tags

This commit is contained in:
Wyatt Johnson
2017-05-12 07:49:02 -06:00
45 changed files with 1776 additions and 615 deletions
+49 -11
View File
@@ -63,11 +63,11 @@ const createComment = ({user, loaders: {Comments}, pubsub}, {body, asset_id, par
/**
* Filters the comment object and outputs wordlist results.
* @param {Object} context graphql context
* @param {String} body body of a comment
* @param {String} body body of a comment
* @param {String} [asset_id] id of asset comment is posted on
* @return {Object} resolves to the wordlist results
*/
const filterNewComment = (context, {body, asset_id}) => {
const filterNewComment = ({body, asset_id}) => {
// Create a new instance of the Wordlist.
const wl = new Wordlist();
@@ -75,20 +75,19 @@ const filterNewComment = (context, {body, asset_id}) => {
// Load the wordlist and filter the comment content.
return Promise.all([
wl.load().then(() => wl.scan('body', body)),
AssetsService.rectifySettings(AssetsService.findById(asset_id))
asset_id && AssetsService.rectifySettings(AssetsService.findById(asset_id))
]);
};
/**
* This resolves a given comment's status to take into account moderator actions
* are applied.
* @param {Object} context graphql context
* @param {String} body body of the comment
* @param {String} asset_id asset for the comment
* @param {String} [asset_id] asset for the comment
* @param {Object} [wordlist={}] the results of the wordlist scan
* @return {Promise} resolves to the comment's status
*/
const resolveNewCommentStatus = (context, {asset_id, body}, wordlist = {}, settings) => {
const resolveNewCommentStatus = ({asset_id, body}, wordlist = {}, settings = {}) => {
// Decide the status based on whether or not the current asset/settings
// has pre-mod enabled or not. If the comment was rejected based on the
@@ -100,7 +99,7 @@ const resolveNewCommentStatus = (context, {asset_id, body}, wordlist = {}, setti
status = Promise.resolve('REJECTED');
} else if (settings.premodLinksEnable && linkify.test(body)) {
status = Promise.resolve('PREMOD');
} else {
} else if (asset_id) {
status = AssetsService
.rectifySettings(AssetsService.findById(asset_id).then((asset) => {
if (!asset) {
@@ -127,6 +126,8 @@ const resolveNewCommentStatus = (context, {asset_id, body}, wordlist = {}, setti
}
return moderation === 'PRE' ? 'PREMOD' : 'NONE';
});
} else {
status = 'NONE';
}
return status;
@@ -144,12 +145,12 @@ const createPublicComment = (context, commentInput) => {
// First we filter the comment contents to ensure that we note any validation
// issues.
return filterNewComment(context, commentInput)
return filterNewComment(commentInput)
// We then take the wordlist and the comment into consideration when
// considering what status to assign the new comment, and resolve the new
// status to set the comment to.
.then(([wordlist, settings]) => resolveNewCommentStatus(context, commentInput, wordlist, settings)
.then(([wordlist, settings]) => resolveNewCommentStatus(commentInput, wordlist, settings)
// Then we actually create the comment with the new status.
.then((status) => createComment(context, commentInput, status))
@@ -210,11 +211,44 @@ const setCommentStatus = ({user, loaders: {Comments}}, {id, status}) => {
});
};
/**
* Edit a Comment
* @param {String} id identifier of the comment (uuid)
* @param {Object} edit describes how to edit the comment
* @param {String} edit.body the new Comment body
*/
const editComment = async ({user, loaders: {Comments}}, {id, asset_id, edit}) => {
const {body} = edit;
const determineStatusForComment = async ({body, asset_id}) => {
const [wordlist, settings] = await filterNewComment({asset_id, body});
const status = await resolveNewCommentStatus({asset_id, body}, wordlist, settings);
return status;
};
const status = await determineStatusForComment({body, asset_id});
try {
await CommentsService.edit(id, asset_id, user.id, Object.assign({status}, edit));
} catch (error) {
switch (error.name) {
case 'CommentNotFound':
throw new errors.APIError('Comment not found', {
status: 404,
translation_key: 'NOT_FOUND',
});
case 'NotAuthorizedToEdit':
throw errors.ErrNotAuthorized;
default:
throw error;
}
}
return {status};
};
module.exports = (context) => {
let mutators = {
Comment: {
create: () => Promise.reject(errors.ErrNotAuthorized),
setCommentStatus: () => Promise.reject(errors.ErrNotAuthorized)
setCommentStatus: () => Promise.reject(errors.ErrNotAuthorized),
editComment: () => Promise.reject(errors.ErrNotAuthorized),
}
};
@@ -226,5 +260,9 @@ module.exports = (context) => {
mutators.Comment.setCommentStatus = (action) => setCommentStatus(context, action);
}
if (context.user) {
mutators.Comment.editComment = (action) => editComment(context, action);
}
return mutators;
};
+9
View File
@@ -1,4 +1,5 @@
const {decorateWithTags} = require('./util');
const CommentsService = require('../../services/comments');
const Comment = {
parent({parent_id}, _, {loaders: {Comments}}) {
@@ -47,6 +48,14 @@ const Comment = {
},
asset({asset_id}, _, {loaders: {Assets}}) {
return Assets.getByID.load(asset_id);
},
editing(comment) {
const editableUntil = CommentsService.getEditableUntilDate(comment);
const edited = comment.body_history.length > 1;
return {
edited,
editableUntil,
};
}
};
+3
View File
@@ -4,6 +4,9 @@ const RootMutation = {
createComment(_, {comment}, {mutators: {Comment}}) {
return wrapResponse('comment')(Comment.create(comment));
},
editComment(_, args, {mutators: {Comment}}) {
return wrapResponse('comment')(Comment.editComment(args));
},
createFlag(_, {flag: {item_id, item_type, reason, message}}, {mutators: {Action}}) {
return wrapResponse('flag')(Action.create({item_id, item_type, action_type: 'FLAG', group_id: reason, metadata: {message}}));
},
+28
View File
@@ -200,6 +200,11 @@ input CommentCountQuery {
tag: [String]
}
type EditInfo {
edited: Boolean!
editableUntil: Date
}
# Comment is the base representation of user interaction in Talk.
type Comment {
@@ -241,6 +246,9 @@ type Comment {
# The time when the comment was created
created_at: Date!
# describes how the comment can be edited
editing: EditInfo
}
################################################################################
@@ -776,6 +784,23 @@ type StopIgnoringUserResponse implements Response {
errors: [UserError!]
}
# Input to editComment mutation
input EditCommentInput {
# Update body of the comment
body: String!
}
type CommentInfoAfterEdit {
# New status of the edited comment
status: COMMENT_STATUS!
}
type EditCommentResponse implements Response {
comment: CommentInfoAfterEdit!
# An array of errors relating to the mutation that occured.
errors: [UserError]
}
# All mutations for the application are defined on this object.
type RootMutation {
@@ -791,6 +816,9 @@ type RootMutation {
# Delete an action based on the action id.
deleteAction(id: ID!): DeleteActionResponse
# Edit a comment
editComment(id: ID!, asset_id: ID!, edit: EditCommentInput): EditCommentResponse
# Sets User status. Requires the `ADMIN` role.
setUserStatus(id: ID!, status: USER_STATUS!): SetUserStatusResponse