diff --git a/app/assets/javascripts/admin/routes/admin-dashboard.js.es6 b/app/assets/javascripts/admin/routes/admin-dashboard.js.es6 index 5f2c6abd8e0..7bdb274e438 100644 --- a/app/assets/javascripts/admin/routes/admin-dashboard.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-dashboard.js.es6 @@ -13,7 +13,7 @@ export default Discourse.Route.extend({ c.set('versionCheck', Discourse.VersionCheck.create(d.version_check)); } - ['global_reports', 'page_view_reports', 'private_message_reports', 'http_reports', 'user_reports'].forEach(name => { + ['global_reports', 'page_view_reports', 'private_message_reports', 'http_reports', 'user_reports', 'mobile_reports'].forEach(name => { c.set(name, d[name].map(r => Discourse.Report.create(r))); }); diff --git a/app/assets/javascripts/admin/templates/dashboard.hbs b/app/assets/javascripts/admin/templates/dashboard.hbs index d4485533012..3496059c9bd 100644 --- a/app/assets/javascripts/admin/templates/dashboard.hbs +++ b/app/assets/javascripts/admin/templates/dashboard.hbs @@ -108,6 +108,28 @@ +
+ + + + + + + + + + + + + {{#unless loading}} + {{#each r in mobile_reports}} + {{admin-report-counts report=r}} + {{/each}} + {{/unless}} + +
{{i18n 'admin.dashboard.mobile_title'}}{{i18n 'admin.dashboard.reports.today'}}{{i18n 'admin.dashboard.reports.yesterday'}}{{i18n 'admin.dashboard.reports.last_7_days'}}{{i18n 'admin.dashboard.reports.last_30_days'}}{{i18n 'admin.dashboard.reports.all'}}
+
+
diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb index b422aa993e3..8c7c69c11f5 100644 --- a/app/controllers/topics_controller.rb +++ b/app/controllers/topics_controller.rb @@ -370,7 +370,8 @@ class TopicsController < ApplicationController current_user, params[:topic_id].to_i, params[:topic_time].to_i, - (params[:timings] || []).map{|post_number, t| [post_number.to_i, t.to_i]} + (params[:timings] || []).map{|post_number, t| [post_number.to_i, t.to_i]}, + {mobile: view_context.mobile_view?} ) render nothing: true end diff --git a/app/models/admin_dashboard_data.rb b/app/models/admin_dashboard_data.rb index bee0d49b8b4..517ed57772e 100644 --- a/app/models/admin_dashboard_data.rb +++ b/app/models/admin_dashboard_data.rb @@ -15,7 +15,7 @@ class AdminDashboardData 'emails', ] - PAGE_VIEW_REPORTS ||= ['page_view_total_reqs'] + ApplicationRequest.req_types.keys.select { |r| r =~ /^page_view_/ }.map { |r| r + "_reqs" } + PAGE_VIEW_REPORTS ||= ['page_view_total_reqs'] + ApplicationRequest.req_types.keys.select { |r| r =~ /^page_view_/ && r !~ /mobile/ }.map { |r| r + "_reqs" } PRIVATE_MESSAGE_REPORTS ||= [ 'user_to_user_private_messages', @@ -29,7 +29,7 @@ class AdminDashboardData USER_REPORTS ||= ['users_by_trust_level'] - # TODO: MOBILE_REPORTS + MOBILE_REPORTS ||= ['mobile_visits'] + ApplicationRequest.req_types.keys.select {|r| r =~ /mobile/}.map { |r| r + "_reqs" } def problems [ rails_env_check, @@ -81,6 +81,7 @@ class AdminDashboardData private_message_reports: AdminDashboardData.reports(PRIVATE_MESSAGE_REPORTS), http_reports: AdminDashboardData.reports(HTTP_REPORTS), user_reports: AdminDashboardData.reports(USER_REPORTS), + mobile_reports: AdminDashboardData.reports(MOBILE_REPORTS), admins: User.admins.count, moderators: User.moderators.count, suspended: User.suspended.count, diff --git a/app/models/post_timing.rb b/app/models/post_timing.rb index 3afd1f77815..8f682090204 100644 --- a/app/models/post_timing.rb +++ b/app/models/post_timing.rb @@ -70,7 +70,7 @@ class PostTiming < ActiveRecord::Base MAX_READ_TIME_PER_BATCH = 60*1000.0 - def self.process_timings(current_user, topic_id, topic_time, timings) + def self.process_timings(current_user, topic_id, topic_time, timings, opts={}) current_user.user_stat.update_time_read! max_time_per_post = ((Time.now - current_user.created_at) * 1000.0) @@ -129,7 +129,8 @@ SQL end topic_time = max_time_per_post if topic_time > max_time_per_post - TopicUser.update_last_read(current_user, topic_id, highest_seen, topic_time) + + TopicUser.update_last_read(current_user, topic_id, highest_seen, topic_time, opts) if total_changed > 0 current_user.reload diff --git a/app/models/report.rb b/app/models/report.rb index d50679a25c3..1e924fc0d83 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -88,6 +88,12 @@ class Report add_counts report, UserVisit, 'visited_at' end + def self.report_mobile_visits(report) + basic_report_about report, UserVisit, :mobile_by_day, report.start_date, report.end_date + report.total = UserVisit.where(mobile: true).count + report.prev30Days = UserVisit.where(mobile: true).where("visited_at >= ? and visited_at < ?", report.start_date - 30.days, report.start_date).count + end + def self.report_signups(report) report_about report, User.real, :count_by_signup_date end diff --git a/app/models/topic_user.rb b/app/models/topic_user.rb index 30fdf0be304..9876d0d3908 100644 --- a/app/models/topic_user.rb +++ b/app/models/topic_user.rb @@ -137,7 +137,7 @@ class TopicUser < ActiveRecord::Base # Update the last read and the last seen post count, but only if it doesn't exist. # This would be a lot easier if psql supported some kind of upsert - def update_last_read(user, topic_id, post_number, msecs) + def update_last_read(user, topic_id, post_number, msecs, opts={}) return if post_number.blank? msecs = 0 if msecs.to_i < 0 @@ -192,7 +192,7 @@ class TopicUser < ActiveRecord::Base if before_last_read < post_number # The user read at least one new post TopicTrackingState.publish_read(topic_id, post_number, user.id, after) - user.update_posts_read!(post_number - before_last_read) + user.update_posts_read!(post_number - before_last_read, mobile: opts[:mobile]) end if before != after @@ -207,7 +207,8 @@ class TopicUser < ActiveRecord::Base args[:new_status] = notification_levels[:tracking] end TopicTrackingState.publish_read(topic_id, post_number, user.id, args[:new_status]) - user.update_posts_read!(post_number) + + user.update_posts_read!(post_number, mobile: opts[:mobile]) exec_sql("INSERT INTO topic_users (user_id, topic_id, last_read_post_number, highest_seen_post_number, last_visited_at, first_visited_at, notification_level) SELECT :user_id, :topic_id, :post_number, ft.highest_post_number, :now, :now, :new_status diff --git a/app/models/user.rb b/app/models/user.rb index da3507ef9db..652168e9c00 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -368,6 +368,11 @@ class User < ActiveRecord::Base last_seen_at.present? end + def create_visit_record!(date, opts={}) + user_stat.update_column(:days_visited, user_stat.days_visited + 1) + user_visits.create!(visited_at: date, posts_read: opts[:posts_read] || 0, mobile: opts[:mobile] || false) + end + def visit_record_for(date) user_visits.find_by(visited_at: date) end @@ -376,14 +381,18 @@ class User < ActiveRecord::Base create_visit_record!(date) unless visit_record_for(date) end - def update_posts_read!(num_posts, now=Time.zone.now, _retry=false) + def update_posts_read!(num_posts, opts={}) + now = opts[:at] || Time.zone.now + _retry = opts[:retry] || false + if user_visit = visit_record_for(now.to_date) user_visit.posts_read += num_posts + user_visit.mobile = true if opts[:mobile] user_visit.save user_visit else begin - create_visit_record!(now.to_date, num_posts) + create_visit_record!(now.to_date, posts_read: num_posts, mobile: opts.fetch(:mobile, false)) rescue ActiveRecord::RecordNotUnique if !_retry update_posts_read!(num_posts, now, _retry=true) @@ -844,11 +853,6 @@ class User < ActiveRecord::Base email_tokens.create(email: email) end - def create_visit_record!(date, posts_read=0) - user_stat.update_column(:days_visited, user_stat.days_visited + 1) - user_visits.create!(visited_at: date, posts_read: posts_read) - end - def ensure_password_is_hashed if @raw_password self.salt = SecureRandom.hex(16) diff --git a/app/models/user_visit.rb b/app/models/user_visit.rb index b54c66e6041..2486da710d1 100644 --- a/app/models/user_visit.rb +++ b/app/models/user_visit.rb @@ -1,8 +1,16 @@ class UserVisit < ActiveRecord::Base - # A count of visits in the last month by day + def self.counts_by_day_query(start_date, end_date) + where('visited_at >= ? and visited_at <= ?', start_date.to_date, end_date.to_date).group(:visited_at).order(:visited_at) + end + + # A count of visits in a date range by day def self.by_day(start_date, end_date) - where('visited_at >= ? and visited_at <= ?', start_date.to_date, end_date.to_date).group(:visited_at).order(:visited_at).count + counts_by_day_query(start_date, end_date).count + end + + def self.mobile_by_day(start_date, end_date) + counts_by_day_query(start_date, end_date).where(mobile: true).count end def self.ensure_consistency! @@ -27,6 +35,7 @@ end # user_id :integer not null # visited_at :date not null # posts_read :integer default(0) +# mobile :boolean default(FALSE) # # Indexes # diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 25fe84f2a55..3403436b222 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1689,6 +1689,7 @@ en: suspended: 'Suspended:' private_messages_short: "Msgs" private_messages_title: "Messages" + mobile_title: "Mobile" space_free: "{{size}} free" uploads: "uploads" backups: "backups" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 4936c2cbfac..33d3c414a44 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -653,11 +653,11 @@ en: xaxis: "Day" yaxis: "Total API Requests" page_view_logged_in_mobile_reqs: - title: "Mobile Logged In" + title: "Logged In API Requests" xaxis: "Day" yaxis: "Mobile Logged In API Requests" page_view_anon_mobile_reqs: - title: "Mobile Anon" + title: "Anon API Requests" xaxis: "Day" yaxis: "Mobile Anon API Requests" http_background_reqs: @@ -692,6 +692,10 @@ en: title: "Topics with no response" xaxis: "Day" yaxis: "Total" + mobile_visits: + title: "User Visits" + xaxis: "Day" + yaxis: "Number of visits" dashboard: rails_env_warning: "Your server is running in %{env} mode." diff --git a/db/migrate/20150706215111_add_mobile_to_user_visits.rb b/db/migrate/20150706215111_add_mobile_to_user_visits.rb new file mode 100644 index 00000000000..f794e1a8ffe --- /dev/null +++ b/db/migrate/20150706215111_add_mobile_to_user_visits.rb @@ -0,0 +1,5 @@ +class AddMobileToUserVisits < ActiveRecord::Migration + def change + add_column :user_visits, :mobile, :boolean, default: false + end +end diff --git a/spec/models/trust_level3_requirements_spec.rb b/spec/models/trust_level3_requirements_spec.rb index 799e09b1699..77f96aed112 100644 --- a/spec/models/trust_level3_requirements_spec.rb +++ b/spec/models/trust_level3_requirements_spec.rb @@ -67,10 +67,10 @@ describe TrustLevel3Requirements do describe "days_visited" do it "counts visits when posts were read no further back than 100 days ago" do user.save - user.update_posts_read!(1, 2.days.ago) - user.update_posts_read!(1, 3.days.ago) - user.update_posts_read!(0, 4.days.ago) - user.update_posts_read!(3, 101.days.ago) + user.update_posts_read!(1, at: 2.days.ago) + user.update_posts_read!(1, at: 3.days.ago) + user.update_posts_read!(0, at: 4.days.ago) + user.update_posts_read!(3, at: 101.days.ago) expect(tl3_requirements.days_visited).to eq(2) end end @@ -106,10 +106,10 @@ describe TrustLevel3Requirements do describe "posts_read" do it "counts posts read within the last 100 days" do user.save - user.update_posts_read!(3, 2.days.ago) - user.update_posts_read!(1, 3.days.ago) - user.update_posts_read!(0, 4.days.ago) - user.update_posts_read!(5, 101.days.ago) + user.update_posts_read!(3, at: 2.days.ago) + user.update_posts_read!(1, at: 3.days.ago) + user.update_posts_read!(0, at: 4.days.ago) + user.update_posts_read!(5, at: 101.days.ago) expect(tl3_requirements.posts_read).to eq(4) end end @@ -127,8 +127,8 @@ describe TrustLevel3Requirements do describe "posts_read_all_time" do it "counts posts read at any time" do user.save - user.update_posts_read!(3, 2.days.ago) - user.update_posts_read!(1, 101.days.ago) + user.update_posts_read!(3, at: 2.days.ago) + user.update_posts_read!(1, at: 101.days.ago) expect(tl3_requirements.posts_read_all_time).to eq(4) end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index bd100e9fa3c..7f3aeb68128 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -921,7 +921,7 @@ describe User do it "with no existing UserVisit record, creates a new UserVisit record and increments the posts_read count" do expect { - user_visit = user.update_posts_read!(3, 5.days.ago) + user_visit = user.update_posts_read!(3, at: 5.days.ago) expect(user_visit.posts_read).to eq(3) }.to change { UserVisit.count }.by(1) end