This commit is contained in:
Stella Rouzi 2016-06-16 13:51:58 +00:00 committed by GitHub
commit 79e0c719cb
38 changed files with 1306 additions and 403 deletions

View file

@ -30,7 +30,13 @@ module Admin
:send_on_conference_registration_dates_updated, :conference_registration_dates_updated_subject, :conference_registration_dates_updated_body,
:send_on_venue_updated, :venue_updated_subject, :venue_updated_body,
:send_on_cfp_dates_updated, :cfp_dates_updated_subject, :cfp_dates_updated_body,
:send_on_program_schedule_public, :program_schedule_public_subject, :program_schedule_public_body)
:send_on_program_schedule_public, :program_schedule_public_subject, :program_schedule_public_body,
:send_on_updated_max_attendees_automatically,
:updated_max_attendees_automatically_subject, :updated_max_attendees_automatically_body,
:send_on_deleted_event_registration_automatically, :deleted_event_registration_automatically_subject,
:deleted_event_registration_automatically_body,
:send_on_new_event_registration,
:new_event_registration_subject, :new_event_registration_body)
end
end
end

View file

@ -171,16 +171,6 @@ module Admin
@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

View file

@ -0,0 +1,72 @@
module Admin
class EventsRegistrationsController < Admin::BaseController
load_resource :conference, find_by: :short_title
load_resource :program, through: :conference, singleton: true
load_resource :event
load_resource :registration, through: :conference
before_action :load_events_registration
authorize_resource only: :toggle_attendance
after_action :prepare_unobtrusive_flash, only: [:toggle, :toggle_attendance]
def show
authorize! :update, @event
end
def toggle_attendance
@events_registration = EventsRegistration.find_by(event_id: @event.id, registration_id: @registration.id)
@events_registration.attended = !@events_registration.attended
if @events_registration.attended
if @events_registration.save
flash[:notice] = "You have marked #{@registration.email} as attended."
else
flash[:error] = "Failed to mark #{@registration.email} as attended."
end
elsif @events_registration.save
flash[:notice] = "You have marked #{@registration.email} as NOT attended."
else
flash[:error] = "Failed to mark #{@registration.email} as NOT attended."
end
respond_to do |format|
format.js
end
end
def toggle
authorize! :toggle, @events_registration
if params[:state] == 'false'
# Destroy the registration to the event
if @events_registration.destroy
flash[:notice] = "You successfully unregistered #{@registration.email} from '#{@event.title}'"
else
flash[:error] = "Failed to unregister #{@registration.email} from '#{@event.title}'. Please try again."
end
elsif params[:state] == 'true'
# Create the registration to the event
if @events_registration.save
flash[:notice] = "You successfully registered #{@registration.email} to '#{@event.title}'"
else
flash[:error] = "Failed to register #{@registration.email} to '#{@event.title}'. Please try again."
end
else
flash[:error] = 'Something went wrong. Please take action again.'
end
respond_to do |format|
format.js
end
end
private
def events_registrations_params
params.require(:events_registrations).permit(:event_id, :registration_id)
end
def load_events_registration
@events_registration = EventsRegistration.find_or_initialize_by(event: @event, registration: @registration)
end
end
end

View file

@ -59,6 +59,21 @@ module Admin
start_time = DateTime.strptime(time, '%Y-%m-%d %k:%M')
event.start_time = start_time
event.save!
if event.require_registration && (event.registrations.length > room.size)
event_registrations = event.events_registrations.order(created_at: :desc).limit(event.registrations.length - room.size)
event_registrations.each do |er|
er.destroy!
DeletedEventRegistrationAutomaticallyJob.perform_later(event.program.conference, er.user, er.event) if er.send_email_on_deleted_event_registration_automatically?
end
event.max_attendees = room.size
event.save!
users_emails = event_registrations.map { |er| er.registration.email }.join(', ')
UpdatedMaxAttendeesAutomaticallyJob.perform_later(event, users_emails) if event.send_email_on_updated_max_attendees_automatically?
end
render json: { 'status' => 'ok' }
end

View file

@ -0,0 +1,82 @@
class EventsRegistrationsController < ApplicationController
load_resource :conference, find_by: :short_title
load_resource :program, through: :conference, singleton: true
load_resource :proposal, class: 'Event'
load_resource :registration, through: :conference
before_action :load_events_registration
authorize_resource only: [:index, :toggle_attendance]
after_action :prepare_unobtrusive_flash, only: [:toggle, :toggle_attendance]
def index
@registration = @conference.registrations.find_by(conference: @conference, user: current_user)
@events = @registration ? @registration.events_ordered : @program.events.require_registration
end
def show
authorize! :update, @proposal
end
def toggle_attendance
@events_registration = EventsRegistration.find_by(event_id: @proposal.id, registration_id: @registration.id)
@events_registration.attended = !@events_registration.attended
if @events_registration.attended
if @events_registration.save
flash[:notice] = "You have marked #{@registration.email} as attended."
else
flash[:error] = "Failed to mark #{@registration.email} as attended."
end
elsif @events_registration.save
flash[:notice] = "You have marked #{@registration.email} as NOT attended."
else
flash[:error] = "Failed to mark #{@registration.email} as NOT attended."
end
respond_to do |format|
format.js
end
end
def toggle
authorize! :toggle, @events_registration
if params[:state] == 'false'
# Destroy the registration to the event
if @events_registration.destroy
flash[:notice] = "You successfully unregistered from '#{@proposal.title}'"
else
flash[:error] = "Failed to unregister you from '#{@proposal.title}'. Please try again."
end
elsif params[:state] == 'true'
# Create the registration to the event
if @events_registration.save
flash[:notice] = "You successfully registered to '#{@proposal.title}'"
if params[:send_email] == 'true'
if @events_registration.send_email_on_new_event_registration?
@events_registration.send_event_registration_mail
end
end
else
flash[:error] = "Failed to register you to '#{@proposal.title}'. Please try again."
end
else
flash[:error] = 'Something went wrong. Please take action again.'
end
respond_to do |format|
format.js
end
end
private
def events_registrations_params
params.require(:events_registrations).permit(:event_id, :registration_id)
end
def load_events_registration
@events_registration = EventsRegistration.find_or_initialize_by(event: @proposal, registration: @registration)
end
end

View file

@ -3,8 +3,8 @@ 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}"
return "#{event.registrations.count}/#{event.max_attendees}" if event.max_attendees
return "#{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)

View file

@ -0,0 +1,7 @@
class DeletedEventRegistrationAutomaticallyJob < ActiveJob::Base
queue_as :default
def perform(conference, user, event)
Mailbot.deleted_event_registration_automatically(conference, user, event).deliver_now
end
end

View file

@ -0,0 +1,13 @@
class UpdatedMaxAttendeesAutomaticallyJob < ActiveJob::Base
queue_as :default
def perform(event, users_emails=nil)
if users_emails.present?
event.program.conference.email_settings.updated_max_attendees_automatically_body << "\n\nThe following users have been unregistered from your event:\n #{users_emails}"
end
event.users.uniq.each do |user|
Mailbot.updated_max_attendees_automatically(event.program.conference, user, event).deliver_now
end
end
end

View file

@ -92,4 +92,34 @@ class Mailbot < ActionMailer::Base
template_name: 'comment_template',
subject: "New comment has been posted for #{@event.title}")
end
def updated_max_attendees_automatically(conference, user, event)
mail(to: user.email,
from: conference.contact.email,
subject: conference.email_settings.updated_max_attendees_automatically_subject,
body: conference.email_settings.generate_email_on_conf_updates(conference,
user,
conference.email_settings.updated_max_attendees_automatically_body,
event))
end
def deleted_event_registration_automatically(conference, user, event)
mail(to: user.email,
from: conference.contact.email,
subject: conference.email_settings.deleted_event_registration_automatically_subject,
body: conference.email_settings.generate_email_on_conf_updates(conference,
user,
conference.email_settings.deleted_event_registration_automatically_body,
event))
end
def event_registration_email(conference, user, event)
mail(to: user.email,
from: conference.contact.email,
subject: conference.email_settings.new_event_registration_subject,
body: conference.email_settings.generate_email_on_conf_updates(conference,
user,
conference.email_settings.new_event_registration_body,
event))
end
end

View file

@ -54,6 +54,9 @@ class Ability
registration.conference.registration_open? && registration.new_record?
end
# Can index Events that require registration
can :index, EventsRegistration
can :show, Event do |event|
event.new_record?
end
@ -92,6 +95,19 @@ class Ability
# can manage the commercials of their own events
can :manage, Commercial, commercialable_type: 'Event', commercialable_id: user.events.pluck(:id)
# Can register/unregister to an event
can :toggle, EventsRegistration do |er|
user.registrations.include?(er.registration) && er.event.require_registration
end
# Proposal submitter can:
# - see the people who registered to the event
# - toggle registration of peope to the event
# - toggle their attendance
can [:show, :toggle, :toggle_attendance], EventsRegistration do |er|
er.event.event_users.pluck(:user_id).include? user.id
end
end
# Abilities for signed in users with roles
@ -117,6 +133,10 @@ class Ability
cannot :destroy, Venue do |venue|
venue.conference.program.events.where.not(room_id: nil).any?
end
cannot :toggle, EventsRegistration do |er|
!er.event.require_registration
end
end
def signed_in_with_organizer_role(user)
@ -148,6 +168,9 @@ class Ability
can :manage, DifficultyLevel, program: { conference_id: conf_ids_for_organizer}
can :manage, Commercial, commercialable_type: 'Event',
commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organizer).pluck(:id)).pluck(:id)
can :manage, EventsRegistration do |er|
conf_ids_for_organizer.include? er.registration.conference.id
end
can :manage, Venue, conference_id: conf_ids_for_organizer
can :manage, Commercial, commercialable_type: 'Venue',
commercialable_id: Venue.where(conference_id: conf_ids_for_organizer).pluck(:id)
@ -182,6 +205,9 @@ class Ability
can :manage, Program, conference_id: conf_ids_for_cfp
can :manage, Commercial, commercialable_type: 'Event',
commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id)
can :manage, EventsRegistration do |er|
conf_ids_for_cfp.include? er.registration.conference.id
end
can :index, Comment, commentable_type: 'Event',
commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id)

View file

@ -51,8 +51,8 @@ class EmailSettings < ActiveRecord::Base
parse_template(event_template, values)
end
def generate_email_on_conf_updates(conference, user, conf_update_template)
values = get_values(conference, user)
def generate_email_on_conf_updates(conference, user, conf_update_template, event=nil)
values = get_values(conference, user, event)
parse_template(conf_update_template, values)
end

View file

@ -36,6 +36,7 @@ class Event < ActiveRecord::Base
validates :max_attendees, numericality: { only_integer: true, greater_than_or_equal_to: 1, allow_nil: true }
validate :max_attendees_no_more_than_room_size
validate :max_attendees_no_less_than_existing_registrations
scope :confirmed, -> { where(state: 'confirmed') }
scope :highlighted, -> { where(is_highlight: true) }
@ -68,6 +69,11 @@ class Event < ActiveRecord::Base
end
end
def send_email_on_updated_max_attendees_automatically?
program.conference.email_settings.send_on_updated_max_attendees_automatically &&
program.conference.email_settings.updated_max_attendees_automatically_subject && program.conference.email_settings.updated_max_attendees_automatically_body
end
##
# Checkes if the event has a start_time and a room
# ====Returns
@ -232,6 +238,13 @@ class Event < ActiveRecord::Base
errors.add(:max_attendees, "cannot be more than the room's capacity (#{room.size})") if max_attendees && (max_attendees > room.size)
end
##
# The value of max_attendees for an event cannot less than the number of existing registrations to that event
def max_attendees_no_less_than_existing_registrations
return unless max_attendees && max_attendees_changed?
errors.add(:max_attendees, 'cannot be less than existing registrations. You first need to unregister people, if you want to reduce this value.') if max_attendees < self.registrations.count
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

@ -9,4 +9,19 @@ class EventsRegistration < ActiveRecord::Base
validates :event, :registration, presence: true
validates :event, uniqueness: { scope: :registration }
def send_event_registration_mail
return unless send_email_on_new_event_registration?
Mailbot.event_registration_email(event.program.conference, registration.user, event).deliver_later
end
def send_email_on_new_event_registration?
event.program.conference.email_settings.send_on_new_event_registration &&
event.program.conference.email_settings.new_event_registration_subject && event.program.conference.email_settings.new_event_registration_body
end
def send_email_on_deleted_event_registration_automatically?
event.program.conference.email_settings.send_on_deleted_event_registration_automatically &&
event.program.conference.email_settings.deleted_event_registration_automatically_subject && event.program.conference.email_settings.deleted_event_registration_automatically_body
end
end

View file

@ -14,6 +14,9 @@
%a{"aria-controls" => "notifications", "data-toggle" => "tab", :href => "#notifications", :role => "tab"} Update Notifications
%li{:role => "presentation"}
%a{"aria-controls" => "cfp", "data-toggle" => "tab", :href => "#cfp", :role => "tab"} Call for Papers
%li{:role => "presentation"}
%a{"aria-controls" => "events_registration", "data-toggle" => "tab", :href => "#events_registrations", :role => "tab"} Events Registrations
/ Tab panes
.tab-content
#onboarding.tab-pane.active{:role => "tabpanel"}
@ -83,6 +86,32 @@
"data-name"=>"email_settings_cfp_dates_updated_body"} Load Template
%a.btn.btn-link.control_label.template_help_link{"data-name"=>"updated_cfp_help"} Show Help
= render partial: 'help', locals: {id: 'updated_cfp_help', show_event_variables: false}
#events_registrations.tab-pane{:role => "tabpanel"}
= f.input :send_on_updated_max_attendees_automatically, hint: "This will notify event users about automatic changes on max_attendees attribute. This refers to events marked with require_registration"
= f.input :updated_max_attendees_automatically_subject
= f.input :updated_max_attendees_automatically_body, input_html: { rows: 10, cols: 20 }
%a.btn.btn-link.control_label.load_template{"data-template"=>"Dear {name},\n\nThe maximum number of attendees that can attend your session {eventtitle} has been modified.\n That is usually due to scheduling your session in a room with less available seats.\n\nFeel free to contact us with any questions or concerns.\n\nWe look forward to seeing you there.\n\nBest wishes\n\n{conference} Team",
"data-name"=>"email_settings_updated_max_attendees_automatically_body"} Load Template
%a.btn.btn-link.control_label.template_help_link{"data-name"=>"updated_max_attendees_automatically_help"} Show Help
= render partial: 'help', locals: { id: 'updated_max_attendees_automatically_help', show_event_variables: true }
= f.input :send_on_deleted_event_registration_automatically, hint: "This will notify all user that they have been unregistered from an event. This occurs when someone else, except for the user, deletes the registration (eg. event submitter, conference organizer)"
= f.input :deleted_event_registration_automatically_subject
= f.input :deleted_event_registration_automatically_body, input_html: { rows: 10, cols: 20 }
%a.btn.btn-link.control_label.load_template{"data-template"=>"Dear {name},\n\nWe are sorry to inform you that you have been unregistered from the session {eventtitle}.\n That might have occured due to technical difficulties or room limitations. You can check online for any future changes.\n\nFeel free to contact us with any questions or concerns.\n\nWe look forward to seeing you there.\n\nBest wishes\n\n{conference} Team",
"data-name"=>"email_settings_deleted_event_registration_automatically_body"} Load Template
%a.btn.btn-link.control_label.template_help_link{"data-name"=>"deleted_event_registration_automatically_help"} Show Help
= render partial: 'help', locals: { id: 'deleted_event_registration_automatically_help', show_event_variables: true }
= f.input :send_on_new_event_registration, hint: "This will notify every user that registers to an event that the registration was successful"
= f.input :new_event_registration_subject
= f.input :new_event_registration_body, input_html: { rows: 10, cols: 20 }
%a.btn.btn-link.control_label.load_template{"data-template"=>"Dear {name},\n\nYou have successfully registered to attend session {eventtitle}. This session requires all attendees to register in advance. This is usually due to limited resources needed during the session, or room limitations. If for any reason you cannot make it, please unregister yourself to free up your slot for other visitors that wish to attend.\n\nFeel free to contact us with any questions or concerns.\n\nWe look forward to seeing you there.\n\nBest wishes\n\n{conference} Team",
"data-name"=>"email_settings_new_event_registration_body"} Load Template
%a.btn.btn-link.control_label.template_help_link{"data-name"=>"new_event_registration_help"} Show Help
= render partial: 'help', locals: { id: 'new_event_registration_help', show_event_variables: true }
.row
.col-md-12
= f.action :submit, :as => :button, :button_html => {:class => "btn btn-primary"}

View file

@ -97,7 +97,7 @@
on_text: 'Yes',
off_text: 'No' }
- if @event.require_registration
= registered_text(@event)
Registered: #{registered_text(@event)}
-if @program.languages.present?
%tr
@ -105,7 +105,6 @@
%b Language
%td
= @event.language
- if !@event.room.nil?
%tr
%td

View file

@ -99,7 +99,7 @@
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'
= link_to "Registered: #{registered_text(event)}", admin_conference_program_event_events_registrations_path(@conference.short_title, event), class: 'btn btn-xs btn-default'
%td.text-center{'data-order' => "#{event.is_highlight}"}
= check_box_tag @conference.short_title, event.id, event.is_highlight,

View file

@ -0,0 +1,46 @@
.unobtrusive-flash-container
.container
.row
.col-md-10
.page-header
%h1
Registrations (#{@event.registrations.length}/#{@event.max_attendees})
.text-muted
for
= @event.title
.well
%table.table.table-hover.table-borderd.table-striped.datatable#registrations
%thead
%th
%th Registered
%th Name
%th Email
%th Created At
%th Attended
%th Attended Conference
%tbody
- @event.registrations.each.with_index(1) do |registration, index|
- event_registration = EventsRegistration.find_by(event_id: @event.id, registration_id: registration.id)
%tr
%td= index
%td
= check_box_tag "toggle-#{@conference.short_title}", registration.id, registration.events.include?(@event), method: :patch, url: "/admin/conference/#{@conference.short_title}/program/events/#{@event.id}/registrations/toggle?events_registrations[event_id]=#{@event.id}&&events_registrations[registration_id]=#{registration.id}&&registration_id=#{registration.id}&&state=", class: 'switch-checkbox', data: { size: 'small', off_color: 'warning', on_text: 'Yes', off_text: 'No' }
%td= event_registration.name
%td= event_registration.email
%td= event_registration.created_at
%td
//We don't send the ID of the events_registration in the url of the switch-checkbox because
//the ID might have changed through the above switch-checkbox (which destroys or creates an events_registration).
//In that case the ID here would be invalid, before we would reload the page (to grab the new ID)
= check_box_tag "toggle_attendance-#{@conference.short_title}", @event.id, event_registration.attended, class: 'switch-checkbox', method: :patch, url: "/admin/conference/#{@conference.short_title}/program/events/#{@event.id}/registrations/toggle_attendance?registration_id=#{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-times.text-danger

View file

@ -0,0 +1 @@
$('.unobtrusive-flash-container').html('');

View file

@ -0,0 +1 @@
$('.unobtrusive-flash-container').html('');

View file

@ -0,0 +1,8 @@
.row
.col-md-10
%h4
%span.fa-stack
%i.fa.fa-square-o.fa-stack-2x
%i.fa.fa-edit.fa-stack-1x
There are #{@conference.program.events.require_registration.length} sessions that require you to #{link_to 'register', conference_program_events_registrations_path(@conference.short_title)}. Check them out!

View file

@ -1,20 +1,5 @@
- if @conference.questions.any?
= render partial: 'conference_registrations/questions', locals: { f: f }
- 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' }

View file

@ -1,6 +1,7 @@
.container
.row
.col-md-12
.unobtrusive-flash-container
.page-header
%h1
Registration for
@ -54,33 +55,9 @@
= qa.answer.title
- else
You haven't answered
- 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
Registered to the following event(s)
%ul
- @registration.events.each do |event|
%li
= 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.program.events.require_registration.any?
.events-with-registration
= render partial: 'events_with_registration'
- if @conference.tickets.any?
.row
@ -117,6 +94,7 @@
.col-md-12
-if @registration
.btn-group-vertical.pull-right
= link_to 'Edit your Registration', edit_conference_conference_registrations_path(@conference.short_title), class: 'btn btn-success', disabled: @conference.end_date < Date.today
= link_to 'Unregister', conference_conference_registrations_path(@conference.short_title),
method: :delete, class: 'btn btn-danger btn-xs', confirm: 'Are you sure you want to unregister?', disabled: @conference.end_date < Date.today

View file

@ -0,0 +1,54 @@
.container
.row
.col-md-11.col-md-offset-1
.unobtrusive-flash-container
.page-header
%h1
Sessions that require registration
= "(#{@program.events.require_registration.length})"
.text-muted
Some of the sessions require participants to pre-register. That gives us an idea about the amount of people interested in a particular session, and helps the speaker prepare for the amount of people that will show up. The speaker can limit the maximum number of attendees at any point, so if you are really interested in a session, go ahead and register for it!
- unless @registration
%br
Attention!!
You need to #{link_to 'register', new_conference_conference_registrations_path(@conference.short_title)} to attend the conference, before you can register to individual sessions.
.well
%table.table.table-hover.table-borderd.table-striped.datatable#registrations
%thead
%th
%th Registered
%th Title
%th Total Registrations
%th Scheduled
%tbody
- @events.each.with_index(1) do |event, index|
%tr
%td= index
%td.text-center
- if @registration
= check_box_tag "toggle-#{@conference.short_title}", event.id, event.registrations.include?(@registration), method: :patch, url: "/conference/#{@conference.short_title}/program/proposal/#{event.id}/registrations/toggle?events_registrations[event_id]=#{event.id}&&events_registrations[registration_id]=#{@registration.id}&&registration_id=#{@registration.id}&&state=", class: 'switch-checkbox', data: { size: 'small', off_color: 'warning', on_text: 'Yes', off_text: 'No' }
- else
No
%td
.col-md-12
= link_to event.title, conference_program_proposal_path(@conference.short_title, event)
.text-muted
.col-md-10
= "by #{event.speakers.first.name}"
.col-md-2
= image_tag event.speakers.first.gravatar_url(size: 25), class: 'img-responsive img-rounded'
%td.text-center= registered_text(event)
%td
- if event.start_time
= event.start_time.strftime('%Y-%m-%d')
%br
= event.start_time.strftime('%H:%M')
- if event.room
%br
In room
= event.room.name

View file

@ -0,0 +1,43 @@
.container
.row
.col-md-10.col-md-offset-1
.unobtrusive-flash-container
.page-header
%h1
Registrations (#{@proposal.registrations.length}/#{@proposal.max_attendees})
.text-muted
for
= @proposal.title
.well
%table.table.table-hover.table-borderd.table-striped.datatable#registrations
%thead
%th
%th Registered
%th Name
%th Email
%th Created At
%th Attended
%th Attended Conference
%tbody
- @proposal.registrations.each.with_index(1) do |registration, index|
- event_registration = EventsRegistration.find_by(event_id: @proposal.id, registration_id: registration.id)
%tr
%td= index
%td
= check_box_tag "toggle-#{@conference.short_title}", registration.id, registration.events.include?(@proposal), method: :patch, url: "/conference/#{@conference.short_title}/program/proposal/#{@proposal.id}/registrations/toggle?events_registrations[event_id]=#{@proposal.id}&&events_registrations[registration_id]=#{registration.id}&&registration_id=#{registration.id}&&state=", class: 'switch-checkbox', data: { size: 'small', off_color: 'warning', on_text: 'Yes', off_text: 'No' }
%td= event_registration.name
%td= event_registration.email
%td= event_registration.created_at
%td
= check_box_tag "toggle_attendance-#{@conference.short_title}", @proposal.id, event_registration.attended, class: 'switch-checkbox', method: :patch, url: "/conference/#{@conference.short_title}/program/proposal/#{@proposal.id}/registrations/toggle_attendance?&&registration_id=#{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-times.text-danger

View file

@ -0,0 +1 @@
$('.unobtrusive-flash-container').html('');

View file

@ -0,0 +1 @@
$('.unobtrusive-flash-container').html('');

View file

@ -48,8 +48,8 @@
words.
= 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 :require_registration, label: 'Require participants to register to your event', input_html: { disabled: @event.registrations.any? }, hint: 'If you enable this option, you must set the max number of attendees. You cannot disable this option, if there are registations.'
- message = @event.room ? "Value must be between 1 and #{@event.room.size}" : 'Check room capacity after scheduling, organizers might automatically reduce this number based on room capacity.'
= 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 }

View file

@ -70,7 +70,8 @@
= "in #{event.track.name}" if event.track
- 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'
= link_to "Registered: #{registered_text(event)}",
conference_program_proposal_events_registrations_path(@conference.short_title, event), class: 'btn btn-xs btn-info'
%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

@ -9,7 +9,7 @@
= @event.subtitle
.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'
= link_to 'Registrations', conference_program_proposal_events_registrations_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
@ -83,4 +83,4 @@
.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?
= link_to "Yes (Registered: #{registered_text(@event)})", conference_conference_registrations_path(@conference.short_title), class: 'btn btn-xs btn-info', disabled: !@event.registration_possible?

View file

@ -50,8 +50,11 @@ Osem::Application.routes.draw do
resources :event_types
resources :difficulty_levels
resources :events do
member do
resource :events_registrations, only: [:index, :show], path: 'registrations' do
patch :toggle
patch :toggle_attendance
end
member do
get :registrations
post :comment
patch :accept
@ -94,13 +97,16 @@ Osem::Application.routes.draw do
resources :conference, only: [:index, :show] do
resource :program, only: [] do
resources :events_registrations, only: :index
resources :proposal, except: :destroy do
resource :events_registrations, only: :show, path: 'registrations' do
patch :toggle
patch :toggle_attendance
end
get 'commercials/render_commercial' => 'commercials#render_commercial'
resources :commercials, only: [:create, :update, :destroy]
member do
get :registrations
patch '/withdraw' => 'proposal#withdraw'
get :registrations
patch '/confirm' => 'proposal#confirm'
patch '/restart' => 'proposal#restart'
end

View file

@ -0,0 +1,15 @@
class AddEventRegistrationFieldsToEmailSettings < ActiveRecord::Migration
def change
add_column :email_settings, :send_on_updated_max_attendees_automatically, :boolean
add_column :email_settings, :updated_max_attendees_automatically_subject, :string
add_column :email_settings, :updated_max_attendees_automatically_body, :text
add_column :email_settings, :send_on_deleted_event_registration_automatically, :boolean
add_column :email_settings, :deleted_event_registration_automatically_subject, :string
add_column :email_settings, :deleted_event_registration_automatically_body, :text
add_column :email_settings, :send_on_new_event_registration, :boolean
add_column :email_settings, :new_event_registration_subject, :string
add_column :email_settings, :new_event_registration_body, :text
end
end

View file

@ -11,293 +11,302 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160427104236) do
ActiveRecord::Schema.define(version: 20160428182258) do
create_table "ahoy_events", force: :cascade do |t|
t.uuid "visit_id", limit: 16
t.integer "user_id"
t.string "name"
t.text "properties"
t.integer "user_id", limit: 4
t.string "name", limit: 255
t.text "properties", limit: 65535
t.datetime "time"
end
add_index "ahoy_events", ["time"], name: "index_ahoy_events_on_time"
add_index "ahoy_events", ["user_id"], name: "index_ahoy_events_on_user_id"
add_index "ahoy_events", ["visit_id"], name: "index_ahoy_events_on_visit_id"
add_index "ahoy_events", ["time"], name: "index_ahoy_events_on_time", using: :btree
add_index "ahoy_events", ["user_id"], name: "index_ahoy_events_on_user_id", using: :btree
add_index "ahoy_events", ["visit_id"], name: "index_ahoy_events_on_visit_id", using: :btree
create_table "answers", force: :cascade do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
t.string "title", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "campaigns", force: :cascade do |t|
t.integer "conference_id"
t.string "name"
t.string "utm_source"
t.string "utm_medium"
t.string "utm_term"
t.string "utm_content"
t.string "utm_campaign"
t.integer "conference_id", limit: 4
t.string "name", limit: 255
t.string "utm_source", limit: 255
t.string "utm_medium", limit: 255
t.string "utm_term", limit: 255
t.string "utm_content", limit: 255
t.string "utm_campaign", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "cfps", force: :cascade do |t|
t.date "start_date", null: false
t.date "end_date", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "program_id"
t.date "start_date", null: false
t.date "end_date", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "program_id", limit: 4
end
create_table "comments", force: :cascade do |t|
t.string "title", limit: 50, default: ""
t.text "body"
t.integer "commentable_id"
t.string "commentable_type"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "subject"
t.integer "parent_id"
t.integer "lft"
t.integer "rgt"
t.string "title", limit: 50, default: ""
t.text "body", limit: 16777215
t.integer "commentable_id", limit: 4
t.string "commentable_type", limit: 255
t.integer "user_id", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "subject", limit: 255
t.integer "parent_id", limit: 4
t.integer "lft", limit: 4
t.integer "rgt", limit: 4
end
add_index "comments", ["commentable_id"], name: "index_comments_on_commentable_id"
add_index "comments", ["commentable_type"], name: "index_comments_on_commentable_type"
add_index "comments", ["user_id"], name: "index_comments_on_user_id"
add_index "comments", ["commentable_id"], name: "index_comments_on_commentable_id", using: :btree
add_index "comments", ["commentable_type"], name: "index_comments_on_commentable_type", using: :btree
add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree
create_table "commercials", force: :cascade do |t|
t.string "commercial_id"
t.string "commercial_type"
t.integer "commercialable_id"
t.string "commercialable_type"
t.string "commercial_id", limit: 255
t.string "commercial_type", limit: 255
t.integer "commercialable_id", limit: 4
t.string "commercialable_type", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
t.string "url"
t.string "url", limit: 255
end
create_table "conferences", force: :cascade do |t|
t.string "guid", null: false
t.string "title", null: false
t.string "short_title", null: false
t.string "timezone", null: false
t.date "start_date", null: false
t.date "end_date", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.string "logo_file_name"
t.string "logo_content_type"
t.integer "logo_file_size"
t.string "guid", limit: 255, null: false
t.string "title", limit: 255, null: false
t.string "short_title", limit: 255, null: false
t.string "timezone", limit: 255, null: false
t.date "start_date", null: false
t.date "end_date", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "logo_file_name", limit: 255
t.string "logo_content_type", limit: 255
t.integer "logo_file_size", limit: 4
t.datetime "logo_updated_at"
t.integer "revision"
t.boolean "use_vpositions", default: false
t.boolean "use_vdays", default: false
t.boolean "use_difficulty_levels", default: false
t.integer "revision", limit: 4
t.boolean "use_vpositions", default: false
t.boolean "use_vdays", default: false
t.boolean "use_difficulty_levels", default: false
t.boolean "use_volunteers"
t.string "color"
t.text "events_per_week"
t.text "description"
t.integer "registration_limit", default: 0
t.string "picture"
t.string "color", limit: 255
t.text "events_per_week", limit: 65535
t.text "description", limit: 65535
t.integer "registration_limit", limit: 4, default: 0
t.string "picture", limit: 255
end
create_table "conferences_questions", id: false, force: :cascade do |t|
t.integer "conference_id"
t.integer "question_id"
t.integer "conference_id", limit: 4
t.integer "question_id", limit: 4
end
create_table "contacts", force: :cascade do |t|
t.string "social_tag"
t.string "email"
t.string "facebook"
t.string "googleplus"
t.string "twitter"
t.string "instagram"
t.integer "conference_id"
t.string "social_tag", limit: 255
t.string "email", limit: 255
t.string "facebook", limit: 255
t.string "googleplus", limit: 255
t.string "twitter", limit: 255
t.string "instagram", limit: 255
t.integer "conference_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
t.string "sponsor_email"
t.string "sponsor_email", limit: 255
end
create_table "delayed_jobs", force: :cascade do |t|
t.integer "priority", default: 0, null: false
t.integer "attempts", default: 0, null: false
t.text "handler", null: false
t.text "last_error"
t.integer "priority", limit: 4, default: 0, null: false
t.integer "attempts", limit: 4, default: 0, null: false
t.text "handler", limit: 65535, null: false
t.text "last_error", limit: 65535
t.datetime "run_at"
t.datetime "locked_at"
t.datetime "failed_at"
t.string "locked_by"
t.string "queue"
t.string "locked_by", limit: 255
t.string "queue", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority"
add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree
create_table "difficulty_levels", force: :cascade do |t|
t.string "title"
t.text "description"
t.string "color"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "program_id"
t.string "title", limit: 255
t.text "description", limit: 65535
t.string "color", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "program_id", limit: 4
end
create_table "email_settings", force: :cascade do |t|
t.integer "conference_id"
t.boolean "send_on_registration", default: false
t.boolean "send_on_accepted", default: false
t.boolean "send_on_rejected", default: false
t.boolean "send_on_confirmed_without_registration", default: false
t.text "registration_body"
t.text "accepted_body"
t.text "rejected_body"
t.text "confirmed_without_registration_body"
t.datetime "created_at"
t.datetime "updated_at"
t.string "registration_subject"
t.string "accepted_subject"
t.string "rejected_subject"
t.string "confirmed_without_registration_subject"
t.boolean "send_on_conference_dates_updated", default: false
t.string "conference_dates_updated_subject"
t.text "conference_dates_updated_body"
t.boolean "send_on_conference_registration_dates_updated", default: false
t.string "conference_registration_dates_updated_subject"
t.text "conference_registration_dates_updated_body"
t.boolean "send_on_venue_updated", default: false
t.string "venue_updated_subject"
t.text "venue_updated_body"
t.boolean "send_on_cfp_dates_updated", default: false
t.boolean "send_on_program_schedule_public", default: false
t.string "program_schedule_public_subject"
t.string "cfp_dates_updated_subject"
t.text "program_schedule_public_body"
t.text "cfp_dates_updated_body"
t.integer "conference_id", limit: 4
t.boolean "send_on_registration", default: false
t.boolean "send_on_accepted", default: false
t.boolean "send_on_rejected", default: false
t.boolean "send_on_confirmed_without_registration", default: false
t.text "registration_body", limit: 16777215
t.text "accepted_body", limit: 16777215
t.text "rejected_body", limit: 16777215
t.text "confirmed_without_registration_body", limit: 16777215
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "registration_subject", limit: 255
t.string "accepted_subject", limit: 255
t.string "rejected_subject", limit: 255
t.string "confirmed_without_registration_subject", limit: 255
t.boolean "send_on_conference_dates_updated", default: false
t.string "conference_dates_updated_subject", limit: 255
t.text "conference_dates_updated_body", limit: 65535
t.boolean "send_on_conference_registration_dates_updated", default: false
t.string "conference_registration_dates_updated_subject", limit: 255
t.text "conference_registration_dates_updated_body", limit: 65535
t.boolean "send_on_venue_updated", default: false
t.string "venue_updated_subject", limit: 255
t.text "venue_updated_body", limit: 65535
t.boolean "send_on_cfp_dates_updated", default: false
t.boolean "send_on_program_schedule_public", default: false
t.string "program_schedule_public_subject", limit: 255
t.string "cfp_dates_updated_subject", limit: 255
t.text "program_schedule_public_body", limit: 65535
t.text "cfp_dates_updated_body", limit: 65535
t.boolean "send_on_updated_max_attendees_automatically"
t.string "updated_max_attendees_automatically_subject", limit: 255
t.text "updated_max_attendees_automatically_body", limit: 65535
t.boolean "send_on_deleted_event_registration_automatically"
t.string "deleted_event_registration_automatically_subject", limit: 255
t.text "deleted_event_registration_automatically_body", limit: 65535
t.boolean "send_on_new_event_registration"
t.string "new_event_registration_subject", limit: 255
t.text "new_event_registration_body", limit: 65535
end
create_table "event_types", force: :cascade do |t|
t.string "title", null: false
t.integer "length", default: 30
t.integer "minimum_abstract_length", default: 0
t.integer "maximum_abstract_length", default: 500
t.string "color"
t.string "description"
t.integer "program_id"
t.string "title", limit: 255, null: false
t.integer "length", limit: 4, default: 30
t.integer "minimum_abstract_length", limit: 4, default: 0
t.integer "maximum_abstract_length", limit: 4, default: 500
t.string "color", limit: 255
t.string "description", limit: 255
t.integer "program_id", limit: 4
end
create_table "event_users", force: :cascade do |t|
t.integer "user_id"
t.integer "event_id"
t.string "event_role", default: "participant", null: false
t.string "comment"
t.integer "user_id", limit: 4
t.integer "event_id", limit: 4
t.string "event_role", limit: 255, default: "participant", null: false
t.string "comment", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "events", force: :cascade do |t|
t.string "guid", null: false
t.integer "event_type_id"
t.string "title", null: false
t.string "subtitle"
t.integer "time_slots"
t.string "state", default: "new", null: false
t.string "progress", default: "new", null: false
t.string "language"
t.string "guid", limit: 255, null: false
t.integer "event_type_id", limit: 4
t.string "title", limit: 255, null: false
t.string "subtitle", limit: 255
t.integer "time_slots", limit: 4
t.string "state", limit: 255, default: "new", null: false
t.string "progress", limit: 255, default: "new", null: false
t.string "language", limit: 255
t.datetime "start_time"
t.text "abstract"
t.text "description"
t.boolean "public", default: true
t.string "logo_file_name"
t.string "logo_content_type"
t.integer "logo_file_size"
t.text "abstract", limit: 16777215
t.text "description", limit: 16777215
t.boolean "public", default: true
t.string "logo_file_name", limit: 255
t.string "logo_content_type", limit: 255
t.integer "logo_file_size", limit: 4
t.datetime "logo_updated_at"
t.text "proposal_additional_speakers"
t.integer "track_id"
t.integer "room_id"
t.datetime "created_at"
t.datetime "updated_at"
t.text "proposal_additional_speakers", limit: 16777215
t.integer "track_id", limit: 4
t.integer "room_id", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "require_registration"
t.integer "difficulty_level_id"
t.integer "week"
t.boolean "is_highlight", default: false
t.integer "program_id"
t.integer "max_attendees"
t.integer "difficulty_level_id", limit: 4
t.integer "week", limit: 4
t.boolean "is_highlight", default: false
t.integer "program_id", limit: 4
t.integer "max_attendees", limit: 4
end
create_table "events_registrations", force: :cascade do |t|
t.integer "registration_id"
t.integer "event_id"
t.boolean "attended", default: false, null: false
t.integer "registration_id", limit: 4
t.integer "event_id", limit: 4
t.boolean "attended", default: false, null: false
t.datetime "created_at"
end
create_table "lodgings", force: :cascade do |t|
t.string "name"
t.text "description"
t.string "photo_file_name"
t.string "photo_content_type"
t.integer "photo_file_size"
t.string "name", limit: 255
t.text "description", limit: 65535
t.string "photo_file_name", limit: 255
t.string "photo_content_type", limit: 255
t.integer "photo_file_size", limit: 4
t.datetime "photo_updated_at"
t.datetime "created_at"
t.datetime "updated_at"
t.string "website_link"
t.integer "conference_id"
t.string "picture"
t.string "website_link", limit: 255
t.integer "conference_id", limit: 4
t.string "picture", limit: 255
end
create_table "openids", force: :cascade do |t|
t.string "provider"
t.string "email"
t.string "uid"
t.integer "user_id"
t.string "provider", limit: 255
t.string "email", limit: 255
t.string "uid", limit: 255
t.integer "user_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "programs", force: :cascade do |t|
t.integer "conference_id"
t.integer "rating", default: 0
t.boolean "schedule_public", default: false
t.boolean "schedule_fluid", default: false
t.integer "conference_id", limit: 4
t.integer "rating", limit: 4, default: 0
t.boolean "schedule_public", default: false
t.boolean "schedule_fluid", default: false
t.datetime "created_at"
t.datetime "updated_at"
t.string "languages"
end
create_table "qanswers", force: :cascade do |t|
t.integer "question_id"
t.integer "answer_id"
t.integer "question_id", limit: 4
t.integer "answer_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "qanswers_registrations", id: false, force: :cascade do |t|
t.integer "registration_id", null: false
t.integer "qanswer_id", null: false
t.integer "registration_id", limit: 4, null: false
t.integer "qanswer_id", limit: 4, null: false
end
create_table "question_types", force: :cascade do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
t.string "title", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "questions", force: :cascade do |t|
t.string "title"
t.integer "question_type_id"
t.integer "conference_id"
t.string "title", limit: 255
t.integer "question_type_id", limit: 4
t.integer "conference_id", limit: 4
t.boolean "global"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "registration_periods", force: :cascade do |t|
t.integer "conference_id"
t.integer "conference_id", limit: 4
t.date "start_date"
t.date "end_date"
t.datetime "created_at"
@ -305,44 +314,44 @@ ActiveRecord::Schema.define(version: 20160427104236) do
end
create_table "registrations", force: :cascade do |t|
t.integer "conference_id"
t.integer "conference_id", limit: 4
t.datetime "arrival"
t.datetime "departure"
t.datetime "created_at"
t.datetime "updated_at"
t.text "other_special_needs"
t.boolean "attended", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "other_special_needs", limit: 16777215
t.boolean "attended", default: false
t.boolean "volunteer"
t.integer "user_id"
t.integer "week"
t.integer "user_id", limit: 4
t.integer "week", limit: 4
end
create_table "registrations_vchoices", id: false, force: :cascade do |t|
t.integer "registration_id"
t.integer "vchoice_id"
t.integer "registration_id", limit: 4
t.integer "vchoice_id", limit: 4
end
create_table "roles", force: :cascade do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.string "description"
t.integer "resource_id"
t.string "resource_type"
t.string "name", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "description", limit: 255
t.integer "resource_id", limit: 4
t.string "resource_type", limit: 255
end
add_index "roles", ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id"
add_index "roles", ["name"], name: "index_roles_on_name"
add_index "roles", ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree
add_index "roles", ["name"], name: "index_roles_on_name", using: :btree
create_table "rooms", force: :cascade do |t|
t.string "guid", null: false
t.string "name", null: false
t.integer "size"
t.integer "venue_id", null: false
t.string "guid", limit: 255, null: false
t.string "name", limit: 255, null: false
t.integer "size", limit: 4
t.integer "venue_id", limit: 4, null: false
end
create_table "splashpages", force: :cascade do |t|
t.integer "conference_id"
t.integer "conference_id", limit: 4
t.boolean "public"
t.boolean "include_tracks"
t.boolean "include_program"
@ -354,208 +363,208 @@ ActiveRecord::Schema.define(version: 20160427104236) do
t.boolean "include_lodgings"
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "include_cfp", default: false
t.boolean "include_cfp", default: false
end
create_table "sponsors", force: :cascade do |t|
t.string "name"
t.text "description"
t.string "website_url"
t.string "logo_file_name"
t.string "logo_content_type"
t.integer "logo_file_size"
t.string "name", limit: 255
t.text "description", limit: 65535
t.string "website_url", limit: 255
t.string "logo_file_name", limit: 255
t.string "logo_content_type", limit: 255
t.integer "logo_file_size", limit: 4
t.datetime "logo_updated_at"
t.integer "sponsorship_level_id"
t.integer "conference_id"
t.integer "sponsorship_level_id", limit: 4
t.integer "conference_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
t.string "picture"
t.string "picture", limit: 255
end
create_table "sponsorship_levels", force: :cascade do |t|
t.string "title"
t.integer "conference_id"
t.string "title", limit: 255
t.integer "conference_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
t.integer "position"
t.integer "position", limit: 4
end
create_table "subscriptions", force: :cascade do |t|
t.integer "user_id"
t.integer "conference_id"
t.integer "user_id", limit: 4
t.integer "conference_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "targets", force: :cascade do |t|
t.integer "conference_id"
t.integer "campaign_id"
t.integer "conference_id", limit: 4
t.integer "campaign_id", limit: 4
t.date "due_date"
t.integer "target_count"
t.string "unit"
t.integer "target_count", limit: 4
t.string "unit", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "ticket_purchases", force: :cascade do |t|
t.integer "ticket_id"
t.integer "conference_id"
t.boolean "paid", default: false
t.integer "ticket_id", limit: 4
t.integer "conference_id", limit: 4
t.boolean "paid", default: false
t.datetime "created_at"
t.integer "quantity", default: 1
t.integer "user_id"
t.integer "quantity", limit: 4, default: 1
t.integer "user_id", limit: 4
end
create_table "tickets", force: :cascade do |t|
t.integer "conference_id"
t.string "title", null: false
t.text "description"
t.integer "price_cents", default: 0, null: false
t.string "price_currency", default: "USD", null: false
t.integer "conference_id", limit: 4
t.string "title", limit: 255, null: false
t.text "description", limit: 65535
t.integer "price_cents", limit: 4, default: 0, null: false
t.string "price_currency", limit: 255, default: "USD", null: false
end
create_table "tracks", force: :cascade do |t|
t.string "guid", null: false
t.string "name", null: false
t.text "description"
t.string "color"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "program_id"
t.string "guid", limit: 255, null: false
t.string "name", limit: 255, null: false
t.text "description", limit: 16777215
t.string "color", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "program_id", limit: 4
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.string "email", limit: 255, default: "", null: false
t.string "encrypted_password", limit: 255, default: "", null: false
t.string "reset_password_token", limit: 255
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0
t.integer "sign_in_count", limit: 4, default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.string "current_sign_in_ip", limit: 255
t.string "last_sign_in_ip", limit: 255
t.string "confirmation_token", limit: 255
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
t.string "unconfirmed_email", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name", limit: 255
t.boolean "email_public"
t.text "biography"
t.string "nickname"
t.string "affiliation"
t.string "avatar_file_name"
t.string "avatar_content_type"
t.integer "avatar_file_size"
t.text "biography", limit: 65535
t.string "nickname", limit: 255
t.string "affiliation", limit: 255
t.string "avatar_file_name", limit: 255
t.string "avatar_content_type", limit: 255
t.integer "avatar_file_size", limit: 4
t.datetime "avatar_updated_at"
t.string "mobile"
t.string "tshirt"
t.string "languages"
t.text "volunteer_experience"
t.boolean "is_admin", default: false
t.string "username"
t.boolean "is_disabled", default: false
t.string "mobile", limit: 255
t.string "tshirt", limit: 255
t.string "languages", limit: 255
t.text "volunteer_experience", limit: 65535
t.boolean "is_admin", default: false
t.string "username", limit: 255
t.boolean "is_disabled", default: false
end
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
add_index "users", ["username"], name: "index_users_on_username", unique: true
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
add_index "users", ["username"], name: "index_users_on_username", unique: true, using: :btree
create_table "users_roles", id: false, force: :cascade do |t|
t.integer "role_id"
t.integer "user_id"
t.integer "role_id", limit: 4
t.integer "user_id", limit: 4
end
add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id"
add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree
create_table "vchoices", force: :cascade do |t|
t.integer "vday_id"
t.integer "vposition_id"
t.integer "vday_id", limit: 4
t.integer "vposition_id", limit: 4
end
create_table "vdays", force: :cascade do |t|
t.integer "conference_id"
t.integer "conference_id", limit: 4
t.date "day"
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
t.text "description", limit: 65535
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "venues", force: :cascade do |t|
t.string "guid"
t.string "name"
t.string "website"
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
t.string "photo_file_name"
t.string "photo_content_type"
t.integer "photo_file_size"
t.string "guid", limit: 255
t.string "name", limit: 255
t.string "website", limit: 255
t.text "description", limit: 65535
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "photo_file_name", limit: 255
t.string "photo_content_type", limit: 255
t.integer "photo_file_size", limit: 4
t.datetime "photo_updated_at"
t.string "street"
t.string "postalcode"
t.string "city"
t.string "country"
t.string "latitude"
t.string "longitude"
t.integer "conference_id"
t.string "picture"
t.string "street", limit: 255
t.string "postalcode", limit: 255
t.string "city", limit: 255
t.string "country", limit: 255
t.string "latitude", limit: 255
t.string "longitude", limit: 255
t.integer "conference_id", limit: 4
t.string "picture", limit: 255
end
create_table "versions", force: :cascade do |t|
t.string "item_type", null: false
t.integer "item_id", null: false
t.string "event", null: false
t.string "whodunnit"
t.text "object"
t.text "object_changes"
t.string "item_type", limit: 255, null: false
t.integer "item_id", limit: 4, null: false
t.string "event", limit: 255, null: false
t.string "whodunnit", limit: 255
t.text "object", limit: 16777215
t.text "object_changes", limit: 16777215
t.datetime "created_at"
end
add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id"
add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id", using: :btree
create_table "visits", force: :cascade do |t|
t.uuid "visitor_id", limit: 16
t.string "ip"
t.text "user_agent"
t.text "referrer"
t.text "landing_page"
t.integer "user_id"
t.string "referring_domain"
t.string "search_keyword"
t.string "browser"
t.string "os"
t.string "device_type"
t.string "country"
t.string "region"
t.string "city"
t.string "utm_source"
t.string "utm_medium"
t.string "utm_term"
t.string "utm_content"
t.string "utm_campaign"
t.string "ip", limit: 255
t.text "user_agent", limit: 65535
t.text "referrer", limit: 65535
t.text "landing_page", limit: 65535
t.integer "user_id", limit: 4
t.string "referring_domain", limit: 255
t.string "search_keyword", limit: 255
t.string "browser", limit: 255
t.string "os", limit: 255
t.string "device_type", limit: 255
t.string "country", limit: 255
t.string "region", limit: 255
t.string "city", limit: 255
t.string "utm_source", limit: 255
t.string "utm_medium", limit: 255
t.string "utm_term", limit: 255
t.string "utm_content", limit: 255
t.string "utm_campaign", limit: 255
t.datetime "started_at"
end
add_index "visits", ["user_id"], name: "index_visits_on_user_id"
add_index "visits", ["user_id"], name: "index_visits_on_user_id", using: :btree
create_table "votes", force: :cascade do |t|
t.integer "event_id"
t.integer "rating"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.integer "event_id", limit: 4
t.integer "rating", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id", limit: 4
end
create_table "vpositions", force: :cascade do |t|
t.integer "conference_id"
t.string "title", null: false
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "conference_id", limit: 4
t.string "title", limit: 255, null: false
t.text "description", limit: 65535
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end

View file

@ -0,0 +1,178 @@
require 'spec_helper'
describe Admin::EventsRegistrationsController do
let(:conference) { create(:conference) }
let(:user_organizer) { create(:user, role_ids: [Role.find_by(name: 'organizer', resource: conference).id]) }
let(:user_cfp) { create(:user, role_ids: [Role.find_by(name: 'cfp', resource: conference).id]) }
let(:user) { create(:user) }
let(:user1) { create(:user) }
let(:user2) { create(:user) }
let(:submitter1) { create(:user) }
let(:submitter2) { create(:user) }
let(:registration1) { create(:registration, user: user1, conference: conference) }
let(:registration2) { create(:registration, user: user2, conference: conference) }
let!(:event_of_submitter1) do
create(:event, program: conference.program,
require_registration: true,
max_attendees: 3,
users: [submitter1])
end
let!(:event_of_submitter2) { create(:event, program: conference.program, users: [submitter2]) }
let(:event_other) { create(:event) }
let!(:events_registration1) do
create(:events_registration,
event: event_of_submitter1,
registration: registration1,
attended: false)
end
let!(:events_registration2) do
create(:events_registration,
event: event_of_submitter2,
registration: registration2,
attended: false)
end
shared_examples 'access allowed' do
describe 'GET #show' do
before :each do
get :show, conference_id: conference.short_title, event_id: event_of_submitter1.id
end
it 'renders show template' do
expect(response).to render_template :show
end
end
describe 'PATCH #toggle' do
it 'unregisters user from event' do
event_of_submitter1.registrations = [registration1]
event_of_submitter1.save!
patch :toggle, conference_id: conference.short_title,
event_id: event_of_submitter1.id,
registration_id: registration1.id,
state: 'false', format: 'js'
event_of_submitter1.reload
expect(event_of_submitter1.registrations).to eq []
end
it 'registers user to event' do
event_of_submitter1.registrations = []
event_of_submitter1.save!
patch :toggle, conference_id: conference.short_title,
event_id: event_of_submitter1.id,
registration_id: registration1.id,
state: 'true', format: 'js'
event_of_submitter1.reload
expect(event_of_submitter1.registrations).to eq [registration1]
end
end
describe 'PATCH #toggle_attendance' do
it 'marks registered user as present' do
events_registration1.attended = false
events_registration1.save!
patch :toggle_attendance, conference_id: conference.short_title,
event_id: event_of_submitter1.id,
registration_id: registration1.id, format: 'js'
events_registration1.reload
expect(events_registration1.attended).to eq true
end
it 'marks registered user as absent' do
events_registration1.attended = true
events_registration1.save!
patch :toggle_attendance, conference_id: conference.short_title,
event_id: event_of_submitter1.id,
registration_id: registration1.id, format: 'js'
events_registration1.reload
expect(events_registration1.attended).to eq false
end
end
end
shared_examples 'access not allowed' do |path|
describe 'GET #show' do
before :each do
get :show, conference_id: conference.short_title, event_id: event_of_submitter1.id
end
it 'redirects to root path' do
expect(response).to redirect_to send(path)
end
end
describe 'PATCH #toggle' do
it 'does not register user to event' do
event_of_submitter1.registrations = []
event_of_submitter1.save!
patch :toggle, conference_id: conference.short_title,
event_id: event_of_submitter1.id,
registration_id: registration1.id,
state: 'true', format: 'js'
expect(event_of_submitter1.registrations).to eq []
end
it 'does not unregister user from event' do
patch :toggle, conference_id: conference.short_title,
event_id: event_of_submitter1.id,
registration_id: registration1.id,
state: 'false', format: 'js'
expect(event_of_submitter1.registrations).to eq [registration1]
end
end
describe 'PATCH #toggle_attendance' do
it 'does not mark registered user as present' do
events_registration1.attended = false
events_registration1.save!
patch :toggle_attendance, conference_id: conference.short_title,
event_id: event_of_submitter1.id,
registration_id: registration1.id, format: 'js'
expect(events_registration1.attended).to eq false
end
it 'does not mark registered user as absent' do
events_registration1.attended = true
events_registration1.save!
patch :toggle_attendance, conference_id: conference.short_title,
event_id: event_of_submitter1.id,
registration_id: registration1.id, format: 'js'
expect(events_registration1.attended).to eq true
end
end
end
describe 'organizer access' do
before(:each) do
sign_in user_organizer
end
it_behaves_like 'access allowed'
end
describe 'cfp access' do
before(:each) do
sign_in user_cfp
end
it_behaves_like 'access allowed'
end
describe 'submitter access' do
before(:each) do
sign_in submitter1
end
it_behaves_like 'access not allowed', :root_path
end
describe 'without user access' do
it_behaves_like 'access not allowed', :new_user_session_path
end
end

View file

@ -0,0 +1,185 @@
require 'spec_helper'
describe EventsRegistrationsController do
let!(:conference) { create(:conference) }
let(:user_organizer) { create(:user, role_ids: [Role.find_by(name: 'organizer', resource: conference).id]) }
let(:user_cfp) { create(:user, role_ids: [Role.find_by(name: 'cfp', resource: conference).id]) }
let(:user) { create(:user) }
let(:user1) { create(:user) }
let(:user2) { create(:user) }
let(:submitter1) { create(:user) }
let(:submitter2) { create(:user) }
let(:registration1) { create(:registration, user: user1, conference: conference) }
let(:registration2) { create(:registration, user: user2, conference: conference) }
let!(:event_of_submitter1) do
create(:event, program: conference.program,
require_registration: true,
max_attendees: 3,
users: [submitter1])
end
let!(:event_of_submitter2) { create(:event, program: conference.program, users: [submitter2]) }
let(:event_other) { create(:event) }
let!(:events_registration1) do
create(:events_registration,
event: event_of_submitter1,
registration: registration1,
attended: false)
end
let!(:events_registration2) do
create(:events_registration,
event: event_of_submitter2,
registration: registration2,
attended: false)
end
shared_examples 'access allowed' do
describe 'GET #show' do
before :each do
get :show, conference_id: conference.short_title, proposal_id: event_of_submitter1.id
end
it 'renders show template' do
expect(response).to render_template :show
end
end
describe 'PATCH #toggle' do
it 'unregisters user from event' do
event_of_submitter1.registrations = [registration1]
event_of_submitter1.save!
patch :toggle, conference_id: conference.short_title,
proposal_id: event_of_submitter1.id,
registration_id: registration1.id,
state: 'false', format: 'js'
event_of_submitter1.reload
expect(event_of_submitter1.registrations).to eq []
end
it 'registers user to event' do
event_of_submitter1.registrations = []
event_of_submitter1.save!
patch :toggle, conference_id: conference.short_title,
proposal_id: event_of_submitter1.id,
registration_id: registration1.id,
state: 'true', format: 'js'
event_of_submitter1.reload
expect(event_of_submitter1.registrations).to eq [registration1]
end
end
describe 'PATCH #toggle_attendance' do
it 'marks registered user as present' do
events_registration1.attended = false
events_registration1.save!
patch :toggle_attendance, conference_id: conference.short_title,
proposal_id: event_of_submitter1.id,
registration_id: registration1.id, format: 'js'
events_registration1.reload
expect(events_registration1.attended).to eq true
end
it 'marks registered user as absent' do
events_registration1.attended = true
events_registration1.save!
patch :toggle_attendance, conference_id: conference.short_title,
proposal_id: event_of_submitter1.id,
registration_id: registration1.id, format: 'js'
events_registration1.reload
expect(events_registration1.attended).to eq false
end
end
end
shared_examples 'access not allowed' do |path|
describe 'GET #show' do
before :each do
get :show, conference_id: conference.short_title, proposal_id: event_of_submitter1.id
end
it 'redirects to root path' do
expect(response).to redirect_to send(path)
end
end
describe 'PATCH #toggle' do
it 'does not register user to event' do
event_of_submitter1.registrations = []
event_of_submitter1.save!
patch :toggle, conference_id: conference.short_title,
proposal_id: event_of_submitter1.id,
registration_id: registration1.id,
state: 'true', format: 'js'
expect(event_of_submitter1.registrations).to eq []
end
it 'does not unregister user from event' do
patch :toggle, conference_id: conference.short_title,
proposal_id: event_of_submitter1.id,
registration_id: registration1.id,
state: 'false', format: 'js'
expect(event_of_submitter1.registrations).to eq [registration1]
end
end
describe 'PATCH #toggle_attendance' do
it 'does not mark registered user as present' do
events_registration1.attended = false
events_registration1.save!
patch :toggle_attendance, conference_id: conference.short_title,
proposal_id: event_of_submitter1.id,
registration_id: registration1.id, format: 'js'
expect(events_registration1.attended).to eq false
end
it 'does not mark registered user as absent' do
events_registration1.attended = true
events_registration1.save!
patch :toggle_attendance, conference_id: conference.short_title,
proposal_id: event_of_submitter1.id,
registration_id: registration1.id, format: 'js'
expect(events_registration1.attended).to eq true
end
end
end
describe 'organizer access' do
before(:each) do
sign_in user_organizer
end
it_behaves_like 'access allowed'
end
describe 'cfp access' do
before(:each) do
sign_in user_cfp
end
it_behaves_like 'access allowed'
end
describe 'submitter access' do
before(:each) do
sign_in submitter1
end
it_behaves_like 'access allowed'
end
describe 'other submitter access' do
before(:each) do
sign_in submitter2
end
it_behaves_like 'access not allowed', :root_path
end
describe 'without user access' do
it_behaves_like 'access not allowed', :root_path
end
end

View file

@ -13,15 +13,18 @@ describe ApplicationHelper, type: :helper do
describe '#registered_text' do
describe 'returns correct string' do
before :each do
event.require_registration = true
event.max_attendees = 3
end
it 'when there are no registrations' do
expect(registered_text(event)).to eq 'Registered: 0'
expect(registered_text(event)).to eq '0/3'
end
it 'when there is 1 registration' do
event.require_registration = true
event.max_attendees = 3
event.registrations << create(:registration, user: event.submitter)
expect(registered_text(event)).to eq 'Registered: 1/3'
event.registrations << create(:registration)
expect(registered_text(event)).to eq '1/3'
end
end
end

View file

@ -90,6 +90,52 @@ describe 'User' do
let(:user_event_with_cfp) { create(:event, users: [user], program: program_with_cfp) }
let(:user_commercial) { create(:commercial, commercialable: user_event_with_cfp) }
let(:event_of_user) do
create(:event, program: my_conference.program,
require_registration: true,
max_attendees: 3,
users: [user])
end
let(:event_of_user2) do
create(:event, program: my_conference.program,
require_registration: true,
max_attendees: 3,
users: [user2])
end
let(:user_registration) { create(:registration, user: user, conference: my_conference) }
let(:event_no_require_registration) { create(:event, program: my_conference.program) }
let!(:registration_to_event_no_require_registration) do
create(:events_registration,
event: event_no_require_registration,
registration: my_registration)
end
let(:registration_to_event_of_user) do
create(:events_registration,
event: event_of_user,
registration: my_registration,
attended: false)
end
let(:user_registration_to_event_of_user) do
create(:events_registration,
event: event_of_user,
registration: other_registration,
attended: false)
end
let(:registration_to_event_of_user2) do
create(:events_registration,
event: event_of_user2,
registration: my_registration,
attended: false)
end
let(:user_registration_to_event_of_user2) do
create(:events_registration,
event: event_of_user2,
registration: user_registration,
attended: false)
end
it{ should be_able_to(:manage, user) }
it{ should be_able_to(:manage, registration_public) }
@ -118,6 +164,30 @@ describe 'User' do
it{ should be_able_to(:create, user_event_with_cfp.commercials.new) }
it{ should be_able_to(:manage, user_commercial) }
it{ should_not be_able_to(:manage, commercial_event_unconfirmed) }
# Submitter can show/toggle/toggle_attendance of registration of another user to his/her event
it{ should be_able_to(:show, registration_to_event_of_user) }
it{ should be_able_to(:toggle, registration_to_event_of_user) }
it{ should be_able_to(:toggle_attendance, registration_to_event_of_user) }
it{ should be_able_to(:show, user_registration_to_event_of_user) }
it{ should be_able_to(:toggle, user_registration_to_event_of_user) }
it{ should be_able_to(:toggle_attendance, user_registration_to_event_of_user) }
# User can only toggle his/her own registration to an event
it{ should be_able_to(:toggle, user_registration_to_event_of_user2) }
it{ should_not be_able_to(:show, user_registration_to_event_of_user2) }
it{ should_not be_able_to(:toggle_attendance, user_registration_to_event_of_user2) }
# User cannot show/toggle/toggle_attendance of registration of other person to an event he/she is not a submitter of
it{ should_not be_able_to(:show, registration_to_event_of_user2) }
it{ should_not be_able_to(:toggle, registration_to_event_of_user2) }
it{ should_not be_able_to(:toggle_attendance, registration_to_event_of_user2) }
# User cannot show/toggle/toggle_attendance registration to an event that does not require_registration
it{ should_not be_able_to(:show, registration_to_event_no_require_registration) }
it{ should_not be_able_to(:toggle, registration_to_event_no_require_registration) }
it{ should_not be_able_to(:toggle_attendance, registration_to_event_no_require_registration) }
end
context 'user #is_admin?' do

View file

@ -0,0 +1,21 @@
require 'spec_helper'
describe Sponsor do
subject { create(:events_registration) }
describe 'association' do
it { is_expected.to belong_to :event }
it { is_expected.to belong_to :registration }
it { is_expected.to have_one :user }
end
describe 'validations' do
it 'has a valid factory' do
expect(build(:events_registration)).to be_valid
end
it { is_expected.to validate_presence_of(:event) }
it { is_expected.to validate_presence_of(:registration) }
it { is_expected.to validate_uniqueness_of(:event).scoped_to(:registration_id) }
end
end

View file

@ -8,7 +8,7 @@ describe 'admin/emails/index' do
assign :settings, @settings
render
expect(rendered).
to have_selector("input[type='checkbox'][value='1']", count: 9)
to have_selector("input[type='checkbox'][value='1']", count: 12)
expect(rendered).
to have_selector("input[checked='checked'][type='checkbox'][value='1']", count: 6)
expect(rendered).to include('Lorem Ipsum Dolsum')