mirror of
https://github.com/wassname/talk.git
synced 2026-07-01 18:58:29 +08:00
Merge branch 'master' into cleanup
This commit is contained in:
+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:
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -198,7 +198,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' ||
|
||||
|
||||
@@ -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"
|
||||
|
||||
+1
-1
@@ -330,7 +330,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: 千
|
||||
|
||||
+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;
|
||||
|
||||
@@ -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