From 516e53d9df10a1231cde8100b8fe74a8f6e42358 Mon Sep 17 00:00:00 2001 From: James Mason Date: Wed, 19 Dec 2018 12:59:52 -0800 Subject: [PATCH] Use chartkick globally * Clean up legacy charting imports * Update existing donut and line charts * Create helpers for parsing out existing chart data * Move chart partials to a more common path --- Gemfile | 1 - Gemfile.lock | 3 - app/assets/javascripts/application.js | 3 +- app/assets/javascripts/osem-dashboard.js | 146 ---------------- .../admin/conferences_controller.rb | 82 +++------ app/controllers/admin/events_controller.rb | 1 + app/helpers/chart_helper.rb | 17 ++ app/models/conference.rb | 153 ++++++++--------- app/models/event.rb | 20 +-- app/models/user.rb | 30 +++- .../conferences/_doughnut_chart.html.haml | 23 --- .../admin/conferences/_line_chart.html.haml | 47 ------ app/views/admin/conferences/index.html.haml | 42 ++--- app/views/admin/conferences/show.html.haml | 71 ++++---- app/views/admin/events/index.html.haml | 17 +- .../admin/physical_tickets/index.html.haml | 10 +- app/views/admin/registrations/index.html.haml | 8 +- .../admin/surveys/_survey_stats.html.haml | 3 - .../_big_statistic.haml | 0 app/views/application/_donut_chart.haml | 16 ++ app/views/application/_line_chart.html.haml | 15 ++ app/views/layouts/application.haml | 1 + config/initializers/assets.rb | 1 - config/initializers/chartkick.rb | 4 + .../admin/conferences_controller_spec.rb | 11 -- spec/factories/users.rb | 1 + spec/models/comment_spec.rb | 6 +- spec/models/conference_spec.rb | 159 ++++++++---------- spec/models/user_spec.rb | 17 ++ 29 files changed, 331 insertions(+), 577 deletions(-) delete mode 100644 app/assets/javascripts/osem-dashboard.js create mode 100644 app/helpers/chart_helper.rb delete mode 100644 app/views/admin/conferences/_doughnut_chart.html.haml delete mode 100644 app/views/admin/conferences/_line_chart.html.haml rename app/views/{shared => application}/_big_statistic.haml (100%) create mode 100644 app/views/application/_donut_chart.haml create mode 100644 app/views/application/_line_chart.html.haml create mode 100644 config/initializers/chartkick.rb diff --git a/Gemfile b/Gemfile index 3642332b..11fd9276 100644 --- a/Gemfile +++ b/Gemfile @@ -128,7 +128,6 @@ gem 'ajax-datatables-rails' gem 'jquery-datatables-rails' # for charts -gem 'chart-js-rails' gem 'chartkick' # for displaying maps diff --git a/Gemfile.lock b/Gemfile.lock index 7d7bfc86..fff37143 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -111,8 +111,6 @@ GEM fastimage case_transform (0.2) activesupport - chart-js-rails (0.1.6) - railties (> 3.1) chartkick (3.0.1) childprocess (0.9.0) ffi (~> 1.0, >= 1.0.11) @@ -633,7 +631,6 @@ DEPENDENCIES capybara carrierwave carrierwave-bombshelter - chart-js-rails chartkick chromedriver-helper climate_control diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 0697566f..da958dc3 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -20,8 +20,9 @@ //= require dataTables/bootstrap/3/jquery.dataTables.bootstrap //= require cocoon //= require bootstrap +//= require Chart.bundle +//= require chartkick //= require osem -//= require osem-dashboard //= require jquery-smooth-scroll //= require trianglify //= require tinycolor diff --git a/app/assets/javascripts/osem-dashboard.js b/app/assets/javascripts/osem-dashboard.js deleted file mode 100644 index 83d2b468..00000000 --- a/app/assets/javascripts/osem-dashboard.js +++ /dev/null @@ -1,146 +0,0 @@ -$(function() { - var t; - function size(animate){ - if (animate == undefined){ - animate = false; - } - clearTimeout(t); - t = setTimeout(function(){ - $("canvas").each(function(i,el){ - $(el).attr({ - "width":$(el).parent().width() - }); - }); - - $(".line_chart").each(function(){ - draw_line_chart(animate, $(this)); - }); - - $(".doughnut_chart").each(function(){ - if($(this).is(":visible")){ - draw_doughnut_chart(animate, $(this)); - } - }); - - }, 30); - } - - function draw_doughnut_chart(animation, $this){ - var options = get_animation({}, animation); - var tmp = $this.data('chart'); - - if(jQuery.isEmptyObject(tmp)){ - // Append error message if there is no data - $this.parent().append("

No data!

"); - // Remove canvas - $this.remove(); - }else{ - var data = []; - for (var key in tmp) { - data.push(tmp[key]); - } - - var ctx = $this.get(0).getContext("2d"); - new Chart(ctx).Doughnut(data, options); - } - } - - function get_animation(options, animation){ - if (!animation){ - options.animation = false; - } else { - options.animation = true; - } - return options; - } - - function draw_line_chart(animation, $canvas){ - var chart_data = create_dataset($canvas); - var weeks = $canvas.parent().data('weeks'); - var data = { - labels : weeks, - datasets : chart_data - } - - var options = get_animation(wholeNumberAxisFix(data), animation); - var ctx = $canvas.get(0).getContext("2d"); - new Chart(ctx).Line(data, options); - } - - function wholeNumberAxisFix(data){ - var maxValue = false; - for(datasetIndex = 0; datasetIndex < data.datasets.length; ++datasetIndex){ - var setMax = Math.max.apply(null, data.datasets[datasetIndex].data); - if (maxValue === false || setMax > maxValue) maxValue = setMax; - } - - var steps = maxValue; - var stepWidth = 1; - if (maxValue > 10) { - stepWidth = Math.floor(maxValue / 10); - steps = Math.ceil(maxValue / stepWidth); - } - return { scaleOverride: true, scaleSteps: steps, scaleStepWidth: stepWidth, scaleStartValue: 0 }; - } - - function create_dataset($canvas){ - var selected = getSelectedConferences($canvas); - var chart_data = $canvas.parent().data('chart'); - var conferences = $canvas.parent().data('conferences'); - var result = []; - - for(var i in conferences){ - if(selected.indexOf(conferences[i].short_title) >= 0){ - var options = {}; - options.fillColor = "rgba(255,255,255,0.0)"; - options.strokeColor = conferences[i].color; - options.data = chart_data[conferences[i].short_title]; - if(options.data == null || options.data.length == 0){ - options.data = [0]; - } - result.push(options) - } - } - return result - } - - function getSelectedConferences($canvas){ - var name = $canvas.data('name'); - var id = '#' + name + 'Checkboxes' - var selected = []; - var $checkboxes = $(id + ' input'); - // If there are checkboxes -> get selected - // Else -> use the active conference - if($checkboxes.length){ - $(id + ' input').each(function(){ - if($(this).is(":checked")) { - selected.push($(this).attr('name')); - } - }); - }else{ - var active = $canvas.parent().data('active'); - for(i in active){ - selected.push(active[i].short_title) - } - } - return selected; - } - - $('.conferenceCheckboxes input').change(function(){ - var chart_name = $(this).parent().data('chart'); - var $canvas = $('#line_chart_' + chart_name); - draw_line_chart(false, $canvas); - }); - - $(window).on('resize', function(){ - size(false); - }); - - $('#doughnut_tabs a').click(function (e) { - e.preventDefault(); - $(this).tab('show'); - size(false); - }); - - size(true); -}); diff --git a/app/controllers/admin/conferences_controller.rb b/app/controllers/admin/conferences_controller.rb index 8b06efeb..f25f2cfe 100644 --- a/app/controllers/admin/conferences_controller.rb +++ b/app/controllers/admin/conferences_controller.rb @@ -37,43 +37,33 @@ module Admin @top_submitter = Conference.get_top_submitter - @submissions = {} - @cfp_weeks = [0] - - @registrations = {} - @registration_weeks = [0] - - @tickets = {} - @ticket_weeks = [0] + @registrations = [] + @submissions = [] + @tickets = [] @conferences.each do |c| - # Event submissions over time chart - @submissions[c.short_title] = c.get_submissions_per_week - @cfp_weeks.push(@submissions[c.short_title].length) - # Conference registrations over time chart - @registrations[c.short_title] = c.get_registrations_per_week - @registration_weeks.push(@registrations[c.short_title].length) - + @registrations << { + name: c.short_title, + data: c.get_registrations_per_week + } + # Event submissions over time chart + @submissions << { + name: c.short_title, + data: c.get_submissions_per_week + } # Tickets sold over time chart - @tickets[c.short_title] = c.get_tickets_sold_per_week - @ticket_weeks.push(@tickets[c.short_title].length) + @tickets << { + name: c.short_title, + data: c.get_tickets_sold_per_week + } end - @cfp_weeks = @cfp_weeks.max - @submissions = normalize_array_length(@submissions, @cfp_weeks) - @cfp_weeks = @cfp_weeks > 0 ? (1..@cfp_weeks).to_a : 1 - - @registration_weeks = @registration_weeks.max - @registrations = normalize_array_length(@registrations, @registration_weeks) - @registration_weeks = @registration_weeks > 0 ? (1..@registration_weeks).to_a : 1 - - @ticket_weeks = @ticket_weeks.max - @tickets = normalize_array_length(@tickets, @ticket_weeks) - @ticket_weeks = @ticket_weeks > 0 ? (1..@ticket_weeks).to_a : 1 - @event_distribution = Conference.event_distribution - @user_distribution = Conference.user_distribution + @event_distribution_colors = Event::COLORS.values + + @user_distribution = User.distribution + @user_distribution_colors = User::DISTRIBUTION_COLORS.values end def new @@ -138,35 +128,9 @@ module Admin @conference_progress = @conference.get_status # Line charts - @registrations = {@conference.short_title => @conference.get_registrations_per_week} - @registration_weeks = [0] - @registration_weeks.push(@registrations[@conference.short_title].length) - - @registration_weeks = @registration_weeks.max - @registrations = normalize_array_length(@registrations, @registration_weeks) - @registration_weeks = @registration_weeks > 0 ? (1..@registration_weeks).to_a : 1 - - @submissions = Conference.get_event_state_line_colors - - @submissions_data = @conference.get_submissions_data - @cfp_weeks = 0 - if @submissions_data['Weeks'] - @cfp_weeks = @submissions_data['Weeks'] - @submissions_data = @submissions_data.except('Weeks') - end - - @tickets_data = @conference.get_tickets_data - @ticket_weeks = 0 - if @tickets_data['Weeks'] - @ticket_weeks = @tickets_data['Weeks'] - @tickets_data = @tickets_data.except('Weeks') - end - - # Set line color using a hash function - @tickets = [] - @tickets_data.each_key do |title| - @tickets.append(short_title: title, color: "\##{Digest::MD5.hexdigest(title)[0..5]}") - end + @registrations = @conference.get_registrations_per_week + @submissions = @conference.get_submissions_data + @tickets = @conference.get_tickets_data # Doughnut charts @event_type_distribution = @conference.event_type_distribution diff --git a/app/controllers/admin/events_controller.rb b/app/controllers/admin/events_controller.rb index 3db9321f..bf579106 100644 --- a/app/controllers/admin/events_controller.rb +++ b/app/controllers/admin/events_controller.rb @@ -16,6 +16,7 @@ module Admin @event_types = @program.event_types @tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed) @event_distribution = @conference.event_distribution + @event_distribution_colors = Event::COLORS.values @scheduled_event_distribution = @conference.scheduled_event_distribution @file_name = "events_for_#{@conference.short_title}" @event_export_option = params[:event_export_option] diff --git a/app/helpers/chart_helper.rb b/app/helpers/chart_helper.rb new file mode 100644 index 00000000..7503e55b --- /dev/null +++ b/app/helpers/chart_helper.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module ChartHelper + def chart_values(distribution_hash) + Hash[ + distribution_hash.collect do |key, data| + [key, data['value']] + end + ] + end + + def chart_colors(distribution_hash) + distribution_hash.collect do |_key, data| + data['color'] + end + end +end diff --git a/app/models/conference.rb b/app/models/conference.rb index 8ffedb78..dea75887 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -176,24 +176,22 @@ class Conference < ApplicationRecord # ====Returns # * +Array+ -> e.g. 'Submitted' => [0, 3, 3, 5] -> first week 0 events, second week 3 events. def get_submissions_data - result = {} - if program&.cfp && program&.events - result = get_events_per_week_by_state + return [] unless program&.cfp && program&.events - start_week = program.cfp.start_week - end_week = end_date.strftime('%W').to_i - weeks = weeks(start_week, end_week) - - result.each do |state, values| - if state == 'Submitted' - result['Submitted'] = pad_array_left_kumulative(start_week, values) - else - result[state] = pad_array_left_not_kumulative(start_week, values) - end + start_week = program.cfp.start_week + get_events_per_week_by_state.collect do |state, values| + if state == 'Submitted' + { + name: 'Submitted', + data: add_week_indices(pad_array_left_kumulative(start_week, values)) + } + else + { + name: state, + data: add_week_indices(pad_array_left_not_kumulative(start_week, values)) + } end - result['Weeks'] = weeks > 0 ? (1..weeks).to_a : 0 end - result end ## @@ -202,19 +200,15 @@ class Conference < ApplicationRecord # ====Returns # * +Array+ -> e.g. [0, 3, 3, 5] -> first week 0, second week 3 registrations def get_registrations_per_week - result = [] + return [] unless registrations && + registration_period && + registration_period.start_date && + registration_period.end_date - if registrations && - registration_period && - registration_period.start_date && - registration_period.end_date - - reg = registrations.group(:week).order(:week).count - start_week = get_registration_start_week - weeks = registration_weeks - result = calculate_items_per_week(start_week, weeks, reg) - end - result + reg = registrations.group(:week).order(:week).count + start_week = get_registration_start_week + weeks = registration_weeks + calculate_items_per_week(start_week, weeks, reg) end ## @@ -223,15 +217,12 @@ class Conference < ApplicationRecord # ====Returns # * +Array+ -> e.g. [0, 3, 3, 5] -> first week 0, second week 3 tickets sold def get_tickets_sold_per_week - result = [] + return [] unless tickets && ticket_purchases && registration_period - if tickets && ticket_purchases && registration_period - tickets_sold = ticket_purchases.paid.group(:week).sum(:quantity) - start_week = get_registration_start_week - weeks = registration_weeks - result = calculate_items_per_week(start_week, weeks, tickets_sold) - end - result + tickets_sold = ticket_purchases.paid.group(:week).sum(:quantity) + start_week = get_registration_start_week + weeks = registration_weeks + calculate_items_per_week(start_week, weeks, tickets_sold) end ## @@ -241,33 +232,32 @@ class Conference < ApplicationRecord # ====Returns # * +Array+ -> e.g. 'Free Access' => [0, 3, 3, 5] -> first week 0 tickets sold, second week 3 tickets sold. def get_tickets_data - result = {} - if tickets && ticket_purchases && registration_period - tickets_per_ticket_id_and_week = ticket_purchases.paid.group(:ticket_id, :week).sum(:quantity) + return [] unless tickets && ticket_purchases && registration_period - start_week = get_registration_start_week - weeks = registration_weeks + tickets_per_ticket_id_and_week = ticket_purchases.paid.group(:ticket_id, :week).sum(:quantity) - tickets_by_id_per_week = {} + start_week = get_registration_start_week + weeks = registration_weeks - tickets.each do |ticket| - tickets_by_id_per_week[ticket.id] = {} - (start_week...(start_week + weeks)).each do |week| - tickets_by_id_per_week[ticket.id][week] = 0 - end + tickets_by_id_per_week = {} + + tickets.each do |ticket| + tickets_by_id_per_week[ticket.id] = {} + (start_week...(start_week + weeks)).each do |week| + tickets_by_id_per_week[ticket.id][week] = 0 end - - tickets_per_ticket_id_and_week.each do |ticket_week, value| - tickets_by_id_per_week[ticket_week[0]][ticket_week[1]] = value - end - - tickets_by_id_per_week.each do |ticket, values| - result[Ticket.find(ticket).title] = pad_array_left_not_kumulative(start_week, values) - end - - result['Weeks'] = weeks > 0 ? (1..weeks).to_a : 0 end - result + + tickets_per_ticket_id_and_week.each do |ticket_week, value| + tickets_by_id_per_week[ticket_week[0]][ticket_week[1]] = value + end + + tickets_by_id_per_week.collect do |ticket, values| + { + name: Ticket.find(ticket).title, + data: add_week_indices(pad_array_left_not_kumulative(start_week, values)) + } + end end ## @@ -400,7 +390,9 @@ class Conference < ApplicationRecord # ====Returns # * +hash+ -> hash def event_distribution - Conference.calculate_event_distribution_hash(program.events.select(:state).group(:state).count) + Conference.calculate_event_distribution_hash( + program.events.select(:state).group(:state).count + ) end ## @@ -465,22 +457,6 @@ class Conference < ApplicationRecord result end - ## - # Returns a hash with user distribution => {value: count of user state, color: color} - # active: signed in during the last 3 months - # unconfirmed: registered but not confirmed - # dead: not signed in during the last year - # - # ====Returns - # * +hash+ -> hash - def self.user_distribution - active_user = User.where('last_sign_in_at > ?', Date.today - 3.months).count - unconfirmed_user = User.where('confirmed_at IS NULL').count - dead_user = User.where('last_sign_in_at < ?', Date.today - 1.year).count - - calculate_user_distribution_hash(active_user, unconfirmed_user, dead_user) - end - ## # Returns a hash with per ticket sales => { "Title" => { value: number of tickets sold, # color: generated from the title using a hash function }, ...} @@ -1110,20 +1086,19 @@ class Conference < ApplicationRecord end ## - # Helper method. Calculates hash with corresponding colors of event state distribution. + # Helper method. Calculates hash of all event states in a consistent order. # # ====Returns # * +hash+ -> hash - def self.calculate_event_distribution_hash(states) - result = {} - states.each do |key, value| - result[key.capitalize] = - { - 'value' => value, - 'color' => Event.get_state_color(key) - } - end - result + def self.calculate_event_distribution_hash(counts) + return {} if counts.values.sum == 0 + + Hash[ + Event.state_machine.states.collect do |state| + state_name = state.name.to_s + [state_name.capitalize, counts[state_name] || 0] + end + ] end ## @@ -1211,6 +1186,12 @@ class Conference < ApplicationRecord result += Array.new(weeks - result.length, sum) end - result + add_week_indices(result) + end + + def add_week_indices(values) + Hash[ + values.collect.with_index { |value, index| ["Wk #{index + 1}", value] } + ] end end diff --git a/app/models/event.rb b/app/models/event.rb index 0b78ebf7..7fbc007d 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -83,6 +83,15 @@ class Event < ApplicationRecord end end + COLORS = { + new: '#0000FF', # blue + withdrawn: '#FF8000', # orange + unconfirmed: '#FFFF00', # yellow + confirmed: '#00FF00', # green + canceled: '#848484', # grey + rejected: '#FF0000' # red + }.freeze + ## # Checkes if the event has a start_time and a room for the selected schedule if there is any # ====Returns @@ -176,16 +185,7 @@ class Event < ApplicationRecord end def self.get_state_color(state) - color = { - new: '#0000FF', # blue - withdrawn: '#FF8000', # orange - confirmed: '#00FF00', # green - unconfirmed: '#FFFF00', # yellow - rejected: '#FF0000', # red - canceled: '#848484' # grey - }[state.to_sym] - - color || '#00FFFF' # azure + COLORS[state.to_sym] || '#00FFFF' # azure end def update_state(transition, mail = false, subject = false, send_mail = false, send_mail_param) diff --git a/app/models/user.rb b/app/models/user.rb index e69cff5c..89fb97a9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -32,6 +32,13 @@ class User < ApplicationRecord # add scope scope :comment_notifiable, ->(conference) {joins(:roles).where('roles.name IN (?)', [:organizer, :cfp]).where('roles.resource_type = ? AND roles.resource_id = ?', 'Conference', conference.id)} + # scopes for user distributions + scope :active, lambda { + where('last_sign_in_at > ?', Date.today - 3.months).where(is_disabled: false) + } + scope :unconfirmed, -> { where('confirmed_at IS NULL') } + scope :dead, -> { where('last_sign_in_at < ?', Date.today - 1.year) } + # Include default devise modules. Others available are: # :token_authenticatable, :confirmable, # :lockable, :timeoutable and :omniauthable @@ -79,7 +86,6 @@ class User < ApplicationRecord accepts_nested_attributes_for :roles scope :admin, -> { where(is_admin: true) } - scope :active, -> { where(is_disabled: false) } validates :email, presence: true @@ -91,6 +97,12 @@ class User < ApplicationRecord validate :biography_limit + DISTRIBUTION_COLORS = { + 'Active' => 'green', + 'Unconfirmed' => 'red', + 'Dead' => 'black' + }.freeze + ## # Checkes if the user attended the event # This is used for events that require registration @@ -152,6 +164,22 @@ class User < ApplicationRecord user end + ## + # Returns a hash with user distribution => {value: count of user state, color: color} + # active: signed in during the last 3 months + # unconfirmed: registered but not confirmed + # dead: not signed in during the last year + # + # ====Returns + # * +hash+ -> hash + def self.distribution + { + 'Active' => User.active.count, + 'Unconfirmed' => User.unconfirmed.count, + 'Dead' => User.dead.count + } + end + def self.find_for_database_authentication(warden_conditions) conditions = warden_conditions.dup login = conditions.delete(:login) diff --git a/app/views/admin/conferences/_doughnut_chart.html.haml b/app/views/admin/conferences/_doughnut_chart.html.haml deleted file mode 100644 index 6ad75cef..00000000 --- a/app/views/admin/conferences/_doughnut_chart.html.haml +++ /dev/null @@ -1,23 +0,0 @@ -.text-center - %h4 #{title} - %canvas.doughnut_chart{ id: "dough_#{title.parameterize.underscore}", 'data-chart' => data.to_json } -- if data - - data.each do |key, value| - %span{ 'style' => "border-bottom: 3px solid #{value['color']}" } #{key}: #{value['value']} - -:javascript - $(document).ready( function(){ - - var d = $("#dough_#{title.parameterize.underscore}"); - var dt = d.get(0).getContext('2d'); - - $(window).resize( respondCanvas ); - - function respondCanvas(){ - dt.canvas.width = 150; - dt.canvas.height = 150; - } - - respondCanvas(); - - }); diff --git a/app/views/admin/conferences/_line_chart.html.haml b/app/views/admin/conferences/_line_chart.html.haml deleted file mode 100644 index 12d825e7..00000000 --- a/app/views/admin/conferences/_line_chart.html.haml +++ /dev/null @@ -1,47 +0,0 @@ -.row - .col-md-12 - .text-center - %h4 - = title -.row - .col-md-12 - .chart_data{ 'data-chart' => "#{y.to_json}", 'data-conferences' => "#{conferences.to_json}", - 'data-deactive' => "#{deactive_conferences.to_json}", 'data-weeks' => "#{x.to_json}", - 'data-active' => "#{active_conferences.to_json}" } - %canvas.line_chart{ id: "line_chart_#{name}", 'data-name' => "#{name}" } -.row - .col-md-12 - .text-center - = unit -.row - .col-md-12 - .conferenceCheckboxes{ id: "#{name}Checkboxes", 'data-name' => "#{name}" } - - if active_conferences && deactive_conferences && conferences && conferences.length > 1 - - active_conferences.each do |conference| - %div - %span{ 'style' => "border-bottom: 3px solid #{conference[:color]};", 'data-chart' => "#{name}" } - %input{ 'type' => 'checkbox', 'name' => "#{conference[:short_title]}", 'checked' => 'checked' } - #{conference[:short_title]} - - deactive_conferences.each do |conference| - %div - %span{ 'style' => "border-bottom: 3px solid #{conference[:color]};", 'data-chart' => "#{name}" } - %input{ 'type' => 'checkbox', 'name' => "#{conference[:short_title]}" } - #{conference[:short_title]} - -:javascript - $(document).ready( function(){ - - var c = $("#line_chart_#{name}"); - var ct = c.get(0).getContext('2d'); - var container = $(c).parent(); - - $(window).resize( respondCanvas ); - - function respondCanvas(){ - c.attr('width', $(container).width() ); - c.attr('height', $(container).height() ); - } - - respondCanvas(); - - }); diff --git a/app/views/admin/conferences/index.html.haml b/app/views/admin/conferences/index.html.haml index 72d6179d..800e612e 100644 --- a/app/views/admin/conferences/index.html.haml +++ b/app/views/admin/conferences/index.html.haml @@ -1,52 +1,32 @@ -= javascript_include_tag 'Chart.min' .row .col-sm-3.col-xs-3 - = render "shared/big_statistic", + = render "big_statistic", icon: "user", subtitle: "User", value: @total_user, delta: @new_user .col-sm-3.col-xs-3 - = render "shared/big_statistic", + = render "big_statistic", icon: "check-square", subtitle: "Registration", value: @total_reg, delta: @new_reg .col-sm-3.col-xs-3 - = render "shared/big_statistic", + = render "big_statistic", icon: "file-text", subtitle: "Submission", value: @total_submissions, delta: @new_submissions .col-sm-3.col-xs-3 - = render "shared/big_statistic", + = render "big_statistic", icon: "archive", subtitle: "Withdrawn", value: @total_withdrawn, delta: @new_withdrawn, reverse: true .row#registrations .col-md-8 - = render partial: 'line_chart', locals: { title: 'Registrations over time', - name: 'registrations', - conferences: @conferences, - active_conferences: @active_conferences, - deactive_conferences: @deactive_conferences, - y: @registrations, - x: @registration_weeks, - unit: 'weeks' } + = render 'line_chart', title: 'Registrations per week', data: @registrations .col-md-4 - = render partial: 'doughnut_chart', locals: { title: 'Events', data: @event_distribution } + = render 'donut_chart', title: 'Events', + data: @event_distribution, colors: @event_distribution_colors .row#submissions .col-md-8 - = render partial: 'line_chart', locals: { title: 'Submissions over time', - name: 'submissions', - conferences: @conferences, - active_conferences: @active_conferences, - deactive_conferences: @deactive_conferences, - y: @submissions, - x: @cfp_weeks, - unit: 'weeks' } + = render 'line_chart', title: 'Submissions per week', data: @submissions .col-md-4 - = render partial: 'doughnut_chart', locals: { title: 'User', data: @user_distribution } + = render 'donut_chart', title: 'Users', + data: @user_distribution, colors: @user_distribution_colors .row#tickets .col-md-8 - = render partial: 'line_chart', locals: { title: 'Tickets sold over time', - name: 'tickets', - conferences: @conferences, - active_conferences: @active_conferences, - deactive_conferences: @deactive_conferences, - y: @tickets, - x: @ticket_weeks, - unit: 'weeks' } + = render 'line_chart', title: 'Tickets sold per week', data: @tickets %br .row .col-md-8 diff --git a/app/views/admin/conferences/show.html.haml b/app/views/admin/conferences/show.html.haml index ed4d0cd1..89daeff5 100644 --- a/app/views/admin/conferences/show.html.haml +++ b/app/views/admin/conferences/show.html.haml @@ -1,21 +1,19 @@ -= javascript_include_tag 'Chart.min' - %h1 %span.fa.fa-tachometer Dashboard for #{@conference.title} %hr .row .col-sm-3.col-xs-3 - = render "shared/big_statistic", + = render "big_statistic", icon: "user", subtitle: "Registration", value: @total_reg, delta: @new_reg .col-sm-3.col-xs-3 - = render "shared/big_statistic", + = render "big_statistic", icon: "check-square", subtitle: "Submission", value: @total_submissions, delta: @new_submissions .col-sm-3.col-xs-3 - = render "shared/big_statistic", + = render "big_statistic", icon: "file-text", subtitle: "Hour", value: @program_length, delta: @new_program_length .col-sm-3.col-xs-3 - = render "shared/big_statistic", + = render "big_statistic", icon: "archive", subtitle: "Withdrawn", value: @total_withdrawn, delta: @new_withdrawn .row @@ -24,37 +22,19 @@ .col-md-8 .row#registrations .col-md-12 - = render partial: 'line_chart', locals: { title: 'Registrations over time', - name: 'registrations', - conferences: [@conference], - active_conferences: [@conference], - deactive_conferences: [], - y: @registrations, - x: @registration_weeks, - unit: 'weeks' } + = render 'line_chart', + title: 'Registrations per week', data: @registrations .row#submissions .col-md-12 - = render partial: 'line_chart', locals: { title: 'Submissions over time', - name: 'submissions', - conferences: @submissions, - active_conferences: @submissions, - deactive_conferences: [], - y: @submissions_data, - x: @cfp_weeks, - unit: 'weeks' } + = render 'line_chart', + title: 'Submissions per week', data: @submissions .col-md-4 - = render partial: 'todo_list', locals: { conference_progress: @conference_progress, - conference: @conference } + = render 'todo_list', + conference_progress: @conference_progress, conference: @conference .row#tickets .col-md-8 - = render partial: 'line_chart', locals: { title: 'Tickets sold over time', - name: 'tickets', - conferences: @tickets, - active_conferences: @tickets, - deactive_conferences: [], - y: @tickets_data, - x: @ticket_weeks, - unit: 'weeks' } + = render 'line_chart', + title: 'Tickets sold per week', data: @tickets %br .row .col-md-12#doughnut @@ -75,27 +55,36 @@ .tab-pane.active#distribution_all .row .col-md-4 - = render partial: 'doughnut_chart', locals: {title: 'Event types', data: @event_type_distribution} + = render 'donut_chart', title: 'Event types', + combined_data: @event_type_distribution .col-md-4 - = render partial: 'doughnut_chart', locals: {title: 'Difficulty levels', data: @difficulty_levels_distribution} + = render 'donut_chart', title: 'Difficulty levels', + combined_data: @difficulty_levels_distribution .col-md-4 - = render partial: 'doughnut_chart', locals: {title: 'Tracks', data: @tracks_distribution} + = render 'donut_chart', title: 'Tracks', + combined_data: @tracks_distribution .tab-pane#distribution_confirmed .row .col-md-4 - = render partial: 'doughnut_chart', locals: {title: 'Event types', data: @event_type_distribution_confirmed} + = render 'donut_chart', title: 'Event types', + combined_data: @event_type_distribution_confirmed .col-md-4 - = render partial: 'doughnut_chart', locals: {title: 'Difficulty levels', data: @difficulty_levels_distribution_confirmed} + = render 'donut_chart', title: 'Difficulty levels', + combined_data: @difficulty_levels_distribution_confirmed .col-md-4 - = render partial: 'doughnut_chart', locals: {title: 'Tracks', data: @tracks_distribution_confirmed} + = render 'donut_chart', title: 'Tracks', + combined_data: @tracks_distribution_confirmed .tab-pane#distribution_withdrawn .row .col-md-4 - = render partial: 'doughnut_chart', locals: {title: 'Event types', data: @event_type_distribution_withdrawn} + = render 'donut_chart', title: 'Event types', + combined_data: @event_type_distribution_withdrawn .col-md-4 - = render partial: 'doughnut_chart', locals: {title: 'Difficulty levels', data: @difficulty_levels_distribution_withdrawn} + = render 'donut_chart', title: 'Difficulty levels', + combined_data: @difficulty_levels_distribution_withdrawn .col-md-4 - = render partial: 'doughnut_chart', locals: {title: 'Tracks', data: @tracks_distribution_withdrawn} + = render 'donut_chart', title: 'Tracks', + combined_data: @tracks_distribution_withdrawn .row .col-md-8 diff --git a/app/views/admin/events/index.html.haml b/app/views/admin/events/index.html.haml index d547c66b..4944d946 100644 --- a/app/views/admin/events/index.html.haml +++ b/app/views/admin/events/index.html.haml @@ -1,5 +1,3 @@ -= javascript_include_tag 'Chart.min' - .row .col-md-12 .page-header @@ -47,17 +45,14 @@ = f.submit 'Add', class: 'btn btn-primary' .row .col-md-4 - = render 'admin/conferences/doughnut_chart', - title: 'Events state', - data: @event_distribution + = render 'donut_chart', title: 'Events state', + data: @event_distribution, colors: @event_distribution_colors .col-md-4 - = render 'admin/conferences/doughnut_chart', - title: 'Confirmed events scheduled', - data: @scheduled_event_distribution + = render 'donut_chart', title: 'Confirmed events scheduled', + combined_data: @scheduled_event_distribution .col-md-4 - = render 'admin/conferences/doughnut_chart', - title: 'Tracks of confirmed events', - data: @tracks_distribution_confirmed + = render 'donut_chart', title: 'Tracks of confirmed events', + combined_data: @tracks_distribution_confirmed .row .col-md-12 .margin-event-table diff --git a/app/views/admin/physical_tickets/index.html.haml b/app/views/admin/physical_tickets/index.html.haml index 88303a50..a1d14cd3 100644 --- a/app/views/admin/physical_tickets/index.html.haml +++ b/app/views/admin/physical_tickets/index.html.haml @@ -1,5 +1,3 @@ -= javascript_include_tag 'Chart.min' - .container .row .col-md-12.page-header @@ -9,11 +7,11 @@ Tickets sold for the conference .row .col-md-4 - = render partial: 'admin/conferences/doughnut_chart', - locals: { title: 'Tickets sold', data: @tickets_sold_distribution } + = render 'donut_chart', title: 'Tickets sold', + combined_data: @tickets_sold_distribution .col-md-4 - = render partial: 'admin/conferences/doughnut_chart', - locals: {title: 'Tickets turnover', data: @tickets_turnover_distribution} + = render 'donut_chart', title: 'Tickets turnover', + combined_data: @tickets_turnover_distribution %br - if @physical_tickets.any? .row diff --git a/app/views/admin/registrations/index.html.haml b/app/views/admin/registrations/index.html.haml index 699d5a9f..8ea544d8 100644 --- a/app/views/admin/registrations/index.html.haml +++ b/app/views/admin/registrations/index.html.haml @@ -1,5 +1,3 @@ -= javascript_include_tag 'Chart.min' - .row .col-md-12 .page-header @@ -14,10 +12,12 @@ %p.text-muted All the people who registered to your event .col-md-4 - = render partial: 'admin/conferences/doughnut_chart', locals: {title: 'Affiliation', data: @affiliation_distribution} + = render 'donut_chart', title: 'Affiliation', + combined_data: @affiliation_distribution - unless @conference.pending? .col-md-4 - = render partial: 'admin/conferences/doughnut_chart', locals: {title: 'Attended registrations', data: @registration_distribution} + = render 'donut_chart', title: 'Attended registrations', + combined_data: @registration_distribution .row .col-md-12 %div.margin-event-table diff --git a/app/views/admin/surveys/_survey_stats.html.haml b/app/views/admin/surveys/_survey_stats.html.haml index b9336f4a..e551a7d1 100644 --- a/app/views/admin/surveys/_survey_stats.html.haml +++ b/app/views/admin/surveys/_survey_stats.html.haml @@ -1,6 +1,3 @@ -= javascript_include_tag "//www.google.com/jsapi", "chartkick" -= javascript_include_tag 'chartkick' - = bar_chart @survey.survey_questions.map{ |q| [q.title, q.survey_replies.count] } - @survey.survey_questions.each.with_index(1) do |survey_question, question_index| diff --git a/app/views/shared/_big_statistic.haml b/app/views/application/_big_statistic.haml similarity index 100% rename from app/views/shared/_big_statistic.haml rename to app/views/application/_big_statistic.haml diff --git a/app/views/application/_donut_chart.haml b/app/views/application/_donut_chart.haml new file mode 100644 index 00000000..351ff216 --- /dev/null +++ b/app/views/application/_donut_chart.haml @@ -0,0 +1,16 @@ +:ruby + combined_data ||= {} + data ||= chart_values(combined_data) + colors ||= chart_colors(combined_data) + + options = { + donut: true, + legend: 'bottom', + download: true, + messages: { empty: 'No data' } + } + options[:colors] = colors if colors.present? + +.text-center + %h4= title + = pie_chart data, options diff --git a/app/views/application/_line_chart.html.haml b/app/views/application/_line_chart.html.haml new file mode 100644 index 00000000..b3dbf7be --- /dev/null +++ b/app/views/application/_line_chart.html.haml @@ -0,0 +1,15 @@ +:ruby + options = { + legend: 'bottom', + download: true, + messages: { empty: 'No data' } + } + +.row + .col-md-12 + .text-center + %h4 + = title +.row + .col-md-12 + = line_chart data, options diff --git a/app/views/layouts/application.haml b/app/views/layouts/application.haml index 0c8f6201..d4c194b9 100644 --- a/app/views/layouts/application.haml +++ b/app/views/layouts/application.haml @@ -50,4 +50,5 @@ Performance data is available on #{link_to "Skylight", ENV["SKYLIGHT_PUBLIC_DASHBOARD_URL"]}. = yield :script_body + = yield :charts_js = piwik_tracking_tag diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 1d25cea1..01ef3e66 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -9,4 +9,3 @@ Rails.application.config.assets.version = '1.0' # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. # Rails.application.config.assets.precompile += %w( search.js ) -Rails.application.config.assets.precompile += %w( Chart.min.js ) diff --git a/config/initializers/chartkick.rb b/config/initializers/chartkick.rb new file mode 100644 index 00000000..23fa3574 --- /dev/null +++ b/config/initializers/chartkick.rb @@ -0,0 +1,4 @@ +Chartkick.options = { + height: '150px', + content_for: :charts_js +} diff --git a/spec/controllers/admin/conferences_controller_spec.rb b/spec/controllers/admin/conferences_controller_spec.rb index 4d8bb060..9a10610c 100644 --- a/spec/controllers/admin/conferences_controller_spec.rb +++ b/spec/controllers/admin/conferences_controller_spec.rb @@ -177,17 +177,6 @@ describe Admin::ConferencesController do expect(assigns(:conferences)).to match_array([conference, con2]) end - it 'assigns cfp_max an array with maximum weeks' do - conference - date = Date.new(2014, 05, 26) - create(:cfp, - program: conference.program, - start_date: date, - end_date: date + 14) - get :index - expect(assigns(:cfp_weeks)).to match_array([1, 2, 3]) - end - it 'renders the index template' do conference get :index diff --git a/spec/factories/users.rb b/spec/factories/users.rb index f868a738..22e4ea7a 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -31,6 +31,7 @@ FactoryBot.define do Quisque cursus facilisis consequat. Etiam volutpat ligula turpis, at gravida. EOS + last_sign_in_at { Date.today } is_disabled { false } after(:create) do |user| diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb index bb294079..e3376e79 100644 --- a/spec/models/comment_spec.rb +++ b/spec/models/comment_spec.rb @@ -5,8 +5,12 @@ require 'spec_helper' describe Commercial do describe '.find_since_last_login' do + let!(:user) do + create(:user, last_sign_in_at: nil) + end + it 'returns none if last_sign_in_at is nil' do - expect(Comment.find_since_last_login(create(:user))).to eq(Comment.none) + expect(Comment.find_since_last_login(user)).to eq(Comment.none) end end end diff --git a/spec/models/conference_spec.rb b/spec/models/conference_spec.rb index f740cc61..5e082e06 100755 --- a/spec/models/conference_spec.rb +++ b/spec/models/conference_spec.rb @@ -166,7 +166,7 @@ describe Conference do describe '#get_submissions_data' do it 'returns emtpy hash if there is no cfp or events' do - expect(subject.get_submissions_data).to eq({}) + expect(subject.get_submissions_data).to eq [] end it 'calculates the correct result with data from database' do @@ -191,12 +191,7 @@ describe Conference do create(:event, program: subject.program, created_at: Date.today - 2.weeks) - result = { - 'Submitted' => [1, 1, 1], - 'Confirmed' => [1, 3, 0], - 'Unconfirmed' => [2, 4, 0], - 'Weeks' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - } + result = [{ name: 'Submitted', data: { 'Wk 1' => 1, 'Wk 2' => 1, 'Wk 3' => 1 } }, { name: 'Confirmed', data: { 'Wk 1' => 1, 'Wk 2' => 3, 'Wk 3' => 0 } }, { name: 'Unconfirmed', data: { 'Wk 1' => 2, 'Wk 2' => 4, 'Wk 3' => 0 } }] expect(subject.get_submissions_data).to eq(result) end @@ -207,12 +202,11 @@ describe Conference do create(:cfp, start_date: Date.today, program: subject.program) create(:event, program: subject.program) - result = { - 'Submitted' => [1], - 'Confirmed' => [0], - 'Unconfirmed' => [0], - 'Weeks' => [1, 2, 3, 4, 5, 6, 7, 8] - } + result = [ + { name: 'Submitted', data: { 'Wk 1'=>1 } }, + { name: 'Confirmed', data: { 'Wk 1'=>0 } }, + { name: 'Unconfirmed', data: { 'Wk 1'=>0 } } + ] expect(subject.get_submissions_data).to eq(result) end @@ -232,12 +226,20 @@ describe Conference do confirmed.accept!(options) confirmed.confirm! - result = { - 'Submitted' => [0, 0, 3], - 'Confirmed' => [0, 0, 1], - 'Unconfirmed' => [0, 0, 1], - 'Weeks' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - } + result = [ + { + name: 'Submitted', + data: { 'Wk 1' => 0, 'Wk 2' => 0, 'Wk 3' => 3 } + }, + { + name: 'Confirmed', + data: { 'Wk 1' => 0, 'Wk 2' => 0, 'Wk 3' => 1 } + }, + { + name: 'Unconfirmed', + data: { 'Wk 1' => 0, 'Wk 2' => 0, 'Wk 3' => 1 } + } + ] expect(subject.get_submissions_data).to eq(result) end @@ -263,12 +265,20 @@ describe Conference do create(:event, program: subject.program, created_at: Date.today - 3.weeks) - result = { - 'Submitted' => [1, 1, 1, 1], - 'Confirmed' => [1, 0, 3, 0], - 'Unconfirmed' => [2, 0, 4, 0], - 'Weeks' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - } + result = [ + { + name: 'Submitted', + data: { 'Wk 1' => 1, 'Wk 2' => 1, 'Wk 3' => 1, 'Wk 4' => 1 } + }, + { + name: 'Confirmed', + data: { 'Wk 1' => 1, 'Wk 2' => 0, 'Wk 3' => 3, 'Wk 4' => 0 } + }, + { + name: 'Unconfirmed', + data: { 'Wk 1' => 2, 'Wk 2' => 0, 'Wk 3' => 4, 'Wk 4' => 0 } + } + ] expect(subject.get_submissions_data).to eq(result) end end @@ -768,13 +778,7 @@ describe Conference do canceled.accept!(@options) canceled.cancel! - @result = {} - @result['New'] = { 'value' => 1, 'color' => '#0000FF' } - @result['Withdrawn'] = { 'value' => 1, 'color' => '#FF8000' } - @result['Unconfirmed'] = { 'value' => 1, 'color' => '#FFFF00' } - @result['Rejected'] = { 'value' => 1, 'color' => '#FF0000' } - @result['Confirmed'] = { 'value' => 1, 'color' => '#00FF00' } - @result['Canceled'] = { 'value' => 1, 'color' => '#848484' } + @result = { 'New' => 1, 'Withdrawn' => 1, 'Unconfirmed' => 1, 'Confirmed' => 1, 'Canceled' => 1, 'Rejected' => 1 } end it '#event_distribution does calculate correct values with events' do @@ -789,7 +793,7 @@ describe Conference do it 'event_distribution does calculate correct values with just a new event' do conference = create(:conference) create(:event, program: conference.program) - result = { 'New' => { 'value' => 1, 'color' => '#0000FF' } } + result = { 'New' => 1, 'Withdrawn' => 0, 'Unconfirmed' => 0, 'Confirmed' => 0, 'Canceled' => 0, 'Rejected' => 0 } expect(conference.event_distribution).to eq(result) end @@ -797,7 +801,7 @@ describe Conference do conference = create(:conference) event = create(:event, program: conference.program) event.withdraw! - result = { 'Withdrawn' => { 'value' => 1, 'color' => '#FF8000' } } + result = { 'New' => 0, 'Withdrawn' => 1, 'Unconfirmed' => 0, 'Confirmed' => 0, 'Canceled' => 0, 'Rejected' => 0 } expect(conference.event_distribution).to eq(result) end @@ -805,7 +809,7 @@ describe Conference do conference = create(:conference) event = create(:event, program: conference.program) event.accept!(@options) - result = { 'Unconfirmed' => { 'value' => 1, 'color' => '#FFFF00' } } + result = { 'New' => 0, 'Withdrawn' => 0, 'Unconfirmed' => 1, 'Confirmed' => 0, 'Canceled' => 0, 'Rejected' => 0 } expect(conference.event_distribution).to eq(result) end @@ -813,7 +817,7 @@ describe Conference do conference = create(:conference) event = create(:event, program: conference.program) event.reject!(@options) - result = { 'Rejected' => { 'value' => 1, 'color' => '#FF0000' } } + result = { 'New' => 0, 'Withdrawn' => 0, 'Unconfirmed' => 0, 'Confirmed' => 0, 'Canceled' => 0, 'Rejected' => 1 } expect(conference.event_distribution).to eq(result) end @@ -823,7 +827,7 @@ describe Conference do event = create(:event, program: conference.program) event.accept!(@options) event.confirm! - result = { 'Confirmed' => { 'value' => 1, 'color' => '#00FF00' } } + result = { 'New' => 0, 'Withdrawn' => 0, 'Unconfirmed' => 0, 'Confirmed' => 1, 'Canceled' => 0, 'Rejected' => 0 } expect(conference.event_distribution).to eq(result) end @@ -832,7 +836,7 @@ describe Conference do event = create(:event, program: conference.program) event.accept!(@options) event.cancel! - result = { 'Canceled' => { 'value' => 1, 'color' => '#848484' } } + result = { 'New' => 0, 'Withdrawn' => 0, 'Unconfirmed' => 0, 'Confirmed' => 0, 'Canceled' => 1, 'Rejected' => 0 } expect(conference.event_distribution).to eq(result) end @@ -848,15 +852,15 @@ describe Conference do it 'self#event_distribution does calculate correct values with just a new event' do @conference.program.events.clear create(:event, program: @conference.program) - result = { 'New' => { 'value' => 1, 'color' => '#0000FF' } } + result = { 'New' => 1, 'Withdrawn' => 0, 'Unconfirmed' => 0, 'Confirmed' => 0, 'Canceled' => 0, 'Rejected' => 0 } expect(Conference.event_distribution).to eq(result) end it 'self#event_distribution does calculate correct values with just a new events from different conferences' do create(:event, program: @conference.program) - @result['New'] = { 'value' => 2, 'color' => '#0000FF' } - expect(Conference.event_distribution).to eq(@result) + result = { 'New' => 2, 'Withdrawn' => 1, 'Unconfirmed' => 1, 'Confirmed' => 1, 'Canceled' => 1, 'Rejected' => 1 } + expect(Conference.event_distribution).to eq(result) end end @@ -865,44 +869,15 @@ describe Conference do let!(:organizer_role) { Role.find_by(name: 'organizer', resource: conference) } let!(:organizer) { create(:user, role_ids: [organizer_role.id]) } - it 'self#event_distribution calculates correct values with user' do - create(:user, last_sign_in_at: Date.today - 3.months + 1.day) # active - create(:user, confirmed_at: nil) # unconfirmed - create(:user, last_sign_in_at: Date.today - 1.year - 1.day) # dead + it 'self#user_distribution calculates correct values with user' do result = {} result['Active'] = { 'color' => 'green', 'value' => 1 } result['Unconfirmed'] = { 'color' => 'red', 'value' => 1 } result['Dead'] = { 'color' => 'black', 'value' => 1 } - expect(Conference.user_distribution).to eq(result) - end - - it 'self#event_distribution calculates correct with only active user' do - create(:user, last_sign_in_at: Date.today - 3.months + 1.day) # active - result = {} - result['Active'] = { 'color' => 'green', 'value' => 1 } - - expect(Conference.user_distribution).to eq(result) - end - - it 'self#event_distribution calculates correct values with only unconfirmed user' do - create(:user, confirmed_at: nil) # unconfirmed - result = {} - result['Unconfirmed'] = { 'color' => 'red', 'value' => 1 } - - expect(Conference.user_distribution).to eq(result) - end - - it 'self#event_distribution calculates correct values with only dead user' do - create(:user, last_sign_in_at: Time.now - 1.year - 1.day) # dead - result = {} - result['Dead'] = { 'color' => 'black', 'value' => 1 } - - expect(Conference.user_distribution).to eq(result) - end - - it 'self#event_distribution calculates correct values without user' do - expect(Conference.user_distribution).to eq({}) + expect( + Conference.calculate_user_distribution_hash(1, 1, 1) + ).to eq(result) end end @@ -1152,7 +1127,7 @@ describe Conference do cfp.end_date = Date.new(2014, 05, 26) + 21 cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) - 7)] - expect(subject.get_submissions_per_week).to eq([1, 1, 1, 1, 1]) + expect(subject.get_submissions_per_week.values).to eq([1, 1, 1, 1, 1]) end it 'does calculate correct if cfp end date is altered' do @@ -1161,7 +1136,7 @@ describe Conference do cfp.end_date = Date.new(2014, 05, 26) + 21 cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 28)] - expect(subject.get_submissions_per_week).to eq([0, 0, 0, 0, 1]) + expect(subject.get_submissions_per_week.values).to eq([0, 0, 0, 0, 1]) end it 'pads with zeros if there are no submissions' do @@ -1169,7 +1144,7 @@ describe Conference do cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 21 cfp.save! - expect(subject.get_submissions_per_week).to eq([0, 0, 0, 0]) + expect(subject.get_submissions_per_week.values).to eq([0, 0, 0, 0]) end it 'summarized correct if there are no submissions in one week' do @@ -1180,7 +1155,7 @@ describe Conference do subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 7)] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 14)] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 28)] - expect(subject.get_submissions_per_week).to eq([0, 1, 2, 2, 3]) + expect(subject.get_submissions_per_week.values).to eq([0, 1, 2, 2, 3]) end it 'summarized correct if there are submissions every week except the first' do @@ -1190,7 +1165,7 @@ describe Conference do cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 7)] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 14)] - expect(subject.get_submissions_per_week).to eq([0, 1, 2, 2]) + expect(subject.get_submissions_per_week.values).to eq([0, 1, 2, 2]) end it 'summarized correct if there are submissions every week' do @@ -1201,7 +1176,9 @@ describe Conference do subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26))] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 7)] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 14)] - expect(subject.get_submissions_per_week).to eq([1, 2, 3, 3]) + expect(subject.get_submissions_per_week).to eq( + 'Wk 1' => 1, 'Wk 2' => 2, 'Wk 3' => 3, 'Wk 4' => 3 + ) end it 'pads left' do @@ -1210,7 +1187,7 @@ describe Conference do cfp.end_date = Date.new(2014, 05, 26) + 21 cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 21)] - expect(subject.get_submissions_per_week).to eq([0, 0, 0, 1]) + expect(subject.get_submissions_per_week.values).to eq([0, 0, 0, 1]) end it 'pads middle' do @@ -1220,7 +1197,7 @@ describe Conference do cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26))] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 21)] - expect(subject.get_submissions_per_week).to eq([1, 1, 1, 2]) + expect(subject.get_submissions_per_week.values).to eq([1, 1, 1, 2]) end it 'pads right' do @@ -1229,7 +1206,7 @@ describe Conference do cfp.end_date = Date.new(2014, 05, 26) + 21 cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26))] - expect(subject.get_submissions_per_week).to eq([1, 1, 1, 1]) + expect(subject.get_submissions_per_week.values).to eq([1, 1, 1, 1]) end end @@ -1240,7 +1217,7 @@ describe Conference do start_date: Date.new(2014, 05, 26), end_date: Date.new(2014, 05, 26) + 21, conference: subject) - expect(subject.get_registrations_per_week).to eq([0, 0, 0, 0]) + expect(subject.get_registrations_per_week.values).to eq([0, 0, 0, 0]) end it 'summarized correct if there are no registrations in one week' do @@ -1255,7 +1232,7 @@ describe Conference do create(:registration, conference: subject, created_at: Date.new(2014, 05, 26) + 28) - expect(subject.get_registrations_per_week).to eq([0, 1, 2, 2, 3]) + expect(subject.get_registrations_per_week.values).to eq([0, 1, 2, 2, 3]) end it 'returns [1] if there is one registration on the first day' do @@ -1265,7 +1242,7 @@ describe Conference do create(:registration, conference: subject, created_at: Date.new(2014, 05, 26)) - expect(subject.get_registrations_per_week).to eq([1, 1]) + expect(subject.get_registrations_per_week.values).to eq([1, 1]) end it 'summarized correct if there are registrations every week' do @@ -1279,7 +1256,7 @@ describe Conference do create(:registration, conference: subject, created_at: Date.new(2014, 05, 26) + 14) - expect(subject.get_registrations_per_week).to eq([1, 2, 3, 3]) + expect(subject.get_registrations_per_week.values).to eq([1, 2, 3, 3]) end it 'summarized correct if there are registrations every week except the first' do @@ -1294,7 +1271,7 @@ describe Conference do create(:registration, conference: subject, created_at: Date.new(2014, 05, 26) + 28) - expect(subject.get_registrations_per_week).to eq([0, 1, 2, 2, 3]) + expect(subject.get_registrations_per_week.values).to eq([0, 1, 2, 2, 3]) end it 'pads left' do @@ -1309,7 +1286,7 @@ describe Conference do create(:registration, conference: subject, created_at: Date.new(2014, 05, 26) + 35) - expect(subject.get_registrations_per_week).to eq([0, 0, 0, 1, 2, 3]) + expect(subject.get_registrations_per_week.values).to eq([0, 0, 0, 1, 2, 3]) end it 'pads middle' do @@ -1322,7 +1299,7 @@ describe Conference do create(:registration, conference: subject, created_at: Date.new(2014, 05, 26) + 35) - expect(subject.get_registrations_per_week).to eq([1, 1, 1, 1, 1, 2]) + expect(subject.get_registrations_per_week.values).to eq([1, 1, 1, 1, 1, 2]) end it 'pads right' do @@ -1335,7 +1312,7 @@ describe Conference do create(:registration, conference: subject, created_at: Date.new(2014, 05, 26) + 7) - expect(subject.get_registrations_per_week).to eq([1, 2, 2, 2, 2, 2]) + expect(subject.get_registrations_per_week.values).to eq([1, 2, 2, 2, 2, 2]) end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 13fcec74..5396a987 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -99,6 +99,23 @@ describe User do expect(User.comment_notifiable(conference)).not_to include(user) end end + + describe 'user distribution scopes' do + it 'scopes active users' do + create(:user, last_sign_in_at: Date.today - 3.months + 1.day) # active + expect(User.active.count).to eq(1) + end + + it 'scopes unconfirmed users' do + create(:user, confirmed_at: nil) # unconfirmed + expect(User.unconfirmed.count).to eq(1) + end + + it 'scopes dead users' do + create(:user, last_sign_in_at: Time.zone.now - 1.year - 1.day) # dead + expect(User.dead.count).to eq(1) + end + end end describe 'methods' do