Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
160 changes: 155 additions & 5 deletions Slack.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function registerEvents()
'ScheduledReports.sendReport' => 'sendReport',
'Template.reportParametersScheduledReports' => 'templateReportParametersScheduledReports',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
'CustomAlerts.validateReportParameters' => 'validateCustomAlertReportParameters',
'CustomAlerts.validateReportParameters' => 'validateCustomAlertReportParameters',
'CustomAlerts.sendNewAlerts' => 'sendNewAlerts',
];
}
Expand All @@ -76,6 +76,16 @@ public function getClientSideTranslationKeys(&$translationKeys)
$translationKeys[] = 'Slack_SlackEnterYourSlackChannelIdHelpText';
}

/**
*
* Validates the Schedule Report for Slack reportType
*
* @param $parameters
* @param $reportType
* @return void
* @throws \Piwik\Exception\DI\DependencyException
* @throws \Piwik\Exception\DI\NotFoundException
*/
public function validateReportParameters(&$parameters, $reportType)
{
if (!self::isSlackEvent($reportType)) {
Expand Down Expand Up @@ -106,8 +116,23 @@ public function validateReportParameters(&$parameters, $reportType)
} elseif (empty($parameters[self::SLACK_CHANNEL_ID_PARAMETER])) {
throw new \Exception(Piwik::translate('Slack_SlackChannelIdRequiredErrorMessage'));
}
$slackChannels = explode(',', (string) $parameters[self::SLACK_CHANNEL_ID_PARAMETER]);
foreach ($slackChannels as $slackChannel) {
if (!ctype_alnum($slackChannel)) {
throw new \Exception(Piwik::translate('Slack_SlackChannelIdInvalidErrorMessage'));
}
}
}

/**
*
* Get report metadata for Slack scheduled report
*
* @param $availableReportMetadata
* @param $reportType
* @param $idSite
* @return void
*/
public function getReportMetadata(&$availableReportMetadata, $reportType, $idSite)
{
if (!self::isSlackEvent($reportType)) {
Expand All @@ -121,25 +146,58 @@ public function getReportMetadata(&$availableReportMetadata, $reportType, $idSit
);
}

/**
*
* Adds Slack as a reportType in Schedule Reports
*
* @param $reportTypes
* @return void
*/
public function getReportTypes(&$reportTypes)
{
$reportTypes = array_merge($reportTypes, self::$managedReportTypes);
}

/**
*
* Adds allowed reportTypes for Slack, e.g. PDF, CSV and TSV
*
* @param $reportFormats
* @param $reportType
* @return void
*/
public function getReportFormats(&$reportFormats, $reportType)
{
if (self::isSlackEvent($reportType)) {
$reportFormats = array_merge($reportFormats, self::$managedReportFormats);
}
}

/**
*
* Adds report parameter for Slack, e.g. SlackChannelID
*
* @param $availableParameters
* @param $reportType
* @return void
*/
public function getReportParameters(&$availableParameters, $reportType)
{
if (self::isSlackEvent($reportType)) {
$availableParameters = self::$availableParameters;
}
}

/**
*
* Process the Schedule report for reportType Slack
*
* @param $processedReports
* @param $reportType
* @param $outputType
* @param $report
* @return void
*/
public function processReports(&$processedReports, $reportType, $outputType, $report)
{
if (!self::isSlackEvent($reportType)) {
Expand All @@ -153,6 +211,17 @@ public function processReports(&$processedReports, $reportType, $outputType, $re
);
}

/**
*
* Sets the rendered instance based on reportFormat for Slack
*
* @param $reportRenderer
* @param $reportType
* @param $outputType
* @param $report
* @return void
* @throws \Exception
*/
public function getRendererInstance(&$reportRenderer, $reportType, $outputType, $report)
{
if (!self::isSlackEvent($reportType)) {
Expand All @@ -164,13 +233,30 @@ public function getRendererInstance(&$reportRenderer, $reportType, $outputType,
$reportRenderer = ReportRenderer::factory($reportFormat);
}

/**
*
* To allow multiple reports in a single file
*
* @param $allowMultipleReports
* @param $reportType
* @return void
*/
public function allowMultipleReports(&$allowMultipleReports, $reportType)
{
if (self::isSlackEvent($reportType)) {
$allowMultipleReports = true;
}
}

/**
*
* Displays the recipients in the list of Schedule Reports
*
* @param $recipients
* @param $reportType
* @param $report
* @return void
*/
public function getReportRecipients(&$recipients, $reportType, $report)
{
if (!self::isSlackEvent($reportType) || empty($report['parameters'][self::SLACK_CHANNEL_ID_PARAMETER])) {
Expand All @@ -181,6 +267,9 @@ public function getReportRecipients(&$recipients, $reportType, $report)
}

/**
*
* Code to send a Schedule Report via Slack
*
* @param $reportType
* @param $report
* @param $contents
Expand All @@ -189,8 +278,11 @@ public function getReportRecipients(&$recipients, $reportType, $report)
* @param $reportSubject
* @param $reportTitle
* @param $additionalFiles
* @param Period|null $period
* @param $period
* @param $force
* @return void
* @throws \Piwik\Exception\DI\DependencyException
* @throws \Piwik\Exception\DI\NotFoundException
*/
public function sendReport(
$reportType,
Expand Down Expand Up @@ -232,6 +324,16 @@ public function sendReport(
$scheduleReportSlack->send();
}

/**
*
* Add the view template for Slack report parameters
*
* @param $out
* @param $context
* @return void
* @throws \Piwik\Exception\DI\DependencyException
* @throws \Piwik\Exception\DI\NotFoundException
*/
public function templateReportParametersScheduledReports(&$out, $context = '')
{
if (Piwik::isUserIsAnonymous()) {
Expand Down Expand Up @@ -277,17 +379,42 @@ public function uninstall()
return;
}

/**
*
* Validation check for CustomAlert report parameters
*
* @param $parameters
* @param $alertMedium
* @return void
* @throws \Exception
*/
public function validateCustomAlertReportParameters($parameters, $alertMedium)
{
if ($alertMedium === self::SLACK_TYPE && empty($parameters[self::SLACK_CHANNEL_ID_PARAMETER])) {
throw new \Exception(Piwik::translate('Slack_SlackChannelIdRequiredErrorMessage'));
if ($alertMedium === self::SLACK_TYPE) {
$settings = StaticContainer::get(SystemSettings::class);
if (empty($settings->slackOauthToken->getValue())) {
throw new \Exception(Piwik::translate('Slack_OauthTokenRequiredErrorMessage'));
} elseif (empty($parameters[self::SLACK_CHANNEL_ID_PARAMETER])) {
throw new \Exception(Piwik::translate('Slack_SlackChannelIdRequiredErrorMessage'));
} elseif (!ctype_alnum($parameters[self::SLACK_CHANNEL_ID_PARAMETER])) {
throw new \Exception(Piwik::translate('Slack_SlackChannelIdInvalidErrorMessage'));
}
}
}

/**
*
* Code to send CustomAlerts via Slack
*
* @param $triggeredAlerts
* @return void
* @throws \Piwik\Exception\DI\DependencyException
* @throws \Piwik\Exception\DI\NotFoundException
*/
public function sendNewAlerts($triggeredAlerts): void
{
if (!empty($triggeredAlerts)) {
$enrichTriggerAlerts = new EnrichTriggeredAlerts();
$enrichTriggerAlerts = StaticContainer::get(EnrichTriggeredAlerts::class);
$triggeredAlerts = $enrichTriggerAlerts->enrichTriggeredAlerts($triggeredAlerts);
$settings = StaticContainer::get(SystemSettings::class);
$token = $settings->slackOauthToken->getValue();
Expand All @@ -305,6 +432,13 @@ public function sendNewAlerts($triggeredAlerts): void
}
}

/**
*
* Group alerts by slackChannelID to reduce number of network calls for multiple alerts
*
* @param array $alerts
* @return array
*/
private function groupAlertsByChannelId(array $alerts): array
{
$groupedAlerts = [];
Expand All @@ -321,11 +455,27 @@ private function groupAlertsByChannelId(array $alerts): array
return $groupedAlerts;
}

/**
*
* Returns the alert message to send via Slack
*
* @param array $alert
* @param string $metric
* @param string $reportName
* @return string
*/
public function getAlertMessage(array $alert, string $metric, string $reportName): string
{
return Piwik::translate('Slack_SlackAlertContent', [$alert['name'], $alert['siteName'], $metric, $reportName, $this->transformAlertCondition($alert)]);
}

/**
*
* Transform the alert condition to text
*
* @param array $alert
* @return string
*/
private function transformAlertCondition(array $alert): string
{
switch ($alert['metric_condition']) {
Expand Down
50 changes: 50 additions & 0 deletions SlackApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ public function uploadFile(string $subject, string $fileName, string $fileConten
return false;
}

/**
*
* Get the URL to upload the file
*
* @param string $fileName
* @param int $fileLength
* @return string
*/
public function getUploadURLExternal(string $fileName, int $fileLength): string
{
try {
Expand Down Expand Up @@ -93,6 +101,14 @@ public function getUploadURLExternal(string $fileName, int $fileLength): string
return '';
}

/**
*
* Upload the file contents to the URL received from getUploadURLExternal method
*
* @param string $uploadURL
* @param string $fileContents
* @return bool
*/
public function sendFile(string $uploadURL, string $fileContents): bool
{
try {
Expand All @@ -111,6 +127,15 @@ public function sendFile(string $uploadURL, string $fileContents): bool
return strtolower($response) === ('ok - ' . strlen($fileContents));
}


/**
*
* Post the uploaded file to a channel
*
* @param string $channel
* @param string $subject
* @return bool
*/
public function completeUploadExternal(string $channel, string $subject): bool
{
try {
Expand All @@ -135,8 +160,21 @@ public function completeUploadExternal(string $channel, string $subject): bool
return !empty($data['ok']);
}

/**
*
* Send a text message to a Slack channel
*
* @param string $message
* @param string $channel
* @return bool
*/
public function sendMessage(string $message, string $channel): bool
{
if (empty($message) || empty($channel)) {
$this->logger->debug('Empty message or channel for sending message');
return false;
}

try {
$response = $this->sendHttpRequest(
self::SLACK_POST_MESSAGE_URL,
Expand All @@ -158,6 +196,18 @@ public function sendMessage(string $message, string $channel): bool
return !empty($data['ok']);
}

/**
*
* Wrapper to send HTTP request
*
* @param string $url
* @param int $timeout
* @param array $requestBody
* @param array $additionalHeaders
* @param $requestBodyAsString
* @return array|bool|int[]|string
* @throws \Exception
*/
public function sendHttpRequest(string $url, int $timeout, array $requestBody, array $additionalHeaders = [], $requestBodyAsString = false)
{
if ($requestBodyAsString && !empty($requestBody[0])) {
Expand Down
1 change: 1 addition & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"OauthTokenSettingDescription": "Enter your Slack OAuth Token generated from your Slack. %1$sLearn more%2$s.",
"PleaseFindYourReport": "Here is your %1$s report for %2$s",
"SlackChannelIdRequiredErrorMessage": "Slack Channel ID cannot be empty.",
"SlackChannelIdInvalidErrorMessage": "Invalid Slack Channel ID, only alphanumeric values are allowed.",
"SlackChannel": "Slack Channel",
"SlackEnterYourSlackChannelIdHelpText": "Enter the Slack Channel ID of the channel that will receive these reports. To find the ID, go to Slack and open the channel details > About tab. %1$sLearn more%2$s",
"SlackAlertContent": "%1$s has been triggered for website %2$s as the metric %3$s in report %4$s %5$s."
Expand Down
Loading