958 lines
36 KiB
PHP
958 lines
36 KiB
PHP
<?php
|
||
/**
|
||
* Piwik - Open source web analytics
|
||
*
|
||
* @link http://piwik.org
|
||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||
*
|
||
*/
|
||
namespace Piwik\Plugins\ScheduledReports;
|
||
|
||
use Exception;
|
||
use Piwik\Common;
|
||
use Piwik\Date;
|
||
use Piwik\Db;
|
||
use Piwik\NoAccessException;
|
||
use Piwik\Piwik;
|
||
use Piwik\Plugins\LanguagesManager\LanguagesManager;
|
||
use Piwik\Plugins\SegmentEditor\API as APISegmentEditor;
|
||
use Piwik\Plugins\SitesManager\API as SitesManagerApi;
|
||
use Piwik\ReportRenderer;
|
||
use Piwik\ReportRenderer\Html;
|
||
use Piwik\Site;
|
||
use Piwik\Translate;
|
||
use Zend_Mime;
|
||
|
||
/**
|
||
* The ScheduledReports API lets you manage Scheduled Email reports, as well as generate, download or email any existing report.
|
||
*
|
||
* "generateReport" will generate the requested report (for a specific date range, website and in the requested language).
|
||
* "sendEmailReport" will send the report by email to the recipients specified for this report.
|
||
*
|
||
* You can also get the list of all existing reports via "getReports", create new reports via "addReport",
|
||
* or manage existing reports with "updateReport" and "deleteReport".
|
||
* See also the documentation about <a href='http://piwik.org/docs/email-reports/' target='_blank'>Scheduled Email reports</a> in Piwik.
|
||
*
|
||
* @method static \Piwik\Plugins\ScheduledReports\API getInstance()
|
||
*/
|
||
class API extends \Piwik\Plugin\API
|
||
{
|
||
const VALIDATE_PARAMETERS_EVENT = 'ScheduledReports.validateReportParameters';
|
||
const GET_REPORT_PARAMETERS_EVENT = 'ScheduledReports.getReportParameters';
|
||
const GET_REPORT_METADATA_EVENT = 'ScheduledReports.getReportMetadata';
|
||
const GET_REPORT_TYPES_EVENT = 'ScheduledReports.getReportTypes';
|
||
const GET_REPORT_FORMATS_EVENT = 'ScheduledReports.getReportFormats';
|
||
const GET_RENDERER_INSTANCE_EVENT = 'ScheduledReports.getRendererInstance';
|
||
const PROCESS_REPORTS_EVENT = 'ScheduledReports.processReports';
|
||
const GET_REPORT_RECIPIENTS_EVENT = 'ScheduledReports.getReportRecipients';
|
||
const ALLOW_MULTIPLE_REPORTS_EVENT = 'ScheduledReports.allowMultipleReports';
|
||
const SEND_REPORT_EVENT = 'ScheduledReports.sendReport';
|
||
|
||
const OUTPUT_DOWNLOAD = 1;
|
||
const OUTPUT_SAVE_ON_DISK = 2;
|
||
const OUTPUT_INLINE = 3;
|
||
const OUTPUT_RETURN = 4;
|
||
|
||
const REPORT_TRUNCATE = 23;
|
||
|
||
/**
|
||
* Creates a new report and schedules it.
|
||
*
|
||
* @param int $idSite
|
||
* @param string $description Report description
|
||
* @param string $period Schedule frequency: day, week or month
|
||
* @param int $hour Hour (0-23) when the report should be sent
|
||
* @param string $reportType 'email' or any other format provided via the ScheduledReports.getReportTypes hook
|
||
* @param string $reportFormat 'pdf', 'html' or any other format provided via the ScheduledReports.getReportFormats hook
|
||
* @param array $reports array of reports
|
||
* @param array $parameters array of parameters
|
||
* @param bool|int $idSegment Segment Identifier
|
||
*
|
||
* @return int idReport generated
|
||
*/
|
||
public function addReport($idSite, $description, $period, $hour, $reportType, $reportFormat, $reports, $parameters, $idSegment = false)
|
||
{
|
||
Piwik::checkUserIsNotAnonymous();
|
||
Piwik::checkUserHasViewAccess($idSite);
|
||
|
||
$currentUser = Piwik::getCurrentUserLogin();
|
||
self::ensureLanguageSetForUser($currentUser);
|
||
|
||
self::validateCommonReportAttributes($period, $hour, $description, $idSegment, $reportType, $reportFormat);
|
||
|
||
// report parameters validations
|
||
$parameters = self::validateReportParameters($reportType, $parameters);
|
||
|
||
// validation of requested reports
|
||
$reports = self::validateRequestedReports($idSite, $reportType, $reports);
|
||
|
||
$db = Db::get();
|
||
$idReport = $db->fetchOne("SELECT max(idreport) + 1 FROM " . Common::prefixTable('report'));
|
||
|
||
if ($idReport == false) {
|
||
$idReport = 1;
|
||
}
|
||
|
||
$db->insert(Common::prefixTable('report'),
|
||
array(
|
||
'idreport' => $idReport,
|
||
'idsite' => $idSite,
|
||
'login' => $currentUser,
|
||
'description' => $description,
|
||
'idsegment' => $idSegment,
|
||
'period' => $period,
|
||
'hour' => $hour,
|
||
'type' => $reportType,
|
||
'format' => $reportFormat,
|
||
'parameters' => $parameters,
|
||
'reports' => $reports,
|
||
'ts_created' => Date::now()->getDatetime(),
|
||
'deleted' => 0,
|
||
));
|
||
|
||
return $idReport;
|
||
}
|
||
|
||
private static function ensureLanguageSetForUser($currentUser)
|
||
{
|
||
$lang = \Piwik\Plugins\LanguagesManager\API::getInstance()->getLanguageForUser($currentUser);
|
||
if (empty($lang)) {
|
||
\Piwik\Plugins\LanguagesManager\API::getInstance()->setLanguageForUser($currentUser, LanguagesManager::getLanguageCodeForCurrentUser());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Updates an existing report.
|
||
*
|
||
* @see addReport()
|
||
*/
|
||
public function updateReport($idReport, $idSite, $description, $period, $hour, $reportType, $reportFormat, $reports, $parameters, $idSegment = false)
|
||
{
|
||
Piwik::checkUserIsNotAnonymous();
|
||
Piwik::checkUserHasViewAccess($idSite);
|
||
|
||
$scheduledReports = $this->getReports($idSite, $periodSearch = false, $idReport);
|
||
$report = reset($scheduledReports);
|
||
$idReport = $report['idreport'];
|
||
|
||
$currentUser = Piwik::getCurrentUserLogin();
|
||
self::ensureLanguageSetForUser($currentUser);
|
||
|
||
self::validateCommonReportAttributes($period, $hour, $description, $idSegment, $reportType, $reportFormat);
|
||
|
||
// report parameters validations
|
||
$parameters = self::validateReportParameters($reportType, $parameters);
|
||
|
||
// validation of requested reports
|
||
$reports = self::validateRequestedReports($idSite, $reportType, $reports);
|
||
|
||
Db::get()->update(Common::prefixTable('report'),
|
||
array(
|
||
'description' => $description,
|
||
'idsegment' => $idSegment,
|
||
'period' => $period,
|
||
'hour' => $hour,
|
||
'type' => $reportType,
|
||
'format' => $reportFormat,
|
||
'parameters' => $parameters,
|
||
'reports' => $reports,
|
||
),
|
||
"idreport = '$idReport'"
|
||
);
|
||
|
||
self::$cache = array();
|
||
}
|
||
|
||
/**
|
||
* Deletes a specific report
|
||
*
|
||
* @param int $idReport
|
||
*/
|
||
public function deleteReport($idReport)
|
||
{
|
||
$APIScheduledReports = $this->getReports($idSite = false, $periodSearch = false, $idReport);
|
||
$report = reset($APIScheduledReports);
|
||
Piwik::checkUserHasSuperUserAccessOrIsTheUser($report['login']);
|
||
|
||
Db::get()->update(Common::prefixTable('report'),
|
||
array(
|
||
'deleted' => 1,
|
||
),
|
||
"idreport = '$idReport'"
|
||
);
|
||
self::$cache = array();
|
||
}
|
||
|
||
// static cache storing reports
|
||
public static $cache = array();
|
||
|
||
/**
|
||
* Returns the list of reports matching the passed parameters
|
||
*
|
||
* @param bool|int $idSite If specified, will filter reports that belong to a specific idsite
|
||
* @param bool|string $period If specified, will filter reports that are scheduled for this period (day,week,month)
|
||
* @param bool|int $idReport If specified, will filter the report that has the given idReport
|
||
* @param bool $ifSuperUserReturnOnlySuperUserReports
|
||
* @param bool|int $idSegment If specified, will filter the report that has the given idSegment
|
||
* @throws Exception
|
||
* @return array
|
||
*/
|
||
public function getReports($idSite = false, $period = false, $idReport = false, $ifSuperUserReturnOnlySuperUserReports = false, $idSegment = false)
|
||
{
|
||
Piwik::checkUserHasSomeViewAccess();
|
||
$cacheKey = (int)$idSite . '.' . (string)$period . '.' . (int)$idReport . '.' . (int)$ifSuperUserReturnOnlySuperUserReports;
|
||
if (isset(self::$cache[$cacheKey])) {
|
||
return self::$cache[$cacheKey];
|
||
}
|
||
|
||
$sqlWhere = '';
|
||
$bind = array();
|
||
|
||
// Super user gets all reports back, other users only their own
|
||
if (!Piwik::hasUserSuperUserAccess()
|
||
|| $ifSuperUserReturnOnlySuperUserReports
|
||
) {
|
||
$sqlWhere .= "AND login = ?";
|
||
$bind[] = Piwik::getCurrentUserLogin();
|
||
}
|
||
|
||
if (!empty($period)) {
|
||
$this->validateReportPeriod($period);
|
||
$sqlWhere .= " AND period = ? ";
|
||
$bind[] = $period;
|
||
}
|
||
if (!empty($idSite)) {
|
||
Piwik::checkUserHasViewAccess($idSite);
|
||
$sqlWhere .= " AND " . Common::prefixTable('site') . ".idsite = ?";
|
||
$bind[] = $idSite;
|
||
}
|
||
if (!empty($idReport)) {
|
||
$sqlWhere .= " AND idreport = ?";
|
||
$bind[] = $idReport;
|
||
}
|
||
if (!empty($idSegment)) {
|
||
$sqlWhere .= " AND idsegment = ?";
|
||
$bind[] = $idSegment;
|
||
}
|
||
|
||
// Joining with the site table to work around pre-1.3 where reports could still be linked to a deleted site
|
||
$reports = Db::fetchAll("SELECT report.*
|
||
FROM " . Common::prefixTable('report') . " AS `report`
|
||
JOIN " . Common::prefixTable('site') . "
|
||
USING (idsite)
|
||
WHERE deleted = 0
|
||
$sqlWhere", $bind);
|
||
// When a specific report was requested and not found, throw an error
|
||
if ($idReport !== false
|
||
&& empty($reports)
|
||
) {
|
||
throw new Exception("Requested report couldn't be found.");
|
||
}
|
||
|
||
foreach ($reports as &$report) {
|
||
// decode report parameters
|
||
$report['parameters'] = Common::json_decode($report['parameters'], true);
|
||
|
||
// decode report list
|
||
$report['reports'] = Common::json_decode($report['reports'], true);
|
||
}
|
||
|
||
// static cache
|
||
self::$cache[$cacheKey] = $reports;
|
||
|
||
return $reports;
|
||
}
|
||
|
||
/**
|
||
* Generates a report file.
|
||
*
|
||
* @param int $idReport ID of the report to generate.
|
||
* @param string $date YYYY-MM-DD
|
||
* @param bool|false|string $language If not passed, will use default language.
|
||
* @param bool|false|int $outputType 1 = download report, 2 = save report to disk, 3 = output report in browser, 4 = return report content to caller, defaults to download
|
||
* @param bool|false|string $period Defaults to 'day'. If not specified, will default to the report's period set when creating the report
|
||
* @param bool|false|string $reportFormat 'pdf', 'html' or any other format provided via the ScheduledReports.getReportFormats hook
|
||
* @param bool|false|array $parameters array of parameters
|
||
* @return array|void
|
||
*/
|
||
public function generateReport($idReport, $date, $language = false, $outputType = false, $period = false, $reportFormat = false, $parameters = false)
|
||
{
|
||
Piwik::checkUserIsNotAnonymous();
|
||
|
||
// load specified language
|
||
if (empty($language)) {
|
||
$language = Translate::getLanguageDefault();
|
||
}
|
||
|
||
Translate::reloadLanguage($language);
|
||
|
||
$reports = $this->getReports($idSite = false, $_period = false, $idReport);
|
||
$report = reset($reports);
|
||
|
||
$idSite = $report['idsite'];
|
||
$login = $report['login'];
|
||
$reportType = $report['type'];
|
||
|
||
$this->checkUserHasViewPermission($login, $idSite);
|
||
|
||
// override report period
|
||
if (empty($period)) {
|
||
$period = $report['period'];
|
||
}
|
||
|
||
// override report format
|
||
if (!empty($reportFormat)) {
|
||
self::validateReportFormat($reportType, $reportFormat);
|
||
$report['format'] = $reportFormat;
|
||
} else {
|
||
$reportFormat = $report['format'];
|
||
}
|
||
|
||
// override and/or validate report parameters
|
||
$report['parameters'] = Common::json_decode(
|
||
self::validateReportParameters($reportType, empty($parameters) ? $report['parameters'] : $parameters),
|
||
true
|
||
);
|
||
|
||
// available reports
|
||
$availableReportMetadata = \Piwik\Plugins\API\API::getInstance()->getReportMetadata($idSite);
|
||
|
||
// we need to lookup which reports metadata are registered in this report
|
||
$reportMetadata = array();
|
||
foreach ($availableReportMetadata as $metadata) {
|
||
if (in_array($metadata['uniqueId'], $report['reports'])) {
|
||
$reportMetadata[] = $metadata;
|
||
}
|
||
}
|
||
|
||
// the report will be rendered with the first 23 rows and will aggregate other rows in a summary row
|
||
// 23 rows table fits in one portrait page
|
||
$initialFilterTruncate = Common::getRequestVar('filter_truncate', false);
|
||
$_GET['filter_truncate'] = self::REPORT_TRUNCATE;
|
||
|
||
$prettyDate = null;
|
||
$processedReports = array();
|
||
$segment = self::getSegment($report['idsegment']);
|
||
foreach ($reportMetadata as $action) {
|
||
$apiModule = $action['module'];
|
||
$apiAction = $action['action'];
|
||
$apiParameters = array();
|
||
if (isset($action['parameters'])) {
|
||
$apiParameters = $action['parameters'];
|
||
}
|
||
|
||
$mustRestoreGET = false;
|
||
|
||
// all Websites dashboard should not be truncated in the report
|
||
if ($apiModule == 'MultiSites') {
|
||
$mustRestoreGET = $_GET;
|
||
$_GET['enhanced'] = true;
|
||
|
||
if ($apiAction == 'getAll') {
|
||
$_GET['filter_truncate'] = false;
|
||
|
||
// when a view/admin user created a report, workaround the fact that "Super User"
|
||
// is enforced in Scheduled tasks, and ensure Multisites.getAll only return the websites that this user can access
|
||
$userLogin = $report['login'];
|
||
if (!empty($userLogin)
|
||
&& !Piwik::hasTheUserSuperUserAccess($userLogin)
|
||
) {
|
||
$_GET['_restrictSitesToLogin'] = $userLogin;
|
||
}
|
||
}
|
||
}
|
||
|
||
$processedReport = \Piwik\Plugins\API\API::getInstance()->getProcessedReport(
|
||
$idSite, $period, $date, $apiModule, $apiAction,
|
||
$segment != null ? urlencode($segment['definition']) : false,
|
||
$apiParameters, $idGoal = false, $language
|
||
);
|
||
|
||
$processedReport['segment'] = $segment;
|
||
|
||
// TODO add static method getPrettyDate($period, $date) in Period
|
||
$prettyDate = $processedReport['prettyDate'];
|
||
|
||
if ($mustRestoreGET) {
|
||
$_GET = $mustRestoreGET;
|
||
}
|
||
|
||
$processedReports[] = $processedReport;
|
||
}
|
||
|
||
// restore filter truncate parameter value
|
||
if ($initialFilterTruncate !== false) {
|
||
$_GET['filter_truncate'] = $initialFilterTruncate;
|
||
}
|
||
|
||
/**
|
||
* Triggered when generating the content of scheduled reports.
|
||
*
|
||
* This event can be used to modify the report data or report metadata of one or more reports
|
||
* in a scheduled report, before the scheduled report is rendered and delivered.
|
||
*
|
||
* TODO: list data available in $report or make it a new class that can be documented (same for
|
||
* all other events that use a $report)
|
||
*
|
||
* @param array &$processedReports The list of processed reports in the scheduled
|
||
* report. Entries includes report data and metadata for each report.
|
||
* @param string $reportType A string ID describing how the scheduled report will be sent, eg,
|
||
* `'sms'` or `'email'`.
|
||
* @param string $outputType The output format of the report, eg, `'html'`, `'pdf'`, etc.
|
||
* @param array $report An array describing the scheduled report that is being
|
||
* generated.
|
||
*/
|
||
Piwik::postEvent(
|
||
self::PROCESS_REPORTS_EVENT,
|
||
array(&$processedReports, $reportType, $outputType, $report)
|
||
);
|
||
|
||
$reportRenderer = null;
|
||
|
||
/**
|
||
* Triggered when obtaining a renderer instance based on the scheduled report output format.
|
||
*
|
||
* Plugins that provide new scheduled report output formats should use this event to
|
||
* handle their new report formats.
|
||
*
|
||
* @param ReportRenderer &$reportRenderer This variable should be set to an instance that
|
||
* extends {@link Piwik\ReportRenderer} by one of the event
|
||
* subscribers.
|
||
* @param string $reportType A string ID describing how the report is sent, eg,
|
||
* `'sms'` or `'email'`.
|
||
* @param string $outputType The output format of the report, eg, `'html'`, `'pdf'`, etc.
|
||
* @param array $report An array describing the scheduled report that is being
|
||
* generated.
|
||
*/
|
||
Piwik::postEvent(
|
||
self::GET_RENDERER_INSTANCE_EVENT,
|
||
array(&$reportRenderer, $reportType, $outputType, $report)
|
||
);
|
||
|
||
if(is_null($reportRenderer)) {
|
||
throw new Exception("A report renderer was not supplied in the event " . self::GET_RENDERER_INSTANCE_EVENT);
|
||
}
|
||
|
||
// init report renderer
|
||
$reportRenderer->setLocale($language);
|
||
|
||
// render report
|
||
$description = str_replace(array("\r", "\n"), ' ', $report['description']);
|
||
|
||
list($reportSubject, $reportTitle) = self::getReportSubjectAndReportTitle(Site::getNameFor($idSite), $report['reports']);
|
||
$filename = "$reportTitle - $prettyDate - $description";
|
||
|
||
$reportRenderer->renderFrontPage($reportTitle, $prettyDate, $description, $reportMetadata, $segment);
|
||
array_walk($processedReports, array($reportRenderer, 'renderReport'));
|
||
|
||
switch ($outputType) {
|
||
|
||
case self::OUTPUT_SAVE_ON_DISK:
|
||
|
||
$outputFilename = strtoupper($reportFormat) . ' ' . ucfirst($reportType) . ' Report - ' . $idReport . '.' . $date . '.' . $idSite . '.' . $language;
|
||
$outputFilename = $reportRenderer->sendToDisk($outputFilename);
|
||
|
||
$additionalFiles = $this->getAttachments($reportRenderer, $report, $processedReports, $prettyDate);
|
||
|
||
return array(
|
||
$outputFilename,
|
||
$prettyDate,
|
||
$reportSubject,
|
||
$reportTitle,
|
||
$additionalFiles,
|
||
);
|
||
|
||
break;
|
||
|
||
case self::OUTPUT_INLINE:
|
||
|
||
$reportRenderer->sendToBrowserInline($filename);
|
||
break;
|
||
|
||
case self::OUTPUT_RETURN:
|
||
|
||
return $reportRenderer->getRenderedReport();
|
||
break;
|
||
|
||
default:
|
||
case self::OUTPUT_DOWNLOAD:
|
||
$reportRenderer->sendToBrowserDownload($filename);
|
||
break;
|
||
}
|
||
}
|
||
|
||
public function sendReport($idReport, $period = false, $date = false)
|
||
{
|
||
Piwik::checkUserIsNotAnonymous();
|
||
|
||
$reports = $this->getReports($idSite = false, false, $idReport);
|
||
$report = reset($reports);
|
||
|
||
if ($report['period'] == 'never') {
|
||
$report['period'] = 'day';
|
||
}
|
||
|
||
if (!empty($period)) {
|
||
$report['period'] = $period;
|
||
}
|
||
|
||
if (empty($date)) {
|
||
$date = Date::now()->subPeriod(1, $report['period'])->toString();
|
||
}
|
||
|
||
$language = \Piwik\Plugins\LanguagesManager\API::getInstance()->getLanguageForUser($report['login']);
|
||
|
||
// generate report
|
||
list($outputFilename, $prettyDate, $reportSubject, $reportTitle, $additionalFiles) =
|
||
$this->generateReport(
|
||
$idReport,
|
||
$date,
|
||
$language,
|
||
self::OUTPUT_SAVE_ON_DISK,
|
||
$report['period']
|
||
);
|
||
|
||
if (!file_exists($outputFilename)) {
|
||
throw new Exception("The report file wasn't found in $outputFilename");
|
||
}
|
||
|
||
$filename = basename($outputFilename);
|
||
$handle = fopen($outputFilename, "r");
|
||
$contents = fread($handle, filesize($outputFilename));
|
||
fclose($handle);
|
||
|
||
/**
|
||
* Triggered when sending scheduled reports.
|
||
*
|
||
* Plugins that provide new scheduled report transport mediums should use this event to
|
||
* send the scheduled report.
|
||
*
|
||
* @param string $reportType A string ID describing how the report is sent, eg,
|
||
* `'sms'` or `'email'`.
|
||
* @param array $report An array describing the scheduled report that is being
|
||
* generated.
|
||
* @param string $contents The contents of the scheduled report that was generated
|
||
* and now should be sent.
|
||
* @param string $filename The path to the file where the scheduled report has
|
||
* been saved.
|
||
* @param string $prettyDate A prettified date string for the data within the
|
||
* scheduled report.
|
||
* @param string $reportSubject A string describing what's in the scheduled
|
||
* report.
|
||
* @param string $reportTitle The scheduled report's given title (given by a Piwik user).
|
||
* @param array $additionalFiles The list of additional files that should be
|
||
* sent with this report.
|
||
*/
|
||
Piwik::postEvent(
|
||
self::SEND_REPORT_EVENT,
|
||
array(
|
||
$report['type'],
|
||
$report,
|
||
$contents,
|
||
$filename,
|
||
$prettyDate,
|
||
$reportSubject,
|
||
$reportTitle,
|
||
$additionalFiles
|
||
)
|
||
);
|
||
|
||
// Update flag in DB
|
||
Db::get()->update(Common::prefixTable('report'),
|
||
array('ts_last_sent' => Date::now()->getDatetime()),
|
||
"idreport = " . $report['idreport']
|
||
);
|
||
|
||
// If running from piwik.php with debug, do not delete the PDF after sending the email
|
||
if (!isset($GLOBALS['PIWIK_TRACKER_DEBUG']) || !$GLOBALS['PIWIK_TRACKER_DEBUG']) {
|
||
@chmod($outputFilename, 0600);
|
||
}
|
||
}
|
||
|
||
private static function getReportSubjectAndReportTitle($websiteName, $reports)
|
||
{
|
||
// if the only report is "All websites", we don't display the site name
|
||
$reportTitle = Piwik::translate('General_Website') . " " . $websiteName;
|
||
$reportSubject = $websiteName;
|
||
if (count($reports) == 1
|
||
&& $reports[0] == 'MultiSites_getAll'
|
||
) {
|
||
$reportSubject = Piwik::translate('General_MultiSitesSummary');
|
||
$reportTitle = $reportSubject;
|
||
}
|
||
|
||
return array($reportSubject, $reportTitle);
|
||
}
|
||
|
||
private static function validateReportParameters($reportType, $parameters)
|
||
{
|
||
// get list of valid parameters
|
||
$availableParameters = array();
|
||
|
||
/**
|
||
* Triggered when gathering the available parameters for a scheduled report type.
|
||
*
|
||
* Plugins that provide their own scheduled report transport mediums should use this
|
||
* event to list the available report parameters for their transport medium.
|
||
*
|
||
* @param array $availableParameters The list of available parameters for this report type.
|
||
* This is an array that maps paramater IDs with a boolean
|
||
* that indicates whether the parameter is mandatory or not.
|
||
* @param string $reportType A string ID describing how the report is sent, eg,
|
||
* `'sms'` or `'email'`.
|
||
*/
|
||
Piwik::postEvent(self::GET_REPORT_PARAMETERS_EVENT, array(&$availableParameters, $reportType));
|
||
|
||
// unset invalid parameters
|
||
$availableParameterKeys = array_keys($availableParameters);
|
||
foreach ($parameters as $key => $value) {
|
||
if (!in_array($key, $availableParameterKeys)) {
|
||
unset($parameters[$key]);
|
||
}
|
||
}
|
||
|
||
// test that all required parameters are provided
|
||
foreach ($availableParameters as $parameter => $mandatory) {
|
||
if ($mandatory && !isset($parameters[$parameter])) {
|
||
throw new Exception('Missing parameter : ' . $parameter);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Triggered when validating the parameters for a scheduled report.
|
||
*
|
||
* Plugins that provide their own scheduled reports backend should use this
|
||
* event to validate the custom parameters defined with {@link ScheduledReports::getReportParameters()}.
|
||
*
|
||
* @param array $parameters The list of parameters for the scheduled report.
|
||
* @param string $reportType A string ID describing how the report is sent, eg,
|
||
* `'sms'` or `'email'`.
|
||
*/
|
||
Piwik::postEvent(self::VALIDATE_PARAMETERS_EVENT, array(&$parameters, $reportType));
|
||
|
||
return Common::json_encode($parameters);
|
||
}
|
||
|
||
private static function validateAndTruncateDescription(&$description)
|
||
{
|
||
$description = substr($description, 0, 250);
|
||
}
|
||
|
||
private static function validateRequestedReports($idSite, $reportType, $requestedReports)
|
||
{
|
||
if (!self::allowMultipleReports($reportType)) {
|
||
//sms can only contain one report, we silently discard all but the first
|
||
$requestedReports = array_slice($requestedReports, 0, 1);
|
||
}
|
||
|
||
// retrieve available reports
|
||
$availableReportMetadata = self::getReportMetadata($idSite, $reportType);
|
||
|
||
$availableReportIds = array();
|
||
foreach ($availableReportMetadata as $reportMetadata) {
|
||
$availableReportIds[] = $reportMetadata['uniqueId'];
|
||
}
|
||
|
||
foreach ($requestedReports as $report) {
|
||
if (!in_array($report, $availableReportIds)) {
|
||
throw new Exception("Report $report is unknown or not available for report type '$reportType'.");
|
||
}
|
||
}
|
||
|
||
return Common::json_encode($requestedReports);
|
||
}
|
||
|
||
private static function validateCommonReportAttributes($period, $hour, &$description, &$idSegment, $reportType, $reportFormat)
|
||
{
|
||
self::validateReportPeriod($period);
|
||
self::validateReportHour($hour);
|
||
self::validateAndTruncateDescription($description);
|
||
self::validateIdSegment($idSegment);
|
||
self::validateReportType($reportType);
|
||
self::validateReportFormat($reportType, $reportFormat);
|
||
}
|
||
|
||
private static function validateReportPeriod($period)
|
||
{
|
||
$availablePeriods = array('day', 'week', 'month', 'never');
|
||
if (!in_array($period, $availablePeriods)) {
|
||
throw new Exception('Period schedule must be one of the following: ' . implode(', ', $availablePeriods));
|
||
}
|
||
}
|
||
|
||
private static function validateReportHour($hour)
|
||
{
|
||
if (!is_numeric($hour) || $hour < 0 || $hour > 23) {
|
||
throw new Exception('Invalid hour schedule. Should be anything from 0 to 23 inclusive.');
|
||
}
|
||
}
|
||
|
||
private static function validateIdSegment(&$idSegment)
|
||
{
|
||
if (empty($idSegment) || (is_numeric($idSegment) && $idSegment == 0)) {
|
||
|
||
$idSegment = null;
|
||
} elseif (!is_numeric($idSegment)) {
|
||
|
||
throw new Exception('Invalid segment identifier. Should be an integer.');
|
||
} elseif (self::getSegment($idSegment) == null) {
|
||
|
||
throw new Exception('Segment with id ' . $idSegment . ' does not exist or SegmentEditor is not activated.');
|
||
}
|
||
}
|
||
|
||
private static function validateReportType($reportType)
|
||
{
|
||
$reportTypes = array_keys(self::getReportTypes());
|
||
|
||
if (!in_array($reportType, $reportTypes)) {
|
||
throw new Exception(
|
||
'Report type \'' . $reportType . '\' not valid. Try one of the following ' . implode(', ', $reportTypes)
|
||
);
|
||
}
|
||
}
|
||
|
||
private static function validateReportFormat($reportType, $reportFormat)
|
||
{
|
||
$reportFormats = array_keys(self::getReportFormats($reportType));
|
||
|
||
if (!in_array($reportFormat, $reportFormats)) {
|
||
throw new Exception(
|
||
Piwik::translate(
|
||
'General_ExceptionInvalidReportRendererFormat',
|
||
array($reportFormat, implode(', ', $reportFormats))
|
||
)
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
*/
|
||
static public function getReportMetadata($idSite, $reportType)
|
||
{
|
||
$availableReportMetadata = array();
|
||
|
||
/**
|
||
* TODO: change this event so it returns a list of API methods instead of report metadata arrays.
|
||
* Triggered when gathering the list of Piwik reports that can be used with a certain
|
||
* transport medium.
|
||
*
|
||
* Plugins that provide their own transport mediums should use this
|
||
* event to list the Piwik reports that their backend supports.
|
||
*
|
||
* @param array &$availableReportMetadata An array containg report metadata for each supported
|
||
* report.
|
||
* @param string $reportType A string ID describing how the report is sent, eg,
|
||
* `'sms'` or `'email'`.
|
||
* @param int $idSite The ID of the site we're getting available reports for.
|
||
*/
|
||
Piwik::postEvent(
|
||
self::GET_REPORT_METADATA_EVENT,
|
||
array(&$availableReportMetadata, $reportType, $idSite)
|
||
);
|
||
|
||
return $availableReportMetadata;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
*/
|
||
static public function allowMultipleReports($reportType)
|
||
{
|
||
$allowMultipleReports = null;
|
||
|
||
/**
|
||
* Triggered when we're determining if a scheduled report transport medium can
|
||
* handle sending multiple Piwik reports in one scheduled report or not.
|
||
*
|
||
* Plugins that provide their own transport mediums should use this
|
||
* event to specify whether their backend can send more than one Piwik report
|
||
* at a time.
|
||
*
|
||
* @param bool &$allowMultipleReports Whether the backend type can handle multiple
|
||
* Piwik reports or not.
|
||
* @param string $reportType A string ID describing how the report is sent, eg,
|
||
* `'sms'` or `'email'`.
|
||
*/
|
||
Piwik::postEvent(
|
||
self::ALLOW_MULTIPLE_REPORTS_EVENT,
|
||
array(&$allowMultipleReports, $reportType)
|
||
);
|
||
return $allowMultipleReports;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
*/
|
||
static public function getReportTypes()
|
||
{
|
||
$reportTypes = array();
|
||
|
||
/**
|
||
* Triggered when gathering all available transport mediums.
|
||
*
|
||
* Plugins that provide their own transport mediums should use this
|
||
* event to make their medium available.
|
||
*
|
||
* @param array &$reportTypes An array mapping transport medium IDs with the paths to those
|
||
* mediums' icons. Add your new backend's ID to this array.
|
||
*/
|
||
Piwik::postEvent(self::GET_REPORT_TYPES_EVENT, array(&$reportTypes));
|
||
|
||
return $reportTypes;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
*/
|
||
static public function getReportFormats($reportType)
|
||
{
|
||
$reportFormats = array();
|
||
|
||
/**
|
||
* Triggered when gathering all available scheduled report formats.
|
||
*
|
||
* Plugins that provide their own scheduled report format should use
|
||
* this event to make their format available.
|
||
*
|
||
* @param array &$reportFormats An array mapping string IDs for each available
|
||
* scheduled report format with icon paths for those
|
||
* formats. Add your new format's ID to this array.
|
||
* @param string $reportType A string ID describing how the report is sent, eg,
|
||
* `'sms'` or `'email'`.
|
||
*/
|
||
Piwik::postEvent(
|
||
self::GET_REPORT_FORMATS_EVENT,
|
||
array(&$reportFormats, $reportType)
|
||
);
|
||
|
||
return $reportFormats;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
*/
|
||
static public function getReportRecipients($report)
|
||
{
|
||
$recipients = array();
|
||
|
||
/**
|
||
* Triggered when getting the list of recipients of a scheduled report.
|
||
*
|
||
* Plugins that provide their own scheduled report transport medium should use this event
|
||
* to extract the list of recipients their backend's specific scheduled report
|
||
* format.
|
||
*
|
||
* @param array &$recipients An array of strings describing each of the scheduled
|
||
* reports recipients. Can be, for example, a list of email
|
||
* addresses or phone numbers or whatever else your plugin
|
||
* uses.
|
||
* @param string $reportType A string ID describing how the report is sent, eg,
|
||
* `'sms'` or `'email'`.
|
||
* @param array $report An array describing the scheduled report that is being
|
||
* generated.
|
||
*/
|
||
Piwik::postEvent(self::GET_REPORT_RECIPIENTS_EVENT, array(&$recipients, $report['type'], $report));
|
||
|
||
return $recipients;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
*/
|
||
static public function getSegment($idSegment)
|
||
{
|
||
if (self::isSegmentEditorActivated() && !empty($idSegment)) {
|
||
|
||
$segment = APISegmentEditor::getInstance()->get($idSegment);
|
||
|
||
if ($segment) {
|
||
return $segment;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
*/
|
||
public static function isSegmentEditorActivated()
|
||
{
|
||
return \Piwik\Plugin\Manager::getInstance()->isPluginActivated('SegmentEditor');
|
||
}
|
||
|
||
private function getAttachments($reportRenderer, $report, $processedReports, $prettyDate)
|
||
{
|
||
$additionalFiles = array();
|
||
|
||
if ($reportRenderer instanceof Html) {
|
||
|
||
foreach ($processedReports as $processedReport) {
|
||
|
||
if ($processedReport['displayGraph']) {
|
||
|
||
$additionalFiles[] = $this->createAttachment($report, $processedReport, $prettyDate);
|
||
}
|
||
}
|
||
}
|
||
|
||
return $additionalFiles;
|
||
}
|
||
|
||
private function createAttachment($report, $processedReport, $prettyDate)
|
||
{
|
||
$additionalFile = array();
|
||
|
||
$segment = self::getSegment($report['idsegment']);
|
||
|
||
$segmentName = $segment != null ? sprintf(' (%s)', $segment['name']) : '';
|
||
|
||
$processedReportMetadata = $processedReport['metadata'];
|
||
|
||
$additionalFile['filename'] =
|
||
sprintf(
|
||
'%s - %s - %s %d - %s %d%s.png',
|
||
$processedReportMetadata['name'],
|
||
$prettyDate,
|
||
Piwik::translate('General_Website'),
|
||
$report['idsite'],
|
||
Piwik::translate('General_Report'),
|
||
$report['idreport'],
|
||
$segmentName
|
||
);
|
||
|
||
$additionalFile['cid'] = $processedReportMetadata['uniqueId'];
|
||
|
||
$additionalFile['content'] =
|
||
ReportRenderer::getStaticGraph(
|
||
$processedReportMetadata,
|
||
Html::IMAGE_GRAPH_WIDTH,
|
||
Html::IMAGE_GRAPH_HEIGHT,
|
||
$processedReport['evolutionGraph'],
|
||
$segment
|
||
);
|
||
|
||
$additionalFile['mimeType'] = 'image/png';
|
||
|
||
$additionalFile['encoding'] = Zend_Mime::ENCODING_BASE64;
|
||
|
||
return $additionalFile;
|
||
}
|
||
|
||
private function checkUserHasViewPermission($login, $idSite)
|
||
{
|
||
if (empty($idSite)) {
|
||
return;
|
||
}
|
||
|
||
$idSitesUserHasAccess = SitesManagerApi::getInstance()->getSitesIdWithAtLeastViewAccess($login);
|
||
|
||
if (empty($idSitesUserHasAccess)
|
||
|| !in_array($idSite, $idSitesUserHasAccess)
|
||
) {
|
||
throw new NoAccessException(Piwik::translate('General_ExceptionPrivilege', array("'view'")));
|
||
}
|
||
}
|
||
}
|