From b645b1a4ffeb73d405539a595c5917421a980843 Mon Sep 17 00:00:00 2001 From: Chrisbr Date: Mon, 2 Jun 2014 12:37:57 +0200 Subject: [PATCH] Implements registrations and last login information for dashboard --- app/assets/javascripts/dashboard.js | 29 ++- app/assets/stylesheets/osem.css | 20 ++ .../admin/conference_controller.rb | 33 ++- app/helpers/application_helper.rb | 8 + app/models/call_for_papers.rb | 24 +- app/models/conference.rb | 117 +++++++-- app/models/event.rb | 2 +- app/models/registration.rb | 4 + app/views/admin/conference/index.html.haml | 65 ++++- .../conferences_controller_spec.rb | 4 +- spec/factories/registration.rb | 8 + spec/models/conference_spec.rb | 231 ++++++++++++++++++ 12 files changed, 496 insertions(+), 49 deletions(-) create mode 100644 spec/factories/registration.rb diff --git a/app/assets/javascripts/dashboard.js b/app/assets/javascripts/dashboard.js index 36526ba4..e18b682f 100644 --- a/app/assets/javascripts/dashboard.js +++ b/app/assets/javascripts/dashboard.js @@ -11,10 +11,9 @@ $(function() { "width":$(el).parent().width(), "height":$(el).parent().outerHeight() }); + redraw(animate, $(this)); }); - redraw(animate); - var m = 0; $(".widget").height(""); $(".widget").each(function(i,el){ m = Math.max(m,$(el).height()); }); @@ -22,7 +21,7 @@ $(function() { }, 30); } - function redraw(animation){ + function redraw(animation, $this){ var options = {}; if (!animation){ options.animation = false; @@ -30,22 +29,22 @@ $(function() { options.animation = true; } - var chart_data = create_dataset(); - var weeks = $('.submissionsChart').data('weeks'); + var chart_data = create_dataset($this); + var weeks = $this.parent().data('weeks'); var data = { labels : weeks, datasets : chart_data } - var canvas = document.getElementById("chart"); + var canvas = $this[0]; var ctx = canvas.getContext("2d"); new Chart(ctx).Line(data, options); } - function create_dataset(){ - var selected = getSelectedConferences(); - var chart_data = $('.submissionsChart').data('chart'); - var conferences = $('.submissionsChart').data('conferences'); + function create_dataset($this){ + var selected = getSelectedConferences($this); + var chart_data = $this.parent().data('chart'); + var conferences = $this.parent().data('conferences'); var result = []; for(var i in conferences){ @@ -60,9 +59,11 @@ $(function() { return result } - function getSelectedConferences(){ + function getSelectedConferences($this){ + var name = $this.data('name'); + var id = '#' + name + 'Checkboxes' var selected = [] - $('.conferenceCheckboxes input').each(function(){ + $(id + ' input').each(function(){ if($(this).is(":checked")) { selected.push($(this).attr('name')); } @@ -71,7 +72,9 @@ $(function() { } $('.conferenceCheckboxes input').change(function(){ - redraw(false); + var chart = $(this).parent().data('chart'); + var $canvas = $('#' + chart + 'Chart'); + redraw(false, $canvas); }); $(window).on('resize', function(){ size(false); }); diff --git a/app/assets/stylesheets/osem.css b/app/assets/stylesheets/osem.css index 08c9f1a7..c065333e 100644 --- a/app/assets/stylesheets/osem.css +++ b/app/assets/stylesheets/osem.css @@ -55,3 +55,23 @@ body > #messages { display: inline-block; padding: 0px 10px 0px 0px; } + +.dashbox { + padding-top: 20px; + padding-bottom: 20px; +} + +.dashbox .icon { + display: block; + font-size: 3.5em; +} + +.dashbox var { + display: block; + font-size: 2em; + font-style: normal; +} + +.dashbox label { + font-size: 1.2em; +} diff --git a/app/controllers/admin/conference_controller.rb b/app/controllers/admin/conference_controller.rb index 86de0667..047cedfa 100644 --- a/app/controllers/admin/conference_controller.rb +++ b/app/controllers/admin/conference_controller.rb @@ -2,18 +2,37 @@ class Admin::ConferenceController < ApplicationController before_filter :verify_organizer def index - @conferences = Conference.select('id, short_title, color, start_date') + @total_user = User.count + @new_user = User.where('created_at > ?', current_user.last_sign_in_at).count + @new_reg = Registration.where('created_at > ?', current_user.last_sign_in_at).count + @total_reg = Registration.count - # Event submissions over time - @weeks = CallForPapers.max_weeks - @result = {} + @conferences = Conference.select('id, short_title, color, start_date, + registration_end_date, registration_start_date') + + @submissions = {} + @cfp_weeks = [0] + + @registrations = {} + @registration_weeks = [0] @conferences.each do |c| - submission = c.get_submissions_per_week(@weeks) - @result[c.short_title] = submission + # Event submissions over time chart + @submissions[c.short_title] = c.get_submissions_per_week + @cfp_weeks.push(c.cfp_weeks) + + # Conference registrations over time chart + @registrations[c.short_title] = c.get_registrations_per_week + @registration_weeks.push(c.registration_weeks) end - @weeks = @weeks > 0 ? (1..@weeks).to_a : 1 + @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 # Redirect to new form if there is no conference if Conference.count == 0 diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index befc56a4..a68e06ac 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -15,6 +15,14 @@ module ApplicationHelper end end + def normalize_array_length(hashmap, length) + hashmap.each do |key, value| + if value.length < length + value.fill(value[-1], value.length...length) + end + end + end + def active_nav_li(link) if current_page?(link) return 'active' diff --git a/app/models/call_for_papers.rb b/app/models/call_for_papers.rb index 73dcd22b..b8eaeddd 100644 --- a/app/models/call_for_papers.rb +++ b/app/models/call_for_papers.rb @@ -7,19 +7,29 @@ class CallForPapers < ActiveRecord::Base validates_presence_of :start_date, :end_date, :hard_deadline validates :rating, :numericality => { :greater_than_or_equal_to => 0, :less_than_or_equal_to => 10 } - def self.max_weeks - all = CallForPapers.all - result = [0] - all.each do |cfp| - result.push(cfp.end_week - cfp.start_week) - end - result.max + ## + # Calculates how many weeks the call for paper is. + # + # ====Returns + # * +Integer+ -> start week + def weeks + result = end_week - start_week + 1 + weeks = Date.new(start_week.year, 12, 31).strftime('%W').to_i + result < 0 ? result + weeks : result end + ## + # Calculates the end week of the cfp + # + # ====Returns def start_week start_date.strftime('%W').to_i end + ## + # Calculates the end week of the cfp + # + # ====Returns def end_week end_date.strftime('%W').to_i end diff --git a/app/models/conference.rb b/app/models/conference.rb index 64561606..c86c4df8 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -127,31 +127,89 @@ class Conference < ActiveRecord::Base ## # Returns an array with the summarized event submissions per week. - # ====Params: - # * +weeks+ -> Integer with number of weeks. This is necessary to compare conferences. # # ====Returns # * +Array+ -> e.g. [0, 3, 3, 5] -> first week 0 events, second week 3 events. - def get_submissions_per_week(weeks) + def get_submissions_per_week result = [] if call_for_papers && events - submissions = events.select('id, created_at').group_by { |t| t.week } + submissions = events.group("strftime('%W', created_at)").count start_week = call_for_papers.start_week - sum = 0 - - (0..weeks - 1).each do |week| - if submissions["#{week + start_week}"] - sum += submissions["#{week + start_week}"].length - end - result.push(sum) - end - else - result = Array.new(weeks, 0) + weeks = call_for_papers.weeks + result = calculate_items_per_week(start_week, weeks, submissions) end result end + ## + # Returns an array with the summarized registrations per week. + # + # ====Returns + # * +Array+ -> e.g. [0, 3, 3, 5] -> first week 0, second week 3 registrations + def get_registrations_per_week + result = [] + + if registrations && + registration_start_date && + registration_end_date + + reg = registrations.group("strftime('%W', created_at)").count + start_week = get_registration_start_week + weeks = registration_weeks + result = calculate_items_per_week(start_week, weeks, reg) + end + result + end + + ## + # Calculates how many weeks the registration is. + # + # ====Returns + # * +Integer+ -> start week + def registration_weeks + result = 0 + weeks = 0 + if registration_start_date && registration_end_date + weeks = Date.new(registration_start_date.year, 12, 31). + strftime('%W').to_i + + result = get_registration_end_week - get_registration_start_week + 1 + end + result < 0 ? result + weeks : result + end + + ## + # Calculates how many weeks call for papers is. + # + # ====Returns + # * +Integer+ -> weeks + def cfp_weeks + result = 0 + if call_for_papers + result = call_for_papers.weeks + end + result + end + + ## + # Calculates the end week of the registration + # + # ====Returns + # * +Integer+ -> start week + def get_registration_start_week + registration_start_date.strftime('%W').to_i + end + + ## + # Calculates the start week of the registration + # + # ====Returns + # * +Integer+ -> start week + def get_registration_end_week + registration_end_date.strftime('%W').to_i + end + ## # Checks if the conference is pending. # @@ -204,4 +262,35 @@ class Conference < ActiveRecord::Base ).sample end end + + # Calculates items per week from a hash. + # + # ====Returns + # * +Array+ -> e.g. [1, 3, 3, 5] -> first week 1, second week 2 registrations + def calculate_items_per_week(start_week, weeks, items) + sum = 0 + result = [] + last_key = start_week + 1 + + items.each_with_index do |(key, value), index| + # Padding left + if index == 0 + result = Array.new(key.to_i - start_week, 0) + # Padding middle + elsif last_key < (key.to_i - 1) + result += Array.new(key.to_i - last_key - 1, sum) + end + + sum += value + result.push(sum) + last_key = key.to_i + end + + # Padding right + if result.length < weeks + result += Array.new(weeks - result.length, sum) + end + + result + end end diff --git a/app/models/event.rb b/app/models/event.rb index 00442843..f4de3182 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -175,7 +175,7 @@ class Event < ActiveRecord::Base end def week - created_at.strftime('%W') + created_at.strftime('%W').to_i end private diff --git a/app/models/registration.rb b/app/models/registration.rb index 8488bcc4..e218eb8f 100644 --- a/app/models/registration.rb +++ b/app/models/registration.rb @@ -33,4 +33,8 @@ class Registration < ActiveRecord::Base delegate :tshirt, :to => :person alias_attribute :other_needs, :other_special_needs + + def week + created_at.strftime('%W').to_i + end end diff --git a/app/views/admin/conference/index.html.haml b/app/views/admin/conference/index.html.haml index 7f67e87b..83d64ea0 100644 --- a/app/views/admin/conference/index.html.haml +++ b/app/views/admin/conference/index.html.haml @@ -1,20 +1,75 @@ +.row + .col-sm-3 + .dashbox.well.well-sm.text-center + .icon + %i.glyphicon.glyphicon-user + .text + %var + = @total_user + %label.text-muted total user + .col-sm-3 + .dashbox.well.well-sm.text-center + .icon + %i.glyphicon.glyphicon-thumbs-up + .text + %var + = @new_user + %label.text-muted new user + .col-sm-3 + .dashbox.well.well-sm.text-center + .icon + %i.glyphicon.glyphicon-star + .text + %var + = @total_reg + %label.text-muted total registrations + .col-sm-3 + .dashbox.well.well-sm.text-center + .icon + %i.glyphicon.glyphicon-usd + .text + %var + = @new_reg + %label.text-muted new registrations .row .col-md-12 - .well + .well#submissions .row .text-center %h4 Event submissions over time .row - .submissionsChart{"data-chart"=>"#{@result.to_json}", "data-conferences"=>"#{@conferences.to_json}", "data-weeks"=>"#{@weeks.to_json}"} - %canvas#chart + .submissionsChart{"data-chart"=>"#{@submissions.to_json}", "data-conferences"=>"#{@conferences.to_json}", "data-weeks"=>"#{@cfp_weeks.to_json}"} + %canvas#submissionsChart{"data-name"=>"submissions"} .row .text-center weeks .row - .conferenceCheckboxes + .conferenceCheckboxes#submissionsCheckboxes - @conferences.each do |conference| %div - %span{"style"=>"border-bottom: 3px solid #{conference.color};"} + %span{"style"=>"border-bottom: 3px solid #{conference.color};", "data-chart"=> "submissions"} + - if conference.pending? + %input{"type"=>"checkbox", "name"=>"#{conference.short_title}", "checked"=>"checked"} + - else + %input{"type"=>"checkbox", "name"=>"#{conference.short_title}"} + #{conference.short_title} +.row + .col-md-12 + .well#registrations + .row + .text-center + %h4 Conference registrations over time + .row + .registrationsChart{"data-chart"=>"#{@registrations.to_json}", "data-conferences"=>"#{@conferences.to_json}", "data-weeks"=>"#{@registration_weeks.to_json}"} + %canvas#registrationsChart{"data-name"=>"registrations"} + .row + .text-center + weeks + .row + .conferenceCheckboxes#registrationsCheckboxes + - @conferences.each do |conference| + %div + %span{"style"=>"border-bottom: 3px solid #{conference.color};", "data-chart"=> "registrations"} - if conference.pending? %input{"type"=>"checkbox", "name"=>"#{conference.short_title}", "checked"=>"checked"} - else diff --git a/spec/controllers/conferences_controller_spec.rb b/spec/controllers/conferences_controller_spec.rb index 580e96ff..bfff37c0 100644 --- a/spec/controllers/conferences_controller_spec.rb +++ b/spec/controllers/conferences_controller_spec.rb @@ -155,12 +155,12 @@ describe Admin::ConferenceController do it 'assigns cfp_max an array with maximum weeks' do conference - date = Date.new(2014, 05, 28) + date = Date.new(2014, 05, 26) conference.call_for_papers = create(:call_for_papers, start_date: date, end_date: date + 14) get :index - expect(assigns(:weeks)).to match_array([1, 2]) + expect(assigns(:cfp_weeks)).to match_array([1, 2, 3]) end it 'renders the index template' do diff --git a/spec/factories/registration.rb b/spec/factories/registration.rb new file mode 100644 index 00000000..6d72df9b --- /dev/null +++ b/spec/factories/registration.rb @@ -0,0 +1,8 @@ +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :registration do + person + conference + end +end diff --git a/spec/models/conference_spec.rb b/spec/models/conference_spec.rb index c9c5f9c4..7f49addd 100644 --- a/spec/models/conference_spec.rb +++ b/spec/models/conference_spec.rb @@ -6,6 +6,237 @@ describe Conference do let(:subject) { create(:conference) } + describe '#registration_weeks' do + + it 'calculates new year' do + subject.registration_start_date = Date.new(2013, 12, 31) + subject.registration_end_date = Date.new(2013, 12, 30) + 6 + expect(subject.registration_weeks).to eq(1) + end + + it 'is one if start and end are 6 days apart' do + subject.registration_start_date = Date.new(2014, 05, 26) + subject.registration_end_date = Date.new(2014, 05, 26) + 6 + expect(subject.registration_weeks).to eq(1) + end + + it 'is one if start and end date are the same' do + subject.registration_start_date = Date.new(2014, 05, 26) + subject.registration_end_date = Date.new(2014, 05, 26) + expect(subject.registration_weeks).to eq(1) + end + + it 'is two if start and end are 10 days apart' do + subject.registration_start_date = Date.new(2014, 05, 26) + subject.registration_end_date = Date.new(2014, 05, 26) + 10 + expect(subject.registration_weeks).to eq(2) + end + end + + describe '#cfp_weeks' do + + it 'calculates new year' do + cfp = create(:call_for_papers) + cfp.start_date = Date.new(2013, 12, 30) + cfp.end_date = Date.new(2013, 12, 30) + 6 + subject.call_for_papers = cfp + expect(subject.cfp_weeks).to eq(1) + end + + it 'is one if start and end are 6 days apart' do + cfp = create(:call_for_papers) + cfp.start_date = Date.new(2014, 05, 26) + cfp.end_date = Date.new(2014, 05, 26) + 6 + subject.call_for_papers = cfp + expect(subject.cfp_weeks).to eq(1) + end + + it 'is one if start and end are the same date' do + cfp = create(:call_for_papers) + cfp.start_date = Date.new(2014, 05, 26) + cfp.end_date = Date.new(2014, 05, 26) + subject.call_for_papers = cfp + expect(subject.cfp_weeks).to eq(1) + end + + it 'is two if start and end are 10 days apart' do + cfp = create(:call_for_papers) + cfp.start_date = Date.new(2014, 05, 26) + cfp.end_date = Date.new(2014, 05, 26) + 10 + subject.call_for_papers = cfp + expect(subject.cfp_weeks).to eq(2) + end + end + + describe '#get_submissions_per_week' do + + it 'pads with zeros if there are no submissions' do + cfp = create(:call_for_papers) + cfp.start_date = Date.new(2014, 05, 26) + cfp.end_date = Date.new(2014, 05, 26) + 21 + subject.call_for_papers = cfp + expect(subject.get_submissions_per_week).to eq([0, 0, 0, 0]) + end + + it 'summarized correct if there are no submissions in one week' do + cfp = create(:call_for_papers) + cfp.start_date = Date.new(2014, 05, 26) + cfp.end_date = Date.new(2014, 05, 26) + 28 + subject.call_for_papers = cfp + subject.events += [create(:event, created_at: Date.new(2014, 05, 26) + 7)] + subject.events += [create(:event, created_at: Date.new(2014, 05, 26) + 14)] + subject.events += [create(:event, created_at: Date.new(2014, 05, 26) + 28)] + expect(subject.get_submissions_per_week).to eq([0, 1, 2, 2, 3]) + end + + it 'summarized correct if there are submissions every week except the first' do + cfp = create(:call_for_papers) + cfp.start_date = Date.new(2014, 05, 26) + cfp.end_date = Date.new(2014, 05, 26) + 21 + subject.call_for_papers = cfp + subject.events += [create(:event, created_at: Date.new(2014, 05, 26) + 7)] + subject.events += [create(:event, created_at: Date.new(2014, 05, 26) + 14)] + expect(subject.get_submissions_per_week).to eq([0, 1, 2, 2]) + end + + it 'summarized correct if there are submissions every week' do + cfp = create(:call_for_papers) + cfp.start_date = Date.new(2014, 05, 26) + cfp.end_date = Date.new(2014, 05, 26) + 21 + subject.call_for_papers = cfp + subject.events += [create(:event, created_at: Date.new(2014, 05, 26))] + subject.events += [create(:event, created_at: Date.new(2014, 05, 26) + 7)] + subject.events += [create(:event, created_at: Date.new(2014, 05, 26) + 14)] + expect(subject.get_submissions_per_week).to eq([1, 2, 3, 3]) + end + + it 'pads left' do + cfp = create(:call_for_papers) + cfp.start_date = Date.new(2014, 05, 26) + cfp.end_date = Date.new(2014, 05, 26) + 21 + subject.call_for_papers = cfp + subject.events += [create(:event, created_at: Date.new(2014, 05, 26) + 21)] + expect(subject.get_submissions_per_week).to eq([0, 0, 0, 1]) + end + + it 'pads middle' do + cfp = create(:call_for_papers) + cfp.start_date = Date.new(2014, 05, 26) + cfp.end_date = Date.new(2014, 05, 26) + 21 + subject.call_for_papers = cfp + subject.events += [create(:event, created_at: Date.new(2014, 05, 26))] + subject.events += [create(:event, created_at: Date.new(2014, 05, 26) + 21)] + expect(subject.get_submissions_per_week).to eq([1, 1, 1, 2]) + end + + it 'pads right' do + cfp = create(:call_for_papers) + cfp.start_date = Date.new(2014, 05, 26) + cfp.end_date = Date.new(2014, 05, 26) + 21 + subject.call_for_papers = cfp + subject.events += [create(:event, created_at: Date.new(2014, 05, 26))] + expect(subject.get_submissions_per_week).to eq([1, 1, 1, 1]) + end + end + + describe '#get_registrations_per_week' do + + it 'pads with zeros if there are no registrations' do + subject.registration_start_date = Date.new(2014, 05, 26) + subject.registration_end_date = Date.new(2014, 05, 26) + 21 + + expect(subject.get_registrations_per_week).to eq([0, 0, 0, 0]) + end + + it 'summarized correct if there are no registrations in one week' do + subject.registration_start_date = Date.new(2014, 05, 26) + subject.registration_end_date = Date.new(2014, 05, 26) + 28 + + create(:registration, conference: subject, + created_at: Date.new(2014, 05, 26) + 7) + create(:registration, conference: subject, + created_at: Date.new(2014, 05, 26) + 14) + 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]) + end + + it 'returns [1] if there is one registration on the first day' do + subject.registration_start_date = Date.new(2014, 05, 26) + subject.registration_end_date = Date.new(2014, 05, 26) + 7 + + create(:registration, conference: subject, + created_at: Date.new(2014, 05, 26)) + expect(subject.get_registrations_per_week).to eq([1, 1]) + end + + it 'summarized correct if there are registrations every week' do + subject.registration_start_date = Date.new(2014, 05, 26) + subject.registration_end_date = Date.new(2014, 05, 26) + 21 + + create(:registration, conference: subject, created_at: Date.new(2014, 05, 26)) + create(:registration, conference: subject, + created_at: Date.new(2014, 05, 26) + 7) + create(:registration, conference: subject, + created_at: Date.new(2014, 05, 26) + 14) + + expect(subject.get_registrations_per_week).to eq([1, 2, 3, 3]) + end + + it 'summarized correct if there are registrations every week except the first' do + subject.registration_start_date = Date.new(2014, 05, 26) + subject.registration_end_date = Date.new(2014, 05, 26) + 28 + + create(:registration, conference: subject, + created_at: Date.new(2014, 05, 26) + 7) + create(:registration, conference: subject, + created_at: Date.new(2014, 05, 26) + 14) + 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]) + end + + it 'pads left' do + subject.registration_start_date = Date.new(2014, 05, 26) + subject.registration_end_date = Date.new(2014, 05, 26) + 35 + + create(:registration, conference: subject, + created_at: Date.new(2014, 05, 26) + 21) + create(:registration, conference: subject, + created_at: Date.new(2014, 05, 26) + 28) + 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]) + end + + it 'pads middle' do + subject.registration_start_date = Date.new(2014, 05, 26) + subject.registration_end_date = Date.new(2014, 05, 26) + 35 + + create(:registration, conference: subject, + created_at: Date.new(2014, 05, 26)) + 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]) + end + + it 'pads right' do + subject.registration_start_date = Date.new(2014, 05, 26) + subject.registration_end_date = Date.new(2014, 05, 26) + 35 + + create(:registration, conference: subject, + created_at: Date.new(2014, 05, 26)) + 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]) + end + end + describe '#pending?' do context 'is pending' do