diff --git a/psd-web/app/controllers/investigations/ownership_controller.rb b/psd-web/app/controllers/investigations/ownership_controller.rb index dc638ff805..516bbebad2 100644 --- a/psd-web/app/controllers/investigations/ownership_controller.rb +++ b/psd-web/app/controllers/investigations/ownership_controller.rb @@ -2,42 +2,37 @@ class Investigations::OwnershipController < ApplicationController include Wicked::Wizard before_action :set_investigation before_action :authorize_user - before_action :potential_owner, only: %i[show create] - before_action :store_owner, only: %i[update] steps :"select-owner", :confirm def show - @potential_owner = potential_owner&.decorate + @potential_owner = form.owner&.decorate render_wizard end def new - clear_session + session[session_store_key] = nil redirect_to wizard_path(steps.first, request.query_parameters) end def update - if owner_valid? - redirect_to next_wizard_path - else - render_wizard - end + return render_wizard unless form.valid? + + session[session_store_key] = form.attributes.compact + redirect_to next_wizard_path end def create - @investigation.owner = potential_owner - @investigation.owner_rationale = params[:investigation][:owner_rationale] - @investigation.save - redirect_to investigation_path(@investigation), flash: { success: "#{@investigation.case_type.upcase_first} owner changed to #{potential_owner.decorate.display_name}" } - end + ChangeCaseOwner.call!(investigation: @investigation, owner: form.owner, rationale: form.owner_rationale, user: current_user) -private + session[session_store_key] = nil - def clear_session - session[:owner_id] = nil + message = "#{@investigation.case_type.upcase_first} owner changed to #{form.owner.decorate.display_name(viewer: current_user)}" + redirect_to investigation_path(@investigation), flash: { success: message } end +private + def set_investigation @investigation = Investigation.find_by!(pretty_id: params[:investigation_pretty_id]).decorate end @@ -46,7 +41,12 @@ def authorize_user authorize @investigation, :change_owner_or_status? end - def owner_params + def session_store_key + "update_case_owner_#{@investigation.pretty_id}_params" + end + + def form_params + params[:investigation] ||= {} params[:investigation][:owner_id] = case params[:investigation][:owner_id] when "someone_in_your_team" params[:investigation][:select_team_member] @@ -59,23 +59,14 @@ def owner_params else params[:investigation][:owner_id] end - params.require(:investigation).permit(:owner_id) - end - - def store_owner - session[:owner_id] = owner_params[:owner_id] + params.require(:investigation).permit(:owner_id, :owner_rationale).merge(session_params) end - def owner_valid? - if step == :"select-owner" - if potential_owner.nil? - @investigation.errors.add(:owner_id, :invalid, message: "Select case owner") - end - end - @investigation.errors.empty? + def session_params + session[session_store_key] || {} end - def potential_owner - User.find_by(id: session[:owner_id]) || Team.find_by(id: session[:owner_id]) + def form + @form ||= ChangeCaseOwnerForm.new(form_params) end end diff --git a/psd-web/app/controllers/investigations_controller.rb b/psd-web/app/controllers/investigations_controller.rb index f4736766bb..e0e4504297 100644 --- a/psd-web/app/controllers/investigations_controller.rb +++ b/psd-web/app/controllers/investigations_controller.rb @@ -124,6 +124,6 @@ def build_breadcrumbs end def set_suggested_previous_owners - @suggested_previous_owners = suggested_previous_owners + @suggested_previous_owners = suggested_previous_owners(@investigation) end end diff --git a/psd-web/app/forms/change_case_owner_form.rb b/psd-web/app/forms/change_case_owner_form.rb new file mode 100644 index 0000000000..76e76c1f1b --- /dev/null +++ b/psd-web/app/forms/change_case_owner_form.rb @@ -0,0 +1,28 @@ +class ChangeCaseOwnerForm + include ActiveModel::Model + include ActiveModel::Attributes + + attribute :owner_id + attribute :owner_rationale + + validates_presence_of :owner_id + validate :new_owner_must_be_active_user_or_team, if: -> { owner_id.present? } + + def owner + user || team + end + +private + + def new_owner_must_be_active_user_or_team + errors.add(:owner_id, :not_found) unless owner + end + + def user + @user ||= User.active.find_by(id: owner_id) + end + + def team + @team ||= Team.find_by(id: owner_id) + end +end diff --git a/psd-web/app/helpers/investigations_helper.rb b/psd-web/app/helpers/investigations_helper.rb index d01280995c..874b172a17 100644 --- a/psd-web/app/helpers/investigations_helper.rb +++ b/psd-web/app/helpers/investigations_helper.rb @@ -241,8 +241,8 @@ def user_ids_from_team(team) [team.id] + team.users.map(&:id) end - def suggested_previous_owners - all_past_owners = @investigation.past_owners + @investigation.past_teams + def suggested_previous_owners(investigation) + all_past_owners = investigation.past_owners return [] if all_past_owners.empty? || all_past_owners == [current_user] all_past_owners || [] diff --git a/psd-web/app/models/activity.rb b/psd-web/app/models/activity.rb index 16aaa5f493..c78365f4a9 100644 --- a/psd-web/app/models/activity.rb +++ b/psd-web/app/models/activity.rb @@ -17,8 +17,13 @@ def attachments {} end - def subtitle - "#{subtitle_slug} by #{source&.show}, #{pretty_date_stamp}" + # Can be overridden by child classes but sometimes need to pass in user + def title(_user) + super() + end + + def subtitle(viewer) + "#{subtitle_slug} by #{source&.show(viewer)}, #{pretty_date_stamp}" end def search_index; end @@ -31,7 +36,7 @@ def can_display_all_data?(_user) true end - def restricted_title + def restricted_title(_user) # where necessary should be implemented by subclasses end diff --git a/psd-web/app/models/audit_activity/correspondence/add_email.rb b/psd-web/app/models/audit_activity/correspondence/add_email.rb index 7955ab660f..a9ac92087e 100644 --- a/psd-web/app/models/audit_activity/correspondence/add_email.rb +++ b/psd-web/app/models/audit_activity/correspondence/add_email.rb @@ -48,7 +48,7 @@ def self.build_email_address(correspondence) output + "
" end - def restricted_title + def restricted_title(_user) "Email added" end diff --git a/psd-web/app/models/audit_activity/correspondence/add_meeting.rb b/psd-web/app/models/audit_activity/correspondence/add_meeting.rb index 585be78a56..4cc9b660c2 100644 --- a/psd-web/app/models/audit_activity/correspondence/add_meeting.rb +++ b/psd-web/app/models/audit_activity/correspondence/add_meeting.rb @@ -23,7 +23,7 @@ def activity_type "meeting" end - def restricted_title + def restricted_title(_user) "Meeting added" end diff --git a/psd-web/app/models/audit_activity/correspondence/add_phone_call.rb b/psd-web/app/models/audit_activity/correspondence/add_phone_call.rb index 88adf4a726..a0d6a828c2 100644 --- a/psd-web/app/models/audit_activity/correspondence/add_phone_call.rb +++ b/psd-web/app/models/audit_activity/correspondence/add_phone_call.rb @@ -39,7 +39,7 @@ def self.build_file_body(correspondence) file.attached? ? "Attached: #{sanitize_text file.filename}
" : "" end - def restricted_title + def restricted_title(_user) "Phone call added" end diff --git a/psd-web/app/models/audit_activity/document/add.rb b/psd-web/app/models/audit_activity/document/add.rb index fb10d31cfd..27da39f938 100644 --- a/psd-web/app/models/audit_activity/document/add.rb +++ b/psd-web/app/models/audit_activity/document/add.rb @@ -8,7 +8,7 @@ def email_update_text(viewer = nil) "Document was attached to the #{investigation.case_type.upcase_first} by #{source&.show(viewer)}." end - def restricted_title + def restricted_title(_user) "Document added" end diff --git a/psd-web/app/models/audit_activity/document/base.rb b/psd-web/app/models/audit_activity/document/base.rb index 2a4bb3168e..ac713fb088 100644 --- a/psd-web/app/models/audit_activity/document/base.rb +++ b/psd-web/app/models/audit_activity/document/base.rb @@ -21,7 +21,7 @@ def attached_image? attachment.image? end - def restricted_title; end + def restricted_title(_user); end def can_display_all_data?(user) can_be_displayed?(attachment, investigation, user) diff --git a/psd-web/app/models/audit_activity/document/destroy.rb b/psd-web/app/models/audit_activity/document/destroy.rb index 16b19991d5..9d6fd6cfb2 100644 --- a/psd-web/app/models/audit_activity/document/destroy.rb +++ b/psd-web/app/models/audit_activity/document/destroy.rb @@ -4,7 +4,7 @@ def self.from(document, investigation) super(document, investigation, title) end - def restricted_title + def restricted_title(_user) "Document deleted" end diff --git a/psd-web/app/models/audit_activity/document/update.rb b/psd-web/app/models/audit_activity/document/update.rb index dc3dd004cb..25b1ef6192 100644 --- a/psd-web/app/models/audit_activity/document/update.rb +++ b/psd-web/app/models/audit_activity/document/update.rb @@ -22,7 +22,7 @@ def self.description_changed?(document, previous_data) document.metadata[:description] != previous_data[:description] end - def restricted_title + def restricted_title(_user) "Document updated" end diff --git a/psd-web/app/models/audit_activity/investigation/add.rb b/psd-web/app/models/audit_activity/investigation/add.rb index ab016d82dd..f3074f05dd 100644 --- a/psd-web/app/models/audit_activity/investigation/add.rb +++ b/psd-web/app/models/audit_activity/investigation/add.rb @@ -31,7 +31,7 @@ def complainant # title may change after investigation was created, so we retrieve from the # metadata stored at the time of creation - def title + def title(_user) return self[:title] if self[:title] # older activities stored this in the database "#{investigation.case_type.titleize} logged: #{metadata['investigation']['title']}" @@ -49,8 +49,8 @@ def can_display_all_data?(user) end # Only used for old records prior to metadata implementation - def restricted_title - title + def restricted_title(user) + title(user) end private diff --git a/psd-web/app/models/audit_activity/investigation/automatically_update_owner.rb b/psd-web/app/models/audit_activity/investigation/automatically_update_owner.rb index 073245e6f8..302b8e58bf 100644 --- a/psd-web/app/models/audit_activity/investigation/automatically_update_owner.rb +++ b/psd-web/app/models/audit_activity/investigation/automatically_update_owner.rb @@ -1,31 +1,30 @@ class AuditActivity::Investigation::AutomaticallyUpdateOwner < AuditActivity::Investigation::Base - def self.from(investigation) - title = investigation.owner.id.to_s - super(investigation, title) + def self.from(*) + raise "Deprecated - use DeleteUser.call instead" end - def owner_id - # We store owner_id in title field, this is getting it back - # Using alias for accessing parent method causes errors elsewhere :( - AuditActivity::Investigation::Base.instance_method(:title).bind(self).call + def self.build_metadata(owner) + { + owner_id: owner.id + } end - # We store owner_id in title field, this is computing title based on that - def title + def title(user) type = investigation.case_type.capitalize - new_owner = (User.find_by(id: owner_id) || Team.find_by(id: owner_id))&.decorate&.display_name + new_owner = owner.decorate.display_name(viewer: user) "Case owner automatically changed on #{type} to #{new_owner}" end - def subtitle + def subtitle(_viewer) "Case owner automatically changed, #{pretty_date_stamp}" end - def entities_to_notify - [] - end +private - def email_subject_text; end + def owner + User.find_by(id: metadata["owner_id"]) || Team.find_by(id: metadata["owner_id"]) + end - def email_update_text(viewer = nil); end + # Do not send investigation_updated mail. This is handled by the DeleteUser service + def notify_relevant_users; end end diff --git a/psd-web/app/models/audit_activity/investigation/team_added.rb b/psd-web/app/models/audit_activity/investigation/team_added.rb index 2641221a82..a0ca4ade04 100644 --- a/psd-web/app/models/audit_activity/investigation/team_added.rb +++ b/psd-web/app/models/audit_activity/investigation/team_added.rb @@ -1,6 +1,6 @@ class AuditActivity::Investigation::TeamAdded < AuditActivity::Investigation::Base - def subtitle - "Team added by #{source&.show}, #{pretty_date_stamp}" + def subtitle(viewer) + "Team added by #{source&.show(viewer)}, #{pretty_date_stamp}" end private diff --git a/psd-web/app/models/audit_activity/investigation/team_deleted.rb b/psd-web/app/models/audit_activity/investigation/team_deleted.rb index 715d5497d8..806031e8cd 100644 --- a/psd-web/app/models/audit_activity/investigation/team_deleted.rb +++ b/psd-web/app/models/audit_activity/investigation/team_deleted.rb @@ -1,6 +1,6 @@ class AuditActivity::Investigation::TeamDeleted < AuditActivity::Investigation::Base - def subtitle - "Team removed by #{source&.show}, #{pretty_date_stamp}" + def subtitle(viewer) + "Team removed by #{source&.show(viewer)}, #{pretty_date_stamp}" end private diff --git a/psd-web/app/models/audit_activity/investigation/update_owner.rb b/psd-web/app/models/audit_activity/investigation/update_owner.rb index 59d9aed90d..a23684a185 100644 --- a/psd-web/app/models/audit_activity/investigation/update_owner.rb +++ b/psd-web/app/models/audit_activity/investigation/update_owner.rb @@ -1,37 +1,25 @@ class AuditActivity::Investigation::UpdateOwner < AuditActivity::Investigation::Base - include NotifyHelper - - def self.from(investigation) - title = investigation.owner.id.to_s - body = investigation.owner_rationale - super(investigation, title, sanitize_text(body)) + def self.from(*) + raise "Deprecated - use ChangeCaseOwner.call instead" end - def owner_id - # We store owner_id in title field, this is getting it back - # Using alias for accessing parent method causes errors elsewhere :( - AuditActivity::Investigation::Base.instance_method(:title).bind(self).call + def self.build_metadata(owner, rationale) + { + owner_id: owner.id, + rationale: rationale + } end - def title - # We store owner_id in title field, this is computing title based on that - "Case owner changed to #{(User.find_by(id: owner_id) || Team.find_by(id: owner_id))&.decorate&.display_name}" + def title(user) + "Case owner changed to #{owner.decorate.display_name(viewer: user)}" end - def email_update_text(viewer = nil) - body = [] - body << "Case owner changed on #{investigation.case_type} to #{investigation.owner.decorate.display_name(viewer: viewer)} by #{source&.show(viewer)}." - - if investigation.owner_rationale.present? - body << "Message from #{source&.show(viewer)}:" - body << inset_text_for_notify(investigation.owner_rationale) - end - - body.join("\n\n") + def body + metadata["rationale"] end - def email_subject_text - "Case owner changed for #{investigation.case_type}" + def owner + User.find_by(id: metadata["owner_id"]) || Team.find_by(id: metadata["owner_id"]) end private @@ -40,27 +28,6 @@ def subtitle_slug "Changed" end - def users_to_notify - compute_relevant_entities(model: User, compute_users_from_entity: proc { |user| [user] }) - end - - def teams_to_notify - compute_relevant_entities(model: Team, compute_users_from_entity: proc { |team| team.users }) - end - - def compute_relevant_entities(model:, compute_users_from_entity:) - return [] unless investigation.saved_changes.key?("owner_id") - - previous_owner_id = investigation.saved_changes["owner_id"][0] - previous_owner = model.find_by(id: previous_owner_id) - new_owner = investigation.owner - owner_changed_by = source.user - - old_users = previous_owner.present? ? compute_users_from_entity.call(previous_owner) : [] - old_entities = previous_owner.present? ? [previous_owner] : [] - new_entities = new_owner.is_a?(model) ? [new_owner] : [] - return new_entities if old_users.include? owner_changed_by - - (new_entities + old_entities).uniq - end + # Do not send investigation_updated mail. This is handled by the ChangeCaseOwner service + def notify_relevant_users; end end diff --git a/psd-web/app/models/comment_activity.rb b/psd-web/app/models/comment_activity.rb index cd9b92c896..cc753d64c6 100644 --- a/psd-web/app/models/comment_activity.rb +++ b/psd-web/app/models/comment_activity.rb @@ -4,7 +4,7 @@ class CommentActivity < Activity validates :body, presence: true validates :body, length: { maximum: 10_000 } - def title + def title(_user) "Comment added" end diff --git a/psd-web/app/models/investigation.rb b/psd-web/app/models/investigation.rb index bd8bf53d0d..05955fc40a 100644 --- a/psd-web/app/models/investigation.rb +++ b/psd-web/app/models/investigation.rb @@ -20,15 +20,17 @@ class Investigation < ApplicationRecord validates :type, presence: true # Prevent saving instances of Investigation; must use a subclass instead validates :description, presence: true, on: :update - validates :owner_id, presence: { message: "Select case owner" }, on: :update + + # Can currently only validate owner_id on update since create case wizards + # validate partially-built Investigation instances + validates :owner_id, presence: true, on: :update validates :user_title, length: { maximum: 100 } validates :description, length: { maximum: 10_000 } validates :non_compliant_reason, length: { maximum: 10_000 } validates :hazard_description, length: { maximum: 10_000 } - after_update :create_audit_activity_for_owner, - :create_audit_activity_for_status, + after_update :create_audit_activity_for_status, :create_audit_activity_for_visibility, :create_audit_activity_for_summary @@ -96,8 +98,7 @@ def important_owner_people def past_owners activities = AuditActivity::Investigation::UpdateOwner.where(investigation_id: id) - user_id_list = activities.map(&:owner_id) - User.where(id: user_id_list) + activities.map(&:owner) end def important_owner_teams @@ -110,12 +111,6 @@ def important_owner_teams teams end - def past_teams - activities = AuditActivity::Investigation::UpdateOwner.where(investigation_id: id) - team_id_list = activities.map(&:owner_id) - Team.where(id: team_id_list) - end - def enquiry? is_a?(Investigation::Enquiry) end @@ -171,14 +166,6 @@ def create_audit_activity_for_visibility end end - def create_audit_activity_for_owner - # TODO: User.current check is here to avoid triggering activity and emails from migrations - # Can be safely removed once the migration PopulateAssigneeAndDescription has run - if ((saved_changes.key? :owner_id) || (saved_changes.key? :owner_type)) && User.current - AuditActivity::Investigation::UpdateOwner.from(self) - end - end - def create_audit_activity_for_summary # TODO: User.current check is here to avoid triggering activity and emails from migrations # Can be safely removed once the migration PopulateAssigneeAndDescription has run diff --git a/psd-web/app/services/change_case_owner.rb b/psd-web/app/services/change_case_owner.rb new file mode 100644 index 0000000000..3e6dccb6ea --- /dev/null +++ b/psd-web/app/services/change_case_owner.rb @@ -0,0 +1,74 @@ +class ChangeCaseOwner + include Interactor + include NotifyHelper + + delegate :investigation, :owner, :rationale, :user, :old_owner, to: :context + + def call + context.fail!(error: "No investigation supplied") unless investigation.is_a?(Investigation) + context.fail!(error: "No owner supplied") unless owner.is_a?(User) || owner.is_a?(Team) + context.fail!(error: "No user supplied") unless user.is_a?(User) + + context.old_owner = investigation.owner + + return if old_owner == owner + + ActiveRecord::Base.transaction do + investigation.update!(owner: owner) + create_audit_activity_for_case_owner_changed + end + + send_notification_email + end + +private + + def create_audit_activity_for_case_owner_changed + metadata = activity_class.build_metadata(owner, rationale) + + activity_class.create!( + source: UserSource.new(user: user), + investigation: investigation, + title: nil, + body: nil, + metadata: metadata + ) + end + + def activity_class + AuditActivity::Investigation::UpdateOwner + end + + def send_notification_email + entities_to_notify.each do |recipient| + email = recipient.is_a?(Team) ? recipient.team_recipient_email : recipient.email + + NotifyMailer.investigation_updated( + investigation.pretty_id, + recipient.name, + email, + email_body(recipient), + "Case owner changed for #{investigation.case_type}" + ).deliver_later + end + end + + # Notify the new owner, and the old one if it's not the user making the change + def entities_to_notify + entities = [owner] + entities << old_owner if old_owner != user + + entities.map { |entity| + return entity.users.active if entity.is_a?(Team) && !entity.team_recipient_email + + entity + }.flatten.uniq + end + + def email_body(viewer = nil) + user_name = user.decorate.display_name(viewer: viewer) + body = "Case owner changed on #{investigation.case_type} to #{owner.decorate.display_name(viewer: viewer)} by #{user_name}." + body << "\n\nMessage from #{user_name}: #{inset_text_for_notify(rationale)}" if rationale + body + end +end diff --git a/psd-web/app/services/delete_user.rb b/psd-web/app/services/delete_user.rb index e8c28d3e4c..c1328e002f 100644 --- a/psd-web/app/services/delete_user.rb +++ b/psd-web/app/services/delete_user.rb @@ -1,12 +1,14 @@ class DeleteUser include Interactor + delegate :user, to: :context + def call - context.fail!(error: "No user supplied") unless context.user - context.fail!(error: "User already deleted") if context.user.deleted? + context.fail!(error: "No user supplied") unless user.is_a?(User) + context.fail!(error: "User already deleted") if user.deleted? ActiveRecord::Base.transaction do - context.user.mark_as_deleted! + user.mark_as_deleted! change_user_investigations_ownership_to_their_team end end @@ -16,10 +18,27 @@ def call def change_user_investigations_ownership_to_their_team context.team = context.user.team - context.user.investigations.each do |investigation| + user.investigations.each do |investigation| investigation.owner = context.team investigation.save! - AuditActivity::Investigation::AutomaticallyUpdateOwner.from(investigation) + + create_audit_activity_for_case_owner_automatically_changed(investigation) end end + + def create_audit_activity_for_case_owner_automatically_changed(investigation) + metadata = activity_class.build_metadata(investigation.owner) + + activity_class.create!( + source: nil, # DeleteUser is called from rake user:delete where no user source is available + investigation: investigation, + title: nil, + body: nil, + metadata: metadata + ) + end + + def activity_class + AuditActivity::Investigation::AutomaticallyUpdateOwner + end end diff --git a/psd-web/app/views/investigations/activities/_activity_card.html.erb b/psd-web/app/views/investigations/activities/_activity_card.html.erb index f4232c1036..4eba9a9ec2 100644 --- a/psd-web/app/views/investigations/activities/_activity_card.html.erb +++ b/psd-web/app/views/investigations/activities/_activity_card.html.erb @@ -1,12 +1,12 @@ <% restricted = !activity.can_display_all_data?(current_user) - title = restricted ? activity.restricted_title : activity.title + title = restricted ? activity.restricted_title(current_user) : activity.title(current_user) %>
  • <%= title %>

    -

    <%= activity.subtitle %>

    +

    <%= activity.subtitle(current_user) %>

    <% if restricted %> <%= render "restricted", activity: activity %> diff --git a/psd-web/app/views/investigations/activities/investigation/_update_owner.html.erb b/psd-web/app/views/investigations/activities/investigation/_update_owner.html.erb new file mode 100644 index 0000000000..4854ec1e62 --- /dev/null +++ b/psd-web/app/views/investigations/activities/investigation/_update_owner.html.erb @@ -0,0 +1 @@ +<%= markdown simple_format(activity.metadata["rationale"]) %> diff --git a/psd-web/config/locales/en.yml b/psd-web/config/locales/en.yml index cc56107760..d7a1fdab12 100644 --- a/psd-web/config/locales/en.yml +++ b/psd-web/config/locales/en.yml @@ -129,6 +129,11 @@ en: activemodel: errors: models: + change_case_owner_form: + attributes: + owner_id: + blank: Select case owner + not_found: User or team not found invite_user_to_team_form: attributes: email: diff --git a/psd-web/db/migrate/20200610111320_move_update_owner_activity_metadata.rb b/psd-web/db/migrate/20200610111320_move_update_owner_activity_metadata.rb new file mode 100644 index 0000000000..b682f63fc8 --- /dev/null +++ b/psd-web/db/migrate/20200610111320_move_update_owner_activity_metadata.rb @@ -0,0 +1,33 @@ +class MoveUpdateOwnerActivityMetadata < ActiveRecord::Migration[5.2] + def change + klass = AuditActivity::Investigation::UpdateOwner + + klass.all.each do |activity| + next if activity.metadata + + # case owner ID is stored in the title column... + next unless (owner_id = activity[:title]) + + owner = User.find_by(id: owner_id) || Team.find_by(id: owner_id) + + metadata = klass.build_metadata(owner, activity[:body]) + + activity.update!(metadata: metadata, title: nil, body: nil) + end + + klass = AuditActivity::Investigation::AutomaticallyUpdateOwner + + klass.all.each do |activity| + next if activity.metadata + + # case owner ID is stored in the title column... + next unless (owner_id = activity[:title]) + + owner = User.find_by(id: owner_id) || Team.find_by(id: owner_id) + + metadata = klass.build_metadata(owner) + + activity.update!(metadata: metadata, title: nil, body: nil) + end + end +end diff --git a/psd-web/db/schema.rb b/psd-web/db/schema.rb index a0aba4aa57..329477e8bf 100644 --- a/psd-web/db/schema.rb +++ b/psd-web/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_06_05_115455) do +ActiveRecord::Schema.define(version: 2020_06_10_111320) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" diff --git a/psd-web/spec/features/change_ownership_for_investigation_spec.rb b/psd-web/spec/features/change_ownership_for_investigation_spec.rb index ab462a42c6..e618108125 100644 --- a/psd-web/spec/features/change_ownership_for_investigation_spec.rb +++ b/psd-web/spec/features/change_ownership_for_investigation_spec.rb @@ -12,7 +12,7 @@ before do sign_in(user) - visit "/cases/#{investigation.pretty_id}/assign/select-owner" + visit "/cases/#{investigation.pretty_id}/assign/new" end scenario "does not show inactive users" do diff --git a/psd-web/spec/features/record_email_activity_spec.rb b/psd-web/spec/features/record_email_activity_spec.rb index 8c5f809b23..06113b06e7 100644 --- a/psd-web/spec/features/record_email_activity_spec.rb +++ b/psd-web/spec/features/record_email_activity_spec.rb @@ -81,7 +81,7 @@ expect_to_be_on_case_activity_page(case_id: investigation.pretty_id) # Consumer info is not hidden from case owner - expect_case_activity_page_to_show_entered_information(name: name, email: email, date: date, file: file) + expect_case_activity_page_to_show_entered_information(user_name: user.name, name: name, email: email, date: date, file: file) click_link "View email" @@ -109,7 +109,7 @@ visit "/cases/#{investigation.pretty_id}/activity" expect_to_be_on_case_activity_page(case_id: investigation.pretty_id) - expect_case_activity_page_to_show_entered_information(name: name, email: email, date: date, file: file) + expect_case_activity_page_to_show_entered_information(user_name: user.name, name: name, email: email, date: date, file: file) end scenario "with non-consumer contact details and summary and subject and body" do @@ -135,7 +135,7 @@ click_on "Activity" expect_to_be_on_case_activity_page(case_id: investigation.pretty_id) - expect_case_activity_page_to_show_entered_information(name: name, email: email, date: date, summary: summary, subject: email_subject, body: body) + expect_case_activity_page_to_show_entered_information(user_name: user.name, name: name, email: email, date: date, summary: summary, subject: email_subject, body: body) # Test that another user in a different organisation can see all info sign_out @@ -145,7 +145,7 @@ visit "/cases/#{investigation.pretty_id}/activity" expect_to_be_on_case_activity_page(case_id: investigation.pretty_id) - expect_case_activity_page_to_show_entered_information(name: name, email: email, date: date, summary: summary, subject: email_subject, body: body) + expect_case_activity_page_to_show_entered_information(user_name: "#{user.name} (#{user.team.name})", name: name, email: email, date: date, summary: summary, subject: email_subject, body: body) end def fill_in_record_email_form(name:, email:, consumer:, date:) @@ -198,8 +198,8 @@ def expect_record_email_form_to_have_entered_information(name:, email:, consumer expect(find_field("Year").value).to eq date.year.to_s end - def expect_case_activity_page_to_show_entered_information(name:, email:, date:, file: nil, summary: nil, subject: nil, body: nil) - item = page.find("p", text: "Email recorded by #{user.name} (#{user.team.name})").find(:xpath, "..") + def expect_case_activity_page_to_show_entered_information(user_name:, name:, email:, date:, file: nil, summary: nil, subject: nil, body: nil) + item = page.find("p", text: "Email recorded by #{user_name}").find(:xpath, "..") expect(item).to have_text("From: #{name} (#{email})") expect(item).to have_text("Date sent: #{date.strftime('%d/%m/%Y')}") diff --git a/psd-web/spec/features/record_phone_call_activity_spec.rb b/psd-web/spec/features/record_phone_call_activity_spec.rb index d7dfc2fb9f..175436d6fa 100644 --- a/psd-web/spec/features/record_phone_call_activity_spec.rb +++ b/psd-web/spec/features/record_phone_call_activity_spec.rb @@ -78,7 +78,7 @@ expect_to_be_on_case_activity_page(case_id: investigation.pretty_id) # Consumer info is not hidden from case owner - expect_case_activity_page_to_show_entered_information(name: name, phone: phone, date: date, file: file) + expect_case_activity_page_to_show_entered_information(user_name: user.name, name: name, phone: phone, date: date, file: file) click_link "View phone call" @@ -106,7 +106,7 @@ visit "/cases/#{investigation.pretty_id}/activity" expect_to_be_on_case_activity_page(case_id: investigation.pretty_id) - expect_case_activity_page_to_show_entered_information(name: name, phone: phone, date: date, file: file) + expect_case_activity_page_to_show_entered_information(user_name: user.name, name: name, phone: phone, date: date, file: file) end scenario "with non-consumer contact details and summary and notes" do @@ -132,7 +132,7 @@ click_on "Activity" expect_to_be_on_case_activity_page(case_id: investigation.pretty_id) - expect_case_activity_page_to_show_entered_information(name: name, phone: phone, date: date, summary: summary, notes: notes) + expect_case_activity_page_to_show_entered_information(user_name: user.name, name: name, phone: phone, date: date, summary: summary, notes: notes) # Test that another user in a different organisation can see all info sign_out @@ -142,7 +142,7 @@ visit "/cases/#{investigation.pretty_id}/activity" expect_to_be_on_case_activity_page(case_id: investigation.pretty_id) - expect_case_activity_page_to_show_entered_information(name: name, phone: phone, date: date, summary: summary, notes: notes) + expect_case_activity_page_to_show_entered_information(user_name: "#{user.name} (#{user.team.name})", name: name, phone: phone, date: date, summary: summary, notes: notes) end def fill_in_record_phone_call_form(name:, phone:, consumer:, date:) @@ -189,8 +189,8 @@ def expect_record_phone_call_form_to_have_entered_information(name:, phone:, con expect(find_field("Year").value).to eq date.year.to_s end - def expect_case_activity_page_to_show_entered_information(name:, phone:, date:, file: nil, summary: nil, notes: nil) - item = page.find("p", text: "Phone call by #{user.name} (#{user.team.name})").find(:xpath, "..") + def expect_case_activity_page_to_show_entered_information(user_name:, name:, phone:, date:, file: nil, summary: nil, notes: nil) + item = page.find("p", text: "Phone call by #{user_name}").find(:xpath, "..") expect(item).to have_text("Call with: #{name} (#{phone})") expect(item).to have_text("Date: #{date.strftime('%d/%m/%Y')}") diff --git a/psd-web/spec/forms/change_case_owner_form_spec.rb b/psd-web/spec/forms/change_case_owner_form_spec.rb new file mode 100644 index 0000000000..01ab20cf11 --- /dev/null +++ b/psd-web/spec/forms/change_case_owner_form_spec.rb @@ -0,0 +1,60 @@ +require "rails_helper" + +RSpec.describe ChangeCaseOwnerForm do + subject(:form) { described_class.new(owner_id: owner_id, owner_rationale: rationale) } + + let(:owner) { create(:team) } + + let(:owner_id) { owner.id } + let(:rationale) { "Test rationale" } + + describe "#valid?" do + shared_examples_for "valid form" do + it "is is valid" do + expect(form).to be_valid + end + + it "does not contain error messages" do + form.validate + expect(form.errors.full_messages).to be_empty + end + end + + shared_examples_for "invalid form" do |*errors| + it "is not valid" do + expect(form).to be_invalid + end + + it "populates an error message" do + form.validate + errors.each do |property, message| + expect(form.errors.full_messages_for(property)).to eq([message]) + end + end + end + + context "when no owner_id is supplied" do + let(:owner_id) { nil } + + include_examples "invalid form", [:owner_id, "Select case owner"] + end + + context "when owner_id does not match a user or team" do + let(:owner_id) { "invalid" } + + include_examples "invalid form", [:owner_id, "User or team not found"] + end + + context "when owner is an inactive user" do + let(:owner) { create(:user, :inactive) } + + include_examples "invalid form", [:owner_id, "User or team not found"] + end + end + + describe "#owner" do + it "returns the owner" do + expect(form.owner).to eq(owner) + end + end +end diff --git a/psd-web/spec/forms/edit_investigation_collaborator_form_spec.rb b/psd-web/spec/forms/edit_investigation_collaborator_form_spec.rb index 8e5e1bfb67..ca0df213f2 100644 --- a/psd-web/spec/forms/edit_investigation_collaborator_form_spec.rb +++ b/psd-web/spec/forms/edit_investigation_collaborator_form_spec.rb @@ -72,7 +72,7 @@ last_added_activity = investigation.activities.reload.order(created_at: :desc) .find_by!(type: "AuditActivity::Investigation::TeamDeleted") - expect(last_added_activity.title).to eql("test team removed from allegation") + expect(last_added_activity.title(user)).to eql("test team removed from allegation") expect(last_added_activity.source.user_id).to eql(user.id) end end diff --git a/psd-web/spec/models/audit_activity/investigation/automatically_update_owner_spec.rb b/psd-web/spec/models/audit_activity/investigation/automatically_update_owner_spec.rb deleted file mode 100644 index 67614dd4f4..0000000000 --- a/psd-web/spec/models/audit_activity/investigation/automatically_update_owner_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -require "rails_helper" - -RSpec.describe AuditActivity::Investigation::AutomaticallyUpdateOwner, :with_stubbed_mailer, :with_stubbed_elasticsearch do - subject(:audit_activity) { described_class.from(investigation) } - - let(:team) { create(:team) } - let(:investigation) { create(:enquiry, owner: team, owner_rationale: "Test owner") } - - describe ".from" do - it "creates an audit activity without information for email notification" do - expect(audit_activity).to have_attributes( - title: "Case owner automatically changed on Enquiry to #{team.display_name}", - body: nil, - email_update_text: nil, - email_subject_text: nil - ) - end - end -end diff --git a/psd-web/spec/models/audit_activity/investigation/update_coronavirus_status_spec.rb b/psd-web/spec/models/audit_activity/investigation/update_coronavirus_status_spec.rb index f8e52d215b..f4a729f816 100644 --- a/psd-web/spec/models/audit_activity/investigation/update_coronavirus_status_spec.rb +++ b/psd-web/spec/models/audit_activity/investigation/update_coronavirus_status_spec.rb @@ -11,10 +11,10 @@ describe ".from" do it "creates an audit activity", :aggregate_failures do expect(audit_activity).to have_attributes( - title: "Status updated: not coronavirus related", body: "The case is not related to the coronavirus outbreak.", email_subject_text: "Coronavirus status updated on #{investigation.case_type.downcase}" ) + expect(audit_activity.title(user)).to eq("Status updated: not coronavirus related") expect(audit_activity.email_update_text(user)).to eq("#{investigation.case_type.capitalize} #{investigation.pretty_id} is not related to the coronavirus outbreak. This status was updated by #{user.name}.") end end diff --git a/psd-web/spec/models/audit_activity/investigation/update_owner_spec.rb b/psd-web/spec/models/audit_activity/investigation/update_owner_spec.rb index 52febdf944..a95ee17c26 100644 --- a/psd-web/spec/models/audit_activity/investigation/update_owner_spec.rb +++ b/psd-web/spec/models/audit_activity/investigation/update_owner_spec.rb @@ -1,21 +1,39 @@ require "rails_helper" -RSpec.describe AuditActivity::Investigation::UpdateOwner, :with_stubbed_mailer, :with_stubbed_elasticsearch do - subject(:audit_activity) { described_class.from(investigation) } +RSpec.describe AuditActivity::Investigation::UpdateOwner, :with_stubbed_elasticsearch, :with_stubbed_mailer do + subject(:activity) { described_class.create(investigation: investigation, metadata: described_class.build_metadata(owner, rationale)) } - let(:user) { create(:user).decorate } - let(:investigation) { create(:enquiry, owner: user, owner_rationale: "Test owner") } + let(:investigation) { create(:allegation, owner: owner) } + let(:owner) { create(:team) } + let(:rationale) { "Test rationale" } + let(:user) { create(:user) } - before { User.current = user } + describe ".build_metadata" do + let(:result) { described_class.build_metadata(owner, rationale) } - describe ".from" do - it "creates an audit activity with information for email notification", :aggregate_failures do - expect(audit_activity).to have_attributes( - title: "Case owner changed to #{user.display_name}", - body: investigation.owner_rationale, - email_subject_text: "Case owner changed for enquiry" - ) - expect(audit_activity.email_update_text(user)).to start_with("Case owner changed on enquiry to #{user.name} by #{user.name}") + it "returns a Hash of the arguments" do + expect(result).to eq({ + owner_id: owner.id, + rationale: rationale + }) + end + end + + describe "#title" do + it "returns a generated String" do + expect(activity.title(user)).to eq("Case owner changed to #{owner.name}") + end + end + + describe "#body" do + it "returns the rationale" do + expect(activity.body).to eq("Test rationale") + end + end + + describe "#owner" do + it "returns the owner" do + expect(activity.owner).to eq(owner) end end end diff --git a/psd-web/spec/services/add_product_to_case_spec.rb b/psd-web/spec/services/add_product_to_case_spec.rb index 2b067b83ea..7297fe7a57 100644 --- a/psd-web/spec/services/add_product_to_case_spec.rb +++ b/psd-web/spec/services/add_product_to_case_spec.rb @@ -59,7 +59,7 @@ expect(activity).to be_a(AuditActivity::Product::Add) expect(activity.source.user).to eq(user) expect(activity.product_id).to eq(product.id) - expect(activity.title).to eq(product.name) + expect(activity.title(nil)).to eq(product.name) end context "when the case owner is a user" do diff --git a/psd-web/spec/services/add_team_to_an_investigation_spec.rb b/psd-web/spec/services/add_team_to_an_investigation_spec.rb index 4213bc7d9e..cbce7adbb8 100644 --- a/psd-web/spec/services/add_team_to_an_investigation_spec.rb +++ b/psd-web/spec/services/add_team_to_an_investigation_spec.rb @@ -51,7 +51,7 @@ aggregate_failures do expect(last_added_activity).to be_a(AuditActivity::Investigation::TeamAdded) - expect(last_added_activity.title).to eql("Testing team added to allegation") + expect(last_added_activity.title(nil)).to eql("Testing team added to allegation") expect(last_added_activity.source.user_id).to eql(user.id) end end diff --git a/psd-web/spec/services/change_case_owner_spec.rb b/psd-web/spec/services/change_case_owner_spec.rb new file mode 100644 index 0000000000..06372d49f8 --- /dev/null +++ b/psd-web/spec/services/change_case_owner_spec.rb @@ -0,0 +1,165 @@ +require "rails_helper" + +RSpec.describe ChangeCaseOwner, :with_stubbed_elasticsearch, :with_test_queue_adapter do + # Create the investigation up front so we can check which activities are generated by the service + let!(:investigation) { create(:enquiry, owner: old_owner, creator: creator) } + + let(:team) { create(:team) } + + let(:creator) { create(:user, :activated, team: team, organisation: team.organisation) } + let(:old_owner) { creator } + let(:new_owner) { create(:user, :activated, team: team, organisation: team.organisation) } + let(:user) { create(:user, :activated, team: team, organisation: team.organisation) } + let(:rationale) { "Test rationale" } + + describe ".call" do + context "with no parameters" do + let(:result) { described_class.call } + + it "returns a failure" do + expect(result).to be_failure + end + end + + context "with no investigation parameter" do + let(:result) { described_class.call(owner: new_owner, user: user) } + + it "returns a failure" do + expect(result).to be_failure + end + end + + context "with no user parameter" do + let(:result) { described_class.call(owner: new_owner, investigation: investigation) } + + it "returns a failure" do + expect(result).to be_failure + end + end + + context "with no owner parameter" do + let(:result) { described_class.call(investigation: investigation, user: user) } + + it "returns a failure" do + expect(result).to be_failure + end + end + + context "with required parameters" do + let(:result) { described_class.call(investigation: investigation, user: user, owner: new_owner, rationale: rationale) } + + it "returns success" do + expect(result).to be_success + end + + context "when the new owner is the same as the old owner" do + let(:new_owner) { old_owner } + + it "does not create an audit activity" do + expect { result }.not_to change(Activity, :count) + end + + it "does not send an email" do + expect { result }.not_to have_enqueued_mail(NotifyMailer, :investigation_updated) + end + end + + it "changes the owner" do + expect { result }.to change(investigation, :owner).from(old_owner).to(new_owner) + end + + it "creates an audit activity for owner changed", :aggregate_failures do + expect { result }.to change(Activity, :count).by(1) + activity = investigation.reload.activities.first + expect(activity).to be_a(AuditActivity::Investigation::UpdateOwner) + expect(activity.source.user).to eq(user) + expect(activity.metadata).to eq(AuditActivity::Investigation::UpdateOwner.build_metadata(new_owner, rationale).deep_stringify_keys) + end + + it "sends a notification email to the new owner" do + expect { result }.to have_enqueued_mail(NotifyMailer, :investigation_updated).with( + investigation.pretty_id, + new_owner.name, + new_owner.email, + expected_email_body, + expected_email_subject + ) + end + + it "sends a notification email to the old owner" do + expect { result }.to have_enqueued_mail(NotifyMailer, :investigation_updated).with( + investigation.pretty_id, + old_owner.name, + old_owner.email, + expected_email_body, + expected_email_subject + ) + end + + context "when no rationale is supplied" do + let(:rationale) { nil } + + it "does not add a message to the notification email" do + expect { result }.to have_enqueued_mail(NotifyMailer, :investigation_updated).with( + investigation.pretty_id, + old_owner.name, + old_owner.email, + "Case owner changed on enquiry to #{new_owner.name} by #{user.name}.", + expected_email_subject + ) + end + end + + context "when the user is the same as the old owner" do + let(:user) { old_owner } + + it "does not send a notification email to the old owner" do + expect { result }.not_to have_enqueued_mail(NotifyMailer, :investigation_updated).with( + investigation.pretty_id, + old_owner.name, + old_owner.email, + expected_email_body, + expected_email_subject + ) + end + end + + context "when the new owner is a Team" do + let(:new_owner) { team } + + context "when the team has a an email address" do + let(:team) { create(:team, team_recipient_email: Faker::Internet.email) } + + it "sends a notification email to the team" do + expect { result }.to have_enqueued_mail(NotifyMailer, :investigation_updated).with( + investigation.pretty_id, + team.name, + team.team_recipient_email, + expected_email_body, + expected_email_subject + ) + end + end + + context "when the team does not have an email address" do + let(:team) { create(:team, team_recipient_email: nil) } + + # Create an inactive user to test email is not delivered to them + before { create(:user, team: team, organisation: team.organisation) } + + it "sends an email to each of the team's active users" do + expect { result }.to have_enqueued_mail(NotifyMailer, :investigation_updated).twice + end + end + end + end + end + + def expected_email_subject + "Case owner changed for enquiry" + end + + def expected_email_body + "Case owner changed on enquiry to #{new_owner.name} by #{user.name}.\n\nMessage from #{user.name}: ^ Test rationale" + end +end diff --git a/psd-web/spec/services/create_case_spec.rb b/psd-web/spec/services/create_case_spec.rb index 8f80ae8d65..ac34727fe9 100644 --- a/psd-web/spec/services/create_case_spec.rb +++ b/psd-web/spec/services/create_case_spec.rb @@ -77,7 +77,7 @@ expect(activity).to be_a(AuditActivity::Product::Add) expect(activity.source.user).to eq(user) expect(activity.product_id).to eq(product.id) - expect(activity.title).to eq(product.name) + expect(activity.title(user)).to eq(product.name) end end diff --git a/psd-web/spec/services/delete_user_spec.rb b/psd-web/spec/services/delete_user_spec.rb index fe63390a2c..60848142d2 100644 --- a/psd-web/spec/services/delete_user_spec.rb +++ b/psd-web/spec/services/delete_user_spec.rb @@ -67,8 +67,8 @@ expect { delete_call }.to change(update_owner_activities, :count).by(3) update_owner_activities.last(3).each do |activity| - expect(activity.title).to start_with "Case owner automatically changed on" - expect(activity.title).to end_with "to #{user.team.display_name}" + expect(activity.title(user)).to start_with "Case owner automatically changed on" + expect(activity.title(user)).to end_with "to #{user.team.name}" end end # rubocop:enable RSpec/ExampleLength diff --git a/psd-web/spec/services/remove_product_from_case_spec.rb b/psd-web/spec/services/remove_product_from_case_spec.rb index eeabbbf297..ed9bed5ad7 100644 --- a/psd-web/spec/services/remove_product_from_case_spec.rb +++ b/psd-web/spec/services/remove_product_from_case_spec.rb @@ -59,7 +59,7 @@ expect(activity).to be_a(AuditActivity::Product::Destroy) expect(activity.source.user).to eq(user) expect(activity.product_id).to eq(product.id) - expect(activity.title).to eq("Removed: #{product.name}") + expect(activity.title(nil)).to eq("Removed: #{product.name}") end context "when the case owner is a user" do diff --git a/psd-web/spec/support/audit_activity_investigation.rb b/psd-web/spec/support/audit_activity_investigation.rb index 35b69791c3..2c4c96b0e0 100644 --- a/psd-web/spec/support/audit_activity_investigation.rb +++ b/psd-web/spec/support/audit_activity_investigation.rb @@ -95,7 +95,7 @@ end describe "#title" do - subject(:title) { activity.title } + subject(:title) { activity.title(nil) } let(:activity) { described_class.create(investigation: investigation, metadata: metadata, title: test_title) } let(:test_title) { nil } @@ -170,14 +170,14 @@ end describe "#restricted_title" do - # This metod will only ever be called for older records with no metadata, + # This method will only ever be called for older records with no metadata, # where the title is pre-generated and stored in the database, so we will # set the title here subject(:activity) { described_class.create(investigation: investigation, title: "Test title") } # titles never contain GDPR data for these activity classes so just return the title it "returns the title" do - expect(activity.restricted_title).to eq("Test title") + expect(activity.restricted_title(nil)).to eq("Test title") end end end diff --git a/psd-web/test/models/complainant_test.rb b/psd-web/test/models/complainant_test.rb index 351d162c10..3ae6264415 100644 --- a/psd-web/test/models/complainant_test.rb +++ b/psd-web/test/models/complainant_test.rb @@ -2,6 +2,7 @@ class ComplainantTest < ActiveSupport::TestCase setup do + stub_notify_mailer @complainant = Complainant.new(complainant_type: "Business") end diff --git a/psd-web/test/models/investigation_test.rb b/psd-web/test/models/investigation_test.rb index 4d0785e15c..08d147457a 100644 --- a/psd-web/test/models/investigation_test.rb +++ b/psd-web/test/models/investigation_test.rb @@ -56,17 +56,11 @@ def pundit_user end test "past owners should be computed" do - user = users(:southampton) - @investigation.update(owner: user) + user = users(:southampton_bob) + ChangeCaseOwner.call!(investigation: @investigation, owner: user, user: user) assert_includes @investigation.past_owners, user end - test "past owner teams should be computed" do - team = Team.first - @investigation.update(owner: team) - assert_includes @investigation.past_teams, team - end - test "people out of current owner's team should not be able to change the case owner" do investigation = create_new_case(users(:southampton)) assert_not policy(investigation).change_owner_or_status?(user: users(:luton)) diff --git a/psd-web/test/models/notification_test.rb b/psd-web/test/models/notification_test.rb index 6ea4e996fb..0daeb02cfe 100644 --- a/psd-web/test/models/notification_test.rb +++ b/psd-web/test/models/notification_test.rb @@ -64,63 +64,6 @@ class NotificationTest < ActiveSupport::TestCase assert_equal 2, @number_of_notifications end - test "should notify previous owner if case is owned by someone else by someone else" do - @investigation.update(owner: teams(:southampton)) - @investigation.update(owner: users(:southampton_bob)) - mock_investigation_updated(who_will_be_notified: [users(:southampton_bob), users(:southampton)].map(&:email)) - @investigation.update(owner: users(:southampton)) - assert_equal @number_of_notifications, 2 - end - - test "should not notify previous owner if case is owned by someone else by them" do - @investigation.update(owner: users(:southampton)) - mock_investigation_updated(who_will_be_notified: [users(:southampton_bob).email]) - @investigation.update(owner: users(:southampton_bob)) - assert_equal @number_of_notifications, 1 - end - - test "should notify previous owner team if case is owned by someone by someone outside" do - @investigation.update!(owner: users(:southampton)) - - team_with_recipient_email = teams(:luton) - - @investigation.update!(owner: team_with_recipient_email) - - expected_recipients = [users(:southampton_bob).email, users(:southampton).email, team_with_recipient_email.team_recipient_email] - - mock_investigation_updated(who_will_be_notified: expected_recipients) - @investigation.update!(owner: users(:southampton)) - assert_equal @number_of_notifications, 3 - end - - test "should not notify previous owner team if case is owned by someone by someone inside" do - @investigation.update(owner: users(:southampton_bob)) - @investigation.update(owner: teams(:southampton)) - mock_investigation_updated(who_will_be_notified: [users(:southampton_bob).email]) - @investigation.update(owner: users(:southampton_bob)) - assert_equal @number_of_notifications, 1 - end - - test "should notify a person who is the case owner" do - mock_investigation_updated(who_will_be_notified: [users(:southampton_bob).email]) - @investigation.update(owner: users(:southampton_bob)) - assert_equal @number_of_notifications, 1 - end - - test "should notify everyone in team that is the case owner" do - mock_investigation_updated(who_will_be_notified: teams(:opss_enforcement).users.map(&:email)) - @investigation.update(owner: teams(:opss_enforcement)) - assert_equal @number_of_notifications, 2 - end - - test "previous owner is computed correctly" do - @investigation.update(owner: users(:southampton)) - @investigation.update(owner: users(:southampton_steve)) - mock_investigation_updated(who_will_be_notified: [users(:southampton_bob), users(:southampton_steve)].map(&:email)) - @investigation.update(owner: users(:southampton_bob)) - assert_equal @number_of_notifications, 2 - end - test "notifies current user when investigation created" do mock_investigation_created(who_will_be_notified: [users(:southampton)]) @investigation_two = investigations :two