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/Gemfile b/Gemfile index 7f25aa46..22dc5f6e 100644 --- a/Gemfile +++ b/Gemfile @@ -200,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 c6b4faa8..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) @@ -290,8 +290,8 @@ GEM 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) @@ -609,6 +609,7 @@ DEPENDENCIES mini_magick money-rails mysql2 + nokogiri (>= 1.8.1) omniauth omniauth-facebook omniauth-github @@ -662,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/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/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 a53a3cf5..3eb8b68d 100644 --- a/app/controllers/ticket_purchases_controller.rb +++ b/app/controllers/ticket_purchases_controller.rb @@ -12,7 +12,7 @@ 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), diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index cf6eb6a8..ed7ce011 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -11,13 +11,13 @@ module Users def handle(provider) auth_hash = request.env['omniauth.auth'] - uid = auth_hash[:uid] + username = auth_hash.info.email.split('@')[0] openid = Openid.find_for_oauth(auth_hash) # Get or create openid # If openid exists and is associated with a user, sign in with associated user, # even if the email of the associated user and the email of the provided openid are different unless (user = openid.user) user = User.find_for_auth(auth_hash, current_user) # Get or create users - user.username = "#{uid}@#{provider}" if user.username.blank? + user.username = "#{username}@#{provider}" if user.username.blank? end begin 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 ccdb488d..231e1c11 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -47,7 +47,11 @@ 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 @@ -93,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/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/venues/_form.html.haml b/app/views/admin/venues/_form.html.haml index 7dd08a2c..6674305b 100644 --- a/app/views/admin/venues/_form.html.haml +++ b/app/views/admin/venues/_form.html.haml @@ -15,6 +15,12 @@ = semantic_form_for(@venue, url: admin_conference_venue_path(@conference.short_title)) do |f| = f.inputs :name, :website = f.input :description, input_html: { rows: 5, cols: 20, data: { provide: 'markdown-editable' } }, hint: markdown_hint + = f.label 'Venue Logo' + %br + - if @venue.picture? + = image_tag @venue.picture.thumb.url + = f.input :picture, label: false, hint: 'This will be displayed on the venue are of the splash page.' + = f.hidden_field :picture_cache = f.inputs :street, :postalcode, :city, :country, :latitude, :longitude = f.action :submit, as: :button, button_html: { 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 a924a4cf..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 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..9f34117f 100644 --- a/app/views/conferences/_venue_map.html.haml +++ b/app/views/conferences/_venue_map.html.haml @@ -1,17 +1,16 @@ #map{style: "height: 500px;" } -- popup = "