Intial event conflicts implementation
This commit is contained in:
parent
bb663ce853
commit
bcef815c08
|
@ -4,4 +4,5 @@
|
||||||
//= require bootstrap-sprockets
|
//= require bootstrap-sprockets
|
||||||
//= require raphael
|
//= require raphael
|
||||||
//= require morris
|
//= require morris
|
||||||
|
//= require chroma-js/chroma
|
||||||
//= require_directory .
|
//= require_directory .
|
||||||
|
|
|
@ -1,11 +1,20 @@
|
||||||
|
conflictsScale=chroma.scale(['#469408', '#D9230F']).mode('lab');
|
||||||
|
|
||||||
$ ->
|
$ ->
|
||||||
$('.cfp-toggle').click ->
|
$('.cfp-toggle').click ->
|
||||||
$(this).addClass("disabled")
|
$(this).addClass("disabled")
|
||||||
Morris.Line
|
if $('#submissions-chart').length > 0
|
||||||
element: 'submissions-chart'
|
Morris.Line
|
||||||
data: $('#submissions-chart').data('submissions')
|
element: 'submissions-chart'
|
||||||
xkey: 'created_at'
|
data: $('#submissions-chart').data('submissions')
|
||||||
ykeys: ['all_submissions', 'all_confirmations']
|
xkey: 'created_at'
|
||||||
labels: ['Submissions', 'Confirmed submissions']
|
ykeys: ['all_submissions', 'all_confirmations']
|
||||||
lineColors: ['#D9230F', '#469408']
|
labels: ['Submissions', 'Confirmed submissions']
|
||||||
resize: true
|
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)))
|
||||||
|
|
|
@ -9,7 +9,7 @@ module EventsHelper
|
||||||
link_to icon('user-plus', participant.email),
|
link_to icon('user-plus', participant.email),
|
||||||
new_management_conference_personal_profile_path(conference_id: event.conference.id,
|
new_management_conference_personal_profile_path(conference_id: event.conference.id,
|
||||||
user_id: participant.id),
|
user_id: participant.id),
|
||||||
title: t('.create_profile'), class: 'bg-danger'
|
title: t('management.events.event.create_profile'), class: 'bg-danger'
|
||||||
end
|
end
|
||||||
end.join(', ').html_safe
|
end.join(', ').html_safe
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,6 +14,9 @@ class Conference < ActiveRecord::Base
|
||||||
has_many :halls
|
has_many :halls
|
||||||
has_many :event_types
|
has_many :event_types
|
||||||
has_many :events
|
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 :volunteer_teams
|
||||||
has_many :volunteers
|
has_many :volunteers
|
||||||
has_one :call_for_participation, dependent: :destroy
|
has_one :call_for_participation, dependent: :destroy
|
||||||
|
@ -48,6 +51,28 @@ class Conference < ActiveRecord::Base
|
||||||
vote_data_endpoint.present?
|
vote_data_endpoint.present?
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
def planned_cfp_end_date_is_before_start_date
|
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 }
|
@ranking ||= remote_summary_data['ranking'].map { |ranking_entry| EventRanking.new ranking_entry }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def conflicts
|
||||||
|
@conflicts ||= remote_summary_data['conflicts'].map { |conflicts_entry| ConflictsForEvent.new conflicts_entry }
|
||||||
|
end
|
||||||
|
|
||||||
def save
|
def save
|
||||||
conference.transaction do
|
conference.transaction do
|
||||||
conference.number_of_ballots_cast = number_of_ballots
|
conference.number_of_ballots_cast = number_of_ballots
|
||||||
|
conflicts.all?(&:save) or raise ActiveRecord::Rollback
|
||||||
ranking.all?(&:save) or raise ActiveRecord::Rollback
|
ranking.all?(&:save) or raise ActiveRecord::Rollback
|
||||||
conference.touch :vote_data_updated_at
|
conference.touch :vote_data_updated_at
|
||||||
conference.save or raise ActiveRecord::Rollback
|
conference.save or raise ActiveRecord::Rollback
|
||||||
|
@ -97,13 +127,28 @@ class Conference < ActiveRecord::Base
|
||||||
end.body)
|
end.body)
|
||||||
end
|
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
|
class EventRanking
|
||||||
include ActiveModel::Model
|
include ActiveModel::Model
|
||||||
|
|
||||||
attr_accessor :talk_id, :votes, :place
|
attr_accessor :talk_id, :votes, :place
|
||||||
|
|
||||||
def save
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
|
@ -9,6 +9,7 @@ class Event < ActiveRecord::Base
|
||||||
has_many :pending_participations, ->() { pending }, class_name: 'Participation'
|
has_many :pending_participations, ->() { pending }, class_name: 'Participation'
|
||||||
has_many :approved_participations, ->() { approved }, class_name: 'Participation'
|
has_many :approved_participations, ->() { approved }, class_name: 'Participation'
|
||||||
has_many :participants, through: :approved_participations
|
has_many :participants, through: :approved_participations
|
||||||
|
has_many :conflict_counts, -> { order(number_of_conflicts: :desc) }, foreign_key: :left_id
|
||||||
|
|
||||||
belongs_to :event_type
|
belongs_to :event_type
|
||||||
|
|
||||||
|
|
|
@ -64,3 +64,51 @@
|
||||||
.col-xs-12
|
.col-xs-12
|
||||||
h3 = Event.human_attribute_name :participants
|
h3 = Event.human_attribute_name :participants
|
||||||
= render partial: 'speaker', collection: @event.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')
|
||||||
|
|
|
@ -51,8 +51,12 @@ bg:
|
||||||
previous_event_propositions: 'Предишни предложения за събития'
|
previous_event_propositions: 'Предишни предложения за събития'
|
||||||
contacts: "Информация за контакт"
|
contacts: "Информация за контакт"
|
||||||
show:
|
show:
|
||||||
|
between_approved_events: "Между одобрени събития"
|
||||||
|
no_approved_events: "Няма достатъчно одобрени събития"
|
||||||
rank: "Класиране"
|
rank: "Класиране"
|
||||||
review: "Преглед на %{event_type} „%{event_title}“"
|
review: "Преглед на %{event_type} „%{event_title}“"
|
||||||
|
conflicts: "Конфликти"
|
||||||
|
percent: "Процент"
|
||||||
index:
|
index:
|
||||||
all: "Всички"
|
all: "Всички"
|
||||||
total: "%{current} от общо %{total}"
|
total: "%{current} от общо %{total}"
|
||||||
|
|
|
@ -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
|
|
@ -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.
|
|
@ -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
Loading…
Reference in New Issue