diff --git a/app/assets/javascripts/admin/controllers/admin_dashboard_controller.js b/app/assets/javascripts/admin/controllers/admin_dashboard_controller.js
index 3bfacd35c68..5dc03a709ba 100644
--- a/app/assets/javascripts/admin/controllers/admin_dashboard_controller.js
+++ b/app/assets/javascripts/admin/controllers/admin_dashboard_controller.js
@@ -42,5 +42,9 @@ Discourse.AdminDashboardController = Ember.Controller.extend({
problemsTimestamp: function() {
return moment(this.get('problemsFetchedAt')).format('LLL');
- }.property('problemsFetchedAt')
+ }.property('problemsFetchedAt'),
+
+ updatedTimestamp: function() {
+ return moment(this.get('updated_at')).format('LLL');
+ }.property('updated_at')
});
diff --git a/app/assets/javascripts/admin/routes/admin_dashboard_route.js b/app/assets/javascripts/admin/routes/admin_dashboard_route.js
index fb3562bc5e5..8af0dab4bee 100644
--- a/app/assets/javascripts/admin/routes/admin_dashboard_route.js
+++ b/app/assets/javascripts/admin/routes/admin_dashboard_route.js
@@ -14,7 +14,7 @@ Discourse.AdminDashboardRoute = Discourse.Route.extend({
},
fetchDashboardData: function(c) {
- if( !c.get('dashboardFetchedAt') || moment().subtract('hour', 1).toDate() > c.get('dashboardFetchedAt') ) {
+ if( !c.get('dashboardFetchedAt') || moment().subtract('minutes', 30).toDate() > c.get('dashboardFetchedAt') ) {
c.set('dashboardFetchedAt', new Date());
Discourse.AdminDashboard.find().then(function(d) {
if( Discourse.SiteSettings.version_checks ){
@@ -32,7 +32,7 @@ Discourse.AdminDashboardRoute = Discourse.Route.extend({
c.set('top_referrers', topReferrers);
}
- ['admins', 'moderators', 'blocked', 'banned', 'top_traffic_sources', 'top_referred_topics'].forEach(function(x) {
+ ['admins', 'moderators', 'blocked', 'banned', 'top_traffic_sources', 'top_referred_topics', 'updated_at'].forEach(function(x) {
c.set(x, d[x]);
});
diff --git a/app/assets/javascripts/admin/templates/dashboard.js.handlebars b/app/assets/javascripts/admin/templates/dashboard.js.handlebars
index 7c90503fdc0..e3e57f9e7fd 100644
--- a/app/assets/javascripts/admin/templates/dashboard.js.handlebars
+++ b/app/assets/javascripts/admin/templates/dashboard.js.handlebars
@@ -276,3 +276,9 @@
+
+
+
{{i18n admin.dashboard.last_updated}} {{updatedTimestamp}}
+
+
+
\ No newline at end of file
diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb
index 1b46c082e2d..b27a1d04a20 100644
--- a/app/controllers/admin/dashboard_controller.rb
+++ b/app/controllers/admin/dashboard_controller.rb
@@ -1,9 +1,6 @@
class Admin::DashboardController < Admin::AdminController
-
def index
- dashboard_data = Rails.cache.fetch("admin-dashboard-data-#{Discourse::VERSION::STRING}", expires_in: 1.hour) do
- AdminDashboardData.fetch_all.as_json
- end
+ dashboard_data = AdminDashboardData.fetch_cached_stats || Jobs::DashboardStats.new.execute({})
dashboard_data.merge!({version_check: DiscourseUpdates.check_version.as_json}) if SiteSetting.version_checks?
render json: dashboard_data
end
diff --git a/app/models/admin_dashboard_data.rb b/app/models/admin_dashboard_data.rb
index 02581e9bf0a..5c2c47fc64f 100644
--- a/app/models/admin_dashboard_data.rb
+++ b/app/models/admin_dashboard_data.rb
@@ -41,9 +41,17 @@ class AdminDashboardData
notification_email_check ].compact
end
- def self.fetch_all
+ def self.fetch_stats
AdminDashboardData.new
end
+ def self.fetch_cached_stats
+ # The DashboardStats job is responsible for generating and caching this.
+ stats = $redis.get(stats_cache_key)
+ stats ? JSON.parse(stats) : nil
+ end
+ def self.stats_cache_key
+ 'dash-stats'
+ end
def self.fetch_problems
AdminDashboardData.new.problems
@@ -58,10 +66,16 @@ class AdminDashboardData
blocked: User.blocked.count,
top_referrers: IncomingLinksReport.find('top_referrers').as_json,
top_traffic_sources: IncomingLinksReport.find('top_traffic_sources').as_json,
- top_referred_topics: IncomingLinksReport.find('top_referred_topics').as_json
+ top_referred_topics: IncomingLinksReport.find('top_referred_topics').as_json,
+ updated_at: Time.zone.now.as_json
}
end
+ def self.recalculate_interval
+ # Could be configurable, but clockwork + multisite need to support it.
+ 30 # minutes
+ end
+
def rails_env_check
I18n.t("dashboard.rails_env_warning", env: Rails.env) unless Rails.env == 'production'
end
diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb
index 6f027adb77a..2dcf0ad07dc 100644
--- a/app/models/site_setting.rb
+++ b/app/models/site_setting.rb
@@ -239,6 +239,7 @@ class SiteSetting < ActiveRecord::Base
setting(:delete_user_max_age, 7)
setting(:delete_all_posts_max, 10)
+
def self.generate_api_key!
self.api_key = SecureRandom.hex(32)
end
diff --git a/config/clock.rb b/config/clock.rb
index db7907fa80e..0272fd8ff40 100644
--- a/config/clock.rb
+++ b/config/clock.rb
@@ -35,5 +35,5 @@ module Clockwork
every(1.minute, 'clockwork_heartbeat')
every(1.minute, 'poll_mailbox')
every(30.minutes, 'destroy_old_deletion_stubs')
-
+ every(AdminDashboardData.recalculate_interval.minutes, 'dashboard_stats')
end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index bff82b261c5..81aa002adf2 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1027,6 +1027,7 @@ en:
dashboard:
title: "Dashboard"
+ last_updated: "Dashboard last updated:"
version: "Version"
up_to_date: "You're up to date!"
critical_available: "A critical update is available."
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 4bcd24329ac..3fae19782d1 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -663,7 +663,6 @@ en:
delete_user_max_age: "The maximum age of a user, in days, which can be deleted by an admin."
delete_all_posts_max: "The maximum number of posts that can be deleted at once with the Delete All Posts button. If a user has more than this many posts, the posts cannot all be deleted at once and the user can't be deleted."
-
notification_types:
mentioned: "%{display_username} mentioned you in %{link}"
liked: "%{display_username} liked your post in %{link}"
diff --git a/lib/jobs/dashboard_stats.rb b/lib/jobs/dashboard_stats.rb
new file mode 100644
index 00000000000..0e4fb46b8a7
--- /dev/null
+++ b/lib/jobs/dashboard_stats.rb
@@ -0,0 +1,15 @@
+module Jobs
+ class DashboardStats < Jobs::Base
+
+ def execute(args)
+ stats_json = AdminDashboardData.fetch_stats.as_json
+
+ # Add some extra time to the expiry so that the next job run has plenty of time to
+ # finish before previous cached value expires.
+ $redis.setex AdminDashboardData.stats_cache_key, (AdminDashboardData.recalculate_interval + 5).minutes, stats_json.to_json
+
+ stats_json
+ end
+
+ end
+end
\ No newline at end of file
diff --git a/spec/controllers/admin/dashboard_controller_spec.rb b/spec/controllers/admin/dashboard_controller_spec.rb
index 6cf637c3d4d..17d0ee253a0 100644
--- a/spec/controllers/admin/dashboard_controller_spec.rb
+++ b/spec/controllers/admin/dashboard_controller_spec.rb
@@ -3,9 +3,7 @@ require_dependency 'discourse_version_check'
describe Admin::DashboardController do
before do
- #NOTE: Rails.cache should be blanked between tests, at the moment we can share state with it
- # that is seriously bust on quite a few levels
- Rails.cache.delete("admin-dashboard-data-#{Discourse::VERSION::STRING}")
+ AdminDashboardData.stubs(:fetch_cached_stats).returns({reports:[]})
Jobs::VersionCheck.any_instance.stubs(:execute).returns(true)
end
@@ -45,13 +43,6 @@ describe Admin::DashboardController do
json['version_check'].should_not be_present
end
end
-
- it 'returns report data' do
- xhr :get, :index
- json = JSON.parse(response.body)
- json.should have_key('reports')
- json['reports'].should be_a(Array)
- end
end
context '.problems' do