class ApplicationController < BaseController protect_from_forgery with: :exception, except: [:do_confirm, :js_error, :admin_update] before_filter :application_setup after_filter :capture_page_info helper_method :protect, :policies def default_url_options { host: "#{request.protocol}#{request.host_with_port}", trailing_slash: true } end def capture_page_info capture_response unless @user_type == :potential_bot || @user_type == :bot end def capture_response(response_code = nil) Request.create( request_id: request.uuid, session_id: session.id, application: :bikebike, response: (response_code || response.code || 0).to_i, data: { user: logged_in? ? current_user.id : nil, params: @original_params || params, remote_ip: request.remote_ip, request_method: request.method, url: request.original_url, user_agent: request.user_agent, language: request.env['HTTP_ACCEPT_LANGUAGE'], cookies: request.env['HTTP_COOKIE'], requested_with: request.env['HTTP_X_REQUESTED_WITH'] }) @error_reports.each { |report| report_on(report) } if @error_reports end def report_on(report) return if Rails.env.development? || Rails.env.test? send_mail(:error_report, report.signature) end def application_setup if request.user_agent =~ /Googlebot/ @user_type = :bot elsif request.url =~ /^.*\.php(\?.*)?$/ @user_type = :potential_bot else @user_type = :normal end # get the current conferences and set them globally status_hierarchy = { open: 1, pre: 2, closed: 3 } @conferences = Conference.where(is_featured: true, is_public: true).order("start_date DESC").sort do |a, b| status_hierarchy[(a.registration_status || :closed).to_sym] <=> status_hierarchy[(b.registration_status || :closed).to_sym] end # set the top conference @conference = @conferences.first # add some style sheets @stylesheets ||= Set.new # add the translations stylesheet if translating @stylesheets << params[:controller] if params[:controller] == 'translations' @_inline_scripts ||= Set.new @_inline_scripts << File.read(File.join(Rails.public_path, ActionController::Base.helpers.asset_path('main.js'))) ActionMailer::Base.default_url_options = { host: "#{request.protocol}#{request.host_with_port}" } @alt_lang_urls = {} I18n.backend.enabled_locales.sort.each do |locale| locale = locale.to_s @alt_lang_urls[locale] = view_context.url_for_locale(locale) # don't show the current locale end # give each environment a different icon and theme colour so that we can easily see where we are. See https://css-tricks.com/give-development-domain-different-favicon-production @favicon = Rails.env.development? || Rails.env.preview? ? "favicon-#{Rails.env.to_s}.ico" : 'favicon.ico' @theme_colour = Rails.env.preview? ? '#EF57B4' : (Rails.env.development? ? '#D89E59' : '#00ADEF') end def home if @conference.present? && @conference.id.present? @workshops = Workshop.where(conference_id: @conference.id) if @conference.workshop_schedule_published @event_dlg = true get_scheule_data(false) end end end def policy @is_policy_page = true end def confirmation_sent(user) template = 'login_confirmation_sent' @page_title ||= 'page_titles.403.Please_Check_Email' if (request.present? && request.referrer.present? && conference = /^\/conferences\/(\w+)\/register\/?$/.match(request.referrer.gsub(/^https?:\/\/.*?\//, '/'))) @this_conference = Conference.find_by!(slug: conference[1]) @banner_image = @this_conference.cover_url template = 'conferences/email_confirm' end do_403 template end def locale_not_enabled!(locale = nil) locale_not_available!(locale) end def locale_not_available locale_not_available!(params[:locale]) end def locale_not_available!(locale = nil) set_default_locale @original_params = params.clone params[:_original_action] = params[:action] params[:action] = 'error-locale-not-available' @page_title = 'page_titles.404.Locale_Not_Available' @main_title_vars = { vars: { language: view_context.language_name(locale) } } @main_title = 'error.locale_not_available.title' unless @alt_lang_urls.present? @alt_lang_urls = {} I18n.backend.enabled_locales.sort.each do |locale| locale = locale.to_s @alt_lang_urls[locale] = view_context.url_for_locale(locale) # don't show the current locale end end render 'application/locale_not_available', status: 404 end def on_error(report, exception = nil) @error_reports ||= [] @error_reports << report logger.info report.backtrace raise exception if exception.present? && Rails.env.development? end def js_error stack = params[:stack] || "#{params[:message]}\n\tat #{params[:url] || params[:location]}:#{params[:line]}:#{params[:col]}" requests = Request.where(session_id: session.id).order("created_at DESC") on_error( Report.create( request_id: requests.first.request_id, signature: params[:message], severity: :error, source: :javascript, backtrace: stack)) render json: {} end unless Rails.env.test? rescue_from StandardError do |exception| handle_exception exception # show the error page error_500 exception end end def handle_exception(exception) # remove memory location from anonymous classes so tat we have a common signature classMatcher = /#<(.*?):0x[0-9a-f]+>/ message = exception.message message.gsub!(classMatcher, '\1') while message =~ classMatcher stack = ([message] + exception.backtrace).join("\n ") on_error( Report.create( request_id: request.uuid, signature: message, severity: :error, source: :application, backtrace: stack), exception) end def i18n_exception(str, exception, locale, key) message = "#{exception.class.name}: #{exception.to_s}" stack = "#{message}\n #{caller.join("\n ")}" on_error( Report.create( request_id: request.uuid, signature: message, severity: :error, source: :i18n, backtrace: stack)) end def protect(&block) begin yield rescue Exception => exception handle_exception exception end end def contact @main_title = @page_title = 'page_titles.contact.Contact_Us' end def contact_send email_list = ['Godwin '] if params[:reason] == 'conference' && logged_in? @conference.conference_administrators.each do |administrator| email_list << administrator.user.named_email end end request_info = { 'remote_ip' => request.remote_ip, 'uuid' => request.uuid, 'original_url' => request.original_url, 'env' => Hash.new } request.env.each do |key, value| request_info['env'][key.to_s] = value.to_s end send_delayed_mail(:contact, current_user || params[:email], params[:subject], params[:message], email_list ) send_delayed_mail(:contact_details, current_user || params[:email], params[:subject], params[:message], request_info, params ) redirect_to contact_sent_path end def contact_sent @main_title = @page_title = 'page_titles.contact.Contact_Us' @sent = true render 'contact' end def confirm_user if params[:email] template = 'login_confirmation_sent' @page_title ||= 'page_titles.403.Please_Check_Email' if (request.present? && request.referrer.present? && conference = /^\/conferences\/(\w+)\/register\/?$/.match(request.referrer.gsub(/^https?:\/\/.*?\//, '/'))) @this_conference = Conference.find_by!(slug: conference[1]) @banner_image = @this_conference.cover_url template = 'conferences/email_confirm' end end if request.post? @banner_image ||= 'grafitti.jpg' @page_title ||= 'page_titles.403.Please_Login' do_403 template else do_404 end end def error_404(args = {}) @original_params = params.clone params[:_original_action] = params[:action] params[:action] = 'error-404' @page_title = 'page_titles.404.Page_Not_Found' @main_title = 'error.404.title' super(args) end def do_403(template = nil) @banner_image = 'grafitti.jpg' unless current_user @page_title = 'page_titles.403.Please_Login' end @template = template @page_title ||= 'page_titles.403.Access_Denied' @main_title ||= @page_title @original_params = params.clone params[:_original_action] = params[:action] params[:action] = 'error-403' super(template) end def error_500(exception = nil) @page_title = 'page_titles.500.An_Error_Occurred' @main_title = 'error.500.title' @original_params = params.clone params[:_original_action] = params[:action] params[:action] = 'error-500' @exception = exception super(exception) capture_response(500) end def on_translation_change(object, data, locale, translator_id) translator = User.find(translator_id) mailer = "#{object.class.table_name.singularize}_translated" if object.respond_to?(:get_translators) object.get_translators(data, locale).each do |id, user| if user.id != current_user.id && user.id != translator_id LinguaFranca.with_locale user.locale do send_delayed_mail(:send, mailer, object.id, data, locale, user.id, translator.id) end end end end end def on_translatable_content_change(object, data) mailer = "#{object.class.table_name.singularize}_original_content_changed" if object.respond_to?(:get_translators) object.get_translators(data).each do |id, user| if user.id != current_user.id LinguaFranca.with_locale user.locale do send_delayed_mail(:send, mailer, object.id, data, user.id, current_user.id) end end end end end def set_success_message(message, is_ajax = false) if is_ajax @success_message = message else flash[:success_message] = message end end def set_error_message(message, is_ajax = false) if is_ajax @error_message = message else flash[:error_message] = message end end def set_error(field, error, is_ajax = false) if is_ajax @errors ||= {} @errors[field] = error else flash[:errors] ||= {} flash[:errors][field] = error end end def set_flash_messages @errors = flash[:errors] || {} @warnings = flash[:warning] || [] @success_message = flash[:success_message] @error_message = flash[:error_message] || [] end def get_block_data conference = @this_conference || @conference @workshop_blocks = conference.workshop_blocks || [] @block_days = [] day = conference.start_date while day <= conference.end_date @block_days << day.wday day += 1.day end end def get_scheule_data(do_analyze = true) conference = @this_conference || @conference @meals = Hash[(conference.meals || {}).map{ |k, v| [k.to_i, v] }].sort.to_h @events = Event.where(conference_id: conference.id).order(start_time: :asc) @workshops = Workshop.where(conference_id: conference.id).order(start_time: :asc) @locations = {} get_block_data schedule = {} day_1 = conference.start_date.wday @workshop_blocks.each_with_index do |info, block| info['days'].each do |block_day| day_diff = block_day.to_i - day_1 day_diff += 7 if day_diff < 0 day = (conference.start_date + day_diff.days).to_date time = info['time'].to_f schedule[day] ||= { times: {}, locations: {} } schedule[day][:times][time] ||= {} schedule[day][:times][time][:type] = :workshop schedule[day][:times][time][:length] = info['length'].to_f schedule[day][:times][time][:item] = { block: block, workshops: {} } end end @workshops.each do |workshop| if workshop.block.present? block = @workshop_blocks[workshop.block['block'].to_i] day_diff = workshop.block['day'].to_i - day_1 day_diff += 7 if day_diff < 0 day = (conference.start_date + day_diff.days).to_date if block.present? && schedule[day].present? && schedule[day][:times].present? && schedule[day][:times][block['time'].to_f].present? schedule[day][:times][block['time'].to_f][:item][:workshops][workshop.event_location_id] = { workshop: workshop, status: { errors: [], warnings: [], conflict_score: nil } } schedule[day][:locations][workshop.event_location_id] ||= workshop.event_location if workshop.event_location.present? end end end @meals.each do |time, meal| day = meal['day'].to_date time = meal['time'].to_f schedule[day] ||= {} schedule[day][:times] ||= {} schedule[day][:times][time] ||= {} schedule[day][:times][time][:type] = :meal schedule[day][:times][time][:length] = (meal['length'] || 1.0).to_f schedule[day][:times][time][:item] = meal end @events.each do |event| if event.present? && event.start_time.present? && event.end_time.present? day = event.start_time.midnight.to_date time = event.start_time.hour.to_f + (event.start_time.min / 60.0) schedule[day] ||= {} schedule[day][:times] ||= {} schedule[day][:times][time] ||= {} schedule[day][:times][time][:type] = :event schedule[day][:times][time][:length] = (event.end_time - event.start_time) / 3600.0 schedule[day][:times][time][:item] = event end end schedule = schedule.sort.to_h schedule.each do |day, data| schedule[day][:times] = data[:times].sort.to_h end schedule.each do |day, data| last_event = nil data[:times].each do |time, time_data| if last_event.present? schedule[day][:times][last_event][:next_event] = time end last_event = time end schedule[day][:num_locations] = (data[:locations] || []).size end schedule.deep_dup.each do |day, data| data[:times].each do |time, time_data| if time_data[:next_event].present? || time_data[:length] > conference.schedule_interval span = conference.schedule_interval length = time_data[:next_event].present? ? time_data[:next_event] - time : time_data[:length] while span < length schedule[day][:times][time + span] ||= { type: (span >= time_data[:length] ? :empty : :nil), length: conference.schedule_interval } span += conference.schedule_interval end end end end schedule.each do |day, data| schedule[day][:times] = data[:times].sort.to_h schedule[day][:locations] ||= {} # sort the locations by name schedule[day][:locations] = schedule[day][:locations].sort_by { |event_id, event| event.present? ? event.title.downcase : '' }.to_h if do_analyze data[:times].each do |time, time_data| if time_data[:type] == :workshop && time_data[:item].present? && time_data[:item][:workshops].present? ids = time_data[:item][:workshops].keys (0..ids.length).each do |i| if time_data[:item][:workshops][ids[i]].present? workshop_i = time_data[:item][:workshops][ids[i]][:workshop] conflicts = {} (i+1..ids.length).each do |j| workshop_j = time_data[:item][:workshops][ids[j]].present? ? time_data[:item][:workshops][ids[j]][:workshop] : nil if workshop_i.present? && workshop_j.present? workshop_i.active_facilitators.each do |facilitator_i| workshop_j.active_facilitators.each do |facilitator_j| if facilitator_i.id == facilitator_j.id schedule[day][:times][time][:status] ||= {} schedule[day][:times][time][:item][:workshops][ids[j]][:status][:errors] << { name: :common_facilitator, facilitator: facilitator_i, workshop: workshop_i, i18nVars: { facilitator_name: facilitator_i.name, workshop_title: workshop_i.title } } end end end end end location = workshop_i.event_location || EventLocation.new needs = JSON.parse(workshop_i.needs || '[]').map &:to_sym amenities = JSON.parse(location.amenities || '[]').map &:to_sym needs.each do |need| schedule[day][:times][time][:item][:workshops][ids[i]][:status][:errors] << { name: :need_not_available, need: need, location: location, workshop: workshop_i, i18nVars: { need: I18n.t("workshop.options.amenity.#{need}"), location: location.title, workshop_title: workshop_i.title } } unless amenities.include? need end # collect common interested users interests = [] (0..ids.length).each do |j| workshop_j = time_data[:item][:workshops][ids[j]].present? ? time_data[:item][:workshops][ids[j]][:workshop] : nil if workshop_i.present? && workshop_j.present? && workshop_i.id != workshop_j.id interests = interests | workshop_j.interested.map { | u | u.user_id } end end schedule[day][:times][time][:item][:workshops][ids[i]][:status][:conflict_score] = (interests & (workshop_i.interested.map { | u | u.user_id })).length end end end end end end @schedule = {} schedule.sort.to_h.each do |day, data| @schedule[day] = [] division = 0 locations = nil @schedule[day][division] = {} @schedule[day][division][:times] = {} data[:times].each do |time, time_data| if time_data[:type] == :workshop && time_data[:item].present? && time_data[:item][:workshops].present? if !locations.nil? && ((locations.keys - time_data[:item][:workshops].keys) | (time_data[:item][:workshops].keys - locations.keys)).length > 0 @schedule[day][division][:locations] = locations.deep_dup @schedule[day][division][:locations][0] = :add if do_analyze || locations.empty? locations = data[:locations].select { |id, l| time_data[:item][:workshops][id].present? } division += 1 @schedule[day][division] = {} @schedule[day][division][:times] = {} else locations = data[:locations].select { |id, l| time_data[:item][:workshops][id].present? } end end # last_time_data = time_data @schedule[day][division][:times][time] = time_data end locations ||= data[:locations] @schedule[day][division][:locations] = locations @schedule[day][division][:locations][0] = :add if do_analyze || locations.empty? @schedule[day][division][:num_locations] = locations.length end end protected def set_conference @this_conference = Conference.find_by!(slug: params[:slug]) end def set_conference_registration @registration = logged_in? ? ConferenceRegistration.find_by(user_id: current_user.id, conference_id: @this_conference.id) : nil end def set_conference_registration! set_conference_registration raise ActiveRecord::PremissionDenied unless @registration.present? end def ensure_registration_is_complete! set_conference_registration! raise ActiveRecord::PremissionDenied unless @registration.registered? end def set_or_create_conference_registration set_conference_registration return @registration if @registration.present? @registration ||= ConferenceRegistration.new( conference: @this_conference, user_id: current_user.id, steps_completed: [] ) last_registration_data = ConferenceRegistration.where(user_id: current_user.id).order(created_at: :desc).limit(1).first if last_registration_data.present? if last_registration_data['languages'].present? && current_user.languages.blank? current_user.languages = JSON.parse(last_registration_data['languages']) current_user.save! end @registration.city = last_registration_data.city if last_registration_data.city.present? end end # Set empty HTML values to nil, sometimes we will get values such as '

' in rich edits, this will help to make sure they are actually empty def html_value(value) return value.present? && ActionView::Base.full_sanitizer.sanitize(value).strip.present? ? value : nil end # send the confirmation email and make sure it get sent as quickly as possible def send_confirmation(confirmation) send_mail(:email_confirmation, confirmation.id) end def send_delayed_mail(*args) if Rails.env.preview? || Rails.env.production? UserMailer.delay(queue: Rails.env.to_s).send(*args) else UserMailer.send(*args).deliver_now end end def send_mail(*args) UserMailer.send(*args).deliver_now end def policies [ :commitment, :respect, :empowerment, :accessible, :peaceful, :spaces, :hearing, :intent, :open_minds, :learning ] end end