diff --git a/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6
index 43b14f4dbb1..8534d64b4fc 100644
--- a/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6
+++ b/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6
@@ -2,18 +2,20 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality';
export default Ember.Controller.extend(ModalFunctionality, {
removeAfter: null,
-
- _agreeFlag(action) {
- let flaggedPost = this.get('model');
- return this.removeAfter(flaggedPost.agreeFlags(action)).then(() => {
- this.send('closeModal');
- });
- },
+ deleteSpammer: null,
actions: {
- agreeFlagHidePost() { return this._agreeFlag("hide"); },
- agreeFlagKeepPost() { return this._agreeFlag("keep"); },
- agreeFlagRestorePost() { return this._agreeFlag("restore"); }
- }
+ agreeDeleteSpammer(user) {
+ return this.removeAfter(user.deleteAsSpammer()).then(() => {
+ this.send('closeModal');
+ });
+ },
+ perform(action) {
+ let flaggedPost = this.get('model');
+ return this.removeAfter(flaggedPost.agreeFlags(action)).then(() => {
+ this.send('closeModal');
+ });
+ },
+ }
});
diff --git a/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6
index be9f74d0eff..f972465ae97 100644
--- a/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6
+++ b/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6
@@ -4,6 +4,12 @@ export default Ember.Controller.extend(ModalFunctionality, {
removeAfter: null,
actions: {
+ deleteSpammer(user) {
+ return this.removeAfter(user.deleteAsSpammer()).then(() => {
+ this.send('closeModal');
+ });
+ },
+
deletePostDeferFlag() {
let flaggedPost = this.get('model');
this.removeAfter(flaggedPost.deferFlags(true)).then(() => {
diff --git a/app/assets/javascripts/admin/models/admin-user.js.es6 b/app/assets/javascripts/admin/models/admin-user.js.es6
index 662f0b046ca..18431757280 100644
--- a/app/assets/javascripts/admin/models/admin-user.js.es6
+++ b/app/assets/javascripts/admin/models/admin-user.js.es6
@@ -463,49 +463,56 @@ const AdminUser = Discourse.User.extend({
bootbox.dialog(message, buttons, { "classes": "delete-user-modal" });
},
- deleteAsSpammer(successCallback) {
- const user = this;
+ deleteAsSpammer() {
+ return this.checkEmail().then(() => {
- user.checkEmail().then(function() {
- const data = {
- "POSTS": user.get('post_count'),
- "TOPICS": user.get('topic_count'),
- email: user.get('email') || I18n.t("flagging.hidden_email_address"),
- ip_address: user.get('ip_address') || I18n.t("flagging.ip_address_missing")
- };
+ let message = I18n.messageFormat('flagging.delete_confirm_MF', {
+ "POSTS": this.get('post_count'),
+ "TOPICS": this.get('topic_count'),
+ email: this.get('email') || I18n.t("flagging.hidden_email_address"),
+ ip_address: this.get('ip_address') || I18n.t("flagging.ip_address_missing")
+ });
- const message = I18n.messageFormat('flagging.delete_confirm_MF', data),
- buttons = [{
- "label": I18n.t("composer.cancel"),
- "class": "cancel-inline",
- "link": true
- }, {
- "label": `${iconHTML('exclamation-triangle')} ` + I18n.t("flagging.yes_delete_spammer"),
- "class": "btn btn-danger",
- "callback": function() {
- return ajax("/admin/users/" + user.get('id') + '.json', {
- type: 'DELETE',
- data: {
- delete_posts: true,
- block_email: true,
- block_urls: true,
- block_ip: true,
- delete_as_spammer: true,
- context: window.location.pathname
+ let userId = this.get('id');
+
+ return new Ember.RSVP.Promise((resolve, reject) => {
+ const buttons = [
+ {
+ label: I18n.t("composer.cancel"),
+ class: "cancel-inline",
+ link: true
+ },
+ {
+ label: `${iconHTML('exclamation-triangle')} ` + I18n.t("flagging.yes_delete_spammer"),
+ class: "btn btn-danger confirm-delete",
+ callback() {
+ return ajax(`/admin/users/${userId}.json`, {
+ type: 'DELETE',
+ data: {
+ delete_posts: true,
+ block_email: true,
+ block_urls: true,
+ block_ip: true,
+ delete_as_spammer: true,
+ context: window.location.pathname
+ }
+ }).then(result => {
+ if (result.deleted) {
+ resolve();
+ } else {
+ throw 'failed to delete';
+ }
+ }).catch(() => {
+ bootbox.alert(I18n.t("admin.user.delete_failed"));
+ reject();
+ });
}
- }).then(function(result) {
- if (result.deleted) {
- if (successCallback) successCallback();
- } else {
- bootbox.alert(I18n.t("admin.user.delete_failed"));
- }
- }).catch(function() {
- bootbox.alert(I18n.t("admin.user.delete_failed"));
- });
- }
- }];
+ }
+ ];
+
+ bootbox.dialog(message, buttons, {classes: "flagging-delete-spammer"});
+ });
- bootbox.dialog(message, buttons, {"classes": "flagging-delete-spammer"});
});
},
diff --git a/app/assets/javascripts/admin/models/flagged-post.js.es6 b/app/assets/javascripts/admin/models/flagged-post.js.es6
index 4f1cc61d106..b2198e75ca4 100644
--- a/app/assets/javascripts/admin/models/flagged-post.js.es6
+++ b/app/assets/javascripts/admin/models/flagged-post.js.es6
@@ -92,7 +92,7 @@ const FlaggedPost = Post.extend({
@computed('post_actions.@each.name_key')
flaggedForSpam() {
- return !_.every(this.get('post_actions'), function(action) { return action.name_key !== 'spam'; });
+ return this.get('post_actions').every(action => action.name_key === 'spam');
},
@computed('post_actions.@each.targets_topic')
@@ -105,9 +105,11 @@ const FlaggedPost = Post.extend({
return _.any(this.get('post_actions'), function(action) { return !action.targets_topic; });
},
- @computed('flaggedForSpan')
+ @computed('flaggedForSpam')
canDeleteAsSpammer(flaggedForSpam) {
- return Discourse.User.currentProp('staff') && flaggedForSpam && this.get('user.can_delete_all_posts') && this.get('user.can_be_deleted');
+ return flaggedForSpam &&
+ this.get('user.can_delete_all_posts') &&
+ this.get('user.can_be_deleted');
},
deletePost() {
diff --git a/app/assets/javascripts/admin/templates/components/flagged-post.hbs b/app/assets/javascripts/admin/templates/components/flagged-post.hbs
index dd420a24f92..69a9a302c82 100644
--- a/app/assets/javascripts/admin/templates/components/flagged-post.hbs
+++ b/app/assets/javascripts/admin/templates/components/flagged-post.hbs
@@ -47,7 +47,7 @@
{{#each flaggedPost.flaggers as |flagger|}}
- {{#link-to 'adminUser' flagger.user}}
+ {{#link-to 'adminUser' flagger.user class='flagger'}}
{{avatar flagger.user imageSize="medium"}}
{{/link-to}}
|
@@ -135,6 +135,7 @@
{{d-button
title="admin.flags.agree_title"
+ class="agree-flag"
label="admin.flags.agree"
icon="thumbs-o-up"
action="showAgreeFlagModal"
@@ -143,25 +144,28 @@
{{#if flaggedPost.postHidden}}
{{d-button
title="admin.flags.disagree_flag_unhide_post_title"
+ class="disagree-flag"
action="disagree"
icon="thumbs-o-down"
label="admin.flags.disagree_flag_unhide_post"}}
{{else}}
{{d-button
title="admin.flags.disagree_flag_title"
+ class="disagree-flag"
action="disagree"
icon="thumbs-o-down"
label="admin.flags.disagree_flag"}}
{{/if}}
{{d-button
+ class="defer-flag"
title="admin.flags.defer_flag_title"
action="defer"
icon="external-link"
label="admin.flags.defer_flag"}}
{{d-button
- class="btn-danger"
+ class="btn-danger delete-flag"
title="admin.flags.delete_title"
action="showDeleteFlagModal"
icon="trash-o"
diff --git a/app/assets/javascripts/admin/templates/components/flagged-posts.hbs b/app/assets/javascripts/admin/templates/components/flagged-posts.hbs
index 583b35c11a7..ff1073db43d 100644
--- a/app/assets/javascripts/admin/templates/components/flagged-posts.hbs
+++ b/app/assets/javascripts/admin/templates/components/flagged-posts.hbs
@@ -17,7 +17,6 @@
removePost=(action "removePost" flaggedPost)
hideTitle=topic}}
{{/each}}
-
{{/load-more}}
diff --git a/app/assets/javascripts/admin/templates/components/flagged-topic-users.hbs b/app/assets/javascripts/admin/templates/components/flagged-topic-users.hbs
index dfc4b3da425..ac6935672c9 100644
--- a/app/assets/javascripts/admin/templates/components/flagged-topic-users.hbs
+++ b/app/assets/javascripts/admin/templates/components/flagged-topic-users.hbs
@@ -1,5 +1,5 @@
{{#each users as |u|}}
- {{#link-to 'adminUser' u}}
+ {{#link-to 'adminUser' u class="flagged-topic-user"}}
{{avatar u imageSize="small"}}
{{/link-to}}
{{/each}}
diff --git a/app/assets/javascripts/admin/templates/flags-topics-index.hbs b/app/assets/javascripts/admin/templates/flags-topics-index.hbs
index 110df355f62..61ef340129d 100644
--- a/app/assets/javascripts/admin/templates/flags-topics-index.hbs
+++ b/app/assets/javascripts/admin/templates/flags-topics-index.hbs
@@ -22,7 +22,7 @@
{{flag-counts details=fc}}
{{/each}}
|
-
+ |
{{flagged-topic-users users=ft.users tagName=""}}
|
@@ -32,7 +32,7 @@
{{#link-to
"adminFlags.topics.show"
ft.id
- class="btn d-button no-text btn-small btn-primary"
+ class="btn d-button no-text btn-small btn-primary show-details"
title=(i18n "admin.flags.show_details")}}
{{d-icon "search"}}
{{/link-to}}
diff --git a/app/assets/javascripts/admin/templates/flags-topics-show.hbs b/app/assets/javascripts/admin/templates/flags-topics-show.hbs
index fae256e8ab2..225b21177d4 100644
--- a/app/assets/javascripts/admin/templates/flags-topics-show.hbs
+++ b/app/assets/javascripts/admin/templates/flags-topics-show.hbs
@@ -11,5 +11,8 @@
{{plugin-outlet name="flagged-topic-details-header" args=(hash topic=topic)}}
- {{flagged-posts flaggedPosts=flaggedPosts query="active" topic=topic}}
+ {{flagged-posts
+ flaggedPosts=flaggedPosts
+ filter="active"
+ topic=topic}}
diff --git a/app/assets/javascripts/admin/templates/modal/admin-agree-flag.hbs b/app/assets/javascripts/admin/templates/modal/admin-agree-flag.hbs
index 63ce16601bd..a69ae42877e 100644
--- a/app/assets/javascripts/admin/templates/modal/admin-agree-flag.hbs
+++ b/app/assets/javascripts/admin/templates/modal/admin-agree-flag.hbs
@@ -1,13 +1,35 @@
{{#d-modal-body title="admin.flags.agree_flag_modal_title"}}
{{#if model.user_deleted}}
-
+ {{d-button
+ title="admin.flags.agree_flag_restore_post_title"
+ class="confirm-agree-restore"
+ action=(action "perform" "restore")
+ icon="eye"
+ label="admin.flags.agree_flag_restore_post"}}
{{else}}
{{#unless model.postHidden}}
-
+ {{d-button
+ title="admin.flags.agree_flag_hide_post_title"
+ action=(action "perform" "hide")
+ class="confirm-agree-hide"
+ icon="eye-slash"
+ label="admin.flags.agree_flag_hide_post"}}
{{/unless}}
{{/if}}
-
+
+ {{d-button
+ title="admin.flags.agree_flag_title"
+ action=(action "perform" "keep")
+ class="confirm-agree-keep"
+ icon="thumbs-o-up"
+ label="admin.flags.agree_flag"}}
+
{{#if model.canDeleteAsSpammer}}
-
+ {{d-button
+ title="admin.flags.delete_spammer_title"
+ action=(action "agreeDeleteSpammer" model.user)
+ class="btn-danger delete-spammer"
+ icon="exclamation-triangle"
+ label="admin.flags.delete_spammer"}}
{{/if}}
{{/d-modal-body}}
diff --git a/app/assets/javascripts/admin/templates/modal/admin-delete-flag.hbs b/app/assets/javascripts/admin/templates/modal/admin-delete-flag.hbs
index 89cf7452a4c..d27c10d1127 100644
--- a/app/assets/javascripts/admin/templates/modal/admin-delete-flag.hbs
+++ b/app/assets/javascripts/admin/templates/modal/admin-delete-flag.hbs
@@ -1,7 +1,24 @@
{{#d-modal-body title="admin.flags.delete_flag_modal_title"}}
-
-
+ {{d-button
+ class="delete-defer"
+ title="admin.flags.delete_post_defer_flag_title"
+ action="deletePostDeferFlag"
+ icon="external-link"
+ label="admin.flags.delete_post_defer_flag"}}
+
+ {{d-button
+ class="delete-agree"
+ title="admin.flags.delete_post_agree_flag_title"
+ action="deletePostAgreeFlag"
+ icon="thumbs-o-up"
+ label="admin.flags.delete_post_agree_flag"}}
+
{{#if model.canDeleteAsSpammer}}
-
+ {{d-button
+ class="btn-danger delete-spammer"
+ title="admin.flags.delete_spammer_title"
+ action=(action "deleteSpammer" model.user)
+ icon="exclamation-triangle"
+ label="admin.flags.delete_spammer"}}
{{/if}}
{{/d-modal-body}}
diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6
index 93598fbb9bd..c53dd857129 100644
--- a/app/assets/javascripts/discourse/routes/application.js.es6
+++ b/app/assets/javascripts/discourse/routes/application.js.es6
@@ -139,8 +139,7 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
},
deleteSpammer(user) {
- this.send('closeModal');
- user.deleteAsSpammer(function() { window.location.reload(); });
+ user.deleteAsSpammer.then(() => window.location.reload());
},
checkEmail(user) {
diff --git a/app/assets/javascripts/pretty-text/emoji.js.es6.erb b/app/assets/javascripts/pretty-text/emoji.js.es6.erb
index 136c2904261..fc7f79c94b6 100644
--- a/app/assets/javascripts/pretty-text/emoji.js.es6.erb
+++ b/app/assets/javascripts/pretty-text/emoji.js.es6.erb
@@ -26,6 +26,8 @@ Object.keys(aliases).forEach(name => {
});
export function performEmojiUnescape(string, opts) {
+ if (!string) { return; }
+
// this can be further improved by supporting matches of emoticons that don't begin with a colon
if (string.indexOf(":") >= 0) {
return string.replace(/\B:[^\s:]+(?::t\d)?:?\B/g, m => {
diff --git a/test/javascripts/acceptance/admin-flags-test.js.es6 b/test/javascripts/acceptance/admin-flags-test.js.es6
new file mode 100644
index 00000000000..1da3ce45f26
--- /dev/null
+++ b/test/javascripts/acceptance/admin-flags-test.js.es6
@@ -0,0 +1,121 @@
+import { acceptance } from "helpers/qunit-helpers";
+acceptance("Admin - Flagging", { loggedIn: true });
+
+QUnit.test("flagged posts", assert => {
+ visit("/admin/flags/active");
+ andThen(() => {
+ assert.equal(find('.admin-flags .flagged-post').length, 1);
+ assert.equal(find('.flagged-post .flaggers .flagger').length, 1, 'shows who flagged it');
+ });
+});
+
+QUnit.test("flagged posts - agree", assert => {
+ visit("/admin/flags/active");
+ click('.agree-flag');
+ andThen(() => {
+ assert.equal(find('.agree-flag-modal:visible').length, 1);
+ });
+ click('.confirm-agree-keep');
+ andThen(() => {
+ assert.equal(find('.agree-flag-modal:visible').length, 0, 'modal is closed');
+ assert.equal(find('.admin-flags .flagged-post').length, 0, 'post was removed');
+ });
+});
+
+QUnit.test("flagged posts - agree + hide", assert => {
+ visit("/admin/flags/active");
+ click('.agree-flag');
+ andThen(() => {
+ assert.equal(find('.agree-flag-modal:visible').length, 1);
+ });
+ click('.confirm-agree-hide');
+ andThen(() => {
+ assert.equal(find('.agree-flag-modal:visible').length, 0, 'modal is closed');
+ assert.equal(find('.admin-flags .flagged-post').length, 0, 'post was removed');
+ });
+});
+
+QUnit.test("flagged posts - agree + deleteSpammer", assert => {
+ visit("/admin/flags/active");
+ click('.agree-flag');
+ andThen(() => {
+ assert.equal(find('.agree-flag-modal:visible').length, 1);
+ });
+ click('.delete-spammer');
+ click('.confirm-delete');
+ andThen(() => {
+ assert.equal(find('.agree-flag-modal:visible').length, 0, 'modal is closed');
+ assert.equal(find('.admin-flags .flagged-post').length, 0, 'post was removed');
+ });
+});
+
+QUnit.test("flagged posts - disagree", assert => {
+ visit("/admin/flags/active");
+ click('.disagree-flag');
+ andThen(() => {
+ assert.equal(find('.admin-flags .flagged-post').length, 0);
+ });
+});
+
+QUnit.test("flagged posts - defer", assert => {
+ visit("/admin/flags/active");
+ click('.defer-flag');
+ andThen(() => {
+ assert.equal(find('.admin-flags .flagged-post').length, 0);
+ });
+});
+
+QUnit.test("flagged posts - delete + defer", assert => {
+ visit("/admin/flags/active");
+ click('.delete-flag');
+ andThen(() => {
+ assert.equal(find('.delete-flag-modal:visible').length, 1);
+ });
+ click('.delete-defer');
+ andThen(() => {
+ assert.equal(find('.delete-flag-modal:visible').length, 0);
+ assert.equal(find('.admin-flags .flagged-post').length, 0);
+ });
+});
+
+QUnit.test("flagged posts - delete + agree", assert => {
+ visit("/admin/flags/active");
+ click('.delete-flag');
+ andThen(() => {
+ assert.equal(find('.delete-flag-modal:visible').length, 1);
+ });
+ click('.delete-agree');
+ andThen(() => {
+ assert.equal(find('.delete-flag-modal:visible').length, 0);
+ assert.equal(find('.admin-flags .flagged-post').length, 0);
+ });
+});
+
+QUnit.test("flagged posts - delete + deleteSpammer", assert => {
+ visit("/admin/flags/active");
+ click('.delete-flag');
+ andThen(() => {
+ assert.equal(find('.delete-flag-modal:visible').length, 1);
+ });
+ click('.delete-spammer');
+ click('.confirm-delete');
+ andThen(() => {
+ assert.equal(find('.delete-flag-modal:visible').length, 0);
+ assert.equal(find('.admin-flags .flagged-post').length, 0);
+ });
+});
+
+
+QUnit.test("topics with flags", assert => {
+ visit("/admin/flags/topics");
+ andThen(() => {
+ assert.equal(find('.flagged-topics .flagged-topic').length, 1);
+ assert.equal(find('.flagged-topic .flagged-topic-user').length, 2);
+ assert.equal(find('.flagged-topic .flag-counts').length, 3);
+ });
+
+ click('.flagged-topic .show-details');
+ andThen(() => {
+ assert.equal(currentURL(), '/admin/flags/topics/280');
+ });
+});
diff --git a/test/javascripts/acceptance/admin-flags-topics-test.js.es6 b/test/javascripts/acceptance/admin-flags-topics-test.js.es6
deleted file mode 100644
index 23e6f56ddc2..00000000000
--- a/test/javascripts/acceptance/admin-flags-topics-test.js.es6
+++ /dev/null
@@ -1,11 +0,0 @@
-import { acceptance } from "helpers/qunit-helpers";
-acceptance("Admin - Flagged Topics", { loggedIn: true });
-
-QUnit.test("topics with flags", assert => {
- visit("/admin/flags/topics");
- andThen(() => {
- assert.ok(exists('.watched-words-list'));
- assert.ok(!exists('.watched-words-list .watched-word'), "Don't show bad words by default.");
- });
-});
-
diff --git a/test/javascripts/helpers/create-pretender.js.es6 b/test/javascripts/helpers/create-pretender.js.es6
index a803bccfe43..f7e4d8df2be 100644
--- a/test/javascripts/helpers/create-pretender.js.es6
+++ b/test/javascripts/helpers/create-pretender.js.es6
@@ -1,5 +1,6 @@
import storePretender from 'helpers/store-pretender';
import fixturePretender from 'helpers/fixture-pretender';
+import flagPretender from 'helpers/flag-pretender';
export function parsePostData(query) {
const result = {};
@@ -41,6 +42,7 @@ export default function() {
const server = new Pretender(function() {
storePretender.call(this, helpers);
+ flagPretender.call(this, helpers);
const fixturesByUrl = fixturePretender.call(this, helpers);
this.get('/admin/plugins', () => response({ plugins: [] }));
@@ -66,7 +68,7 @@ export default function() {
}] });
});
- this.get(`/u/eviltrout/emails.json`, () => {
+ this.get(`/u/:username/emails.json`, () => {
return response({ email: 'eviltrout@example.com' });
});
@@ -323,14 +325,6 @@ export default function() {
]);
});
- this.get('/admin/flagged_topics', () => {
- return response(200, {
- "flagged_topics": [
- { id: 1 }
- ]
- });
- });
-
this.get('/admin/customize/site_texts', request => {
if (request.queryParams.overridden) {
@@ -353,6 +347,7 @@ export default function() {
this.get('/tag_groups', () => response(200, {tag_groups: []}));
this.post('/admin/users/:user_id/generate_api_key', success);
this.delete('/admin/users/:user_id/revoke_api_key', success);
+ this.delete('/admin/users/:user_id.json', () => response(200, { deleted: true }));
this.post('/admin/badges', success);
this.delete('/admin/badges/:id', success);
diff --git a/test/javascripts/helpers/flag-pretender.js.es6 b/test/javascripts/helpers/flag-pretender.js.es6
new file mode 100644
index 00000000000..5ce060aacf7
--- /dev/null
+++ b/test/javascripts/helpers/flag-pretender.js.es6
@@ -0,0 +1,58 @@
+export default function(helpers) {
+ const { response, success } = helpers;
+
+ const eviltrout = {
+ id: 1,
+ username: "eviltrout",
+ avatar_template:"/images/avatar.png",
+ };
+ const sam = {
+ id: 2,
+ username: "sam",
+ avatar_template:"/images/avatar.png",
+ can_delete_all_posts: true,
+ can_be_deleted: true,
+ post_count: 1,
+ topic_count: 0
+ };
+
+ this.get('/admin/flagged_topics', () => {
+ return response(200, {
+ "flagged_topics": [
+ {
+ id: 280,
+ user_ids: [eviltrout.id, sam.id],
+ flag_counts: [
+ { flag_type_id: 1, count: 3 },
+ { flag_type_id: 2, count: 2 },
+ { flag_type_id: 3, count: 1 },
+ ]
+ }
+ ],
+ "users": [ eviltrout, sam ],
+ "__rest_serializer":"1"
+ });
+ });
+
+ this.get('/admin/flags/active.json', () => {
+ return response(200, {
+ posts: [
+ {
+ id: 1,
+ user_id: sam.id,
+ post_actions: [{
+ user_id: eviltrout.id,
+ post_action_type_id: 8,
+ name_key: 'spam'
+ }]
+ }
+ ],
+ users: [eviltrout, sam],
+ topics: [],
+ });
+ });
+
+ this.post('/admin/flags/agree/1', success);
+ this.post('/admin/flags/defer/1', success);
+ this.post('/admin/flags/disagree/1', success);
+}
|