mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 23:58:31 -05:00
Log site customization changes. Use a modal to show staff action log details for site customizations.
This commit is contained in:
parent
7f69a58439
commit
a95303fcd8
16 changed files with 202 additions and 8 deletions
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
The modal for viewing the details of a staff action log record.
|
||||
|
||||
@class ChangeSiteCustomizationDetailsController
|
||||
@extends Discourse.Controller
|
||||
@namespace Discourse
|
||||
@uses Discourse.ModalFunctionality
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ChangeSiteCustomizationDetailsController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
||||
previousSelected: Ember.computed.equal('selectedTab', 'previous'),
|
||||
newSelected: Ember.computed.equal('selectedTab', 'new'),
|
||||
|
||||
onShow: function() {
|
||||
this.selectNew();
|
||||
},
|
||||
|
||||
selectNew: function() {
|
||||
this.set('selectedTab', 'new');
|
||||
},
|
||||
|
||||
selectPrevious: function() {
|
||||
this.set('selectedTab', 'previous');
|
||||
}
|
||||
});
|
|
@ -17,8 +17,10 @@ Discourse.StaffActionLog = Discourse.Model.extend({
|
|||
var formatted = "";
|
||||
formatted += this.format('email', 'email');
|
||||
formatted += this.format('admin.logs.staff_actions.ip_address', 'ip_address');
|
||||
if (!this.get('useModalForDetails')) {
|
||||
formatted += this.format('admin.logs.staff_actions.new_value', 'new_value');
|
||||
formatted += this.format('admin.logs.staff_actions.previous_value', 'previous_value');
|
||||
}
|
||||
return formatted;
|
||||
}.property('ip_address', 'email'),
|
||||
|
||||
|
@ -28,7 +30,11 @@ Discourse.StaffActionLog = Discourse.Model.extend({
|
|||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
useModalForDetails: function() {
|
||||
return (this.get('action_name') === 'change_site_customization');
|
||||
}.property('action_name')
|
||||
});
|
||||
|
||||
Discourse.StaffActionLog.reopenClass({
|
||||
|
|
|
@ -33,6 +33,13 @@ Discourse.AdminLogsStaffActionLogsRoute = Discourse.Route.extend({
|
|||
return controller.show();
|
||||
},
|
||||
|
||||
events: {
|
||||
showDetailsModal: function(logRecord) {
|
||||
Discourse.Route.showModal(this, logRecord.action_name + '_details', logRecord);
|
||||
this.controllerFor('modal').set('modalClass', 'tabbed-modal log-details-modal');
|
||||
}
|
||||
},
|
||||
|
||||
deactivate: function() {
|
||||
this._super();
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<section class="field">
|
||||
<b>{{i18n admin.customize.css}}</b>: ({{i18n character_count count=stylesheet.length}})<br/>
|
||||
{{textarea value=stylesheet class="plain"}}
|
||||
</section>
|
||||
<section class="field">
|
||||
<b>{{i18n admin.customize.header}}</b>: ({{i18n character_count count=header.length}})<br/>
|
||||
{{textarea value=header class="plain"}}
|
||||
</section>
|
||||
<section class="field">
|
||||
<b>{{i18n admin.customize.enabled}}</b>: {{enabled}}
|
||||
</section>
|
||||
<section class="field">
|
||||
<b>{{i18n admin.customize.override_default}}</b>: {{override_default_style}}
|
||||
</section>
|
|
@ -0,0 +1,29 @@
|
|||
<div>
|
||||
<ul class="nav nav-pills">
|
||||
<li {{bindAttr class="newSelected:active"}}>
|
||||
<a href="#" {{action selectNew}}>{{i18n admin.logs.staff_actions.new_value}}</a>
|
||||
</li>
|
||||
<li {{bindAttr class="previousSelected:active"}}>
|
||||
<a href="#" {{action selectPrevious}}>{{i18n admin.logs.staff_actions.previous_value}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="modal-body">
|
||||
<div {{bindAttr class=":modal-tab :new-tab newSelected::invisible"}}>
|
||||
{{#with new_value}}
|
||||
{{partial "admin/templates/logs/site_customization_change_details"}}
|
||||
{{/with}}
|
||||
</div>
|
||||
<div {{bindAttr class=":modal-tab :previous-tab previousSelected::invisible"}}>
|
||||
{{#if previous_value}}
|
||||
{{#with previous_value}}
|
||||
{{partial "admin/templates/logs/site_customization_change_details"}}
|
||||
{{/with}}
|
||||
{{else}}
|
||||
{{i18n admin.logs.staff_actions.no_previous}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' {{action closeModal}}>{{i18n close}}</button>
|
||||
</div>
|
||||
</div>
|
|
@ -17,12 +17,16 @@
|
|||
<div class="col value created_at">{{unboundAgeWithTooltip created_at}}</div>
|
||||
<div class="col value details">
|
||||
{{{formattedDetails}}}
|
||||
{{#if useModalForDetails}}
|
||||
<a {{action showDetailsModal this}}>{{i18n admin.logs.staff_actions.show}}</a>
|
||||
{{else}}
|
||||
{{#if showFullDetails}}
|
||||
<a {{action toggleFullDetails this}}>{{i18n less}}</a><br/>
|
||||
{{details}}
|
||||
{{else}}
|
||||
<a {{action toggleFullDetails this}}>{{i18n more}}</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="col value context">{{context}}</div>
|
||||
<div class="clearfix"></div>
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
A modal view for details of a staff action log record in a modal.
|
||||
|
||||
@class ChangeSiteCustomizationDetailsView
|
||||
@extends Discourse.ModalBodyView
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ChangeSiteCustomizationDetailsView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'admin/templates/logs/site_customization_change_modal',
|
||||
title: I18n.t('admin.logs.staff_actions.modal_title')
|
||||
});
|
|
@ -806,3 +806,9 @@ table {
|
|||
border-top: solid 1px #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
.log-details-modal {
|
||||
.modal-tab {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
|
@ -253,6 +253,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.tabbed-modal {
|
||||
.modal-body {
|
||||
position: relative;
|
||||
height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-tab {
|
||||
position: absolute;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ class Admin::SiteCustomizationsController < Admin::AdminController
|
|||
|
||||
respond_to do |format|
|
||||
if @site_customization.save
|
||||
log_site_customization_change(nil, site_customization_params)
|
||||
format.json { render json: @site_customization, status: :created}
|
||||
else
|
||||
format.json { render json: @site_customization.errors, status: :unprocessable_entity }
|
||||
|
@ -23,11 +24,13 @@ class Admin::SiteCustomizationsController < Admin::AdminController
|
|||
|
||||
def update
|
||||
@site_customization = SiteCustomization.find(params[:id])
|
||||
log_record = log_site_customization_change(@site_customization, site_customization_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @site_customization.update_attributes(site_customization_params)
|
||||
format.json { head :no_content }
|
||||
else
|
||||
log_record.destroy if log_record
|
||||
format.json { render json: @site_customization.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
|
@ -37,6 +40,8 @@ class Admin::SiteCustomizationsController < Admin::AdminController
|
|||
@site_customization = SiteCustomization.find(params[:id])
|
||||
@site_customization.destroy
|
||||
|
||||
# TODO: log this
|
||||
|
||||
respond_to do |format|
|
||||
format.json { head :no_content }
|
||||
end
|
||||
|
@ -48,4 +53,8 @@ class Admin::SiteCustomizationsController < Admin::AdminController
|
|||
params.require(:site_customization).permit(:name, :stylesheet, :header, :position, :enabled, :key, :override_default_style, :stylesheet_baked)
|
||||
end
|
||||
|
||||
def log_site_customization_change(old_record, new_params)
|
||||
StaffActionLogger.new(current_user).log_site_customization_change(old_record, new_params)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ class StaffActionLog < ActiveRecord::Base
|
|||
validates_presence_of :action
|
||||
|
||||
def self.actions
|
||||
@actions ||= Enum.new(:delete_user, :change_trust_level, :change_site_setting)
|
||||
@actions ||= Enum.new(:delete_user, :change_trust_level, :change_site_setting, :change_site_customization)
|
||||
end
|
||||
|
||||
def self.with_filters(filters)
|
||||
|
@ -25,6 +25,14 @@ class StaffActionLog < ActiveRecord::Base
|
|||
query = query.where("subject = ?", filters[:subject]) if filters[:subject]
|
||||
query
|
||||
end
|
||||
|
||||
def new_value_is_json?
|
||||
action == StaffActionLog.actions[:change_site_customization]
|
||||
end
|
||||
|
||||
def previous_value_is_json?
|
||||
new_value_is_json?
|
||||
end
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
|
|
|
@ -15,4 +15,20 @@ class StaffActionLogSerializer < ApplicationSerializer
|
|||
def action_name
|
||||
StaffActionLog.actions.key(object.action).to_s
|
||||
end
|
||||
|
||||
def new_value
|
||||
if object.new_value
|
||||
object.new_value_is_json? ? ::JSON.parse(object.new_value) : object.new_value
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def previous_value
|
||||
if object.previous_value
|
||||
object.previous_value_is_json? ? ::JSON.parse(object.previous_value) : object.previous_value
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -37,6 +37,17 @@ class StaffActionLogger
|
|||
}))
|
||||
end
|
||||
|
||||
def log_site_customization_change(old_record, site_customization_params, opts={})
|
||||
raise Discourse::InvalidParameters.new('site_customization_params is nil') unless site_customization_params
|
||||
logged_attrs = ['stylesheet', 'header', 'position', 'enabled', 'key', 'override_default_style']
|
||||
StaffActionLog.create( params(opts).merge({
|
||||
action: StaffActionLog.actions[:change_site_customization],
|
||||
subject: site_customization_params[:name],
|
||||
previous_value: old_record ? old_record.attributes.slice(*logged_attrs).to_json : nil,
|
||||
new_value: site_customization_params.slice(*(logged_attrs.map(&:to_sym))).to_json
|
||||
}))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def params(opts)
|
||||
|
|
|
@ -100,6 +100,9 @@ en:
|
|||
read_more: 'read more'
|
||||
more: "More"
|
||||
less: "Less"
|
||||
character_count:
|
||||
one: "{{count}} character"
|
||||
other: "{{count}} characters"
|
||||
|
||||
in_n_seconds:
|
||||
one: "in 1 second"
|
||||
|
@ -1196,10 +1199,15 @@ en:
|
|||
ip_address: "IP"
|
||||
previous_value: "Previous"
|
||||
new_value: "New"
|
||||
diff: "Diff"
|
||||
show: "Show"
|
||||
modal_title: "Details"
|
||||
no_previous: "There is no previous value."
|
||||
actions:
|
||||
delete_user: "delete user"
|
||||
change_trust_level: "change trust level"
|
||||
change_site_setting: "change site setting"
|
||||
change_site_customization: "change site customization"
|
||||
screened_emails:
|
||||
title: "Screened Emails"
|
||||
description: "When someone tries to create a new account, the following email addresses will be checked and the registration will be blocked, or some other action performed."
|
||||
|
|
|
@ -34,6 +34,11 @@ describe Admin::SiteCustomizationsController do
|
|||
xhr :post, :create, site_customization: {name: 'my test name'}
|
||||
::JSON.parse(response.body).should be_present
|
||||
end
|
||||
|
||||
it 'logs the change' do
|
||||
StaffActionLogger.any_instance.expects(:log_site_customization_change).once
|
||||
xhr :post, :create, site_customization: {name: 'my test name'}
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -73,4 +73,31 @@ describe StaffActionLogger do
|
|||
expect { logger.log_site_setting_change('title', 'Discourse', 'My Site') }.to change { StaffActionLog.count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe "log_site_customization_change" do
|
||||
let(:valid_params) { {name: 'Cool Theme', stylesheet: "body {\n background-color: blue;\n}\n", header: "h1 {color: white;}"} }
|
||||
|
||||
it "raises an error when params are invalid" do
|
||||
expect { logger.log_site_customization_change(nil, nil) }.to raise_error(Discourse::InvalidParameters)
|
||||
end
|
||||
|
||||
it "logs new site customizations" do
|
||||
log_record = logger.log_site_customization_change(nil, valid_params)
|
||||
log_record.subject.should == valid_params[:name]
|
||||
log_record.previous_value.should be_nil
|
||||
log_record.new_value.should be_present
|
||||
json = ::JSON.parse(log_record.new_value)
|
||||
json['stylesheet'].should be_present
|
||||
json['header'].should be_present
|
||||
end
|
||||
|
||||
it "logs updated site customizations" do
|
||||
existing = SiteCustomization.new(name: 'Banana', stylesheet: "body {color: yellow;}", header: "h1 {color: brown;}")
|
||||
log_record = logger.log_site_customization_change(existing, valid_params)
|
||||
log_record.previous_value.should be_present
|
||||
json = ::JSON.parse(log_record.previous_value)
|
||||
json['stylesheet'].should == existing.stylesheet
|
||||
json['header'].should == existing.header
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue