2
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2025-09-05 08:59:27 +08:00

Many enhancements to the flagging / suspending interface.

This commit is contained in:
Robin Ward 2018-01-30 16:31:29 -05:00
parent f7df68c9a3
commit 8ff4104555
18 changed files with 255 additions and 120 deletions

View file

@ -4,8 +4,6 @@ import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({
adminTools: Ember.inject.service(),
expanded: false,
suspended: false,
tagName: 'div',
classNameBindings: [
':flagged-post',
@ -21,12 +19,7 @@ export default Ember.Component.extend({
},
removeAfter(promise) {
return promise.then(() => {
this.attrs.removePost();
}).catch(error => {
if (error._discourse_displayed) { return; }
bootbox.alert(I18n.t("admin.flags.error"));
});
return promise.then(() => this.attrs.removePost());
},
_spawnModal(name, model, modalClass) {
@ -36,7 +29,7 @@ export default Ember.Component.extend({
actions: {
removeAfter(promise) {
this.removeAfter(promise);
return this.removeAfter(promise);
},
disagree() {
@ -58,18 +51,6 @@ export default Ember.Component.extend({
filter: 'post',
post_id: this.get('flaggedPost.id')
});
},
showSuspendModal() {
let post = this.get('flaggedPost');
let user = post.get('user');
this.get('adminTools').showSuspendModal(
user,
{
post,
successCallback: result => this.set('suspended', result.suspended)
}
);
}
}
});

View file

@ -0,0 +1,32 @@
import computed from 'ember-addons/ember-computed-decorators';
const ACTIONS = ['delete', 'edit', 'none'];
export default Ember.Component.extend({
postAction: null,
postEdit: null,
@computed
penaltyActions() {
return ACTIONS.map(id => {
return { id, name: I18n.t(`admin.user.penalty_post_${id}`) };
});
},
editing: Ember.computed.equal('postAction', 'edit'),
actions: {
penaltyChanged() {
let postAction = this.get('postAction');
// If we switch to edit mode, jump to the edit textarea
if (postAction === 'edit') {
Ember.run.scheduleOnce('afterRender', () => {
let $elem = this.$();
let body = $elem.closest('.modal-body');
body.scrollTop(body.height());
$elem.find('.post-editor').focus();
});
}
}
}
});

View file

@ -1,26 +1,14 @@
import ModalFunctionality from 'discourse/mixins/modal-functionality';
import computed from 'ember-addons/ember-computed-decorators';
import { popupAjaxError } from 'discourse/lib/ajax-error';
import PenaltyController from 'admin/mixins/penalty-controller';
export default Ember.Controller.extend(ModalFunctionality, {
export default Ember.Controller.extend(PenaltyController, {
silenceUntil: null,
reason: null,
message: null,
silencing: false,
user: null,
post: null,
successCallback: null,
onShow() {
this.setProperties({
silenceUntil: null,
reason: null,
message: null,
silencing: false,
loadingUser: true,
post: null,
successCallback: null,
});
this.resetModal();
this.setProperties({ silenceUntil: null, silencing: false });
},
@computed('silenceUntil', 'reason', 'silencing')
@ -33,18 +21,16 @@ export default Ember.Controller.extend(ModalFunctionality, {
if (this.get('submitDisabled')) { return; }
this.set('silencing', true);
this.get('user').silence({
silenced_till: this.get('silenceUntil'),
reason: this.get('reason'),
message: this.get('message'),
post_id: this.get('post.id')
}).then(result => {
this.send('closeModal');
let callback = this.get('successCallback');
if (callback) {
callback(result);
}
}).catch(popupAjaxError).finally(() => this.set('silencing', false));
this.penalize(() => {
return this.get('user').silence({
silenced_till: this.get('silenceUntil'),
reason: this.get('reason'),
message: this.get('message'),
post_id: this.get('post.id'),
post_action: this.get('postAction'),
post_edit: this.get('postEdit')
});
}).finally(() => this.set('silencing', false));
}
}
});

View file

@ -1,26 +1,13 @@
import ModalFunctionality from 'discourse/mixins/modal-functionality';
import computed from 'ember-addons/ember-computed-decorators';
import { popupAjaxError } from 'discourse/lib/ajax-error';
import PenaltyController from 'admin/mixins/penalty-controller';
export default Ember.Controller.extend(ModalFunctionality, {
export default Ember.Controller.extend(PenaltyController, {
suspendUntil: null,
reason: null,
message: null,
suspending: false,
user: null,
post: null,
successCallback: null,
onShow() {
this.setProperties({
suspendUntil: null,
reason: null,
message: null,
suspending: false,
loadingUser: true,
post: null,
successCallback: null,
});
this.resetModal();
this.setProperties({ suspendUntil: null, suspending: false });
},
@computed('suspendUntil', 'reason', 'suspending')
@ -33,19 +20,17 @@ export default Ember.Controller.extend(ModalFunctionality, {
if (this.get('submitDisabled')) { return; }
this.set('suspending', true);
this.get('user').suspend({
suspend_until: this.get('suspendUntil'),
reason: this.get('reason'),
message: this.get('message'),
post_id: this.get('post.id')
}).then(result => {
this.send('closeModal');
let callback = this.get('successCallback');
if (callback) {
callback(result);
}
}).catch(popupAjaxError).finally(() => this.set('suspending', false));
this.penalize(() => {
return this.get('user').suspend({
suspend_until: this.get('suspendUntil'),
reason: this.get('reason'),
message: this.get('message'),
post_id: this.get('post.id'),
post_action: this.get('postAction'),
post_edit: this.get('postEdit')
});
}).finally(() => this.set('suspending', false));
}
}
});

View file

@ -0,0 +1,41 @@
import ModalFunctionality from 'discourse/mixins/modal-functionality';
import { popupAjaxError } from 'discourse/lib/ajax-error';
export default Ember.Mixin.create(ModalFunctionality, {
reason: null,
message: null,
postEdit: null,
postAction: null,
user: null,
post: null,
successCallback: null,
resetModal() {
this.setProperties({
reason: null,
message: null,
loadingUser: true,
post: null,
postEdit: null,
postAction: 'delete',
before: null,
successCallback: null
});
},
penalize(cb) {
let before = this.get('before');
let promise = before ? before() : Ember.RSVP.resolve();
return promise
.then(() => cb())
.then(result => {
this.send('closeModal');
let callback = this.get('successCallback');
if (callback) {
callback(result);
}
})
.catch(popupAjaxError);
}
});

View file

@ -52,7 +52,10 @@ export default Ember.Service.extend({
modalClass: `${type}-user-modal`
});
if (opts.post) {
controller.set('post', opts.post);
controller.setProperties({
post: opts.post,
postEdit: opts.post.get('raw')
});
}
return (user.adminUserView ?
@ -62,6 +65,7 @@ export default Ember.Service.extend({
controller.setProperties({
user: loadedUser,
loadingUser: false,
before: opts.before,
successCallback: opts.successCallback
});
});

View file

@ -68,12 +68,6 @@
{{flag-user-lists flaggedPost=flaggedPost showResolvedBy=showResolvedBy}}
{{#if suspended}}
<div class='suspended-message'>
{{i18n "admin.flags.suspended_for_post"}}
</div>
{{/if}}
<div class='flagged-post-controls'>
{{#if canAct}}
{{admin-agree-flag-dropdown
@ -106,15 +100,6 @@
{{admin-delete-flag-dropdown
post=flaggedPost
removeAfter=(action "removeAfter")}}
{{#unless suspended}}
{{d-button
class="btn-danger suspend-user"
icon="ban"
label="admin.flags.suspend_user"
title="admin.flags.suspend_user_title"
action=(action "showSuspendModal")}}
{{/unless}}
{{/if}}
{{d-button

View file

@ -0,0 +1,16 @@
<div class='penalty-post-controls'>
<label>
<div class='penalty-post-label'>
{{{i18n 'admin.user.penalty_post_actions'}}}
</div>
</label>
{{combo-box value=postAction content=penaltyActions onSelect=(action "penaltyChanged")}}
</div>
{{#if editing}}
<div class='penalty-post-edit'>
{{textarea
value=postEdit
class="post-editor"}}
</div>
{{/if}}

View file

@ -12,6 +12,12 @@
</div>
{{silence-details reason=reason message=message}}
{{#if post}}
{{penalty-post-action
post=post
postAction=postAction
postEdit=postEdit}}
{{/if}}
{{/conditional-loading-spinner}}

View file

@ -13,6 +13,13 @@
</div>
{{suspension-details reason=reason message=message}}
{{#if post}}
{{penalty-post-action
post=post
postAction=postAction
postEdit=postEdit}}
{{/if}}
{{else}}
<div class='cant-suspend'>
{{i18n "admin.user.cant_suspend"}}

View file

@ -54,9 +54,11 @@ export function throwAjaxError(undoCallback) {
}
export function popupAjaxError(error) {
if (error && error._discourse_displayed) { return; }
bootbox.alert(extractError(error));
error._discourse_displayed = true;
// We re-throw in a catch to not swallow the exception
throw error;
}

View file

@ -55,6 +55,22 @@ export default DropdownSelectBox.extend({
label: I18n.t("admin.flags.agree_flag"),
});
content.push({
icon: 'ban',
id: 'confirm-agree-suspend',
description: I18n.t('admin.flags.agree_flag_suspend_title'),
action: () => this.send("showSuspendModal"),
label: I18n.t("admin.flags.agree_flag_suspend"),
});
content.push({
icon: 'microphone-slash',
id: 'confirm-agree-silence',
description: I18n.t('admin.flags.agree_flag_silence_title'),
action: () => this.send("showSilenceModal"),
label: I18n.t("admin.flags.agree_flag_silence"),
});
if (canDeleteSpammer) {
content.push({
title: I18n.t("admin.flags.delete_spammer_title"),
@ -79,6 +95,28 @@ export default DropdownSelectBox.extend({
this.attrs.removeAfter(spammerDetails.deleteUser());
},
showSuspendModal() {
let post = this.get('post');
let user = post.get('user');
this.get('adminTools').showSuspendModal(user, {
post,
before: () => {
return this.attrs.removeAfter(post.agreeFlags('suspended'));
}
});
},
showSilenceModal() {
let post = this.get('post');
let user = post.get('user');
this.get('adminTools').showSilenceModal(user, {
post,
before: () => {
return this.attrs.removeAfter(post.agreeFlags('silenced'));
}
});
},
perform(action) {
let flaggedPost = this.get("post");
this.attrs.removeAfter(flaggedPost.agreeFlags(action));

View file

@ -21,3 +21,13 @@
float: right;
}
}
.modal-body {
.penalty-post-edit {
margin-top: 1em;
textarea {
height: 10em;
}
}
}