mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 01:01:39 -05:00
Make sure family invitations are handled after sign-in
This commit is contained in:
parent
4f4ac08caf
commit
d23e118645
3 changed files with 85 additions and 14 deletions
|
|
@ -40,6 +40,14 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
# Check for family invitation first
|
||||
invitation_token = params[:invitation_token] || session[:invitation_token]
|
||||
if invitation_token.present?
|
||||
invitation = Family::Invitation.find_by(token: invitation_token)
|
||||
return family_invitation_path(invitation.token) if invitation&.can_be_accepted?
|
||||
end
|
||||
|
||||
# Handle iOS client flow
|
||||
client_type = request.headers['X-Dawarich-Client'] || session[:dawarich_client]
|
||||
|
||||
case client_type
|
||||
|
|
|
|||
|
|
@ -7,26 +7,14 @@ class Users::SessionsController < Devise::SessionsController
|
|||
super
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
if invitation_token.present?
|
||||
invitation = Family::Invitation.find_by(token: invitation_token)
|
||||
|
||||
if invitation&.can_be_accepted?
|
||||
return family_invitation_path(invitation.token)
|
||||
end
|
||||
end
|
||||
|
||||
super(resource)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_invitation_context
|
||||
return unless invitation_token.present?
|
||||
|
||||
@invitation = Family::Invitation.find_by(token: invitation_token)
|
||||
# Store token in session so it persists through the sign-in process
|
||||
session[:invitation_token] = invitation_token if invitation_token.present?
|
||||
end
|
||||
|
||||
def invitation_token
|
||||
|
|
|
|||
|
|
@ -166,4 +166,79 @@ RSpec.describe 'Authentication', type: :request do
|
|||
expect(response.location).not_to include('auth/ios/success')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Family Invitation with Authentication' do
|
||||
let(:family) { create(:family, creator: user) }
|
||||
let!(:membership) { create(:family_membership, user: user, family: family, role: :owner) }
|
||||
let(:invitee) { create(:user, email: 'invitee@example.com', password: 'password123') }
|
||||
let(:invitation) { create(:family_invitation, family: family, invited_by: user, email: invitee.email) }
|
||||
|
||||
it 'redirects to invitation page when signing in with invitation token in params' do
|
||||
post user_session_path, params: {
|
||||
user: { email: invitee.email, password: 'password123' },
|
||||
invitation_token: invitation.token
|
||||
}
|
||||
|
||||
expect(response).to redirect_to(family_invitation_path(invitation.token))
|
||||
end
|
||||
|
||||
it 'redirects to invitation page when signing in with invitation token in session' do
|
||||
# The invitation token is stored in session by Users::SessionsController#load_invitation_context
|
||||
# when accessing the sign-in page with invitation_token param
|
||||
get new_user_session_path, params: { invitation_token: invitation.token }
|
||||
|
||||
# Then sign in without the invitation_token in params (should use session value)
|
||||
post user_session_path, params: {
|
||||
user: { email: invitee.email, password: 'password123' }
|
||||
}
|
||||
|
||||
expect(response).to redirect_to(family_invitation_path(invitation.token))
|
||||
end
|
||||
|
||||
it 'prioritizes invitation over iOS flow when both are present' do
|
||||
# Sign in with both iOS header AND invitation token
|
||||
post user_session_path, params: {
|
||||
user: { email: invitee.email, password: 'password123' },
|
||||
invitation_token: invitation.token
|
||||
}, headers: {
|
||||
'X-Dawarich-Client' => 'ios'
|
||||
}
|
||||
|
||||
# Should redirect to invitation page, NOT iOS success
|
||||
expect(response).to redirect_to(family_invitation_path(invitation.token))
|
||||
expect(response.location).not_to include('auth/ios/success')
|
||||
end
|
||||
|
||||
it 'redirects to iOS success when invitation is expired' do
|
||||
# Create an expired invitation
|
||||
expired_invitation = create(:family_invitation,
|
||||
family: family,
|
||||
invited_by: user,
|
||||
email: invitee.email,
|
||||
expires_at: 1.day.ago)
|
||||
|
||||
# Sign in with iOS header and expired invitation token
|
||||
post user_session_path, params: {
|
||||
user: { email: invitee.email, password: 'password123' },
|
||||
invitation_token: expired_invitation.token
|
||||
}, headers: {
|
||||
'X-Dawarich-Client' => 'ios'
|
||||
}
|
||||
|
||||
# Should redirect to iOS success since invitation can't be accepted
|
||||
expect(response).to redirect_to(%r{auth/ios/success\?token=})
|
||||
end
|
||||
|
||||
it 'uses default path when invitation token is invalid' do
|
||||
# Sign in with invalid invitation token
|
||||
post user_session_path, params: {
|
||||
user: { email: invitee.email, password: 'password123' },
|
||||
invitation_token: 'invalid-token-123'
|
||||
}
|
||||
|
||||
# Should use default redirect path
|
||||
expect(response).not_to redirect_to(%r{/invitations/})
|
||||
expect(response).to redirect_to(root_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue