dawarich/app/services/families/memberships/destroy.rb

181 lines
5.1 KiB
Ruby
Raw Normal View History

2025-10-04 16:39:47 -04:00
# frozen_string_literal: true
module Families
module Memberships
class Destroy
attr_reader :user, :member_to_remove, :error_message
2025-10-11 08:17:48 -04:00
def initialize(user:, member_to_remove: nil)
@user = user # The user performing the action (current_user)
@member_to_remove = member_to_remove || user # The user being removed (defaults to self)
@error_message = nil
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def call
return false unless validate_can_leave
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
# Store family info before removing membership
@family_name = member_to_remove.family.name
@family_owner = member_to_remove.family.owner
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
ActiveRecord::Base.transaction do
handle_ownership_transfer if member_to_remove.family_owner?
remove_membership
send_notifications
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
true
rescue ActiveRecord::RecordInvalid => e
handle_record_invalid_error(e)
false
rescue StandardError => e
handle_generic_error(e)
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
false
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
private
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def validate_can_leave
return false unless validate_in_family
return false unless validate_removal_allowed
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
true
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def validate_in_family
return true if member_to_remove.in_family?
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
@error_message = 'User is not currently in a family.'
false
2025-10-04 16:39:47 -04:00
end
2025-10-11 08:17:48 -04:00
def validate_removal_allowed
# If removing self (user == member_to_remove)
return validate_owner_can_leave if removing_self?
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
# If removing another member, user must be owner and member must be in same family
return false unless validate_remover_is_owner
return false unless validate_same_family
return false unless validate_not_removing_owner
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
true
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def removing_self?
user == member_to_remove
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def validate_owner_can_leave
return true unless member_to_remove.family_owner?
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
@error_message = 'Family owners cannot remove their own membership. To leave the family, delete it instead.'
false
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def validate_remover_is_owner
return true if user.family_owner?
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
@error_message = 'Only family owners can remove other members.'
false
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def validate_same_family
return true if user.family == member_to_remove.family
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
@error_message = 'Cannot remove members from a different family.'
false
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def validate_not_removing_owner
return true unless member_to_remove.family_owner?
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
@error_message = 'Cannot remove the family owner. The owner must delete the family or leave on their own.'
false
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def family_has_other_members?
member_to_remove.family.members.count > 1
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def handle_ownership_transfer
# If this is the last member (owner), delete the family
return unless member_to_remove.family.members.count == 1
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
member_to_remove.family.destroy!
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
# If owner tries to leave with other members, it should be prevented in validation
end
def remove_membership
member_to_remove.family_membership.destroy!
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def send_notifications
return unless defined?(Notification)
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
if removing_self?
send_self_removal_notifications
else
send_member_removed_notifications
end
2025-10-04 16:39:47 -04:00
end
2025-10-11 08:17:48 -04:00
def send_self_removal_notifications
# Notify the user who left
Notification.create!(
user: member_to_remove,
kind: :info,
title: 'Left Family',
content: "You've left the family \"#{@family_name}\""
)
# Notify the family owner
return unless @family_owner&.persisted?
Notification.create!(
user: @family_owner,
kind: :info,
title: 'Family Member Left',
content: "#{member_to_remove.email} has left the family \"#{@family_name}\""
)
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def send_member_removed_notifications
# Notify the member who was removed
Notification.create!(
user: member_to_remove,
kind: :info,
title: 'Removed from Family',
content: "You have been removed from the family \"#{@family_name}\" by #{user.email}"
)
# Notify the owner who removed the member (if different from the member)
return unless user != member_to_remove
Notification.create!(
user: user,
kind: :info,
title: 'Member Removed',
content: "#{member_to_remove.email} has been removed from the family \"#{@family_name}\""
)
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def handle_record_invalid_error(error)
@error_message =
if error.record&.errors&.any?
error.record.errors.full_messages.first
else
"Failed to leave family: #{error.message}"
end
end
2025-10-04 16:39:47 -04:00
2025-10-11 08:17:48 -04:00
def handle_generic_error(error)
ExceptionReporter.call(error, "Unexpected error in Families::Memberships::Destroy: #{error.message}")
@error_message = 'An unexpected error occurred while removing the membership. Please try again'
end
2025-10-04 16:39:47 -04:00
end
end
end