mirror of
https://github.com/we-promise/sure.git
synced 2026-07-16 14:55:23 +00:00
* fix: share family accounts with invited members on every sign-up path A user who joined an existing family through an invitation was added to the family but saw none of its accounts, even when the family's default sharing is "share with all members". Only Invitation#accept_for created the AccountShare records; the OIDC just-in-time sign-up, invite-token registration, and mobile SSO onboarding paths all skipped it, so invitees landed in the family with an empty account list. Signups routed into an invite-only default family had the same gap. Extract the sharing into Family#auto_share_existing_accounts_with, the single entry point for "a member just joined, apply the family's sharing policy". It honors default_account_sharing, only shares with a persisted member of the family, grants read_only to guests and read_write to everyone else, excludes accounts the user already owns, and is idempotent. accept_for and every sign-up path call it, so no current or future join path can reintroduce the empty-account bug or share accounts across families. Also wrap the two SSO account-creation paths (OIDC JIT and mobile SSO) in a transaction covering the user save, invitation acceptance, account sharing, and identity creation, so a failure partway through can no longer leave a half-onboarded user with no linked identity. * address review: guest read_only symmetric in auto_share_with_family!, load-bearing guard comment, mobile SSO private-no-op test
176 lines
5.7 KiB
Ruby
176 lines
5.7 KiB
Ruby
require "test_helper"
|
|
|
|
class RegistrationsControllerTest < ActionDispatch::IntegrationTest
|
|
test "new" do
|
|
get new_registration_url
|
|
assert_response :success
|
|
end
|
|
|
|
test "create redirects to correct URL" do
|
|
post registration_url, params: { user: {
|
|
email: "john@example.com",
|
|
password: "Password1!" } }
|
|
|
|
assert_redirected_to root_url
|
|
end
|
|
|
|
test "first user of instance becomes super_admin" do
|
|
# Clear all users to simulate fresh instance
|
|
User.destroy_all
|
|
|
|
assert_difference "User.count", +1 do
|
|
post registration_url, params: { user: {
|
|
email: "firstuser@example.com",
|
|
password: "Password1!" } }
|
|
end
|
|
|
|
first_user = User.find_by(email: "firstuser@example.com")
|
|
assert first_user.super_admin?, "First user should be super_admin"
|
|
end
|
|
|
|
test "subsequent users become admin not super_admin" do
|
|
# Ensure users exist from fixtures
|
|
assert User.exists?
|
|
|
|
assert_difference "User.count", +1 do
|
|
post registration_url, params: { user: {
|
|
email: "seconduser@example.com",
|
|
password: "Password1!" } }
|
|
end
|
|
|
|
new_user = User.find_by(email: "seconduser@example.com")
|
|
assert new_user.admin?, "Subsequent user should be admin"
|
|
assert_not new_user.super_admin?, "Subsequent user should not be super_admin"
|
|
end
|
|
|
|
test "create when hosted requires an invite code" do
|
|
with_env_overrides REQUIRE_INVITE_CODE: "true" do
|
|
assert_no_difference "User.count" do
|
|
post registration_url, params: { user: {
|
|
email: "john@example.com",
|
|
password: "Password1!" } }
|
|
assert_redirected_to new_registration_url
|
|
|
|
post registration_url, params: { user: {
|
|
email: "john@example.com",
|
|
password: "Password1!",
|
|
invite_code: "foo" } }
|
|
assert_redirected_to new_registration_url
|
|
end
|
|
|
|
assert_difference "User.count", +1 do
|
|
invite_code = InviteCode.generate!
|
|
post registration_url, params: { user: {
|
|
email: "john@example.com",
|
|
password: "Password1!",
|
|
invite_code: invite_code } }
|
|
assert_redirected_to root_url
|
|
assert_not InviteCode.exists?(token: invite_code)
|
|
end
|
|
end
|
|
end
|
|
|
|
test "invite code is not consumed when signup fails validation" do
|
|
with_env_overrides REQUIRE_INVITE_CODE: "true" do
|
|
invite_code = InviteCode.generate!
|
|
|
|
assert_no_difference "User.count" do
|
|
post registration_url, params: { user: {
|
|
email: "validationfail@example.com",
|
|
password: "weak",
|
|
invite_code: invite_code } }
|
|
end
|
|
|
|
assert_response :unprocessable_entity
|
|
assert InviteCode.exists?(token: invite_code)
|
|
end
|
|
end
|
|
|
|
test "invalid invite code does not create a user" do
|
|
with_env_overrides REQUIRE_INVITE_CODE: "true" do
|
|
assert_no_difference "User.count" do
|
|
post registration_url, params: { user: {
|
|
email: "valid@example.com",
|
|
password: "Password1!",
|
|
invite_code: "invalid-token-that-does-not-exist" } }
|
|
end
|
|
|
|
assert_redirected_to new_registration_url
|
|
end
|
|
end
|
|
|
|
test "creating account from guest invitation assigns guest role and intro layout" do
|
|
invitation = invitations(:one)
|
|
invitation.update!(role: "guest", email: "guest-signup@example.com")
|
|
|
|
assert_difference "User.count", +1 do
|
|
post registration_url, params: { user: {
|
|
email: invitation.email,
|
|
password: "Password1!",
|
|
invitation: invitation.token
|
|
} }
|
|
end
|
|
|
|
created_user = User.find_by(email: invitation.email)
|
|
assert_equal "guest", created_user.role
|
|
assert created_user.ui_layout_intro?
|
|
assert_not created_user.show_sidebar?
|
|
assert_not created_user.show_ai_sidebar?
|
|
assert created_user.ai_enabled?
|
|
end
|
|
|
|
test "creating account from invitation shares existing family accounts when family shares by default" do
|
|
invitation = invitations(:one)
|
|
invitation.family.update!(default_account_sharing: "shared")
|
|
|
|
post registration_url, params: { user: {
|
|
email: invitation.email,
|
|
password: "Password1!",
|
|
invitation: invitation.token
|
|
} }
|
|
|
|
created_user = User.find_by(email: invitation.email)
|
|
assert_not_nil created_user
|
|
assert_equal invitation.family_id, created_user.family_id
|
|
assert_equal invitation.family.accounts.pluck(:id).sort,
|
|
AccountShare.where(user: created_user).pluck(:account_id).sort
|
|
end
|
|
|
|
test "creating account in invite-only default family shares existing family accounts" do
|
|
family = families(:dylan_family)
|
|
family.update!(default_account_sharing: "shared")
|
|
Setting.onboarding_state = "invite_only"
|
|
Setting.invite_only_default_family_id = family.id
|
|
|
|
assert_difference "User.count", +1 do
|
|
post registration_url, params: { user: {
|
|
email: "default-family-signup@example.com",
|
|
password: "Password1!"
|
|
} }
|
|
end
|
|
|
|
created_user = User.find_by(email: "default-family-signup@example.com")
|
|
assert_not_nil created_user
|
|
assert_equal family.id, created_user.family_id
|
|
assert_equal "member", created_user.role
|
|
assert_equal family.accounts.pluck(:id).sort,
|
|
AccountShare.where(user: created_user).pluck(:account_id).sort
|
|
assert AccountShare.where(user: created_user).all?(&:read_write?)
|
|
end
|
|
|
|
test "creating account from invitation shares nothing when family sharing is private" do
|
|
invitation = invitations(:one)
|
|
invitation.family.update!(default_account_sharing: "private")
|
|
|
|
post registration_url, params: { user: {
|
|
email: invitation.email,
|
|
password: "Password1!",
|
|
invitation: invitation.token
|
|
} }
|
|
|
|
created_user = User.find_by(email: invitation.email)
|
|
assert_not_nil created_user
|
|
assert_equal 0, AccountShare.where(user: created_user).count
|
|
end
|
|
end
|