Code to support EmberJS + Discourse Tutorial feature: Admin Reports

This commit is contained in:
Robin Ward 2013-02-27 22:39:42 -05:00
parent 416f981f92
commit dc8e1196fd
11 changed files with 213 additions and 0 deletions

View 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);
}
});

View File

@ -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'});
}
});

View File

@ -11,6 +11,8 @@ Discourse.Route.buildRoutes(function() {
this.route('email_logs', { path: '/email_logs' });
this.route('customize', { path: '/customize' });
this.resource('adminReports', { path: '/reports/:type' });
this.resource('adminFlags', { path: '/flags' }, function() {
this.route('active', { path: '/active' });
this.route('old', { path: '/old' });

View 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}}

View 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
View 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

View File

@ -1,3 +1,9 @@
class UserVisit < ActiveRecord::Base
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

View File

@ -230,6 +230,12 @@ en:
title: "Re-Subscribed!"
description: "You have been re-subscribed."
reports:
visits:
title: "Users Visits by Day"
xaxis: "Day"
yaxis: "Visits"
site_settings:
min_post_length: "Minimum post length in characters"
max_post_length: "Maximum post length in characters"

View File

@ -24,6 +24,8 @@ Discourse::Application.routes.draw do
get '' => 'admin#index'
resources :site_settings
get 'reports/:type' => 'reports#show'
resources :users, id: USERNAME_ROUTE_FORMAT do
collection do
get 'list/:query' => 'users#index'

View 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

View 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