From 5c8c52482a274755b188b778624fb1fa8b2ba1c6 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Wed, 7 Aug 2013 16:04:12 -0400 Subject: [PATCH] Add a way to view staff action logs in admin --- .../admin_logs_blocked_emails_controller.js | 1 - ...admin_logs_staff_action_logs_controller.js | 24 +++++++++ .../javascripts/admin/models/blocked_email.js | 6 +-- .../admin/models/staff_action_log.js | 46 +++++++++++++++++ .../admin/routes/admin_logs_routes.js | 24 +++++++-- .../javascripts/admin/routes/admin_routes.js | 1 + .../admin/templates/logs.js.handlebars | 3 +- .../logs/blocked_emails.js.handlebars | 6 +-- .../logs/staff_action_logs.js.handlebars | 50 +++++++++++++++++++ app/assets/stylesheets/admin/admin_base.scss | 20 +++++++- .../admin/blocked_emails_controller.rb | 2 +- .../admin/staff_action_logs_controller.rb | 8 +++ .../staff_action_log_serializer.rb | 15 ++++++ config/locales/client.en.yml | 24 ++++++--- config/routes.rb | 3 +- .../staff_action_logs_controller_spec.rb | 22 ++++++++ 16 files changed, 231 insertions(+), 24 deletions(-) create mode 100644 app/assets/javascripts/admin/controllers/admin_logs_staff_action_logs_controller.js create mode 100644 app/assets/javascripts/admin/models/staff_action_log.js create mode 100644 app/assets/javascripts/admin/templates/logs/staff_action_logs.js.handlebars create mode 100644 app/controllers/admin/staff_action_logs_controller.rb create mode 100644 app/serializers/staff_action_log_serializer.rb create mode 100644 spec/controllers/admin/staff_action_logs_controller_spec.rb diff --git a/app/assets/javascripts/admin/controllers/admin_logs_blocked_emails_controller.js b/app/assets/javascripts/admin/controllers/admin_logs_blocked_emails_controller.js index 6a340eaf0..d667a2ad1 100644 --- a/app/assets/javascripts/admin/controllers/admin_logs_blocked_emails_controller.js +++ b/app/assets/javascripts/admin/controllers/admin_logs_blocked_emails_controller.js @@ -13,7 +13,6 @@ Discourse.AdminLogsBlockedEmailsController = Ember.ArrayController.extend(Discou var self = this; this.set('loading', true); Discourse.BlockedEmail.findAll().then(function(result) { - console.log('findAll done'); self.set('content', result); self.set('loading', false); }); diff --git a/app/assets/javascripts/admin/controllers/admin_logs_staff_action_logs_controller.js b/app/assets/javascripts/admin/controllers/admin_logs_staff_action_logs_controller.js new file mode 100644 index 000000000..6692643ab --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin_logs_staff_action_logs_controller.js @@ -0,0 +1,24 @@ +/** + This controller supports the interface for listing staff action logs in the admin section. + + @class AdminLogsStaffActionLogsController + @extends Ember.ArrayController + @namespace Discourse + @module Discourse +**/ +Discourse.AdminLogsStaffActionLogsController = Ember.ArrayController.extend(Discourse.Presence, { + loading: false, + + show: function() { + var self = this; + this.set('loading', true); + Discourse.StaffActionLog.findAll().then(function(result) { + self.set('content', result); + self.set('loading', false); + }); + }, + + toggleFullDetails: function(target) { + target.set('showFullDetails', !target.get('showFullDetails')); + } +}); diff --git a/app/assets/javascripts/admin/models/blocked_email.js b/app/assets/javascripts/admin/models/blocked_email.js index 762102c93..9d0bc2cc5 100644 --- a/app/assets/javascripts/admin/models/blocked_email.js +++ b/app/assets/javascripts/admin/models/blocked_email.js @@ -9,7 +9,7 @@ **/ Discourse.BlockedEmail = Discourse.Model.extend({ actionName: function() { - return I18n.t("admin.logs.actions." + this.get('action')); + return I18n.t("admin.logs.blocked_emails.actions." + this.get('action')); }.property('action') }); @@ -18,9 +18,7 @@ Discourse.BlockedEmail.reopenClass({ return Discourse.ajax("/admin/logs/blocked_emails.json").then(function(blocked_emails) { return blocked_emails.map(function(b) { return Discourse.BlockedEmail.create(b); - }) + }); }); } }); - - diff --git a/app/assets/javascripts/admin/models/staff_action_log.js b/app/assets/javascripts/admin/models/staff_action_log.js new file mode 100644 index 000000000..1b6433791 --- /dev/null +++ b/app/assets/javascripts/admin/models/staff_action_log.js @@ -0,0 +1,46 @@ +/** + Represents an action taken by a staff member that has been logged. + + @class StaffActionLog + @extends Discourse.Model + @namespace Discourse + @module Discourse +**/ +Discourse.StaffActionLog = Discourse.Model.extend({ + showFullDetails: false, + + actionName: function() { + return I18n.t("admin.logs.staff_actions.actions." + this.get('action_name')); + }.property('action_name'), + + formattedDetails: function() { + var formatted = ""; + if (this.get('email')) { + formatted += "Email: " + this.get('email') + "
"; + } + if (this.get('ip_address')) { + formatted += "IP: " + this.get('ip_address') + "
"; + } + return formatted; + }.property('ip_address', 'email') +}); + +Discourse.StaffActionLog.reopenClass({ + create: function(attrs) { + if (attrs.staff_user) { + attrs.staff_user = Discourse.AdminUser.create(attrs.staff_user); + } + if (attrs.target_user) { + attrs.target_user = Discourse.AdminUser.create(attrs.target_user); + } + return this._super(attrs); + }, + + findAll: function(filter) { + return Discourse.ajax("/admin/logs/staff_action_logs.json").then(function(staff_actions) { + return staff_actions.map(function(s) { + return Discourse.StaffActionLog.create(s); + }); + }); + } +}); diff --git a/app/assets/javascripts/admin/routes/admin_logs_routes.js b/app/assets/javascripts/admin/routes/admin_logs_routes.js index 3301fc46d..73cc4917d 100644 --- a/app/assets/javascripts/admin/routes/admin_logs_routes.js +++ b/app/assets/javascripts/admin/routes/admin_logs_routes.js @@ -8,7 +8,7 @@ **/ Discourse.AdminLogsIndexRoute = Discourse.Route.extend({ redirect: function() { - this.transitionTo('adminLogs.blockedEmails'); + this.transitionTo('adminLogs.staffActionLogs'); } }); @@ -21,10 +21,6 @@ Discourse.AdminLogsIndexRoute = Discourse.Route.extend({ @module Discourse **/ Discourse.AdminLogsBlockedEmailsRoute = Discourse.Route.extend({ - // model: function() { - // return Discourse.BlockedEmail.findAll(); - // }, - renderTemplate: function() { this.render('admin/templates/logs/blocked_emails', {into: 'adminLogs'}); }, @@ -32,4 +28,22 @@ Discourse.AdminLogsBlockedEmailsRoute = Discourse.Route.extend({ setupController: function() { return this.controllerFor('adminLogsBlockedEmails').show(); } +}); + +/** + The route that lists staff actions that were logged. + + @class AdminLogsStaffActionLogsRoute + @extends Discourse.Route + @namespace Discourse + @module Discourse +**/ +Discourse.AdminLogsStaffActionLogsRoute = Discourse.Route.extend({ + renderTemplate: function() { + this.render('admin/templates/logs/staff_action_logs', {into: 'adminLogs'}); + }, + + setupController: function() { + return this.controllerFor('adminLogsStaffActionLogs').show(); + } }); \ No newline at end of file diff --git a/app/assets/javascripts/admin/routes/admin_routes.js b/app/assets/javascripts/admin/routes/admin_routes.js index 5e3133739..517cca1a8 100644 --- a/app/assets/javascripts/admin/routes/admin_routes.js +++ b/app/assets/javascripts/admin/routes/admin_routes.js @@ -31,6 +31,7 @@ Discourse.Route.buildRoutes(function() { this.resource('adminLogs', { path: '/logs' }, function() { this.route('blockedEmails', { path: '/blocked_emails' }); + this.route('staffActionLogs', { path: '/staff_action_logs' }); }); this.route('groups', {path: '/groups'}); diff --git a/app/assets/javascripts/admin/templates/logs.js.handlebars b/app/assets/javascripts/admin/templates/logs.js.handlebars index 7d033a1a6..f3f6f476c 100644 --- a/app/assets/javascripts/admin/templates/logs.js.handlebars +++ b/app/assets/javascripts/admin/templates/logs.js.handlebars @@ -1,7 +1,8 @@
diff --git a/app/assets/javascripts/admin/templates/logs/blocked_emails.js.handlebars b/app/assets/javascripts/admin/templates/logs/blocked_emails.js.handlebars index 30f78bf45..6c5055951 100644 --- a/app/assets/javascripts/admin/templates/logs/blocked_emails.js.handlebars +++ b/app/assets/javascripts/admin/templates/logs/blocked_emails.js.handlebars @@ -4,10 +4,10 @@ {{#if model.length}} - + - - + + diff --git a/app/assets/javascripts/admin/templates/logs/staff_action_logs.js.handlebars b/app/assets/javascripts/admin/templates/logs/staff_action_logs.js.handlebars new file mode 100644 index 000000000..25fd839d3 --- /dev/null +++ b/app/assets/javascripts/admin/templates/logs/staff_action_logs.js.handlebars @@ -0,0 +1,50 @@ +{{#if loading}} +
{{i18n loading}}
+{{else}} + {{#if model.length}} +
{{i18n admin.logs.action}}{{i18n admin.logs.match_count}}{{i18n admin.logs.last_match_at}}{{i18n admin.logs.blocked_emails.match_count}}{{i18n admin.logs.blocked_emails.last_match_at}} {{i18n admin.logs.created_at}}
+ + + + + + + + + + + {{#each model}} + + + + + + + + + {{/each}} + +
{{i18n admin.logs.action}}{{i18n admin.logs.staff_actions.staff_user}}{{i18n admin.logs.staff_actions.target_user}}{{i18n admin.logs.staff_actions.context}}{{i18n admin.logs.created_at}}{{i18n admin.logs.staff_actions.details}}
{{actionName}} + {{#linkTo 'adminUser' staff_user}}{{avatar staff_user imageSize="tiny"}}{{/linkTo}} + {{#linkTo 'adminUser' staff_user}}{{staff_user.username}}{{/linkTo}} + + {{#if target_user}} + {{#linkTo 'adminUser' target_user}}{{avatar target_user imageSize="tiny"}}{{/linkTo}} + {{#linkTo 'adminUser' target_user}}{{target_user.username}}{{/linkTo}} + {{else}} + — + {{/if}} + {{context}}{{unboundAgeWithTooltip created_at}} + {{{formattedDetails}}} + {{#if showFullDetails}} + {{details}} +
+ Less + {{else}} + More + {{/if}} +
+ {{else}} + No results. + {{/if}} +{{/if}} \ No newline at end of file diff --git a/app/assets/stylesheets/admin/admin_base.scss b/app/assets/stylesheets/admin/admin_base.scss index 0ee4dd4a4..34cdf21ab 100644 --- a/app/assets/stylesheets/admin/admin_base.scss +++ b/app/assets/stylesheets/admin/admin_base.scss @@ -700,4 +700,22 @@ table { .match_count, .last_match_at, .created_at { text-align: center; } -} \ No newline at end of file +} + +.staff-actions { + .action { + width: 120px; + } + .staff_user, .target_user { + white-space: nowrap; + } + .created_at { + text-align: center; + } + .details { + width: 500px; + a { + text-decoration: underline; + } + } +} diff --git a/app/controllers/admin/blocked_emails_controller.rb b/app/controllers/admin/blocked_emails_controller.rb index b121fdad7..2ef690709 100644 --- a/app/controllers/admin/blocked_emails_controller.rb +++ b/app/controllers/admin/blocked_emails_controller.rb @@ -1,7 +1,7 @@ class Admin::BlockedEmailsController < Admin::AdminController def index - blocked_emails = BlockedEmail.limit(50).order('created_at desc').to_a + blocked_emails = BlockedEmail.limit(50).order('last_match_at desc').to_a render_serialized(blocked_emails, BlockedEmailSerializer) end diff --git a/app/controllers/admin/staff_action_logs_controller.rb b/app/controllers/admin/staff_action_logs_controller.rb new file mode 100644 index 000000000..1de752d25 --- /dev/null +++ b/app/controllers/admin/staff_action_logs_controller.rb @@ -0,0 +1,8 @@ +class Admin::StaffActionLogsController < Admin::AdminController + + def index + staff_actions = StaffActionLog.limit(50).order('created_at desc').to_a + render_serialized(staff_actions, StaffActionLogSerializer) + end + +end diff --git a/app/serializers/staff_action_log_serializer.rb b/app/serializers/staff_action_log_serializer.rb new file mode 100644 index 000000000..0f0db2672 --- /dev/null +++ b/app/serializers/staff_action_log_serializer.rb @@ -0,0 +1,15 @@ +class StaffActionLogSerializer < ApplicationSerializer + attributes :action_name, + :details, + :context, + :ip_address, + :email, + :created_at + + has_one :staff_user, serializer: BasicUserSerializer, embed: :objects + has_one :target_user, serializer: BasicUserSerializer, embed: :objects + + def action_name + StaffActionLog.actions.key(object.action).to_s + end +end \ No newline at end of file diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 88595615e..b5cc3d1f3 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1162,15 +1162,25 @@ en: logs: title: "Logs" - blocked_emails: "Blocked Emails" - email: "Email Address" action: "Action" - last_match_at: "Last Matched" - match_count: "Matches" created_at: "Created" - actions: - block: "block" - do_nothing: "do nothing" + blocked_emails: + title: "Blocked Emails" + email: "Email Address" + last_match_at: "Last Matched" + match_count: "Matches" + actions: + block: "block" + do_nothing: "do nothing" + staff_actions: + title: "Staff Actions" + staff_user: "Staff User" + target_user: "Target User" + context: "Context" + details: "Details" + actions: + delete_user: "delete user" + change_trust_level: "change trust level" impersonate: title: "Impersonate User" diff --git a/config/routes.rb b/config/routes.rb index 61017e772..406e2e6a6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -63,7 +63,8 @@ Discourse::Application.routes.draw do end scope '/logs' do - resources :blocked_emails, only: [:index, :create, :update, :destroy] + resources :blocked_emails, only: [:index, :create, :update, :destroy] + resources :staff_action_logs, only: [:index, :create, :update, :destroy] end get 'customize' => 'site_customizations#index', constraints: AdminConstraint.new diff --git a/spec/controllers/admin/staff_action_logs_controller_spec.rb b/spec/controllers/admin/staff_action_logs_controller_spec.rb new file mode 100644 index 000000000..023b495a2 --- /dev/null +++ b/spec/controllers/admin/staff_action_logs_controller_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe Admin::StaffActionLogsController do + it "is a subclass of AdminController" do + (Admin::StaffActionLogsController < Admin::AdminController).should be_true + end + + let!(:user) { log_in(:admin) } + + context '.index' do + before do + xhr :get, :index + end + + subject { response } + it { should be_success } + + it 'returns JSON' do + ::JSON.parse(subject.body).should be_a(Array) + end + end +end