diff --git a/AGENTS.md b/AGENTS.md index 05033a0e9..e3cd2a1fd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -114,7 +114,7 @@ AWBW Portal (Rails 8.1) - **Root level** (~48 controllers): Workshops, stories, resources, events, people, organizations, etc. - **`admin/`**: HomeController, AnalyticsController, AhoyActivitiesController - **`api/v1/`**: ApiController base, Authentications, Workshops, Quotes, Resources -- **`events/`**: Registrations sub-resource +- **`events/`**: Registrations sub-resource (create/destroy + slug-based show at `/registration/:slug`) - **Devise overrides**: Registrations, Confirmations, Passwords ### Base Controller Pattern diff --git a/app/controllers/event_registrations_controller.rb b/app/controllers/event_registrations_controller.rb index 7559d42b7..442bc7aad 100644 --- a/app/controllers/event_registrations_controller.rb +++ b/app/controllers/event_registrations_controller.rb @@ -1,7 +1,7 @@ class EventRegistrationsController < ApplicationController require "csv" - skip_before_action :authenticate_user!, only: [ :show ] + # show redirects to slug URL; kept for backwards compatibility before_action :set_event_registration, only: [ :show, :edit, :update, :destroy ] def index @@ -30,6 +30,7 @@ def index def show authorize! @event_registration + redirect_to registration_ticket_path(@event_registration.slug), status: :moved_permanently end def new @@ -67,7 +68,7 @@ def create redirect_to manage_event_path(@event_registration.event), notice: "Registration created." else - redirect_to @event_registration, + redirect_to registration_ticket_path(@event_registration.slug), notice: "Registration created." end } @@ -100,7 +101,7 @@ def update if params[:return_to] == "manage" redirect_to manage_event_path(@event_registration.event), notice: "Registration was successfully updated.", status: :see_other else - redirect_to @event_registration, notice: "Registration was successfully updated.", status: :see_other + redirect_to registration_ticket_path(@event_registration.slug), notice: "Registration was successfully updated.", status: :see_other end } end diff --git a/app/controllers/events/public_registrations_controller.rb b/app/controllers/events/public_registrations_controller.rb index 886d0f4a3..3207796d1 100644 --- a/app/controllers/events/public_registrations_controller.rb +++ b/app/controllers/events/public_registrations_controller.rb @@ -50,7 +50,7 @@ def create ) if result.success? - redirect_to event_registration_path(result.event_registration), + redirect_to registration_ticket_path(result.event_registration.slug), notice: "You have been successfully registered!" else @form_fields = @form.form_fields.where(status: :active).reorder(position: :asc) @@ -63,14 +63,15 @@ def create def show authorize! :public_registration, to: :show? + registration = EventRegistration.find_by!(slug: params[:reg], event_id: @event.id) + @form = registration_form unless @form redirect_to event_path(@event), alert: "Registration form not found." return end - - @person_form = @form.person_forms.find_by(person: params[:person_id]) + @person_form = @form.person_forms.find_by(person: registration.registrant) unless @person_form redirect_to event_path(@event), alert: "No registration form submission found." return diff --git a/app/controllers/events/registrations_controller.rb b/app/controllers/events/registrations_controller.rb index 313efec4a..becfb6aec 100644 --- a/app/controllers/events/registrations_controller.rb +++ b/app/controllers/events/registrations_controller.rb @@ -1,8 +1,41 @@ module Events class RegistrationsController < ApplicationController - before_action :authenticate_user! - before_action :set_event - before_action :set_registrant + before_action :authenticate_user!, only: [ :create, :destroy ] + before_action :set_event, only: [ :create, :destroy ] + before_action :set_registrant, only: [ :create, :destroy ] + before_action :set_event_registration, only: [ :show, :resend_confirmation, :cancel, :reactivate ] + + def show + authorize! @event_registration, to: :show_public? + end + + def resend_confirmation + authorize! @event_registration, to: :show_public? + EventMailer.event_registration_confirmation(@event_registration).deliver_later + redirect_to registration_ticket_path(@event_registration.slug), notice: "Confirmation email sent." + end + + def cancel + authorize! @event_registration, to: :show_public? + + if @event_registration.active? + @event_registration.update!(status: "cancelled") + redirect_to registration_ticket_path(@event_registration.slug), notice: "Your registration has been cancelled." + else + redirect_to registration_ticket_path(@event_registration.slug), alert: "Registration is already cancelled." + end + end + + def reactivate + authorize! @event_registration, to: :show_public? + + if @event_registration.status == "cancelled" + @event_registration.update!(status: "registered") + redirect_to registration_ticket_path(@event_registration.slug), notice: "Your registration has been reactivated." + else + redirect_to registration_ticket_path(@event_registration.slug), alert: "Registration is not cancelled." + end + end def create @event_registration = @event.event_registrations.new(registrant: @registrant) @@ -12,7 +45,7 @@ def create success = "You have successfully registered for this event." respond_to do |format| format.turbo_stream { flash.now[:notice] = success } - format.html { redirect_to @event_registration, notice: success } + format.html { redirect_to registration_ticket_path(@event_registration.slug), notice: success } end else error = @event_registration.errors.full_messages.to_sentence @@ -78,5 +111,9 @@ def create_person_for_current_user current_user.update!(person: person) person end + + def set_event_registration + @event_registration = EventRegistration.find_by!(slug: params[:slug]) + end end end diff --git a/app/decorators/event_registration_decorator.rb b/app/decorators/event_registration_decorator.rb index 3d1aec85e..e46f6c7e3 100644 --- a/app/decorators/event_registration_decorator.rb +++ b/app/decorators/event_registration_decorator.rb @@ -6,6 +6,10 @@ def title def detail(length: nil) end + def link_target + h.registration_ticket_path(slug) + end + def default_display_image return event.primary_asset.file if event.respond_to?(:primary_asset) && event.primary_asset&.file&.attached? "theme_default.png" diff --git a/app/mailers/event_mailer.rb b/app/mailers/event_mailer.rb index 23880e3db..988e1b59a 100644 --- a/app/mailers/event_mailer.rb +++ b/app/mailers/event_mailer.rb @@ -7,7 +7,7 @@ def event_registration_confirmation(event_registration) @notification_type = "Event registration confirmation" @time_zone = @person.user&.time_zone || Time.zone.name - @event_url = event_url(@event) + @event_url = event_url(@event, reg: @event_registration.slug) @organization_name = ENV.fetch("ORGANIZATION_NAME", "AWBW") @organization_website = ENV.fetch("ORGANIZATION_WEBSITE", root_url) diff --git a/app/models/event_registration.rb b/app/models/event_registration.rb index afaf7912b..dc38b6311 100644 --- a/app/models/event_registration.rb +++ b/app/models/event_registration.rb @@ -9,6 +9,8 @@ class EventRegistration < ApplicationRecord accepts_nested_attributes_for :comments, reject_if: proc { |attrs| attrs["body"].blank? } + before_create :generate_slug + ACTIVE_STATUSES = %w[ registered attended incomplete_attendance ].freeze INACTIVE_STATUSES = %w[ cancelled no_show ].freeze ATTENDANCE_STATUSES = (ACTIVE_STATUSES + INACTIVE_STATUSES).freeze @@ -17,6 +19,7 @@ class EventRegistration < ApplicationRecord validates :registrant_id, uniqueness: { scope: :event_id } validates :event_id, presence: true validates :status, inclusion: { in: ATTENDANCE_STATUSES }, allow_nil: false + validates :slug, uniqueness: true, allow_nil: true # Scopes scope :registrant_name, ->(registrant_name) { joins(:registrant).where( @@ -136,4 +139,11 @@ def create_refund_payments currency: "usd" ) end + + def generate_slug + loop do + self.slug = SecureRandom.urlsafe_base64(16) + break unless EventRegistration.exists?(slug: slug) + end + end end diff --git a/app/policies/event_registration_policy.rb b/app/policies/event_registration_policy.rb index 1e8b39a3c..eb55d62bb 100644 --- a/app/policies/event_registration_policy.rb +++ b/app/policies/event_registration_policy.rb @@ -7,7 +7,8 @@ def index? = admin? def create? = admin? || owner? def update? = admin? || owner? def destroy? = record.persisted? && (admin? || owner?) - def show? = true + def show? = admin? + def show_public? = true relation_scope do |relation| diff --git a/app/services/event_registration_form_builder.rb b/app/services/event_registration_form_builder.rb index a8b59c617..591fe6ff2 100644 --- a/app/services/event_registration_form_builder.rb +++ b/app/services/event_registration_form_builder.rb @@ -155,6 +155,9 @@ def build_qualitative_fields(form, position) key: "referral_source", group: "qualitative", required: false) position = add_field(form, position, "What motivates you to attend this training?", :free_form_input_paragraph, key: "training_motivation", group: "qualitative", required: false) + position = add_field(form, position, "Are you interested in learning more about upcoming trainings or resources?", :multiple_choice_radio, + key: "interested_in_more", group: "qualitative", required: true, + options: %w[Yes No]) position end diff --git a/app/views/event_mailer/event_registration_confirmation.html.erb b/app/views/event_mailer/event_registration_confirmation.html.erb index 93e9bc33a..7fc392cdd 100644 --- a/app/views/event_mailer/event_registration_confirmation.html.erb +++ b/app/views/event_mailer/event_registration_confirmation.html.erb @@ -65,7 +65,7 @@
<% if @event_registration.persisted? %> - View registration + View registration <% end %> View event
\ No newline at end of file diff --git a/app/views/event_mailer/event_registration_confirmation.text.erb b/app/views/event_mailer/event_registration_confirmation.text.erb index 474a1728e..bcbe8a3fa 100644 --- a/app/views/event_mailer/event_registration_confirmation.text.erb +++ b/app/views/event_mailer/event_registration_confirmation.text.erb @@ -25,6 +25,9 @@ Videoconference URL: <%= @event.videoconference_url %> <%= @event.detail %> <% end %> +View your registration: +<%= registration_ticket_url(@event_registration.slug) %> + View the event page: <%= @event_url %> diff --git a/app/views/event_registrations/show.html.erb b/app/views/event_registrations/_ticket.html.erb similarity index 51% rename from app/views/event_registrations/show.html.erb rename to app/views/event_registrations/_ticket.html.erb index 7b339b2e7..ffc289594 100644 --- a/app/views/event_registrations/show.html.erb +++ b/app/views/event_registrations/_ticket.html.erb @@ -1,12 +1,5 @@ -<% content_for(:page_bg_class, "admin-or-owner") %> -<%= @event_registration.event.pre_title %>
+ <% if event_registration.event.respond_to?(:pre_title) && event_registration.event.pre_title.present? %> +<%= event_registration.event.pre_title %>
<% end %>Registrant
<% if user_signed_in? %> - <%= link_to @event_registration.registrant.full_name, person_path(@event_registration.registrant), class: "text-blue-700 hover:text-blue-900 underline" %> + <%= link_to event_registration.registrant.full_name, person_path(event_registration.registrant), class: "text-blue-700 hover:text-blue-900 underline" %> <% else %> - <%= @event_registration.registrant.full_name %> + <%= event_registration.registrant.full_name %> <% end %>
diff --git a/app/views/events/public_registrations/_form_field.html.erb b/app/views/events/public_registrations/_form_field.html.erb index 79f19d1d6..d5fe9730f 100644 --- a/app/views/events/public_registrations/_form_field.html.erb +++ b/app/views/events/public_registrations/_form_field.html.erb @@ -67,7 +67,7 @@ name="<%= field_name %>" value="<%= ffao.answer_option.name %>" class="text-blue-600 focus:ring-blue-500" - <%= "checked" if value == ffao.answer_option.name %> + <%= "checked" if value == ffao.answer_option.name || (value.blank? && field.field_key == "interested_in_more" && ffao.answer_option.name == "Yes") %> <%= "required" if field.is_required %>> <%= ffao.answer_option.name %> diff --git a/app/views/events/public_registrations/show.html.erb b/app/views/events/public_registrations/show.html.erb index fe970f472..de4b85c79 100644 --- a/app/views/events/public_registrations/show.html.erb +++ b/app/views/events/public_registrations/show.html.erb @@ -1,10 +1,11 @@ -<% content_for(:page_bg_class, "admin-or-owner") %> +<% content_for(:page_bg_class, "public") %>