New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ability to delete a team #877
Conversation
|
||
delegate :team, :new_team, :user, to: :context | ||
|
||
def call |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Method call
has a Cognitive Complexity of 8 (exceeds 5 allowed). Consider refactoring.
@@ -36,6 +36,9 @@ Style/TrailingCommaInArguments: | |||
Rails/HelperInstanceVariable: | |||
Enabled: false | |||
|
|||
Lint/AmbiguousBlockAssociation: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disabled this because fixing it introduces syntax errors: rubocop/rubocop#4222
@@ -1,6 +1,6 @@ | |||
module Investigations::UserFiltersHelper | |||
def entities | |||
User.get_owners(except: current_user).decorate + Team.all_with_organisation.decorate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We no longer need the team organisation. This was previously used in the display_name
method but was changed a while ago to no longer require it.
class DeleteTeam | ||
include Interactor | ||
|
||
delegate :team, :new_team, :user, to: :context |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest rewording this to be clearer that it’s deleting a team and merging all its users & cases into another team:
class DeleteTeam | |
include Interactor | |
delegate :team, :new_team, :user, to: :context | |
class MergeTeams | |
include Interactor | |
delegate :team_to_delete, :team_to_keep, :user, to: :context |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 not sure about this. The merging is the thing you have to do to accomplish the team deletion.
app/services/delete_team.rb
Outdated
def change_case_owner_to_new_team(collaboration) | ||
ChangeCaseOwner.call!( | ||
investigation: collaboration.investigation, | ||
owner: new_team, | ||
user: user, | ||
rationale: change_case_owner_rationale, | ||
silent: true | ||
) | ||
end | ||
|
||
def change_case_owner_team(collaboration) | ||
collaboration.update!(collaborator_id: new_team.id) | ||
|
||
metadata = update_owner_activity_class.build_metadata(new_team, change_case_owner_rationale) | ||
|
||
update_owner_activity_class.create!( | ||
source: UserSource.new(user: user), | ||
investigation: collaboration.investigation, | ||
title: nil, | ||
body: nil, | ||
metadata: metadata | ||
) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These method names are so similar it's kinda hard to follow. I think I understand what’s going on, but it's taken a bit of head-scratching. I don't have any immediate suggestions on how to make it clearer though. 😬
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. I'll try to think of better names.
|
||
def change | ||
add_column :teams, :deleted_at, :datetime | ||
add_index :teams, :deleted_at, algorithm: :concurrently |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if a partial index would be helpful here, as we'd normally be querying for non-deleted teams?
add_index :teams, :deleted_at, algorithm: :concurrently | |
add_index :teams, :deleted_at, name: 'not_deleted_index', where: {deleted_at: nil), algorithm: :concurrently |
(Probably marginal gains at our scale though)
# Check deleted teams are not listed | ||
expect(page).to have_css("#team option[value=\"#{team.id}\"]") | ||
expect(page).not_to have_css("#team option[value=\"#{deleted_team.id}\"]") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use the Capybara method here to check the values of the select?
# Check deleted teams are not listed | |
expect(page).to have_css("#team option[value=\"#{team.id}\"]") | |
expect(page).not_to have_css("#team option[value=\"#{deleted_team.id}\"]") | |
# Check deleted teams are not listed | |
expect(page).not_to have_select("Select other team name", with_options: [deleted_team.name]) | |
expect(page).to have_select("Select other team name", with_options: [team.name]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good as expected!
app/services/delete_team.rb
Outdated
context.fail!(error: "No team supplied") unless team.is_a?(Team) | ||
context.fail!(error: "No new team supplied to absorb cases and users") unless new_team.is_a?(Team) | ||
context.fail!(error: "No user supplied") unless user.is_a?(User) | ||
context.fail!(error: "Team cannot already be deleted") if team.deleted? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
context.fail!(error: "Team cannot already be deleted") if team.deleted? | |
context.fail!(error: "Team already deleted") if team.deleted? |
app/services/delete_team.rb
Outdated
context.fail!(error: "No new team supplied to absorb cases and users") unless new_team.is_a?(Team) | ||
context.fail!(error: "No user supplied") unless user.is_a?(User) | ||
context.fail!(error: "Team cannot already be deleted") if team.deleted? | ||
context.fail!(error: "New team cannot already be deleted") if new_team.deleted? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
context.fail!(error: "New team cannot already be deleted") if new_team.deleted? | |
context.fail!(error: "New team already be deleted") if new_team.deleted? |
app/services/delete_team.rb
Outdated
end | ||
|
||
def new_team_already_collaborating?(investigation) | ||
investigation.collaboration_accesses.find_by(collaborator_id: new_team.id).present? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
investigation.collaboration_accesses.find_by(collaborator_id: new_team.id).present? | |
investigation.collaboration_accesses.where(collaborator: new_team).exists? |
lib/tasks/delete_team.rake
Outdated
namespace :team do | ||
desc "Marks the given team as deleted, assigning their cases and users to another team" | ||
task delete: :environment do | ||
team = Team.find(ENV.fetch("ID", nil)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
team = Team.find(ENV.fetch("ID", nil)) | |
team = Team.find(ENV["ID"]) |
doc/tasks.md
Outdated
cf run-task psd-web "export \$(./env/get-env-from-vcap.sh) && ID=<id> NEW_TEAM_ID=<id> EMAIL=<email address> rake team:delete" --name <task name> | ||
``` | ||
|
||
Case collaborations and users which belong to the team identified by `ID` will be migrated to another team identified by `NEW_TEAM`. The user identified by `EMAIL` will be attributed to the change on all relevant audit activity. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Case collaborations and users which belong to the team identified by `ID` will be migrated to another team identified by `NEW_TEAM`. The user identified by `EMAIL` will be attributed to the change on all relevant audit activity. | |
Case collaborations and users which belong to the team identified by `ID` will be migrated to another team identified by `NEW_TEAM_ID`. The user identified by `EMAIL` will be attributed to the change on all relevant audit activity. |
expect(page).to have_css("#created_by_someone_else_id option[value=\"#{another_active_user.id}\"]") | ||
expect(page).not_to have_css("#created_by_someone_else_id option[value=\"#{another_inactive_user.id}\"]") | ||
expect(page).not_to have_css("#created_by_someone_else_id option[value=\"#{other_deleted_team.id}\"]") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as @frankieroberto comment above, you could use the have_select(team.name)
, that would also test that the value in the drop down is the one team name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refactored the other existing expectations as well, looks a lot better.
|
||
context "when the new team is not already a collaborator on the case" do | ||
it "adds the new team to the case with the same access level as the old team" do | ||
expect { delete_team }.to change { other_team_case.reload.teams_with_read_only_access }.from([team]).to([new_team]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expect { delete_team }.to change { other_team_case.reload.teams_with_read_only_access }.from([team]).to([new_team]) | |
expect { delete_team }.to change(other_team_case, :teams_with_read_only_access).from([team]).to([new_team]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't work. Need reload
.
https://trello.com/c/FRRtOhuq/668-5-absorb-opss-product-safety-enforcement-into-opss-enforcement
Description
This allows us to delete a team from service.
When a team is deleted:
In our initial use case this process would ordinarily generate many hundreds of emails to the affected users. This implementation suppresses those emails. This could be made optional in a future iteration.
Checklist:
General testing (author)
Accessibility testing (author)