Merge branch 'master' of github.com:coralproject/talk into plugin_examples

This commit is contained in:
Belen Curcio
2017-04-17 14:17:42 -03:00
52 changed files with 1380 additions and 272 deletions
+93 -1
View File
@@ -6,6 +6,7 @@ const {
const DataLoader = require('dataloader');
const CommentModel = require('../../models/comment');
const UsersService = require('../../services/users');
/**
* Returns the comment count for all comments that are public based on their
@@ -39,6 +40,31 @@ const getCountsByAssetID = (context, asset_ids) => {
.then((results) => results.map((result) => result ? result.count : 0));
};
/**
* Returns the count of all public comments on an asset id, also filtering by personalization options.
*
* @param {Array<String>} id The ID of the asset
* @param {Array<String>} excludeIgnored Exclude comments ignored by the requesting user
*/
const getCountsByAssetIDPersonalized = async (context, {assetId, excludeIgnored}) => {
const query = {
asset_id: assetId,
status: {
$in: ['NONE', 'ACCEPTED'],
},
};
const user = context.user;
if (excludeIgnored && user) {
// load afresh, as `user` may be from cache and not have recent ignores
const freshUser = await UsersService.findById(user.id);
const ignoredUsers = freshUser.ignoresUsers;
query.author_id = {$nin: ignoredUsers};
}
const count = await CommentModel.where(query).count();
return count;
};
/**
* Returns the comment count for all comments that are public based on their
* asset ids.
@@ -72,6 +98,32 @@ const getParentCountsByAssetID = (context, asset_ids) => {
.then((results) => results.map((result) => result ? result.count : 0));
};
/**
* Returns the count of top-level comments on an asset id, also filtering by personalization options.
*
* @param {Array<String>} id The ID of the asset
* @param {Array<String>} excludeIgnored Exclude comments ignored by the requesting user
*/
const getParentCountByAssetIDPersonalized = async (context, {assetId, excludeIgnored}) => {
const query = {
asset_id: assetId,
parent_id: null,
status: {
$in: ['NONE', 'ACCEPTED'],
},
};
const user = context.user;
if (excludeIgnored && user) {
// load afresh, as `user` may be from cache and not have recent ignores
const freshUser = await UsersService.findById(user.id);
const ignoredUsers = freshUser.ignoresUsers;
query.author_id = {$nin: ignoredUsers};
}
const count = await CommentModel.where(query).count();
return count;
};
/**
* Returns the comment count for all comments that are public based on their
* parent ids.
@@ -104,6 +156,33 @@ const getCountsByParentID = (context, parent_ids) => {
.then((results) => results.map((result) => result ? result.count : 0));
};
/**
* Returns the count of comments for the provided parent_id, also filtering by personalization options.
*
* @param {Array<String>} id The ID of the parent comment
* @param {Array<String>} excludeIgnored Exclude comments ignored by context.user
*/
const getCountByParentIDPersonalized = async (context, {id, excludeIgnored}) => {
const query = {
parent_id: {
$in: [id]
},
status: {
$in: ['NONE', 'ACCEPTED']
}
};
const user = context.user;
if (excludeIgnored && user) {
// load afresh, as `user` may be from cache and not have recent ignores
const freshUser = await UsersService.findById(user.id);
const ignoredUsers = freshUser.ignoresUsers;
query.author_id = {$nin: ignoredUsers};
}
const count = await CommentModel.where(query).count();
return count;
};
/**
* Retrieves the count of comments based on the passed in query.
* @param {Object} context graph context
@@ -142,7 +221,7 @@ const getCommentCountByQuery = (context, {ids, statuses, asset_id, parent_id}) =
* @param {Object} context graph context
* @param {Object} query query terms to apply to the comments query
*/
const getCommentsByQuery = ({user}, {ids, statuses, asset_id, parent_id, author_id, limit, cursor, sort}) => {
const getCommentsByQuery = async ({user}, {ids, statuses, asset_id, parent_id, author_id, limit, cursor, sort, excludeIgnored}) => {
let comments = CommentModel.find();
// Only administrators can search for comments with statuses that are not
@@ -184,6 +263,16 @@ const getCommentsByQuery = ({user}, {ids, statuses, asset_id, parent_id, author_
comments = comments.where({parent_id});
}
if (excludeIgnored && user) {
// load afresh, as `user` may be from cache and not have recent ignores
const freshUser = await UsersService.findById(user.id);
const ignoredUsers = freshUser.ignoresUsers;
comments = comments.where({
author_id: {$nin: ignoredUsers}
});
}
if (cursor) {
if (sort === 'REVERSE_CHRONOLOGICAL') {
comments = comments.where({
@@ -344,8 +433,11 @@ module.exports = (context) => ({
getByQuery: (query) => getCommentsByQuery(context, query),
getCountByQuery: (query) => getCommentCountByQuery(context, query),
countByAssetID: new SharedCounterDataLoader('Comments.totalCommentCount', 3600, (ids) => getCountsByAssetID(context, ids)),
countByAssetIDPersonalized: (query) => getCountsByAssetIDPersonalized(context, query),
parentCountByAssetID: new SharedCounterDataLoader('Comments.countByAssetID', 3600, (ids) => getParentCountsByAssetID(context, ids)),
parentCountByAssetIDPersonalized: (query) => getParentCountByAssetIDPersonalized(context, query),
countByParentID: new SharedCounterDataLoader('Comments.countByParentID', 3600, (ids) => getCountsByParentID(context, ids)),
countByParentIDPersonalized: (query) => getCountByParentIDPersonalized(context, query),
genRecentReplies: new DataLoader((ids) => genRecentReplies(context, ids)),
genRecentComments: new DataLoader((ids) => genRecentComments(context, ids))
}
+11 -1
View File
@@ -13,11 +13,21 @@ const suspendUser = ({user}, {id, message}) => {
});
};
const ignoreUser = async ({user}, userToIgnore) => {
return await UsersService.ignoreUsers(user.id, [userToIgnore.id]);
};
const stopIgnoringUser = async ({user}, userToStopIgnoring) => {
return await UsersService.stopIgnoringUsers(user.id, [userToStopIgnoring.id]);
};
module.exports = (context) => {
let mutators = {
User: {
setUserStatus: () => Promise.reject(errors.ErrNotAuthorized),
suspendUser: () => Promise.reject(errors.ErrNotAuthorized)
suspendUser: () => Promise.reject(errors.ErrNotAuthorized),
ignoreUser: (action) => ignoreUser(context, action),
stopIgnoringUser: (action) => stopIgnoringUser(context, action),
}
};
+11 -6
View File
@@ -9,26 +9,31 @@ const Asset = {
recentComments({id}, _, {loaders: {Comments}}) {
return Comments.genRecentComments.load(id);
},
comments({id}, {sort, limit}, {loaders: {Comments}}) {
comments({id}, {sort, limit, excludeIgnored}, {loaders: {Comments}}) {
return Comments.getByQuery({
asset_id: id,
sort,
limit,
parent_id: null
parent_id: null,
excludeIgnored,
});
},
commentCount({id, commentCount}, _, {loaders: {Comments}}) {
commentCount({id, commentCount}, {excludeIgnored}, {user, loaders: {Comments}}) {
if (user && excludeIgnored) {
return Comments.parentCountByAssetIDPersonalized({assetId: id, excludeIgnored});
}
if (commentCount != null) {
return commentCount;
}
return Comments.parentCountByAssetID.load(id);
},
totalCommentCount({id, totalCommentCount}, _, {loaders: {Comments}}) {
totalCommentCount({id, totalCommentCount}, {excludeIgnored}, {user, loaders: {Comments}}) {
if (user && excludeIgnored) {
return Comments.countByAssetIDPersonalized({assetId: id, excludeIgnored});
}
if (totalCommentCount != null) {
return totalCommentCount;
}
return Comments.countByAssetID.load(id);
},
settings({settings = null}, _, {loaders: {Settings}}) {
+8 -4
View File
@@ -12,16 +12,20 @@ const Comment = {
recentReplies({id}, _, {loaders: {Comments}}) {
return Comments.genRecentReplies.load(id);
},
replies({id, asset_id}, {sort, limit}, {loaders: {Comments}}) {
replies({id, asset_id}, {sort, limit, excludeIgnored}, {loaders: {Comments}}) {
return Comments.getByQuery({
asset_id,
parent_id: id,
sort,
limit
limit,
excludeIgnored,
});
},
replyCount({id}, _, {loaders: {Comments}}) {
return Comments.countByParentID.load(id);
replyCount({id}, {excludeIgnored}, {user, loaders: {Comments}}) {
if (user && excludeIgnored) {
return Comments.countByParentIDPersonalized({id, excludeIgnored});
}
return Comments.countByParentID.load(id);
},
actions({id}, _, {user, loaders: {Actions}}) {
+6
View File
@@ -23,6 +23,12 @@ const RootMutation = {
suspendUser(_, {id, message}, {mutators: {User}}) {
return wrapResponse(null)(User.suspendUser({id, message}));
},
ignoreUser(_, {id}, {mutators: {User}}) {
return wrapResponse(null)(User.ignoreUser({id}));
},
stopIgnoringUser(_, {id}, {mutators: {User}}) {
return wrapResponse(null)(User.stopIgnoringUser({id}));
},
setCommentStatus(_, {id, status}, {mutators: {Comment}}) {
return wrapResponse(null)(Comment.setCommentStatus({id, status}));
},
+13 -3
View File
@@ -19,15 +19,15 @@ const RootQuery = {
// This endpoint is used for loading moderation queues, so hide it in the
// event that we aren't an admin.
comments(_, {query: {action_type, statuses, asset_id, parent_id, limit, cursor, sort}}, {user, loaders: {Comments, Actions}}) {
let query = {statuses, asset_id, parent_id, limit, cursor, sort};
comments(_, {query: {action_type, statuses, asset_id, parent_id, limit, cursor, sort, excludeIgnored}}, {user, loaders: {Comments, Actions}}) {
let query = {statuses, asset_id, parent_id, limit, cursor, sort, excludeIgnored};
if (user != null && user.hasRoles('ADMIN') && action_type) {
return Actions.getByTypes({action_type, item_type: 'COMMENTS'})
.then((ids) => {
// Perform the query using the available resolver.
return Comments.getByQuery({ids, statuses, asset_id, parent_id, limit, cursor, sort});
return Comments.getByQuery({ids, statuses, asset_id, parent_id, limit, cursor, sort, excludeIgnored});
});
}
@@ -83,6 +83,16 @@ const RootQuery = {
return user;
},
myIgnoredUsers: async (_, args, {user, loaders: {Users}}) => {
// get currentUser again since context.user was out of date when running test/graph/mutations/ignoreUser
const currentUser = (await Users.getByQuery({ids: [user.id], limit: 1}))[0];
if ( ! (currentUser && Array.isArray(currentUser.ignoresUsers) && currentUser.ignoresUsers.length)) {
return [];
}
return await Users.getByQuery({ids: currentUser.ignoresUsers});
},
// This endpoint is used for loading the user moderation queues (users whose username has been flagged),
// so hide it in the event that we aren't an admin.
users(_, {query: {action_type, limit, cursor, sort}}, {user, loaders: {Users, Actions}}) {
+31 -7
View File
@@ -140,6 +140,9 @@ input CommentsQuery {
# Sort the results by created_at.
sort: SORT_ORDER = REVERSE_CHRONOLOGICAL
# Exclude comments ignored by the requesting user
excludeIgnored: Boolean
}
# CommentCountQuery allows the ability to query comment counts by specific
@@ -185,10 +188,10 @@ type Comment {
recentReplies: [Comment]
# the replies that were made to the comment.
replies(sort: SORT_ORDER = CHRONOLOGICAL, limit: Int = 3): [Comment]
replies(sort: SORT_ORDER = CHRONOLOGICAL, limit: Int = 3, excludeIgnored: Boolean): [Comment]
# The count of replies on a comment.
replyCount: Int
replyCount(excludeIgnored: Boolean): Int
# Actions completed on the parent. Requires the `ADMIN` role.
actions: [Action]
@@ -420,13 +423,13 @@ type Asset {
recentComments: [Comment]
# The top level comments that are attached to the asset.
comments(sort: SORT_ORDER = REVERSE_CHRONOLOGICAL, limit: Int = 10): [Comment]
comments(sort: SORT_ORDER = REVERSE_CHRONOLOGICAL, limit: Int = 10, excludeIgnored: Boolean): [Comment]
# The count of top level comments on the asset.
commentCount: Int
commentCount(excludeIgnored: Boolean): Int
# The total count of all comments made on the asset.
totalCommentCount: Int
totalCommentCount(excludeIgnored: Boolean): Int
# The settings (rectified with the global settings) that should be applied to
# this asset.
@@ -540,15 +543,18 @@ type RootQuery {
# role.
me: User
# Users that the currently logged in user ignores
myIgnoredUsers: [User]
# Users returned based on a query.
users(query: UsersQuery): [User]
# Asset metrics related to user actions are saturated into the assets
# returned.
# returned. Parameters `from` and `to` are related to the action created_at field.
assetMetrics(from: Date!, to: Date!, sort: ASSET_METRICS_SORT!, limit: Int = 10): [Asset!]
# Comment metrics related to user actions are saturated into the comments
# returned.
# returned. Parameters `from` and `to` are related to the action created_at field.
commentMetrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Comment!]
}
@@ -726,6 +732,18 @@ type RemoveCommentTagResponse implements Response {
errors: [UserError]
}
# Response to ignoreUser mutation
type IgnoreUserResponse implements Response {
# An array of errors relating to the mutation that occured.
errors: [UserError]
}
# Response to stopIgnoringUser mutation
type StopIgnoringUserResponse implements Response {
# An array of errors relating to the mutation that occured.
errors: [UserError]
}
# All mutations for the application are defined on this object.
type RootMutation {
@@ -758,6 +776,12 @@ type RootMutation {
# Remove tag from comment.
removeCommentTag(id: ID!, tag: String!): RemoveCommentTagResponse
# Ignore comments by another user
ignoreUser(id: ID!): IgnoreUserResponse
# Stop Ignoring comments by another user
stopIgnoringUser(id: ID!): StopIgnoringUserResponse
}
################################################################################