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
28 changes: 17 additions & 11 deletions API.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,14 @@ public function getAlerts($idSites, $ifSuperUserReturnAllAlerts = false)
* @param int $comparedTo
* @param bool|string $reportCondition
* @param bool|string $reportValue
* @param array $reportMediums
* @return int ID of new Alert
*/
public function addAlert($name, $idSites, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition = false, $reportValue = false)
public function addAlert($name, $idSites, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition = false, $reportValue = false, array $reportMediums = [])
{
$idSites = Site::getIdSitesFromIdSitesString($idSites);
$additionalEmails = $this->filterAdditionalEmails($additionalEmails);
$phoneNumbers = $this->filterPhoneNumbers($phoneNumbers);

$this->checkAlert($idSites, $name, $period, $additionalEmails, $metricCondition, $metric, $comparedTo, $reportCondition, $reportUniqueId);
$this->checkAlert($idSites, $name, $period, $emailMe, $additionalEmails, $phoneNumbers, $metricCondition, $metric, $comparedTo, $reportCondition, $reportUniqueId, $reportMediums);

$name = Common::unsanitizeInputValue($name);
$login = Piwik::getCurrentUserLogin();
Expand All @@ -148,7 +147,7 @@ public function addAlert($name, $idSites, $period, $emailMe, $additionalEmails,

$metricValue = Common::forceDotAsSeparatorForDecimalPoint((float)$metricValue);

return $this->getModel()->createAlert($name, $idSites, $login, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition, $reportValue);
return $this->getModel()->createAlert($name, $idSites, $login, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition, $reportValue, $reportMediums);
}

private function filterAdditionalEmails($additionalEmails)
Expand Down Expand Up @@ -182,21 +181,29 @@ private function filterPhoneNumbers($phoneNumbers)
return array_values($phoneNumbers);
}

private function checkAlert($idSites, $name, $period, $additionalEmails, $metricCondition, $metricValue, $comparedTo, $reportCondition, $reportUniqueId)
private function checkAlert($idSites, $name, $period, &$emailMe, &$additionalEmails, &$phoneNumbers, $metricCondition, $metricValue, $comparedTo, $reportCondition, $reportUniqueId, $reportMediums)
{
Piwik::checkUserHasViewAccess($idSites);
$additionalEmails = in_array('email', $reportMediums) ? $this->filterAdditionalEmails($additionalEmails) : [];
$phoneNumbers = in_array('mobile', $reportMediums) ? $this->filterPhoneNumbers($phoneNumbers) : [];
$emailMe = in_array('email', $reportMediums) && $emailMe;

$this->validator->checkName($name);
$this->validator->checkPeriod($period);
$this->validator->checkComparedTo($period, $comparedTo);
$this->validator->checkMetricCondition($metricCondition);
$this->validator->checkReportCondition($reportCondition);
$this->validator->checkReportMediums($reportMediums);

foreach ($idSites as $idSite) {
$this->validator->checkApiMethodAndMetric($idSite, $reportUniqueId, $metricValue);
}

$this->validator->checkAdditionalEmails($additionalEmails);

foreach ($reportMediums as $reportMedium) {
Piwik::postEvent('CustomAlerts.validateReportParameters', [get_defined_vars(), $reportMedium]);
}
}

/**
Expand All @@ -216,19 +223,18 @@ private function checkAlert($idSites, $name, $period, $additionalEmails, $metric
* @param int $comparedTo
* @param bool|string $reportCondition
* @param bool|string $reportValue
* @param array $reportMediums
*
* @return boolean
*/
public function editAlert($idAlert, $name, $idSites, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition = false, $reportValue = false)
public function editAlert($idAlert, $name, $idSites, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition = false, $reportValue = false, array $reportMediums = [])
{
// make sure alert exists and user has permission to read
$this->getAlert($idAlert);

$idSites = Site::getIdSitesFromIdSitesString($idSites);
$additionalEmails = $this->filterAdditionalEmails($additionalEmails);
$phoneNumbers = $this->filterPhoneNumbers($phoneNumbers);

$this->checkAlert($idSites, $name, $period, $additionalEmails, $metricCondition, $metric, $comparedTo, $reportCondition, $reportUniqueId);
$this->checkAlert($idSites, $name, $period, $emailMe, $additionalEmails, $phoneNumbers, $metricCondition, $metric, $comparedTo, $reportCondition, $reportUniqueId, $reportMediums);

$name = Common::unsanitizeInputValue($name);

Expand All @@ -239,7 +245,7 @@ public function editAlert($idAlert, $name, $idSites, $period, $emailMe, $additio

$metricValue = Common::forceDotAsSeparatorForDecimalPoint((float)$metricValue);

return $this->getModel()->updateAlert($idAlert, $name, $idSites, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition, $reportValue);
return $this->getModel()->updateAlert($idAlert, $name, $idSites, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition, $reportValue, $reportMediums);
}

/**
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Changelog

* 5.1.0 - 2025-09-29 Refactored UI to support different mediums to alert and changes to alert via Slack
* 5.0.7 - 2025-07-07 Textual changes
* 5.0.6 - 2024-09-23 Added check if reports used by alert are done archiving and retry if not archived
* 5.0.5 Combined all the actions into one column
Expand Down
7 changes: 4 additions & 3 deletions Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -276,12 +276,13 @@ private function addBasicCreateAndEditVariables($view, $alert)
$view->currentUserEmail = Piwik::getCurrentUserEmail();
$view->comparablesDates = $comparablesDates;
$view->reportMetadata = $this->findReportMetadata($alert);
$view->supportsSMS = $this->supportsSms();
$view->supportsSMS = $this->supportsPlugin('MobileMessaging');
$view->periodOptions = array(
array('key' => 'day', 'value' => Piwik::translate('Intl_PeriodDay')),
array('key' => 'week', 'value' => Piwik::translate('Intl_PeriodWeek')),
array('key' => 'month', 'value' => Piwik::translate('Intl_PeriodMonth')),
);
$view->alertReportMediumOptions = CustomAlerts::getReportMediumOptions();

$numbers = (new \Piwik\Plugins\MobileMessaging\Model())->getActivatedPhoneNumbers(Piwik::getCurrentUserLogin());

Expand All @@ -301,9 +302,9 @@ private function addBasicCreateAndEditVariables($view, $alert)
$view->metricConditionOptions = $metricConditionOptions;
}

private function supportsSms()
private function supportsPlugin(string $pluginName): bool
{
return PluginManager::getInstance()->isPluginActivated('MobileMessaging');
return PluginManager::getInstance()->isPluginActivated($pluginName);
}

public function editAlert()
Expand Down
27 changes: 26 additions & 1 deletion CustomAlerts.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Piwik\Common;
use Piwik\Container\StaticContainer;
use Piwik\Piwik;
use Piwik\Plugin\Manager as PluginManager;
use Piwik\Plugins\SitesManager\API as SitesManagerApi;
use Piwik\Scheduler\Task;

Expand Down Expand Up @@ -44,6 +45,7 @@ public function registerEvents()
'Db.getTablesInstalled' => 'getTablesInstalled',
'ScheduledTasks.execute' => 'startingScheduledTask',
'ScheduledTasks.execute.end' => 'endingScheduledTask',
'CustomAlerts.validateReportParameters' => 'validateReportParameters',
);
}

Expand Down Expand Up @@ -175,7 +177,8 @@ public function removePhoneNumberFromAllAlerts($phoneNumber)
$alert['compared_to'],
$alert['report'],
$alert['report_condition'],
$alert['report_matched']
$alert['report_matched'],
$alert['report_mediums']
);
}
}
Expand Down Expand Up @@ -262,5 +265,27 @@ public function getClientSideTranslationKeys(&$translations)
$translations[] = 'CustomAlerts_ThisAppliesToHelp';
$translations[] = 'General_Yes';
$translations[] = 'General_No';
$translations[] = 'CustomAlerts_MediumTitle';
$translations[] = 'CustomAlerts_MediumDescription';
}

public static function getReportMediumOptions(): array
{
return [
['key' => 'email', 'value' => Piwik::translate('CustomAlerts_MediumEmail'), 'disabled' => false],
['key' => 'mobile', 'value' => Piwik::translate('CustomAlerts_MediumMobile'), 'disabled' => !PluginManager::getInstance()->isPluginActivated('MobileMessaging')],
];
}

public function validateReportParameters($parameters, $alertMedium)
{
if ($alertMedium === 'email' && empty($parameters['emailMe']) && empty($parameters['additionalEmails'])) {
throw new \Exception(Piwik::translate('CustomAlerts_InvalidEmailReportParameter'));
} elseif ($alertMedium === 'mobile' && empty($parameters['phoneNumbers'])) {
if (defined('PIWIK_TEST_MODE') && PIWIK_TEST_MODE) {
return;
}
throw new \Exception(Piwik::translate('CustomAlerts_InvalidPhoneNumberReportParameter'));
}
}
}
18 changes: 13 additions & 5 deletions Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public static function install()
`report` VARCHAR(150) NOT NULL ,
`report_condition` VARCHAR(50) ,
`report_matched` VARCHAR(255) ,
`report_mediums` TEXT ,
`metric` VARCHAR(150) NOT NULL ,
`metric_condition` VARCHAR(50) NOT NULL ,
`metric_matched` FLOAT NOT NULL ,
Expand Down Expand Up @@ -58,6 +59,7 @@ public static function install()
`report` VARCHAR(150) NOT NULL ,
`report_condition` VARCHAR(50) ,
`report_matched` VARCHAR(1000) ,
`report_mediums` TEXT ,
`metric` VARCHAR(150) NOT NULL ,
`metric_condition` VARCHAR(50) NOT NULL ,
`metric_matched` FLOAT NOT NULL ,
Expand Down Expand Up @@ -123,6 +125,7 @@ private function completeAlerts($alerts)
foreach ($alerts as &$alert) {
$alert['additional_emails'] = json_decode($alert['additional_emails']);
$alert['phone_numbers'] = json_decode($alert['phone_numbers']);
$alert['report_mediums'] = json_decode($alert['report_mediums']);
$alert['email_me'] = (int)$alert['email_me'];
$alert['compared_to'] = (int)$alert['compared_to'];
$alert['id_sites'] = $this->getDefinedSiteIds($alert['idalert']);
Expand Down Expand Up @@ -247,11 +250,12 @@ public function getAllAlertsForPeriod($period)
* @param string $reportUniqueId
* @param string $reportCondition
* @param string $reportValue
* @param array $reportMediums
*
* @return int ID of new Alert
* @throws \Exception
*/
public function createAlert($name, $idSites, $login, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition, $reportValue)
public function createAlert($name, $idSites, $login, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition, $reportValue, $reportMediums)
{
$idAlert = $this->getNextAlertId();

Expand All @@ -269,7 +273,8 @@ public function createAlert($name, $idSites, $login, $period, $emailMe, $additio
'report' => $reportUniqueId,
'compared_to' => $comparedTo,
'report_condition' => $reportCondition,
'report_matched' => $reportValue
'report_matched' => $reportValue,
'report_mediums' => json_encode($reportMediums)
);

$db = $this->getDb();
Expand Down Expand Up @@ -326,11 +331,12 @@ private function removeAllSites($idAlert)
* @param string $reportUniqueId
* @param string $reportCondition
* @param string $reportValue
* @param array $reportMediums
*
* @return int
* @throws \Exception
*/
public function updateAlert($idAlert, $name, $idSites, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition, $reportValue)
public function updateAlert($idAlert, $name, $idSites, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition, $reportValue, $reportMediums)
{
$alert = array(
'name' => $name,
Expand All @@ -344,7 +350,8 @@ public function updateAlert($idAlert, $name, $idSites, $period, $emailMe, $addit
'report' => $reportUniqueId,
'compared_to' => $comparedTo,
'report_condition' => $reportCondition,
'report_matched' => $reportValue
'report_matched' => $reportValue,
'report_mediums' => json_encode($reportMediums),
);

$db = $this->getDb();
Expand Down Expand Up @@ -374,7 +381,7 @@ public function triggerAlert($idAlert, $idSite, $valueNew, $valueOld, $datetime)
{
$alert = $this->getAlert($idAlert);

$keysToKeep = array('idalert', 'name', 'login', 'period', 'metric', 'metric_condition', 'metric_matched', 'report', 'report_condition', 'report_matched', 'compared_to', 'email_me', 'additional_emails', 'phone_numbers');
$keysToKeep = array('idalert', 'name', 'login', 'period', 'metric', 'metric_condition', 'metric_matched', 'report', 'report_condition', 'report_matched', 'report_mediums', 'compared_to', 'email_me', 'additional_emails', 'phone_numbers');

$triggeredAlert = array();
foreach ($keysToKeep as $key) {
Expand All @@ -389,6 +396,7 @@ public function triggerAlert($idAlert, $idSite, $valueNew, $valueOld, $datetime)
$triggeredAlert['idsite'] = $idSite;
$triggeredAlert['additional_emails'] = json_encode($triggeredAlert['additional_emails']);
$triggeredAlert['phone_numbers'] = json_encode($triggeredAlert['phone_numbers']);
$triggeredAlert['report_mediums'] = json_encode($triggeredAlert['report_mediums']);

$db = $this->getDb();
$db->insert(
Expand Down
52 changes: 52 additions & 0 deletions Updates/5.1.0.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/

namespace Piwik\Plugins\CustomAlerts;

use Piwik\Common;
use Piwik\Updater;
use Piwik\Updater\Migration\Factory as MigrationFactory;
use Piwik\Updates;

/**
*/
class Updates_5_1_0 extends Updates
{
/**
* @var MigrationFactory
*/
private $migration;

public function __construct(MigrationFactory $factory)
{
$this->migration = $factory;
}

public function doUpdate(Updater $updater)
{
$updater->executeMigrations(__FILE__, $this->getMigrations($updater));
}

public function getMigrations(Updater $updater)
{
$alertTableName = Common::prefixTable('alert');
$alertTriggeredTableName = Common::prefixTable('alert_triggered');
$emailPhoneJson = json_encode(["email","mobile"]);
$emailJson = json_encode(["email"]);
$phoneJson = json_encode(["mobile"]);
$emptyJson = json_encode([]);
return array(
$this->migration->db->addColumn('alert', 'report_mediums', 'TEXT NOT NULL', 'report_matched'),
$this->migration->db->addColumn('alert_triggered', 'report_mediums', 'TEXT NOT NULL', 'report_matched'),
$this->migration->db->sql("UPDATE `$alertTableName` set report_mediums=CASE WHEN (email_me=1 OR additional_emails!='[]') AND phone_numbers!='[]' THEN '$emailPhoneJson' WHEN (email_me=1 OR additional_emails!='[]') AND phone_numbers='[]' THEN '$emailJson' WHEN (email_me!=1 AND additional_emails='[]') AND phone_numbers!='[]' THEN '$phoneJson' ELSE '$emptyJson' END"),
$this->migration->db->sql("UPDATE `$alertTriggeredTableName` set report_mediums=CASE WHEN (email_me=1 OR additional_emails!='[]') AND phone_numbers!='[]' THEN '$emailPhoneJson' WHEN (email_me=1 OR additional_emails!='[]') AND phone_numbers='[]' THEN '$emailJson' WHEN (email_me!=1 AND additional_emails='[]') AND phone_numbers!='[]' THEN '$phoneJson' ELSE '$emptyJson' END"),
);
}
}
27 changes: 27 additions & 0 deletions Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,20 @@ public function checkReportCondition($condition)
}
}

public function checkReportMediums(array $reportMediums)
{
$allowedMediums = $this->getAllowedMediums();
if (empty($reportMediums)) {
throw new Exception(Piwik::translate('CustomAlerts_EmptyReportMediums'));
}

foreach ($reportMediums as $reportMedium) {
if (!in_array($reportMedium, $allowedMediums)) {
throw new Exception(Piwik::translate('CustomAlerts_InvalidReportMediums', [implode(', ', $allowedMediums)]));
}
}
}

public function checkComparedTo($period, $comparedTo)
{
if (!self::isValidComparableDate($period, $comparedTo)) {
Expand Down Expand Up @@ -165,4 +179,17 @@ public function checkUserHasPermissionForAlert($alert)
throw new Exception(Piwik::translate('CustomAlerts_AccessException', $alert['idalert']));
}
}

private function getAllowedMediums(): array
{
$allowedMediums = CustomAlerts::getReportMediumOptions();
$allowedMediumList = [];
foreach ($allowedMediums as $allowedMedium) {
if (!$allowedMedium['disabled']) {
$allowedMediumList[] = $allowedMedium['key'];
}
}

return $allowedMediumList;
}
}
10 changes: 9 additions & 1 deletion lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@
"When": "when",
"YouCanChoosePeriodFrom": "You can choose from the following options",
"TaskRetryExceptionMessage": "The following alerts were unable to process because archiving is not complete for the associated reports: %1$s",
"FinalTaskRetryWarning": "Final retry of alerts task. Unable to process the following alerts: %1$s"
"FinalTaskRetryWarning": "Final retry of alerts task. Unable to process the following alerts: %1$s",
"MediumEmail": "Email",
"MediumMobile": "Mobile",
"MediumTitle": "Send alerts via",
"MediumDescription": "Select the medium to send alerts.",
"EmptyReportMediums": "Report mediums cannot be empty.",
"InvalidReportMediums": "Invalid report mediums value. Allowed values are %1$s.",
"InvalidEmailReportParameter": "Please select \"Send to me\" or specify valid email addresses to email the report.",
"InvalidPhoneNumberReportParameter": "Phone numbers cannot be empty."
}
}
3 changes: 2 additions & 1 deletion phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
<file>.</file>

<exclude-pattern>tests/javascript/*</exclude-pattern>
<exclude-pattern>Updates/*</exclude-pattern>
<exclude-pattern>*/vendor/*</exclude-pattern>

<rule ref="Matomo"></rule>

<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="250" />
<property name="lineLimit" value="260" />
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Naughty? 😂

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yaa it was giving an error of 255 characters, so increased it to 260

</properties>
<exclude-pattern>tests/*</exclude-pattern>
</rule>
Expand Down
Loading