Skip to content

Commit

Permalink
Refactor existing Interactors
Browse files Browse the repository at this point in the history
  • Loading branch information
phil-l-brockwell committed Dec 9, 2024
1 parent 76ac523 commit 9a806a0
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 35 deletions.
102 changes: 86 additions & 16 deletions app/interactors/admin_actions/add_collaborator.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
module AdminActions
class AddCollaborator
attr_reader :form_answer,
:user,
:success,
:errors
attr_reader :account, :role, :transfer_form_answers, :new_owner_id, :collaborator, :success, :errors

def initialize(form_answer, user)
@form_answer = form_answer
@user = user
def initialize(account:, collaborator:, params:, existing_account: collaborator.account)
@account = account
@collaborator = collaborator
@existing_account = existing_account
@role = params.fetch(:role, "regular")
@transfer_form_answers = params.fetch(:transfer_form_answers, false)
@new_owner_id = params.fetch(:new_owner_id, nil)
@errors = []
end

def run
if user.can_be_added_to_collaborators_to_another_account?
persist!
if account_will_be_orphaned?
@errors << "User account has active users, ownership of the account must be transferred"
elsif progressed_form_answers_will_be_orphaned?
@errors << "User has applications in progress, and there are no other users on the account to transfer them to"
else
@errors = "can't be added as linked with another account!"
persist!
end

self
Expand All @@ -24,17 +28,83 @@ def success?
@success.present?
end

def error_messages
@errors.join(", ")
end

private

def persist!
user.role = "regular"
user.account = form_answer.account

if user.save
ActiveRecord::Base.transaction do
transfer_collaborator!
transfer_ownership!
handle_form_answers!
delete_existing_account!
@success = true
else
@errors = user.errors.full_messages.join(", ")
end
rescue ActiveRecord::RecordInvalid => e
@errors << e.message
end

def existing_account_has_other_collaborators?
return unless @existing_account

@existing_account.collaborators_without(collaborator).any?
end

def account_will_be_orphaned?
collaborator_is_owner? && existing_account_has_other_collaborators? && new_owner_id.blank?
end

def collaborator_is_owner?
return unless @existing_account

@existing_account.owner == collaborator
end

def progressed_form_answers_will_be_orphaned?
keep_form_answers_on_original_account? && progressed_form_answers? && !existing_account_has_other_collaborators?
end

def progressed_form_answers?
collaborator.form_answers.any? && collaborator.form_answers.any?(&:any_progress?)
end

def transfer_form_answers?
transfer_form_answers
end

def keep_form_answers_on_original_account?
!transfer_form_answers?
end

def handle_form_answers!
return unless @collaborator.form_answers.any?

if transfer_form_answers?
@collaborator.form_answers.each { |f| f.update!(account: @account) }
elsif existing_account_has_other_collaborators?
@collaborator.form_answers.each { |f| f.update!(user: @existing_account.owner) }
elsif !progressed_form_answers?
@collaborator.form_answers.each(&:destroy!)
end
end

def transfer_ownership!
return unless @new_owner_id

@existing_account.update!(owner_id: @new_owner_id)
end

def transfer_collaborator!
collaborator.update!(role: role, account: account)
end

def delete_existing_account!
return unless @existing_account
return if existing_account_has_other_collaborators?

@existing_account.destroy!
end
end
end
15 changes: 4 additions & 11 deletions app/interactors/admin_actions/search_collaborator_candidates.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
module AdminActions
class SearchCollaboratorCandidates
attr_accessor :form_answer,
:account,
:existing_collaborators,
:candidates,
:query,
:error
attr_accessor :account, :existing_collaborators, :candidates, :query, :error

def initialize(form_answer, query = nil)
@query = query[:query]
@form_answer = form_answer
@account = form_answer.account
@existing_collaborators = account.users
def initialize(existing_collaborators:, params: {})
@query = params[:query]
@existing_collaborators = existing_collaborators
end

def run
Expand Down
8 changes: 8 additions & 0 deletions app/models/form_answer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class FormAnswer < ApplicationRecord
},
}

ZERO_PROGRESS = 0.06666666666666667

POSSIBLE_AWARDS = [
"trade", # International Trade Award
"innovation", # Innovation Award
Expand Down Expand Up @@ -341,6 +343,12 @@ def fill_progress_in_percents
((fill_progress || 0) * 100).floor.to_s + "%"
end

def any_progress?
return unless fill_progress

fill_progress > ZERO_PROGRESS
end

def performance_years
case award_type
when "innovation"
Expand Down
8 changes: 0 additions & 8 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,6 @@ def reset_password_period_valid?
end
end

def can_be_added_to_collaborators_to_another_account?
account.blank? || (
account.present? &&
form_answers.blank? &&
account.form_answers.blank?
)
end

def new_member?
created_at > 3.days.ago
end
Expand Down
197 changes: 197 additions & 0 deletions spec/interactors/admin_actions/add_collaborator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
require "rails_helper"

describe AdminActions::AddCollaborator do
describe "#run" do
let(:result) { described_class.new(account:, collaborator:, params:, existing_account:).run }
let(:account) { create(:account) }
let(:collaborator) { create(:user, form_answers: form_answers, account: collaborator_account, role: "regular") }
let(:existing_account) { collaborator.account }
let(:collaborator_account) { create(:account) }
let(:collaborator_account_other_users) { [] }
let(:form_answers) { [] }
let(:params) { { role: role, transfer_form_answers: transfer_form_answers, new_owner_id: new_owner_id } }
let(:role) { "account_admin" }
let(:new_owner_id) { nil }

context "when transfer_form_answers is true" do
let(:transfer_form_answers) { true }

context "when the collaborator has form_answers" do
let(:form_answers) { create_list(:form_answer, 3) }

context "when the collaborator_account has no other users" do
it "transfers the collaborator and form_answers, and the collaborator account is deleted" do
expect(result).to be_success
expect(collaborator.account).to eq(account)
expect(collaborator.role).to eq(role)
expect { collaborator_account.reload }.to raise_error(ActiveRecord::RecordNotFound)
form_answers.each { |f| expect(f.account).to eq(account) }
end
end

context "when the collaborator_account has other users" do
let!(:collaborator_account_other_users) { create_list(:user, 2, account: collaborator_account) }
let(:new_owner_id) { collaborator_account_other_users.first.id }

it "transfers the collaborator and form_answers, and ownership of the collaborator account is transferred" do
expect(result).to be_success
expect(collaborator.account).to eq(account)
expect(collaborator.role).to eq(role)
expect(collaborator_account.owner).to eq(collaborator_account_other_users.first)
expect(collaborator_account.users).not_to include(collaborator)
form_answers.each { |f| expect(f.account).to eq(account) }
end
end
end
end

context "when transfer_form_answers is false" do
let(:transfer_form_answers) { false }

context "when the existing_account is nil" do
let(:existing_account) { nil }

it "transfers the collaborator" do
expect(result).to be_success
expect(collaborator.account).to eq(account)
expect(collaborator.role).to eq(role)
end
end

context "when the collaborator does not have form_answers" do
let(:form_answers) { [] }

it "transfers the collaborator and the collaborator account is deleted" do
expect(result).to be_success
expect(collaborator.account).to eq(account)
expect(collaborator.role).to eq(role)
expect { collaborator_account.reload }.to raise_error(ActiveRecord::RecordNotFound)
end

context "when the collaborator is the owner of the account" do
before do
collaborator_account.owner = collaborator
collaborator_account.save
end

it "transfers the collaborator and the collaborator account is deleted" do
expect(result).to be_success
expect(collaborator.account).to eq(account)
expect(collaborator.role).to eq(role)
expect { collaborator_account.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end

context "when the collaborator_account has other users" do
let!(:collaborator_account_other_users) { create_list(:user, 2, account: collaborator_account) }

it "transfers the collaborator and the collaborator account is not deleted" do
expect(result).to be_success
expect(collaborator.account).to eq(account)
expect(collaborator.role).to eq(role)
expect(collaborator_account.users).to eq(collaborator_account_other_users)
end

context "when the collaborator is the owner of the account" do
let(:new_owner_id) { collaborator_account_other_users.first.id }

before do
collaborator_account.owner = collaborator
collaborator_account.save
end

it "transfers the collaborator and ownership of the collaborator_account" do
expect(result).to be_success
expect(collaborator.account).to eq(account)
expect(collaborator.role).to eq(role)
expect(collaborator_account.owner).to eq(collaborator_account_other_users.first)
expect(collaborator_account.users).not_to include(collaborator)
end

context "when the new_owner_id is not specified" do
let(:new_owner_id) { nil }

it "is not a success" do
expect(result).not_to be_success
expect(result.error_messages)
.to eq("User account has active users, ownership of the account must be transferred")
expect(collaborator.account).to eq(collaborator_account)
end
end

context "when an invalid new_owner_id is specified" do
let(:new_owner_id) { 1000 }

it "is not a success" do
expect(result).not_to be_success
expect(result.error_messages)
.to eq("Validation failed: Owner Owner is empty - it is a required field and must be filled in")
expect(collaborator.reload.account).to eq(collaborator_account)
end
end
end
end
end
context "when the collaborator has form_answers" do
let(:form_answers) { create_list(:form_answer, 3) }

context "when the collaborator_account has no other users" do
it "transfers the collaborator, and the collaborator account and form_answers are deleted" do
expect(result).to be_success
expect(collaborator.account).to eq(account)
expect(collaborator.role).to eq(role)
expect { collaborator_account.reload }.to raise_error(ActiveRecord::RecordNotFound)
form_answers.each { |f| expect { f.reload }.to raise_error(ActiveRecord::RecordNotFound) }
end
end

context "when the form_answers are in progress" do
let(:form_answers) { create_list(:form_answer, 3, :development) }

context "when the collaborator_account has other users" do
let!(:collaborator_account_other_users) { create_list(:user, 2, account: collaborator_account) }

context "when the new_owner_id is specified" do
let(:new_owner_id) { collaborator_account_other_users.first.id }

it "transfers the collaborator and ownership of the form_answers to the new owner" do
expect(result).to be_success
expect(collaborator.account).to eq(account)
expect(collaborator.role).to eq(role)
expect(collaborator_account.owner).to eq(collaborator_account_other_users.first)
form_answers.each { |f| expect(f.user).to eq(collaborator_account_other_users.first) }
expect(collaborator_account.users).not_to include(collaborator)
end
end

context "when the new_owner_id is not specified" do
let(:new_owner_id) { nil }

before do
collaborator_account.owner = collaborator_account_other_users.first
collaborator_account.save
end

it "transfers the collaborator and ownership of the form_answers to the existing owner" do
expect(result).to be_success
expect(collaborator.account).to eq(account)
expect(collaborator.role).to eq(role)
expect(collaborator_account.users).not_to include(collaborator)
form_answers.each { |f| expect(f.user).to eq(collaborator_account_other_users.first) }
end
end
end

context "when the collaborator_account has no other users" do
it "is not a success" do
expect(result).not_to be_success
expect(result.error_messages)
.to eq("User has applications in progress, and there are no other users on the account to transfer them to")
expect(collaborator.account).to eq(collaborator_account)
end
end
end
end
end
end
end

0 comments on commit 9a806a0

Please sign in to comment.