getInnerSiteQuery($idSites) . ") "); $values = array(); if ($login !== false) { $sql .= " AND login = ?"; $values[] = $login; } $alerts = Db::fetchAll($sql, $values); $alerts = $this->completeAlerts($alerts); return $alerts; } /** * @param $idSites * @return string */ protected function getInnerSiteQuery($idSites) { $idSites = array_map('intval', $idSites); $innerSiteQuery = "SELECT idalert FROM " . Common::prefixTable('alert_site') . " WHERE idsite IN (" . implode(",", $idSites) . ")"; return $innerSiteQuery; } 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']); } return $alerts; } private function getDefinedSiteIds($idAlert) { $sql = "SELECT idsite FROM " . Common::prefixTable('alert_site') . " WHERE idalert = ?"; $sites = Db::fetchAll($sql, $idAlert); $idSites = array(); foreach ($sites as $site) { $idSites[] = $site['idsite']; } return $idSites; } public function getTriggeredAlertsForPeriod($period, $date) { $piwikDate = Date::factory($date); $date = Period\Factory::build($period, $piwikDate); $db = $this->getDb(); $sql = $this->getTriggeredAlertsSelectPart() . " WHERE period = ? AND ts_triggered BETWEEN ? AND ?"; $values = array( $period, $date->getDateStart()->getDateStartUTC(), $date->getDateEnd()->getDateEndUTC() ); $alerts = $db->fetchAll($sql, $values); $alerts = $this->completeAlerts($alerts); return $alerts; } private function getDb() { return Db::get(); } private function getTriggeredAlertsSelectPart() { return "SELECT * FROM " . Common::prefixTable('alert_triggered'); } public function getTriggeredAlerts($idSites, $login) { $idSites = array_map('intval', $idSites); $db = $this->getDb(); $sql = $this->getTriggeredAlertsSelectPart() . " WHERE idsite IN (" . Common::getSqlStringFieldsArray($idSites) . ")" . " AND login = ?"; $values = $idSites; $values[] = $login; $alerts = $db->fetchAll($sql, $values); $alerts = $this->completeAlerts($alerts); return $alerts; } public function getTriggeredAlertsFromPastNHours(string $period, int $idSite, int $hours) { $timestamp = Date::now()->addHour(-1 * $hours)->getDatetime(); $db = $this->getDb(); $sql = $this->getTriggeredAlertsSelectPart() . " WHERE idsite = ?" . " AND period = ?" . " AND ts_triggered > ?"; $values = [$idSite, $period, $timestamp]; $alerts = $db->fetchAll($sql, $values); return $this->completeAlerts($alerts); } public function getAllAlerts() { $sql = "SELECT * FROM " . Common::prefixTable('alert'); $alerts = Db::fetchAll($sql); $alerts = $this->completeAlerts($alerts); return $alerts; } public function getAllAlertsForPeriod($period) { $sql = "SELECT * FROM " . Common::prefixTable('alert') . " WHERE period = ?"; $alerts = Db::fetchAll($sql, array($period)); $alerts = $this->completeAlerts($alerts); return $alerts; } /** * Creates an Alert for given website(s). * * @param string $name * @param int[] $idSites * @param string $login * @param string $period * @param bool $emailMe * @param array $additionalEmails * @param array $phoneNumbers * @param string $metric (nb_uniq_visits, sum_visit_length, ..) * @param string $metricCondition * @param float $metricValue * @param int $comparedTo * @param string $reportUniqueId * @param string $reportCondition * @param string $reportValue * @param array $reportMediums * @param string $slackChannelID * @param string $msTeamsWebhookUrl * * @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, $reportMediums, $slackChannelID, $msTeamsWebhookUrl, $description = '') { $idAlert = $this->getNextAlertId(); $newAlert = array( 'idalert' => $idAlert, 'name' => $name, 'description' => $description, 'period' => $period, 'login' => $login, 'email_me' => $emailMe ? 1 : 0, 'additional_emails' => json_encode($additionalEmails), 'phone_numbers' => json_encode($phoneNumbers), 'metric' => $metric, 'metric_condition' => $metricCondition, 'metric_matched' => $metricValue, 'report' => $reportUniqueId, 'compared_to' => $comparedTo, 'report_condition' => $reportCondition, 'report_matched' => $reportValue, 'report_mediums' => json_encode($reportMediums), 'slack_channel_id' => $slackChannelID, 'ms_teams_webhook_url' => $msTeamsWebhookUrl, ); $db = $this->getDb(); $db->insert(Common::prefixTable('alert'), $newAlert); $this->setSiteIds($idAlert, $idSites); return $idAlert; } private function getNextAlertId() { $idAlert = Db::fetchOne("SELECT max(idalert) + 1 FROM " . Common::prefixTable('alert')); if (empty($idAlert)) { $idAlert = 1; } return $idAlert; } public function setSiteIds($idAlert, $idSites) { $this->removeAllSites($idAlert); $db = $this->getDb(); foreach ($idSites as $idSite) { $db->insert(Common::prefixTable('alert_site'), array( 'idalert' => intval($idAlert), 'idsite' => intval($idSite) )); } } private function removeAllSites($idAlert) { $this->getDb()->query("DELETE FROM " . Common::prefixTable("alert_site") . " WHERE idalert = ?", $idAlert); } /** * Edits an Alert for given website(s). * * @param int $idAlert * @param string $name Name of Alert * @param int[] $idSites array of ints of idSites. * @param string $period Period the alert is defined on. * @param bool $emailMe * @param array $additionalEmails * @param array $phoneNumbers * @param string $metric (nb_uniq_visits, sum_visit_length, ..) * @param string $metricCondition * @param float $metricValue * @param int $comparedTo * @param string $reportUniqueId * @param string $reportCondition * @param string $reportValue * @param array $reportMediums * @param string $slackChannelID * @param string $msTeamsWebhookUrl * * @return int * @throws \Exception */ public function updateAlert($idAlert, $name, $idSites, $period, $emailMe, $additionalEmails, $phoneNumbers, $metric, $metricCondition, $metricValue, $comparedTo, $reportUniqueId, $reportCondition, $reportValue, $reportMediums, $slackChannelID, $msTeamsWebhookUrl, $description = '') { $alert = array( 'name' => $name, 'description' => $description, 'period' => $period, 'email_me' => $emailMe ? 1 : 0, 'additional_emails' => json_encode($additionalEmails), 'phone_numbers' => json_encode($phoneNumbers), 'metric' => $metric, 'metric_condition' => $metricCondition, 'metric_matched' => $metricValue, 'report' => $reportUniqueId, 'compared_to' => $comparedTo, 'report_condition' => $reportCondition, 'report_matched' => $reportValue, 'report_mediums' => json_encode($reportMediums), 'slack_channel_id' => $slackChannelID, 'ms_teams_webhook_url' => $msTeamsWebhookUrl, ); $db = $this->getDb(); $db->update(Common::prefixTable('alert'), $alert, "idalert = " . intval($idAlert)); $this->setSiteIds($idAlert, $idSites); return $idAlert; } /** * Delete alert by id. * * @param int $idAlert * * @throws \Exception In case alert does not exist or not enough permission */ public function deleteAlert($idAlert) { $db = $this->getDb(); $db->query("DELETE FROM " . Common::prefixTable("alert") . " WHERE idalert = ?", array($idAlert)); $db->query("DELETE FROM " . Common::prefixTable("alert_triggered") . " WHERE idalert = ?", array($idAlert)); $this->removeAllSites($idAlert); } public function triggerAlert($idAlert, $idSite, $valueNew, $valueOld, $datetime) { $alert = $this->getAlert($idAlert); $keysToKeep = array('idalert', 'name', 'description', 'login', 'period', 'metric', 'metric_condition', 'metric_matched', 'report', 'report_condition', 'report_matched', 'report_mediums', 'compared_to', 'email_me', 'additional_emails', 'phone_numbers', 'slack_channel_id', 'ms_teams_webhook_url'); $triggeredAlert = array(); foreach ($keysToKeep as $key) { $triggeredAlert[$key] = $alert[$key]; } $triggeredAlert['metric_matched'] = Common::forceDotAsSeparatorForDecimalPoint($triggeredAlert['metric_matched']); $triggeredAlert['ts_triggered'] = $datetime; $triggeredAlert['ts_last_sent'] = null; $triggeredAlert['value_new'] = $valueNew; $triggeredAlert['value_old'] = $valueOld; $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( Common::prefixTable('alert_triggered'), $triggeredAlert ); } /** * Returns a single Alert * * @param int $idAlert * * @return array|null */ public function getAlert($idAlert) { $query = sprintf('SELECT * FROM %s WHERE idalert = ? LIMIT 1', Common::prefixTable('alert')); $alerts = Db::fetchAll($query, array(intval($idAlert))); if (empty($alerts)) { return null; } $alerts = $this->completeAlerts($alerts); return array_shift($alerts); } public function markTriggeredAlertAsSent($idTriggered, $timestamp) { $log = array( 'ts_last_sent' => Date::factory($timestamp)->getDatetime() ); $where = sprintf("idtriggered = %d", $idTriggered); $db = $this->getDb(); $db->update(Common::prefixTable('alert_triggered'), $log, $where); } public function deleteTriggeredAlertsForSite($idSite) { $this->getDb()->query("DELETE FROM " . Common::prefixTable("alert_triggered") . " WHERE idsite = ?", $idSite); } public function deleteTriggeredAlertsForUserAndSites($idAlert, $idSites, $login) { $db = $this->getDb(); $placeholders = Common::getSqlStringFieldsArray($idSites); $bind = array_merge(array($idAlert, $login), $idSites); $db->query( "DELETE FROM " . Common::prefixTable("alert_triggered") . " WHERE idalert = ? AND login = ? AND idsite in (" . $placeholders . " )", $bind ); } public function deleteAlertSitesForSites($idAlert, $idSites) { $db = $this->getDb(); $placeholders = Common::getSqlStringFieldsArray($idSites); $bind = array_merge(array($idAlert), $idSites); $db->query( "DELETE FROM " . Common::prefixTable("alert_site") . " WHERE idalert = ? AND idsite in (" . $placeholders . " )", $bind ); } }