This commit is contained in:
coderkun 2015-04-27 16:42:05 +02:00
commit 046a724272
4209 changed files with 1186656 additions and 0 deletions

View file

@ -0,0 +1,958 @@
<?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'")));
}
}
}

View file

@ -0,0 +1,92 @@
<?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 Piwik\Common;
use Piwik\Piwik;
use Piwik\Plugins\LanguagesManager\LanguagesManager;
use Piwik\Plugins\SegmentEditor\API as APISegmentEditor;
use Piwik\Plugins\SitesManager\API as APISitesManager;
use Piwik\View;
/**
*
*/
class Controller extends \Piwik\Plugin\Controller
{
const DEFAULT_REPORT_TYPE = ScheduledReports::EMAIL_TYPE;
public function index()
{
$view = new View('@ScheduledReports/index');
$this->setGeneralVariablesView($view);
$view->countWebsites = count(APISitesManager::getInstance()->getSitesIdWithAtLeastViewAccess());
// get report types
$reportTypes = API::getReportTypes();
$view->reportTypes = $reportTypes;
$view->defaultReportType = self::DEFAULT_REPORT_TYPE;
$view->defaultReportFormat = ScheduledReports::DEFAULT_REPORT_FORMAT;
$view->displayFormats = ScheduledReports::getDisplayFormats();
$reportsByCategoryByType = array();
$reportFormatsByReportType = array();
$allowMultipleReportsByReportType = array();
foreach ($reportTypes as $reportType => $reportTypeIcon) {
// get report formats
$reportFormatsByReportType[$reportType] = API::getReportFormats($reportType);
$allowMultipleReportsByReportType[$reportType] = API::allowMultipleReports($reportType);
// get report metadata
$reportsByCategory = array();
$availableReportMetadata = API::getReportMetadata($this->idSite, $reportType);
foreach ($availableReportMetadata as $reportMetadata) {
$reportsByCategory[$reportMetadata['category']][] = $reportMetadata;
}
$reportsByCategoryByType[$reportType] = $reportsByCategory;
}
$view->reportsByCategoryByReportType = $reportsByCategoryByType;
$view->reportFormatsByReportType = $reportFormatsByReportType;
$view->allowMultipleReportsByReportType = $allowMultipleReportsByReportType;
$reports = array();
$reportsById = array();
if (!Piwik::isUserIsAnonymous()) {
$reports = API::getInstance()->getReports($this->idSite, $period = false, $idReport = false, $ifSuperUserReturnOnlySuperUserReports = true);
foreach ($reports as &$report) {
$report['recipients'] = API::getReportRecipients($report);
$reportsById[$report['idreport']] = $report;
}
}
$view->reports = $reports;
$view->reportsJSON = Common::json_encode($reportsById);
$view->downloadOutputType = API::OUTPUT_INLINE;
$view->periods = ScheduledReports::getPeriodToFrequency();
$view->defaultPeriod = ScheduledReports::DEFAULT_PERIOD;
$view->defaultHour = ScheduledReports::DEFAULT_HOUR;
$view->language = LanguagesManager::getLanguageCodeForCurrentUser();
$view->segmentEditorActivated = false;
if (API::isSegmentEditorActivated()) {
$savedSegmentsById = array();
foreach (APISegmentEditor::getInstance()->getAll($this->idSite) as $savedSegment) {
$savedSegmentsById[$savedSegment['idsegment']] = $savedSegment['name'];
}
$view->savedSegmentsById = $savedSegmentsById;
$view->segmentEditorActivated = true;
}
return $view->render();
}
}

View file

@ -0,0 +1,642 @@
<?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\Config;
use Piwik\Db;
use Piwik\DbHelper;
use Piwik\Mail;
use Piwik\Menu\MenuTop;
use Piwik\Piwik;
use Piwik\Plugins\CoreAdminHome\CustomLogo;
use Piwik\Plugins\MobileMessaging\API as APIMobileMessaging;
use Piwik\Plugins\MobileMessaging\MobileMessaging;
use Piwik\Plugins\SegmentEditor\API as APISegmentEditor;
use Piwik\Plugins\UsersManager\API as APIUsersManager;
use Piwik\ReportRenderer;
use Piwik\ScheduledTask;
use Piwik\ScheduledTime;
use Piwik\Site;
use Piwik\View;
use Zend_Mime;
/**
*
*/
class ScheduledReports extends \Piwik\Plugin
{
const MOBILE_MESSAGING_TOP_MENU_TRANSLATION_KEY = 'MobileMessaging_TopMenu';
const PDF_REPORTS_TOP_MENU_TRANSLATION_KEY = 'ScheduledReports_EmailReports';
const DISPLAY_FORMAT_GRAPHS_ONLY_FOR_KEY_METRICS = 1; // Display Tables Only (Graphs only for key metrics)
const DISPLAY_FORMAT_GRAPHS_ONLY = 2; // Display Graphs Only for all reports
const DISPLAY_FORMAT_TABLES_AND_GRAPHS = 3; // Display Tables and Graphs for all reports
const DISPLAY_FORMAT_TABLES_ONLY = 4; // Display only tables for all reports
const DEFAULT_DISPLAY_FORMAT = self::DISPLAY_FORMAT_GRAPHS_ONLY_FOR_KEY_METRICS;
const DEFAULT_REPORT_FORMAT = ReportRenderer::HTML_FORMAT;
const DEFAULT_PERIOD = 'week';
const DEFAULT_HOUR = '0';
const EMAIL_ME_PARAMETER = 'emailMe';
const EVOLUTION_GRAPH_PARAMETER = 'evolutionGraph';
const ADDITIONAL_EMAILS_PARAMETER = 'additionalEmails';
const DISPLAY_FORMAT_PARAMETER = 'displayFormat';
const EMAIL_ME_PARAMETER_DEFAULT_VALUE = true;
const EVOLUTION_GRAPH_PARAMETER_DEFAULT_VALUE = false;
const EMAIL_TYPE = 'email';
static private $availableParameters = array(
self::EMAIL_ME_PARAMETER => 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',
ReportRenderer::CSV_FORMAT => 'plugins/Morpheus/images/export.png',
);
/**
* @see Piwik\Plugin::getListHooksRegistered
*/
public function getListHooksRegistered()
{
return array(
'Menu.Top.addItems' => 'addTopMenu',
'TaskScheduler.getScheduledTasks' => 'getScheduledTasks',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'MobileMessaging.deletePhoneNumber' => 'deletePhoneNumber',
'ScheduledReports.getReportParameters' => 'getReportParameters',
'ScheduledReports.validateReportParameters' => 'validateReportParameters',
'ScheduledReports.getReportMetadata' => 'getReportMetadata',
'ScheduledReports.getReportTypes' => 'getReportTypes',
'ScheduledReports.getReportFormats' => 'getReportFormats',
'ScheduledReports.getRendererInstance' => 'getRendererInstance',
'ScheduledReports.getReportRecipients' => 'getReportRecipients',
'ScheduledReports.processReports' => 'processReports',
'ScheduledReports.allowMultipleReports' => 'allowMultipleReports',
'ScheduledReports.sendReport' => 'sendReport',
'Template.reportParametersScheduledReports' => 'template_reportParametersScheduledReports',
'UsersManager.deleteUser' => 'deleteUserReport',
'SitesManager.deleteSite.end' => 'deleteSiteReport',
APISegmentEditor::DEACTIVATE_SEGMENT_EVENT => 'segmentDeactivation',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
);
}
public function getClientSideTranslationKeys(&$translationKeys)
{
$translationKeys[] = "ScheduledReports_ReportSent";
$translationKeys[] = "ScheduledReports_ReportUpdated";
}
/**
* 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/ScheduledReports/javascripts/pdf.js";
}
public function validateReportParameters(&$parameters, $reportType)
{
if (self::manageEvent($reportType)) {
$reportFormat = $parameters[self::DISPLAY_FORMAT_PARAMETER];
$availableDisplayFormats = array_keys(self::getDisplayFormats());
if (!in_array($reportFormat, $availableDisplayFormats)) {
throw new Exception(
Piwik::translate(
// 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, $reportType, $idSite)
{
if (self::manageEvent($reportType)) {
$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, $reportType)
{
if (self::manageEvent($reportType)) {
$reportFormats = self::$managedReportFormats;
}
}
public function getReportParameters(&$availableParameters, $reportType)
{
if (self::manageEvent($reportType)) {
$availableParameters = self::$availableParameters;
}
}
public function processReports(&$processedReports, $reportType, $outputType, $report)
{
if (self::manageEvent($reportType)) {
$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\Plugin\Manager::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, $reportType, $outputType, $report)
{
if (self::manageEvent($reportType)) {
$reportFormat = $report['format'];
$reportRenderer = ReportRenderer::factory($reportFormat);
if ($reportFormat == ReportRenderer::HTML_FORMAT) {
$reportRenderer->setRenderImageInline($outputType != API::OUTPUT_SAVE_ON_DISK);
}
}
}
public function allowMultipleReports(&$allowMultipleReports, $reportType)
{
if (self::manageEvent($reportType)) {
$allowMultipleReports = true;
}
}
public function sendReport($reportType, $report, $contents, $filename, $prettyDate, $reportSubject, $reportTitle,
$additionalFiles)
{
if (self::manageEvent($reportType)) {
$periods = self::getPeriodToFrequencyAsAdjective();
$message = Piwik::translate('ScheduledReports_EmailHello');
$subject = Piwik::translate('General_Report') . ' ' . $reportTitle . " - " . $prettyDate;
$mail = new Mail();
$mail->setDefaultFromPiwik();
$mail->setSubject($subject);
$attachmentName = $subject;
$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 .= "<br/>" . Piwik::translate('ScheduledReports_PleaseFindBelow', array($periods[$report['period']], $reportTitle));
if ($displaySegmentInfo) {
$message .= " " . $segmentInfo;
}
$mail->setBodyHtml($message . "<br/><br/>" . $contents);
break;
case 'csv':
$message .= "\n" . Piwik::translate('ScheduledReports_PleaseFindAttachedFile', array($periods[$report['period']], $reportTitle));
if ($displaySegmentInfo) {
$message .= " " . $segmentInfo;
}
$mail->setBodyText($message);
$mail->createAttachment(
$contents,
'application/csv',
Zend_Mime::DISPOSITION_INLINE,
Zend_Mime::ENCODING_BASE64,
$attachmentName . '.csv'
);
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();
} 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 deletePhoneNumber($phoneNumber)
{
$api = API::getInstance();
$reports = $api->getReports(
$idSite = false,
$period = false,
$idReport = false,
$ifSuperUserReturnOnlySuperUserReports = false
);
foreach ($reports as $report) {
if ($report['type'] == MobileMessaging::MOBILE_TYPE) {
$reportParameters = $report['parameters'];
$reportPhoneNumbers = $reportParameters[MobileMessaging::PHONE_NUMBERS_PARAMETER];
$updatedPhoneNumbers = array();
foreach ($reportPhoneNumbers as $reportPhoneNumber) {
if ($reportPhoneNumber != $phoneNumber) {
$updatedPhoneNumbers[] = $reportPhoneNumber;
}
}
if (count($updatedPhoneNumbers) != count($reportPhoneNumbers)) {
$reportParameters[MobileMessaging::PHONE_NUMBERS_PARAMETER] = $updatedPhoneNumbers;
// note: reports can end up without any recipients
$api->updateReport(
$report['idreport'],
$report['idsite'],
$report['description'],
$report['period'],
$report['hour'],
$report['type'],
$report['format'],
$report['reports'],
$reportParameters
);
}
}
}
}
public function getReportRecipients(&$recipients, $reportType, $report)
{
if (self::manageEvent($reportType)) {
$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_reportParametersScheduledReports(&$out)
{
$view = new View('@ScheduledReports/reportParametersScheduledReports');
$view->currentUserEmail = Piwik::getCurrentUserEmail();
$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($reportType)
{
return in_array($reportType, array_keys(self::$managedReportTypes));
}
public function getScheduledTasks(&$tasks)
{
foreach (API::getInstance()->getReports() as $report) {
if (!$report['deleted'] && $report['period'] != ScheduledTime::PERIOD_NEVER) {
$timezone = Site::getTimezoneFor($report['idsite']);
$schedule = ScheduledTime::getScheduledTimeForPeriod($report['period']);
$schedule->setHour($report['hour']);
$schedule->setTimezone($timezone);
$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()
{
MenuTop::addEntry(
$this->getTopMenuTranslationKey(),
array('module' => 'ScheduledReports', 'action' => 'index', 'segment' => false),
true,
13,
$isHTML = false,
$tooltip = Piwik::translate(
\Piwik\Plugin\Manager::getInstance()->isPluginActivated('MobileMessaging')
? 'MobileMessaging_TopLinkTooltip' : 'ScheduledReports_TopLinkTooltip'
)
);
}
function getTopMenuTranslationKey()
{
// if MobileMessaging is not activated, display 'Email reports'
if (!\Piwik\Plugin\Manager::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()
{
$reportTable = "`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`)";
DbHelper::createTable('report', $reportTable);
}
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::translate('UsersManager_ExceptionInvalidEmail') . ' (' . $email . ')');
}
}
$additionalEmails = array_filter($additionalEmails);
return $additionalEmails;
}
public 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'),
);
}
}

View file

@ -0,0 +1,245 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
/**
* Override settings in libs/tcpdf_config.php
*
*/
define('K_PATH_MAIN', PIWIK_INCLUDE_PATH . '/libs/tcpdf/');
$pathTmpTCPDF = PIWIK_USER_PATH . '/tmp/tcpdf/';
$pathTmpTCPDF = \Piwik\SettingsPiwik::rewriteTmpPathWithHostname($pathTmpTCPDF);
define('K_PATH_CACHE', $pathTmpTCPDF);
define('K_PATH_IMAGES', $pathTmpTCPDF);
if (!defined('K_TCPDF_EXTERNAL_CONFIG')) {
// DOCUMENT_ROOT fix for IIS Webserver
if ((!isset($_SERVER['DOCUMENT_ROOT'])) OR (empty($_SERVER['DOCUMENT_ROOT']))) {
if (isset($_SERVER['SCRIPT_FILENAME'])) {
$_SERVER['DOCUMENT_ROOT'] = str_replace('\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0 - strlen($_SERVER['PHP_SELF'])));
} elseif (isset($_SERVER['PATH_TRANSLATED'])) {
$_SERVER['DOCUMENT_ROOT'] = str_replace('\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0 - strlen($_SERVER['PHP_SELF'])));
} else {
// define here your DOCUMENT_ROOT path if the previous fails
$_SERVER['DOCUMENT_ROOT'] = '/var/www';
}
}
if (!defined('K_PATH_MAIN')) {
// Automatic calculation for the following K_PATH_MAIN constant
$k_path_main = str_replace('\\', '/', realpath(substr(dirname(__FILE__), 0, 0 - strlen('config'))));
if (substr($k_path_main, -1) != '/') {
$k_path_main .= '/';
}
/**
* Installation path (/var/www/tcpdf/).
* By default it is automatically calculated but you can also set it as a fixed string to improve performances.
*/
if (!defined('K_PATH_MAIN')) {
define ('K_PATH_MAIN', $k_path_main);
}
}
if (!defined('K_PATH_URL')) {
// Automatic calculation for the following K_PATH_URL constant
$k_path_url = K_PATH_MAIN; // default value for console mode
if (isset($_SERVER['HTTP_HOST']) AND (!empty($_SERVER['HTTP_HOST']))) {
if (isset($_SERVER['HTTPS']) AND (!empty($_SERVER['HTTPS'])) AND strtolower($_SERVER['HTTPS']) != 'off') {
$k_path_url = 'https://';
} else {
$k_path_url = 'http://';
}
$k_path_url .= $_SERVER['HTTP_HOST'];
$k_path_url .= str_replace('\\', '/', substr(K_PATH_MAIN, (strlen($_SERVER['DOCUMENT_ROOT']) - 1)));
}
/**
* URL path to tcpdf installation folder (http://localhost/tcpdf/).
* By default it is automatically calculated but you can also set it as a fixed string to improve performances.
*/
define ('K_PATH_URL', $k_path_url);
}
/**
* path for PDF fonts
* use K_PATH_MAIN.'fonts/old/' for old non-UTF8 fonts
*/
define ('K_PATH_FONTS', K_PATH_MAIN . 'fonts/');
/**
* cache directory for temporary files (full path)
*/
if (!defined('K_PATH_CACHE')) {
define ('K_PATH_CACHE', K_PATH_MAIN . 'cache/');
}
/**
* cache directory for temporary files (url path)
*/
define ('K_PATH_URL_CACHE', K_PATH_URL . 'cache/');
/**
*images directory
*/
if (!defined('K_PATH_IMAGES')) {
define ('K_PATH_IMAGES', K_PATH_MAIN . 'images/');
}
/**
* blank image
*/
define ('K_BLANK_IMAGE', K_PATH_IMAGES . '_blank.png');
/**
* page format
*/
define ('PDF_PAGE_FORMAT', 'A4');
/**
* page orientation (P=portrait, L=landscape)
*/
define ('PDF_PAGE_ORIENTATION', 'P');
/**
* document creator
*/
define ('PDF_CREATOR', 'TCPDF');
/**
* document author
*/
define ('PDF_AUTHOR', 'TCPDF');
/**
* header title
*/
define ('PDF_HEADER_TITLE', 'TCPDF Example');
/**
* header description string
*/
define ('PDF_HEADER_STRING', "by Nicola Asuni - Tecnick.com\nwww.tcpdf.org");
/**
* image logo
*/
define ('PDF_HEADER_LOGO', 'tcpdf_logo.jpg');
/**
* header logo image width [mm]
*/
define ('PDF_HEADER_LOGO_WIDTH', 30);
/**
* document unit of measure [pt=point, mm=millimeter, cm=centimeter, in=inch]
*/
define ('PDF_UNIT', 'mm');
/**
* header margin
*/
define ('PDF_MARGIN_HEADER', 5);
/**
* footer margin
*/
define ('PDF_MARGIN_FOOTER', 10);
/**
* top margin
*/
define ('PDF_MARGIN_TOP', 27);
/**
* bottom margin
*/
define ('PDF_MARGIN_BOTTOM', 25);
/**
* left margin
*/
define ('PDF_MARGIN_LEFT', 15);
/**
* right margin
*/
define ('PDF_MARGIN_RIGHT', 15);
/**
* default main font name
*/
define ('PDF_FONT_NAME_MAIN', 'helvetica');
/**
* default main font size
*/
define ('PDF_FONT_SIZE_MAIN', 10);
/**
* default data font name
*/
define ('PDF_FONT_NAME_DATA', 'helvetica');
/**
* default data font size
*/
define ('PDF_FONT_SIZE_DATA', 8);
/**
* default monospaced font name
*/
define ('PDF_FONT_MONOSPACED', 'courier');
/**
* ratio used to adjust the conversion of pixels to user units
*/
define ('PDF_IMAGE_SCALE_RATIO', 1.25);
/**
* magnification factor for titles
*/
define('HEAD_MAGNIFICATION', 1.1);
/**
* height of cell repect font height
*/
define('K_CELL_HEIGHT_RATIO', 1.25);
/**
* title magnification respect main font size
*/
define('K_TITLE_MAGNIFICATION', 1.3);
/**
* reduction factor for small font
*/
define('K_SMALL_RATIO', 2 / 3);
/**
* set to true to enable the special procedure used to avoid the overlappind of symbols on Thai language
*/
define('K_THAI_TOPCHARS', true);
/**
* if true allows to call TCPDF methods using HTML syntax
* IMPORTANT: For security reason, disable this feature if you are printing user HTML content.
*/
define('K_TCPDF_CALLS_IN_HTML', true);
}
// define the constant K_TCPDF_EXTERNAL_CONFIG to ignore tcpdf's default settings
define('K_TCPDF_EXTERNAL_CONFIG', true);
//============================================================+
// END OF FILE
//============================================================+

View file

@ -0,0 +1,202 @@
/*!
* Piwik - Web Analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
var getReportParametersFunctions = Object();
var updateReportParametersFunctions = Object();
var resetReportParametersFunctions = Object();
function formSetEditReport(idReport) {
var report = {
'type': ReportPlugin.defaultReportType,
'format': ReportPlugin.defaultReportFormat,
'description': '',
'period': ReportPlugin.defaultPeriod,
'hour': ReportPlugin.defaultHour,
'reports': []
};
if (idReport > 0) {
report = ReportPlugin.reportList[idReport];
$('#report_submit').val(ReportPlugin.updateReportString);
}
else {
$('#report_submit').val(ReportPlugin.createReportString);
}
toggleReportType(report.type);
$('#report_description').html(report.description);
$('#report_segment').find('option[value=' + report.idsegment + ']').prop('selected', 'selected');
$('#report_type').find('option[value=' + report.type + ']').prop('selected', 'selected');
$('#report_period').find('option[value=' + report.period + ']').prop('selected', 'selected');
$('#report_hour').val(report.hour);
$('[name=report_format].' + report.type + ' option[value=' + report.format + ']').prop('selected', 'selected');
var selectorReportFormat = 'select[name=report_format].' + $('#report_type').val();
$(selectorReportFormat).change( toggleDisplayOptionsByFormat );
// When CSV is selected, hide "Display options"
toggleDisplayOptionsByFormat();
function toggleDisplayOptionsByFormat() {
var format = $(selectorReportFormat).val();
var displayOptionsSelector = $('#row_report_display_options');
if (format == 'csv') {
displayOptionsSelector.hide();
} else {
displayOptionsSelector.show();
}
}
$('[name=reportsList] input').prop('checked', false);
var key;
for (key in report.reports) {
$('.' + report.type + ' [report-unique-id=' + report.reports[key] + ']').prop('checked', 'checked');
}
updateReportParametersFunctions[report.type](report.parameters);
$('#report_idreport').val(idReport);
}
function getReportAjaxRequest(idReport, defaultApiMethod) {
var parameters = {};
piwikHelper.lazyScrollTo(".centerLargeDiv>h2", 400);
parameters.module = 'API';
parameters.method = defaultApiMethod;
if (idReport == 0) {
parameters.method = 'ScheduledReports.addReport';
}
parameters.format = 'json';
return parameters;
}
function toggleReportType(reportType) {
resetReportParametersFunctions[reportType]();
$('#report_type').find('option').each(function (index, type) {
$('.' + $(type).val()).hide();
});
$('.' + reportType).show();
}
function fadeInOutSuccessMessage(selector, message) {
var UI = require('piwik/UI');
var notification = new UI.Notification();
notification.show(message, {
placeat: selector,
context: 'success',
noclear: true,
type: 'toast',
style: {display: 'inline-block', marginTop: '10px'},
id: 'usersManagerAccessUpdated'
});
piwikHelper.refreshAfter(2);
}
function initManagePdf() {
// Click Add/Update Submit
$('#addEditReport').submit(function () {
var idReport = $('#report_idreport').val();
var apiParameters = getReportAjaxRequest(idReport, 'ScheduledReports.updateReport');
apiParameters.idReport = idReport;
apiParameters.description = $('#report_description').val();
apiParameters.idSegment = $('#report_segment').find('option:selected').val();
apiParameters.reportType = $('#report_type').find('option:selected').val();
apiParameters.reportFormat = $('[name=report_format].' + apiParameters.reportType + ' option:selected').val();
var reports = [];
$('[name=reportsList].' + apiParameters.reportType + ' input:checked').each(function () {
reports.push($(this).attr('report-unique-id'));
});
if (reports.length > 0) {
apiParameters.reports = reports;
}
apiParameters.parameters = getReportParametersFunctions[apiParameters.reportType]();
var ajaxHandler = new ajaxHelper();
ajaxHandler.addParams(apiParameters, 'POST');
ajaxHandler.addParams({period: $('#report_period').find('option:selected').val()}, 'GET');
ajaxHandler.addParams({hour: $('#report_hour').val()}, 'GET');
ajaxHandler.redirectOnSuccess();
ajaxHandler.setLoadingElement();
if (idReport) {
ajaxHandler.setCallback(function (response) {
fadeInOutSuccessMessage('#reportUpdatedSuccess', _pk_translate('ScheduledReports_ReportUpdated'));
});
}
ajaxHandler.send(true);
return false;
});
// Email now
$('a[name=linkSendNow]').click(function () {
var idReport = $(this).attr('idreport');
var parameters = getReportAjaxRequest(idReport, 'ScheduledReports.sendReport');
parameters.idReport = idReport;
var ajaxHandler = new ajaxHelper();
ajaxHandler.addParams(parameters, 'POST');
ajaxHandler.setLoadingElement();
ajaxHandler.setCallback(function (response) {
fadeInOutSuccessMessage('#reportSentSuccess', _pk_translate('ScheduledReports_ReportSent'));
});
ajaxHandler.send(true);
});
// Delete Report
$('a[name=linkDeleteReport]').click(function () {
var idReport = $(this).attr('id');
function onDelete() {
var parameters = getReportAjaxRequest(idReport, 'ScheduledReports.deleteReport');
parameters.idReport = idReport;
var ajaxHandler = new ajaxHelper();
ajaxHandler.addParams(parameters, 'POST');
ajaxHandler.redirectOnSuccess();
ajaxHandler.setLoadingElement();
ajaxHandler.send(true);
}
piwikHelper.modalConfirm('#confirm', {yes: onDelete});
});
// Edit Report click
$('a[name=linkEditReport]').click(function () {
var idReport = $(this).attr('id');
formSetEditReport(idReport);
$('.entityAddContainer').show();
$('#entityEditContainer').hide();
$(document).trigger('ScheduledReport.edit', {});
});
// Switch Report Type
$('#report_type').change(function () {
var reportType = $(this).val();
toggleReportType(reportType);
});
// Add a Report click
$('#linkAddReport').click(function () {
$('.entityAddContainer').show();
$('#entityEditContainer').hide();
formSetEditReport(/*idReport = */0);
});
// Cancel click
$('.entityCancelLink').click(function () {
$('.entityAddContainer').hide();
$('#entityEditContainer').show();
piwikHelper.hideAjaxError();
}).click();
}

View file

@ -0,0 +1,181 @@
<div class="entityAddContainer" style="display:none;">
<div class='entityCancel'>
{{ 'ScheduledReports_CancelAndReturnToReports'|translate("<a class='entityCancelLink'>","</a>")|raw }}
</div>
<div class='clear'></div>
<form id='addEditReport'>
<table class="dataTable entityTable">
<thead>
<tr class="first">
<th colspan="2">{{ 'ScheduledReports_CreateAndScheduleReport'|translate }}</th>
<tr>
</thead>
<tbody>
<tr>
<td class="first">{{ 'General_Website'|translate }} </td>
<td style="width:650px;">
{{ siteName|raw }}
</td>
</tr>
<tr>
<td class="first">{{ 'General_Description'|translate }} </td>
<td>
<textarea cols="30" rows="3" id="report_description" class="inp"></textarea>
<div class="entityInlineHelp">
{{ 'ScheduledReports_DescriptionOnFirstPage'|translate }}
</div>
</td>
</tr>
{% if segmentEditorActivated %}
<tr>
<td class="first">{{ 'SegmentEditor_ChooseASegment'|translate }} </td>
<td>
<select id='report_segment'>
<option value="">{{ 'SegmentEditor_DefaultAllVisits'|translate }}</option>
{% for savedSegmentId, savedSegmentName in savedSegmentsById %}
<option value="{{ savedSegmentId }}">{{ savedSegmentName[:50] }}</option>
{% endfor %}
</select>
<div class="entityInlineHelp">
{% set SegmentEditor_DefaultAllVisits %}{{ 'SegmentEditor_DefaultAllVisits'|translate }}{% endset %}
{% set SegmentEditor_AddNewSegment %}{{ 'SegmentEditor_AddNewSegment'|translate }}{% endset %}
{{ 'ScheduledReports_Segment_Help'|translate('<a href="./" target="_blank">','</a>',SegmentEditor_DefaultAllVisits,SegmentEditor_AddNewSegment)|raw }}
</div>
</td>
</tr>
{% endif %}
<tr>
<td class="first">{{ 'ScheduledReports_EmailSchedule'|translate }}</td>
<td>
<select id="report_period" class="inp">
{% for periodId, period in periods %}
<option value="{{ periodId }}">
{{ period }}
</option>
{% endfor %}
</select>
<div class="entityInlineHelp">
{{ 'ScheduledReports_WeeklyScheduleHelp'|translate }}
<br/>
{{ 'ScheduledReports_MonthlyScheduleHelp'|translate }}
<br/>
{{ 'ScheduledReports_ReportHour'|translate }}
<input type="text" style="height: 0.9em;padding-left: 5px;width: 35px;" id="report_hour" class="inp" size="2">
{{ 'ScheduledReports_OClock'|translate }}
</div>
</td>
</tr>
<tr {% if reportTypes|length == 1 %}style="display:none;"{% endif %}>
<td class="first">
{{ 'ScheduledReports_ReportType'|translate }}
</td>
<td>
<select id="report_type">
{% for reportType, reportTypeIcon in reportTypes %}
<option value="{{ reportType }}">{{ reportType|upper }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td class="first">
{{ 'ScheduledReports_ReportFormat'|translate }}
</td>
<td>
{% for reportType, reportFormats in reportFormatsByReportType %}
<select name='report_format' class='{{ reportType }}'>
{% for reportFormat, reportFormatIcon in reportFormats %}
<option value="{{ reportFormat }}">{{ reportFormat|upper }}</option>
{% endfor %}
</select>
{% endfor %}
</td>
</tr>
{{ postEvent("Template.reportParametersScheduledReports") }}
<tr id="row_report_display_options">
<td class="first">
{# ScheduledReports_AggregateReportsFormat should be named ScheduledReports_DisplayFormat #}
{{ 'ScheduledReports_AggregateReportsFormat'|translate }}
</td>
<td>
<select id="display_format">
{% for formatValue, formatLabel in displayFormats %}
<option {% if formatValue==1 %}selected{% endif %} value="{{ formatValue }}">{{ formatLabel }}</option>
{% endfor %}
</select>
<div class='report_evolution_graph'>
<br/>
<input type="checkbox" id="report_evolution_graph"/>
<label for="report_evolution_graph"><em>{{ 'ScheduledReports_EvolutionGraph'|translate(5) }}</em></label>
</div>
</td>
</tr>
<tr>
<td class="first">{{ 'ScheduledReports_ReportsIncluded'|translate }}</td>
<td>
{% for reportType, reportsByCategory in reportsByCategoryByReportType %}
<div name='reportsList' class='{{ reportType }}'>
{% if allowMultipleReportsByReportType[reportType] %}
{% set reportInputType='checkbox' %}
{% else %}
{% set reportInputType='radio' %}
{% endif %}
{% set countCategory=0 %}
{% set newColumnAfter=(reportsByCategory|length + 1)//2 %}
<div id='leftcolumn'>
{% for category, reports in reportsByCategory %}
{% if countCategory >= newColumnAfter and newColumnAfter != 0 %}
{% set newColumnAfter=0 %}
</div>
<div id='rightcolumn'>
{% endif %}
<div class='reportCategory'>{{ category }}</div>
<ul class='listReports'>
{% for report in reports %}
<li>
<input type='{{ reportInputType }}' id="{{ reportType }}{{ report.uniqueId }}" report-unique-id='{{ report.uniqueId }}'
name='{{ reportType }}Reports'/>
<label for="{{ reportType }}{{ report.uniqueId }}">
{{ report.name|raw }}
{% if report.uniqueId=='MultiSites_getAll' %}
<div class="entityInlineHelp">{{ 'ScheduledReports_ReportIncludeNWebsites'|translate(countWebsites)
}}</div>
{% endif %}
</label>
</li>
{% endfor %}
{% set countCategory=countCategory+1 %}
</ul>
<br/>
{% endfor %}
</div>
</div>
{% endfor %}
</td>
</tr>
</tbody>
</table>
<input type="hidden" id="report_idreport" value="">
<input type="submit" id="report_submit" name="submit" class="submit"/>
</form>
<div class='entityCancel'>
{{ 'General_OrCancel'|translate("<a class='entityCancelLink'>","</a>")|raw }}
</div>
</div>

View file

@ -0,0 +1,103 @@
<div id='entityEditContainer'>
<table class="dataTable entityTable">
<thead>
<tr>
<th class="first">{{ 'General_Description'|translate }}</th>
<th>{{ 'ScheduledReports_EmailSchedule'|translate }}</th>
<th>{{ 'ScheduledReports_ReportFormat'|translate }}</th>
<th>{{ 'ScheduledReports_SendReportTo'|translate }}</th>
<th>{{ 'General_Download'|translate }}</th>
<th>{{ 'General_Edit'|translate }}</th>
<th>{{ 'General_Delete'|translate }}</th>
</tr>
</thead>
{% if userLogin == 'anonymous' %}
<tr>
<td colspan='7'>
<br/>
{{ 'ScheduledReports_MustBeLoggedIn'|translate }}
<br/>&rsaquo; <a href='index.php?module={{ loginModule }}'>{{ 'Login_LogIn'|translate }}</a>
<br/><br/>
</td>
</tr>
</table>
{% elseif reports is empty %}
<tr>
<td colspan='7'>
<br/>
{{ 'ScheduledReports_ThereIsNoReportToManage'|translate(siteName)|raw }}.
<br/><br/>
<a onclick='' id='linkAddReport'>&rsaquo; {{ 'ScheduledReports_CreateAndScheduleReport'|translate }}</a>
<br/><br/>
</td>
</tr>
</table>
{% else %}
{% for report in reports %}
<tr>
<td class="first">
{{ report.description | raw }}
{% if segmentEditorActivated and report.idsegment %}
<div class="entityInlineHelp" style="font-size: 9pt;">
{{ savedSegmentsById[report.idsegment] }}
</div>
{% endif %}
</td>
<td>{{ periods[report.period] }}
<!-- Last sent on {{ report.ts_last_sent }} -->
</td>
<td>
{% if report.format is not empty %}
{{ report.format|upper }}
{% endif %}
</td>
<td>
{# report recipients #}
{% if report.recipients|length == 0 %}
{{ 'ScheduledReports_NoRecipients'|translate }}
{% else %}
{% for recipient in report.recipients %}
{{ recipient }}
<br/>
{% endfor %}
{# send now link #}
<a href="#" idreport="{{ report.idreport }}" name="linkSendNow" class="link_but" style="margin-top:3px;">
<img border=0 src='{{ reportTypes[report.type] }}'/>
{{ 'ScheduledReports_SendReportNow'|translate }}
</a>
{% endif %}
</td>
<td>
{# download link #}
<a href="{{ linkTo({'module':'API', 'segment': null, 'token_auth':token_auth, 'method':'ScheduledReports.generateReport', 'idReport':report.idreport, 'outputType':downloadOutputType, 'language':language}) }}"
target="_blank" name="linkDownloadReport" id="{{ report.idreport }}" class="link_but">
<img src='{{ reportFormatsByReportType[report.type][report.format] }}' border="0"/>
{{ 'General_Download'|translate }}
</a>
</td>
<td>
{# edit link #}
<a href='#' name="linkEditReport" id="{{ report.idreport }}" class="link_but">
<img src='plugins/Zeitgeist/images/ico_edit.png' border="0"/>
{{ 'General_Edit'|translate }}
</a>
</td>
<td>
{# delete link #}
<a href='#' name="linkDeleteReport" id="{{ report.idreport }}" class="link_but">
<img src='plugins/Zeitgeist/images/ico_delete.png' border="0"/>
{{ 'General_Delete'|translate }}
</a>
</td>
</tr>
{% endfor %}
</table>
{% if userLogin != 'anonymous' %}
<br/>
<a onclick='' id='linkAddReport'>&rsaquo; {{ 'ScheduledReports_CreateAndScheduleReport'|translate }}</a>
<br/>
<br/>
{% endif %}
{% endif %}
</div>

View file

@ -0,0 +1,62 @@
{% extends 'dashboard.twig' %}
{% block content %}
{% include "@CoreHome/_siteSelectHeader.twig" %}
<div class="top_controls">
{% include "@CoreHome/_periodSelect.twig" %}
</div>
<div class="centerLargeDiv">
<h2 piwik-enriched-headline
help-url="http://piwik.org/docs/email-reports/">{{ 'ScheduledReports_ManageEmailReports'|translate }}</h2>
<span id="reportSentSuccess"></span>
<span id="reportUpdatedSuccess"></span>
<div class="entityContainer">
{% import 'ajaxMacros.twig' as ajax %}
{{ ajax.errorDiv() }}
{{ ajax.loadingDiv() }}
{% include "@ScheduledReports/_listReports.twig" %}
{% include "@ScheduledReports/_addReport.twig" %}
<a id='bottom'></a>
</div>
</div>
<div class="ui-confirm" id="confirm">
<h2>{{ 'ScheduledReports_AreYouSureDeleteReport'|translate }}</h2>
<input role="yes" type="button" value="{{ 'General_Yes'|translate }}"/>
<input role="no" type="button" value="{{ 'General_No'|translate }}"/>
</div>
<script type="text/javascript">
var ReportPlugin = {};
ReportPlugin.defaultPeriod = '{{ defaultPeriod }}';
ReportPlugin.defaultHour = '{{ defaultHour }}';
ReportPlugin.defaultReportType = '{{ defaultReportType }}';
ReportPlugin.defaultReportFormat = '{{ defaultReportFormat }}';
ReportPlugin.reportList = {{ reportsJSON | raw }};
ReportPlugin.createReportString = "{{ 'ScheduledReports_CreateReport'|translate }}";
ReportPlugin.updateReportString = "{{ 'ScheduledReports_UpdateReport'|translate }}";
$(function () {
initManagePdf();
});
</script>
<style type="text/css">
.reportCategory {
font-weight: bold;
margin-bottom: 5px;
}
.entityAddContainer {
position:relative;
}
.entityAddContainer > .entityCancel:first-child {
position: absolute;
right:0;
bottom:100%;
}
</style>
{% endblock %}

View file

@ -0,0 +1,78 @@
<tr class='{{ reportType }}'>
<td style='width:240px;' class="first">{{ 'ScheduledReports_SendReportTo'|translate }}
</td>
<td>
<input type="checkbox" id="report_email_me"/>
<label for="report_email_me">{{ 'ScheduledReports_SentToMe'|translate }} (<em>{{ currentUserEmail }}</em>) </label>
<br/><br/>
{{ 'ScheduledReports_AlsoSendReportToTheseEmails'|translate }}<br/>
<textarea cols="30" rows="3" id="report_additional_emails" class="inp"></textarea>
<script>
function updateEvolutionGraphParameterVisibility() {
var evolutionGraphParameterInput = $('.report_evolution_graph');
var nonApplicableDisplayFormats = ['1', '4'];
$.inArray($('#display_format').find('option:selected').val(), nonApplicableDisplayFormats) != -1 ?
evolutionGraphParameterInput.hide() : evolutionGraphParameterInput.show();
}
$(function () {
resetReportParametersFunctions ['{{ reportType }}'] =
function () {
var reportParameters = {
'displayFormat': '{{ defaultDisplayFormat }}',
'emailMe': {{ defaultEmailMe }},
'evolutionGraph': {{ defaultEvolutionGraph }},
'additionalEmails': null
};
updateReportParametersFunctions['{{ reportType }}'](reportParameters);
};
updateReportParametersFunctions['{{ reportType }}'] =
function (reportParameters) {
if (reportParameters == null) return;
$('#display_format').find('option[value=' + reportParameters.displayFormat + ']').prop('selected', 'selected');
updateEvolutionGraphParameterVisibility();
if (reportParameters.emailMe === true)
$('#report_email_me').prop('checked', 'checked');
else
$('#report_email_me').removeProp('checked');
if (reportParameters.evolutionGraph === true)
$('#report_evolution_graph').prop('checked', 'checked');
else
$('#report_evolution_graph').removeProp('checked');
if (reportParameters.additionalEmails != null)
$('#report_additional_emails').text(reportParameters.additionalEmails.join('\n'));
else
$('#report_additional_emails').html('');
$(document).trigger('ScheduledReport.edit', {});
};
getReportParametersFunctions['{{ reportType }}'] =
function () {
var parameters = Object();
parameters.displayFormat = $('#display_format').find('option:selected').val();
parameters.emailMe = $('#report_email_me').prop('checked');
parameters.evolutionGraph = $('#report_evolution_graph').prop('checked');
var additionalEmails = $('#report_additional_emails').val();
parameters.additionalEmails =
additionalEmails != '' ? additionalEmails.split('\n') : [];
return parameters;
};
$('#display_format').change(updateEvolutionGraphParameterVisibility);
});
</script>
</td>
</tr>