Add button to delete a spammer in the flag modal

Add SiteSettings: delete_user_max_age, delete_all_posts_max. Add delete spammer button to admin flags UI
Moderators can delete users too
This commit is contained in:
Neil Lalonde
2013-07-26 15:40:08 -04:00
parent e076158789
commit 4fd5087f91
18 changed files with 265 additions and 37 deletions

View File

@@ -56,6 +56,16 @@ Discourse.AdminFlagsController = Ember.ArrayController.extend({
});
},
/**
Deletes a user and all posts and topics created by that user.
@method deleteSpammer
@param {Discourse.FlaggedPost} item The post to delete
**/
deleteSpammer: function(item) {
item.get('user').deleteAsSpammer(function() { window.location.reload(); });
},
/**
Are we viewing the 'old' view?

View File

@@ -264,6 +264,36 @@ Discourse.AdminUser = Discourse.User.extend({
bootbox.dialog(message, buttons, {"classes": "delete-user-modal"});
},
deleteAsSpammer: function(successCallback) {
var user = this;
var message = I18n.t('flagging.delete_confirm', {posts: user.get('post_count'), topics: user.get('topic_count'), email: user.get('email')});
var buttons = [{
"label": I18n.t("composer.cancel"),
"class": "cancel",
"link": true
}, {
"label": I18n.t("flagging.yes_delete_spammer"),
"class": "btn btn-danger",
"callback": function() {
Discourse.ajax("/admin/users/" + user.get('id') + '.json', {
type: 'DELETE',
data: {delete_posts: true, block_email: true}
}).then(function(data) {
if (data.deleted) {
bootbox.alert(I18n.t("admin.user.deleted"), function() {
if (successCallback) successCallback();
});
} else {
bootbox.alert(I18n.t("admin.user.delete_failed"));
}
}, function(jqXHR, status, error) {
bootbox.alert(I18n.t("admin.user.delete_failed"));
});
}
}];
bootbox.dialog(message, buttons, {"classes": "flagging-delete-spammer"});
},
loadDetails: function() {
var model = this;
if (model.get('loadedDetails')) { return Ember.RSVP.resolve(model); }

View File

@@ -57,6 +57,14 @@ Discourse.FlaggedPost = Discourse.Post.extend({
return !this.get('topic_visible');
}.property('topic_hidden'),
flaggedForSpam: function() {
return !_.every(this.get('post_actions'), function(action) { return action.name_key !== 'spam'; });
}.property('post_actions.@each.name_key'),
canDeleteAsSpammer: function() {
return (Discourse.User.current('staff') && this.get('flaggedForSpam') && this.get('user.can_delete_all_posts') && this.get('user.can_be_deleted'));
}.property('flaggedForSpam'),
deletePost: function() {
if (this.get('post_number') === '1') {
return Discourse.ajax('/t/' + this.topic_id, { type: 'DELETE', cache: false });

View File

@@ -22,17 +22,17 @@
</tr>
</thead>
<tbody>
{{#each flag in content}}
<tr {{bindAttr class="flag.extraClasses"}}>
{{#each flaggedPost in content}}
<tr {{bindAttr class="flaggedPost.extraClasses"}}>
<td class='user'>{{#if flag.user}}{{#linkTo 'adminUser' flag.user}}{{avatar flag.user imageSize="small"}}{{/linkTo}}{{/if}}</td>
<td class='user'>{{#if flaggedPost.user}}{{#linkTo 'adminUser' flaggedPost.user}}{{avatar flaggedPost.user imageSize="small"}}{{/linkTo}}{{/if}}</td>
<td class='excerpt'>{{#if flag.topicHidden}}<i title='{{i18n topic_statuses.invisible.help}}' class='icon icon-eye-close'></i> {{/if}}<h3><a href='{{unbound flag.url}}'>{{flag.title}}</a></h3><br>{{{flag.excerpt}}}
<td class='excerpt'>{{#if flaggedPost.topicHidden}}<i title='{{i18n topic_statuses.invisible.help}}' class='icon icon-eye-close'></i> {{/if}}<h3><a href='{{unbound flaggedPost.url}}'>{{flaggedPost.title}}</a></h3><br>{{{flaggedPost.excerpt}}}
</td>
<td class='flaggers'>
<table>
{{#each flag.flaggers}}
{{#each flaggedPost.flaggers}}
<tr>
<td>
{{#linkTo 'adminUser' this.user}}{{avatar this.user imageSize="small"}} {{/linkTo}}
@@ -50,7 +50,7 @@
</tr>
{{#each flag.messages}}
{{#each flaggedPost.messages}}
<tr>
<td></td>
<td class='message'>
@@ -64,14 +64,19 @@
<tr>
<td colspan="4" class="action">
{{#if adminActiveFlagsView}}
{{#if flag.postHidden}}
<button title='{{i18n admin.flags.disagree_unhide_title}}' class='btn' {{action disagreeFlags flag}}><i class="icon-thumbs-down"></i> {{i18n admin.flags.disagree_unhide}}</button>
<button title='{{i18n admin.flags.defer_title}}' class='btn' {{action deferFlags flag}}><i class="icon-external-link"></i> {{i18n admin.flags.defer}}</button>
{{#if flaggedPost.postHidden}}
<button title='{{i18n admin.flags.disagree_unhide_title}}' class='btn' {{action disagreeFlags flaggedPost}}><i class="icon-thumbs-down"></i> {{i18n admin.flags.disagree_unhide}}</button>
<button title='{{i18n admin.flags.defer_title}}' class='btn' {{action deferFlags flaggedPost}}><i class="icon-external-link"></i> {{i18n admin.flags.defer}}</button>
{{else}}
<button title='{{i18n admin.flags.agree_hide_title}}' class='btn' {{action agreeFlags flag}}><i class="icon-thumbs-up"></i> {{i18n admin.flags.agree_hide}}</button>
<button title='{{i18n admin.flags.disagree_title}}' class='btn' {{action disagreeFlags flag}}><i class="icon-thumbs-down"></i> {{i18n admin.flags.disagree}}</button>
<button title='{{i18n admin.flags.agree_hide_title}}' class='btn' {{action agreeFlags flaggedPost}}><i class="icon-thumbs-up"></i> {{i18n admin.flags.agree_hide}}</button>
<button title='{{i18n admin.flags.disagree_title}}' class='btn' {{action disagreeFlags flaggedPost}}><i class="icon-thumbs-down"></i> {{i18n admin.flags.disagree}}</button>
{{/if}}
<button title='{{i18n admin.flags.delete_post_title}}' class='btn' {{action deletePost flag}}><i class="icon-trash"></i> {{i18n admin.flags.delete_post}}</button>
{{#if flaggedPost.canDeleteAsSpammer}}
<button title='{{i18n admin.flags.delete_spammer_title}}' class="btn" {{action deleteSpammer flaggedPost}}><i class="icon icon-trash"></i> {{i18n flagging.delete_spammer}}</button>
{{/if}}
<button title='{{i18n admin.flags.delete_post_title}}' class='btn' {{action deletePost flaggedPost}}><i class="icon-trash"></i> {{i18n admin.flags.delete_post}}</button>
{{/if}}
</td>
</tr>

View File

@@ -63,8 +63,33 @@ Discourse.FlagController = Discourse.ObjectController.extend(Discourse.ModalFunc
}, function(errors) {
flagController.displayErrors(errors);
});
},
canDeleteSpammer: function() {
if (Discourse.User.current('staff') && this.get('selected.name_key') === 'spam') {
return this.get('userDetails.can_be_deleted') && this.get('userDetails.can_delete_all_posts');
} else {
return false;
}
}.property('selected.name_key', 'userDetails.can_be_deleted', 'userDetails.can_delete_all_posts'),
deleteSpammer: function() {
this.send('closeModal');
this.get('userDetails').deleteAsSpammer(function() { window.location.reload(); });
},
usernameChanged: function() {
this.set('userDetails', null);
this.fetchUserDetails();
}.observes('username'),
fetchUserDetails: function() {
if( Discourse.User.current('staff') && this.get('username') ) {
var flagController = this;
Discourse.AdminUser.find(this.get('username')).then(function(user){
flagController.set('userDetails', user);
});
}
}
});

View File

@@ -26,5 +26,9 @@
{{#if canTakeAction}}
<button class='btn btn-danger' {{action takeAction}} {{bindAttr disabled="submitDisabled"}}>{{i18n flagging.take_action}}</button>
{{/if}}
{{#if canDeleteSpammer}}
<button class="btn btn-danger" {{action deleteSpammer}} {{bindAttr disabled="submitDisabled"}}><i class="icon icon-trash"></i> {{i18n flagging.delete_spammer}}</button>
{{/if}}
</div>