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:
parent
f7df68c9a3
commit
8ff4104555
18 changed files with 255 additions and 120 deletions
|
@ -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)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
|
@ -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
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
|
@ -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}}
|
||||
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -21,3 +21,13 @@
|
|||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
.penalty-post-edit {
|
||||
margin-top: 1em;
|
||||
|
||||
textarea {
|
||||
height: 10em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue