false,
self::EVOLUTION_GRAPH_PARAMETER => false,
self::ADDITIONAL_EMAILS_PARAMETER => false,
self::DISPLAY_FORMAT_PARAMETER => true,
);
static private $managedReportTypes = array(
self::EMAIL_TYPE => 'plugins/Zeitgeist/images/email.png'
);
static private $managedReportFormats = array(
ReportRenderer::HTML_FORMAT => 'plugins/Zeitgeist/images/html_icon.png',
ReportRenderer::PDF_FORMAT => 'plugins/UserSettings/images/plugins/pdf.gif'
);
/**
* @see Piwik_Plugin::getListHooksRegistered
*/
public function getListHooksRegistered()
{
return array(
'TopMenu.addMenuEntry' => 'addTopMenu',
'TaskScheduler.getScheduledTasks' => 'getScheduledTasks',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'PDFReports.getReportParameters' => 'getReportParameters',
'PDFReports.validateReportParameters' => 'validateReportParameters',
'PDFReports.getReportMetadata' => 'getReportMetadata',
'PDFReports.getReportTypes' => 'getReportTypes',
'PDFReports.getReportFormats' => 'getReportFormats',
'PDFReports.getRendererInstance' => 'getRendererInstance',
'PDFReports.getReportRecipients' => 'getReportRecipients',
'PDFReports.processReports' => 'processReports',
'PDFReports.allowMultipleReports' => 'allowMultipleReports',
'PDFReports.sendReport' => 'sendReport',
'Template.reportParametersPDFReports' => 'template_reportParametersPDFReports',
'UsersManager.deleteUser' => 'deleteUserReport',
'SitesManager.deleteSite.end' => 'deleteSiteReport',
APISegmentEditor::DEACTIVATE_SEGMENT_EVENT => 'segmentDeactivation',
);
}
/**
* Delete reports for the website
*/
public function deleteSiteReport($idSite)
{
$idReports = API::getInstance()->getReports($idSite);
foreach ($idReports as $report) {
$idReport = $report['idreport'];
API::getInstance()->deleteReport($idReport);
}
}
public function getJsFiles(&$jsFiles)
{
$jsFiles[] = "plugins/PDFReports/javascripts/pdf.js";
}
public function validateReportParameters(&$parameters, $info)
{
if (self::manageEvent($info)) {
$reportFormat = $parameters[self::DISPLAY_FORMAT_PARAMETER];
$availableDisplayFormats = array_keys(self::getDisplayFormats());
if (!in_array($reportFormat, $availableDisplayFormats)) {
throw new Exception(
Piwik_TranslateException(
// General_ExceptionInvalidAggregateReportsFormat should be named General_ExceptionInvalidDisplayFormat
'General_ExceptionInvalidAggregateReportsFormat',
array($reportFormat, implode(', ', $availableDisplayFormats))
)
);
}
// emailMe is an optional parameter
if (!isset($parameters[self::EMAIL_ME_PARAMETER])) {
$parameters[self::EMAIL_ME_PARAMETER] = self::EMAIL_ME_PARAMETER_DEFAULT_VALUE;
} else {
$parameters[self::EMAIL_ME_PARAMETER] = self::valueIsTrue($parameters[self::EMAIL_ME_PARAMETER]);
}
// evolutionGraph is an optional parameter
if (!isset($parameters[self::EVOLUTION_GRAPH_PARAMETER])) {
$parameters[self::EVOLUTION_GRAPH_PARAMETER] = self::EVOLUTION_GRAPH_PARAMETER_DEFAULT_VALUE;
} else {
$parameters[self::EVOLUTION_GRAPH_PARAMETER] = self::valueIsTrue($parameters[self::EVOLUTION_GRAPH_PARAMETER]);
}
// additionalEmails is an optional parameter
if (isset($parameters[self::ADDITIONAL_EMAILS_PARAMETER])) {
$parameters[self::ADDITIONAL_EMAILS_PARAMETER] = self::checkAdditionalEmails($parameters[self::ADDITIONAL_EMAILS_PARAMETER]);
}
}
}
// based on http://www.php.net/manual/en/filter.filters.validate.php -> FILTER_VALIDATE_BOOLEAN
static private function valueIsTrue($value)
{
return $value == 'true' || $value == 1 || $value == '1' || $value === true;
}
public function getReportMetadata(&$reportMetadata, $notificationInfo)
{
if (self::manageEvent($notificationInfo)) {
$idSite = $notificationInfo[API::ID_SITE_INFO_KEY];
$availableReportMetadata = \Piwik\Plugins\API\API::getInstance()->getReportMetadata($idSite);
$filteredReportMetadata = array();
foreach ($availableReportMetadata as $reportMetadata) {
// removing reports from the API category and MultiSites.getOne
if (
$reportMetadata['category'] == 'API' ||
$reportMetadata['category'] == Piwik_Translate('General_MultiSitesSummary') && $reportMetadata['name'] == Piwik_Translate('General_SingleWebsitesDashboard')
) continue;
$filteredReportMetadata[] = $reportMetadata;
}
$reportMetadata = $filteredReportMetadata;
}
}
public function getReportTypes(&$reportTypes)
{
$reportTypes = array_merge($reportTypes, self::$managedReportTypes);
}
public function getReportFormats(&$reportFormats, $info)
{
if (self::manageEvent($info)) {
$reportFormats = self::$managedReportFormats;
}
}
public function getReportParameters(&$availableParameters, $info)
{
if (self::manageEvent($info)) {
$availableParameters = self::$availableParameters;
}
}
public function processReports(&$processedReports, $notificationInfo)
{
if (self::manageEvent($notificationInfo)) {
$report = $notificationInfo[API::REPORT_KEY];
$displayFormat = $report['parameters'][self::DISPLAY_FORMAT_PARAMETER];
$evolutionGraph = $report['parameters'][self::EVOLUTION_GRAPH_PARAMETER];
foreach ($processedReports as &$processedReport) {
$metadata = $processedReport['metadata'];
$isAggregateReport = !empty($metadata['dimension']);
$processedReport['displayTable'] = $displayFormat != self::DISPLAY_FORMAT_GRAPHS_ONLY;
$processedReport['displayGraph'] =
($isAggregateReport ?
$displayFormat == self::DISPLAY_FORMAT_GRAPHS_ONLY || $displayFormat == self::DISPLAY_FORMAT_TABLES_AND_GRAPHS
:
$displayFormat != self::DISPLAY_FORMAT_TABLES_ONLY)
&& \Piwik\SettingsServer::isGdExtensionEnabled()
&& \Piwik\PluginsManager::getInstance()->isPluginActivated('ImageGraph')
&& !empty($metadata['imageGraphUrl']);
$processedReport['evolutionGraph'] = $evolutionGraph;
// remove evolution metrics from MultiSites.getAll
if ($metadata['module'] == 'MultiSites') {
$columns = $processedReport['columns'];
foreach (\Piwik\Plugins\MultiSites\API::getApiMetrics($enhanced = true) as $metricSettings) {
unset($columns[$metricSettings[\Piwik\Plugins\MultiSites\API::METRIC_EVOLUTION_COL_NAME_KEY]]);
}
$processedReport['metadata'] = $metadata;
$processedReport['columns'] = $columns;
}
}
}
}
public function getRendererInstance(&$reportRenderer, $notificationInfo)
{
if (self::manageEvent($notificationInfo)) {
$reportFormat = $notificationInfo[API::REPORT_KEY]['format'];
$outputType = $notificationInfo[API::OUTPUT_TYPE_INFO_KEY];
$reportRenderer = ReportRenderer::factory($reportFormat);
if ($reportFormat == ReportRenderer::HTML_FORMAT) {
$reportRenderer->setRenderImageInline($outputType != API::OUTPUT_SAVE_ON_DISK);
}
}
}
public function allowMultipleReports(&$allowMultipleReports, $info)
{
if (self::manageEvent($info)) {
$allowMultipleReports = true;
}
}
public function sendReport($notificationInfo)
{
if (self::manageEvent($notificationInfo)) {
$report = $notificationInfo[API::REPORT_KEY];
$reportTitle = $notificationInfo[API::REPORT_TITLE_KEY];
$prettyDate = $notificationInfo[API::PRETTY_DATE_KEY];
$contents = $notificationInfo[API::REPORT_CONTENT_KEY];
$filename = $notificationInfo[API::FILENAME_KEY];
$additionalFiles = $notificationInfo[API::ADDITIONAL_FILES_KEY];
$periods = self::getPeriodToFrequencyAsAdjective();
$message = Piwik_Translate('ScheduledReports_EmailHello');
$subject = Piwik_Translate('General_Report') . ' ' . $reportTitle . " - " . $prettyDate;
$mail = new Mail();
$mail->setSubject($subject);
$fromEmailName = Config::getInstance()->branding['use_custom_logo']
? Piwik_Translate('CoreHome_WebAnalyticsReports')
: Piwik_Translate('ScheduledReports_PiwikReports');
$fromEmailAddress = Config::getInstance()->General['noreply_email_address'];
$attachmentName = $subject;
$mail->setFrom($fromEmailAddress, $fromEmailName);
$displaySegmentInfo = false;
$segmentInfo = null;
$segment = API::getSegment($report['idsegment']);
if ($segment != null) {
$displaySegmentInfo = true;
$segmentInfo = Piwik_Translate('ScheduledReports_SegmentAppliedToReports', $segment['name']);
}
switch ($report['format']) {
case 'html':
// Needed when using images as attachment with cid
$mail->setType(Zend_Mime::MULTIPART_RELATED);
$message .= "
" . Piwik_Translate('ScheduledReports_PleaseFindBelow', array($periods[$report['period']], $reportTitle));
if ($displaySegmentInfo) {
$message .= " " . $segmentInfo;
}
$mail->setBodyHtml($message . "
" . $contents);
break;
default:
case 'pdf':
$message .= "\n" . Piwik_Translate('ScheduledReports_PleaseFindAttachedFile', array($periods[$report['period']], $reportTitle));
if ($displaySegmentInfo) {
$message .= " " . $segmentInfo;
}
$mail->setBodyText($message);
$mail->createAttachment(
$contents,
'application/pdf',
Zend_Mime::DISPOSITION_INLINE,
Zend_Mime::ENCODING_BASE64,
$attachmentName . '.pdf'
);
break;
}
foreach ($additionalFiles as $additionalFile) {
$fileContent = $additionalFile['content'];
$at = $mail->createAttachment(
$fileContent,
$additionalFile['mimeType'],
Zend_Mime::DISPOSITION_INLINE,
$additionalFile['encoding'],
$additionalFile['filename']
);
$at->id = $additionalFile['cid'];
unset($fileContent);
}
// Get user emails and languages
$reportParameters = $report['parameters'];
$emails = array();
if (isset($reportParameters[self::ADDITIONAL_EMAILS_PARAMETER])) {
$emails = $reportParameters[self::ADDITIONAL_EMAILS_PARAMETER];
}
if ($reportParameters[self::EMAIL_ME_PARAMETER] == 1) {
if (Piwik::getCurrentUserLogin() == $report['login']) {
$emails[] = Piwik::getCurrentUserEmail();
} elseif ($report['login'] == Piwik::getSuperUserLogin()) {
$emails[] = Piwik::getSuperUserEmail();
} else {
try {
$user = APIUsersManager::getInstance()->getUser($report['login']);
} catch (Exception $e) {
return;
}
$emails[] = $user['email'];
}
}
foreach ($emails as $email) {
if (empty($email)) {
continue;
}
$mail->addTo($email);
try {
$mail->send();
} catch (Exception $e) {
// If running from piwik.php with debug, we ignore the 'email not sent' error
if (!isset($GLOBALS['PIWIK_TRACKER_DEBUG']) || !$GLOBALS['PIWIK_TRACKER_DEBUG']) {
throw new Exception("An error occured while sending '$filename' " .
" to " . implode(', ', $mail->getRecipients()) .
". Error was '" . $e->getMessage() . "'");
}
}
$mail->clearRecipients();
}
}
}
public function getReportRecipients(&$recipients, $notificationInfo)
{
if (self::manageEvent($notificationInfo)) {
$report = $notificationInfo[API::REPORT_KEY];
$parameters = $report['parameters'];
$eMailMe = $parameters[self::EMAIL_ME_PARAMETER];
if ($eMailMe) {
$recipients[] = Piwik::getCurrentUserEmail();
}
if (isset($parameters[self::ADDITIONAL_EMAILS_PARAMETER])) {
$additionalEMails = $parameters[self::ADDITIONAL_EMAILS_PARAMETER];
$recipients = array_merge($recipients, $additionalEMails);
}
$recipients = array_filter($recipients);
}
}
static public function template_reportParametersPDFReports(&$out)
{
$view = new View('@PDFReports/reportParametersPDFReports');
$view->currentUserEmail = Piwik::getCurrentUserEmail();
$view->displayFormats = self::getDisplayFormats();
$view->reportType = self::EMAIL_TYPE;
$view->defaultDisplayFormat = self::DEFAULT_DISPLAY_FORMAT;
$view->defaultEmailMe = self::EMAIL_ME_PARAMETER_DEFAULT_VALUE ? 'true' : 'false';
$view->defaultEvolutionGraph = self::EVOLUTION_GRAPH_PARAMETER_DEFAULT_VALUE ? 'true' : 'false';
$out .= $view->render();
}
private static function manageEvent($info)
{
return in_array(
$info[API::REPORT_TYPE_INFO_KEY],
array_keys(self::$managedReportTypes)
);
}
public function getScheduledTasks(&$tasks)
{
$arbitraryDateInUTC = Date::factory('2011-01-01');
foreach (API::getInstance()->getReports() as $report) {
if (!$report['deleted'] && $report['period'] != ScheduledTime::PERIOD_NEVER) {
$midnightInSiteTimezone =
date(
'H',
Date::factory(
$arbitraryDateInUTC,
Site::getTimezoneFor($report['idsite'])
)->getTimestamp()
);
$hourInUTC = (24 - $midnightInSiteTimezone + $report['hour']) % 24;
$schedule = ScheduledTime::getScheduledTimeForPeriod($report['period']);
$schedule->setHour($hourInUTC);
$tasks[] = new ScheduledTask (
API::getInstance(),
'sendReport',
$report['idreport'], $schedule
);
}
}
}
public function segmentDeactivation(&$idSegment)
{
$reportsUsingSegment = API::getInstance()->getReports(false, false, false, false, $idSegment);
if (count($reportsUsingSegment) > 0) {
$reportList = '';
$reportNameJoinText = ' ' . Piwik_Translate('General_And') . ' ';
foreach ($reportsUsingSegment as $report) {
$reportList .= '\'' . $report['description'] . '\'' . $reportNameJoinText;
}
$reportList = rtrim($reportList, $reportNameJoinText);
$errorMessage = Piwik_Translate('ScheduledReports_Segment_Deletion_Error', $reportList);
throw new Exception($errorMessage);
}
}
function addTopMenu()
{
Piwik_AddTopMenu(
$this->getTopMenuTranslationKey(),
array('module' => 'PDFReports', 'action' => 'index', 'segment' => false),
true,
13,
$isHTML = false,
$tooltip = Piwik_Translate(
\Piwik\PluginsManager::getInstance()->isPluginActivated('MobileMessaging')
? 'MobileMessaging_TopLinkTooltip' : 'ScheduledReports_TopLinkTooltip'
)
);
}
function getTopMenuTranslationKey()
{
// if MobileMessaging is not activated, display 'Email reports'
if (!\Piwik\PluginsManager::getInstance()->isPluginActivated('MobileMessaging'))
return self::PDF_REPORTS_TOP_MENU_TRANSLATION_KEY;
if (Piwik::isUserIsAnonymous()) {
return self::MOBILE_MESSAGING_TOP_MENU_TRANSLATION_KEY;
}
$reports = API::getInstance()->getReports();
$reportCount = count($reports);
// if there are no reports and the mobile account is
// not configured, display 'Email reports'
// configured, display 'Email & SMS reports'
if ($reportCount == 0)
return APIMobileMessaging::getInstance()->areSMSAPICredentialProvided() ?
self::MOBILE_MESSAGING_TOP_MENU_TRANSLATION_KEY : self::PDF_REPORTS_TOP_MENU_TRANSLATION_KEY;
$anyMobileReport = false;
foreach ($reports as $report) {
if ($report['type'] == MobileMessaging::MOBILE_TYPE) {
$anyMobileReport = true;
break;
}
}
// if there is at least one sms report, display 'Email & SMS reports'
if ($anyMobileReport) {
return self::MOBILE_MESSAGING_TOP_MENU_TRANSLATION_KEY;
}
return self::PDF_REPORTS_TOP_MENU_TRANSLATION_KEY;
}
public function deleteUserReport($userLogin)
{
Db::query('DELETE FROM ' . Common::prefixTable('report') . ' WHERE login = ?', $userLogin);
}
public function install()
{
$queries[] = '
CREATE TABLE `' . Common::prefixTable('report') . '` (
`idreport` INT(11) NOT NULL AUTO_INCREMENT,
`idsite` INTEGER(11) NOT NULL,
`login` VARCHAR(100) NOT NULL,
`description` VARCHAR(255) NOT NULL,
`idsegment` INT(11),
`period` VARCHAR(10) NOT NULL,
`hour` tinyint NOT NULL default 0,
`type` VARCHAR(10) NOT NULL,
`format` VARCHAR(10) NOT NULL,
`reports` TEXT NOT NULL,
`parameters` TEXT NULL,
`ts_created` TIMESTAMP NULL,
`ts_last_sent` TIMESTAMP NULL,
`deleted` tinyint(4) NOT NULL default 0,
PRIMARY KEY (`idreport`)
) DEFAULT CHARSET=utf8';
try {
foreach ($queries as $query) {
Db::exec($query);
}
} catch (Exception $e) {
if (!Db::get()->isErrNo($e, '1050')) {
throw $e;
}
}
}
private static function checkAdditionalEmails($additionalEmails)
{
foreach ($additionalEmails as &$email) {
$email = trim($email);
if (empty($email)) {
$email = false;
} elseif (!Piwik::isValidEmailString($email)) {
throw new Exception(Piwik_TranslateException('UsersManager_ExceptionInvalidEmail') . ' (' . $email . ')');
}
}
$additionalEmails = array_filter($additionalEmails);
return $additionalEmails;
}
private static function getDisplayFormats()
{
$displayFormats = array(
// ScheduledReports_AggregateReportsFormat_TablesOnly should be named ScheduledReports_DisplayFormat_GraphsOnlyForKeyMetrics
self::DISPLAY_FORMAT_GRAPHS_ONLY_FOR_KEY_METRICS => Piwik_Translate('ScheduledReports_AggregateReportsFormat_TablesOnly'),
// ScheduledReports_AggregateReportsFormat_GraphsOnly should be named ScheduledReports_DisplayFormat_GraphsOnly
self::DISPLAY_FORMAT_GRAPHS_ONLY => Piwik_Translate('ScheduledReports_AggregateReportsFormat_GraphsOnly'),
// ScheduledReports_AggregateReportsFormat_TablesAndGraphs should be named ScheduledReports_DisplayFormat_TablesAndGraphs
self::DISPLAY_FORMAT_TABLES_AND_GRAPHS => Piwik_Translate('ScheduledReports_AggregateReportsFormat_TablesAndGraphs'),
self::DISPLAY_FORMAT_TABLES_ONLY => Piwik_Translate('ScheduledReports_DisplayFormat_TablesOnly'),
);
return $displayFormats;
}
/**
* Used in the Report Listing
* @ignore
*/
static public function getPeriodToFrequency()
{
return array(
ScheduledTime::PERIOD_NEVER => Piwik_Translate('General_Never'),
ScheduledTime::PERIOD_DAY => Piwik_Translate('General_Daily'),
ScheduledTime::PERIOD_WEEK => Piwik_Translate('General_Weekly'),
ScheduledTime::PERIOD_MONTH => Piwik_Translate('General_Monthly'),
);
}
/**
* Used in the Report's email content, ie "monthly report"
* @ignore
*/
static public function getPeriodToFrequencyAsAdjective()
{
return array(
ScheduledTime::PERIOD_DAY => Piwik_Translate('General_DailyReport'),
ScheduledTime::PERIOD_WEEK => Piwik_Translate('General_WeeklyReport'),
ScheduledTime::PERIOD_MONTH => Piwik_Translate('General_MonthlyReport'),
ScheduledTime::PERIOD_YEAR => Piwik_Translate('General_YearlyReport'),
ScheduledTime::PERIOD_RANGE => Piwik_Translate('General_RangeReports'),
);
}
}