mirror of
https://github.com/wassname/talk.git
synced 2026-07-02 19:06:38 +08:00
Merge branch 'master' into notify-on-edit
This commit is contained in:
+56
-8
@@ -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.
|
||||
|
||||
+1
-3
@@ -37,7 +37,7 @@ dependencies:
|
||||
|
||||
# Install node dependencies.
|
||||
- yarn --version
|
||||
- yarn global add node-gyp nsp --force
|
||||
- yarn global add node-gyp --force
|
||||
- yarn
|
||||
|
||||
post:
|
||||
@@ -59,8 +59,6 @@ test:
|
||||
- yarn test
|
||||
# Run the end to end tests
|
||||
- yarn e2e:ci
|
||||
# Check dependancies using nsp.
|
||||
- nsp check
|
||||
|
||||
deployment:
|
||||
release:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -23,7 +23,7 @@ export default class ModerationKeysModal extends React.Component {
|
||||
'ctrl+f': 'modqueue.toggle_search',
|
||||
t: 'modqueue.next_queue',
|
||||
[`1...${this.props.queueCount}`]: 'modqueue.jump_to_queue',
|
||||
s: 'modqueue.singleview',
|
||||
z: 'modqueue.singleview',
|
||||
'?': 'modqueue.thismenu',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -86,7 +86,6 @@ export default class Configure extends Component {
|
||||
}
|
||||
|
||||
Configure.propTypes = {
|
||||
notify: PropTypes.func.isRequired,
|
||||
savePending: PropTypes.func.isRequired,
|
||||
auth: PropTypes.object.isRequired,
|
||||
data: PropTypes.object.isRequired,
|
||||
|
||||
@@ -19,7 +19,7 @@ class Moderation extends Component {
|
||||
componentWillMount() {
|
||||
const { toggleModal, singleView } = this.props;
|
||||
|
||||
key('s', () => singleView());
|
||||
key('z', () => singleView());
|
||||
key('shift+/', () => toggleModal(true));
|
||||
key('esc', () => toggleModal(false));
|
||||
key('ctrl+f', () => this.openSearch());
|
||||
@@ -113,7 +113,7 @@ class Moderation extends Component {
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
key.unbind('s');
|
||||
key.unbind('z');
|
||||
key.unbind('shift+/');
|
||||
key.unbind('esc');
|
||||
key.unbind('ctrl+f');
|
||||
|
||||
@@ -112,6 +112,10 @@ function getOlderDate(a, b) {
|
||||
function determineLatestChange(comment) {
|
||||
let lc = null;
|
||||
|
||||
comment.body_history.forEach(item => {
|
||||
lc = getOlderDate(lc, item.created_at);
|
||||
});
|
||||
|
||||
comment.status_history.forEach(item => {
|
||||
lc = getOlderDate(lc, item.created_at);
|
||||
});
|
||||
@@ -124,12 +128,16 @@ function determineLatestChange(comment) {
|
||||
}
|
||||
|
||||
function reconstructPreviousCommentState(comment) {
|
||||
const history = comment.status_history;
|
||||
const statusHistory = comment.status_history;
|
||||
const bodyHistory = comment.body_history;
|
||||
const actions = comment.actions;
|
||||
const lastChangeDate = determineLatestChange(comment);
|
||||
const previousComment = {
|
||||
...comment,
|
||||
status_history: history.filter(
|
||||
body_history: bodyHistory.filter(
|
||||
item => new Date(item.created_at) < lastChangeDate
|
||||
),
|
||||
status_history: statusHistory.filter(
|
||||
item => new Date(item.created_at) < lastChangeDate
|
||||
),
|
||||
actions: actions.filter(item => new Date(item.created_at) < lastChangeDate),
|
||||
@@ -145,6 +153,9 @@ function reconstructPreviousCommentState(comment) {
|
||||
previousComment.status_history.length - 1
|
||||
].type;
|
||||
|
||||
previousComment.body =
|
||||
previousComment.body_history[previousComment.body_history.length - 1].body;
|
||||
|
||||
return previousComment;
|
||||
}
|
||||
|
||||
@@ -383,6 +394,11 @@ export function handleIndicatorChange(root, comment, queueConfig) {
|
||||
|
||||
export const subscriptionFields = `
|
||||
status
|
||||
body
|
||||
body_history {
|
||||
body
|
||||
created_at
|
||||
}
|
||||
actions {
|
||||
__typename
|
||||
created_at
|
||||
|
||||
@@ -195,7 +195,7 @@ export default {
|
||||
{ mutationResult: { data: { createComment: { comment } } } }
|
||||
) => {
|
||||
if (
|
||||
(prev.me.role !== 'ADMIN' &&
|
||||
(!['ADMIN', 'MODERATOR'].includes(prev.me.role) &&
|
||||
prev.asset.settings.moderation === 'PRE') ||
|
||||
comment.status === 'PREMOD' ||
|
||||
comment.status === 'REJECTED' ||
|
||||
|
||||
@@ -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;
|
||||
@@ -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 && (
|
||||
|
||||
@@ -133,16 +133,18 @@ Talk also allows you to moderate a commenters recent comments from this view.
|
||||
Talk also supports a number of keyboard shortcuts that moderators can leverage
|
||||
to moderate quickly:
|
||||
|
||||
| Shortcut | Action |
|
||||
| -------- | ------------------------------- |
|
||||
| `j` | Go to the next comment |
|
||||
| `k` | Go to the previous comment |
|
||||
| `ctrl+f` | Open search |
|
||||
| `t` | Switch queues |
|
||||
| `s` | Toggle single comment edit view |
|
||||
| `?` | Open this menu |
|
||||
| `d` | Approve |
|
||||
| `f` | Reject |
|
||||
| Shortcut | Action |
|
||||
| -------- | -------------------------- |
|
||||
| `j` | Go to the next comment |
|
||||
| `k` | Go to the previous comment |
|
||||
| `ctrl+f` | Open search |
|
||||
| `t` | Switch queues |
|
||||
| `z` | Zen mode |
|
||||
| `?` | Open this menu |
|
||||
| `d` | Approve |
|
||||
| `f` | Reject |
|
||||
|
||||
Note: "Zen mode" allows a moderator to view and action only one comment at a time. Enjoy the silence!
|
||||
|
||||
### Stories
|
||||
|
||||
|
||||
@@ -453,6 +453,11 @@ type EditInfo {
|
||||
editableUntil: Date
|
||||
}
|
||||
|
||||
type CommentBodyHistory {
|
||||
body: String!
|
||||
created_at: Date!
|
||||
}
|
||||
|
||||
type CommentStatusHistory {
|
||||
type: COMMENT_STATUS!
|
||||
created_at: Date!
|
||||
@@ -471,6 +476,9 @@ type Comment {
|
||||
# The actual comment data.
|
||||
body: String!
|
||||
|
||||
# The body history of the comment.
|
||||
body_history: [CommentBodyHistory!]!
|
||||
|
||||
# the tags on the comment
|
||||
tags: [TagLink!]
|
||||
|
||||
|
||||
+1
-1
@@ -274,7 +274,7 @@ da:
|
||||
shift_key: "⇧"
|
||||
shortcuts: "Genveje"
|
||||
show_shortcuts: "Vis genveje"
|
||||
singleview: "Skift enkeltkommentar redigerings visning"
|
||||
singleview: "Zen mode"
|
||||
thismenu: "Åben denne menu"
|
||||
thousand: "k"
|
||||
try_these: "Prøv disse"
|
||||
|
||||
+3
-1
@@ -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}"
|
||||
@@ -330,7 +332,7 @@ en:
|
||||
shortcuts: "Shortcuts"
|
||||
sort: "Sort"
|
||||
show_shortcuts: "Show Shortcuts"
|
||||
singleview: "Toggle single comment edit view"
|
||||
singleview: "Zen mode"
|
||||
thismenu: "Open this menu"
|
||||
jump_to_queue: "Jump to specific queue"
|
||||
thousand: k
|
||||
|
||||
+1
-1
@@ -291,7 +291,7 @@ es:
|
||||
shortcuts: Atajos
|
||||
sort: "Ordenar"
|
||||
show_shortcuts: "Mostrar Atajos"
|
||||
singleview: "Colocar vista de edición de comentario único"
|
||||
singleview: "Modo zen"
|
||||
thismenu: "Abrir este menu"
|
||||
thousand: k
|
||||
try_these: "Intentar estos"
|
||||
|
||||
+1
-1
@@ -225,7 +225,7 @@ fr:
|
||||
shift_key: ⇧
|
||||
shortcuts: Raccourcis
|
||||
show_shortcuts: "Afficher les raccourcis"
|
||||
singleview: "Passer en mode d'édition de commentaire unique"
|
||||
singleview: "Mode zen"
|
||||
spam_ads: Spam / Publicités
|
||||
thismenu: "Ouvrir ce menu"
|
||||
thousand: k
|
||||
|
||||
+1
-1
@@ -325,7 +325,7 @@ nl_NL:
|
||||
shortcuts: "Sneltoetsen"
|
||||
sort: "Sorteer"
|
||||
show_shortcuts: "Toon sneltoetsen"
|
||||
singleview: "Schakel wijzigen enkele reactie aan of uit"
|
||||
singleview: "Zen-modus"
|
||||
thismenu: "Open dit menu"
|
||||
jump_to_queue: "Spring naar specifieke wachtrij"
|
||||
thousand: k
|
||||
|
||||
+1
-1
@@ -276,7 +276,7 @@ pt_BR:
|
||||
shift_key: "⇧"
|
||||
shortcuts: "Atalhos"
|
||||
show_shortcuts: "Ver atalhos"
|
||||
singleview: "Alternar vista de edição de comentário único"
|
||||
singleview: "Modo zen"
|
||||
spam_ads: Spam/Anuncios
|
||||
thismenu: "Abra este menu"
|
||||
thousand: k
|
||||
|
||||
+1
-1
@@ -290,7 +290,7 @@ zh_CN:
|
||||
shortcuts: "快捷键"
|
||||
sort: "排序"
|
||||
show_shortcuts: "显示快捷键"
|
||||
singleview: "展开单评论编辑视图"
|
||||
singleview: "禅宗模式"
|
||||
thismenu: "开启该菜单"
|
||||
jump_to_queue: "跳转到特定序列"
|
||||
thousand: "千"
|
||||
|
||||
+1
-1
@@ -290,7 +290,7 @@ zh_TW:
|
||||
shortcuts: "快捷鍵"
|
||||
sort: "排序"
|
||||
show_shortcuts: "顯示快捷鍵"
|
||||
singleview: "切換單個評論編輯視圖"
|
||||
singleview: "禪宗模式"
|
||||
thismenu: "打開這個菜單"
|
||||
jump_to_queue: "跳轉到特定隊列"
|
||||
thousand: 千
|
||||
|
||||
@@ -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:
|
||||
|
||||
+8
-46
@@ -19,6 +19,7 @@ module.exports = class CommentsService {
|
||||
static async publicCreate(input) {
|
||||
// Extract the parent_id from the comment, if there is one.
|
||||
const { status = 'NONE', parent_id = null } = input;
|
||||
const created_at = new Date();
|
||||
|
||||
// Check to see if we are replying to a comment, and if that comment is
|
||||
// visible.
|
||||
@@ -37,14 +38,14 @@ module.exports = class CommentsService {
|
||||
? [
|
||||
{
|
||||
type: status,
|
||||
created_at: new Date(),
|
||||
created_at,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
body_history: [
|
||||
{
|
||||
body: input.body,
|
||||
created_at: new Date(),
|
||||
created_at,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -85,6 +86,7 @@ module.exports = class CommentsService {
|
||||
*/
|
||||
static async edit({ id, author_id, body, status }) {
|
||||
const EDITABLE_STATUSES = ['NONE', 'PREMOD', 'ACCEPTED'];
|
||||
const created_at = new Date();
|
||||
|
||||
const query = {
|
||||
id,
|
||||
@@ -112,11 +114,11 @@ module.exports = class CommentsService {
|
||||
$push: {
|
||||
body_history: {
|
||||
body,
|
||||
created_at: new Date(),
|
||||
created_at,
|
||||
},
|
||||
status_history: {
|
||||
type: status,
|
||||
created_at: new Date(),
|
||||
created_at,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -160,53 +162,13 @@ module.exports = class CommentsService {
|
||||
editedComment.body = body;
|
||||
editedComment.body_history.push({
|
||||
body,
|
||||
created_at: new Date(),
|
||||
created_at,
|
||||
});
|
||||
editedComment.status_history.push({
|
||||
type: status,
|
||||
created_at: new Date(),
|
||||
created_at,
|
||||
});
|
||||
|
||||
// We should adjust the comment's status such that if it was approved
|
||||
// previously, we should mark the comment as 'NONE' or 'PREMOD', which ever
|
||||
// was most recent if the new comment is destined to be `NONE` or `PREMOD`.
|
||||
if (originalComment.status === 'ACCEPTED' && status === 'NONE') {
|
||||
const lastUnmoderatedStatus = CommentsService.lastUnmoderatedStatus(
|
||||
originalComment
|
||||
);
|
||||
|
||||
// If the last moderated status was found and the current comment doesn't
|
||||
// match this already.
|
||||
if (lastUnmoderatedStatus && status !== lastUnmoderatedStatus) {
|
||||
// Update the comment model (if at this point, the status is still
|
||||
// accepted) with the previously unmoderated status
|
||||
await CommentModel.update(
|
||||
{
|
||||
id,
|
||||
status,
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
status: lastUnmoderatedStatus,
|
||||
},
|
||||
$push: {
|
||||
status_history: {
|
||||
type: lastUnmoderatedStatus,
|
||||
created_at: new Date(),
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Update the returned comment.
|
||||
editedComment.status = lastUnmoderatedStatus;
|
||||
editedComment.status_history.push({
|
||||
type: lastUnmoderatedStatus,
|
||||
created_at: new Date(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await events.emitAsync(COMMENTS_EDIT, originalComment, editedComment);
|
||||
|
||||
return editedComment;
|
||||
|
||||
@@ -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' }));
|
||||
|
||||
|
||||
@@ -227,12 +227,12 @@ describe('services.CommentsService', () => {
|
||||
id: originalComment.id,
|
||||
author_id: '123',
|
||||
body: 'This is a body!',
|
||||
status: 'NONE',
|
||||
status: 'PREMOD',
|
||||
});
|
||||
|
||||
expect(editedComment).to.have.property('status', 'PREMOD');
|
||||
expect(editedComment.status_history).to.have.length(4);
|
||||
expect(editedComment.status_history[3]).to.have.property(
|
||||
expect(editedComment.status_history).to.have.length(3);
|
||||
expect(editedComment.status_history[2]).to.have.property(
|
||||
'type',
|
||||
'PREMOD'
|
||||
);
|
||||
@@ -240,8 +240,8 @@ describe('services.CommentsService', () => {
|
||||
retrivedComment = await CommentsService.findById(originalComment.id);
|
||||
|
||||
expect(retrivedComment).to.have.property('status', 'PREMOD');
|
||||
expect(retrivedComment.status_history).to.have.length(4);
|
||||
expect(retrivedComment.status_history[3]).to.have.property(
|
||||
expect(retrivedComment.status_history).to.have.length(3);
|
||||
expect(retrivedComment.status_history[2]).to.have.property(
|
||||
'type',
|
||||
'PREMOD'
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user