From 25073e873f66cb1c37131617a28d78a1c8931f83 Mon Sep 17 00:00:00 2001
From: Neil Lalonde <neillalonde@gmail.com>
Date: Fri, 29 Mar 2013 15:48:26 -0400
Subject: [PATCH] Fetch the list of problems more frequently on the admin
 dashboard

---
 .../admin/models/admin_dashboard.js           | 36 +++++++++++++++++++
 .../admin/routes/admin_dashboard_route.js     |  7 ++++
 app/controllers/admin/dashboard_controller.rb |  5 ++-
 app/models/admin_dashboard_data.rb            | 12 +++++--
 config/routes.rb                              |  6 +++-
 .../admin/dashboard_controller_spec.rb        | 34 ++++++++++++++++++
 6 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/app/assets/javascripts/admin/models/admin_dashboard.js b/app/assets/javascripts/admin/models/admin_dashboard.js
index 453b9dd16..fb663c42e 100644
--- a/app/assets/javascripts/admin/models/admin_dashboard.js
+++ b/app/assets/javascripts/admin/models/admin_dashboard.js
@@ -1,6 +1,23 @@
+/**
+  A model that stores all or some data that is displayed on the dashboard.
+
+  @class AdminDashboard
+  @extends Discourse.Model
+  @namespace Discourse
+  @module Discourse
+**/
+
 Discourse.AdminDashboard = Discourse.Model.extend({});
 
 Discourse.AdminDashboard.reopenClass({
+
+  /**
+    Fetch all dashboard data. This can be an expensive request when the cached data
+    has expired and the server must collect the data again.
+
+    @method find
+    @return {jqXHR} a jQuery Promise object
+  **/
   find: function() {
     var model = Discourse.AdminDashboard.create();
     return $.ajax(Discourse.getURL("/admin/dashboard"), {
@@ -11,5 +28,24 @@ Discourse.AdminDashboard.reopenClass({
         model.set('loaded', true);
       }
     });
+  },
+
+  /**
+    Only fetch the list of problems that should be rendered on the dashboard.
+    The model will only have its "problems" attribute set.
+
+    @method fetchProblems
+    @return {jqXHR} a jQuery Promise object
+  **/
+  fetchProblems: function() {
+    var model = Discourse.AdminDashboard.create();
+    return $.ajax(Discourse.getURL("/admin/dashboard/problems"), {
+      type: 'GET',
+      dataType: 'json',
+      success: function(json) {
+        model.mergeAttributes(json);
+        model.set('loaded', true);
+      }
+    });
   }
 });
diff --git a/app/assets/javascripts/admin/routes/admin_dashboard_route.js b/app/assets/javascripts/admin/routes/admin_dashboard_route.js
index 34c9b3383..8024edc75 100644
--- a/app/assets/javascripts/admin/routes/admin_dashboard_route.js
+++ b/app/assets/javascripts/admin/routes/admin_dashboard_route.js
@@ -19,6 +19,7 @@ Discourse.AdminDashboardRoute = Discourse.Route.extend({
   fetchDashboardData: function(c) {
     if( !c.get('dashboardFetchedAt') || Date.create('1 hour ago', 'en') > c.get('dashboardFetchedAt') ) {
       c.set('dashboardFetchedAt', new Date());
+      c.set('problemsFetchedAt', new Date());
       Discourse.AdminDashboard.find().then(function(d) {
         if( Discourse.SiteSettings.version_checks ){
           c.set('versionCheck', Discourse.VersionCheck.create(d.version_check));
@@ -31,6 +32,12 @@ Discourse.AdminDashboardRoute = Discourse.Route.extend({
         c.set('problems', d.problems);
         c.set('loading', false);
       });
+    } else if( !c.get('problemsFetchedAt') || Date.create('1 minute ago', 'en') > c.get('problemsFetchedAt') ) {
+      c.set('problemsFetchedAt', new Date());
+      Discourse.AdminDashboard.fetchProblems().then(function(d) {
+        c.set('problems', d.problems);
+        c.set('loading', false);
+      });
     }
   },
 
diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb
index 95f524779..2b7c74f6b 100644
--- a/app/controllers/admin/dashboard_controller.rb
+++ b/app/controllers/admin/dashboard_controller.rb
@@ -3,7 +3,10 @@ class Admin::DashboardController < Admin::AdminController
   caches_action :index, expires_in: 1.hour
 
   def index
-    render_json_dump(AdminDashboardData.fetch)
+    render_json_dump(AdminDashboardData.fetch_all)
   end
 
+  def problems
+    render_json_dump({problems: AdminDashboardData.fetch_problems})
+  end
 end
\ No newline at end of file
diff --git a/app/models/admin_dashboard_data.rb b/app/models/admin_dashboard_data.rb
index 59a1703bc..b35ee4998 100644
--- a/app/models/admin_dashboard_data.rb
+++ b/app/models/admin_dashboard_data.rb
@@ -4,14 +4,18 @@ class AdminDashboardData
 
   REPORTS = ['visits', 'signups', 'topics', 'posts', 'flags', 'users_by_trust_level', 'likes', 'emails']
 
-  def self.fetch
+  def self.fetch_all
     AdminDashboardData.new
   end
 
+  def self.fetch_problems
+    AdminDashboardData.new.problems
+  end
+
   def as_json
     @json ||= {
       reports: REPORTS.map { |type| Report.find(type) },
-      problems: [rails_env_check, host_names_check, gc_checks, sidekiq_check || clockwork_check, ram_check, facebook_config_check, twitter_config_check, github_config_check].compact,
+      problems: problems,
       admins: User.admins.count,
       moderators: User.moderators.count
     }.merge(
@@ -19,6 +23,10 @@ class AdminDashboardData
     )
   end
 
+  def problems
+    [rails_env_check, host_names_check, gc_checks, sidekiq_check || clockwork_check, ram_check, facebook_config_check, twitter_config_check, github_config_check].compact
+  end
+
   def rails_env_check
     I18n.t("dashboard.rails_env_warning", env: Rails.env) unless Rails.env == 'production'
   end
diff --git a/config/routes.rb b/config/routes.rb
index f6bac25af..3fe0d6270 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -56,7 +56,11 @@ Discourse::Application.routes.draw do
     resources :site_customizations
     resources :export
     get 'version_check' => 'versions#show'
-    resources :dashboard, only: [:index]
+    resources :dashboard, only: [:index] do
+      collection do
+        get 'problems'
+      end
+    end
     resources :api, only: [:index] do
       collection do
         post 'generate_key'
diff --git a/spec/controllers/admin/dashboard_controller_spec.rb b/spec/controllers/admin/dashboard_controller_spec.rb
index 6a3234351..a54bd6ea5 100644
--- a/spec/controllers/admin/dashboard_controller_spec.rb
+++ b/spec/controllers/admin/dashboard_controller_spec.rb
@@ -46,5 +46,39 @@ describe Admin::DashboardController do
         json['reports'].should be_a(Array)
       end
     end
+
+    context '.problems' do
+      it 'should be successful' do
+        AdminDashboardData.stubs(:fetch_problems).returns([])
+        xhr :get, :problems
+        response.should be_successful
+      end
+
+      context 'when there are no problems' do
+        before do
+          AdminDashboardData.stubs(:fetch_problems).returns([])
+        end
+
+        it 'returns an empty array' do
+          xhr :get, :problems
+          json = JSON.parse(response.body)
+          json['problems'].should have(0).problems
+        end
+      end
+
+      context 'when there are problems' do
+        before do
+          AdminDashboardData.stubs(:fetch_problems).returns(['Not enough awesome', 'Too much sass'])
+        end
+
+        it 'returns an array of strings' do
+          xhr :get, :problems
+          json = JSON.parse(response.body)
+          json['problems'].should have(2).problems
+          json['problems'][0].should be_a(String)
+          json['problems'][1].should be_a(String)
+        end
+      end
+    end
   end
 end
\ No newline at end of file