diff --git a/.gitignore b/.gitignore index 75a1bdc6..ce3e7f0f 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,5 @@ pickle-email-*.html .env.local docker-compose.env docker-compose.yml +.DS_Store +.byebug_history diff --git a/.travis.yml b/.travis.yml index 9191bbd7..6650fbf9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_install: - "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc" - "echo `phantomjs -v`" addons: - mariadb: '10.1' + mariadb: '10.2' notifications: email: on_success: change diff --git a/Gemfile b/Gemfile index 08170e30..22dc5f6e 100644 --- a/Gemfile +++ b/Gemfile @@ -83,6 +83,8 @@ gem 'jquery-ui-rails', '~> 4.2.1' # for languages validation gem 'iso-639' +gem 'thor', '0.19.1' + # frontend javascripts source 'https://rails-assets.org' do # for placeholder images @@ -198,6 +200,11 @@ gem 'sprockets-rails' # for multiple speakers select on proposal/event forms gem 'selectize-rails' +# Nokogiri < 1.8.1 is subject to: +# CVE-2017-0663, CVE-2017-7375, CVE-2017-7376, CVE-2017-9047, CVE-2017-9048, +# CVE-2017-9049, CVE-2017-9050 +gem 'nokogiri', '>= 1.8.1' + # Use guard and spring for testing in development group :development do # to launch specs when files are modified diff --git a/Gemfile.lock b/Gemfile.lock index faaa8246..dc730e82 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -270,7 +270,7 @@ GEM open4 (~> 1.3.4) rake mini_magick (4.5.1) - mini_portile2 (2.2.0) + mini_portile2 (2.3.0) minitest (5.10.2) momentjs-rails (2.8.1) railties (>= 3.1) @@ -287,11 +287,11 @@ GEM multi_json (1.12.1) multi_xml (0.5.5) multipart-post (2.0.0) - mysql2 (0.4.2) + mysql2 (0.4.9) nenv (0.3.0) netrc (0.11.0) - nokogiri (1.8.0) - mini_portile2 (~> 2.2.0) + nokogiri (1.8.1) + mini_portile2 (~> 2.3.0) notiffany (0.1.1) nenv (~> 0.1) shellany (~> 0.0) @@ -511,7 +511,7 @@ GEM sysexits (1.2.0) term-ansicolor (1.3.2) tins (~> 1.0) - thor (0.19.4) + thor (0.19.1) thread_safe (0.3.6) tilt (1.4.1) timecop (0.7.1) @@ -609,6 +609,7 @@ DEPENDENCIES mini_magick money-rails mysql2 + nokogiri (>= 1.8.1) omniauth omniauth-facebook omniauth-github @@ -651,6 +652,7 @@ DEPENDENCIES sqlite3 stripe stripe-ruby-mock + thor (= 0.19.1) timecop transitions turbolinks @@ -661,4 +663,4 @@ DEPENDENCIES whenever BUNDLED WITH - 1.15.1 + 1.15.4 diff --git a/app/assets/javascripts/osem-tickets.js b/app/assets/javascripts/osem-tickets.js index ea99a349..51881055 100644 --- a/app/assets/javascripts/osem-tickets.js +++ b/app/assets/javascripts/osem-tickets.js @@ -4,12 +4,12 @@ function update_price($this){ // Calculate price for row var value = $this.val(); var price = $('#price_' + id).text(); - $('#total_row_' + id).text(value * price); + $('#total_row_' + id).text((value * price).toFixed(2)); // Calculate total price var total = 0; $('.total_row').each(function( index ) { - total += parseInt($(this).text()); + total += parseFloat($(this).text()); }); $('#total_price').text(total); } diff --git a/app/controllers/admin/booths_controller.rb b/app/controllers/admin/booths_controller.rb index a65de090..102eb10b 100644 --- a/app/controllers/admin/booths_controller.rb +++ b/app/controllers/admin/booths_controller.rb @@ -22,7 +22,7 @@ module Admin redirect_to admin_conference_booths_path, notice: 'Booth successfully created.' else - flash[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}." render :new end end @@ -40,7 +40,7 @@ module Admin redirect_to admin_conference_booths_path, notice: "Successfully updated booth for #{@booth.title}." else - flash[:error] = "An error prohibited the Booth for #{@booth.title} "\ + flash.now[:error] = "An error prohibited the Booth for #{@booth.title} "\ "#{@booth.errors.full_messages.join('. ')}." render :edit end diff --git a/app/controllers/admin/events_controller.rb b/app/controllers/admin/events_controller.rb index bb23dac9..accfb281 100644 --- a/app/controllers/admin/events_controller.rb +++ b/app/controllers/admin/events_controller.rb @@ -102,7 +102,7 @@ module Admin ahoy.track 'Event submission', title: 'New submission' redirect_to admin_conference_program_events_path(@conference.short_title), notice: 'Event was successfully submitted.' else - flash[:error] = "Could not submit proposal: #{@event.errors.full_messages.join(', ')}" + flash.now[:error] = "Could not submit proposal: #{@event.errors.full_messages.join(', ')}" render action: 'new' end end diff --git a/app/controllers/admin/physical_ticket_controller.rb b/app/controllers/admin/physical_tickets_controller.rb similarity index 88% rename from app/controllers/admin/physical_ticket_controller.rb rename to app/controllers/admin/physical_tickets_controller.rb index d43c5c33..0fb26ad8 100644 --- a/app/controllers/admin/physical_ticket_controller.rb +++ b/app/controllers/admin/physical_tickets_controller.rb @@ -1,5 +1,5 @@ module Admin - class PhysicalTicketController < Admin::BaseController + class PhysicalTicketsController < Admin::BaseController before_action :authenticate_user! load_resource :conference, find_by: :short_title load_and_authorize_resource diff --git a/app/controllers/booths_controller.rb b/app/controllers/booths_controller.rb index 99fde3bc..f0457b88 100644 --- a/app/controllers/booths_controller.rb +++ b/app/controllers/booths_controller.rb @@ -23,7 +23,7 @@ class BoothsController < ApplicationController redirect_to conference_booths_path, notice: 'Booth successfully created.' else - flash[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}." render :new end end @@ -40,7 +40,7 @@ class BoothsController < ApplicationController redirect_to conference_booths_path, notice: 'Booth successfully updated!' else - flash[:error] = "Booth could not be updated. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Booth could not be updated. #{@booth.errors.full_messages.to_sentence}." end end @@ -56,7 +56,7 @@ class BoothsController < ApplicationController redirect_to conference_booths_path, notice: 'Booth successfully withdrawn' else - flash[:error] = "Booth could not be withdrawn. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Booth could not be withdrawn. #{@booth.errors.full_messages.to_sentence}." end end @@ -70,7 +70,7 @@ class BoothsController < ApplicationController redirect_to conference_booths_path, notice: 'Booth successfully confirmed' else - flash[:error] = "Booth could not be confirmed. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Booth could not be confirmed. #{@booth.errors.full_messages.to_sentence}." end end @@ -84,7 +84,7 @@ class BoothsController < ApplicationController redirect_to conference_booths_path, notice: 'Booth successfully re-submitted' else - flash[:error] = "Booth could not be re-submitted. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Booth could not be re-submitted. #{@booth.errors.full_messages.to_sentence}." end end diff --git a/app/controllers/payments_controller.rb b/app/controllers/payments_controller.rb index b5e2c193..322ed397 100644 --- a/app/controllers/payments_controller.rb +++ b/app/controllers/payments_controller.rb @@ -10,6 +10,9 @@ class PaymentsController < ApplicationController def new @total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false) + if @total_amount_to_pay.zero? + raise CanCan::AccessDenied.new('Nothing to pay for!', :new, Payment) + end @unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference) end @@ -18,7 +21,7 @@ class PaymentsController < ApplicationController if @payment.purchase && @payment.save update_purchased_ticket_purchases - redirect_to conference_physical_ticket_index_path, + redirect_to conference_physical_tickets_path, notice: 'Thanks! Your ticket is booked successfully.' else @total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false) diff --git a/app/controllers/physical_ticket_controller.rb b/app/controllers/physical_tickets_controller.rb similarity index 94% rename from app/controllers/physical_ticket_controller.rb rename to app/controllers/physical_tickets_controller.rb index af02155c..2f6f18ec 100644 --- a/app/controllers/physical_ticket_controller.rb +++ b/app/controllers/physical_tickets_controller.rb @@ -1,4 +1,4 @@ -class PhysicalTicketController < ApplicationController +class PhysicalTicketsController < ApplicationController before_action :authenticate_user! load_resource :conference, find_by: :short_title load_and_authorize_resource find_by: :token diff --git a/app/controllers/schedules_controller.rb b/app/controllers/schedules_controller.rb index eeb272e0..eb145730 100644 --- a/app/controllers/schedules_controller.rb +++ b/app/controllers/schedules_controller.rb @@ -21,10 +21,10 @@ class SchedulesController < ApplicationController # the schedule takes you to today if it is a date of the schedule @current_day = @conference.current_conference_day @day = @current_day.present? ? @current_day : @dates.first - return unless @current_day - # the schedule takes you to the current time if it is beetween the start and the end time. - @hour_column = @conference.hours_from_start_time(@conf_start, @conference.end_hour) - + unless @current_day + # the schedule takes you to the current time if it is beetween the start and the end time. + @hour_column = @conference.hours_from_start_time(@conf_start, @conference.end_hour) + end # Ids of the schedules of confrmed self_organized tracks along with the selected_schedule_id @selected_schedules_ids = [@conference.program.selected_schedule_id] @conference.program.tracks.self_organized.confirmed.each do |track| diff --git a/app/controllers/ticket_purchases_controller.rb b/app/controllers/ticket_purchases_controller.rb index f15fc993..3eb8b68d 100644 --- a/app/controllers/ticket_purchases_controller.rb +++ b/app/controllers/ticket_purchases_controller.rb @@ -12,14 +12,14 @@ class TicketPurchasesController < ApplicationController redirect_to new_conference_payment_path, notice: 'Please pay here to get tickets.' elsif current_user.ticket_purchases.by_conference(@conference).paid.any? - redirect_to conference_physical_ticket_index_path, + redirect_to conference_physical_tickets_path, notice: 'You have free tickets for the conference.' else redirect_to conference_tickets_path(@conference.short_title), error: 'Please get at least one ticket to continue.' end else - redirect_to conference_conference_registration_path(@conference.short_title), + redirect_to conference_tickets_path(@conference.short_title), error: "Oops, something went wrong with your purchase! #{message}" end end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index e8f295d5..8f620e62 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -44,7 +44,7 @@ module EventsHelper if @program.tracks.confirmed.cfp_active.any? form.input :track_id, as: :select, collection: @program.tracks.confirmed.cfp_active.pluck(:name, :id), - include_blank: true + include_blank: '(Please select)' end end end diff --git a/app/models/ticket_purchase.rb b/app/models/ticket_purchase.rb index a2ed2747..97fa9957 100644 --- a/app/models/ticket_purchase.rb +++ b/app/models/ticket_purchase.rb @@ -5,7 +5,8 @@ class TicketPurchase < ActiveRecord::Base belongs_to :payment validates :ticket_id, :user_id, :conference_id, :quantity, presence: true - + validate :one_registration_ticket_per_user + validate :registration_ticket_already_purchased, on: :create validates :quantity, numericality: { greater_than: 0 } delegate :title, to: :ticket @@ -25,18 +26,21 @@ class TicketPurchase < ActiveRecord::Base def self.purchase(conference, user, purchases) errors = [] - ActiveRecord::Base.transaction do - conference.tickets.each do |ticket| - quantity = purchases[ticket.id.to_s].to_i - # if the user bought the ticket and is still unpaid, just update the quantity - purchase = if ticket.bought?(user) && ticket.unpaid?(user) - update_quantity(conference, quantity, ticket, user) - else - purchase_ticket(conference, quantity, ticket, user) - end - - if purchase && !purchase.save - errors.push(purchase.errors.full_messages) + if count_purchased_registration_tickets(conference, purchases) > 1 + errors.push('You cannot buy more than one registration tickets.') + else + ActiveRecord::Base.transaction do + conference.tickets.each do |ticket| + quantity = purchases[ticket.id.to_s].to_i + # if the user bought the ticket and is still unpaid, just update the quantity + purchase = if ticket.bought?(user) && ticket.unpaid?(user) + update_quantity(conference, quantity, ticket, user) + else + purchase_ticket(conference, quantity, ticket, user) + end + if purchase && !purchase.save + errors.push(purchase.errors.full_messages) + end end end end @@ -71,6 +75,18 @@ class TicketPurchase < ActiveRecord::Base end Mailbot.ticket_confirmation_mail(self).deliver_later end + + def one_registration_ticket_per_user + if ticket.try(:registration_ticket?) && quantity != 1 + errors.add(:quantity, 'cannot be greater than one for registration tickets.') + end + end + + def registration_ticket_already_purchased + if ticket.try(:registration_ticket?) && user.tickets.for_registration(conference).present? + errors.add(:quantity, 'cannot be greater than one for registration tickets.') + end + end end private @@ -79,3 +95,9 @@ def set_week self.week = created_at.strftime('%W') save! end + +def count_purchased_registration_tickets(conference, purchases) + conference.tickets.for_registration.inject(0) do |sum, registration_ticket| + sum + purchases[registration_ticket.id.to_s].to_i + end +end diff --git a/app/models/ticket_scanning.rb b/app/models/ticket_scanning.rb index 6ce9d00c..350d4f9b 100644 --- a/app/models/ticket_scanning.rb +++ b/app/models/ticket_scanning.rb @@ -1,3 +1,13 @@ class TicketScanning < ActiveRecord::Base belongs_to :physical_ticket + + before_create :mark_user_present + + private + + def mark_user_present + if physical_ticket.ticket.registration_ticket? + physical_ticket.user.mark_attendance_for_conference(physical_ticket.conference) + end + end end diff --git a/app/models/user.rb b/app/models/user.rb index 793db609..231e1c11 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -47,11 +47,19 @@ class User < ActiveRecord::Base has_many :event_users, dependent: :destroy has_many :events, -> { uniq }, through: :event_users has_many :presented_events, -> { joins(:event_users).where(event_users: {event_role: 'speaker'}).uniq }, through: :event_users, source: :event - has_many :registrations, dependent: :destroy + has_many :registrations, dependent: :destroy do + def for_conference conference + where(conference: conference).first + end + end has_many :events_registrations, through: :registrations has_many :ticket_purchases, dependent: :destroy has_many :payments, dependent: :destroy - has_many :tickets, through: :ticket_purchases, source: :ticket + has_many :tickets, through: :ticket_purchases, source: :ticket do + def for_registration conference + where(conference: conference, registration_ticket: true).first + end + end has_many :votes, dependent: :destroy has_many :voted_events, through: :votes, source: :events has_many :subscriptions, dependent: :destroy @@ -89,6 +97,12 @@ class User < ActiveRecord::Base event_registration.attended end + def mark_attendance_for_conference conference + registration = registrations.for_conference(conference) + registration.attended = true + registration.save + end + def name self[:name].blank? ? username : self[:name] end diff --git a/app/pdfs/ticket_pdf.rb b/app/pdfs/ticket_pdf.rb index ecb4cd2c..9a09f9fe 100644 --- a/app/pdfs/ticket_pdf.rb +++ b/app/pdfs/ticket_pdf.rb @@ -25,20 +25,23 @@ class TicketPdf < Prawn::Document move_up @mid_vertical draw_text 'TICKET HOLDER', at: [@x, cursor - 30], size: 17 dash(2, space: 0) - stroke_rectangle [@x, cursor - 50], 230, 150 - move_down 80 - draw_text 'NAME', at: [@x + 10, cursor], size: 13 - fill_color '808080' - draw_text @user.name.to_s, at: [@x + 10, cursor - 25], size: 20 - fill_color '000000' - draw_text 'EMAIL', at: [@x + 10, cursor - 50], size: 13 - fill_color '808080' - draw_text @user.email.to_s, at: [@x + 10, cursor - 75], size: 20 - fill_color '000000' - move_up 20 + bounding_box [@x, cursor - 50], width: 230, height: 150 do + pad(15) do + text_box 'NAME', at: [@x + 10, cursor], size: 13 + fill_color '808080' + text_box @user.name.to_s, at: [@x + 10, cursor - 20], size: 18 + fill_color '000000' + text_box 'EMAIL', at: [@x + 10, cursor - 60], size: 13 + fill_color '808080' + text_box @user.email.to_s, at: [@x + 10, cursor - 80], size: 18, overflow: :shrink_to_fit + fill_color '000000' + end + stroke_bounds + end end def draw_second_square + move_up 150 if @conference.picture? if 7 * @conference.picture.image[:width] > 12 * @conference.picture.image[:height] image "#{Rails.root}/public#{@conference.picture_url}", at: [@mid_horizontal + 30, cursor], width: 120 @@ -51,7 +54,11 @@ class TicketPdf < Prawn::Document move_down 70 draw_text @conference.title.to_s, at: [@mid_horizontal + 30, cursor - 30], size: 12 draw_text @conference.organization.name.to_s, at: [@mid_horizontal + 30, cursor - 50], size: 12 - draw_text @conference.venue.name.to_s, at: [@mid_horizontal + 30, cursor - 70] + if @conference.venue + draw_text @conference.venue.name, at: [@mid_horizontal + 30, cursor - 70] + draw_text @conference.venue.street, at: [@mid_horizontal + 30, cursor - 90] + draw_text @conference.venue.city, at: [@mid_horizontal + 30, cursor - 110] + end move_up 130 move_down @mid_vertical end diff --git a/app/views/admin/booths/index.html.haml b/app/views/admin/booths/index.html.haml index fc3f3ba3..428895e5 100644 --- a/app/views/admin/booths/index.html.haml +++ b/app/views/admin/booths/index.html.haml @@ -4,9 +4,6 @@ %h1 Booths = "(#{@booths.length})" if @booths.any? - .pull-right - - if can? :create, Booth - = link_to 'Add Booth', new_admin_conference_booth_path(@conference.short_title), class: 'button btn btn-primary' %p.text-muted All the booth requests @@ -32,45 +29,50 @@ ( = link_to "#{@conference.booth_limit} booths", edit_admin_conference_path(@conference.short_title) ) - %table.table.table-striped.table-bordered.table-hover.datatable - %thead - %th - %b ID - %th - %b Logo - %th - %b Title - %th - %b Submitter - %th - %b Responsibles - %th - %b State - %th - %b Actions - - @booths.each do |booth| - %tr - %td - = booth.id - %td - - if booth.logo_link - = image_tag(booth.picture.thumb.url, width: '20%') - %td - = link_to booth.title, admin_conference_booth_path(@conference.short_title, booth) - %td - = link_to booth.submitter.name, admin_user_path(booth.submitter) if booth.submitter - %td - .responsibles - - booth.responsibles.each_with_index do |responsible, i| - = link_to responsible.name, admin_user_path(responsible) - = ", " unless i == booth.responsibles.length - 1 - %td - .btn-group - %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } - = booth.state.humanize - %span.caret - %ul.dropdown-menu{ role: 'menu' } - = render 'change_state_dropdown', booth: booth + - if @booths.any? + %table.table.table-striped.table-bordered.table-hover.datatable + %thead + %th + %b ID + %th + %b Logo + %th + %b Title + %th + %b Submitter + %th + %b Responsibles + %th + %b State + %th + %b Actions + - @booths.each do |booth| + %tr %td - = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id), - class: 'btn btn-primary' + = booth.id + %td + - if booth.logo_link + = image_tag(booth.picture.thumb.url, width: '20%') + %td + = link_to booth.title, admin_conference_booth_path(@conference.short_title, booth) + %td + = link_to booth.submitter.name, admin_user_path(booth.submitter) if booth.submitter + %td + .responsibles + - booth.responsibles.each_with_index do |responsible, i| + = link_to responsible.name, admin_user_path(responsible) + = ", " unless i == booth.responsibles.length - 1 + %td + .btn-group + %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } + = booth.state.humanize + %span.caret + %ul.dropdown-menu{ role: 'menu' } + = render 'change_state_dropdown', booth: booth + %td + = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id), + class: 'btn btn-primary' +.row + .col-md-12.text-right + - if can? :create, Booth + = link_to 'New Booth', new_admin_conference_booth_path(@conference.short_title), class: 'button btn btn-primary' diff --git a/app/views/admin/cfps/_booths_cfp.html.haml b/app/views/admin/cfps/_booths_cfp.html.haml index 89012336..7cdc6db4 100644 --- a/app/views/admin/cfps/_booths_cfp.html.haml +++ b/app/views/admin/cfps/_booths_cfp.html.haml @@ -1,12 +1,16 @@ %dt - Start Date + Type: +%dd + = @cfp.cfp_type.capitalize +%dt + Start Date: %dd = @cfp.start_date.strftime('%A, %B %e. %Y') %dt - End Date + End Date: %dd = @cfp.end_date.strftime('%A, %B %e. %Y') %dt - Days Left + Days Left: %dd = pluralize(@cfp.remaining_days, 'day') diff --git a/app/views/admin/cfps/_events_cfp.html.haml b/app/views/admin/cfps/_events_cfp.html.haml index 51bc2079..f06aa6ca 100644 --- a/app/views/admin/cfps/_events_cfp.html.haml +++ b/app/views/admin/cfps/_events_cfp.html.haml @@ -1,3 +1,7 @@ +%dt + Type: +%dd + = @cfp.cfp_type.capitalize %dt Start Date: %dd#start_date @@ -19,7 +23,7 @@ %dd = tracks(@conference) %dt - Public Schedule + Public Schedule: %dd#schedule_public - if @program.schedule_public Yes @@ -33,6 +37,6 @@ - else No %dt - Rating Levels + Rating Levels: %dd#rating = @program.rating diff --git a/app/views/admin/cfps/_tracks_cfp.html.haml b/app/views/admin/cfps/_tracks_cfp.html.haml index e381df96..bcc2df43 100644 --- a/app/views/admin/cfps/_tracks_cfp.html.haml +++ b/app/views/admin/cfps/_tracks_cfp.html.haml @@ -1,3 +1,7 @@ +%dt + Type: +%dd + = @cfp.cfp_type.capitalize %dt Start Date: %dd#start_date diff --git a/app/views/admin/events/_nested_comments.html.haml b/app/views/admin/events/_nested_comments.html.haml index 8ab3cabb..0bfb440c 100644 --- a/app/views/admin/events/_nested_comments.html.haml +++ b/app/views/admin/events/_nested_comments.html.haml @@ -6,9 +6,9 @@ %div %a.pull-right.comment-reply-link{ href: '#' } Reply .comment-reply - = semantic_form_for :comment, url: '#{comment_admin_conference_program_event_path(@conference.short_title, comment.commentable_id)}', method: :post do |f| + = semantic_form_for :comment, url: comment_admin_conference_program_event_path(@conference.short_title, comment.commentable_id), method: :post do |f| = f.input :body - %input{ name: 'parent', type: 'hidden', value: '#{comment.id}' } + %input{ name: 'parent', type: 'hidden', value: comment.id } %input{ name: 'authenticity_token', type: 'hidden', value: '#{form_authenticity_token}' } %button.btn.btn-primary.pull-right{ name: 'button', type: 'submit' } Add Reply - comment.children.each do |child| diff --git a/app/views/admin/events/index.html.haml b/app/views/admin/events/index.html.haml index 50d7acd5..f8b58b63 100644 --- a/app/views/admin/events/index.html.haml +++ b/app/views/admin/events/index.html.haml @@ -9,13 +9,14 @@ =link_to 'Add Event', new_admin_conference_program_event_path(@conference.short_title), class: 'button btn btn-default btn-info' - if can? :read, Event .btn-group - %button.btn.btn-default.dropdown-toggle{ 'data-toggle' => 'dropdown', type: 'button', class: 'btn btn-success' } - Export PDF - %span.caret - %ul.dropdown-menu{ role: 'menu' } - %li= link_to 'All Events', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'all') - %li= link_to 'Confirmed Events', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'confirmed') - %li= link_to 'All Events with Comments', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'all_with_comments') + .btn-group + %button.btn.btn-default.dropdown-toggle{ 'data-toggle' => 'dropdown', type: 'button', class: 'btn btn-success' } + Export PDF + %span.caret + %ul.dropdown-menu{ role: 'menu' } + %li= link_to 'All Events', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'all') + %li= link_to 'Confirmed Events', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'confirmed') + %li= link_to 'All Events with Comments', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'all_with_comments') .btn-group %button.btn.btn-default.dropdown-toggle{ 'data-toggle' => 'dropdown', type: 'button', class: 'btn btn-success' } Export CSV diff --git a/app/views/admin/physical_ticket/index.html.haml b/app/views/admin/physical_tickets/index.html.haml similarity index 100% rename from app/views/admin/physical_ticket/index.html.haml rename to app/views/admin/physical_tickets/index.html.haml diff --git a/app/views/admin/schedules/show.html.haml b/app/views/admin/schedules/show.html.haml index 9009fcbb..258b4d87 100644 --- a/app/views/admin/schedules/show.html.haml +++ b/app/views/admin/schedules/show.html.haml @@ -40,11 +40,23 @@ .tab-pane{ class: "#{ (@dates.first == date) ? 'active' : '' }", id: "#{date}" } = render partial: 'day_tab', locals: { date: date } - else - .h3 - No Rooms! - %small - = link_to 'Create rooms', admin_conference_venue_rooms_path - before creating the schedule. + - if @venue.try(:rooms).present? + .text-right + - if can? :create, @program.schedules.new + = link_to 'Add Schedule', admin_conference_schedules_path(@conference.short_title), + method: :post, class: 'btn btn-primary' + - elsif @venue + .h3 + No Rooms! + %small + = link_to 'Create rooms', admin_conference_venue_rooms_path + before creating the schedule. + - else + .h3 + No Venue! + %small + = link_to 'Create a venue with rooms', new_admin_conference_venue_path + before creating the schedule. :javascript $(document).ready( function() { diff --git a/app/views/admin/tickets/index.html.haml b/app/views/admin/tickets/index.html.haml index b8cdb505..42154ae7 100644 --- a/app/views/admin/tickets/index.html.haml +++ b/app/views/admin/tickets/index.html.haml @@ -40,4 +40,4 @@ .row .col-md-12 = link_to 'Add Ticket', new_admin_conference_ticket_path, class: 'btn btn-success pull-right' - = link_to 'Tickets Sold', admin_conference_physical_ticket_index_path, class: 'button btn btn-default btn-info pull-right' + = link_to 'Tickets Sold', admin_conference_physical_tickets_path, class: 'button btn btn-default btn-info pull-right' diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 6ac42003..b814ac8e 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -7,75 +7,76 @@ Categorize events in your conference .row .col-md-12 - %table.table.table-hover.table-striped.table-bordered.datatable#tracks - %thead - %th ID - %th Name - %th Description - %th Room - %th Start Date - %th End Date - %th Submitter - %th Included in Cfp - %th State - %th Actions - %tbody - - @tracks.each do |track| - %tr - %td - = track.id - %td{ style: 'padding: 15px 0px 0px 10px;' } - = link_to admin_conference_program_track_path(@conference.short_title, track), class: 'btn' do - %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} - = track.name - %td - %p - = markdown(truncate(track.description)) - %td - = track.room.try(:name) - %td - = track.start_date.strftime('%A, %B %-d. %Y') if track.start_date - %td - = track.end_date.strftime('%A, %B %-d. %Y') if track.end_date - %td - = link_to track.submitter.name, admin_user_path(track.submitter) if track.self_organized? - %td.text-center{ 'id' => "cfp_switch_#{track.id}", 'data-order' => track.cfp_active.to_s } - = check_box_tag "#{@conference.short_title}_#{track.short_name}", track.id, track.cfp_active, - class: 'switch-checkbox', method: :patch, - url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.short_name)+"?included=", - data: { size: 'small', - on_color: 'success', - off_color: 'warning', - on_text: 'Yes', - off_text: 'No' } + - if @tracks.any? + %table.table.table-hover.table-striped.table-bordered.datatable#tracks + %thead + %th ID + %th Name + %th Description + %th Room + %th Start Date + %th End Date + %th Submitter + %th Included in Cfp + %th State + %th Actions + %tbody + - @tracks.each do |track| + %tr + %td + = track.id + %td{ style: 'padding: 15px 0px 0px 10px;' } + = link_to admin_conference_program_track_path(@conference.short_title, track), class: 'btn' do + %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} + = track.name + %td + %p + = markdown(truncate(track.description)) + %td + = track.room.try(:name) + %td + = track.start_date.strftime('%A, %B %-d. %Y') if track.start_date + %td + = track.end_date.strftime('%A, %B %-d. %Y') if track.end_date + %td + = link_to track.submitter.name, admin_user_path(track.submitter) if track.self_organized? + %td.text-center{ 'id' => "cfp_switch_#{track.id}", 'data-order' => track.cfp_active.to_s } + = check_box_tag "#{@conference.short_title}_#{track.short_name}", track.id, track.cfp_active, + class: 'switch-checkbox', method: :patch, + url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.short_name)+"?included=", + data: { size: 'small', + on_color: 'success', + off_color: 'warning', + on_text: 'Yes', + off_text: 'No' } - %td.text-center - - if track.self_organized? - .btn-group - %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } - = track.state.humanize - %span.caret - %ul.dropdown-menu{ role: 'menu' } - = render 'change_state_dropdown', track: track - - else - = track.state.humanize - %td - .btn-group{ role: 'group' } - - if can? :edit, track - = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-primary' - - special_style = true - - if can? :destroy, track - = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track), method: :delete, class: 'btn btn-danger', - data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" } + %td.text-center - if track.self_organized? - - if track.selected_schedule - - if can? :show, track.selected_schedule - = link_to 'Show Schedule', admin_conference_schedule_path(@conference.short_title, track.selected_schedule), - class: 'btn btn-default' - - elsif can? :create, @program.schedules.build(track: track) - = button_to 'Create Schedule', admin_conference_schedules_path(@conference.short_title), - form: { class: 'btn', style: 'padding: 0px 0px; margin-top: -1px;' }, class: 'btn btn-default', - style: ('border-top-left-radius: 0; border-bottom-left-radius: 0;' if special_style), params: { 'schedule[track_id]' => track.id } + .btn-group + %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } + = track.state.humanize + %span.caret + %ul.dropdown-menu{ role: 'menu' } + = render 'change_state_dropdown', track: track + - else + = track.state.humanize + %td + .btn-group{ role: 'group' } + - if can? :edit, track + = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-primary' + - special_style = true + - if can? :destroy, track + = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track), method: :delete, class: 'btn btn-danger', + data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" } + - if track.self_organized? + - if track.selected_schedule + - if can? :show, track.selected_schedule + = link_to 'Show Schedule', admin_conference_schedule_path(@conference.short_title, track.selected_schedule), + class: 'btn btn-default' + - elsif can? :create, @program.schedules.build(track: track) + = button_to 'Create Schedule', admin_conference_schedules_path(@conference.short_title), + form: { class: 'btn', style: 'padding: 0px 0px; margin-top: -1px;' }, class: 'btn btn-default', + style: ('border-top-left-radius: 0; border-bottom-left-radius: 0;' if special_style), params: { 'schedule[track_id]' => track.id } .row .col-md-12.text-right - = link_to 'New Track', new_admin_conference_program_track_path(@conference.short_title), class: 'btn btn-success' + = link_to 'New Track', new_admin_conference_program_track_path(@conference.short_title), class: 'btn btn-primary' diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index 12f9dbbc..8c717900 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -19,7 +19,7 @@ - else - conference = Conference.find_by(id: version.conference_id) - conference_short_title = conference.try(:short_title) || current_or_last_object_state('Conference', version.conference_id).try(:short_title) || ' ' - = link_if_alive version, role.try(:name), admin_conference_role_path(role.try(:name) || ' ', conference_short_title), conference + = link_if_alive version, role.try(:name), admin_conference_role_path(conference_short_title,role.try(:name) || ' '), conference = version.event == 'create' ? 'to' : 'from' user @@ -106,7 +106,8 @@ = 'booth' - booth = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, booth.title, - admin_conference_booth_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id ) + admin_conference_booth_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id ), + conference - when 'Program' = link_if_alive version, 'program', diff --git a/app/views/conference_registrations/show.html.haml b/app/views/conference_registrations/show.html.haml index c510a263..83d6d89c 100644 --- a/app/views/conference_registrations/show.html.haml +++ b/app/views/conference_registrations/show.html.haml @@ -109,7 +109,7 @@ You haven't bought any tickets. = link_to 'Please get some tickets to support us!', conference_tickets_path(@conference.short_title) %p - (Your participation won't be valid without getting a ticket) + (Your participation won't be valid without getting a registration ticket) .row .col-md-12 diff --git a/app/views/conferences/_conference_details.html.haml b/app/views/conferences/_conference_details.html.haml index ebf80ef6..84a87303 100644 --- a/app/views/conferences/_conference_details.html.haml +++ b/app/views/conferences/_conference_details.html.haml @@ -47,4 +47,4 @@ - else = link_to 'Unsubscribe', conference_subscriptions_path(conference.short_title), method: :delete, class: 'btn btn-default' - if current_user && current_user.physical_tickets.by_conference(conference).any? - = link_to "My Tickets", conference_physical_ticket_index_path(conference.short_title), class: 'btn btn-default' + = link_to "My Tickets", conference_physical_tickets_path(conference.short_title), class: 'btn btn-default' diff --git a/app/views/conferences/_venue.html.haml b/app/views/conferences/_venue.html.haml index 62af90c7..4436b0fe 100644 --- a/app/views/conferences/_venue.html.haml +++ b/app/views/conferences/_venue.html.haml @@ -32,4 +32,4 @@ = @conference.venue.country_name - if @conference.venue.website %br - =link_to @conference.venue.website, @conference.venue.website + =link_to(h(@conference.venue.website), h(@conference.venue.website)).html_safe diff --git a/app/views/conferences/_venue_map.html.haml b/app/views/conferences/_venue_map.html.haml index b58b3053..717069d5 100644 --- a/app/views/conferences/_venue_map.html.haml +++ b/app/views/conferences/_venue_map.html.haml @@ -3,15 +3,15 @@ - content_for(:script_body) do :javascript // create a map in the "map" div, set the view to a given place and zoom - var map = L.map('map', { scrollWheelZoom: false }).setView([#{@conference.venue.latitude}, #{@conference.venue.longitude}], 11); + var map = L.map('map', { scrollWheelZoom: false }).setView([#{h(@conference.venue.latitude)}, #{h(@conference.venue.longitude)}], 11); // add an OpenStreetMap tile layer L.tileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox', maxZoom: 18 }).addTo(map); // add a marker in the given location, attach some popup content to it and open the popup - L.marker([#{@conference.venue.latitude}, #{@conference.venue.longitude}]).addTo(map) - .bindPopup("#{popup}") + L.marker([#{h(@conference.venue.latitude)}, #{h(@conference.venue.longitude)}]).addTo(map) + .bindPopup("#{h(popup)}") .openPopup(); // Turn scrollwheel on when user clicks map.on('focus', function(e) { diff --git a/app/views/conferences/show.html.haml b/app/views/conferences/show.html.haml index f94b8ee4..dd6b2d62 100644 --- a/app/views/conferences/show.html.haml +++ b/app/views/conferences/show.html.haml @@ -82,7 +82,7 @@ - content_for :script_head do :javascript - var triangle_tcs = tinycolor("#{@conference.color}").monochromatic(); + var triangle_tcs = tinycolor("#{h(@conference.color)}").monochromatic(); var triangle_colors = triangle_tcs.map(function(t) { return t.toHexString(); }); $(function () { $(document).ready(function() { diff --git a/app/views/physical_ticket/index.html.haml b/app/views/physical_tickets/index.html.haml similarity index 100% rename from app/views/physical_ticket/index.html.haml rename to app/views/physical_tickets/index.html.haml diff --git a/app/views/physical_ticket/show.html.haml b/app/views/physical_tickets/show.html.haml similarity index 100% rename from app/views/physical_ticket/show.html.haml rename to app/views/physical_tickets/show.html.haml diff --git a/app/views/proposals/_encouragement_text.html.haml b/app/views/proposals/_encouragement_text.html.haml index c6d574d6..48fcd045 100644 --- a/app/views/proposals/_encouragement_text.html.haml +++ b/app/views/proposals/_encouragement_text.html.haml @@ -2,7 +2,7 @@ - if @program.event_types.any? You can submit proposals for = "#{event_types(@conference)}." - - if @program.tracks.any? + - if @program.tracks.confirmed.cfp_active.any? Proposals should fit in one of the = "#{pluralize(@program.tracks.confirmed.cfp_active.count, 'track')}:" = "#{tracks(@conference)}." diff --git a/app/views/tickets/_ticket.html.haml b/app/views/tickets/_ticket.html.haml index e3985773..8f5fc82b 100644 --- a/app/views/tickets/_ticket.html.haml +++ b/app/views/tickets/_ticket.html.haml @@ -1,5 +1,5 @@ %tr - %td.col-sm-8.col-md-6 + %td.col-sm-8.col-md-4 .media .media-body %h4.media-heading @@ -7,9 +7,14 @@ %h5.media-heading - unless ticket.description.blank? = markdown(ticket.description) + %td.col-sm-1.col-md-2.text-center + = ticket.registration_ticket? ? 'Yes' : 'No' %td.col-sm-1.col-md-1 - = text_field_tag("tickets[][#{ticket.id}]", 0, - type: 'number', min: 0, class: "form-control quantity", 'data-id' => ticket.id) + - options = { type: 'number', min: 0, class: "form-control quantity", 'data-id' => ticket.id } + - if ticket.registration_ticket? + - options[:max] = 1 + - options[:disabled] = current_user.tickets.for_registration(ticket.conference).present? + = text_field_tag("tickets[][#{ticket.id}]", 0, options) %td.col-sm-1.col-md-1.text-center = ticket.price.symbol %span{id: "price_#{ticket.id}"} diff --git a/app/views/tickets/index.html.haml b/app/views/tickets/index.html.haml index dc67f529..cba13ea5 100644 --- a/app/views/tickets/index.html.haml +++ b/app/views/tickets/index.html.haml @@ -14,6 +14,7 @@ %thead %tr %th Ticket + %th Registration Ticket %th Quantity %th Price %th Total @@ -21,6 +22,7 @@ - @conference.tickets.each do |ticket| = render partial: 'ticket', f: f, locals: {ticket: ticket} %tr + %td %td %td %td.col-sm-1.col-md-1.text-center @@ -46,4 +48,4 @@ .col-md-13 %p.text-muted.text-center %small - * Getting a ticket is mandatory. Your participation will not be valid until you get a ticket. + * Getting a registration ticket is mandatory. Your participation will not be valid until you get a registration ticket. diff --git a/config/environments/production.rb b/config/environments/production.rb index cb3a5d67..4e2c2e79 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -36,7 +36,7 @@ Osem::Application.configure do # config.force_ssl = true # See everything in the log (default is :info) - # config.log_level = :debug + config.log_level = :info # Prepend all log lines with the following tags # config.log_tags = [ :subdomain, :uuid ] diff --git a/config/routes.rb b/config/routes.rb index 0d7e7aec..99f716e4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -122,7 +122,7 @@ Osem::Application.routes.draw do resources :targets, except: [:show] resources :campaigns, except: [:show] resources :emails, only: [:show, :update, :index] - resources :physical_ticket, only: [:index] + resources :physical_tickets, only: [:index] resources :roles, except: [:new, :create] do member do post :toggle_user @@ -184,7 +184,7 @@ Osem::Application.routes.draw do resources :tickets, only: [:index] resources :ticket_purchases, only: [:create, :destroy, :index] resources :payments, only: [:index, :new, :create] - resources :physical_ticket, only: [:index, :show] + resources :physical_tickets, only: [:index, :show] resource :subscriptions, only: [:create, :destroy] resource :schedule, only: [:show] do member do diff --git a/spec/controllers/admin/ticket_scannings_controller_spec.rb b/spec/controllers/admin/ticket_scannings_controller_spec.rb index 245bd885..2eb2e4ed 100644 --- a/spec/controllers/admin/ticket_scannings_controller_spec.rb +++ b/spec/controllers/admin/ticket_scannings_controller_spec.rb @@ -4,7 +4,9 @@ describe Admin::TicketScanningsController do let(:admin) { create(:admin) } let(:conference) { create(:conference) } let(:user) { create(:user) } - let(:paid_ticket_purchase) { create(:ticket_purchase, conference: conference, user: user) } + let!(:registration) { create(:registration, conference: conference, user: user) } + let(:registration_ticket) { create(:registration_ticket, conference: conference) } + let(:paid_ticket_purchase) { create(:ticket_purchase, conference: conference, user: user, ticket: registration_ticket, quantity: 1) } let(:physical_ticket) { create(:physical_ticket, ticket_purchase: paid_ticket_purchase) } context 'logged in as user with no role' do diff --git a/spec/controllers/physical_ticket_controller_spec.rb b/spec/controllers/physical_ticket_controller_spec.rb index 863e27af..476a1717 100644 --- a/spec/controllers/physical_ticket_controller_spec.rb +++ b/spec/controllers/physical_ticket_controller_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe PhysicalTicketController do +describe PhysicalTicketsController do let(:conference) { create(:conference) } let(:user) { create(:user) } let(:paid_ticket_purchase) { create(:ticket_purchase, conference: conference, user: user) } diff --git a/spec/factories/ticket_scanning.rb b/spec/factories/ticket_scanning.rb new file mode 100644 index 00000000..540d1fd0 --- /dev/null +++ b/spec/factories/ticket_scanning.rb @@ -0,0 +1,5 @@ +FactoryGirl.define do + factory :ticket_scanning do + physical_ticket + end +end diff --git a/spec/features/sponsor_spec.rb b/spec/features/sponsor_spec.rb index c6b5009e..b12ee90d 100644 --- a/spec/features/sponsor_spec.rb +++ b/spec/features/sponsor_spec.rb @@ -36,7 +36,14 @@ feature Sponsor do end # Remove sponsor - click_link 'Delete' + visit admin_conference_sponsors_path( + conference_id: conference.short_title + ) + within('table#sponsors') do + page.accept_confirm do + click_link 'Delete' + end + end expect(flash).to eq('Sponsor successfully deleted.') expect(page).to_not have_selector('table#sponsors') end diff --git a/spec/features/ticket_purchases_spec.rb b/spec/features/ticket_purchases_spec.rb index 958ae645..9cace981 100644 --- a/spec/features/ticket_purchases_spec.rb +++ b/spec/features/ticket_purchases_spec.rb @@ -3,7 +3,9 @@ require 'spec_helper' feature Registration do let!(:ticket) { create(:ticket) } let!(:free_ticket) { create(:ticket, price_cents: 0) } - let!(:conference) { create(:conference, title: 'ExampleCon', tickets: [ticket, free_ticket], registration_period: create(:registration_period, start_date: 3.days.ago)) } + let!(:first_registration_ticket) { create(:registration_ticket, price_cents: 0) } + let!(:second_registration_ticket) { create(:registration_ticket, price_cents: 0) } + let!(:conference) { create(:conference, title: 'ExampleCon', tickets: [ticket, free_ticket, first_registration_ticket, second_registration_ticket], registration_period: create(:registration_period, start_date: 3.days.ago)) } let!(:participant) { create(:user) } context 'as a participant' do @@ -101,11 +103,43 @@ feature Registration do click_button 'Continue' - expect(current_path).to eq(conference_physical_ticket_index_path(conference.short_title)) + expect(current_path).to eq(conference_physical_tickets_path(conference.short_title)) purchase = TicketPurchase.where(user_id: participant.id, ticket_id: free_ticket.id).first expect(purchase.quantity).to eq(5) expect(purchase.paid).to be true end + + scenario 'purchases more than one registration tickets of a single type' do + visit root_path + click_link 'Register' + + expect(current_path).to eq(new_conference_conference_registration_path(conference.short_title)) + click_button 'Register' + + fill_in "tickets__#{first_registration_ticket.id}", with: '5' + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + + click_button 'Continue' + + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + end + + scenario 'purchases one registration ticket of a different types' do + visit root_path + click_link 'Register' + + expect(current_path).to eq(new_conference_conference_registration_path(conference.short_title)) + click_button 'Register' + + fill_in "tickets__#{first_registration_ticket.id}", with: '1' + fill_in "tickets__#{second_registration_ticket.id}", with: '1' + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + + click_button 'Continue' + + expect(flash).to eq('Oops, something went wrong with your purchase! You cannot buy more than one registration tickets.') + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + end end context 'who is registered' do diff --git a/spec/features/tracks_spec.rb b/spec/features/tracks_spec.rb index 0819c650..f753abc2 100644 --- a/spec/features/tracks_spec.rb +++ b/spec/features/tracks_spec.rb @@ -36,16 +36,18 @@ feature Track do expected = expect do visit admin_conference_program_tracks_path(conference_id: conference.short_title) - - click_link 'Delete' + within('#tracks', visible: true) do + page.accept_confirm do + find_link('Delete').click + end + end end expected.to change { Track.count }.by(-1) expect(flash).to eq('Track successfully deleted.') - within('table#tracks') do - expect(page.has_content?(track.name)).to be false - expect(page.has_content?(track.description)).to be false - end + expect(page.has_css?('table#tracks')).to be false + expect(page.has_content?(track.name)).to be false + expect(page.has_content?(track.description)).to be false end scenario 'updates a track', feature: true, js: true do @@ -54,7 +56,9 @@ feature Track do expected = expect do visit admin_conference_program_tracks_path(conference_id: conference.short_title) - click_link 'Edit' + within('#tracks', visible: true) do + find_link('Edit').trigger('click') + end fill_in 'track_name', with: 'Distribution' fill_in 'track_short_name', with: 'Distribution' diff --git a/spec/models/ticket_purchase_spec.rb b/spec/models/ticket_purchase_spec.rb index 3ef9a861..bfca5efc 100644 --- a/spec/models/ticket_purchase_spec.rb +++ b/spec/models/ticket_purchase_spec.rb @@ -34,6 +34,22 @@ describe TicketPurchase do it 'is valid with a quantity greater than zero' do should allow_value(1).for(:quantity) end + + describe 'one_registration_ticket_per_user' do + let(:registration_ticket) { create(:registration_ticket) } + let(:ticket_purchase) { build(:ticket_purchase, ticket: registration_ticket, quantity: 1) } + + it 'it is valid, if quantity for registration tickets is less than or equal to one' do + expect(ticket_purchase.valid?).to eq true + end + + it 'it is not valid, if quantity for registration tickets is greater than to one' do + ticket_purchase.quantity = 4 + + expect(ticket_purchase.valid?).to eq false + expect(ticket_purchase.errors[:quantity]).to eq ['cannot be greater than one for registration tickets.'] + end + end end describe 'self#purchase' do diff --git a/spec/models/ticket_scanning_spec.rb b/spec/models/ticket_scanning_spec.rb new file mode 100644 index 00000000..3d978f4f --- /dev/null +++ b/spec/models/ticket_scanning_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe TicketScanning do + let(:conference) { create(:conference) } + let(:user) { create(:user) } + let(:registration) { create(:registration, conference: conference, user: user) } + let(:registration_ticket) { create(:registration_ticket, conference: conference) } + let(:paid_ticket_purchase) { create(:ticket_purchase, conference: conference, user: user, ticket: registration_ticket, quantity: 1) } + let(:physical_ticket) { create(:physical_ticket, ticket_purchase: paid_ticket_purchase) } + let(:ticket_scanning) { create(:ticket_scanning, physical_ticket: physical_ticket) } + + describe 'before_create' do + it 'marks user as present' do + expect(registration.attended).to eq(false) + ticket_scanning + registration.reload + expect(registration.attended).to eq(true) + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index fc56e829..d9283117 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -59,7 +59,7 @@ RSpec.configure do |config| Capybara.javascript_driver = :poltergeist Capybara.register_driver :poltergeist do |app| - Capybara::Poltergeist::Driver.new(app, phantomjs: Phantomjs.path, js_errors: false) + Capybara::Poltergeist::Driver.new(app, phantomjs: Phantomjs.path, js_errors: false, window_size: [1920, 1080]) end # Includes helpers and connect them to specific types of tests @@ -82,6 +82,14 @@ RSpec.configure do |config| # Types of tests (controller, feature, model) will # be inferred from subfolder name config.infer_spec_type_from_file_location! + + # Enable this if you like to see what you're debugging + # config.after(:example) do |example| + # if example.exception + # save_and_open_screenshot + # save_and_open_page + # end + # end end OmniAuth.config.test_mode = true