mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 06:04:11 +08:00
Add a way to view staff action logs in admin
This commit is contained in:
parent
d2fb6ec53f
commit
5c8c52482a
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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'));
|
||||
}
|
||||
});
|
|
@ -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);
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
46
app/assets/javascripts/admin/models/staff_action_log.js
Normal file
46
app/assets/javascripts/admin/models/staff_action_log.js
Normal file
|
@ -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 += "<b>Email:</b> " + this.get('email') + "<br/>";
|
||||
}
|
||||
if (this.get('ip_address')) {
|
||||
formatted += "<b>IP:</b> " + this.get('ip_address') + "<br/>";
|
||||
}
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
|
@ -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();
|
||||
}
|
||||
});
|
|
@ -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'});
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<div class='admin-controls'>
|
||||
<div class='span15'>
|
||||
<ul class="nav nav-pills">
|
||||
<li>{{#linkTo 'adminLogs.blockedEmails'}}{{i18n admin.logs.blocked_emails}}{{/linkTo}}</li>
|
||||
<li>{{#linkTo 'adminLogs.staffActionLogs'}}{{i18n admin.logs.staff_actions.title}}{{/linkTo}}</li>
|
||||
<li>{{#linkTo 'adminLogs.blockedEmails'}}{{i18n admin.logs.blocked_emails.title}}{{/linkTo}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
{{#if model.length}}
|
||||
<table class='table blocked-emails'>
|
||||
<thead>
|
||||
<th class="email">{{i18n admin.logs.email}}</th>
|
||||
<th class="email">{{i18n admin.logs.blocked_emails.email}}</th>
|
||||
<th class="action">{{i18n admin.logs.action}}</th>
|
||||
<th class="match_count">{{i18n admin.logs.match_count}}</th>
|
||||
<th class="last_match_at">{{i18n admin.logs.last_match_at}}</th>
|
||||
<th class="match_count">{{i18n admin.logs.blocked_emails.match_count}}</th>
|
||||
<th class="last_match_at">{{i18n admin.logs.blocked_emails.last_match_at}}</th>
|
||||
<th class="created_at">{{i18n admin.logs.created_at}}</th>
|
||||
</thead>
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
{{#if loading}}
|
||||
<div class='admin-loading'>{{i18n loading}}</div>
|
||||
{{else}}
|
||||
{{#if model.length}}
|
||||
<table class='table staff-actions'>
|
||||
<thead>
|
||||
<th class="action">{{i18n admin.logs.action}}</th>
|
||||
<th class="staff_user">{{i18n admin.logs.staff_actions.staff_user}}</th>
|
||||
<th class="target_user">{{i18n admin.logs.staff_actions.target_user}}</th>
|
||||
<th class="context">{{i18n admin.logs.staff_actions.context}}</th>
|
||||
<th class="created_at">{{i18n admin.logs.created_at}}</th>
|
||||
<th class="details">{{i18n admin.logs.staff_actions.details}}</th>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{#each model}}
|
||||
<tr>
|
||||
<td class="action">{{actionName}}</td>
|
||||
<td class="staff_user">
|
||||
{{#linkTo 'adminUser' staff_user}}{{avatar staff_user imageSize="tiny"}}{{/linkTo}}
|
||||
{{#linkTo 'adminUser' staff_user}}{{staff_user.username}}{{/linkTo}}
|
||||
</td>
|
||||
<td class="target_user">
|
||||
{{#if target_user}}
|
||||
{{#linkTo 'adminUser' target_user}}{{avatar target_user imageSize="tiny"}}{{/linkTo}}
|
||||
{{#linkTo 'adminUser' target_user}}{{target_user.username}}{{/linkTo}}
|
||||
{{else}}
|
||||
—
|
||||
{{/if}}
|
||||
</td>
|
||||
<td class="context">{{context}}</td>
|
||||
<td class="created_at">{{unboundAgeWithTooltip created_at}}</td>
|
||||
<td class="details">
|
||||
{{{formattedDetails}}}
|
||||
{{#if showFullDetails}}
|
||||
{{details}}
|
||||
<br/>
|
||||
<a {{action toggleFullDetails this}}>Less</a>
|
||||
{{else}}
|
||||
<a {{action toggleFullDetails this}}>More</a>
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
No results.
|
||||
{{/if}}
|
||||
{{/if}}
|
|
@ -700,4 +700,22 @@ table {
|
|||
.match_count, .last_match_at, .created_at {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.staff-actions {
|
||||
.action {
|
||||
width: 120px;
|
||||
}
|
||||
.staff_user, .target_user {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.created_at {
|
||||
text-align: center;
|
||||
}
|
||||
.details {
|
||||
width: 500px;
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
8
app/controllers/admin/staff_action_logs_controller.rb
Normal file
8
app/controllers/admin/staff_action_logs_controller.rb
Normal file
|
@ -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
|
15
app/serializers/staff_action_log_serializer.rb
Normal file
15
app/serializers/staff_action_log_serializer.rb
Normal file
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
22
spec/controllers/admin/staff_action_logs_controller_spec.rb
Normal file
22
spec/controllers/admin/staff_action_logs_controller_spec.rb
Normal file
|
@ -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
|
Loading…
Reference in New Issue
Block a user