Registration for Events

This commit is contained in:
Stella Rouzi 2016-04-22 18:18:46 +03:00
parent f188fd5575
commit 01ec43e53a
35 changed files with 522 additions and 46 deletions

View file

@ -3,6 +3,7 @@ module Admin
load_and_authorize_resource :conference, find_by: :short_title
load_and_authorize_resource :program, through: :conference, singleton: true
load_and_authorize_resource :event, through: :program
load_and_authorize_resource :events_registration, only: :toggle_attendance
before_action :get_event, except: [:index, :create]
@ -116,7 +117,7 @@ module Admin
end
else
@url = admin_conference_program_event_path(@conference.short_title, @event)
flash[:notice] = 'Update not successful. ' + @event.errors.full_messages.to_sentence
flash[:error] = 'Update not successful. ' + @event.errors.full_messages.to_sentence
render :edit
end
end
@ -165,6 +166,20 @@ module Admin
end
end
def registrations
@event_registrations = @event.events_registrations
end
def toggle_attendance
@events_registration.attended = !@events_registration.attended
if @events_registration.save
head :ok
else
head :unprocessable_entity
end
end
private
def event_params
@ -172,7 +187,7 @@ module Admin
# Set also in proposals controller
:title, :subtitle, :event_type_id, :abstract, :description, :require_registration, :difficulty_level_id,
# Set only in admin/events controller
:track_id, :state, :language, :start_time, :is_highlight,
:track_id, :state, :language, :start_time, :is_highlight, :max_attendees,
# Not used anymore?
:proposal_additional_speakers, :user, :users_attributes)
end

View file

@ -33,7 +33,6 @@ class ConferenceRegistrationsController < ApplicationController
end
def show
@workshops = @registration.workshops
@total_price = Ticket.total_price(@conference, current_user)
@tickets = current_user.ticket_purchases.where(conference_id: @conference.id)
end

View file

@ -145,10 +145,14 @@ class ProposalController < ApplicationController
end
end
def registrations; end
private
def event_params
params.require(:event).permit(:title, :subtitle, :track_id, :event_type_id, :abstract, :description, :require_registration, :difficulty_level_id)
params.require(:event).permit(:event_type_id, :track_id, :difficulty_level_id,
:title, :subtitle, :abstract, :description,
:require_registration, :max_attendees)
end
def user_params

View file

@ -1,4 +1,12 @@
module ApplicationHelper
##
# ====Returns
# * +String+ -> number of registrations / max allowed registrations
def registered_text(event)
return "Registered: #{event.registrations.count}/#{event.max_attendees}" if event.max_attendees
"Registered: #{event.registrations.count}"
end
# Set resource_name for devise so that we can call the devise help links (views/devise/shared/_links) from anywhere (eg sign_up form in proposal#new)
def resource_name
:user

View file

@ -14,7 +14,8 @@ class Event < ActiveRecord::Base
has_many :commercials, as: :commercialable, dependent: :destroy
belongs_to :event_type
has_and_belongs_to_many :registrations
has_many :events_registrations
has_many :registrations, through: :events_registrations
belongs_to :track
belongs_to :room
@ -32,6 +33,10 @@ class Event < ActiveRecord::Base
validates :abstract, presence: true
validates :event_type, presence: true
validates :program, presence: true
validates :max_attendees, numericality: { only_integer: true, greater_than_or_equal_to: 1, allow_nil: true }
validate :max_attendees_and_require_registration
validate :max_attendees_no_more_than_room_size
scope :confirmed, -> { where(state: 'confirmed') }
scope :highlighted, -> { where(is_highlight: true) }
@ -64,6 +69,19 @@ class Event < ActiveRecord::Base
end
end
##
# Checkes if the event has a start_time and a room
# ====Returns
# * +true+ or +false+
def scheduled?
room && start_time ? true : false
end
def registration_possible?
return false unless max_attendees
registrations.count < max_attendees
end
def voted?(event, user)
event.votes.where('user_id = ?', user).first
end
@ -207,6 +225,21 @@ class Event < ActiveRecord::Base
private
##
# If max_attendees variable is set (higher than 0)
# variable require_registration must also be set
def max_attendees_and_require_registration
errors.add(:require_registration, 'must be enabled, when you set max_attendees') if max_attendees && !require_registration
errors.add(:max_attendees, 'must be enabled, when you set require_registration') if require_registration && max_attendees.nil?
end
##
# Do not allow, for the event, more attendees than the size of the room
def max_attendees_no_more_than_room_size
return unless room && max_attendees_changed?
errors.add(:max_attendees, "cannot be more than the room's capacity (#{room.size})") if max_attendees && (max_attendees > room.size)
end
def abstract_limit
# If we don't have an event type, there is no need to count anything
return unless event_type && abstract

View file

@ -1,4 +1,12 @@
class EventsRegistration < ActiveRecord::Base
belongs_to :registration
belongs_to :event
has_one :user, through: :registration
delegate :name, to: :registration
delegate :email, to: :registration
validates :event, :registration, presence: true
validates :event, uniqueness: { scope: :registration }
end

View file

@ -8,10 +8,21 @@ class Program < ActiveRecord::Base
has_many :tracks, dependent: :destroy
has_many :difficulty_levels, dependent: :destroy
has_many :events, dependent: :destroy do
def workshops
def require_registration
where(require_registration: true, state: :confirmed)
end
def with_registration_open
where(require_registration: true, state: :confirmed).
map { |e| e if e.max_attendees > e.registrations.count }.compact
end
# All confirmed events of the conference with attribute require_registration
# excluding the events the user has already registered to
def remaining_for_registration(registration)
require_registration - registration.events
end
def confirmed
where(state: :confirmed)
end

View file

@ -7,7 +7,7 @@ class Registration < ActiveRecord::Base
has_and_belongs_to_many :vchoices
has_many :events_registrations
has_many :workshops, through: :events_registrations, source: :event
has_many :events, through: :events_registrations
accepts_nested_attributes_for :user
accepts_nested_attributes_for :qanswers
@ -24,16 +24,40 @@ class Registration < ActiveRecord::Base
validates_uniqueness_of :user_id, scope: :conference_id, message: 'already Registered!'
validate :registration_limit_not_exceed, on: :create
validate :registration_to_events_only_if_present
after_create :set_week, :subscribe_to_conference, :send_registration_mail
after_destroy :destroy_purchased_tickets
##
# Makes a list of events that includes (in that order):
# Events that require registration, and registration to them is still possible
# Events to which the user is already registered to
# ==== RETURNS
# * +Array+ -> [event_to_register_to, event_already_registered_to]
def events_ordered
(conference.program.events.with_registration_open - events) + events
end
def week
created_at.strftime('%W').to_i
end
private
##
# If the user registers to attend events that are already scheduled,
# only allow registration to events if the user will be present
# (based on arrival and departure attributes)
# No validation if arrival/departure attributes are empty
def registration_to_events_only_if_present
if (arrival || departure) && events.pluck(:start_time).any?
errors.add(:arrival, 'is too late! You cannot register for events that take place before your arrival') if events.pluck(:start_time).compact.map { |x| x < arrival }.any?
errors.add(:departure, 'is too early! You cannot register for events that take place after your departure') if events.pluck(:start_time).compact.map { |x| x > departure }.any?
end
end
def destroy_purchased_tickets
ticket_purchased = TicketPurchase.where(conference_id: conference_id, user_id: user.id)
ticket_purchased.destroy_all

View file

@ -36,6 +36,7 @@ class User < ActiveRecord::Base
has_many :event_users, dependent: :destroy
has_many :events, -> { uniq }, through: :event_users
has_many :registrations, dependent: :destroy
has_many :events_registrations, through: :registrations
has_many :ticket_purchases, dependent: :destroy
has_many :tickets, through: :ticket_purchases, source: :ticket
has_many :votes, dependent: :destroy
@ -53,10 +54,33 @@ class User < ActiveRecord::Base
},
presence: true
##
# Checkes if the user attended the event
# This is used for events that require registration
# The user must have registered to attend the event
# Gets an event
# === Returns
# * +true+ if the user attended the event
# * +false+ if the user did not attend the event
def attended_event? event
event_registration = event.events_registrations.find_by(registration: self.registrations)
return false unless event_registration.present?
event_registration.attended
end
def name
self[:name] || username
end
##
# Checks if a user has registered to an event
# ====Returns
# * +true+ or +false+
def registered_to_event? event
event.registrations.pluck(:id).include? self.registrations.find_by(conference_id: event.program.conference.id).id
end
def subscribed? conference
self.subscriptions.find_by(conference_id: conference.id).present?
end

View file

@ -5,7 +5,9 @@
%br
%small
= @event.subtitle
= link_to 'Edit', edit_admin_conference_program_event_path(@conference.short_title, @event), class: 'btn btn-mini btn-primary pull-right'
.btn-group.pull-right
= link_to 'Registrations', registrations_admin_conference_program_event_path(@conference.short_title, @event), class: 'btn btn-success'
= link_to 'Edit', edit_admin_conference_program_event_path(@conference.short_title, @event), class: 'btn btn-mini btn-primary'
.row
.col-md-12
@ -94,7 +96,8 @@
off_color: 'warning',
on_text: 'Yes',
off_text: 'No' }
- if @event.require_registration
= registered_text(@event)
- if !@event.room.nil?
%tr
%td

View file

@ -23,7 +23,7 @@
%th
%b Speaker
%th
%b Pre-registration
%b Requires Registration
%th
%b Highlight
%th
@ -83,15 +83,18 @@
- else
Unknown speaker
%td{'data-order' => "#{event.require_registration}"}
%td.text-center{'data-order' => "#{event.require_registration}"}
= check_box_tag @conference.short_title, event.id, event.require_registration,
method: :patch, url: "/admin/conference/#{@conference.short_title}/program/events/#{event.id}?event[require_registration]=",
class: 'switch-checkbox', data: { size: 'small',
off_color: 'warning',
on_text: 'Yes',
off_text: 'No' }
- if event.require_registration
%br
= link_to registered_text(event), registrations_admin_conference_program_event_path(@conference.short_title, event), class: 'btn btn-xs btn-default'
%td{'data-order' => "#{event.is_highlight}"}
%td.text-center{'data-order' => "#{event.is_highlight}"}
= check_box_tag @conference.short_title, event.id, event.is_highlight,
method: :patch, url: "/admin/conference/#{@conference.short_title}/program/events/#{event.id}?event[is_highlight]=",
class: 'switch-checkbox', data: { size: 'small',

View file

@ -0,0 +1,40 @@
.row
.col-md-12
.page-header
%h1
Registrations (#{@event_registrations.length}/#{@event.max_attendees})
.text-muted
for
= @event.title
- if @event.room && (@event_registrations.length > @event.room.size)
%b Attention:
You have more registrations than the capacity of the room!
.well
%table.table.table-hover.table-borderd.table-striped.datatable#registrations
%thead
%th
%th Name
%th Email
%th Created At
%th Attended
%th Attended Conference
%tbody
- @event_registrations.each.with_index(1) do |event_registration, index|
%tr
%td= index
%td= event_registration.name
%td= event_registration.email
%td= event_registration.created_at
%td
= check_box_tag @conference.short_title, @event.id, event_registration.attended, class: 'switch-checkbox', method: :patch, url: "/admin/conference/#{@conference.short_title}/program/events/#{@event.id}/toggle_attendance?events_registration_id=#{event_registration.id}&&event_registration[attended]=",
data: { size: 'small',
off_color: 'danger',
on_text: 'Yes',
off_text: 'No' }
%td
- if event_registration.registration.attended
%i.fa.fa-check.text-success
-else
%i.fa.fa-close.text-danger

View file

@ -0,0 +1,25 @@
.row
.col-md-12.page-header
%h2
Registrations to Events
.col-md-12
.well
%table.table.table-bordered.table-striped.table-hover.datatable#event_registrations
%thead
%th ID
%th Conference
%th Title
%th Attended
%tbody
- @user.events_registrations.each do |event_registration|
- event = event_registration.event
%tr
%td= event.id
%td= link_to event.program.conference.short_title, admin_conference_path(event.program.conference.short_title)
%td= link_to event.title, admin_conference_program_event_path(event.program.conference.short_title, event)
%td
- if @user.attended_event?(event)
%i.fa.fa-check.text-success
- else
%i.fa.fa-times.text-danger

View file

@ -7,6 +7,8 @@
- unless @user.events.blank?
%li{class: "#{'active' if params[:tab] == 'submissions-content'}"}
= link_to 'Submissions', '#submissions-content', 'data-toggle'=>'tab'
%li{class: "#{'active' if params[:tab] == 'event_registrations-content'}"}
= link_to 'Event Registrations', '#event_registrations', 'data-toggle'=>'tab'
.tab-content
#user-info-content.tab-pane{class: "#{'active' unless params[:tab] == 'submissions-content'}"}
- if can? :edit, @user
@ -31,3 +33,5 @@
%td= @user.send(attr)
#submissions-content.tab-pane{class: "#{'active' if params[:tab] == 'submissions-content'}"}
= render 'submissions'
#event_registrations.tab-pane{class: "#{'active' if params[:tab] == 'event_registrations'}"}
= render 'event_registrations'

View file

@ -6,7 +6,7 @@
Registration for
= @conference.title
.row
.col-md-6
.col-md-8
- if !current_user
%legend
%span

View file

@ -1,8 +1,21 @@
- if @conference.questions.any?
= render partial: 'conference_registrations/questions', locals: { f: f }
- if @conference.program.events.workshops.any?
=f.inputs 'Pre-registration required for the following:' do
= f.input :events, as: :check_boxes, label: false, collection: @conference.program.events.workshops
- if @conference.program.events.with_registration_open.any? || @registration.events.any?
= f.inputs 'Pre-registration required for the following:' do
- @registration.events_ordered.each do |event|
%label
= hidden_field_tag "registration[event_ids][]", nil
= check_box_tag "registration[event_ids][]", event.id, event.registrations.include?(@registration)
= event.title
.text-muted
= registered_text(event)
- if event.scheduled?
(Scheduled on: #{event.start_time.to_date})
%br
= f.inputs 'Your Travel Info' do
= f.input :arrival, as: :string, label: 'Your arrival time', input_html: { value: (f.object.arrival.to_formatted_s(:db_without_seconds) unless f.object.arrival.nil?), id: 'registration-arrival-datepicker',start_date: @conference.start_date,end_date: @conference.end_date,readonly: 'readonly' }
= f.input :departure, as: :string, label: 'Your departure time', input_html: { value: (f.object.departure.to_formatted_s(:db_without_seconds) unless f.object.departure.nil?), id: 'registration-departure-datepicker', readonly: 'readonly' }

View file

@ -54,18 +54,34 @@
= qa.answer.title
- else
You haven't answered
- if @workshops.any?
- if @registration.events.any?
.row
.col-md-12
%h4
%span.fa-stack
%i.fa.fa-square-o.fa-stack-2x
%i.fa.fa-check.fa-stack-1x
Event Registrations
Registered to the following event(s)
%ul
- @workshops.each do |workshop|
- @registration.events.each do |event|
%li
= link_to workshop.title, conference_program_proposal_path(@conference.short_title, workshop.id)
= link_to event.title, conference_program_proposal_path(@conference.short_title, event.id)
= '(' + registered_text(event) + ')'
- if @registration.conference.program.events.remaining_for_registration(@registration).any?
.row
.col-md-12
%h4
%span.fa-stack
%i.fa.fa-square-o.fa-stack-2x
%i.fa.fa-question.fa-stack-1x
Events that require registration
%ul
- @registration.conference.program.events.remaining_for_registration(@registration).each do |event|
%li
= link_to event.title, conference_program_proposal_path(@conference.short_title, event.id)
= '(' + registered_text(event) + ')'
- if @conference.tickets.any?
.row
.col-md-12

View file

@ -42,7 +42,10 @@
250
words.
= f.input :require_registration, label: 'Require participants to register to your event'
= f.inputs 'Enable pre-registration' do
= f.input :require_registration, label: 'Require participants to register to your event'
- message = @event.room ? "Value must be between 1 and #{@event.room.size}" : 'Check room capacity after scheduling.'
= f.input :max_attendees, hint: 'The maximum number of participants. ' + message
- if current_user.has_any_role? :admin, { name: :organizer, resource: @conference }, { name: :cfp, resource: @conference }
= f.input :is_highlight

View file

@ -2,7 +2,7 @@
.row
.col-md-12.page-header
%h1
Proposals for
Proposals for
%span.notranslate
= @conference.title
@ -68,9 +68,9 @@
= event.event_type.title
= "(#{event.event_type.length} min)"
= "in #{event.track.name}" if event.track
- if event.state == 'confirmed' && event.require_registration == true
,
Pre-registered: #{pre_registered(event).count}
- if event.require_registration
%br
= link_to registered_text(event), registrations_conference_program_proposal_path(@conference.short_title, event), class: 'btn btn-xs btn-danger'
%td.col-md-2{style: "padding:20px 8px 20px 8px;"}
= link_to 'Complete your proposal', 'javascript: void(0)', "type"=>"button", "data-trigger"=>"focus", "data-toggle"=>"popover", "title"=>"Your todo list", "data-content"=>"#{render partial: 'tooltip', locals: { event: event} }"

View file

@ -0,0 +1,36 @@
.container
.row
.col-md-10.col-md-offset-1
.page-header
%h1
Registrations (#{@event.events_registrations.length}/#{@event.max_attendees})
.text-muted
for
= @event.title
.well
%table.table.table-hover.table-borderd.table-striped.datatable#registrations
%thead
%th
%th Name
%th Email
%th Created AT
%th Attended
%th Attended Conference
%tbody
- @event.events_registrations.each.with_index(1) do |event_registration, index|
%tr
%td= index
%td= event_registration.name
%td= event_registration.email
%td= event_registration.created_at
%td.text-center
- if event_registration.attended
%i.fa.fa-check.text-success
- else
%i.fa.fa-times.text-danger
%td
- if event_registration.registration.attended
%i.fa.fa-check.text-success
-else
%i.fa.fa-times.text-danger

View file

@ -7,10 +7,13 @@
%br
%small
= @event.subtitle
- if can? :schedule, @conference
= link_to "Schedule", schedule_conference_path(@conference.short_title), :class =>"btn btn-success pull-right"
- if can? :edit, @event
= link_to "Edit", edit_conference_program_proposal_path(@conference.short_title, @event), :class => "btn btn-mini btn-primary pull-right"
.btn-group.pull-right
- if can? :update, @event
= link_to 'Registrations', registrations_conference_program_proposal_path(@conference.short_title, @event), class: 'btn btn-mini btn-success'
- if can? :edit, @event
= link_to "Edit", edit_conference_program_proposal_path(@conference.short_title, @event), :class => "btn btn-mini btn-primary"
- if can? :schedule, @conference
= link_to "Schedule", schedule_conference_path(@conference.short_title), :class =>"btn btn-success"
.row
.col-md-3
.speakerinfo
@ -28,7 +31,6 @@
= @speaker.affiliation
-if @speaker.biography?
= simple_format(@speaker.biography)
.col-md-9
.row
.col-md-12
@ -76,5 +78,9 @@
- if @event.difficulty_level_id
%span.label{:style =>"background-color: #{@event.difficulty_level.color};"}
= @event.difficulty_level.title
- if @event.require_registration
= link_to "Registration required!", new_conference_conference_registrations_path(@conference.short_title), :class => "btn btn-xs btn-warning"
- if @event.require_registration
.col-md-12
%dt Requires Registration:
%dd
= link_to "Yes (#{registered_text(@event)})", new_conference_conference_registrations_path(@conference.short_title), class: 'btn btn-xs btn-danger', disabled: !@event.registration_possible?