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

Add footer to all emails sent by Kibana email connector with a link to open Kibana or to the alert details page #84371

Merged
merged 24 commits into from
Dec 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
191ecbc
Initial work
mikecote Nov 25, 2020
ef22bf7
Change messaging from copy
mikecote Nov 26, 2020
b1de0f1
Fix jest tests for email connector
mikecote Nov 26, 2020
6d284e1
Fix jest tests for alerts plugin
mikecote Nov 26, 2020
94ffce3
Merge branch 'master' of github.com:elastic/kibana into alerting/emai…
mikecote Nov 30, 2020
f001906
Update copy
mikecote Nov 30, 2020
ee7f216
Merge branch 'master' of github.com:elastic/kibana into alerting/emai…
mikecote Dec 7, 2020
7471e04
Merge branch 'master' of github.com:elastic/kibana into alerting/emai…
mikecote Dec 9, 2020
2f5519d
Use server.publicBaseUrl
mikecote Dec 9, 2020
1867bba
Fix jest tests
mikecote Dec 9, 2020
6ae221a
Update tests
mikecote Dec 9, 2020
6c71106
Cleanup jest test
mikecote Dec 9, 2020
d2aac98
Code cleanup
mikecote Dec 10, 2020
f73718f
Merge branch 'master' of github.com:elastic/kibana into alerting/emai…
mikecote Dec 14, 2020
0e33787
Improve email parameter names for kibana footer url
mikecote Dec 14, 2020
800e3b5
Cleanup
mikecote Dec 14, 2020
f076a2f
Merge branch 'master' of github.com:elastic/kibana into alerting/emai…
mikecote Dec 14, 2020
e9d237f
Update with master + PR feedback
mikecote Dec 15, 2020
99b5cad
Add test for kibana footer link
mikecote Dec 15, 2020
098ad91
Fix type check
mikecote Dec 15, 2020
0ef3031
Fix jest test
mikecote Dec 15, 2020
4078870
Merge branch 'master' into alerting/email-footer-url
kibanamachine Dec 15, 2020
2b01fdc
Merge branch 'master' into alerting/email-footer-url
kibanamachine Dec 15, 2020
0dbc6e1
Merge branch 'master' into alerting/email-footer-url
kibanamachine Dec 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
270 changes: 159 additions & 111 deletions x-pack/plugins/actions/server/builtin_action_types/email.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ describe('params validation', () => {
Object {
"bcc": Array [],
"cc": Array [],
"kibanaFooterLink": Object {
"path": "/",
"text": "Go to Kibana",
},
"message": "this is the message",
"subject": "this is a test",
"to": Array [
Expand All @@ -228,35 +232,40 @@ describe('params validation', () => {
});

describe('execute()', () => {
test('ensure parameters are as expected', async () => {
const config: ActionTypeConfigType = {
service: '__json',
host: 'a host',
port: 42,
secure: true,
from: 'bob@example.com',
hasAuth: true,
};
const secrets: ActionTypeSecretsType = {
user: 'bob',
password: 'supersecret',
};
const params: ActionParamsType = {
to: ['jim@example.com'],
cc: ['james@example.com'],
bcc: ['jimmy@example.com'],
subject: 'the subject',
message: 'a message to you',
};
const config: ActionTypeConfigType = {
service: '__json',
host: 'a host',
port: 42,
secure: true,
from: 'bob@example.com',
hasAuth: true,
};
const secrets: ActionTypeSecretsType = {
user: 'bob',
password: 'supersecret',
};
const params: ActionParamsType = {
to: ['jim@example.com'],
cc: ['james@example.com'],
bcc: ['jimmy@example.com'],
subject: 'the subject',
message: 'a message to you',
kibanaFooterLink: {
path: '/',
text: 'Go to Kibana',
},
};

const actionId = 'some-id';
const executorOptions: EmailActionTypeExecutorOptions = {
actionId,
config,
params,
secrets,
services,
};

const actionId = 'some-id';
const executorOptions: EmailActionTypeExecutorOptions = {
actionId,
config,
params,
secrets,
services,
};
test('ensure parameters are as expected', async () => {
sendEmailMock.mockReset();
const result = await actionType.executor(executorOptions);
expect(result).toMatchInlineSnapshot(`
Expand All @@ -267,69 +276,63 @@ describe('execute()', () => {
}
`);
expect(sendEmailMock.mock.calls[0][1]).toMatchInlineSnapshot(`
Object {
"content": Object {
"message": "a message to you",
"subject": "the subject",
},
"hasAuth": true,
"proxySettings": undefined,
"routing": Object {
"bcc": Array [
"jimmy@example.com",
],
"cc": Array [
"james@example.com",
],
"from": "bob@example.com",
"to": Array [
"jim@example.com",
],
},
"transport": Object {
"password": "supersecret",
"service": "__json",
"user": "bob",
},
}
Object {
"content": Object {
"message": "a message to you

--

This message was sent by Kibana.",
"subject": "the subject",
},
"hasAuth": true,
"proxySettings": undefined,
"routing": Object {
"bcc": Array [
"jimmy@example.com",
],
"cc": Array [
"james@example.com",
],
"from": "bob@example.com",
"to": Array [
"jim@example.com",
],
},
"transport": Object {
"password": "supersecret",
"service": "__json",
"user": "bob",
},
}
`);
});

test('parameters are as expected with no auth', async () => {
const config: ActionTypeConfigType = {
service: null,
host: 'a host',
port: 42,
secure: true,
from: 'bob@example.com',
hasAuth: false,
};
const secrets: ActionTypeSecretsType = {
user: null,
password: null,
};
const params: ActionParamsType = {
to: ['jim@example.com'],
cc: ['james@example.com'],
bcc: ['jimmy@example.com'],
subject: 'the subject',
message: 'a message to you',
const customExecutorOptions: EmailActionTypeExecutorOptions = {
...executorOptions,
config: {
...config,
service: null,
hasAuth: false,
},
secrets: {
...secrets,
user: null,
password: null,
},
};

const actionId = 'some-id';
const executorOptions: EmailActionTypeExecutorOptions = {
actionId,
config,
params,
secrets,
services,
};
sendEmailMock.mockReset();
await actionType.executor(executorOptions);
await actionType.executor(customExecutorOptions);
expect(sendEmailMock.mock.calls[0][1]).toMatchInlineSnapshot(`
Object {
"content": Object {
"message": "a message to you",
"message": "a message to you

--

This message was sent by Kibana.",
"subject": "the subject",
},
"hasAuth": false,
Expand All @@ -356,37 +359,23 @@ describe('execute()', () => {
});

test('returns expected result when an error is thrown', async () => {
const config: ActionTypeConfigType = {
service: null,
host: 'a host',
port: 42,
secure: true,
from: 'bob@example.com',
hasAuth: false,
};
const secrets: ActionTypeSecretsType = {
user: null,
password: null,
};
const params: ActionParamsType = {
to: ['jim@example.com'],
cc: ['james@example.com'],
bcc: ['jimmy@example.com'],
subject: 'the subject',
message: 'a message to you',
const customExecutorOptions: EmailActionTypeExecutorOptions = {
...executorOptions,
config: {
...config,
service: null,
hasAuth: false,
},
secrets: {
...secrets,
user: null,
password: null,
},
};

const actionId = 'some-id';
const executorOptions: EmailActionTypeExecutorOptions = {
actionId,
config,
params,
secrets,
services,
};
sendEmailMock.mockReset();
sendEmailMock.mockRejectedValue(new Error('wops'));
const result = await actionType.executor(executorOptions);
const result = await actionType.executor(customExecutorOptions);
expect(result).toMatchInlineSnapshot(`
Object {
"actionId": "some-id",
Expand All @@ -405,15 +394,19 @@ describe('execute()', () => {
bcc: ['jim', '{{rogue}}', 'bob'],
subject: '{{rogue}}',
message: '{{rogue}}',
kibanaFooterLink: {
path: '/',
text: 'Go to Kibana',
},
};
const variables = {
rogue: '*bold*',
};
const params = actionType.renderParameterTemplates!(paramsWithTemplates, variables);
const renderedParams = actionType.renderParameterTemplates!(paramsWithTemplates, variables);
// Yes, this is tested in the snapshot below, but it's double-escaped there,
// so easier to see here that the escaping is correct.
expect(params.message).toBe('\\*bold\\*');
expect(params).toMatchInlineSnapshot(`
expect(renderedParams.message).toBe('\\*bold\\*');
expect(renderedParams).toMatchInlineSnapshot(`
Object {
"bcc": Array [
"jim",
Expand All @@ -423,10 +416,65 @@ describe('execute()', () => {
"cc": Array [
"*bold*",
],
"kibanaFooterLink": Object {
"path": "/",
"text": "Go to Kibana",
},
"message": "\\\\*bold\\\\*",
"subject": "*bold*",
"to": Array [],
}
`);
});

test('provides a footer link to Kibana when publicBaseUrl is defined', async () => {
const actionTypeWithPublicUrl = getActionType({
logger: mockedLogger,
configurationUtilities: actionsConfigMock.create(),
publicBaseUrl: 'https://localhost:1234/foo/bar',
});

await actionTypeWithPublicUrl.executor(executorOptions);

expect(sendEmailMock).toHaveBeenCalledTimes(1);
const sendMailCall = sendEmailMock.mock.calls[0][1];
expect(sendMailCall.content.message).toMatchInlineSnapshot(`
"a message to you

--

This message was sent by Kibana. [Go to Kibana](https://localhost:1234/foo/bar)."
`);
});

test('allows to generate a deep link into Kibana when publicBaseUrl is defined', async () => {
const actionTypeWithPublicUrl = getActionType({
logger: mockedLogger,
configurationUtilities: actionsConfigMock.create(),
publicBaseUrl: 'https://localhost:1234/foo/bar',
});

const customExecutorOptions: EmailActionTypeExecutorOptions = {
...executorOptions,
params: {
...params,
kibanaFooterLink: {
path: '/my/app',
text: 'View this in Kibana',
},
},
};

await actionTypeWithPublicUrl.executor(customExecutorOptions);

expect(sendEmailMock).toHaveBeenCalledTimes(1);
const sendMailCall = sendEmailMock.mock.calls[0][1];
expect(sendMailCall.content.message).toMatchInlineSnapshot(`
"a message to you

--

This message was sent by Kibana. [View this in Kibana](https://localhost:1234/foo/bar/my/app)."
`);
});
});
Loading