From ce9ee0a5b0428c5f6da15639243d8e2fbb07389a Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Fri, 1 Dec 2017 15:28:09 -0300 Subject: [PATCH 1/9] Adding styles for mob devs --- .../src/tabs/stream/components/Comment.css | 22 +++++++++++++++++-- client/coral-embed-stream/style/default.css | 1 - .../client/components/SubscriberBadge.css | 1 - postcss.config.js | 8 +++---- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/client/coral-embed-stream/src/tabs/stream/components/Comment.css b/client/coral-embed-stream/src/tabs/stream/components/Comment.css index f5bead3b8..d104b4731 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Comment.css +++ b/client/coral-embed-stream/src/tabs/stream/components/Comment.css @@ -152,9 +152,27 @@ } .header { - display: flex; - align-items: center; margin: 10px 0; + flex-direction: column; + align-items: flex-start; + + > * { + margin: 3px 0; + + &:first-child { + margin-left: 0; + } + } + + @media (min-width: 480px) { + display: flex; + align-items: center; + flex-direction: row; + + > div { + margin: 0px 5px; + } + } } .content { diff --git a/client/coral-embed-stream/style/default.css b/client/coral-embed-stream/style/default.css index 63f1edf67..451b27289 100644 --- a/client/coral-embed-stream/style/default.css +++ b/client/coral-embed-stream/style/default.css @@ -190,7 +190,6 @@ body { background-color: #4C1066; color: white; display: inline-block; - margin: 0px 5px; padding: 5px 5px; border-radius: 2px; font-size: 12px; diff --git a/plugins/talk-plugin-subscriber/client/components/SubscriberBadge.css b/plugins/talk-plugin-subscriber/client/components/SubscriberBadge.css index 42edfd8ff..e6c8d9161 100644 --- a/plugins/talk-plugin-subscriber/client/components/SubscriberBadge.css +++ b/plugins/talk-plugin-subscriber/client/components/SubscriberBadge.css @@ -2,7 +2,6 @@ background-color: #616161; color: white; display: inline-block; - margin: 0px 5px; padding: 5px 5px; border-radius: 2px; font-size: 12px; diff --git a/postcss.config.js b/postcss.config.js index 79fae36cb..e76e674d2 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,7 +1,7 @@ module.exports = { plugins: [ - require('postcss-smart-import')({ /* ...options */ }), - require('precss')({ /* ...options */ }), - require('autoprefixer')({ /* ...options */ }) - ] + require('postcss-smart-import'), + require('precss'), + require('autoprefixer'), + ], }; From 67a4d63a23b231da6ae821fb23a0475e1c2277da Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Fri, 1 Dec 2017 15:31:05 -0300 Subject: [PATCH 2/9] Good margin --- .../src/tabs/stream/components/Comment.css | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/client/coral-embed-stream/src/tabs/stream/components/Comment.css b/client/coral-embed-stream/src/tabs/stream/components/Comment.css index d104b4731..d1a118c77 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Comment.css +++ b/client/coral-embed-stream/src/tabs/stream/components/Comment.css @@ -158,10 +158,6 @@ > * { margin: 3px 0; - - &:first-child { - margin-left: 0; - } } @media (min-width: 480px) { @@ -169,8 +165,8 @@ align-items: center; flex-direction: row; - > div { - margin: 0px 5px; + > * { + margin: 0 3px 0 0; } } } From 7731ec42de6511c4b2655192b1d3dc3506f413df Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Fri, 1 Dec 2017 23:43:19 -0300 Subject: [PATCH 3/9] css tag label --- client/coral-embed-stream/style/default.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/coral-embed-stream/style/default.css b/client/coral-embed-stream/style/default.css index 451b27289..154bfc868 100644 --- a/client/coral-embed-stream/style/default.css +++ b/client/coral-embed-stream/style/default.css @@ -190,10 +190,9 @@ body { background-color: #4C1066; color: white; display: inline-block; - padding: 5px 5px; border-radius: 2px; font-size: 12px; - font-weight: bold; + padding: 2px 6px; } /* Comment Action Styles */ From 6da4439b9421591375c15597f947ee4f7b7806bd Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Sat, 2 Dec 2017 00:20:59 -0300 Subject: [PATCH 4/9] Adding header container --- .../src/tabs/stream/components/Comment.css | 10 +++- .../src/tabs/stream/components/Comment.js | 60 ++++++++++--------- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/client/coral-embed-stream/src/tabs/stream/components/Comment.css b/client/coral-embed-stream/src/tabs/stream/components/Comment.css index d1a118c77..8bdeeaaa4 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Comment.css +++ b/client/coral-embed-stream/src/tabs/stream/components/Comment.css @@ -119,6 +119,8 @@ .commentInfoBar { margin-left: auto; + flex: 1; + text-align: right; } @keyframes enter { @@ -131,9 +133,6 @@ animation: enter 1000ms; } -.commentContainer { -} - .commentAvatar { max-width: 60px; } @@ -153,6 +152,11 @@ .header { margin: 10px 0; + display: flex; +} + +.headerContainer { + flex: 1; flex-direction: column; align-items: flex-start; diff --git a/client/coral-embed-stream/src/tabs/stream/components/Comment.js b/client/coral-embed-stream/src/tabs/stream/components/Comment.js index 3da59afdc..d66bebd75 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Comment.js +++ b/client/coral-embed-stream/src/tabs/stream/components/Comment.js @@ -452,39 +452,41 @@ export default class Comment extends React.Component {
- - - {isStaff(comment.tags) ? Staff : null} - - - - +
- { - (comment.editing && comment.editing.edited) - ?  ({t('comment.edited')}) - : null - } - + + {isStaff(comment.tags) ? Staff : null} + + + + + + { + (comment.editing && comment.editing.edited) + ?  ({t('comment.edited')}) + : null + } + +
Date: Mon, 4 Dec 2017 09:27:56 -0700 Subject: [PATCH 5/9] adjusted logic flow for comment flags --- graph/mutators/action.js | 107 ++++++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 30 deletions(-) diff --git a/graph/mutators/action.js b/graph/mutators/action.js index 93806ced9..1ef9014a8 100644 --- a/graph/mutators/action.js +++ b/graph/mutators/action.js @@ -1,28 +1,72 @@ -const ActionsService = require('../../services/actions'); -const UsersService = require('../../services/users'); const errors = require('../../errors'); const {CREATE_ACTION, DELETE_ACTION} = require('../../perms/constants'); +/** + * getActionItem will return the item that is associated with the given action. + * If it does not exist, it will throw an error. + * + * @param {Object} ctx the graphql context for the request + * @param {Object} action the action being performed + * @return {Promise} resolves to the referenced item + */ +const getActionItem = async (ctx, {item_id, item_type}) => { + const { + loaders: { + Comments, + Users, + }, + } = ctx; + + if (item_type === 'COMMENTS') { + const comment = await Comments.get.load(item_id); + if (!comment) { + throw errors.ErrNotFound; + } + + return comment; + } else if (item_type === 'USERS') { + const user = await Users.getByID.load(item_id); + if (!user) { + throw errors.ErrNotFound; + } + + return user; + } +}; + /** * Creates an action on a item. If the item is a user flag, sets the user's status to * pending. - * @param {Object} user the user performing the request - * @param {String} item_id id of the item to add the action to - * @param {String} item_type type of the item - * @param {String} action_type type of the action - * @return {Promise} resolves to the action created + * + * @param {Object} ctx the graphql context for the request + * @param {Object} action the action being created + * @return {Promise} resolves to the action created */ -const createAction = async ({user = {}, pubsub, loaders: {Comments}}, {item_id, item_type, action_type, group_id, metadata = {}}) => { +const createAction = async (ctx, {item_id, item_type, action_type, group_id, metadata = {}}) => { + const { + user = {}, + pubsub, + connectors: { + services: { + Actions, + }, + }, + } = ctx; - let comment; - if (item_type === 'COMMENTS') { - comment = await Comments.get.load(item_id); - if (!comment) { - throw new Error('Comment not found'); + // Gets the item referenced by the action. + const item = await getActionItem(ctx, {item_id, item_type}); + + if (action_type === 'FLAG' && item_type === 'USERS') { + + // The item is a user, and this is a flag. Check to see if they are staff, + // if they are, don't permit the flag. + if (item.isStaff()) { + throw errors.ErrNotAuthorized; } } - let action = await ActionsService.create({ + // Create the action itself. + let action = await Actions.create({ item_id, item_type, user_id: user.id, @@ -31,17 +75,11 @@ const createAction = async ({user = {}, pubsub, loaders: {Comments}}, {item_id, metadata }); - if (item_type === 'USERS' && action_type === 'FLAG') { + if (action_type === 'FLAG' && item_type === 'COMMENTS') { - // Set the user as pending if it was a user flag and user has no Admin, Staff or Moderation roles - let user = await UsersService.findById(item_id); - if(!user.isStaff()){ - await UsersService.setStatus(item_id, 'PENDING'); - } - } - - if (comment) { - pubsub.publish('commentFlagged', comment); + // The item is a comment, and this is a flag. Push that the comment was + // flagged, don't wait for it to finish. + pubsub.publish('commentFlagged', item); } return action; @@ -53,16 +91,25 @@ const createAction = async ({user = {}, pubsub, loaders: {Comments}}, {item_id, * @param {String} id the id of the action to delete * @return {Promise} resolves to the deleted action, or null if not found. */ -const deleteAction = ({user}, {id}) => { - return ActionsService.delete({id, user_id: user.id}); +const deleteAction = (ctx, {id}) => { + const { + user, + connectors: { + services: { + Actions, + }, + }, + } = ctx; + + return Actions.delete({id, user_id: user.id}); }; -module.exports = (context) => { - if (context.user && context.user.can(CREATE_ACTION, DELETE_ACTION)) { +module.exports = (ctx) => { + if (ctx.user && ctx.user.can(CREATE_ACTION, DELETE_ACTION)) { return { Action: { - create: (action) => createAction(context, action), - delete: (action) => deleteAction(context, action) + create: (action) => createAction(ctx, action), + delete: (action) => deleteAction(ctx, action) } }; } From fdf11fa2778e4d683b58d4e09702a0144de42ac1 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 4 Dec 2017 13:42:22 -0300 Subject: [PATCH 6/9] Adding extra container and styling --- .../src/tabs/stream/components/Comment.css | 18 +++++++++++------- .../src/tabs/stream/components/Comment.js | 18 ++++++++++-------- client/coral-embed-stream/style/default.css | 2 +- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/client/coral-embed-stream/src/tabs/stream/components/Comment.css b/client/coral-embed-stream/src/tabs/stream/components/Comment.css index 8bdeeaaa4..15d42bef0 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Comment.css +++ b/client/coral-embed-stream/src/tabs/stream/components/Comment.css @@ -160,18 +160,22 @@ flex-direction: column; align-items: flex-start; - > * { - margin: 3px 0; - } - @media (min-width: 480px) { display: flex; align-items: center; flex-direction: row; + } +} - > * { - margin: 0 3px 0 0; - } +.tagsContainer { + display: flex; +} + +.tagsContainer > * { + margin: 3px; + + &:first-child { + margin-left: 0px; } } diff --git a/client/coral-embed-stream/src/tabs/stream/components/Comment.js b/client/coral-embed-stream/src/tabs/stream/components/Comment.js index d66bebd75..ba14e3c7f 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Comment.js +++ b/client/coral-embed-stream/src/tabs/stream/components/Comment.js @@ -461,15 +461,17 @@ export default class Comment extends React.Component { {...slotProps} /> - {isStaff(comment.tags) ? Staff : null} +
+ {isStaff(comment.tags) ? Staff : null} - + +
Date: Mon, 4 Dec 2017 15:00:43 -0300 Subject: [PATCH 7/9] Timestamp no break --- client/coral-framework/components/CommentTimestamp.css | 1 + 1 file changed, 1 insertion(+) diff --git a/client/coral-framework/components/CommentTimestamp.css b/client/coral-framework/components/CommentTimestamp.css index a4620902c..0c54019ff 100644 --- a/client/coral-framework/components/CommentTimestamp.css +++ b/client/coral-framework/components/CommentTimestamp.css @@ -2,5 +2,6 @@ display: inline-block; color: #696969; font-size: 12px; + white-space: nowrap; } From 87ef0f1cb9d235c9db610ea5c93eacd706c3b3a4 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 4 Dec 2017 12:17:39 -0700 Subject: [PATCH 8/9] Adjusted flag beheviour for staff --- config.js | 7 +++++- docs/_docs/02-02-advanced-configuration.md | 5 ++++ graph/mutators/action.js | 17 ++++++++++---- graph/mutators/comment.js | 16 ++++++++++--- plugin-api/beta/server/getReactionConfig.js | 26 +++++++++++---------- 5 files changed, 50 insertions(+), 21 deletions(-) diff --git a/config.js b/config.js index 4601683c1..3e167b294 100644 --- a/config.js +++ b/config.js @@ -175,7 +175,12 @@ const CONFIG = { DISABLE_AUTOFLAG_SUSPECT_WORDS: process.env.TALK_DISABLE_AUTOFLAG_SUSPECT_WORDS === 'TRUE', // TRUST_THRESHOLDS defines the thresholds used for automoderation. - TRUST_THRESHOLDS: process.env.TRUST_THRESHOLDS || 'comment:2,-1;flag:2,-1' + TRUST_THRESHOLDS: process.env.TRUST_THRESHOLDS || 'comment:2,-1;flag:2,-1', + + // IGNORE_FLAGS_AGAINST_STAFF disables staff members from entering the + // reported queue from comments after this was enabled and from reports + // against the staff members user account. + IGNORE_FLAGS_AGAINST_STAFF: process.env.TALK_DISABLE_IGNORE_FLAGS_AGAINST_STAFF === 'TRUE', }; //============================================================================== diff --git a/docs/_docs/02-02-advanced-configuration.md b/docs/_docs/02-02-advanced-configuration.md index 74099258d..94a6b402d 100644 --- a/docs/_docs/02-02-advanced-configuration.md +++ b/docs/_docs/02-02-advanced-configuration.md @@ -456,3 +456,8 @@ Could be read as: added back to the queue. - At the moment of writing, behavior is not attached to the flagging reliability, but it is recorded. + +## TALK_DISABLE_IGNORE_FLAGS_AGAINST_STAFF + +When `TRUE`, staff members will have their accounts and comments moderated the +same as any other user in the system. (Default `FALSE`) \ No newline at end of file diff --git a/graph/mutators/action.js b/graph/mutators/action.js index 1ef9014a8..29a6e67af 100644 --- a/graph/mutators/action.js +++ b/graph/mutators/action.js @@ -1,5 +1,8 @@ const errors = require('../../errors'); const {CREATE_ACTION, DELETE_ACTION} = require('../../perms/constants'); +const { + IGNORE_FLAGS_AGAINST_STAFF, +} = require('../../config'); /** * getActionItem will return the item that is associated with the given action. @@ -56,12 +59,16 @@ const createAction = async (ctx, {item_id, item_type, action_type, group_id, met // Gets the item referenced by the action. const item = await getActionItem(ctx, {item_id, item_type}); - if (action_type === 'FLAG' && item_type === 'USERS') { + // If we are ignoring flags against staff, ensure that the target isn't a + // staff member. + if (IGNORE_FLAGS_AGAINST_STAFF) { + if (action_type === 'FLAG') { - // The item is a user, and this is a flag. Check to see if they are staff, - // if they are, don't permit the flag. - if (item.isStaff()) { - throw errors.ErrNotAuthorized; + // If the item is a user, and this is a flag. Check to see if they are + // staff, if they are, don't permit the flag. + if (item_type === 'USERS' && item.isStaff()) { + return null; + } } } diff --git a/graph/mutators/comment.js b/graph/mutators/comment.js index de3345257..bd8ab18fd 100644 --- a/graph/mutators/comment.js +++ b/graph/mutators/comment.js @@ -19,7 +19,8 @@ const { } = require('../../perms/constants'); const { - DISABLE_AUTOFLAG_SUSPECT_WORDS + DISABLE_AUTOFLAG_SUSPECT_WORDS, + IGNORE_FLAGS_AGAINST_STAFF, } = require('../../config'); const debug = require('debug')('talk:graph:mutators:tags'); @@ -292,7 +293,7 @@ const moderationPhases = [ } }, - // This phase checks to see if the comment's length exeeds maximum. + // This phase checks to see if the comment's length exceeds maximum. (context, comment, {assetSettings: {charCountEnable, charCount}}) => { // Reject if the comment is too long @@ -313,6 +314,15 @@ const moderationPhases = [ } }, + // If a given user is a staff member, always approve their comment. + (context) => { + if (IGNORE_FLAGS_AGAINST_STAFF && context.user && context.user.isStaff()) { + return { + status: 'ACCEPTED', + }; + } + }, + // This phase checks the comment if it has any links in it if the check is // enabled. (context, comment, {assetSettings: {premodLinksEnable}}) => { @@ -362,7 +372,7 @@ const moderationPhases = [ } }, - // This phase checks to see if the comment was already perscribed a status. + // This phase checks to see if the comment was already prescribed a status. (context, comment) => { // If the status was already defined, don't redefine it. It's only defined diff --git a/plugin-api/beta/server/getReactionConfig.js b/plugin-api/beta/server/getReactionConfig.js index 481990c16..2fffb4d1c 100644 --- a/plugin-api/beta/server/getReactionConfig.js +++ b/plugin-api/beta/server/getReactionConfig.js @@ -157,10 +157,22 @@ function getReactionConfig(reaction) { RootMutation: { [`create${Reaction}Action`]: async (_, {input: {item_id}}, {mutators: {Action}, pubsub, loaders: {Comments}}) => { const comment = await Comments.get.load(item_id); + if (!comment) { + throw errors.ErrNotFound; + } - let action; try { - action = await Action.create({item_id, item_type: 'COMMENTS', action_type: REACTION}); + const action = await Action.create({item_id, item_type: 'COMMENTS', action_type: REACTION}); + + if (pubsub) { + + // The comment is needed to allow better filtering e.g. by asset_id. + pubsub.publish(`${reaction}ActionCreated`, {action, comment}); + } + + return { + [reaction]: action, + }; } catch (err) { if (err instanceof errors.ErrAlreadyExists) { return err.metadata.existing; @@ -168,16 +180,6 @@ function getReactionConfig(reaction) { throw err; } - - if (pubsub) { - - // The comment is needed to allow better filtering e.g. by asset_id. - pubsub.publish(`${reaction}ActionCreated`, {action, comment}); - } - - return { - [reaction]: action, - }; }, [`delete${Reaction}Action`]: async (_, {input: {id}}, {mutators: {Action}, pubsub, loaders: {Comments}}) => { const action = await Action.delete({id}); From 3b4e69f06e9d84be53c08c96c09107b5646537d1 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 4 Dec 2017 14:06:32 -0700 Subject: [PATCH 9/9] fixed based on e2e finding a bug! --- graph/mutators/action.js | 15 +++++++++++---- services/users.js | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/graph/mutators/action.js b/graph/mutators/action.js index 29a6e67af..06417844b 100644 --- a/graph/mutators/action.js +++ b/graph/mutators/action.js @@ -1,4 +1,5 @@ const errors = require('../../errors'); +const UsersService = require('../../services/users'); const {CREATE_ACTION, DELETE_ACTION} = require('../../perms/constants'); const { IGNORE_FLAGS_AGAINST_STAFF, @@ -82,11 +83,17 @@ const createAction = async (ctx, {item_id, item_type, action_type, group_id, met metadata }); - if (action_type === 'FLAG' && item_type === 'COMMENTS') { + if (action_type === 'FLAG') { + if (item_type === 'USERS') { - // The item is a comment, and this is a flag. Push that the comment was - // flagged, don't wait for it to finish. - pubsub.publish('commentFlagged', item); + // Set the user's status as pending, as we need to review it. + await UsersService.setStatus(item_id, 'PENDING'); + } else if (item_type === 'COMMENTS') { + + // The item is a comment, and this is a flag. Push that the comment was + // flagged, don't wait for it to finish. + pubsub.publish('commentFlagged', item); + } } return action; diff --git a/services/users.js b/services/users.js index e0f7d1599..fbaf89609 100644 --- a/services/users.js +++ b/services/users.js @@ -395,18 +395,34 @@ module.exports = class UsersService { throw new Error(`status ${status} is not supported`); } - // TODO: current updating status behavior is weird. - // once a user has been `APPROVED` its status cannot be - // changed anymore. - const user = await UserModel.findOneAndUpdate({ - id, - status: { - $ne: 'APPROVED' - } - }, { + // Compose the query. + const query = {id}; + + // Insert extra validations into the query. + switch (status) { + case 'ACTIVE': + case 'BANNED': + case 'APPROVED': + + // A user cannot become change their status from what it is already. + query.status = { + $ne: status, + }; + break; + case 'PENDING': + + // A user cannot become pending if they are already approved, pending, or + // banned + query.status = { + $nin: [status, 'APPROVED', 'BANNED'], + }; + break; + } + + const user = await UserModel.findOneAndUpdate(query, { $set: { - status - } + status, + }, }, { new: true, }); @@ -426,8 +442,8 @@ module.exports = class UsersService { }; await MailerService.sendSimple(options); } - } + return user; }