diff --git a/app/avo/resources/session.rb b/app/avo/resources/session.rb index 0e20798e..2f092693 100644 --- a/app/avo/resources/session.rb +++ b/app/avo/resources/session.rb @@ -21,6 +21,7 @@ def fields field :title, as: :text, sortable: true, link_to_record: true field :slug, as: :text, hide_on: :new field :description, as: :trix + field :public, as: :boolean field :starts_at, as: :date_time, help: "The datetime field will use your browser's current timezone.", sortable: true, format: "FFFF" diff --git a/app/constraints/authenticated_constraint.rb b/app/constraints/authenticated_constraint.rb new file mode 100644 index 00000000..9bd45ece --- /dev/null +++ b/app/constraints/authenticated_constraint.rb @@ -0,0 +1,5 @@ +class AuthenticatedConstraint + def matches?(request) + request.session[:user_id].present? + end +end diff --git a/app/constraints/unauthenticated_constraint.rb b/app/constraints/unauthenticated_constraint.rb new file mode 100644 index 00000000..7c8b3116 --- /dev/null +++ b/app/constraints/unauthenticated_constraint.rb @@ -0,0 +1,5 @@ +class UnauthenticatedConstraint + def matches?(request) + request.session[:user_id].nil? + end +end diff --git a/app/controllers/abouts_controller.rb b/app/controllers/abouts_controller.rb index e17cc4de..dee0a886 100644 --- a/app/controllers/abouts_controller.rb +++ b/app/controllers/abouts_controller.rb @@ -1,4 +1,5 @@ class AboutsController < ApplicationController + allow_unauthenticated_access def show end end diff --git a/app/controllers/concerns/authentication.rb b/app/controllers/concerns/authentication.rb index 0fa41334..da010ffa 100644 --- a/app/controllers/concerns/authentication.rb +++ b/app/controllers/concerns/authentication.rb @@ -27,6 +27,7 @@ def authenticate_user! authenticate_user if !user_signed_in? + flash[:notice] = I18n.t("authentication.unauthenticated") redirect_to new_user_session_path end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 4fcbf50a..520635ac 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,6 +1,8 @@ class SessionsController < ApplicationController + allow_unauthenticated_access + def index - @user_session_ids = current_user.sessions.pluck(:id) + @user_session_ids = current_user&.sessions&.pluck(:id) @sessions = SessionQuery.new( relation: sessions.joins(:location).distinct, params: filter_params @@ -9,7 +11,11 @@ def index def show @user_session_ids = current_user.sessions.pluck(:id) - @session = sessions.friendly.includes(:location, :tags, speakers: [profile: :image_attachment]).find(params[:id]) + @session = if user_signed_in? + sessions.friendly.includes(:location, :tags, speakers: [profile: :image_attachment]).find(params[:id]) + else + sessions.publics.friendly.includes(:location, :tags, speakers: [profile: :image_attachment]).find(params[:id]) + end end private @@ -19,6 +25,6 @@ def sessions end def filter_params - params.permit(:starts_at, :live, :past, :starting_soon) + params.permit(:starts_at, :live, :past, :starting_soon).merge(show_private: user_signed_in?) end end diff --git a/app/controllers/speakers_controller.rb b/app/controllers/speakers_controller.rb index 7bb1a30c..0f1c0747 100644 --- a/app/controllers/speakers_controller.rb +++ b/app/controllers/speakers_controller.rb @@ -1,4 +1,5 @@ class SpeakersController < ApplicationController + allow_unauthenticated_access only: [:show] def show @speaker = current_conference.speakers.friendly.find(params[:id]) @profile = @speaker.profile.presence || Profile.new diff --git a/app/helpers/navigation_helper.rb b/app/helpers/navigation_helper.rb index 22959002..67d73e42 100644 --- a/app/helpers/navigation_helper.rb +++ b/app/helpers/navigation_helper.rb @@ -22,8 +22,21 @@ def show_header? end def show_bottom_navbar? - user_signed_in? && - !current_page?(coming_soon_path) + current_page?(sessions_path) || + (user_signed_in? || !current_page?(unauthenticated_root_path)) && + !excluded_paths.any? { |path| current_page?(path) } + end + + private + + def excluded_paths + [ + new_user_session_path, + new_registration_path, + new_password_reset_path, + edit_password_reset_path, + post_submit_password_reset_path + ] end def show_back_button? diff --git a/app/helpers/session_helper.rb b/app/helpers/session_helper.rb index 28fd0f75..22e08529 100644 --- a/app/helpers/session_helper.rb +++ b/app/helpers/session_helper.rb @@ -37,6 +37,6 @@ def current_agenda_session end def current_schedule_session - @current_schedule_session ||= current_user.sessions.live_or_upcoming_today.first + @current_schedule_session ||= current_user&.sessions&.live_or_upcoming_today&.first end end diff --git a/app/models/session.rb b/app/models/session.rb index d97e6a43..6e0038b0 100644 --- a/app/models/session.rb +++ b/app/models/session.rb @@ -4,6 +4,7 @@ # # id :integer not null, primary key # ends_at :datetime not null +# public :boolean default(TRUE), not null # sent_reminders :json # slug :string # starts_at :datetime not null @@ -51,6 +52,8 @@ class Session < ApplicationRecord scope :starting_soon, -> { where("starts_at BETWEEN ? and ?", Time.current, 1.hour.from_now) } scope :upcoming_today, -> { where("date(starts_at) = ? and starts_at > ?", Date.current, Time.current) } scope :live_or_upcoming_today, -> { live.or(upcoming_today) } + scope :publics, -> { where(public: true) } + scope :privates, -> { where(public: false) } def self.ransackable_attributes(_auth_object = nil) %w[title] @@ -69,4 +72,8 @@ def starting_soon? def past? ends_at < Time.current end + + def private? + !public? + end end diff --git a/app/queries/session_query.rb b/app/queries/session_query.rb index 7807e336..8902a28f 100644 --- a/app/queries/session_query.rb +++ b/app/queries/session_query.rb @@ -9,6 +9,7 @@ def initialize(relation: Session.all, params: {}) def call filter_by_date filter_by_status + filter_privates relation end @@ -27,6 +28,12 @@ def filter_by_status self.relation = relation.send_chain_or(status_scopes) end + def filter_privates + return if params[:show_private].present? + + self.relation = relation.publics + end + def starts_at @_starts_at ||= params[:starts_at]&.to_date rescue Date::Error diff --git a/app/views/layouts/_bottom_navbar.html.erb b/app/views/layouts/_bottom_navbar.html.erb index a40c4d5a..036e5bdb 100644 --- a/app/views/layouts/_bottom_navbar.html.erb +++ b/app/views/layouts/_bottom_navbar.html.erb @@ -18,7 +18,7 @@ <%= link_to( schedule_path( starts_at: current_starts_at_filter, - anchor: session_anchor(current_user.sessions.live_or_upcoming_today.first) + anchor: session_anchor(current_schedule_session) ), class: [ nav_text_class_for([schedule_path]), @@ -30,16 +30,16 @@ <% end %> <%= link_to( - profile_path(current_profile&.uuid), + user_signed_in? ? profile_path(current_profile&.uuid) : new_user_session_path, class: [ nav_text_class_for(["/profiles"]), "flex flex-col items-center justify-center" ] - ) do %> + ) do %> <%= inline_svg_tag( "icons/avatar_no_fill.svg", class: nav_icon_class_for(["/profiles"]) - ) %> + ) %> Profile <% end %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 57bdfca7..0bc5628e 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -50,7 +50,7 @@ <%= yield %> <% if show_bottom_navbar? %> - <%= render partial: "layouts/bottom_navbar", locals: { unread_notifications: current_user.notifications.unread } %> + <%= render partial: "layouts/bottom_navbar", locals: { unread_notifications: current_user&.notifications&.unread } %> <% end %> diff --git a/app/views/sessions/index.html.erb b/app/views/sessions/index.html.erb index 77a73ef8..32769a42 100644 --- a/app/views/sessions/index.html.erb +++ b/app/views/sessions/index.html.erb @@ -39,7 +39,7 @@ partial: 'sessions/card', locals: { session: session, - user_is_an_attendee: @user_session_ids.include?(session.id) + user_is_an_attendee: @user_session_ids&.include?(session.id) } ) %> <% end %> diff --git a/app/views/speakers/show.html.erb b/app/views/speakers/show.html.erb index d4e5febc..9602778f 100644 --- a/app/views/speakers/show.html.erb +++ b/app/views/speakers/show.html.erb @@ -68,7 +68,7 @@ partial: "sessions/card", locals: { session: session, - user_is_an_attendee: Current.user.sessions.include?(session) + user_is_an_attendee: Current.user&.sessions&.include?(session) } ) %> <% end %> diff --git a/app/views/user_sessions/new.html.erb b/app/views/user_sessions/new.html.erb index e3c1ffc6..ca69bae3 100644 --- a/app/views/user_sessions/new.html.erb +++ b/app/views/user_sessions/new.html.erb @@ -15,10 +15,13 @@
- <%= form.label :password, class: "text-white italic font-bold mb-2" %> +
+ <%= form.label :password, class: "text-white italic font-bold mb-2" %> + <%= link_to "Forgot password?", new_password_reset_path, class: "font-black italic underline text-white" %> +
<%= form.password_field :password, required: true, class: "peer w-full", placeholder: "Password", data: { test_id: "password_field", "password-visibility-target": "input" } %> - @@ -27,8 +30,8 @@
- <%= link_to "Forgot password?", new_password_reset_path, class: "font-black italic underline text-white mb-10" %> - <%= link_to "Sign up", new_registration_path, class: "font-black italic underline text-white" %> + <%= link_to "View as guest", sessions_path, class: "font-black italic underline text-white mb-10" %> + <%= link_to "Sign up", new_registration_path, class: "font-black italic underline text-white mb-10" %>
diff --git a/config/locales/en.yml b/config/locales/en.yml index 46bcb690..90e11b60 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -45,6 +45,8 @@ en: live: "Live" starting_soon: "Starting soon" submit: "Apply" + authentication: + unauthenticated: "You need to sign in or sign up before continuing." authorization: unauthorized: "You are not authorized to access this page." invalid_auth_token: "Your request has expired. Please try again." diff --git a/config/routes.rb b/config/routes.rb index 283581f8..ada1bb41 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,11 @@ Rails.application.routes.draw do - root "sessions#index" + constraints AuthenticatedConstraint.new do + root "sessions#index" + end + + constraints UnauthenticatedConstraint.new do + root "user_sessions#new", as: :unauthenticated_root + end get "up" => "rails/health#show", :as => :rails_health_check get "/service-worker.js" => "service_worker#service_worker" diff --git a/db/migrate/20240829165208_add_public_to_sessions.rb b/db/migrate/20240829165208_add_public_to_sessions.rb new file mode 100644 index 00000000..94d7c37e --- /dev/null +++ b/db/migrate/20240829165208_add_public_to_sessions.rb @@ -0,0 +1,5 @@ +class AddPublicToSessions < ActiveRecord::Migration[7.2] + def change + add_column :sessions, :public, :boolean, default: true, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 16b9e5b4..d1df726e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_08_26_205135) do +ActiveRecord::Schema[7.2].define(version: 2024_08_29_165208) do create_table "action_text_rich_texts", force: :cascade do |t| t.string "name", null: false t.text "body" @@ -117,6 +117,7 @@ t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "slug" + t.boolean "public", default: true, null: false t.index ["conference_id"], name: "index_sessions_on_conference_id" t.index ["ends_at"], name: "index_sessions_on_ends_at" t.index ["location_id"], name: "index_sessions_on_location_id" diff --git a/spec/factories/sessions.rb b/spec/factories/sessions.rb index c4a780dc..fc036a96 100644 --- a/spec/factories/sessions.rb +++ b/spec/factories/sessions.rb @@ -4,6 +4,7 @@ # # id :integer not null, primary key # ends_at :datetime not null +# public :boolean default(TRUE), not null # sent_reminders :json # slug :string # starts_at :datetime not null diff --git a/spec/models/session_spec.rb b/spec/models/session_spec.rb index 4a58a678..2aa14f5c 100644 --- a/spec/models/session_spec.rb +++ b/spec/models/session_spec.rb @@ -4,6 +4,7 @@ # # id :integer not null, primary key # ends_at :datetime not null +# public :boolean default(TRUE), not null # sent_reminders :json # slug :string # starts_at :datetime not null