Skip to content
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

[Cases] Notify assignees when assigned to a case #144391

Merged
merged 15 commits into from
Nov 8, 2022

Conversation

cnasikas
Copy link
Member

@cnasikas cnasikas commented Nov 2, 2022

Summary

The PR adds the ability to notify users by email when assigned to a case. A user is:

  • Not notified if he/she assigns themselves
  • Notified if added as an assignee to a case
  • Not notified if removed from a case

I did not add integration tests due to the complexity of simulating an email server. I added unit test coverage. If integration test coverage is needed we can add the tests on another PR.

Depends on: #143303
Fixes: #142307

Email screenshot

Screenshot 2022-11-08 at 7 05 39 PM

@shanisagiv1 @lcawl What do you think about the content of the email (see screenshot)?

Testing

  1. Put the following in your kibana.yml:
notifications.connectors.default.email: 'mail-dev'

xpack.actions.preconfigured:
  mail-dev:
    name: preconfigured-email-notification-maildev
    actionTypeId: .email
    config:
      service: other
      from: mlr-test-sink@elastic.co
      host: localhost
      port: 1025
      secure: false
      hasAuth: false
  1. Install maildev: npm install -g maildev
  2. Run maildev: maildev
  3. Open MailDev's web interface (http://0.0.0.0:1080/)
  4. Create a case and assign users. You should see the emails in the MailDev inbox.
  5. Update the assignees of a case. You should see the emails in the MailDev inbox.

Note: If you assign yourself you should not see an email. If you delete an assignee you should not see an email.

Checklist

Delete any items that are not applicable to this PR.

For maintainers

Release notes

Notify users by email when assigned to a case

@cnasikas cnasikas added backport:skip This commit does not require backporting Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) Feature:Cases Cases feature release_note:feature Makes this part of the condensed release notes v8.6.0 labels Nov 2, 2022
@cnasikas cnasikas self-assigned this Nov 2, 2022
@github-actions
Copy link

github-actions bot commented Nov 2, 2022

Documentation preview:

@cnasikas cnasikas marked this pull request as ready for review November 7, 2022 11:00
@cnasikas cnasikas requested a review from a team as a code owner November 7, 2022 11:00
@elasticmachine
Copy link
Contributor

Pinging @elastic/response-ops (Team:ResponseOps)

@elasticmachine
Copy link
Contributor

Pinging @elastic/response-ops-cases (Feature:Cases)

@shanisagiv1
Copy link

a few comments:

  • can we call it "Elastic Kibana Case" instead of "Elastic Case"
  • a question for @lcawl - "you got assigned" or "you have been assigned to" - what is more accurate?
  • "view case" URL --> "View the case details"

not related to the content - how the FROM address is defined?

@cnasikas
Copy link
Member Author

cnasikas commented Nov 7, 2022

can we call it "Elastic Kibana Case" instead of "Elastic Case"

Ofc!

a question for @lcawl - "you got assigned" or "you have been assigned to" - what is more accurate?

This is my mistake. @lcawl suggested, "You are assigned to a case". I forgot to update.

"view case" URL --> "View the case details"

Ok!

not related to the content - how the FROM address is defined?

From the email connector configuration. The user decides what the FROM address will be.

@cnasikas
Copy link
Member Author

cnasikas commented Nov 7, 2022

@shanisagiv1, @gsoldevila found out that in the cloud the from is set automatically to noreply@alerts.elastic.co. On-prem the users can configure it as they want.

Copy link
Contributor

@lcawl lcawl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest replacing "got" in the message, otherwise text LGTM

@lcawl lcawl added the ui-copy Review of UI copy with docs team is recommended label Nov 7, 2022
Copy link
Contributor

@jonathan-buttner jonathan-buttner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks great, left a few comments. I still need to test it. As for integration tests, it looks like the email connector uses a mock email server to receive its emails. Do you think we could implement the same thing? We can do it as a follow up PR.

]);
});

it('does not notify if the case does not exist', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this test ensure that the clientArgs.services.notificationService.bulkNotifyAssignees function was not called?

);
});

it('does not notify if the case is patched with the same assignee', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this test ensure that the clientArgs.services.notificationService.bulkNotifyAssignees function was not called?

user
);

if (casesAndAssigneesToNotifyForAssignment.length > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we move the if check inside of the bulkNotifyAssignees and just have it return if the passed in value is an empty array?

}

return acc;
}, [] as Array<{ assignees: CaseAssignees; theCase: CaseSavedObject }>);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think we can avoid the cast if we add this definition to the reduce<Array<{ assignees: CaseAssignees; theCase: CaseSavedObject }>>

const caseSO = mockCases[0];
const assignees = userProfiles.map((userProfile) => ({ uid: userProfile.uid }));

const notifications = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, does the notification plugin return a mock that we could leverage here?

Copy link
Member Author

@cnasikas cnasikas Nov 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! When I wrote the code they did not but they added it later. I will update it to include it.

]);

await emailNotificationService.notifyAssignees({
assignees: [...assignees, { uid: assignees[0].uid }],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: to make it clearer maybe we should remove the duplicate assignee?

this.publicBaseUrl = publicBaseUrl;
}

private getTitle(theCase: CaseSavedObject) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we could make this a private static getTitle method.

}

public async notifyAssignees({ assignees, theCase }: NotifyArgs) {
if (!this.notifications.isEmailServiceAvailable()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't know if it's possible for isEmailServiceAvailable() to throw an error but maybe we should move it into the try?


public async bulkNotifyAssignees(args: NotifyArgs[]) {
await Promise.all(
args.map(({ assignees, theCase }) => this.notifyAssignees({ assignees, theCase }))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use the pMap to ensure we don't make to many concurrent requests.

@cnasikas
Copy link
Member Author

cnasikas commented Nov 8, 2022

Code looks great, left a few comments. I still need to test it. As for integration tests, it looks like the email connector uses a mock email server to receive its emails. Do you think we could implement the same thing? We can do it as a follow up PR.

Thank you @jonathan-buttner for the feedback. I addressed all the suggestions. The email server is not mocked. The service: "__json" is passed as a param when the connector is executed. That is a special "service" that does not actually send the email but it uses nodemailer's jsonTransport to dry run sending emails. In our case, it is not possible to get the output of the executor as it is run in the task manager and the response is not written to any log. We talked about it with @pmuellr and to do it we need to use maildev to mock the email server. Then we need to check for new emails every 1s and save them in memory to be able to later search them when needed from a test. Given the limited time and the amount of work is need to simulate the email server I would prefer to do it on another PR if you do not mind.

Copy link
Contributor

@jonathan-buttner jonathan-buttner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! Tested and looks good.

@cnasikas cnasikas enabled auto-merge (squash) November 8, 2022 17:04
@kibana-ci
Copy link
Collaborator

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #37 / Resolver test app when the user is interacting with the node with ID: firstChild when the user hovers over the primary button when the user has clicked the primary button (which selects the node.) should render as expected
  • [job] [logs] FTR Configs #37 / Resolver test app when the user is interacting with the node with ID: firstChild when the user hovers over the primary button when the user has clicked the primary button (which selects the node.) when the user has moved their mouse off of the primary button (and onto the zoom controls.) should render as expected

Metrics [docs]

Unknown metric groups

ESLint disabled in files

id before after diff
osquery 1 2 +1

ESLint disabled line counts

id before after diff
enterpriseSearch 19 21 +2
fleet 59 65 +6
osquery 108 113 +5
securitySolution 440 446 +6
total +19

Total ESLint disabled count

id before after diff
enterpriseSearch 20 22 +2
fleet 67 73 +6
osquery 109 115 +6
securitySolution 517 523 +6
total +20

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @cnasikas

@cnasikas cnasikas merged commit 82083c4 into elastic:main Nov 8, 2022
@cnasikas cnasikas deleted the notify_assignees branch November 8, 2022 18:18
@EricDavisX
Copy link
Contributor

Wanted to share that I have done a quick test and seen the 'Cases Assignment will send an email notification' feature working via Cloud-QA deploy of latest 8.6 snapshot code, with the current known requirement that the users that shall receive email notifications are whitelisted in cloud, per this meaning

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting Feature:Cases Cases feature release_note:feature Makes this part of the condensed release notes Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) ui-copy Review of UI copy with docs team is recommended v8.6.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Cases] Notify users when assigned on a case
7 participants