mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -05:00
Minor changes
This commit is contained in:
parent
2af0147505
commit
e17f732706
13 changed files with 97 additions and 47 deletions
|
|
@ -76,7 +76,8 @@ class FamiliesController < ApplicationController
|
||||||
end
|
end
|
||||||
rescue Pundit::NotAuthorizedError
|
rescue Pundit::NotAuthorizedError
|
||||||
# Handle case where owner with members tries to leave
|
# Handle case where owner with members tries to leave
|
||||||
redirect_to family_path(@family), alert: 'You cannot leave the family while you are the owner and there are other members. Remove all members first or transfer ownership.'
|
redirect_to family_path(@family),
|
||||||
|
alert: 'You cannot leave the family while you are the owner and there are other members. Remove all members first or transfer ownership.'
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,7 @@ class FamilyInvitationsController < ApplicationController
|
||||||
)
|
)
|
||||||
|
|
||||||
if service.call
|
if service.call
|
||||||
current_user.reload
|
redirect_to family_path(current_user.reload.family), notice: 'Welcome to the family!'
|
||||||
redirect_to family_path(current_user.family), notice: 'Welcome to the family!'
|
|
||||||
else
|
else
|
||||||
redirect_to root_path, alert: service.error_message || 'Unable to accept invitation'
|
redirect_to root_path, alert: service.error_message || 'Unable to accept invitation'
|
||||||
end
|
end
|
||||||
|
|
@ -67,7 +66,8 @@ class FamilyInvitationsController < ApplicationController
|
||||||
|
|
||||||
def set_family
|
def set_family
|
||||||
@family = current_user.family
|
@family = current_user.family
|
||||||
redirect_to families_path unless @family
|
|
||||||
|
redirect_to families_path, alert: 'Family not found' and return unless @family
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_invitation
|
def set_invitation
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class User < ApplicationRecord # rubocop:disable Metrics/ClassLength
|
||||||
# Family associations
|
# Family associations
|
||||||
has_one :family_membership, dependent: :destroy
|
has_one :family_membership, dependent: :destroy
|
||||||
has_one :family, through: :family_membership
|
has_one :family, through: :family_membership
|
||||||
has_many :created_families, class_name: 'Family', foreign_key: 'creator_id', inverse_of: :creator, dependent: :destroy
|
has_one :created_family, class_name: 'Family', foreign_key: 'creator_id', inverse_of: :creator, dependent: :destroy
|
||||||
has_many :sent_family_invitations, class_name: 'FamilyInvitation', foreign_key: 'invited_by_id',
|
has_many :sent_family_invitations, class_name: 'FamilyInvitation', foreign_key: 'invited_by_id',
|
||||||
inverse_of: :invited_by, dependent: :destroy
|
inverse_of: :invited_by, dependent: :destroy
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,9 @@ module Families
|
||||||
class AcceptInvitation
|
class AcceptInvitation
|
||||||
attr_reader :invitation, :user, :error_message
|
attr_reader :invitation, :user, :error_message
|
||||||
|
|
||||||
def initialize(invitation:, user:, auto_leave: false)
|
def initialize(invitation:, user:)
|
||||||
@invitation = invitation
|
@invitation = invitation
|
||||||
@user = user
|
@user = user
|
||||||
@auto_leave = auto_leave
|
|
||||||
@error_message = nil
|
@error_message = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -15,17 +14,9 @@ module Families
|
||||||
return false unless can_accept?
|
return false unless can_accept?
|
||||||
|
|
||||||
if user.in_family?
|
if user.in_family?
|
||||||
if @auto_leave
|
|
||||||
leave_service = Families::Leave.new(user: user)
|
|
||||||
unless leave_service.call
|
|
||||||
@error_message = leave_service.error_message || 'Failed to leave current family.'
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
else
|
|
||||||
@error_message = 'You must leave your current family before joining a new one.'
|
@error_message = 'You must leave your current family before joining a new one.'
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
create_membership
|
create_membership
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@ module Families
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if user.created_family.present?
|
||||||
|
@errors[:user] = 'User has already created a family'
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
unless can_create_family?
|
unless can_create_family?
|
||||||
@errors[:base] = 'Cannot create family'
|
@errors[:base] = 'Cannot create family'
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,11 @@ module Families
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
|
||||||
def invite_sendable?
|
def invite_sendable?
|
||||||
return add_error_and_false(:invited_by, 'You must be a family owner to send invitations') unless invited_by.family_owner?
|
unless invited_by.family_owner?
|
||||||
|
return add_error_and_false(:invited_by,
|
||||||
|
'You must be a family owner to send invitations')
|
||||||
|
end
|
||||||
return add_error_and_false(:family, 'Family is full') if family.members.count >= Family::MAX_MEMBERS
|
return add_error_and_false(:family, 'Family is full') if family.members.count >= Family::MAX_MEMBERS
|
||||||
return add_error_and_false(:email, 'User is already in a family') if user_already_in_family?
|
return add_error_and_false(:email, 'User is already in a family') if user_already_in_family?
|
||||||
return add_error_and_false(:email, 'Invitation already sent to this email') if pending_invitation_exists?
|
return add_error_and_false(:email, 'Invitation already sent to this email') if pending_invitation_exists?
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,10 @@ module Families
|
||||||
|
|
||||||
def handle_ownership_transfer
|
def handle_ownership_transfer
|
||||||
# If this is the last member (owner), delete the family
|
# If this is the last member (owner), delete the family
|
||||||
if user.family.members.count == 1
|
return unless user.family.members.count == 1
|
||||||
|
|
||||||
user.family.destroy!
|
user.family.destroy!
|
||||||
end
|
|
||||||
# If owner tries to leave with other members, it should be prevented in validation
|
# If owner tries to leave with other members, it should be prevented in validation
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ RSpec.describe User, 'family methods', type: :model do
|
||||||
it { is_expected.to have_one(:family_membership).dependent(:destroy) }
|
it { is_expected.to have_one(:family_membership).dependent(:destroy) }
|
||||||
it { is_expected.to have_one(:family).through(:family_membership) }
|
it { is_expected.to have_one(:family).through(:family_membership) }
|
||||||
it {
|
it {
|
||||||
is_expected.to have_many(:created_families).class_name('Family').with_foreign_key('creator_id').dependent(:destroy)
|
is_expected.to have_one(:created_family).class_name('Family').with_foreign_key('creator_id').dependent(:destroy)
|
||||||
}
|
}
|
||||||
it {
|
it {
|
||||||
is_expected.to have_many(:sent_family_invitations).class_name('FamilyInvitation').with_foreign_key('invited_by_id').dependent(:destroy)
|
is_expected.to have_many(:sent_family_invitations).class_name('FamilyInvitation').with_foreign_key('invited_by_id').dependent(:destroy)
|
||||||
|
|
|
||||||
|
|
@ -41,14 +41,22 @@ RSpec.describe Families::AcceptInvitation do
|
||||||
context 'when user is already in another family' do
|
context 'when user is already in another family' do
|
||||||
let(:other_family) { create(:family) }
|
let(:other_family) { create(:family) }
|
||||||
let!(:existing_membership) { create(:family_membership, user: invitee, family: other_family) }
|
let!(:existing_membership) { create(:family_membership, user: invitee, family: other_family) }
|
||||||
let(:service) { described_class.new(invitation: invitation, user: invitee, auto_leave: true) }
|
|
||||||
|
|
||||||
it 'leaves current family before joining new one' do
|
it 'returns false' do
|
||||||
expect(Families::Leave).to receive(:new).with(user: invitee).and_call_original
|
expect(service.call).to be false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not create membership' do
|
||||||
|
expect { service.call }.not_to change(FamilyMembership, :count)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sets appropriate error message' do
|
||||||
service.call
|
service.call
|
||||||
|
expect(service.error_message).to eq('You must leave your current family before joining a new one.')
|
||||||
|
end
|
||||||
|
|
||||||
# Should have new membership in the invited family
|
it 'does not change user family' do
|
||||||
expect(invitee.reload.family).to eq(family)
|
expect { service.call }.not_to(change { invitee.reload.family })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,38 @@ RSpec.describe Families::Create do
|
||||||
it 'does not create a membership' do
|
it 'does not create a membership' do
|
||||||
expect { service.call }.not_to change(FamilyMembership, :count)
|
expect { service.call }.not_to change(FamilyMembership, :count)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'sets appropriate error message' do
|
||||||
|
service.call
|
||||||
|
expect(service.errors[:user]).to eq('User is already in a family')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when user has already created a family before' do
|
||||||
|
before do
|
||||||
|
# User creates and then deletes their family membership, but family still exists
|
||||||
|
old_family = create(:family, creator: user)
|
||||||
|
membership = create(:family_membership, user: user, family: old_family, role: :owner)
|
||||||
|
membership.destroy! # User leaves the family but family still exists
|
||||||
|
user.reload # Ensure user association is refreshed
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns false' do
|
||||||
|
expect(service.call).to be false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not create a family' do
|
||||||
|
expect { service.call }.not_to change(Family, :count)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not create a membership' do
|
||||||
|
expect { service.call }.not_to change(FamilyMembership, :count)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sets appropriate error message' do
|
||||||
|
service.call
|
||||||
|
expect(service.errors[:user]).to eq('User has already created a family')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@ RSpec.describe Families::Invite do
|
||||||
context 'when invitation is valid' do
|
context 'when invitation is valid' do
|
||||||
it 'creates an invitation' do
|
it 'creates an invitation' do
|
||||||
expect { service.call }.to change(FamilyInvitation, :count).by(1)
|
expect { service.call }.to change(FamilyInvitation, :count).by(1)
|
||||||
invitation = FamilyInvitation.last
|
|
||||||
|
invitation = owner.sent_family_invitations.last
|
||||||
|
|
||||||
expect(invitation.family).to eq(family)
|
expect(invitation.family).to eq(family)
|
||||||
expect(invitation.email).to eq(email)
|
expect(invitation.email).to eq(email)
|
||||||
expect(invitation.invited_by).to eq(owner)
|
expect(invitation.invited_by).to eq(owner)
|
||||||
|
|
@ -27,7 +29,9 @@ RSpec.describe Families::Invite do
|
||||||
|
|
||||||
it 'sends notification to inviter' do
|
it 'sends notification to inviter' do
|
||||||
expect { service.call }.to change(Notification, :count).by(1)
|
expect { service.call }.to change(Notification, :count).by(1)
|
||||||
notification = Notification.last
|
|
||||||
|
notification = owner.notifications.last
|
||||||
|
|
||||||
expect(notification.user).to eq(owner)
|
expect(notification.user).to eq(owner)
|
||||||
expect(notification.title).to eq('Invitation Sent')
|
expect(notification.title).to eq('Invitation Sent')
|
||||||
end
|
end
|
||||||
|
|
@ -116,7 +120,8 @@ RSpec.describe Families::Invite do
|
||||||
|
|
||||||
it 'normalizes email to lowercase and strips whitespace' do
|
it 'normalizes email to lowercase and strips whitespace' do
|
||||||
service.call
|
service.call
|
||||||
invitation = FamilyInvitation.last
|
invitation = family.family_invitations.last
|
||||||
|
|
||||||
expect(invitation.email).to eq('upper@example.com')
|
expect(invitation.email).to eq('upper@example.com')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,9 @@ RSpec.describe Families::Leave do
|
||||||
|
|
||||||
it 'sends notification' do
|
it 'sends notification' do
|
||||||
expect { service.call }.to change(Notification, :count).by(1)
|
expect { service.call }.to change(Notification, :count).by(1)
|
||||||
notification = Notification.last
|
|
||||||
expect(notification.user).to eq(member)
|
notification = member.notifications.last
|
||||||
|
|
||||||
expect(notification.title).to eq('Left Family')
|
expect(notification.title).to eq('Left Family')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -38,6 +39,10 @@ RSpec.describe Families::Leave do
|
||||||
expect(user.reload.family_membership).to be_nil
|
expect(user.reload.family_membership).to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'deletes the family' do
|
||||||
|
expect { service.call }.to change(Family, :count).by(-1)
|
||||||
|
end
|
||||||
|
|
||||||
it 'returns true' do
|
it 'returns true' do
|
||||||
expect(service.call).to be true
|
expect(service.call).to be true
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue