diff --git a/app/assets/stylesheets/card-columns.css b/app/assets/stylesheets/card-columns.css index 90f6859c6..4e028663f 100644 --- a/app/assets/stylesheets/card-columns.css +++ b/app/assets/stylesheets/card-columns.css @@ -85,7 +85,7 @@ .card__background { .card:has(& img:not([src=""])) { - .card__body, + .card__content, .card__meta, .workflow-stage:not(.workflow-stage--current) { opacity: 0; diff --git a/app/assets/stylesheets/comments.css b/app/assets/stylesheets/comments.css index bba7f8a34..a8b8da16b 100644 --- a/app/assets/stylesheets/comments.css +++ b/app/assets/stylesheets/comments.css @@ -37,8 +37,14 @@ } .comment__author { - .comment--system & strong { - display: none; + .comment--system & { + h3 { + margin-inline: auto; + } + + strong { + display: none; + } } .btn { diff --git a/app/assets/stylesheets/inputs.css b/app/assets/stylesheets/inputs.css index 3acda5855..ed4a51072 100644 --- a/app/assets/stylesheets/inputs.css +++ b/app/assets/stylesheets/inputs.css @@ -37,7 +37,6 @@ } .input--file { - border: 0; cursor: pointer; display: grid; inline-size: auto; @@ -52,6 +51,7 @@ } input[type="file"] { + --hover-size: 0; --input-border-color: transparent; --input-border-radius: 8px; @@ -69,9 +69,9 @@ &:focus, &:focus-visible { - --input-border-color: var(--color-selected-dark); - --input-border-radius: 8px; - --input-border-size: 0.15rem; + .input--file:has(&) { + outline: 0.15rem solid var(--color-selected-dark); + } } } diff --git a/app/controllers/concerns/authentication.rb b/app/controllers/concerns/authentication.rb index dc3ee7bb7..39a6d293e 100644 --- a/app/controllers/concerns/authentication.rb +++ b/app/controllers/concerns/authentication.rb @@ -48,11 +48,7 @@ module Authentication def request_authentication session[:return_to_after_authenticating] = request.url - if Rails.application.config.x.local_authentication - redirect_to new_session_path - else - redirect_to Launchpad.login_url(account: Current.account), allow_other_host: true - end + redirect_to Launchpad.login_url(account: Current.account), allow_other_host: true end def after_authentication_url diff --git a/app/controllers/sessions/launchpad_controller.rb b/app/controllers/sessions/launchpad_controller.rb index 0e2ad16a7..8a9a082dd 100644 --- a/app/controllers/sessions/launchpad_controller.rb +++ b/app/controllers/sessions/launchpad_controller.rb @@ -1,8 +1,7 @@ class Sessions::LaunchpadController < ApplicationController require_unauthenticated_access - before_action :store_sig, only: :show - before_action :restore_and_clear_sig, only: :update + before_action :require_sig def show end @@ -17,11 +16,7 @@ class Sessions::LaunchpadController < ApplicationController end private - def store_sig - cookies[:_fizzy_launchpad_sig] = params.expect(:sig) - end - - def restore_and_clear_sig - @sig = cookies.delete :_fizzy_launchpad_sig + def require_sig + @sig = params.expect(:sig) end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 428c5a7f4..fa7d98974 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,28 +1,6 @@ class SessionsController < ApplicationController - require_unauthenticated_access only: %i[ new create ] - rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_path, alert: "Try again later." } - - before_action :require_first_run_completion - - def new - end - - def create - if user = User.active.authenticate_by(params.permit(:email_address, :password)) - start_new_session_for user - redirect_to after_authentication_url - else - redirect_to new_session_path, alert: "Try another email address or password." - end - end - def destroy terminate_session - redirect_to new_session_path + redirect_to Launchpad.login_url, allow_other_host: true end - - private - def require_first_run_completion - redirect_to first_run_path if Account.none? - end end diff --git a/app/controllers/signup/base_controller.rb b/app/controllers/signup/base_controller.rb index 40ae83e92..088937b04 100644 --- a/app/controllers/signup/base_controller.rb +++ b/app/controllers/signup/base_controller.rb @@ -1,6 +1,5 @@ class Signup::BaseController < ApplicationController require_untenanted_access - before_action :redirect_if_local_auth # TODO: Remove this auth before launch. http_basic_authenticate_with( @@ -34,8 +33,4 @@ class Signup::BaseController < ApplicationController redirect_to account.signal_account.owner.remote_login_url(proceed_to: root_path), allow_other_host: true end - - def redirect_if_local_auth - render plain: "Unauthorized", status: :unauthorized if Rails.application.config.x.local_authentication - end end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 6b4ffd47d..51e69e94b 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -37,7 +37,7 @@ module EventsHelper def event_cluster_tag(hour, col, &) row = 25 - hour - tag.ul class: "events__time-block", style: "grid-area: #{row}/#{col}", & + tag.div class: "events__time-block", style: "grid-area: #{row}/#{col}", & end def event_next_page_link(next_day) diff --git a/app/javascript/controllers/dialog_controller.js b/app/javascript/controllers/dialog_controller.js index fd4d122e0..123c2384e 100644 --- a/app/javascript/controllers/dialog_controller.js +++ b/app/javascript/controllers/dialog_controller.js @@ -6,6 +6,10 @@ export default class extends Controller { modal: { type: Boolean, default: false } } + connect() { + this.dialogTarget.setAttribute('aria-hidden', 'true') + } + open() { const modal = this.modalValue @@ -14,6 +18,7 @@ export default class extends Controller { } else { this.dialogTarget.show() } + this.dialogTarget.setAttribute('aria-hidden', 'false') } toggle() { @@ -26,6 +31,7 @@ export default class extends Controller { close() { this.dialogTarget.close() + this.dialogTarget.setAttribute('aria-hidden', 'true') this.dialogTarget.blur() } diff --git a/app/models/account/signal_account.rb b/app/models/account/signal_account.rb index 610a4ed9c..a01af7ad2 100644 --- a/app/models/account/signal_account.rb +++ b/app/models/account/signal_account.rb @@ -2,10 +2,7 @@ module Account::SignalAccount extend ActiveSupport::Concern included do - unless Rails.application.config.x.local_authentication - # TODO: remove the "optional: true" once we've populated the accounts properly - belongs_to :signal_account, class_name: "SignalId::Account", primary_key: :queenbee_id, foreign_key: :queenbee_id, optional: true - end + belongs_to :signal_account, class_name: "SignalId::Account", primary_key: :queenbee_id, foreign_key: :queenbee_id end class_methods do diff --git a/app/models/user/signal_user.rb b/app/models/user/signal_user.rb index 924cfe87d..16bee49bc 100644 --- a/app/models/user/signal_user.rb +++ b/app/models/user/signal_user.rb @@ -2,8 +2,6 @@ module User::SignalUser extend ActiveSupport::Concern included do - unless Rails.application.config.x.local_authentication - belongs_to :signal_user, dependent: :destroy, class_name: "SignalId::User", optional: true - end + belongs_to :signal_user, dependent: :destroy, class_name: "SignalId::User", optional: true end end diff --git a/app/views/accounts/_user.html.erb b/app/views/accounts/_user.html.erb index cdf3c9beb..f176236c3 100644 --- a/app/views/accounts/_user.html.erb +++ b/app/views/accounts/_user.html.erb @@ -1,5 +1,5 @@
  • - <%= avatar_tag user %> + <%= avatar_tag user, hidden_for_screen_reader: true %> <%= link_to user.name, user, class: "txt-ink btn btn--plain" %> diff --git a/app/views/accounts/settings/_users.html.erb b/app/views/accounts/settings/_users.html.erb index 550715545..7ffd3c5a5 100644 --- a/app/views/accounts/settings/_users.html.erb +++ b/app/views/accounts/settings/_users.html.erb @@ -1,6 +1,6 @@
    People on the account - <%= render "accounts/invite" %> + <%#= render "accounts/invite" # Scheduled work in https://3.basecamp.com/2914079/buckets/37331921/todos/8746162337 %>
    diff --git a/app/views/cards/comments/_comment.html.erb b/app/views/cards/comments/_comment.html.erb index 8a66b2fcd..daa3eda11 100644 --- a/app/views/cards/comments/_comment.html.erb +++ b/app/views/cards/comments/_comment.html.erb @@ -8,14 +8,16 @@
    - - <%= link_to comment.creator.name, comment.creator, class: "txt-ink btn btn--plain fill-transparent", data: { turbo_frame: "_top" } %> - +

    + + <%= link_to comment.creator.name, comment.creator, class: "txt-ink btn btn--plain fill-transparent", data: { turbo_frame: "_top" } %> + - <%= link_to comment, class: "txt-undecorated txt-ink translucent txt-normal txt-capitalize flex-item-justify-start" do %> - <%= local_datetime_tag comment.created_at, style: :agoorweekday %>, - <%= local_datetime_tag comment.created_at, style: :time %> - <% end %> + <%= link_to comment, class: "txt-undecorated txt-ink translucent txt-normal txt-capitalize" do %> + <%= local_datetime_tag comment.created_at, style: :agoorweekday %>, + <%= local_datetime_tag comment.created_at, style: :time %> + <% end %> +

    <%= link_to edit_card_comment_path(comment.card, comment), class: "comment__edit btn btn--circle borderless fill-transparent translucent" do %> diff --git a/app/views/cards/comments/reactions/_quick_reaction.html.erb b/app/views/cards/comments/reactions/_quick_reaction.html.erb index b93931813..d316e8ef7 100644 --- a/app/views/cards/comments/reactions/_quick_reaction.html.erb +++ b/app/views/cards/comments/reactions/_quick_reaction.html.erb @@ -1,4 +1,4 @@ -
    +
    <%= yield %> diff --git a/app/views/cards/container/_closure.html.erb b/app/views/cards/container/_closure.html.erb index d8df5173f..7d5914a9a 100644 --- a/app/views/cards/container/_closure.html.erb +++ b/app/views/cards/container/_closure.html.erb @@ -7,7 +7,7 @@ <% end %>
    <% else %> -
    +
    Close as <%= icon_tag "caret-down" %> diff --git a/app/views/cards/container/_image.html.erb b/app/views/cards/container/_image.html.erb index c1617792e..773f7f949 100644 --- a/app/views/cards/container/_image.html.erb +++ b/app/views/cards/container/_image.html.erb @@ -5,13 +5,12 @@ <% end %> <% elsif !card.closed? %> <%= form_with model: card, url: collection_card_path(card.collection, card), data: { controller: "form" } do |form| %> -
    - <%= button_to session_path, method: :delete, class: "btn center txt-medium" do %> + <%= button_to session_path, method: :delete, class: "btn center txt-medium", data: { turbo: false } do %> <%= icon_tag "logout" %> Sign out <% end %> diff --git a/config/initializers/signal_id.rb b/config/initializers/signal_id.rb index afb6ff60c..b356ef881 100644 --- a/config/initializers/signal_id.rb +++ b/config/initializers/signal_id.rb @@ -1,18 +1,11 @@ require "signal_id" -Rails.application.config.x.local_authentication = ENV["LOCAL_AUTHENTICATION"].present? - ENV["SIGNAL_ID_SECRET"] = Rails.application.credentials.signal_id_secret Rails.application.config.to_prepare do SignalId.product = "fizzy" db_config = SignalId::Database.default_configuration - if Rails.application.config.x.local_authentication - db_config.each do |name, config| - config["connect_timeout"] = 1 - end - end SignalId::Database.load_configuration db_config SignalId::Database.enable_rw_splitting! diff --git a/config/routes.rb b/config/routes.rb index 505bba048..985122b47 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -85,11 +85,11 @@ Rails.application.routes.draw do get "join/:join_code", to: "users#new", as: :join post "join/:join_code", to: "users#create" - resource :session do + resource :session, only: :destroy do scope module: "sessions" do resources :transfers, only: %i[ show update ] + resource :launchpad, only: %i[ show update ], controller: "launchpad" end - resource :launchpad, only: %i[ show update ], controller: "sessions/launchpad" end namespace :signup do diff --git a/db/migrate/20250702154620_remove_password_from_users.rb b/db/migrate/20250702154620_remove_password_from_users.rb new file mode 100644 index 000000000..75173ad1a --- /dev/null +++ b/db/migrate/20250702154620_remove_password_from_users.rb @@ -0,0 +1,5 @@ +class RemovePasswordFromUsers < ActiveRecord::Migration[8.1] + def change + remove_column :users, :password, :string + end +end diff --git a/db/migrate/20250702160230_add_not_null_to_accounts_queenbee_id.rb b/db/migrate/20250702160230_add_not_null_to_accounts_queenbee_id.rb new file mode 100644 index 000000000..9698302bf --- /dev/null +++ b/db/migrate/20250702160230_add_not_null_to_accounts_queenbee_id.rb @@ -0,0 +1,5 @@ +class AddNotNullToAccountsQueenbeeId < ActiveRecord::Migration[8.1] + def change + change_column_null :accounts, :queenbee_id, false + end +end diff --git a/db/schema.rb b/db/schema.rb index be6ae5012..57520f743 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[8.1].define(version: 2025_06_25_120000) do +ActiveRecord::Schema[8.1].define(version: 2025_07_02_160230) do create_table "accesses", force: :cascade do |t| t.datetime "accessed_at" t.integer "collection_id", null: false @@ -28,7 +28,7 @@ ActiveRecord::Schema[8.1].define(version: 2025_06_25_120000) do t.datetime "created_at", null: false t.string "join_code" t.string "name", null: false - t.integer "queenbee_id" + t.integer "queenbee_id", null: false t.datetime "updated_at", null: false t.index ["queenbee_id"], name: "index_accounts_on_queenbee_id", unique: true end diff --git a/db/schema_cache.yml b/db/schema_cache.yml index d72e1af13..34de2aa3b 100644 --- a/db/schema_cache.yml +++ b/db/schema_cache.yml @@ -128,7 +128,7 @@ columns: name: queenbee_id cast_type: *3 sql_type_metadata: *4 - 'null': true + 'null': false default: default_function: collation: @@ -2451,4 +2451,4 @@ indexes: comment: valid: true workflows: [] -version: 20250625120000 +version: 20250702160230 diff --git a/test/controllers/events_controller_test.rb b/test/controllers/events_controller_test.rb index d89d953f4..c89c06540 100644 --- a/test/controllers/events_controller_test.rb +++ b/test/controllers/events_controller_test.rb @@ -11,7 +11,7 @@ class EventsControllerTest < ActionDispatch::IntegrationTest test "index" do get events_path - assert_select "ul.events__time-block[style='grid-area: 17/2']" do + assert_select "div.events__time-block[style='grid-area: 17/2']" do assert_select "strong", text: "David assigned JZ to Layout is broken" end end @@ -21,7 +21,7 @@ class EventsControllerTest < ActionDispatch::IntegrationTest get events_path - assert_select "ul.events__time-block[style='grid-area: 22/2']" do + assert_select "div.events__time-block[style='grid-area: 22/2']" do assert_select "strong", text: "David assigned JZ to Layout is broken" end end diff --git a/test/controllers/sessions/launchpad_controller_test.rb b/test/controllers/sessions/launchpad_controller_test.rb index 2ab50b2a0..c67ac8ee2 100644 --- a/test/controllers/sessions/launchpad_controller_test.rb +++ b/test/controllers/sessions/launchpad_controller_test.rb @@ -6,14 +6,16 @@ class Sessions::LaunchpadControllerTest < ActionDispatch::IntegrationTest assert_response :success - assert_equal cookies[:_fizzy_launchpad_sig], "test-sig" + assert_select "form input#sig" do |node| + assert_equal node.length, 1 + assert_equal node.first["value"], "test-sig" + end end test "create establishes a session when the sig is valid" do user = users(:david) - cookies[:_fizzy_launchpad_sig] = user.signal_user.perishable_signature - put session_launchpad_path + put session_launchpad_path(params: { sig: user.signal_user.perishable_signature }) assert_redirected_to root_url assert parsed_cookies.signed[:session_token] @@ -21,9 +23,8 @@ class Sessions::LaunchpadControllerTest < ActionDispatch::IntegrationTest test "returns 401 when the sig is invalid" do user = users(:david) - cookies[:sig] = "not-valid" - put session_launchpad_path + put session_launchpad_path(params: { sig: "invalid" }) assert_response :unauthorized end diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb index 1cf460c6c..35a6b0385 100644 --- a/test/controllers/sessions_controller_test.rb +++ b/test/controllers/sessions_controller_test.rb @@ -1,38 +1,10 @@ require "test_helper" class SessionsControllerTest < ActionDispatch::IntegrationTest - ALLOWED_BROWSER = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15" - DISALLOWED_BROWSER = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0" - - test "new" do - get new_session_path - assert_response :success - end - - test "new enforces browser compatibility" do - get new_session_path, env: { "HTTP_USER_AGENT" => DISALLOWED_BROWSER } - assert_select "svg", message: /Your browser is not supported/ - - get new_session_path, env: { "HTTP_USER_AGENT" => ALLOWED_BROWSER } - assert_select "svg", text: /Your browser is not supported/, count: 0 - end - - test "create with valid credentials" do - post session_path, params: { email_address: "david@37signals.com", password: "secret123456" } - assert_redirected_to root_path - assert cookies[:session_token].present? - end - - test "create with invalid credentials" do - post session_path, params: { email_address: "david@37signals.com", password: "wrong" } - assert_redirected_to new_session_path - assert_not cookies[:session_token].present? - end - test "destroy" do sign_in_as :kevin delete session_path - assert_redirected_to new_session_path + assert_redirected_to Launchpad.login_url assert_not cookies[:session_token].present? end end diff --git a/test/test_helpers/session_test_helper.rb b/test/test_helpers/session_test_helper.rb index 5e4f7eaf0..f4bb6aa45 100644 --- a/test/test_helpers/session_test_helper.rb +++ b/test/test_helpers/session_test_helper.rb @@ -6,7 +6,7 @@ module SessionTestHelper def sign_in_as(user) cookies[:session_token] = nil user = users(user) unless user.is_a? User - post session_path, params: { email_address: user.email_address, password: "secret123456" } + put session_launchpad_path, params: { sig: user.signal_user.perishable_signature } assert cookies[:session_token].present? end