From fa549a370b9ed6fc35c109750367bf7ae97c744f Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Fri, 5 Dec 2025 16:16:58 -0500 Subject: [PATCH 1/5] Add a system test for joining an account Reworked the magic link stimulus controller, because the system test was causing double-submission of the form (because the event was bubbling up). I think that change simplifies the form and will still work well for iOS devices. --- .../controllers/magic_link_controller.js | 18 +++++++++++------ app/views/sessions/magic_links/show.html.erb | 2 +- test/system/smoke_test.rb | 20 +++++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/app/javascript/controllers/magic_link_controller.js b/app/javascript/controllers/magic_link_controller.js index 4d6c45ab5..3e2e4618c 100644 --- a/app/javascript/controllers/magic_link_controller.js +++ b/app/javascript/controllers/magic_link_controller.js @@ -4,12 +4,18 @@ import { onNextEventLoopTick } from "helpers/timing_helpers" export default class extends Controller { static targets = [ "input" ] + submitOnEnter(event) { + event.preventDefault() + this.submit() + } + + submitOnPaste() { + onNextEventLoopTick(() => this.submit()) + } + submit() { - onNextEventLoopTick(() => { - if (!this.inputTarget.disabled) { - this.element.submit() - this.inputTarget.disabled = true - } - }) + if (this.inputTarget.disabled) return + this.element.submit() + this.inputTarget.disabled = true } } diff --git a/app/views/sessions/magic_links/show.html.erb b/app/views/sessions/magic_links/show.html.erb index 931156ff6..434bb93c3 100644 --- a/app/views/sessions/magic_links/show.html.erb +++ b/app/views/sessions/magic_links/show.html.erb @@ -10,7 +10,7 @@ <%= form.text_field :code, required: true, class: "input center txt-align-enter txt-large", autofocus: true, autocorrect: "off", autocapitalize: "off", spellcheck: "false", "data-1p-ignore": true, autocomplete: "one-time-code", maxlength: "6", placeholder: "••••••", value: params[:code], - data: { magic_link_target: "input", action: "keydown.enter->magic-link#submit paste->magic-link#submit" } %> + data: { magic_link_target: "input", action: "keydown.enter->magic-link#submitOnEnter paste->magic-link#submitOnPaste" } %> <% end %>

The code you receive will work for <%= distance_of_time_in_words(MagicLink::EXPIRATION_TIME) %>.

diff --git a/test/system/smoke_test.rb b/test/system/smoke_test.rb index e4bc9cae9..c70d42e95 100644 --- a/test/system/smoke_test.rb +++ b/test/system/smoke_test.rb @@ -1,6 +1,26 @@ require "application_system_test_case" class SmokeTest < ApplicationSystemTestCase + test "joining an account" do + account = accounts("37s") + + visit join_url(code: account.join_code.code, script_name: account.slug) + fill_in "Email address", with: "newbie@example.com" + click_on "Continue" + + assert_selector "h1", text: "Check your email" + identity = Identity.find_by!(email_address: "newbie@example.com") + code = identity.magic_links.active.first.code + fill_in "code", with: code + send_keys :enter + + assert_selector "input[id=user_name]" + fill_in "Full name", with: "New Bee" + click_on "Continue" + + assert_selector "h1", text: "Writebook" + end + test "create a card" do sign_in_as(users(:david)) From 4602cd3cdd87949aafd151b23059dd70b4457292 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 4 Dec 2025 20:20:20 -0500 Subject: [PATCH 2/5] Add verified_at timestamp to use for spam prevention User are marked as verified after a join code is redeemed. The user is redirected to Users::VerificationsController, either: - after submitting a valid magic link code, - or immediately after redeeming the join code (if they're already authenticated with the correct identity) Account owners are automatically verified when the account is created (because they have already provided a magic link code at that point). This sets up for later commits that will backfill existing users and require verification before sending notification emails. Co-Authored-By: Claude --- app/controllers/join_codes_controller.rb | 4 +-- .../users/verifications_controller.rb | 11 +++++++ app/models/account.rb | 2 +- app/models/user.rb | 8 +++++ app/views/users/verifications/new.html.erb | 1 + config/routes.rb | 1 + ...20251205010536_add_verified_at_to_users.rb | 5 +++ db/schema.rb | 3 +- db/schema_sqlite.rb | 3 +- db/seeds.rb | 2 +- .../controllers/join_codes_controller_test.rb | 6 ++-- .../users/verifications_controller_test.rb | 24 ++++++++++++++ test/fixtures/users.yml | 5 +++ test/models/account_test.rb | 2 ++ test/models/user_test.rb | 32 +++++++++++++++++++ test/system/smoke_test.rb | 1 + 16 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 app/controllers/users/verifications_controller.rb create mode 100644 app/views/users/verifications/new.html.erb create mode 100644 db/migrate/20251205010536_add_verified_at_to_users.rb create mode 100644 test/controllers/users/verifications_controller_test.rb diff --git a/app/controllers/join_codes_controller.rb b/app/controllers/join_codes_controller.rb index 971b3c6f8..eb328df18 100644 --- a/app/controllers/join_codes_controller.rb +++ b/app/controllers/join_codes_controller.rb @@ -18,7 +18,7 @@ class JoinCodesController < ApplicationController if identity == Current.identity && user.setup? redirect_to landing_url(script_name: @join_code.account.slug) elsif identity == Current.identity - redirect_to new_users_join_url(script_name: @join_code.account.slug) + redirect_to new_users_verification_url(script_name: @join_code.account.slug) else logout_and_send_new_magic_link(identity) redirect_to session_magic_link_url(script_name: nil) @@ -44,6 +44,6 @@ class JoinCodesController < ApplicationController magic_link = identity.send_magic_link serve_development_magic_link(magic_link) - session[:return_to_after_authenticating] = new_users_join_url(script_name: @join_code.account.slug) + session[:return_to_after_authenticating] = new_users_verification_url(script_name: @join_code.account.slug) end end diff --git a/app/controllers/users/verifications_controller.rb b/app/controllers/users/verifications_controller.rb new file mode 100644 index 000000000..d99492576 --- /dev/null +++ b/app/controllers/users/verifications_controller.rb @@ -0,0 +1,11 @@ +class Users::VerificationsController < ApplicationController + layout "public" + + def new + end + + def create + Current.user.verify + redirect_to new_users_join_path + end +end diff --git a/app/models/account.rb b/app/models/account.rb index 50f3bf3ee..61a636adb 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -21,7 +21,7 @@ class Account < ApplicationRecord def create_with_owner(account:, owner:) create!(**account).tap do |account| account.users.create!(role: :system, name: "System") - account.users.create!(**owner.reverse_merge(role: "owner")) + account.users.create!(**owner.reverse_merge(role: "owner", verified_at: Time.current)) end end end diff --git a/app/models/user.rb b/app/models/user.rb index 8c0ac42a5..20ee1c40c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -28,6 +28,14 @@ class User < ApplicationRecord name != identity.email_address end + def verified? + verified_at.present? + end + + def verify + update!(verified_at: Time.current) unless verified? + end + private def close_remote_connections ActionCable.server.remote_connections.where(current_user: self).disconnect(reconnect: false) diff --git a/app/views/users/verifications/new.html.erb b/app/views/users/verifications/new.html.erb new file mode 100644 index 000000000..fe830cd28 --- /dev/null +++ b/app/views/users/verifications/new.html.erb @@ -0,0 +1 @@ +<%= auto_submit_form_with url: users_verifications_path, method: :post %> diff --git a/config/routes.rb b/config/routes.rb index 9fa8f81bf..e67e4ef7c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -138,6 +138,7 @@ Rails.application.routes.draw do namespace :users do resources :joins + resources :verifications, only: %i[ new create ] end resource :session do diff --git a/db/migrate/20251205010536_add_verified_at_to_users.rb b/db/migrate/20251205010536_add_verified_at_to_users.rb new file mode 100644 index 000000000..b853cb952 --- /dev/null +++ b/db/migrate/20251205010536_add_verified_at_to_users.rb @@ -0,0 +1,5 @@ +class AddVerifiedAtToUsers < ActiveRecord::Migration[8.2] + def change + add_column :users, :verified_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index b84d3c160..42458db17 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.2].define(version: 2025_12_01_100607) do +ActiveRecord::Schema[8.2].define(version: 2025_12_05_010536) do create_table "accesses", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.datetime "accessed_at" t.uuid "account_id", null: false @@ -726,6 +726,7 @@ ActiveRecord::Schema[8.2].define(version: 2025_12_01_100607) do t.string "name", null: false t.string "role", default: "member", null: false t.datetime "updated_at", null: false + t.datetime "verified_at" t.index ["account_id", "identity_id"], name: "index_users_on_account_id_and_identity_id", unique: true t.index ["account_id", "role"], name: "index_users_on_account_id_and_role" t.index ["identity_id"], name: "index_users_on_identity_id" diff --git a/db/schema_sqlite.rb b/db/schema_sqlite.rb index 6f6d6cf53..1dd2b3e00 100644 --- a/db/schema_sqlite.rb +++ b/db/schema_sqlite.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.2].define(version: 2025_12_01_100607) do +ActiveRecord::Schema[8.2].define(version: 2025_12_05_010536) do create_table "accesses", id: :uuid, force: :cascade do |t| t.datetime "accessed_at" t.uuid "account_id", null: false @@ -499,6 +499,7 @@ ActiveRecord::Schema[8.2].define(version: 2025_12_01_100607) do t.string "name", limit: 255, null: false t.string "role", limit: 255, default: "member", null: false t.datetime "updated_at", null: false + t.datetime "verified_at" t.index ["account_id", "identity_id"], name: "index_users_on_account_id_and_identity_id", unique: true t.index ["account_id", "role"], name: "index_users_on_account_id_and_role" t.index ["identity_id"], name: "index_users_on_identity_id" diff --git a/db/seeds.rb b/db/seeds.rb index bb8db7db8..7cba1b5f9 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -36,7 +36,7 @@ else if user = identity.users.find_by(account: Current.account) user else - User.create!(name: full_name, identity: identity, account: Current.account) + User.create!(name: full_name, identity: identity, account: Current.account, verified_at: Time.current) end end diff --git a/test/controllers/join_codes_controller_test.rb b/test/controllers/join_codes_controller_test.rb index fe8c820d9..0a4bf5793 100644 --- a/test/controllers/join_codes_controller_test.rb +++ b/test/controllers/join_codes_controller_test.rb @@ -36,7 +36,7 @@ class JoinCodesControllerTest < ActionDispatch::IntegrationTest end assert_redirected_to session_magic_link_url(script_name: nil) - assert_equal new_users_join_url(script_name: @account.slug), session[:return_to_after_authenticating] + assert_equal new_users_verification_url(script_name: @account.slug), session[:return_to_after_authenticating] end test "create for existing identity" do @@ -55,7 +55,7 @@ class JoinCodesControllerTest < ActionDispatch::IntegrationTest assert_redirected_to landing_url(script_name: @account.slug) end - test "create for signed-in identity without a user in the account redirects to user setup" do + test "create for signed-in identity without a user in the account redirects to verification" do identity = identities(:mike) sign_in_as :mike @@ -67,6 +67,6 @@ class JoinCodesControllerTest < ActionDispatch::IntegrationTest end end - assert_redirected_to new_users_join_url(script_name: @account.slug) + assert_redirected_to new_users_verification_url(script_name: @account.slug) end end diff --git a/test/controllers/users/verifications_controller_test.rb b/test/controllers/users/verifications_controller_test.rb new file mode 100644 index 000000000..25ecdba1c --- /dev/null +++ b/test/controllers/users/verifications_controller_test.rb @@ -0,0 +1,24 @@ +require "test_helper" + +class Users::VerificationsControllerTest < ActionDispatch::IntegrationTest + test "new renders the auto-submit form" do + sign_in_as :david + + get new_users_verification_path + + assert_response :ok + end + + test "create verifies the user and redirects to join" do + sign_in_as :david + + user = users(:david) + user.update_column(:verified_at, nil) + assert_not user.verified? + + post users_verifications_path + + assert_redirected_to new_users_join_path + assert user.reload.verified? + end +end diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index 4c7dad414..cf4d9e6d0 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -4,6 +4,7 @@ david: role: member identity: david account: 37s_uuid + verified_at: <%= Time.current.to_fs(:db) %> jz: id: <%= ActiveRecord::FixtureSet.identify("jz", :uuid) %> @@ -11,6 +12,7 @@ jz: role: member identity: jz account: 37s_uuid + verified_at: <%= Time.current.to_fs(:db) %> jason: id: <%= ActiveRecord::FixtureSet.identify("jason", :uuid) %> @@ -18,6 +20,7 @@ jason: role: owner identity: jason account: 37s_uuid + verified_at: <%= Time.current.to_fs(:db) %> kevin: id: <%= ActiveRecord::FixtureSet.identify("kevin", :uuid) %> @@ -25,6 +28,7 @@ kevin: role: admin identity: kevin account: 37s_uuid + verified_at: <%= Time.current.to_fs(:db) %> system: id: <%= ActiveRecord::FixtureSet.identify("system", :uuid) %> @@ -38,6 +42,7 @@ mike: role: admin identity: mike account: initech_uuid + verified_at: <%= Time.current.to_fs(:db) %> system_initech: id: <%= ActiveRecord::FixtureSet.identify("system_initech", :uuid) %> diff --git a/test/models/account_test.rb b/test/models/account_test.rb index 490d6e32e..75da41fb9 100644 --- a/test/models/account_test.rb +++ b/test/models/account_test.rb @@ -44,6 +44,8 @@ class AccountTest < ActiveSupport::TestCase assert owner.admin?, "owner should also be considered an admin" assert_predicate account.system_user, :present? + + assert owner.verified?, "owner should be verified on account creation" end end diff --git a/test/models/user_test.rb b/test/models/user_test.rb index 36b0e7986..645e3a386 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -48,4 +48,36 @@ class UserTest < ActiveSupport::TestCase user.update!(name: "Kevin") assert user.setup? end + + test "verified? returns true when verified_at is present" do + user = users(:david) + user.update_column(:verified_at, Time.current) + + assert user.verified? + end + + test "verified? returns false when verified_at is nil" do + user = users(:david) + user.update_column(:verified_at, nil) + + assert_not user.verified? + end + + test "verify sets verified_at when not already verified" do + user = users(:david) + user.update_column(:verified_at, nil) + + assert_nil user.verified_at + user.verify + assert_not_nil user.reload.verified_at + end + + test "verify does not update verified_at when already verified" do + user = users(:david) + original_time = 1.day.ago + user.update_column(:verified_at, original_time) + + user.verify + assert_equal original_time.to_i, user.reload.verified_at.to_i + end end diff --git a/test/system/smoke_test.rb b/test/system/smoke_test.rb index c70d42e95..485fba810 100644 --- a/test/system/smoke_test.rb +++ b/test/system/smoke_test.rb @@ -15,6 +15,7 @@ class SmokeTest < ApplicationSystemTestCase send_keys :enter assert_selector "input[id=user_name]" + assert account.users.find_by!(identity:).verified?, "User was not properly verified" fill_in "Full name", with: "New Bee" click_on "Continue" From e174206233add17c8d1e1aa9efb03b70ad2a961a Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Fri, 5 Dec 2025 08:42:58 -0500 Subject: [PATCH 3/5] Add backfill script for verified_at timestamps Identifies users who have demonstrated authentication by looking for evidence of real activity: owners, content creators (cards, comments, boards, events), action takers (assigners, closers, postponers, reactors, pinners, filter creators), board accessors, export requesters, push subscribers, setup completers, and users with active sessions. Run this script after deploying the verified_at column to backfill existing users before enabling the notification guard. Co-Authored-By: Claude --- .../20251205-backfill-verified-at.rb | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100755 script/migrations/20251205-backfill-verified-at.rb diff --git a/script/migrations/20251205-backfill-verified-at.rb b/script/migrations/20251205-backfill-verified-at.rb new file mode 100755 index 000000000..7cd4f0030 --- /dev/null +++ b/script/migrations/20251205-backfill-verified-at.rb @@ -0,0 +1,112 @@ +#!/usr/bin/env ruby + +require_relative "../../config/environment" + +BACKFILL_TIMESTAMP = Time.parse("2025-12-02 12:00:00 UTC") + +def collect_verified_user_ids + verified_ids = Set.new + + # Owners (they created the account) + verified_ids.merge(User.where(role: :owner).pluck(:id)) + puts "After owners: #{verified_ids.size} users" + + # Card creators + verified_ids.merge(Card.distinct.pluck(:creator_id).compact) + puts "After card creators: #{verified_ids.size} users" + + # Comment creators + verified_ids.merge(Comment.distinct.pluck(:creator_id).compact) + puts "After comment creators: #{verified_ids.size} users" + + # Board creators + verified_ids.merge(Board.distinct.pluck(:creator_id).compact) + puts "After board creators: #{verified_ids.size} users" + + # Event creators + verified_ids.merge(Event.distinct.pluck(:creator_id).compact) + puts "After event creators: #{verified_ids.size} users" + + # Assigners (not assignees - they could be assigned without logging in) + verified_ids.merge(Assignment.distinct.pluck(:assigner_id).compact) + puts "After assigners: #{verified_ids.size} users" + + # Manual closers (user_id is nil for automatic closures) + verified_ids.merge(Closure.where.not(user_id: nil).distinct.pluck(:user_id).compact) + puts "After closers: #{verified_ids.size} users" + + # Manual postponers (user_id is nil for automatic entropy postponements) + verified_ids.merge(Card::NotNow.where.not(user_id: nil).distinct.pluck(:user_id).compact) + puts "After postponers: #{verified_ids.size} users" + + # Reactors + verified_ids.merge(Reaction.distinct.pluck(:reacter_id).compact) + puts "After reactors: #{verified_ids.size} users" + + # Filter creators + verified_ids.merge(Filter.distinct.pluck(:creator_id).compact) + puts "After filter creators: #{verified_ids.size} users" + + # Pinners + verified_ids.merge(Pin.distinct.pluck(:user_id).compact) + puts "After pinners: #{verified_ids.size} users" + + # Board accessors (accessed_at is touched when viewing boards) + verified_ids.merge(Access.where.not(accessed_at: nil).distinct.pluck(:user_id).compact) + puts "After board accessors: #{verified_ids.size} users" + + # Export requesters + verified_ids.merge(Account::Export.distinct.pluck(:user_id).compact) + puts "After export requesters: #{verified_ids.size} users" + + # Push subscribers + verified_ids.merge(Push::Subscription.distinct.pluck(:user_id).compact) + puts "After push subscribers: #{verified_ids.size} users" + + # Users who completed setup (name != email) + verified_ids.merge( + User.joins(:identity) + .where.not("users.name = identities.email_address") + .pluck(:id) + ) + puts "After setup completers: #{verified_ids.size} users" + + # Users whose identity has at least one session + verified_ids.merge( + User.where(identity_id: Session.distinct.select(:identity_id)).pluck(:id) + ) + puts "After identity sessions: #{verified_ids.size} users" + + verified_ids +end + +puts "Collecting verified user IDs..." +verified_user_ids = collect_verified_user_ids + +puts "\nFiltering to unverified users only..." +users_to_update = User.where(id: verified_user_ids.to_a) + .where(verified_at: nil) + .where(active: true) + .where.not(identity_id: nil) + .where.not(role: :system) + +update_count = users_to_update.count +puts "Found #{update_count} users to backfill" + +# Report remaining unverified users (before update) +remaining_before = User.where(verified_at: nil, active: true) + .where.not(identity_id: nil) + .where.not(role: :system) + .count +remaining_after = remaining_before - update_count +puts "\nCurrently unverified active users: #{remaining_before}" +puts "After backfill, remaining unverified: #{remaining_after}" +puts "These users will need to verify on next login." + +if update_count > 0 + puts "\nBackfilling verified_at..." + updated = users_to_update.update_all(verified_at: BACKFILL_TIMESTAMP) + puts "Updated #{updated} users" +end + +puts "\nDone!" From 1ad52d25906082f7c9ebac7bf3bf471a580bb620 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Fri, 5 Dec 2025 08:45:42 -0500 Subject: [PATCH 4/5] Only send notification emails to verified users Adds verified? check to bundling_emails? to prevent notification emails from being sent to users who have never authenticated. This closes the spam vector where bad actors could create users for known email addresses and trigger unwanted notifications by mentioning them. Co-Authored-By: Claude --- app/models/user/settings.rb | 2 +- test/models/user/settings_test.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/user/settings.rb b/app/models/user/settings.rb index 1651e9a64..598ede9c5 100644 --- a/app/models/user/settings.rb +++ b/app/models/user/settings.rb @@ -21,7 +21,7 @@ class User::Settings < ApplicationRecord end def bundling_emails? - !bundle_email_never? && !user.system? && user.active? + !bundle_email_never? && !user.system? && user.active? && user.verified? end def timezone diff --git a/test/models/user/settings_test.rb b/test/models/user/settings_test.rb index b72de92c5..69145c419 100644 --- a/test/models/user/settings_test.rb +++ b/test/models/user/settings_test.rb @@ -49,5 +49,9 @@ class User::SettingsTest < ActiveSupport::TestCase @user.update!(role: :member, active: false) assert_not @user.settings.bundling_emails?, "Inactive users should not receive bundled emails" + + @user.update!(active: true) + @user.update_column(:verified_at, nil) + assert_not @user.settings.bundling_emails?, "Unverified users should not receive bundled emails" end end From fc8ef333324a6b9d0a7a206050cd8287ef706178 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Fri, 5 Dec 2025 12:16:18 -0500 Subject: [PATCH 5/5] Show unverified status on user profile page Display "Unverified" with an explanation instead of the email address for users who haven't confirmed their identity. Hide the card links and activity timeline since unverified users won't have any activity. Co-Authored-By: Claude --- app/views/users/show.html.erb | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index eec6444a0..17f418e84 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -18,20 +18,25 @@

<%= @user.name %>

- <% if @user.active? %> - <%= mail_to @user.identity.email_address %> - <% else %> + <% if !@user.active? %> <%= @user.name %> is no longer on this account + <% elsif !@user.verified? %> + Unverified +
A sign-in code has been sent to this email address, but the user has not yet logged in to confirm their identity.
+ <% else %> + <%= mail_to @user.identity.email_address %> <% end %>
-
- <%= link_to "Which cards are assigned to #{me_or_you}?", - cards_path(assignee_ids: [ @user.id ], sorted_by: "newest"), class: "btn", data: { turbo_frame: "_top" } %> - <%= link_to "Which cards were added by #{me_or_you}?", - cards_path(creator_ids: [ @user.id ], sorted_by: "newest"), class: "btn", data: { turbo_frame: "_top" } %> -
+ <% if @user.verified? %> +
+ <%= link_to "Which cards are assigned to #{me_or_you}?", + cards_path(assignee_ids: [ @user.id ], sorted_by: "newest"), class: "btn", data: { turbo_frame: "_top" } %> + <%= link_to "Which cards were added by #{me_or_you}?", + cards_path(creator_ids: [ @user.id ], sorted_by: "newest"), class: "btn", data: { turbo_frame: "_top" } %> +
+ <% end %> @@ -48,4 +53,6 @@ <% end %> -<%= turbo_frame_tag "user_events", src: user_events_path(@user) %> +<% if @user.verified? %> + <%= turbo_frame_tag "user_events", src: user_events_path(@user) %> +<% end %>