diff --git a/Gemfile b/Gemfile
index a513adb80e..cf25046564 100644
--- a/Gemfile
+++ b/Gemfile
@@ -36,7 +36,7 @@ gem 'redis-namespace'
gem 'active_model_serializers', '~> 0.8.3'
-gem 'onebox', '1.8.36'
+gem 'onebox', '1.8.38'
gem 'http_accept_language', '~>2.0.5', require: false
@@ -59,7 +59,7 @@ gem 'aws-sdk-s3', require: false
gem 'excon', require: false
gem 'unf', require: false
-gem 'email_reply_trimmer', '0.1.9'
+gem 'email_reply_trimmer', '0.1.10'
# Forked until https://github.com/toy/image_optim/pull/149 is merged
gem 'discourse_image_optim', require: 'image_optim'
@@ -67,9 +67,6 @@ gem 'multi_json'
gem 'mustache'
gem 'nokogiri'
-# this may end up deprecating nokogiri
-gem 'oga', require: false
-
gem 'omniauth'
gem 'omniauth-openid'
gem 'openid-redis-store'
diff --git a/Gemfile.lock b/Gemfile.lock
index b2397688ec..09d9ff3bb3 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -41,7 +41,6 @@ GEM
annotate (2.7.2)
activerecord (>= 3.2, < 6.0)
rake (>= 10.4, < 13.0)
- ansi (1.5.0)
arel (8.0.0)
ast (2.3.0)
aws-partitions (1.24.0)
@@ -91,7 +90,7 @@ GEM
image_size (~> 1.5)
in_threads (~> 1.3)
progress (~> 3.0, >= 3.0.1)
- email_reply_trimmer (0.1.9)
+ email_reply_trimmer (0.1.10)
ember-data-source (2.2.1)
ember-source (>= 1.8, < 3.0)
ember-handlebars-template (0.7.5)
@@ -165,7 +164,7 @@ GEM
lru_redux (1.1.0)
mail (2.6.6)
mime-types (>= 1.16, < 4)
- memory_profiler (0.9.8)
+ memory_profiler (0.9.10)
message_bus (2.1.2)
rack (>= 1.1.3)
metaclass (0.0.4)
@@ -189,7 +188,7 @@ GEM
multi_xml (0.6.0)
multipart-post (2.0.0)
mustache (1.0.5)
- nokogiri (1.8.1)
+ nokogiri (1.8.2)
mini_portile2 (~> 2.3.0)
nokogumbo (1.4.13)
nokogiri
@@ -200,9 +199,6 @@ GEM
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
- oga (2.10)
- ast
- ruby-ll (~> 2.1)
oj (3.1.0)
omniauth (1.6.1)
hashie (>= 3.4.6, < 3.6.0)
@@ -232,7 +228,7 @@ GEM
omniauth-twitter (1.3.0)
omniauth-oauth (~> 1.1)
rack
- onebox (1.8.36)
+ onebox (1.8.38)
fast_blank (>= 1.0.0)
htmlentities (~> 4.3)
moneta (~> 1.0)
@@ -275,7 +271,7 @@ GEM
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
- rails_multisite (2.0.2)
+ rails_multisite (2.0.4)
activerecord (> 4.2, < 6)
railties (> 4.2, < 6)
railties (5.1.4)
@@ -334,9 +330,6 @@ GEM
rainbow (>= 2.2.2, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
- ruby-ll (2.1.2)
- ansi
- ast
ruby-openid (2.7.0)
ruby-prof (0.16.2)
ruby-progressbar (1.9.0)
@@ -421,7 +414,7 @@ DEPENDENCIES
cppjieba_rb
discourse-qunit-rails
discourse_image_optim
- email_reply_trimmer (= 0.1.9)
+ email_reply_trimmer (= 0.1.10)
ember-handlebars-template (= 0.7.5)
ember-rails (= 0.18.5)
ember-source (= 2.13.3)
@@ -459,7 +452,6 @@ DEPENDENCIES
multi_json
mustache
nokogiri
- oga
oj
omniauth
omniauth-facebook
@@ -469,7 +461,7 @@ DEPENDENCIES
omniauth-oauth2
omniauth-openid
omniauth-twitter
- onebox (= 1.8.36)
+ onebox (= 1.8.38)
openid-redis-store
pg (~> 0.21.0)
pry-nav
diff --git a/app/assets/javascripts/admin/components/flagged-post.js.es6 b/app/assets/javascripts/admin/components/flagged-post.js.es6
index aaa4759e82..8aff3d2a2d 100644
--- a/app/assets/javascripts/admin/components/flagged-post.js.es6
+++ b/app/assets/javascripts/admin/components/flagged-post.js.es6
@@ -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)
- }
- );
}
}
});
diff --git a/app/assets/javascripts/admin/components/penalty-post-action.js.es6 b/app/assets/javascripts/admin/components/penalty-post-action.js.es6
new file mode 100644
index 0000000000..d89c69a32d
--- /dev/null
+++ b/app/assets/javascripts/admin/components/penalty-post-action.js.es6
@@ -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();
+ });
+ }
+ }
+ }
+});
diff --git a/app/assets/javascripts/admin/components/staff-actions.js.es6 b/app/assets/javascripts/admin/components/staff-actions.js.es6
new file mode 100644
index 0000000000..9e742526af
--- /dev/null
+++ b/app/assets/javascripts/admin/components/staff-actions.js.es6
@@ -0,0 +1,22 @@
+import DiscourseURL from 'discourse/lib/url';
+
+export default Ember.Component.extend({
+ classNames: ['table', 'staff-actions'],
+
+ willDestroyElement() {
+ this.$().off('click.discourse-staff-logs');
+ },
+
+ didInsertElement() {
+ this._super();
+
+ this.$().on('click.discourse-staff-logs', '[data-link-post-id]', e => {
+ let postId = $(e.target).attr('data-link-post-id');
+
+ this.store.find('post', postId).then(p => {
+ DiscourseURL.routeTo(p.get('url'));
+ });
+ return false;
+ });
+ }
+});
diff --git a/app/assets/javascripts/admin/controllers/modals/admin-silence-user.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-silence-user.js.es6
index 9f1aef916f..ec55cbdbe8 100644
--- a/app/assets/javascripts/admin/controllers/modals/admin-silence-user.js.es6
+++ b/app/assets/javascripts/admin/controllers/modals/admin-silence-user.js.es6
@@ -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, {
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 +20,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));
}
}
});
diff --git a/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6
index efcd142670..f66a1eec69 100644
--- a/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6
+++ b/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6
@@ -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));
}
}
-
});
diff --git a/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 b/app/assets/javascripts/admin/mixins/penalty-controller.js.es6
new file mode 100644
index 0000000000..8b5bbb0629
--- /dev/null
+++ b/app/assets/javascripts/admin/mixins/penalty-controller.js.es6
@@ -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);
+ }
+});
diff --git a/app/assets/javascripts/admin/models/staff-action-log.js.es6 b/app/assets/javascripts/admin/models/staff-action-log.js.es6
index e60d815f7c..78d39869cf 100644
--- a/app/assets/javascripts/admin/models/staff-action-log.js.es6
+++ b/app/assets/javascripts/admin/models/staff-action-log.js.es6
@@ -10,7 +10,7 @@ const StaffActionLog = Discourse.Model.extend({
}.property('action_name'),
formattedDetails: function() {
- var formatted = "";
+ let formatted = "";
formatted += this.format('email', 'email');
formatted += this.format('admin.logs.ip_address', 'ip_address');
formatted += this.format('admin.logs.topic_id', 'topic_id');
@@ -26,9 +26,13 @@ const StaffActionLog = Discourse.Model.extend({
return formatted;
}.property('ip_address', 'email', 'topic_id', 'post_id', 'category_id'),
- format: function(label, propertyName) {
+ format(label, propertyName) {
if (this.get(propertyName)) {
- return ('' + I18n.t(label) + ': ' + escapeExpression(this.get(propertyName)) + '
');
+ let value = escapeExpression(this.get(propertyName));
+ if (propertyName === 'post_id') {
+ value = `${value}`;
+ }
+ return `${I18n.t(label)}: ${value}
`;
} else {
return '';
}
diff --git a/app/assets/javascripts/admin/services/admin-tools.js.es6 b/app/assets/javascripts/admin/services/admin-tools.js.es6
index a6a56d0f14..9f9bec8b03 100644
--- a/app/assets/javascripts/admin/services/admin-tools.js.es6
+++ b/app/assets/javascripts/admin/services/admin-tools.js.es6
@@ -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
});
});
diff --git a/app/assets/javascripts/admin/templates/backups.hbs b/app/assets/javascripts/admin/templates/backups.hbs
index 5cfd123114..33229e2253 100644
--- a/app/assets/javascripts/admin/templates/backups.hbs
+++ b/app/assets/javascripts/admin/templates/backups.hbs
@@ -1,12 +1,12 @@
{{i18n 'admin.badges.none_selected'}}