Intial event conflicts implementation

This commit is contained in:
Petko Bordjukov 2016-10-13 08:59:22 +03:00
parent bb663ce853
commit bcef815c08
12 changed files with 2649 additions and 10 deletions

View File

@ -4,4 +4,5 @@
//= require bootstrap-sprockets
//= require raphael
//= require morris
//= require chroma-js/chroma
//= require_directory .

View File

@ -1,11 +1,20 @@
conflictsScale=chroma.scale(['#469408', '#D9230F']).mode('lab');
$ ->
$('.cfp-toggle').click ->
$(this).addClass("disabled")
Morris.Line
element: 'submissions-chart'
data: $('#submissions-chart').data('submissions')
xkey: 'created_at'
ykeys: ['all_submissions', 'all_confirmations']
labels: ['Submissions', 'Confirmed submissions']
lineColors: ['#D9230F', '#469408']
resize: true
if $('#submissions-chart').length > 0
Morris.Line
element: 'submissions-chart'
data: $('#submissions-chart').data('submissions')
xkey: 'created_at'
ykeys: ['all_submissions', 'all_confirmations']
labels: ['Submissions', 'Confirmed submissions']
lineColors: ['#D9230F', '#469408']
resize: true
$('[data-conflicts]').each (e) ->
most_conflicts = parseInt($(this).data('most-conflicts'))
conflicts = parseInt($(this).data('conflicts'))
least_conflicts = parseInt($(this).data('least-conflicts'))
console.log 1.0 * (conflicts - least_conflicts) / (most_conflicts - least_conflicts)
$(this).css('background-color', conflictsScale(1.0 * (conflicts - least_conflicts) / (most_conflicts - least_conflicts)))

View File

@ -9,7 +9,7 @@ module EventsHelper
link_to icon('user-plus', participant.email),
new_management_conference_personal_profile_path(conference_id: event.conference.id,
user_id: participant.id),
title: t('.create_profile'), class: 'bg-danger'
title: t('management.events.event.create_profile'), class: 'bg-danger'
end
end.join(', ').html_safe
end

View File

@ -14,6 +14,9 @@ class Conference < ActiveRecord::Base
has_many :halls
has_many :event_types
has_many :events
has_many :approved_events,
-> { joins(:proposition).where(propositions: {status: Proposition.statuses[:approved]}) }, class_name: 'Event'
has_many :conflict_counts, through: :events
has_many :volunteer_teams
has_many :volunteers
has_one :call_for_participation, dependent: :destroy
@ -48,6 +51,28 @@ class Conference < ActiveRecord::Base
vote_data_endpoint.present?
end
def update_conflict_data!
update_vote_data! or raise ActiveRecord::Rollback
events.all? { |event| event.update_conflict_data(false) } or raise ActiveRecord::Rollback
end
def most_conflicts
conflict_counts.order(number_of_conflicts: :desc).first.try(:number_of_conflicts) || 0
end
def least_conflicts
conflict_counts.unscoped.order(number_of_conflicts: :asc).first.try(:number_of_conflicts) || 0
end
def most_conflicts_between_approved_events
conflict_counts.unscoped.where(left: approved_events, right: approved_events).order(number_of_conflicts: :desc).first.try(:number_of_conflicts) || 0
end
def least_conflicts_between_approved_events
conflict_counts.unscoped.where(left: approved_events, right: approved_events).order(number_of_conflicts: :asc).first.try(:number_of_conflicts) || 0
end
private
def planned_cfp_end_date_is_before_start_date
@ -75,9 +100,14 @@ class Conference < ActiveRecord::Base
@ranking ||= remote_summary_data['ranking'].map { |ranking_entry| EventRanking.new ranking_entry }
end
def conflicts
@conflicts ||= remote_summary_data['conflicts'].map { |conflicts_entry| ConflictsForEvent.new conflicts_entry }
end
def save
conference.transaction do
conference.number_of_ballots_cast = number_of_ballots
conflicts.all?(&:save) or raise ActiveRecord::Rollback
ranking.all?(&:save) or raise ActiveRecord::Rollback
conference.touch :vote_data_updated_at
conference.save or raise ActiveRecord::Rollback
@ -97,13 +127,28 @@ class Conference < ActiveRecord::Base
end.body)
end
class ConflictsForEvent
include ActiveModel::Model
attr_accessor :talk_id, :conflicts
def save
@event = Event.find(talk_id)
@event.conflict_counts.destroy_all or raise ActiveRecord::Rollback
conflicts.all? do |right_event_id, number_of_conflicts|
ConflictCount.create left_id: talk_id, right_id: right_event_id, number_of_conflicts: number_of_conflicts
end or raise ActiveRecord::Rollback
end
end
class EventRanking
include ActiveModel::Model
attr_accessor :talk_id, :votes, :place
def save
Event.find(talk_id).update(number_of_votes: votes, rank: place)
Event.where(id: talk_id).update_all(number_of_votes: votes, rank: place)
end
end
end

View File

@ -0,0 +1,5 @@
class ConflictCount < ActiveRecord::Base
belongs_to :left, class_name: 'Event'
belongs_to :right, class_name: 'Event'
has_one :conference, through: :left
end

View File

@ -9,6 +9,7 @@ class Event < ActiveRecord::Base
has_many :pending_participations, ->() { pending }, class_name: 'Participation'
has_many :approved_participations, ->() { approved }, class_name: 'Participation'
has_many :participants, through: :approved_participations
has_many :conflict_counts, -> { order(number_of_conflicts: :desc) }, foreign_key: :left_id
belongs_to :event_type

View File

@ -64,3 +64,51 @@
.col-xs-12
h3 = Event.human_attribute_name :participants
= render partial: 'speaker', collection: @event.participants
- if @conference.has_vote_results? or @conference.has_voting_endpoint?
.row
.col-xs-12
h2
= t '.conflicts'
small< = t '.between_approved_events'
.panel.panel-default
table.table.table-striped.table-hover.record-table
- if @conference.has_vote_results? and @conference.approved_events.count > 2
thead
tr
th.text-right
= t '.percent'
th
= Event.model_name.human.mb_chars.capitalize
th
tbody
- if @conference.has_vote_results?
- if @conference.approved_events.count > 2
- @event.conflict_counts.where(right_id: @conference.approved_events.pluck(:id)).includes(:right).each do |conflict_count|
- conflict_percent = Rational(conflict_count.number_of_conflicts, @conference.number_of_ballots_cast)
tr
td.text-right
.large
span.label.label-success data-conflicts="#{conflict_count.number_of_conflicts}" data-most-conflicts="#{@conference.most_conflicts_between_approved_events}" data-least-conflicts="#{@conference.least_conflicts_between_approved_events}"
= number_to_percentage(conflict_percent * 100, strip_insignificant_zeros: true, precision: 2)
td
h4 = conflict_count.right.title
h5 = conflict_count.right.subtitle
= links_to_event_participants_for(conflict_count.right)
td.actions
= action_buttons @conference, conflict_count.right, [:show]
- else
tr
td colspan="20"
= t '.no_approved_events'
- else
tr
td colspan="20"
= t 'management.conferences.vote_results.vote_data_never_updated'
= icon :refresh, t('management.conferences.vote_results.fetch_vote_results')
- if @conference.has_vote_results?
.panel-footer.text-right
.btn-group
= link_to update_vote_data_management_conference_path(@conference), method: :patch, class: ['btn', 'btn-primary'] do
= icon :refresh, t('management.conferences.vote_results.fetch_vote_results')

View File

@ -51,8 +51,12 @@ bg:
previous_event_propositions: 'Предишни предложения за събития'
contacts: "Информация за контакт"
show:
between_approved_events: "Между одобрени събития"
no_approved_events: "Няма достатъчно одобрени събития"
rank: "Класиране"
review: "Преглед на %{event_type} „%{event_title}“"
conflicts: "Конфликти"
percent: "Процент"
index:
all: "Всички"
total: "%{current} от общо %{total}"

View File

@ -0,0 +1,11 @@
class CreateConflictCounts < ActiveRecord::Migration
def change
create_table :conflict_counts do |t|
t.references :left, index: true
t.references :right, index: true
t.integer :number_of_conflicts
end
add_index :conflict_counts, [:left_id, :right_id], unique: true
end
end

View File

@ -0,0 +1,28 @@
chroma.js - JavaScript library for color conversions
Copyright (c) 2011-2015, Gregor Aisch
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name Gregor Aisch may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,22 @@
chroma.js includes colors from colorbrewer2.org,
which are released under the following license:
Copyright (c) 2002 Cynthia Brewer, Mark Harrower,
and The Pennsylvania State University.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied. See the License for the specific
language governing permissions and limitations under the License.
Named colors are taken from X11 Color Names.
http://www.w3.org/TR/css3-color/#svg-color

File diff suppressed because it is too large Load Diff