From 96ab3bb28cce0a9445f046e88a577b3b0f07be28 Mon Sep 17 00:00:00 2001 From: Zhongnan Su Date: Mon, 18 Oct 2021 13:52:36 -0700 Subject: [PATCH 1/2] remove the email tempalte and helpers from dashboards plugin --- dashboards-reports/package.json | 1 - .../report_definitions/delivery/delivery.tsx | 175 ++++--- .../notification/deliveryContentHelper.ts | 56 --- .../email_content_template.html | 470 ------------------ .../notification_content_template/logo.png | Bin 7098 -> 0 bytes dashboards-reports/yarn.lock | 169 +------ 6 files changed, 95 insertions(+), 776 deletions(-) delete mode 100644 dashboards-reports/server/routes/utils/notification/deliveryContentHelper.ts delete mode 100644 dashboards-reports/server/routes/utils/notification/notification_content_template/email_content_template.html delete mode 100644 dashboards-reports/server/routes/utils/notification/notification_content_template/logo.png diff --git a/dashboards-reports/package.json b/dashboards-reports/package.json index 06e8eb1e..ac97ba8d 100644 --- a/dashboards-reports/package.json +++ b/dashboards-reports/package.json @@ -22,7 +22,6 @@ "dependencies": { "async-mutex": "^0.2.6", "babel-polyfill": "^6.26.0", - "cheerio": "0.22.0", "cron-validator": "^1.1.1", "dompurify": "^2.1.1", "elastic-builder": "^2.7.1", diff --git a/dashboards-reports/public/components/report_definitions/delivery/delivery.tsx b/dashboards-reports/public/components/report_definitions/delivery/delivery.tsx index f35affb7..bfa28504 100644 --- a/dashboards-reports/public/components/report_definitions/delivery/delivery.tsx +++ b/dashboards-reports/public/components/report_definitions/delivery/delivery.tsx @@ -39,11 +39,11 @@ import { EuiButton, } from '@elastic/eui'; import CSS from 'csstype'; -import { - getChannelsQueryObject, - noDeliveryChannelsSelectedMessage, - testMessageConfirmationMessage, - testMessageFailureMessage +import { + getChannelsQueryObject, + noDeliveryChannelsSelectedMessage, + testMessageConfirmationMessage, + testMessageFailureMessage, } from './delivery_constants'; import 'react-mde/lib/styles/css/react-mde-all.css'; import { reportDefinitionParams } from '../create/create_report_definition'; @@ -83,7 +83,7 @@ export function ReportDelivery(props: ReportDeliveryProps) { showDeliverySubjectError, deliverySubjectError, showDeliveryTextError, - deliveryTextError + deliveryTextError, } = props; const [isDeliveryHidden, setIsHidden] = useState(false); @@ -91,47 +91,54 @@ export function ReportDelivery(props: ReportDeliveryProps) { const [channels, setChannels] = useState([]); const [selectedChannels, setSelectedChannels] = useState([]); const [notificationSubject, setNotificationSubject] = useState('New report'); - const [notificationMessage, setNotificationMessage] = useState('New report available to view'); + const [notificationMessage, setNotificationMessage] = useState( + 'New report available to view' + ); const [selectedTab, setSelectedTab] = React.useState<'write' | 'preview'>( 'write' ); const [testMessageConfirmation, setTestMessageConfirmation] = useState(''); - const handleSendNotification = (e: { target: { checked: boolean }; }) => { + const handleSendNotification = (e: { target: { checked: boolean } }) => { setSendNotification(e.target.checked); includeDelivery = e.target.checked; if (includeDelivery) { reportDefinitionRequest.delivery.title = 'New report'; - reportDefinitionRequest.delivery.textDescription = 'New report available to view'; - } - else { + reportDefinitionRequest.delivery.textDescription = + 'New report available to view'; + reportDefinitionRequest.delivery.htmlDescription = converter.makeHtml( + 'New report available to view' + ); + } else { reportDefinitionRequest.delivery.title = `\u2014`; reportDefinitionRequest.delivery.textDescription = `\u2014`; } - } + }; - const handleSelectedChannels = (e: Array<{ label: string, id: string}>) => { + const handleSelectedChannels = (e: Array<{ label: string; id: string }>) => { setSelectedChannels(e); reportDefinitionRequest.delivery.configIds = []; for (let i = 0; i < e.length; ++i) { reportDefinitionRequest.delivery.configIds.push(e[i].id); } - } + }; - const handleNotificationSubject = (e: { target: { value: string }; }) => { + const handleNotificationSubject = (e: { target: { value: string } }) => { setNotificationSubject(e.target.value); reportDefinitionRequest.delivery.title = e.target.value; - } + }; const handleNotificationMessage = (e: string) => { setNotificationMessage(e); reportDefinitionRequest.delivery.textDescription = e.toString(); - reportDefinitionRequest.delivery.htmlDescription = converter.makeHtml(e.toString()); - } + reportDefinitionRequest.delivery.htmlDescription = converter.makeHtml( + e.toString() + ); + }; const handleTestMessageConfirmation = (e: JSX.Element) => { setTestMessageConfirmation(e); - } + }; const defaultCreateDeliveryParams = () => { includeDelivery = false; @@ -139,7 +146,7 @@ export function ReportDelivery(props: ReportDeliveryProps) { configIds: [], title: `\u2014`, // default values before any Notifications settings are configured textDescription: `\u2014`, - htmlDescription: '' + htmlDescription: '', }; }; @@ -149,8 +156,8 @@ export function ReportDelivery(props: ReportDeliveryProps) { }; const eventToNotification = (event: any) => { - const success = event.event.status_list.every( - (status: any) => isStatusCodeSuccess(status.delivery_status.status_code) + const success = event.event.status_list.every((status: any) => + isStatusCodeSuccess(status.delivery_status.status_code) ); return { event_source: event.event.event_source, @@ -179,23 +186,24 @@ export function ReportDelivery(props: ReportDeliveryProps) { for (let i = 0; i < selectedChannels.length; ++i) { try { const eventId = await httpClientProps - .get(`${REPORTING_NOTIFICATIONS_DASHBOARDS_API.SEND_TEST_MESSAGE}/${selectedChannels[i].id}`, - { - query: { - feature: 'reports' + .get( + `${REPORTING_NOTIFICATIONS_DASHBOARDS_API.SEND_TEST_MESSAGE}/${selectedChannels[i].id}`, + { + query: { + feature: 'reports', + }, } - }) + ) .then((response) => response.event_id); - - await getNotification(eventId) - .then((response) => { - if (!response.success) { - const error = new Error('Failed to send the test message.'); - failedChannels.push(response.status_list[0].config_name); - error.stack = JSON.stringify(response.status_list, null, 2); - throw error; - } - }); + + await getNotification(eventId).then((response) => { + if (!response.success) { + const error = new Error('Failed to send the test message.'); + failedChannels.push(response.status_list[0].config_name); + error.stack = JSON.stringify(response.status_list, null, 2); + throw error; + } + }); } catch (error) { testMessageFailures = true; } @@ -205,39 +213,44 @@ export function ReportDelivery(props: ReportDeliveryProps) { } else { handleTestMessageConfirmation(testMessageConfirmationMessage); } - } + }; const checkIfNotificationsPluginIsInstalled = () => { - fetch("../api/console/proxy?path=%2F_cat%2Fplugins%3Fv%3Dtrue%26s%3Dcomponent%26h%3Dcomponent&method=GET", { - "credentials": "include", - "headers": { - "Accept": "text/plain, */*; q=0.01", - "Accept-Language": "en-US,en;q=0.5", - "osd-xsrf": "true" - }, - "method": "POST", - "mode": "cors" - }) - .then((response) => { - return response.text(); - }) - .then(function(data) { - if (data.includes('opensearch-notifications')) { - setIsHidden(false); - return; + fetch( + '../api/console/proxy?path=%2F_cat%2Fplugins%3Fv%3Dtrue%26s%3Dcomponent%26h%3Dcomponent&method=GET', + { + credentials: 'include', + headers: { + Accept: 'text/plain, */*; q=0.01', + 'Accept-Language': 'en-US,en;q=0.5', + 'osd-xsrf': 'true', + }, + method: 'POST', + mode: 'cors', } - setIsHidden(true); - }) - } + ) + .then((response) => { + return response.text(); + }) + .then(function (data) { + if (data.includes('opensearch-notifications')) { + setIsHidden(false); + return; + } + setIsHidden(true); + }); + }; useEffect(() => { checkIfNotificationsPluginIsInstalled(); httpClientProps .get(`${REPORTING_NOTIFICATIONS_DASHBOARDS_API.GET_CONFIGS}`, { - query: getChannelsQueryObject + query: getChannelsQueryObject, }) - .then(async (response: any) => { - let availableChannels = getAvailableNotificationsChannels(response.config_list); + .then(async (response: any) => { + let availableChannels = getAvailableNotificationsChannels( + response.config_list + ); setChannels(availableChannels); return availableChannels; }) @@ -248,7 +261,7 @@ export function ReportDelivery(props: ReportDeliveryProps) { .then(async (response: any) => { if (response.report_definition.delivery.configIds.length > 0) { // add config IDs - handleSendNotification({target: {checked: true}}); + handleSendNotification({ target: { checked: true } }); let delivery = response.report_definition.delivery; let editChannelOptions = []; for (let i = 0; i < delivery.configIds.length; ++i) { @@ -256,10 +269,10 @@ export function ReportDelivery(props: ReportDeliveryProps) { if (delivery.configIds[i] === availableChannels[j].id) { let editChannelOption = { label: availableChannels[j].label, - id: availableChannels[j].id + id: availableChannels[j].id, }; editChannelOptions.push(editChannelOption); - break; + break; } } } @@ -274,20 +287,23 @@ export function ReportDelivery(props: ReportDeliveryProps) { } }) .catch((error: string) => { - console.log('error: cannot get available channels from Notifications plugin:', error); - }) + console.log( + 'error: cannot get available channels from Notifications plugin:', + error + ); + }); }, []); const showNotificationsBody = sendNotification ? (
- - - + + Send test message @@ -356,8 +367,8 @@ export function ReportDelivery(props: ReportDeliveryProps) { diff --git a/dashboards-reports/server/routes/utils/notification/deliveryContentHelper.ts b/dashboards-reports/server/routes/utils/notification/deliveryContentHelper.ts deleted file mode 100644 index 1c1aa22f..00000000 --- a/dashboards-reports/server/routes/utils/notification/deliveryContentHelper.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -/* - * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -import fs from 'fs'; -import cheerio from 'cheerio'; - -export const composeEmbeddedHtml = ( - htmlDescription: string = '', - originalQueryUrl: string, - reportDetailUrl: string, - reportName: string -) => { - const logoAsBase64 = fs.readFileSync( - `${__dirname}/notification_content_template/logo.png`, - 'base64' - ); - - const $ = cheerio.load( - fs.readFileSync( - `${__dirname}/notification_content_template/email_content_template.html` - ), - { decodeEntities: false } - ); - // set each link and logo - $('.logo').attr('src', `data:image/png;base64,${logoAsBase64}`); - $('.report_name').attr('href', reportDetailUrl).text(reportName); - $('.report_snapshot').attr('href', originalQueryUrl); - $('.optional_message').html(htmlDescription); - //TODO: Add this once we have the actual link to download - // $('.report_download').attr('href', '') - - return $.root().html(); -}; diff --git a/dashboards-reports/server/routes/utils/notification/notification_content_template/email_content_template.html b/dashboards-reports/server/routes/utils/notification/notification_content_template/email_content_template.html deleted file mode 100644 index 42871d67..00000000 --- a/dashboards-reports/server/routes/utils/notification/notification_content_template/email_content_template.html +++ /dev/null @@ -1,470 +0,0 @@ - - - - - - - OpenSearch Dashboards Reports: %REPORT_TITLE% - - - - - A new OpenSearch Dashboards report is available                 -                                 -                                 -                                 -                               - - - - - - - - - - - diff --git a/dashboards-reports/server/routes/utils/notification/notification_content_template/logo.png b/dashboards-reports/server/routes/utils/notification/notification_content_template/logo.png deleted file mode 100644 index 2b32eb9425b92e9c793f2f571cdc5f5ea35cd909..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7098 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 y9cy10`TXZxkITW6LnCFJ13fbQ|Bn-=cc=eUAi Date: Mon, 18 Oct 2021 14:52:44 -0700 Subject: [PATCH 2/2] build email message from template for reporting notifcation Signed-off-by: Zhongnan Su --- reports-scheduler/build.gradle | 1 + .../action/ReportInstanceActions.kt | 3 +- .../notifications/MessageBuilder.kt | 49 ++ .../notifications/NotificationsActions.kt | 25 +- .../template/email_content_template.html | 470 ++++++++++++++++++ .../resources/notifications/template/logo.png | Bin 0 -> 7098 bytes 6 files changed, 540 insertions(+), 8 deletions(-) create mode 100644 reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/MessageBuilder.kt create mode 100644 reports-scheduler/src/main/resources/notifications/template/email_content_template.html create mode 100644 reports-scheduler/src/main/resources/notifications/template/logo.png diff --git a/reports-scheduler/build.gradle b/reports-scheduler/build.gradle index 291ea9f7..abc4c9d4 100644 --- a/reports-scheduler/build.gradle +++ b/reports-scheduler/build.gradle @@ -146,6 +146,7 @@ dependencies { compile group: 'com.google.guava', name: 'guava', version: '15.0' compile "org.json:json:20180813" compile group: 'com.github.wnameless', name: 'json-flattener', version: '0.1.0' + implementation 'org.jsoup:jsoup:1.14.3' testImplementation( 'org.assertj:assertj-core:3.16.1', diff --git a/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/action/ReportInstanceActions.kt b/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/action/ReportInstanceActions.kt index d6514fae..3030c2df 100644 --- a/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/action/ReportInstanceActions.kt +++ b/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/action/ReportInstanceActions.kt @@ -125,8 +125,9 @@ internal object ReportInstanceActions { throw OpenSearchStatusException("Report Instance Creation failed", RestStatus.INTERNAL_SERVER_ERROR) } if (reportDefinitionDetails.reportDefinition.delivery != null) { + val reportName = reportInstance.reportDefinitionDetails!!.reportDefinition.name val reportLink = buildReportLink(reportDefinitionDetails.reportDefinition.source.origin, reportInstance.tenant, docId) - NotificationsActions.send(reportDefinitionDetails.reportDefinition.delivery, docId, reportLink) + NotificationsActions.send(reportDefinitionDetails.reportDefinition.delivery, docId, reportLink, reportName) } val reportInstanceCopy = reportInstance.copy(id = docId) return OnDemandReportCreateResponse(reportInstanceCopy, true) diff --git a/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/MessageBuilder.kt b/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/MessageBuilder.kt new file mode 100644 index 00000000..df4ceb31 --- /dev/null +++ b/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/MessageBuilder.kt @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.reportsscheduler.notifications + +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import org.opensearch.commons.utils.logger +import java.util.Base64 + +/** + * Provide functions to build email message with html template, or pure text message for non-email channels + */ +internal object MessageBuilder { + private val log by logger(MessageBuilder::class.java) + + private const val LOGO_ID = "logo" + private const val REPORT_NAME_ID = "report_name" + private const val OPEN_IN_REPORTING_BUTTON_ID = "open_in_reporting_button" + private const val OPTIONAL_MESSAGE_ID = "optional_message" + private const val EMAIL_HTML_TEMPLATE_PATH = "/notifications/template/email_content_template.html" + private const val LOGO_PATH = "/notifications/template/logo.png" + // load logo and html template + private val templateHtml = javaClass.getResource(EMAIL_HTML_TEMPLATE_PATH)!!.readText() + private val logo = javaClass.getResource(LOGO_PATH)!!.readBytes() + private val encodedLogo: String = Base64.getEncoder().encodeToString(logo) + + fun buildEmailMessageWithTemplate(htmlDescription: String, reportLink: String, reportName: String): String { + val doc: Document = Jsoup.parse(templateHtml) + doc.getElementById(LOGO_ID)?.attr("src", "data:image/png;base64,$encodedLogo") + doc.getElementById(REPORT_NAME_ID)?.attr("href", reportLink)?.text(reportName) + doc.getElementById(OPEN_IN_REPORTING_BUTTON_ID)?.attr("href", reportLink) + doc.getElementById(OPTIONAL_MESSAGE_ID)?.html(htmlDescription) + + return doc.html() + } + + fun buildTextMessage(textDescription: String, reportLink: String, reportName: String): String { + return "$textDescription\nYour Report [$reportName] is now available at $reportLink" + } +} diff --git a/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/NotificationsActions.kt b/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/NotificationsActions.kt index 072c4a79..0df6e67b 100644 --- a/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/NotificationsActions.kt +++ b/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/NotificationsActions.kt @@ -50,8 +50,8 @@ internal object NotificationsActions { * @param referenceId [String] object * @return [CreateReportDefinitionResponse] */ - fun send(delivery: ReportDefinition.Delivery, referenceId: String, reportLink: String): SendNotificationResponse? { - return send(delivery, referenceId, reportLink, "") + fun send(delivery: ReportDefinition.Delivery, referenceId: String, reportLink: String, reportName: String): SendNotificationResponse? { + return send(delivery, referenceId, reportLink, reportName, "") } /** @@ -61,9 +61,15 @@ internal object NotificationsActions { * @param userStr [String] object, * @return [CreateReportDefinitionResponse] */ - fun send(delivery: ReportDefinition.Delivery, referenceId: String, reportLink: String, userStr: String?): SendNotificationResponse? { + fun send( + delivery: ReportDefinition.Delivery, + referenceId: String, + reportLink: String, + reportName: String, + userStr: String? + ): SendNotificationResponse? { if (userStr.isNullOrEmpty()) { - return sendNotificationHelper(delivery, referenceId, reportLink) + return sendNotificationHelper(delivery, referenceId, reportLink, reportName) } var sendNotificationResponse: SendNotificationResponse? = null @@ -72,7 +78,7 @@ internal object NotificationsActions { ConfigConstants.OPENSEARCH_SECURITY_USER_INFO_THREAD_CONTEXT, userStr ) - sendNotificationResponse = sendNotificationHelper(delivery, referenceId, reportLink) + sendNotificationResponse = sendNotificationHelper(delivery, referenceId, reportLink, reportName) } return sendNotificationResponse } @@ -81,7 +87,8 @@ internal object NotificationsActions { private fun sendNotificationHelper( delivery: ReportDefinition.Delivery, referenceId: String, - reportLink: String + reportLink: String, + reportName: String ): SendNotificationResponse? { log.info("$LOG_PREFIX:NotificationsActions-send") var sendNotificationResponse: SendNotificationResponse? = null @@ -90,7 +97,11 @@ internal object NotificationsActions { NotificationsPluginInterface.sendNotification( client, EventSource(delivery.title, referenceId, FEATURE_REPORTS, SeverityType.INFO), - ChannelMessage("${delivery.textDescription}\nGet your report at $reportLink", delivery.htmlDescription, null), + ChannelMessage( + MessageBuilder.buildTextMessage(delivery.textDescription, reportLink, reportName), + delivery.htmlDescription?.let { MessageBuilder.buildEmailMessageWithTemplate(it, reportLink, reportName) }, + null + ), delivery.configIds, object : ActionListener { override fun onResponse(response: SendNotificationResponse) { diff --git a/reports-scheduler/src/main/resources/notifications/template/email_content_template.html b/reports-scheduler/src/main/resources/notifications/template/email_content_template.html new file mode 100644 index 00000000..a84981eb --- /dev/null +++ b/reports-scheduler/src/main/resources/notifications/template/email_content_template.html @@ -0,0 +1,470 @@ + + + + + + + OpenSearch Dashboards Reports: %REPORT_TITLE% + + + + + A new OpenSearch Dashboards report is available                 +                                 +                                 +                                 +                               + + + + + + + + + + + diff --git a/reports-scheduler/src/main/resources/notifications/template/logo.png b/reports-scheduler/src/main/resources/notifications/template/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2b32eb9425b92e9c793f2f571cdc5f5ea35cd909 GIT binary patch literal 7098 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 y9cy10`TXZxkITW6LnCFJ13fbQ|Bn-=cc=eUAi