module Eco module API class MicroCases # Frees up `target_email` from an account not present in this org. # Allows to force `target_email` on the current user's account. # - If the person does not have account, this case will not do anything. # - If `original_doc["account"]` is `nil` (no account on server side), this case will not do anything. # - If the `target_email` and the `current_email` are the same or empty, this case will not do anything. # @note # - **It does not do the final update to the server to the `target_email`**. You will need to do this part yourself. # - You would call this function only when you got an error of `email already taken`. # - If the `target_email` is associated to a user in the same org, this will fail. # @param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. # @param dest_email [String, Proc] the email that we will move the other account to, when we free up `target_email`. # @param target_email [String] the email that we want to free up from another account and bring to ours. # If it's empty, the `person.email` will be used instead. # @param options [Hash] the options. # @param current_email [String] the email that the person's account is currently linked. # As the current email should be associated with this person's account on server side, we use `original_doc["email"]`. # @param context [String] main core part of logs. Provides context to the logs. def take_email_from_account(person, dest_email:, target_email: nil, options: {}, context: "Session") return false if options.dig(:exclude, :account) return false unless account = person.account return false unless had_account = person.original_doc["account"] target_email ||= person.email account_email = person.original_doc["email"] return false unless target_email != account_email return false if account_email.to_s.strip.empty? return false if target_email.to_s.strip.empty? if dest_email.is_a?(String) return false unless target_email != dest_email return false unless dest_email != account_email return false if dest_email.to_s.strip.empty? end account_json = _take_email_account_json(account) person.email = account_email if success = _take_email_remove_account!(person, context: context) if success = _take_email_acquire_account!(person, target_email, account: {}, context: context) if success = _take_email_email_free_up!(person, dest_email: dest_email, context: context) if success = _take_email_remove_account!(person, context: context) # Bring back the original account if success = _take_email_acquire_account!(person, account_email, account: account_json, context: context) success = true person.email = target_email end end else # free up target email # restore reverted = false if reverted ||= _take_email_remove_account!(person, context: context) reverted ||= _take_email_acquire_account!(person, account_email, account: account_json, context: context) end puts "Could not revert back to the original account #{person.identify}" unless reverted success = false end else # aquire other account # restore unless _take_email_acquire_account!(person, account_email, account: account_json, context: context) puts "Could not bring back the original account we want to update the email to '#{target_email}' #{person.identify}" end success = false end end success end private def _take_email_account_json(account) JSON.parse(account.to_json).tap do |hash| hash.delete("user_id") hash.delete("permissions_merged") hash.delete("permissions_preset") hash.delete("prefilter") if pref = hash["preferences"] hash["preferences"] = pref.reject do |attr, value| attr.start_with?("kiosk") end end end end # Bring the account of the `target_email` taken, so we can change the email of this account def _take_email_acquire_account!(person, target_email, account: {}, context: "Session") person.account = account person.account.send_invites = false person.email = target_email micro.person_update!(person, reason: "bring account with email '#{target_email}'", context: context) end # Free up the email (`target_email`) of the account that has it taken to `dest_email` def _take_email_email_free_up!(person, dest_email:, target_email: nil, context: "Session") target_email ||= person.email person.email = dest_email.is_a?(Proc)? dest_email.call(target_email) : dest_email reason = "free up email '#{target_email}', by moving account to '#{person.email}'" micro.person_update!(person, reason: reason, context: context) end def _take_email_remove_account!(person, context: "Session") person.account = nil micro.person_update!(person, reason: "remove account", context: context) end end end end