Code to support EmberJS + Discourse Tutorial feature: Admin Reports
This commit is contained in:
parent
416f981f92
commit
dc8e1196fd
11 changed files with 213 additions and 0 deletions
app
assets/javascripts/admin
controllers/admin
models
config
spec
15
app/assets/javascripts/admin/models/report.js
Normal file
15
app/assets/javascripts/admin/models/report.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
Discourse.Report = Discourse.Model.extend({});
|
||||||
|
|
||||||
|
Discourse.Report.reopenClass({
|
||||||
|
find: function(type) {
|
||||||
|
var model = Discourse.Report.create();
|
||||||
|
jQuery.ajax("/admin/reports/" + type, {
|
||||||
|
type: 'GET',
|
||||||
|
success: function(json) {
|
||||||
|
model.mergeAttributes(json.report);
|
||||||
|
model.set('loaded', true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return(model);
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
Discourse.AdminReportsRoute = Discourse.Route.extend({
|
||||||
|
model: function(params) {
|
||||||
|
return(Discourse.Report.find(params.type));
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTemplate: function() {
|
||||||
|
this.render('admin/templates/reports', {into: 'admin/templates/admin'});
|
||||||
|
}
|
||||||
|
});
|
|
@ -11,6 +11,8 @@ Discourse.Route.buildRoutes(function() {
|
||||||
this.route('email_logs', { path: '/email_logs' });
|
this.route('email_logs', { path: '/email_logs' });
|
||||||
this.route('customize', { path: '/customize' });
|
this.route('customize', { path: '/customize' });
|
||||||
|
|
||||||
|
this.resource('adminReports', { path: '/reports/:type' });
|
||||||
|
|
||||||
this.resource('adminFlags', { path: '/flags' }, function() {
|
this.resource('adminFlags', { path: '/flags' }, function() {
|
||||||
this.route('active', { path: '/active' });
|
this.route('active', { path: '/active' });
|
||||||
this.route('old', { path: '/old' });
|
this.route('old', { path: '/old' });
|
||||||
|
|
20
app/assets/javascripts/admin/templates/reports.js.handlebars
Normal file
20
app/assets/javascripts/admin/templates/reports.js.handlebars
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{{#if content.loaded}}
|
||||||
|
<h3>{{content.title}}</h3>
|
||||||
|
|
||||||
|
<table class='table'>
|
||||||
|
<tr>
|
||||||
|
<th>{{content.xaxis}}</th>
|
||||||
|
<th>{{content.yaxis}}</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{{#each content.data}}
|
||||||
|
<tr>
|
||||||
|
<td>{{x}}</td>
|
||||||
|
<td>{{y}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
{{i18n loading}}
|
||||||
|
{{/if}}
|
17
app/controllers/admin/reports_controller.rb
Normal file
17
app/controllers/admin/reports_controller.rb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
require_dependency 'report'
|
||||||
|
|
||||||
|
class Admin::ReportsController < Admin::AdminController
|
||||||
|
|
||||||
|
def show
|
||||||
|
|
||||||
|
report_type = params[:type]
|
||||||
|
|
||||||
|
raise Discourse::NotFound.new unless report_type =~ /^[a-z0-9\_]+$/
|
||||||
|
|
||||||
|
report = Report.find(report_type)
|
||||||
|
raise Discourse::NotFound.new if report.blank?
|
||||||
|
|
||||||
|
render_json_dump(report: report)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
37
app/models/report.rb
Normal file
37
app/models/report.rb
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
class Report
|
||||||
|
|
||||||
|
attr_accessor :type, :data
|
||||||
|
|
||||||
|
def initialize(type)
|
||||||
|
@type = type
|
||||||
|
@data = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
{
|
||||||
|
type: self.type,
|
||||||
|
title: I18n.t("reports.#{self.type}.title"),
|
||||||
|
xaxis: I18n.t("reports.#{self.type}.xaxis"),
|
||||||
|
yaxis: I18n.t("reports.#{self.type}.yaxis"),
|
||||||
|
data: self.data
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.find(type)
|
||||||
|
report_method = :"report_#{type}"
|
||||||
|
return nil unless respond_to?(report_method)
|
||||||
|
|
||||||
|
# Load the report
|
||||||
|
report = Report.new(type)
|
||||||
|
send(report_method, report)
|
||||||
|
report
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.report_visits(report)
|
||||||
|
report.data = []
|
||||||
|
UserVisit.by_day.each do |date, count|
|
||||||
|
report.data << {x: date, y: count}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -1,3 +1,9 @@
|
||||||
class UserVisit < ActiveRecord::Base
|
class UserVisit < ActiveRecord::Base
|
||||||
attr_accessible :visited_at, :user_id
|
attr_accessible :visited_at, :user_id
|
||||||
|
|
||||||
|
# A list of visits in the last month by day
|
||||||
|
def self.by_day
|
||||||
|
where("visited_at > ?", 1.month.ago).group(:visited_at).order(:visited_at).count
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -230,6 +230,12 @@ en:
|
||||||
title: "Re-Subscribed!"
|
title: "Re-Subscribed!"
|
||||||
description: "You have been re-subscribed."
|
description: "You have been re-subscribed."
|
||||||
|
|
||||||
|
reports:
|
||||||
|
visits:
|
||||||
|
title: "Users Visits by Day"
|
||||||
|
xaxis: "Day"
|
||||||
|
yaxis: "Visits"
|
||||||
|
|
||||||
site_settings:
|
site_settings:
|
||||||
min_post_length: "Minimum post length in characters"
|
min_post_length: "Minimum post length in characters"
|
||||||
max_post_length: "Maximum post length in characters"
|
max_post_length: "Maximum post length in characters"
|
||||||
|
|
|
@ -24,6 +24,8 @@ Discourse::Application.routes.draw do
|
||||||
get '' => 'admin#index'
|
get '' => 'admin#index'
|
||||||
|
|
||||||
resources :site_settings
|
resources :site_settings
|
||||||
|
get 'reports/:type' => 'reports#show'
|
||||||
|
|
||||||
resources :users, id: USERNAME_ROUTE_FORMAT do
|
resources :users, id: USERNAME_ROUTE_FORMAT do
|
||||||
collection do
|
collection do
|
||||||
get 'list/:query' => 'users#index'
|
get 'list/:query' => 'users#index'
|
||||||
|
|
65
spec/controllers/admin/reports_controller_spec.rb
Normal file
65
spec/controllers/admin/reports_controller_spec.rb
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Admin::ReportsController do
|
||||||
|
|
||||||
|
it "is a subclass of AdminController" do
|
||||||
|
(Admin::ReportsController < Admin::AdminController).should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'while logged in as an admin' do
|
||||||
|
let!(:admin) { log_in(:admin) }
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
|
||||||
|
context '.show' do
|
||||||
|
|
||||||
|
context "invalid id form" do
|
||||||
|
let(:invalid_id) { "!!&asdfasdf" }
|
||||||
|
|
||||||
|
it "never calls Report.find" do
|
||||||
|
Report.expects(:find).never
|
||||||
|
xhr :get, :show, type: invalid_id
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns 404" do
|
||||||
|
xhr :get, :show, type: invalid_id
|
||||||
|
response.status.should == 404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "valid type form" do
|
||||||
|
|
||||||
|
context 'missing report' do
|
||||||
|
before do
|
||||||
|
Report.expects(:find).with('active').returns(nil)
|
||||||
|
xhr :get, :show, type: 'active'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "renders the report as JSON" do
|
||||||
|
response.status.should == 404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'a report is found' do
|
||||||
|
before do
|
||||||
|
Report.expects(:find).with('active').returns(Report.new('active'))
|
||||||
|
xhr :get, :show, type: 'active'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "renders the report as JSON" do
|
||||||
|
response.should be_success
|
||||||
|
end
|
||||||
|
|
||||||
|
it "renders the report as JSON" do
|
||||||
|
::JSON.parse(response.body).should be_present
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
34
spec/models/report_spec.rb
Normal file
34
spec/models/report_spec.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Report do
|
||||||
|
|
||||||
|
|
||||||
|
describe 'visits report' do
|
||||||
|
|
||||||
|
let(:report) { Report.find('visits') }
|
||||||
|
|
||||||
|
context "no visits" do
|
||||||
|
it "returns an empty report" do
|
||||||
|
report.data.should be_blank
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with visits" do
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
user.user_visits.create(visited_at: 1.day.ago)
|
||||||
|
user.user_visits.create(visited_at: 2.days.ago)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a report with data" do
|
||||||
|
report.data.should be_present
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
Reference in a new issue