Merge branch 'master' into events

This commit is contained in:
Wyatt Johnson
2018-01-30 11:04:42 -07:00
56 changed files with 303 additions and 138 deletions
+56 -8
View File
@@ -8,6 +8,7 @@ const util = require('./util');
const program = require('commander');
const inquirer = require('inquirer');
const { graphql } = require('graphql');
const helpers = require('../services/migration/helpers');
const { stripIndent } = require('common-tags');
const Table = require('cli-table');
@@ -28,11 +29,23 @@ const CommentModel = require('../models/comment');
const ActionModel = require('../models/action');
const USER_ROLES = require('../models/enum/user_roles');
const mongoose = require('../services/mongoose');
const databaseVerifications = require('./verifications/database');
// Register the shutdown criteria.
util.onshutdown([() => mongoose.disconnect()]);
/**
* transforms a specific action to a removal action on the target model.
*/
const actionDecrTransformer = ({ item_id, action_type, group_id }) => ({
query: { id: item_id },
update: {
$inc: {
[`action_counts.${action_type.toLowerCase()}`]: -1,
[`action_counts.${action_type.toLowerCase()}_${group_id.toLowerCase()}`]: -1,
},
},
});
/**
* Deletes a user and cleans up their associated verifications.
*/
@@ -63,8 +76,27 @@ async function deleteUser(userID) {
return util.shutdown();
}
const { transformSingleWithCursor } = helpers({
queryBatchSize: 10000,
updateBatchSize: 10000,
});
console.warn("Removing user's actions");
// Remove all actions against comments.
await transformSingleWithCursor(
ActionModel.collection.find({ user_id: user.id, item_type: 'COMMENTS' }),
actionDecrTransformer,
CommentModel
);
// Remove all actions against users.
await transformSingleWithCursor(
ActionModel.collection.find({ user_id: user.id, item_type: 'USERS' }),
actionDecrTransformer,
UserModel
);
// Remove all the user's actions.
await ActionModel.where({ user_id: user.id })
.setOptions({ multi: true })
@@ -72,18 +104,34 @@ async function deleteUser(userID) {
console.warn("Removing user's comments");
// Removes all the user's reply counts on each of the comments that they
// have commented on.
await transformSingleWithCursor(
CommentModel.collection.aggregate([
{ $match: { author_id: user.id } },
{
$group: {
_id: '$parent_id',
count: { $sum: 1 },
},
},
]),
({ _id: parent_id, count }) => ({
query: { id: parent_id },
update: {
$inc: {
reply_count: -1 * count,
},
},
}),
CommentModel
);
// Remove all the user's comments.
await CommentModel.where({ author_id: user.id })
.setOptions({ multi: true })
.remove();
console.warn('Updating the database indexes');
// Update the counts that might have changed.
for (const verification of databaseVerifications) {
await verification({ fix: true, limit: Infinity, batch: 1000 });
}
console.warn('Removing the user');
// Remove the user.
@@ -5,16 +5,11 @@
background: white;
padding: 10px 12px;
box-sizing: border-box;
vertical-align: middle;
line-height: 24px;
font-size: 17px;
height: 47px;
border-radius: 3px;
text-transform: capitalize;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09);
width: 129px;
transform: scale(.8);
margin: 0;
width: 100%;
margin: 0 0 .5em;
&:not(:disabled):hover {
box-shadow: none;
@@ -5,16 +5,11 @@
background: white;
padding: 10px 11px;
box-sizing: border-box;
vertical-align: middle;
line-height: 24px;
font-size: 17px;
height: 47px;
border-radius: 3px;
text-transform: capitalize;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09);
width: 129px;
transform: scale(.8);
margin: 0;
width: 100%;
margin: 0 0 .5em;
&:not(:disabled):hover {
color: white;
@@ -81,6 +81,8 @@
}
.sideActions {
/* IE 11 needs this... */
width: 105px;
}
.editedMarker {
+2 -2
View File
@@ -2,8 +2,8 @@ export const NEXT_STEP = 'NEXT_STEP';
export const GO_TO_STEP = 'GO_TO_STEP';
export const PREVIOUS_STEP = 'PREVIOUS_STEP';
export const ADD_ERROR = 'ADD_ERROR';
export const HAS_ERROR = 'HAS_ERROR';
export const SHOW_ERRORS = 'SHOW_ERRORS';
export const HAS_ERROR = 'HAS_ERROR';
export const SHOW_ERRORS = 'SHOW_ERRORS';
export const CLEAR_ERRORS = 'CLEAR_ERRORS';
export const INSTALL_REQUEST = 'INSTALL_REQUEST';
export const INSTALL_SUCCESS = 'INSTALL_SUCCESS';
@@ -3,7 +3,7 @@ import styles from './FlaggedUser.css';
import PropTypes from 'prop-types';
import cn from 'classnames';
import t from 'coral-framework/services/i18n';
import { username } from 'talk-plugin-flags/helpers/flagReasons';
import { username } from 'coral-framework/graphql/flagReasons';
import ApproveButton from 'coral-admin/src/components/ApproveButton';
import RejectButton from 'coral-admin/src/components/RejectButton';
import { isFlaggedUserDangling } from '../utils';
+1 -1
View File
@@ -3,7 +3,7 @@ import { Router, Route } from 'react-router';
import PropTypes from 'prop-types';
import Embed from './containers/Embed';
import { LoginContainer } from 'coral-sign-in/containers/LoginContainer';
import { LoginContainer } from './containers/LoginContainer';
const routes = (
<div>
@@ -70,3 +70,17 @@ export const removeCommentClassName = idx => ({
export const setActiveTab = tab => dispatch => {
dispatch({ type: actions.SET_ACTIVE_TAB, tab });
};
export const addCommentBoxTag = tag => ({
type: actions.ADD_COMMENT_BOX_TAG,
tag,
});
export const removeCommentBoxTag = idx => ({
type: actions.REMOVE_COMMENT_BOX_TAG,
idx,
});
export const clearCommentBoxTags = () => ({
type: actions.CLEAR_COMMENT_BOX_TAGS,
});
@@ -9,7 +9,7 @@ import AutomaticAssetClosure from '../containers/AutomaticAssetClosure';
import ExtendableTabPanel from '../containers/ExtendableTabPanel';
import { Tab, TabPane } from 'coral-ui';
import ProfileContainer from 'coral-settings/containers/ProfileContainer';
import ProfileContainer from '../tabs/profile/containers/ProfileContainer';
import Popup from 'coral-framework/components/Popup';
import IfSlotIsNotEmpty from 'coral-framework/components/IfSlotIsNotEmpty';
import cn from 'classnames';
@@ -1,3 +1,5 @@
const prefix = 'TALK_EMBED_STREAM';
export const SET_ACTIVE_REPLY_BOX = 'SET_ACTIVE_REPLY_BOX';
export const ADDTL_COMMENTS_ON_LOAD_MORE = 10;
export const VIEW_ALL_COMMENTS = 'VIEW_ALL_COMMENTS';
@@ -7,3 +9,6 @@ export const REMOVE_COMMENT_CLASSNAME = 'REMOVE_COMMENT_CLASSNAME';
export const THREADING_LEVEL = process.env.TALK_THREADING_LEVEL;
export const SET_ACTIVE_TAB = 'CORAL_STREAM_SET_ACTIVE_TAB';
export const SET_SORT = 'CORAL_STREAM_SET_SORT';
export const ADD_COMMENT_BOX_TAG = `${prefix}_COMMENT_BOX_ADD_TAG`;
export const REMOVE_COMMENT_BOX_TAG = `${prefix}_COMMENT_BOX_REMOVE_TAG`;
export const CLEAR_COMMENT_BOX_TAGS = `${prefix}_COMMENT_BOX_CLEAR_TAGS`;
@@ -93,9 +93,6 @@ export default {
name
created_at
}
assigned_by {
id
}
}
user {
id
@@ -4,12 +4,10 @@ import embed from './embed';
import config from './config';
import configure from './configure';
import stream from './stream';
import { reducer as commentBox } from '../../../talk-plugin-commentbox';
export default {
auth,
asset,
commentBox,
embed,
config,
configure,
@@ -25,6 +25,7 @@ const initialState = {
previousTab: '',
sortBy: 'CREATED_AT',
sortOrder: 'DESC',
commentBoxTags: [],
};
export default function stream(state = initialState, action) {
@@ -74,6 +75,24 @@ export default function stream(state = initialState, action) {
sortOrder: action.sortOrder ? action.sortOrder : state.sortOrder,
sortBy: action.sortBy ? action.sortBy : state.sortBy,
};
case actions.ADD_COMMENT_BOX_TAG:
return {
...state,
commentBoxTags: [...state.commentBoxTags, action.tag],
};
case actions.REMOVE_COMMENT_BOX_TAG:
return {
...state,
commentBoxTags: [
...state.commentBoxTags.slice(0, action.idx),
...state.commentBoxTags.slice(action.idx + 1),
],
};
case actions.CLEAR_COMMENT_BOX_TAGS:
return {
...state,
commentBoxTags: [],
};
default:
return state;
}
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Icon } from '../coral-ui';
import { Icon } from 'coral-ui';
import styles from './Comment.css';
import Slot from 'coral-framework/components/Slot';
import CommentTimestamp from 'coral-framework/components/CommentTimestamp';
@@ -8,7 +8,7 @@ import cn from 'classnames';
import { link } from 'coral-framework/services/pym';
import NotLoggedIn from '../components/NotLoggedIn';
import { Spinner } from 'coral-ui';
import CommentHistory from 'talk-plugin-history/CommentHistory';
import CommentHistory from '../components/CommentHistory';
// TODO: Auth logic needs refactoring.
import {
@@ -0,0 +1,17 @@
import React, { Component } from 'react';
import t from 'coral-framework/services/i18n';
import RestrictedMessageBox from 'coral-framework/components/RestrictedMessageBox';
class ChangeUsername extends Component {
render() {
return (
<RestrictedMessageBox>
<div className="talk-change-username">
<span>{t('framework.changed_name.msg')}</span>
</div>
</RestrictedMessageBox>
);
}
}
export default ChangeUsername;
@@ -1,10 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import TagLabel from 'talk-plugin-tag-label/TagLabel';
import TagLabel from './TagLabel';
import CommentTimestamp from 'coral-framework/components/CommentTimestamp';
import { ReplyBox, ReplyButton } from 'talk-plugin-replies';
import { FlagComment } from 'talk-plugin-flags';
import ReplyButton from './ReplyButton';
import ReplyBox from './ReplyBox';
import FlagComment from './FlagComment';
import { can } from 'coral-framework/services/perms';
import { TransitionGroup } from 'react-transition-group';
import cn from 'classnames';
@@ -79,6 +80,11 @@ const ActionButton = ({ children }) => {
);
};
ActionButton.propTypes = {
// id of currently opened ReplyBox. tracked in Stream.js
children: PropTypes.node,
};
// Determine whether the comment with id is in the part of the comments tree.
function containsCommentId(props, id) {
if (props.comment.id === id) {
@@ -154,6 +160,7 @@ export default class Comment extends React.Component {
static propTypes = {
// id of currently opened ReplyBox. tracked in Stream.js
children: PropTypes.node,
activeReplyBox: PropTypes.string.isRequired,
disableReply: PropTypes.bool,
setActiveReplyBox: PropTypes.func.isRequired,
@@ -172,6 +179,12 @@ export default class Comment extends React.Component {
}),
charCountEnable: PropTypes.bool.isRequired,
maxCharCount: PropTypes.number,
data: PropTypes.object,
root: PropTypes.object,
loadMore: PropTypes.func,
postDontAgree: PropTypes.func,
animateEnter: PropTypes.bool,
commentClassNames: PropTypes.array,
comment: PropTypes.shape({
depth: PropTypes.number,
action_summaries: PropTypes.array.isRequired,
@@ -4,8 +4,9 @@ import { Button } from 'coral-ui';
import cn from 'classnames';
import Slot from 'coral-framework/components/Slot';
import { name } from './CommentBox';
import styles from './styles.css';
// TODO: (kiwi) Need to adapt CSS classes post refactor to match the rest.
import { name } from '../containers/CommentBox';
import styles from './CommentForm.css';
import t from 'coral-framework/services/i18n';
@@ -1,7 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import { notifyForNewCommentStatus } from 'talk-plugin-commentbox/CommentBox';
import { CommentForm } from 'talk-plugin-commentbox/CommentForm';
import { notifyForNewCommentStatus } from '../helpers';
import { CommentForm } from './CommentForm';
import styles from './Comment.css';
import { CountdownSeconds } from './CountdownSeconds';
import { getEditableUntilDate } from './util';
@@ -43,6 +44,8 @@ export class EditableCommentContent extends React.Component {
stopEditing: PropTypes.func,
};
unmounted = false;
constructor(props) {
super(props);
this.editWindowExpiryTimeout = null;
@@ -62,6 +65,7 @@ export class EditableCommentContent extends React.Component {
}
}
componentWillUnmount() {
this.unmounted = true;
if (this.editWindowExpiryTimeout) {
this.editWindowExpiryTimeout = clearTimeout(this.editWindowExpiryTimeout);
}
@@ -86,7 +90,9 @@ export class EditableCommentContent extends React.Component {
let response;
try {
response = await editComment({ body: this.state.body });
this.setState({ loadingState: 'success' });
if (!this.unmounted) {
this.setState({ loadingState: 'success' });
}
const status = response.data.editComment.comment.status;
notifyForNewCommentStatus(this.props.notify, status);
if (typeof stopEditing === 'function') {
@@ -6,11 +6,12 @@ import { can } from 'coral-framework/services/perms';
import { PopupMenu, Button } from 'coral-ui';
import ClickOutside from 'coral-framework/components/ClickOutside';
import cn from 'classnames';
import styles from './styles.css';
import * as REASONS from '../helpers/flagReasons';
import styles from './FlagButton.css';
import * as REASONS from 'coral-framework/graphql/flagReasons';
import { getErrorMessages, forEachError } from 'coral-framework/utils';
// TODO: (kiwi) Need to adapt CSS classes post refactor to match the rest.
const name = 'talk-plugin-flags';
export default class FlagButton extends Component {
@@ -2,7 +2,7 @@ import React from 'react';
import FlagButton from './FlagButton';
import t from 'coral-framework/services/i18n';
import { username, comment } from '../helpers/flagReasons';
import { username, comment } from 'coral-framework/graphql/flagReasons';
const FlagComment = props => (
<FlagButton {...props} getPopupMenu={getPopupMenu} />
@@ -1,6 +1,7 @@
import React from 'react';
import Markdown from 'coral-framework/components/Markdown';
// TODO: (kiwi) Need to adapt CSS classes post refactor to match the rest.
const packagename = 'talk-plugin-infobox';
const InfoBox = ({ enable, content }) => (
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './styles.css';
import styles from './ModerationLink.css';
import cn from 'classnames';
import t from 'coral-framework/services/i18n';
@@ -1,7 +1,8 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import CommentBox from '../talk-plugin-commentbox/CommentBox';
import CommentBox from '../containers/CommentBox';
// TODO: (kiwi) Need to adapt CSS classes post refactor to match the rest.
const name = 'talk-plugin-replies';
class ReplyBox extends Component {
@@ -6,6 +6,7 @@ import t from 'coral-framework/services/i18n';
import cn from 'classnames';
import styles from './ReplyButton.css';
// TODO: (kiwi) Need to adapt CSS classes post refactor to match the rest.
const name = 'talk-plugin-replies';
const ReplyButton = ({ onClick }) => {
@@ -5,12 +5,12 @@ import Comment from '../containers/Comment';
import BannedAccount from '../../../components/BannedAccount';
import ChangeUsername from '../containers/ChangeUsername';
import Slot from 'coral-framework/components/Slot';
import InfoBox from 'talk-plugin-infobox/InfoBox';
import InfoBox from './InfoBox';
import { can } from 'coral-framework/services/perms';
import { ModerationLink } from 'talk-plugin-moderation';
import ModerationLink from './ModerationLink';
import RestrictedMessageBox from 'coral-framework/components/RestrictedMessageBox';
import t, { timeago } from 'coral-framework/services/i18n';
import CommentBox from 'talk-plugin-commentbox/CommentBox';
import CommentBox from '../containers/CommentBox';
import QuestionBox from '../../../components/QuestionBox';
import { isCommentActive } from 'coral-framework/utils';
import { Tab, TabCount, TabPane } from 'coral-ui';
@@ -25,6 +25,7 @@ import AllCommentsPane from './AllCommentsPane';
import ExtendableTabPanel from '../../../containers/ExtendableTabPanel';
import styles from './Stream.css';
import ChangedUsername from './ChangedUsername';
class Stream extends React.Component {
constructor(props) {
@@ -237,6 +238,7 @@ class Stream extends React.Component {
const banned = get(user, 'status.banned.status');
const suspensionUntil = get(user, 'status.suspension.until');
const rejectedUsername = get(user, 'status.username.status') === 'REJECTED';
const changedUsername = get(user, 'status.username.status') === 'CHANGED';
const temporarilySuspended =
user && suspensionUntil && new Date(suspensionUntil) > new Date();
@@ -246,6 +248,7 @@ class Stream extends React.Component {
((!banned &&
!temporarilySuspended &&
!rejectedUsername &&
!changedUsername &&
!highlightedComment) ||
keepCommentBox);
const slotProps = { data };
@@ -285,6 +288,7 @@ class Stream extends React.Component {
)}
</RestrictedMessageBox>
)}
{changedUsername && <ChangedUsername />}
{!banned && rejectedUsername && <ChangeUsername user={user} />}
{banned && <BannedAccount />}
{showCommentBox && (
@@ -1,5 +1,7 @@
import React from 'react';
// TODO: (kiwi) Need to adapt CSS classes post refactor to match the rest.
const TagLabel = ({ children }) => (
<div className="talk-plugin-tag-label">{children}</div>
);
@@ -6,32 +6,12 @@ import { can } from 'coral-framework/services/perms';
import Slot from 'coral-framework/components/Slot';
import { connect } from 'react-redux';
import { CommentForm } from './CommentForm';
import { CommentForm } from '../components/CommentForm';
import { notifyForNewCommentStatus } from '../helpers';
// TODO: (kiwi) Need to adapt CSS classes post refactor to match the rest.
export const name = 'talk-plugin-commentbox';
const notifyReasons = ['LINKS', 'TRUST'];
function shouldNotify(actions = []) {
return actions.some(
({ __typename, reason }) =>
__typename === 'FlagAction' && notifyReasons.includes(reason)
);
}
// Given a newly posted comment's status, show a notification to the user
// if needed
export const notifyForNewCommentStatus = (notify, comment, actions) => {
if (comment.status === 'REJECTED') {
notify('error', t('comment_box.comment_post_banned_word'));
} else if (
comment.status === 'PREMOD' ||
(comment.status === 'SYSTEM_WITHHELD' && shouldNotify(actions))
) {
notify('success', t('comment_box.comment_post_notif_premod'));
}
};
/**
* Container for posting a new Comment
*/
@@ -70,7 +50,7 @@ class CommentBox extends React.Component {
asset_id: assetId,
parent_id: parentId,
body: this.state.body,
...this.props.commentBox,
tags: this.props.tags,
};
// Execute preSubmit Hooks
@@ -86,7 +66,7 @@ class CommentBox extends React.Component {
// Execute postSubmit Hooks
this.state.hooks.postSubmit.forEach(hook => hook(data));
notifyForNewCommentStatus(notify, postedComment, actions);
notifyForNewCommentStatus(notify, postedComment.status, actions);
if (commentPostedHandler) {
commentPostedHandler();
@@ -202,9 +182,11 @@ CommentBox.propTypes = {
isReply: PropTypes.bool.isRequired,
canPost: PropTypes.bool,
notify: PropTypes.func.isRequired,
commentBox: PropTypes.object,
tags: PropTypes.array,
};
const mapStateToProps = ({ commentBox }) => ({ commentBox });
const mapStateToProps = state => ({
tags: state.stream.commentBoxTags,
});
export default connect(mapStateToProps, null)(CommentBox);
@@ -0,0 +1,23 @@
import t from 'coral-framework/services/i18n';
const notifyReasons = ['LINKS', 'TRUST'];
function shouldNotify(actions = []) {
return actions.some(
({ __typename, reason }) =>
__typename === 'FlagAction' && notifyReasons.includes(reason)
);
}
// Given a newly posted or edited comment's status, show a notification to the user
// if needed
export const notifyForNewCommentStatus = (notify, status, actions) => {
if (status === 'REJECTED') {
notify('error', t('comment_box.comment_post_banned_word'));
} else if (
status === 'PREMOD' ||
(status === 'SYSTEM_WITHHELD' && shouldNotify(actions))
) {
notify('success', t('comment_box.comment_post_notif_premod'));
}
};
-13
View File
@@ -1,13 +0,0 @@
export const addTag = tag => ({
type: 'ADD_TAG',
tag,
});
export const removeTag = idx => ({
type: 'REMOVE_TAG',
idx,
});
export const clearTags = () => ({
type: 'CLEAR_TAGS',
});
@@ -1,3 +0,0 @@
export const ADD_TAG = 'ADD_TAG';
export const REMOVE_TAG = 'REMOVE_TAG';
export const CLEAR_TAGS = 'CLEAR_TAGS';
-1
View File
@@ -1 +0,0 @@
export { default as reducer } from './reducer';
-27
View File
@@ -1,27 +0,0 @@
import { ADD_TAG, REMOVE_TAG, CLEAR_TAGS } from './constants';
const initialState = {
tags: [],
};
export default function commentBox(state = initialState, action) {
switch (action.type) {
case ADD_TAG:
return {
...state,
tags: [...state.tags, action.tag],
};
case REMOVE_TAG:
return {
...state,
tags: [
...state.tags.slice(0, action.idx),
...state.tags.slice(action.idx + 1),
],
};
case CLEAR_TAGS:
return initialState;
default:
return state;
}
}
-1
View File
@@ -1 +0,0 @@
export { default as FlagComment } from './components/FlagComment';
-1
View File
@@ -1 +0,0 @@
export { default as ModerationLink } from './ModerationLink';
-4
View File
@@ -1,4 +0,0 @@
import ReplyBox from './ReplyBox';
import ReplyButton from './ReplyButton';
export { ReplyBox, ReplyButton };
+3 -1
View File
@@ -65,7 +65,7 @@ en:
notify_approved: '{0} approved username {1}'
notify_rejected: '{0} rejected username {1}'
notify_flagged: '{0} reported username {1}'
notify_changed: 'user {0} changed his username to {1}'
notify_changed: 'user {0} changed their username to {1}'
community:
account_creation_date: "Account Creation Date"
active: Active
@@ -254,6 +254,8 @@ en:
error: "Usernames can contain letters numbers and _ only"
label: "New Username"
msg: "Your account is currently suspended because your username has been deemed inappropriate. To restore your account please enter a new username. Please contact us if you have any questions."
changed_name:
msg: "Your username change is under review by our moderation team."
my_comments: "My Comments"
my_profile: "My profile"
new_count: "View {0} more {1}"
+3 -1
View File
@@ -15,7 +15,9 @@ module.exports = (user, perm) => {
case types.EDIT_COMMENT:
// Anyone can do these things if they aren't suspended, banned, or blocked
// as they're editing their username.
return !['UNSET', 'REJECTED'].includes(user.status.username.status);
return !['UNSET', 'REJECTED', 'CHANGED'].includes(
user.status.username.status
);
case types.ADD_COMMENT_TAG:
case types.REMOVE_COMMENT_TAG:
+2 -1
View File
@@ -1,5 +1,6 @@
export { addTag, removeTag } from 'talk-plugin-commentbox/actions';
export {
addCommentClassName,
removeCommentClassName,
addCommentBoxTag as addTag,
removeCommentBoxTag as removeTag,
} from 'coral-embed-stream/src/actions/stream';
+1 -1
View File
@@ -1,3 +1,3 @@
export const commentBoxTagsSelector = state => state.commentBox.tags;
export const commentBoxTagsSelector = state => state.stream.commentBoxTags;
export const commentClassNamesSelector = state =>
state.stream.commentClassNames;
@@ -1,6 +1,6 @@
import React from 'react';
import t from 'coral-framework/services/i18n';
import { ReplyButton } from 'talk-plugin-replies';
import ReplyButton from 'coral-embed-stream/src/tabs/stream/components/ReplyButton';
import styles from './FakeComment.css';
import { Icon } from 'plugin-api/beta/client/components/ui';
import { CommentTimestamp } from 'plugin-api/beta/client/components';
+48 -6
View File
@@ -15,13 +15,13 @@ module.exports = {
client.end();
},
'admin logs in': client => {
'Admin logs in': client => {
const adminPage = client.page.admin();
const { testData: { admin } } = client.globals;
adminPage.navigateAndLogin(admin);
},
'admin flags users username as offensive': client => {
'Admin flags users username as offensive': client => {
const embedStream = client.page.embedStream();
const comments = embedStream.navigate().ready();
@@ -42,7 +42,7 @@ module.exports = {
.waitForElementVisible('@popUpText')
.click('@continueButton');
},
'admin goes to Reported Usernames': client => {
'Admin goes to Reported Usernames': client => {
const adminPage = client.page.admin();
const community = adminPage
@@ -54,14 +54,14 @@ module.exports = {
.waitForElementVisible('@flaggedAccountsContainer')
.waitForElementVisible('@flaggedUser');
},
'admin rejects the user flag': client => {
'Admin rejects the user flag': client => {
const community = client.page.admin().section.community;
community
.waitForElementVisible('@flaggedUserRejectButton')
.click('@flaggedUserRejectButton');
},
'admin suspends the user': client => {
'Admin suspends the user': client => {
const community = client.page.admin().section.community;
const usernameDialog = client.page.admin().section.usernameDialog;
@@ -76,7 +76,7 @@ module.exports = {
community.waitForElementNotPresent('@flaggedUser');
},
'admin logs out': client => {
'Admin logs out': client => {
client.page.admin().logout();
},
'user logs in': client => {
@@ -114,6 +114,48 @@ module.exports = {
.click('@changeUsernameSubmitButton')
.waitForElementNotPresent('@changeUsernameInput');
},
'user should not be able to comment still': client => {
const embedStream = client.page.embedStream();
const comments = embedStream.section.comments;
comments
.waitForElementNotPresent('@commentBoxTextarea')
.waitForElementNotPresent('@commentBoxPostButton');
},
'user logs out': client => {
const embedStream = client.page.embedStream();
const comments = embedStream.section.comments;
comments.logout();
},
'Admin accepts the user flag': client => {
const adminPage = client.page.admin();
const { testData: { admin } } = client.globals;
adminPage.navigateAndLogin(admin);
const community = adminPage
.navigate()
.ready()
.goToCommunity();
community
.waitForElementVisible('@flaggedAccountsContainer')
.waitForElementVisible('@flaggedUser')
.waitForElementVisible('@flaggedUserApproveButton')
.click('@flaggedUserApproveButton');
client.page.admin().logout();
},
'user logs in to check comment': client => {
const { testData: { user } } = client.globals;
const embedStream = client.page.embedStream();
embedStream
.navigate()
.ready()
.openLoginPopup(popup => popup.login(user));
},
'user should be able to comment': client => {
const embedStream = client.page.embedStream();
const comments = embedStream.section.comments;
@@ -270,6 +270,49 @@ describe('graph.mutations.createComment', () => {
});
});
describe('user with different username statuses', () => {
beforeEach(() => AssetModel.create({ id: '123' }));
[
{ status: 'UNSET', error: true },
{ status: 'SET', error: false },
{ status: 'APPROVED', error: false },
{ status: 'REJECTED', error: true },
{ status: 'CHANGED', error: true },
].forEach(({ status, error }) => {
describe(`user.status.username.status=${status}`, () => {
it(`${error ? 'can not' : 'can'} create a comment`, async () => {
const context = new Context({
user: new UserModel({ status: { username: { status } } }),
});
const { data, errors } = await graphql(schema, query, {}, context);
if (errors) {
console.error(errors);
}
expect(errors).to.be.undefined;
if (error) {
expect(data.createComment).to.have.property('errors').not.null;
expect(data.createComment).to.have.property('comment').null;
expect(data.createComment.errors).to.have.length(1);
expect(data.createComment.errors[0]).to.have.property(
'translation_key',
'NOT_AUTHORIZED'
);
} else {
if (data.createComment.errors) {
console.error(data.createComment.errors);
}
expect(data.createComment).to.have.property('errors').null;
expect(data.createComment).to.have.property('comment').not.null;
}
});
});
});
});
describe('users with different roles', () => {
beforeEach(() => AssetModel.create({ id: '123' }));