diff --git a/.envrc b/.envrc index fd1fd93b..33a38f1b 100644 --- a/.envrc +++ b/.envrc @@ -72,5 +72,7 @@ export RUBY_CFLAGS="$CFLAGS" [[ -f .envrc.local ]] && source .envrc.local - +if [[ $(uname -s) == "Darwin" ]]; then + export BULLET_ENABLED=true +fi diff --git a/.rubocop.yml b/.rubocop.yml index d2e59faf..d0ecd843 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -17,7 +17,7 @@ RSpecRails/InferredSpecType: Enabled: false Metrics/ClassLength: - Max: 300 + Enabled: false Metrics/ModuleLength: Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index ab59876a..a6542f29 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2024-05-20 21:02:26 UTC using RuboCop version 1.63.5. +# on 2024-08-02 21:17:29 UTC using RuboCop version 1.65.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -16,11 +16,11 @@ Lint/UnmodifiedReduceAccumulator: Exclude: - 'app/helpers/shifts_helper.rb' -# Offense count: 6 +# Offense count: 7 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode. # AllowedMethods: refine Metrics/BlockLength: - Max: 47 + Max: 63 # Offense count: 12 # Configuration parameters: AllowedMethods, AllowedPatterns. @@ -30,7 +30,7 @@ Metrics/CyclomaticComplexity: # Offense count: 50 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. Metrics/MethodLength: - Max: 60 + Max: 46 # Offense count: 10 # Configuration parameters: AllowedMethods, AllowedPatterns. @@ -44,7 +44,7 @@ Naming/MethodParameterName: Exclude: - 'spec/support/time_extensions.rb' -# Offense count: 22 +# Offense count: 26 # Configuration parameters: Prefixes, AllowedPatterns. # Prefixes: when, with, without RSpec/ContextWording: @@ -59,10 +59,14 @@ RSpec/DescribeClass: Exclude: - 'spec/lib/fnf/music_submissions_spec.rb' -# Offense count: 29 +# Offense count: 1 +RSpec/MultipleExpectations: + Max: 3 + +# Offense count: 23 # Configuration parameters: AllowSubject. RSpec/MultipleMemoizedHelpers: - Max: 11 + Max: 7 # Offense count: 2 # Configuration parameters: EnforcedStyle, IgnoreSharedExamples. @@ -72,7 +76,7 @@ RSpec/NamedSubject: - 'spec/lib/fnf/csv_reader_spec.rb' - 'spec/models/ticket_request_spec.rb' -# Offense count: 86 +# Offense count: 84 # Configuration parameters: AllowedGroups. RSpec/NestedGroups: Max: 6 @@ -91,7 +95,7 @@ RSpec/RepeatedExampleGroupBody: Exclude: - 'spec/models/event_spec.rb' -# Offense count: 9 +# Offense count: 12 # Configuration parameters: Database, Include. # SupportedDatabases: mysql, postgresql # Include: db/**/*.rb @@ -125,7 +129,7 @@ Rails/HelperInstanceVariable: Exclude: - 'app/helpers/shifts_helper.rb' -# Offense count: 23 +# Offense count: 24 Rails/I18nLocaleTexts: Exclude: - 'app/controllers/events_controller.rb' @@ -149,7 +153,7 @@ Rails/NotNullColumn: - 'db/migrate/20130226221916_add_user_to_ticket_request.rb' - 'db/migrate/20130311213508_add_event_id_to_ticket_request.rb' -# Offense count: 9 +# Offense count: 22 # Configuration parameters: Include. # Include: db/**/*.rb Rails/ReversibleMigration: @@ -183,21 +187,13 @@ Rails/ThreeStateBooleanColumn: - 'db/migrate/20140616030905_change_camping_type_on_ticket_requests.rb' - 'db/migrate/20150609064608_add_agrees_terms_to_ticket_requests.rb' -# Offense count: 2 -# Configuration parameters: Include. -# Include: app/models/**/*.rb -Rails/UniqueValidationWithoutIndex: - Exclude: - - 'app/models/payment.rb' - - 'app/models/site_admin.rb' - # Offense count: 2 # This cop supports safe autocorrection (--autocorrect). Rake/Desc: Exclude: - 'Rakefile' -# Offense count: 87 +# Offense count: 94 # Configuration parameters: AllowedConstants. Style/Documentation: Enabled: false @@ -210,18 +206,16 @@ Style/FrozenStringLiteralComment: Exclude: - 'app/models/application_record.rb' -# Offense count: 6 +# Offense count: 2 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: MinBodyLength, AllowConsecutiveConditionals. Style/GuardClause: Exclude: - 'app/controllers/application_controller.rb' - - 'app/controllers/ticket_requests_controller.rb' - - 'app/models/event.rb' -# Offense count: 27 +# Offense count: 34 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. # URISchemes: http, https Layout/LineLength: - Max: 252 + Max: 154 diff --git a/.version b/.version index 1892b926..80e78df6 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -1.3.2 +1.3.5 diff --git a/Gemfile b/Gemfile index aa9f3af2..3a28319b 100644 --- a/Gemfile +++ b/Gemfile @@ -101,6 +101,7 @@ end group :development do gem 'asciidoctor' + gem 'bullet', require: false # gem 'rack-mini-profiler' gem 'better_errors' gem 'binding_of_caller' diff --git a/Gemfile.lock b/Gemfile.lock index 1e6836a8..5d95d76c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -105,6 +105,9 @@ GEM brakeman (6.1.2) racc builder (3.3.0) + bullet (7.2.0) + activesupport (>= 3.0.0) + uniform_notifier (~> 1.11) capistrano (3.19.1) airbrussh (>= 1.0.0) i18n @@ -436,6 +439,7 @@ GEM concurrent-ruby (~> 1.0) unaccent (0.4.0) unicode-display_width (2.5.0) + uniform_notifier (1.16.0) ventable (1.3.1) activesupport (>= 5) warden (1.2.9) @@ -474,6 +478,7 @@ DEPENDENCIES binding_of_caller bootsnap brakeman + bullet capistrano capistrano-faster-assets capistrano-rails diff --git a/Makefile b/Makefile index 13c544c2..50bdef97 100755 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ reset: ## Complete reset of the databases and runs the rspec and rubocop @printf "\n$(bg_purple) 👉 $(purple)î‚°$(clear) $(yellow)Creating local databases...$(clear)\n" @bundle exec rake db:create:all @printf "\n$(bg_purple) 👉 $(purple)î‚°$(clear) $(yellow)Migrating development...$(clear)\n" - @bundle exec rake db:migrate + @bundle exec rake db:migrate:with_data @printf "\n$(bg_purple) 👉 $(purple)î‚°$(clear) $(yellow)Seeding development...$(clear)\n" @bundle exec rake db:seed @printf "\n$(bg_purple) 👉 $(purple)î‚°$(clear) $(yellow)Cloning to test DB...$(clear)\n" @@ -84,7 +84,7 @@ db-create: node_modules ## Create if necessary, migrate and seed the database @printf "\n$(bg_purple) 👉 $(purple)î‚°$(clear) $(yellow)Creating Database: [$(DEV_DB)]$(clear)\n" @bin/rails db:create @printf "\n$(bg_purple) 👉 $(purple)î‚°$(clear) $(yellow)Migrating Databases: [$(DEV_DB)]$(clear)\n" - @bin/rails db:migrate + @bin/rails db:migrate:with_data @printf "\n$(bg_purple) 👉 $(purple)î‚°$(clear) $(yellow)Seeding dev database: [$(DEV_DB)]$(clear)\n" @bin/rails db:seed @@ -109,7 +109,7 @@ dev: gems node_modules db-create foreman ## Start the development envi ci: ## Run all tests and linters as if on CI - bin/rails db:migrate + bin/rails db:migrate:with_data bin/rails db:test:prepare bundle exec rspec bundle exec rubocop diff --git a/Procfile.dev b/Procfile.dev index 417662d7..2fb4a7c7 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,5 +1,5 @@ # vim: ft=yaml -web: bin/rails server -p 8080 +web: BULLET_ENABLED=true bin/rails server -p 8080 js: yarn watch:js css: yarn watch:css browser: sleep 4 && open http://tickets-local.fnf.org:8080/ && while true; do sleep 100; echo .; done diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5d19096d..51566271 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -33,13 +33,22 @@ def stripe_publishable_api_key def set_event event_id = permitted_params[:event_id].to_i - Rails.logger.debug { "#set_event() => event_id = #{event_id}, params[:event_id] => #{permitted_params[:event_id]}" } + event_slug = permitted_params[:event_id].delete("#{event_id}-") - @event = Event.where(id: event_id).first - if @event.nil? - flash.now[:error] = "Event with id #{event_id} was not found." + Rails.logger.debug { "#set_event() => event_id = #{event_id}, event_slug = #{event_slug} params[:event_id] => #{permitted_params[:event_id]}" } + + event_not_found = lambda do |eid, flash| + flash.now[:error] = "Event with id #{eid} was not found." raise ArgumentError, flash.now[:error] end + + @event = Event.where(id: event_id).first + + if @event.slug != event_slug + Rails.logger.warn("Event slug mismatch: [#{event_slug}] != [#{@event&.slug}]") + end + + event_not_found[event_id, flash] if @event.nil? end def ticket_request_id diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index e18887b2..95c85eec 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -10,9 +10,9 @@ class EventsController < ApplicationController def index if current_user.site_admin? - @events = Event.order(start_time: :desc) + @events = Event.includes(:ticket_requests).order(start_time: :desc) elsif current_user.event_admin? - @events = current_user.events_administrated.order(:start_time) + @events = current_user.events_administrated.includes(:ticket_requests).order(:start_time) else redirect_to :root end @@ -44,10 +44,6 @@ def create TimeHelper.normalize_time_attributes(create_params) @event = Event.new(create_params) - # if create_params[:event_addons_attributes].present? - # @event.build_event_addons_from_params(create_params[:event_addons_attributes]) - # end - Rails.logger.info("event_create: created event: #{@event.id} event_addons: #{@event.event_addons.inspect}") if @event.save diff --git a/app/models/event.rb b/app/models/event.rb index 3ab3d7cd..f51b3c0f 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -37,8 +37,6 @@ class Event < ApplicationRecord MAX_NAME_LENGTH = 100 - GUEST_LIST_FINAL_WITHIN = 2.days - attr_accessible :name, :start_time, :end_time, :adult_ticket_price, :kid_ticket_price, :max_adult_tickets_per_request, :max_kid_tickets_per_request, :photo, :photo_cache, :tickets_require_approval, :require_mailing_address, diff --git a/app/models/ticket_request.rb b/app/models/ticket_request.rb index 2324e40d..b74ce651 100644 --- a/app/models/ticket_request.rb +++ b/app/models/ticket_request.rb @@ -101,11 +101,11 @@ def csv_columns include ActiveModel::Validations::Callbacks STATUSES = [ - STATUS_PENDING = 'P', + STATUS_PENDING = 'P', STATUS_AWAITING_PAYMENT = 'A', - STATUS_DECLINED = 'D', - STATUS_COMPLETED = 'C', - STATUS_REFUNDED = 'R' + STATUS_DECLINED = 'D', + STATUS_COMPLETED = 'C', + STATUS_REFUNDED = 'R' ].freeze STATUS_NAMES = { @@ -133,7 +133,7 @@ def csv_columns }.freeze belongs_to :user, inverse_of: :ticket_requests - belongs_to :event, inverse_of: :ticket_requests + belongs_to :event, inverse_of: :ticket_requests, touch: true has_one :payment, inverse_of: :ticket_request, dependent: :destroy @@ -274,11 +274,7 @@ def refund # calculate the total price for this ticket request def price - return special_price if special_price - - total = tickets_price - total += calculate_addons_price - total + @price ||= special_price.presence || (tickets_price + calculate_addons_price) end def tickets_price @@ -288,14 +284,17 @@ def tickets_price end def calculate_addons_price - return 0 unless ticket_request_event_addons? - - tr_addons_price = 0 - ticket_request_event_addons.each do |tr_event_addon| - tr_addons_price += tr_event_addon.calculate_cost - end + @calculate_addons_price ||= + if ticket_request_event_addons? + tr_addons_price = 0 + ticket_request_event_addons.each do |tr_event_addon| + tr_addons_price += tr_event_addon.calculate_cost + end - tr_addons_price + tr_addons_price + else + 0 + end end def cost @@ -360,27 +359,28 @@ def build_ticket_request_event_addons_from_params(build_params) end def active_addons - ticket_request_event_addons.where('quantity > ?', 0) + @active_addons ||= ticket_request_event_addons.where('quantity > ?', 0) end def active_addons_sum - active_addons.sum(&:quantity) + @active_addons_sum ||= active_addons.sum(&:quantity) end def active_sorted_addons - active_addons.sort_by { |e| [e.category, e.price, e.name] } + @active_sorted_addons ||= active_addons.sort_by { |e| [e.category, e.price, e.name] } end def active_addon_pass_sum - active_addon_sum_quantity_by_category(Addon::CATEGORY_PASS) + @active_addon_pass_sum ||= active_addon_sum_quantity_by_category(Addon::CATEGORY_PASS) end def active_addon_camp_sum - active_addon_sum_quantity_by_category(Addon::CATEGORY_CAMP) + @active_addon_camp_sum ||= active_addon_sum_quantity_by_category(Addon::CATEGORY_CAMP) end def active_addon_sum_quantity_by_category(category) - active_addons.select { |addon| addon.category == category }.sum(&:quantity) + @active_addon_sum_quantity_by_category ||= {} + @active_addon_sum_quantity_by_category[category] ||= active_addons.select { |addon| addon.category == category }.sum(&:quantity) end def ticket_request_event_addons? diff --git a/app/models/ticket_request_event_addon.rb b/app/models/ticket_request_event_addon.rb index 1fcaee00..f7ee5f72 100644 --- a/app/models/ticket_request_event_addon.rb +++ b/app/models/ticket_request_event_addon.rb @@ -52,6 +52,6 @@ def purchase_category(category) end def name_category_price_each - "#{name} #{purchase_category(category)} @ #{price} each" + "#{name} #{purchase_category(category)} @ $#{price} each" end end diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml index ee01a040..9eb9b2c0 100644 --- a/app/views/devise/passwords/edit.html.haml +++ b/app/views/devise/passwords/edit.html.haml @@ -1,21 +1,19 @@ -%h2 Change your password +%h3 Change your password = form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }, data: { turbo: false } ) do |f| = render "devise/shared/error_messages", resource: resource = f.hidden_field :reset_password_token .field - %p= f.label :password, "New password" - - if @minimum_password_length - %p - %em - (#{@minimum_password_length} characters minimum) + %br + %strong= "New Password" + %small.fst-italic.text-nowrap + = " (#{@minimum_password_length} characters minimum)" %p= f.password_field :password, autofocus: true, autocomplete: "new-password" .field - %p= f.label :password_confirmation, "Confirm new password" - - if @minimum_password_length - %p - %em - (#{@minimum_password_length} characters minimum) - %p= f.password_field :password_confirmation, autocomplete: "new-password" + %br + %strong= "New Password Confirmation" + %small.fst-italic.text-nowrap + = " (#{@minimum_password_length} characters minimum)" + %p= f.password_field :password_confirmation, autocomplete: "new-password", required: true .actions = f.submit "Change my password", class: 'btn btn-primary btn-large' = render "devise/shared/links" diff --git a/app/views/devise/registrations/_change_password.html.haml b/app/views/devise/registrations/_change_password.html.haml index 482e1f2d..e62e89b3 100644 --- a/app/views/devise/registrations/_change_password.html.haml +++ b/app/views/devise/registrations/_change_password.html.haml @@ -2,27 +2,34 @@ .col-12 .vertical-20 - if existing - %small.nowrap NOTE: leave these fields blank if you don't want to change your password. + %strong= "Change Password" + %br + %small.fst-italic.nowrap Leave blank if you don't want to change your password. - else %h5 Please enter and confirm your new password. - NOTE: Passwords must be at least 6 characters long. + %strong.fst-italic.text-nowrap Passwords must be at least 6 characters long. .row .col-5 = f.label :password do - %strong= "Password:" + - if existing + %strong= "New Password:" + - else + %strong= "Password:" - if @minimum_password_length %br - %small.text-nowrap - NOTE: - = "#{@minimum_password_length} characters minimum" - = f.password_field :password, autocomplete: "new-password" + %normal.fst-italic.nowrap (#{@minimum_password_length} characters minimum) + = f.password_field :password, autocomplete: "new-password", min_length: @minimum_password_length .col-7 = f.label :password_confirmation do - %strong= "Password Confirmation:" + - if existing + %strong= "New Password Confirmation:" + - else + %strong= "Password Confirmation:" - if @minimum_password_length %br + %normal.fst-italic.nowrap (#{@minimum_password_length} characters minimum) %br - %p= f.password_field :password_confirmation, autocomplete: "new-password" + %p= f.password_field :password_confirmation, autocomplete: "new-password", min_length: @minimum_password_length diff --git a/app/views/devise/shared/_register.html.haml b/app/views/devise/shared/_register.html.haml index c34f7a79..44c48640 100644 --- a/app/views/devise/shared/_register.html.haml +++ b/app/views/devise/shared/_register.html.haml @@ -1,10 +1,11 @@ -%h2 Register New Account - http_method = existing ? :put : :post = form_for(resource, as: resource_name, url: user_registration_path, html: { method: http_method }, data: { turbo: false } ) do |f| = hidden_field_tag :authenticity_token, form_authenticity_token = render "devise/shared/error_messages", resource: resource + - unless existing + %h2 Register New Account .container-fluid .row @@ -24,18 +25,18 @@ - if defined?(redirect_to) = hidden_field_tag :redirect_to, redirect_to + %br + %hr = render partial: 'devise/registrations/change_password', locals: { existing: existing, f: f } %br %hr - if existing .row .col-md-6.col-sm-12 - %p.lead - We need your current password to confirm your changes + %strong= "Your current password is required make changes to your account" %strong = f.label :current_password - %br - = f.password_field :current_password, autocomplete: "current-password" + = f.password_field :current_password, autocomplete: "current-password", required: true .row @@ -44,12 +45,11 @@ = f.submit "Update", class: 'btn btn-primary btn-large w-1' - unless existing - .row .col-12 .actions.btn-group-md = f.submit "Register", class: 'btn btn-primary btn-lg' - - if controller_name != 'ticket_requests' - = link_to "Go Back ↩".html_safe, :back, class: 'btn btn-warning btn-md' - %p= link_to "Forgot your password?", new_password_path(resource_name) + + - if controller_name != 'ticket_requests' + = link_to "Go Back ↩".html_safe, :back, class: 'btn btn-warning btn-md' diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml new file mode 100644 index 00000000..a1c19497 --- /dev/null +++ b/app/views/events/_event.html.haml @@ -0,0 +1,21 @@ +- status_widget = event.status + +%tr + %td.p-1.align-content-center + .span.me-1 + = link_to event, class: "text-nowrap btn btn-#{status_widget.css_class} btn-sm btn-event-name" do + = event.name.truncate(35, separator: /\s/) + %td.p-1.optional.align-content-center.mx-4.text-nowrap + %span{class: "text-#{status_widget.css_class}"}= status_widget.name + %td.p-1.text-end.optional.align-content-center + = number_with_delimiter(event.ticket_requests.count) + %td.p-1.text-end.align-content-center + = number_with_delimiter(event.ticket_requests.sum(&:guest_count)) + %td.p-1.text-end.optional.align-content-center + = number_to_currency(event.ticket_requests.completed.sum(&:cost)) + %td.p-1.text-end.optional.align-content-center + = number_to_currency(event.ticket_requests.awaiting_payment.sum(&:cost)) + %td.text-nowrap.small.align-content-center.event-dates.optional-small + = TimeHelper.for_display(event.start_time.localtime) + %br + = TimeHelper.for_display(event.end_time.localtime) diff --git a/app/views/events/index.html.haml b/app/views/events/index.html.haml index aea54f4c..57fb6357 100644 --- a/app/views/events/index.html.haml +++ b/app/views/events/index.html.haml @@ -19,28 +19,7 @@ %th.bg-body-secondary.text-end.optional Awaiting Payment %th.bg-body-secondary.optional-small Start Time / End Time %tbody - - @events.each do |event| - - status_widget = event.status - - %tr - %td.p-1.align-content-center - .span.me-1 - = link_to event, class: "text-nowrap btn btn-#{status_widget.css_class} btn-sm btn-event-name" do - = event.name.truncate(35, separator: /\s/) - %td.p-1.optional.align-content-center.mx-4.text-nowrap - %span{class: "text-#{status_widget.css_class}"}= status_widget.name - %td.p-1.text-end.optional.align-content-center - = number_with_delimiter(event.ticket_requests.count) - %td.p-1.text-end.align-content-center - = number_with_delimiter(event.ticket_requests.sum(&:guest_count)) - %td.p-1.text-end.optional.align-content-center - = number_to_currency(event.ticket_requests.completed.sum(&:cost)) - %td.p-1.text-end.optional.align-content-center - = number_to_currency(event.ticket_requests.awaiting_payment.sum(&:cost)) - %td.text-nowrap.small.align-content-center.event-dates.optional-small - = TimeHelper.for_display(event.start_time.localtime) - %br - = TimeHelper.for_display(event.end_time.localtime) + = render partial: 'events/event', collection: @events, cached: true .card-footer.bg-dark-subtle = link_to new_event_path, class: 'btn btn-warning ' do diff --git a/app/views/ticket_requests/_form.html.haml b/app/views/ticket_requests/_form.html.haml index 141071ab..66cd1918 100644 --- a/app/views/ticket_requests/_form.html.haml +++ b/app/views/ticket_requests/_form.html.haml @@ -7,7 +7,7 @@ - if signed_in? && @user.present? %h4 Ticket Request for #{@user.name} - else - %h5 Please sign-in or register to request tickets. + %h5 Please log-in or register to request tickets .card-body = render 'shared/form_errors', resource: @ticket_request @@ -49,25 +49,18 @@ .row .col-lg-6.col-xl-6.col-md-12.col-sm-12 - - list_finalized = (@event.start_time - Time.current) < ::Event::GUEST_LIST_FINAL_WITHIN - - if list_finalized - %span.text-error - Guest list has already been finalized. If you need to update your guests, please email - = mail_to 'tickets@fnf.org' - %br - - else - %h4 Adult Guests - %h5 Examples: - %ul - %li DJ Carl Cox (as himself) <carl@carlcox.com> - %li John Digweed <digweed@bedrock-records.com> + %h4 Adult Guests + %h5 Examples: + %ul + %li DJ Carl Cox (as himself) <carl@carlcox.com> + %li John Digweed <digweed@bedrock-records.com> - - total_guests = @ticket_request.guest_count - - adult_guests = @ticket_request.adults - - adult_guests.times do |guest_id| - - default_value = guest_id == 0 ? @ticket_request.user.name_and_email : '' - = f.label "Guest #{guest_id + 1}" - = f.text_field :guest_list, readonly: list_finalized, multiple: true, value: Array(@ticket_request.guests[0...adult_guests])[guest_id] || default_value, style: 'width: 80%' + - total_guests = @ticket_request.guest_count + - adult_guests = @ticket_request.adults + - adult_guests.times do |guest_id| + - default_value = guest_id == 0 ? @ticket_request.user.name_and_email : '' + = f.label "Guest #{guest_id + 1}" + = f.text_field :guest_list, multiple: true, value: Array(@ticket_request.guests[0...adult_guests])[guest_id] || default_value, style: 'width: 80%' - if @ticket_request.kids.positive? .col-lg-6.col-xl-6.col-md-12.col-sm-12 @@ -80,7 +73,7 @@ - kid_guests = @ticket_request.kids - kid_guests.times do |guest_id| = f.label "Kid Guest #{guest_id + 1}" - = f.text_field :guest_list, readonly: list_finalized, multiple: true, value: Array(@ticket_request.guests[(adult_guests)..total_guests])[guest_id], style: 'width: 80%' + = f.text_field :guest_list, multiple: true, value: Array(@ticket_request.guests[(adult_guests)..total_guests])[guest_id], style: 'width: 80%' - else -# on create, set user into guests list = f.hidden_field :guests, value: @user.name_and_email diff --git a/config/application.rb b/config/application.rb index 9026fa7f..82f5a436 100644 --- a/config/application.rb +++ b/config/application.rb @@ -86,5 +86,7 @@ class Application < Rails::Application min_threads: 1, max_threads: 3, idletime: 30.seconds + + config.cache_store = :mem_cache_store, '127.0.0.1:11211', { pool: { size: 10 } } end end diff --git a/config/environments/development.rb b/config/environments/development.rb index 1ae44cb8..f8072c08 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -2,6 +2,9 @@ require 'active_support/core_ext/integer/time' +BULLET_ENABLED = ENV.fetch('BULLET_ENABLED', false) +require 'bullet' if BULLET_ENABLED + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -24,8 +27,6 @@ if Rails.root.join('tmp/caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true - - config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false @@ -115,4 +116,25 @@ secret_api_key: Rails.application.credentials.development.dig(:stripe, :secret_api_key), publishable_api_key: Rails.application.credentials.development.dig(:stripe, :publishable_api_key) } + + if BULLET_ENABLED + config.after_initialize do + Bullet.enable = true + Bullet.alert = true + Bullet.bullet_logger = true + Bullet.console = true + Bullet.add_footer = true + + Bullet.skip_html_injection = false + + Bullet.sentry = false + Bullet.rails_logger = true + Bullet.honeybadger = false + Bullet.bugsnag = false + Bullet.appsignal = false + Bullet.airbrake = false + Bullet.rollbar = false + # Bullet.slack = { webhook_url: 'http://some.slack.url', channel: '#default', username: 'notifier' } + end + end end diff --git a/config/environments/production.rb b/config/environments/production.rb index e3b83e2e..0f6022dc 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -70,7 +70,7 @@ config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info') # Use a different cache store in production. - config.cache_store = :memory_store + # config.cache_store = :memory_store # Use a real queuing backend for Active Job (and separate queues per environment). # config.active_job.queue_adapter = :resque diff --git a/config/routes.rb b/config/routes.rb index cbf1e0be..2ed7b2e5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -# rubocop: disable Metrics/BlockLength Rails.application.routes.draw do root 'home#index' # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html @@ -73,4 +72,3 @@ get '/tickets/request/:event_id', to: 'ticket_requests#new', as: :tickets_request get '/attend/:event_id', to: 'ticket_requests#new', as: :attend_event end -# rubocop: enable Metrics/BlockLength diff --git a/db/data/20240730034256_default_addons.rb b/db/data/20240730034256_default_addons.rb index 7bff8da2..f4e90376 100644 --- a/db/data/20240730034256_default_addons.rb +++ b/db/data/20240730034256_default_addons.rb @@ -6,7 +6,7 @@ def up Addon.create category: Addon::CATEGORY_PASS, name: 'Late Departure', default_price: 30 Addon.create category: Addon::CATEGORY_CAMP, name: 'Car Camping', default_price: 50 Addon.create category: Addon::CATEGORY_CAMP, name: 'RV under 20ft', default_price: 100 - Addon.create category: Addon::CATEGORY_CAMP, name: 'RV under 25ft', default_price: 125 + Addon.create category: Addon::CATEGORY_CAMP, name: 'RV 20ft to 25ft', default_price: 125 Addon.create category: Addon::CATEGORY_CAMP, name: 'RV over 25ft', default_price: 150 end diff --git a/spec/controllers/payments_controller_spec.rb b/spec/controllers/payments_controller_spec.rb index ccc815e3..8c85f0f2 100644 --- a/spec/controllers/payments_controller_spec.rb +++ b/spec/controllers/payments_controller_spec.rb @@ -37,7 +37,7 @@ end describe 'GET #show' do - subject { get :show, params: { id: payment.id, event_id: ticket_request.event.id, ticket_request_id: ticket_request.id } } + subject { get :show, params: { id: payment.id, event_id: ticket_request.event.to_param, ticket_request_id: ticket_request.id } } context 'when payment exists' do it { is_expected.to have_http_status(:ok) } diff --git a/spec/controllers/ticket_requests_controller_spec.rb b/spec/controllers/ticket_requests_controller_spec.rb index 7d24e2f4..da6e9ae2 100644 --- a/spec/controllers/ticket_requests_controller_spec.rb +++ b/spec/controllers/ticket_requests_controller_spec.rb @@ -130,7 +130,7 @@ end describe 'POST #create' do - let(:event) { create(:event, tickets_require_approval: true) } + let(:event) { create(:event, tickets_require_approval: true, slug: 'created-event') } let(:ticket_request_params) { build(:ticket_request, event:).as_json } diff --git a/spec/models/ticket_request_spec.rb b/spec/models/ticket_request_spec.rb index 90520100..0b1e3bfd 100644 --- a/spec/models/ticket_request_spec.rb +++ b/spec/models/ticket_request_spec.rb @@ -270,7 +270,7 @@ let(:event) do build(:event, adult_ticket_price: adult_price, - kid_ticket_price: kid_price) + kid_ticket_price: kid_price) end let(:ticket_request) do build(:ticket_request, @@ -313,6 +313,53 @@ it 'calculates event addons price for ticket request' do expect(ticket_request.calculate_addons_price).to eq(event_addon.price * ticket_request_event_addon.quantity) end + + describe '#active_addon_sum_quantity_by_category' do + it 'camping and pass category' do + expect(ticket_request.active_addon_sum_quantity_by_category(Addon::CATEGORY_PASS)).to eq(1) + expect(ticket_request.active_addon_sum_quantity_by_category(Addon::CATEGORY_CAMP)).to eq(0) + end + end + end + + describe '#active_addons' do + let!(:event) { create(:event) } + let!(:event_addon) { create(:event_addon, price: 10) } + let!(:ticket_request) { create(:ticket_request, event_id: event.id) } + let!(:ticket_request_event_addon) do + create(:ticket_request_event_addon, event_addon_id: event_addon.id, ticket_request_id: ticket_request.id, quantity: 1) + end + + it 'returns an active record association' do + expect(ticket_request.active_addons).to be_a(ActiveRecord::AssociationRelation) + end + + it 'finds one active addon for ticket request' do + expect(ticket_request.active_addons.count).to eq(1) + end + + it 'finds no active addons after update setting quantity to 0' do + ticket_request_event_addon.update(quantity: 0) + expect(ticket_request.active_addons.count).to eq(0) + end + end + + describe '#active_addons_sum' do + let!(:event) { create(:event) } + let!(:event_addon) { create(:event_addon, price: 10) } + let!(:ticket_request) { create(:ticket_request, event_id: event.id) } + let!(:ticket_request_event_addon) do + create(:ticket_request_event_addon, event_addon_id: event_addon.id, ticket_request_id: ticket_request.id, quantity: 1) + end + + it 'gets total active addons for ticket request' do + expect(ticket_request.active_addons_sum).to eq(1) + end + + it 'gets 2 addons for ticket request after update of quantity' do + ticket_request_event_addon.update(quantity: 2) + expect(ticket_request.active_addons_sum).to eq(2) + end end describe '#total_tickets' do