From 87825a8f5160f7f85a193ea6bef69618be45b436 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Tue, 16 Jan 2018 15:27:13 -0500 Subject: [PATCH] Add a link to the post of the staff note, if provided --- .rubocop.yml | 112 ++++++++++++++++++ .../lib/staff-notes.js.es6 | 5 +- .../discourse/controllers/staff-notes.js.es6 | 11 +- .../initializers/enable-staff-notes.js.es6 | 9 +- .../templates/components/show-staff-notes.hbs | 2 +- .../discourse/templates/modal/staff-notes.hbs | 15 ++- config/locales/client.en.yml | 1 + plugin.rb | 82 +++++++++++-- 8 files changed, 215 insertions(+), 22 deletions(-) create mode 100644 .rubocop.yml diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..a529980 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,112 @@ +AllCops: + TargetRubyVersion: 2.4 + DisabledByDefault: true + Exclude: + - 'db/schema.rb' + - 'bundle/**/*' + - 'vendor/**/*' + - 'node_modules/**/*' + +# Prefer &&/|| over and/or. +Style/AndOr: + Enabled: true + +# Do not use braces for hash literals when they are the last argument of a +# method call. +Style/BracesAroundHashParameters: + Enabled: true + +# Align `when` with `case`. +Layout/CaseIndentation: + Enabled: true + +# Align comments with method definitions. +Layout/CommentIndentation: + Enabled: true + +# No extra empty lines. +Layout/EmptyLines: + Enabled: true + +# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }. +Style/HashSyntax: + Enabled: true + +# Two spaces, no tabs (for indentation). +Layout/IndentationWidth: + Enabled: true + +Layout/SpaceAfterColon: + Enabled: true + +Layout/SpaceAfterComma: + Enabled: true + +Layout/SpaceAroundEqualsInParameterDefault: + Enabled: true + +Layout/SpaceAroundKeyword: + Enabled: true + +Layout/SpaceAroundOperators: + Enabled: true + +Layout/SpaceBeforeFirstArg: + Enabled: true + +# Defining a method with parameters needs parentheses. +Style/MethodDefParentheses: + Enabled: true + +# Use `foo {}` not `foo{}`. +Layout/SpaceBeforeBlockBraces: + Enabled: true + +# Use `foo { bar }` not `foo {bar}`. +Layout/SpaceInsideBlockBraces: + Enabled: true + +# Use `{ a: 1 }` not `{a:1}`. +Layout/SpaceInsideHashLiteralBraces: + Enabled: true + +Layout/SpaceInsideParens: + Enabled: true + +# Detect hard tabs, no hard tabs. +Layout/Tab: + Enabled: true + +# Blank lines should not have any spaces. +Layout/TrailingBlankLines: + Enabled: true + +# No trailing whitespace. +Layout/TrailingWhitespace: + Enabled: true + +Lint/Debugger: + Enabled: true + +Lint/BlockAlignment: + Enabled: true + +# Align `end` with the matching keyword or starting expression except for +# assignments, where it should be aligned with the LHS. +Lint/EndAlignment: + Enabled: true + EnforcedStyleAlignWith: variable + +# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg. +Lint/RequireParentheses: + Enabled: true + +Layout/MultilineMethodCallIndentation: + Enabled: true + EnforcedStyle: indented + +Layout/AlignHash: + Enabled: true + +Bundler/OrderedGems: + Enabled: false diff --git a/assets/javascripts/discourse-staff-notes/lib/staff-notes.js.es6 b/assets/javascripts/discourse-staff-notes/lib/staff-notes.js.es6 index 5b684ac..1413ac6 100644 --- a/assets/javascripts/discourse-staff-notes/lib/staff-notes.js.es6 +++ b/assets/javascripts/discourse-staff-notes/lib/staff-notes.js.es6 @@ -1,7 +1,9 @@ import showModal from 'discourse/lib/show-modal'; import loadScript from 'discourse/lib/load-script'; -export function showStaffNotes(store, userId, callback) { +export function showStaffNotes(store, userId, callback, opts) { + opts = opts || {}; + return loadScript('defer/html-sanitizer-bundle').then(() => { return store.find('staff-note', { user_id: userId }).then(model => { const controller = showModal('staff-notes', { @@ -12,6 +14,7 @@ export function showStaffNotes(store, userId, callback) { controller.reset(); controller.set('userId', userId); controller.set('callback', callback); + controller.set('postId', opts.postId); return controller; }); }); diff --git a/assets/javascripts/discourse/controllers/staff-notes.js.es6 b/assets/javascripts/discourse/controllers/staff-notes.js.es6 index 2736d71..4f25376 100644 --- a/assets/javascripts/discourse/controllers/staff-notes.js.es6 +++ b/assets/javascripts/discourse/controllers/staff-notes.js.es6 @@ -29,7 +29,15 @@ export default Ember.Controller.extend({ const userId = parseInt(this.get('userId')); this.set('saving', true); - note.save({ raw: this.get('newNote'), user_id: userId }).then(() => { + let args = { + raw: this.get('newNote'), + user_id: userId + }; + let postId = this.get('postId'); + if (postId) { + args.post_id = parseInt(postId); + } + note.save(args).then(() => { this.set('newNote', ''); this.get('model').pushObject(note); this._refreshCount(); @@ -37,7 +45,6 @@ export default Ember.Controller.extend({ }, removeNote(note) { - bootbox.confirm(I18n.t("staff_notes.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), result => { if (result) { note.destroyRecord().then(() => { diff --git a/assets/javascripts/discourse/initializers/enable-staff-notes.js.es6 b/assets/javascripts/discourse/initializers/enable-staff-notes.js.es6 index e6fe494..036883d 100644 --- a/assets/javascripts/discourse/initializers/enable-staff-notes.js.es6 +++ b/assets/javascripts/discourse/initializers/enable-staff-notes.js.es6 @@ -1,5 +1,5 @@ import { withPluginApi } from 'discourse/lib/plugin-api'; -import { iconNode } from 'discourse/helpers/fa-icon-node'; +import { iconNode } from 'discourse-common/lib/icon-library'; import { showStaffNotes } from 'discourse/plugins/discourse-staff-notes/discourse-staff-notes/lib/staff-notes'; export default { @@ -10,10 +10,12 @@ export default { if (!siteSettings.staff_notes_enabled || !currentUser || !currentUser.staff) { return; } const store = container.lookup('store:main'); - withPluginApi('0.2', api => { + withPluginApi('0.8.15', api => { function widgetShowStaffNotes() { showStaffNotes(store, this.attrs.user_id, count => { this.sendWidgetAction('refreshStaffNotes', count); + }, { + postId: this.attrs.id }); } @@ -23,8 +25,7 @@ export default { this.model.set('user_custom_fields', cfs); }); - const UserController = container.lookupFactory('controller:user'); - UserController.reopen({ + api.modifyClass('controller:user', { staffNotesCount: null, _modelChanged: function() { diff --git a/assets/javascripts/discourse/templates/components/show-staff-notes.hbs b/assets/javascripts/discourse/templates/components/show-staff-notes.hbs index 11b7d71..d5bde2b 100644 --- a/assets/javascripts/discourse/templates/components/show-staff-notes.hbs +++ b/assets/javascripts/discourse/templates/components/show-staff-notes.hbs @@ -1,5 +1,5 @@ - {{fa-icon "pencil"}} + {{d-icon "pencil"}} {{#if showCount}} {{i18n 'staff_notes.show' count=count}} {{else}} diff --git a/assets/javascripts/discourse/templates/modal/staff-notes.hbs b/assets/javascripts/discourse/templates/modal/staff-notes.hbs index 369a780..6f3eafc 100644 --- a/assets/javascripts/discourse/templates/modal/staff-notes.hbs +++ b/assets/javascripts/discourse/templates/modal/staff-notes.hbs @@ -13,11 +13,10 @@ {{#if n.can_delete}} - {{d-button action="removeNote" - actionParam=n - icon="times" - class="btn-small btn-danger" - title="staff_notes.remove"}} + {{d-button action=(action "removeNote" n) + icon="times" + class="btn-small btn-danger" + title="staff_notes.remove"}} {{/if}} @@ -25,6 +24,12 @@
{{cook-text n.raw}}
+ + {{#if n.post_id}} +
+ {{i18n "staff_notes.show_post"}} + + {{/if}}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index b3d6456..db92b66 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -6,3 +6,4 @@ en: remove: "Remove Staff Note" show: "Staff Notes ({{count}})" delete_confirm: "Are you sure you want to delete that staff note?" + show_post: "Show Post" diff --git a/plugin.rb b/plugin.rb index 5c0bb94..fc94efc 100644 --- a/plugin.rb +++ b/plugin.rb @@ -28,9 +28,18 @@ after_initialize do PluginStore.get('staff_notes', key_for(user_id)) || [] end - def self.add_note(user, raw, created_by) + def self.add_note(user, raw, created_by, opts = nil) + opts ||= {} + notes = notes_for(user.id) - record = { id: SecureRandom.hex(16), user_id: user.id, raw: raw, created_by: created_by, created_at: Time.now } + record = { + id: SecureRandom.hex(16), + user_id: user.id, + raw: raw, + created_by: created_by, + created_at: Time.now + }.merge(opts) + notes << record ::PluginStore.set("staff_notes", key_for(user.id), notes) @@ -57,7 +66,17 @@ after_initialize do require_dependency 'application_serializer' class ::StaffNoteSerializer < ApplicationSerializer - attributes :id, :user_id, :raw, :created_by, :created_at, :can_delete + attributes( + :id, + :user_id, + :raw, + :created_by, + :created_at, + :can_delete, + :post_id, + :post_url, + :post_title + ) def id object[:id] @@ -82,6 +101,22 @@ after_initialize do def can_delete scope.can_delete_staff_notes? end + + def post_id + object[:post_id] + end + + def post_url + object[:post].try(:url) + end + + def post_title + object[:post].try(:title) + end + + def topic_id + object[:topic_id] + end end require_dependency 'application_controller' @@ -103,7 +138,17 @@ after_initialize do def create user = User.where(id: params[:staff_note][:user_id]).first raise Discourse::NotFound if user.blank? - staff_note = ::DiscourseStaffNotes.add_note(user, params[:staff_note][:raw], current_user.id) + extras = {} + if post_id = params[:staff_note][:post_id] + extras[:post_id] = post_id + end + + staff_note = ::DiscourseStaffNotes.add_note( + user, + params[:staff_note][:raw], + current_user.id, + extras + ) render json: create_json(staff_note) end @@ -123,13 +168,21 @@ after_initialize do def create_json(obj) # Avoid n+1 if obj.is_a?(Array) - by_ids = {} + users_by_id = {} + posts_by_id = {} User.where(id: obj.map { |o| o[:created_by] }).each do |u| - by_ids[u.id] = u + users_by_id[u.id] = u + end + Post.with_deleted.where(id: obj.map { |o| o[:post_id] }).each do |p| + posts_by_id[p.id] = p + end + obj.each do |o| + o[:created_by] = users_by_id[o[:created_by].to_i] + o[:post] = posts_by_id[o[:post_id].to_i] end - obj.each { |o| o[:created_by] = by_ids[o[:created_by].to_i] } else obj[:created_by] = User.where(id: obj[:created_by]).first + obj[:post] = Post.with_deleted.where(id: obj[:post_id]).first end serialize_data(obj, ::StaffNoteSerializer) @@ -161,7 +214,12 @@ after_initialize do created_by_user = User.find_by_id(self.created_by_id) warning_topic = Topic.find_by_id(self.topic_id) raw_note = I18n.t("staff_notes.official_warning", username: created_by_user.username, warning_link: "[#{warning_topic.title}](#{warning_topic.url})") - ::DiscourseStaffNotes.add_note(user, raw_note, Discourse::SYSTEM_USER_ID) + ::DiscourseStaffNotes.add_note( + user, + raw_note, + Discourse::SYSTEM_USER_ID, + topic_id: self.topic_id + ) end add_model_callback(UserHistory, :after_commit, on: :create) do @@ -169,7 +227,13 @@ after_initialize do target_user = User.find_by_id(self.target_user_id) created_by_user = User.find_by_id(self.acting_user_id) raw_note = I18n.t("staff_notes.user_suspended", username: created_by_user.username, suspended_till: I18n.l(target_user.suspended_till, format: :date_only), reason: self.details) - ::DiscourseStaffNotes.add_note(target_user, raw_note, Discourse::SYSTEM_USER_ID) + ::DiscourseStaffNotes.add_note( + target_user, + raw_note, + Discourse::SYSTEM_USER_ID, + post_id: self.post_id, + topic_id: self.topic_id + ) end end