Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/global.ini.php2
-rw-r--r--core/Piwik.php5
-rw-r--r--core/PluginsFunctions/Sql.php74
-rw-r--r--core/ScheduledTask.php24
-rw-r--r--core/TaskScheduler.php74
-rw-r--r--core/ViewDataTable.php29
-rw-r--r--core/ViewDataTable/Cloud.php6
-rw-r--r--core/ViewDataTable/GenerateGraphHTML.php5
-rw-r--r--core/ViewDataTable/HtmlTable.php5
-rw-r--r--lang/be.php5
-rw-r--r--lang/da.php5
-rw-r--r--lang/de.php5
-rw-r--r--lang/el.php9
-rw-r--r--lang/en.php29
-rw-r--r--lang/es.php5
-rw-r--r--lang/fr.php3
-rw-r--r--lang/id.php5
-rw-r--r--lang/it.php4
-rw-r--r--lang/lt.php4
-rw-r--r--lang/lv.php4
-rw-r--r--lang/pl.php3
-rw-r--r--lang/pt.php5
-rw-r--r--lang/ru.php3
-rw-r--r--lang/sq.php3
-rw-r--r--lang/sv.php5
-rw-r--r--plugins/CoreAdminHome/CoreAdminHome.php9
-rw-r--r--plugins/CoreAdminHome/templates/generalSettings.tpl6
-rw-r--r--plugins/CoreHome/templates/cloud.tpl4
-rw-r--r--plugins/CoreHome/templates/datatable.tpl6
-rw-r--r--plugins/CoreHome/templates/graph.tpl6
-rw-r--r--plugins/DBStats/API.php35
-rw-r--r--plugins/DBStats/Controller.php2
-rw-r--r--plugins/DBStats/templates/DBStats.tpl4
-rw-r--r--plugins/Dashboard/Dashboard.php3
-rw-r--r--plugins/Goals/API.php2
-rw-r--r--plugins/LanguagesManager/LanguagesManager.php3
-rw-r--r--plugins/PrivacyManager/Controller.php174
-rwxr-xr-xplugins/PrivacyManager/LogDataPurger.php151
-rw-r--r--plugins/PrivacyManager/PrivacyManager.php443
-rwxr-xr-xplugins/PrivacyManager/ReportsPurger.php309
-rwxr-xr-xplugins/PrivacyManager/templates/databaseSize.tpl4
-rw-r--r--plugins/PrivacyManager/templates/privacySettings.js141
-rw-r--r--plugins/PrivacyManager/templates/privacySettings.tpl211
-rwxr-xr-xplugins/PrivacyManager/tests/PrivacyManager.test.php601
-rw-r--r--tests/integration/expected/test_apiGetReportMetadata_year__LanguagesManager.getTranslationsForLanguage.xml12
45 files changed, 2107 insertions, 340 deletions
diff --git a/config/global.ini.php b/config/global.ini.php
index 27950adbbe..fcc40d730b 100644
--- a/config/global.ini.php
+++ b/config/global.ini.php
@@ -375,11 +375,9 @@ tracking_requests_require_authentication = 1
; otherwise you may lose tracking data.
; delete_logs_schedule_lowest_interval - lowest possible interval between two table deletes (in days, 1|7|30). Default: 7.
; delete_logs_older_than - delete data older than XX (days). Default: 180
-; delete_max_rows_per_run - Maximum of rows deleted in one go (in thousands); 0 for no limit
delete_logs_enable = 0
delete_logs_schedule_lowest_interval = 7
delete_logs_older_than = 180
-delete_max_rows_per_run = 100
[branding]
; custom logo
diff --git a/core/Piwik.php b/core/Piwik.php
index 7019cb36a4..c989ac838f 100644
--- a/core/Piwik.php
+++ b/core/Piwik.php
@@ -1480,6 +1480,11 @@ class Piwik
*/
static public function getPrettySizeFromBytes($size)
{
+ if ($size == 0)
+ {
+ return '0 M';
+ }
+
$bytes = array('','K','M','G','T');
foreach($bytes as $val)
{
diff --git a/core/PluginsFunctions/Sql.php b/core/PluginsFunctions/Sql.php
index f35a91102b..87021d3053 100644
--- a/core/PluginsFunctions/Sql.php
+++ b/core/PluginsFunctions/Sql.php
@@ -59,6 +59,42 @@ class Piwik_Sql
{
return self::getDb()->fetchOne($sql, $parameters);
}
+
+ static public function deleteAllRows( $table, $where, $maxRowsPerQuery, $parameters = array() )
+ {
+ $sql = "DELETE FROM $table $where LIMIT ".(int)$maxRowsPerQuery;
+
+ // delete rows w/ a limit
+ $totalRowsDeleted = 0;
+ do
+ {
+ $rowsDeleted = self::query($sql, $parameters)->rowCount();
+
+ $totalRowsDeleted += $rowsDeleted;
+ } while ($rowsDeleted >= $maxRowsPerQuery);
+
+ return $totalRowsDeleted;
+ }
+
+ static public function optimizeTables( $tables )
+ {
+ if (!is_array($tables))
+ {
+ $tables = array($tables);
+ }
+
+ return self::query("OPTIMIZE TABLE ".implode(',', $tables));
+ }
+
+ static public function dropTables( $tables )
+ {
+ if (!is_array($tables))
+ {
+ $tables = array($tables);
+ }
+
+ return self::query("DROP TABLE ".implode(',', $tables));
+ }
}
/**
@@ -125,3 +161,41 @@ function Piwik_FetchOne( $sqlQuery, $parameters = array())
{
return Piwik_Sql::fetchOne($sqlQuery, $parameters);
}
+
+/**
+ * Deletes all desired rows in a table, while using a limit. This function will execute a
+ * DELETE query until there are no more rows to delete.
+ *
+ * @param string $table The table to delete from.
+ * @param string $where The where clause of the query. Must include the WHERE keyword.
+ * @param int $maxRowsPerQuery The maximum number of rows to delete per DELETE query.
+ * @param array $parameters Parameters to bind in the query.
+ * @return int The total number of rows deleted.
+ */
+function Piwik_DeleteAllRows( $table, $where, $maxRowsPerQuery, $parameters = array() )
+{
+ return Piwik_Sql::deleteAllRows($table, $where, $maxRowsPerQuery, $parameters);
+}
+
+/**
+ * Runs an OPTIMIZE TABLE query on the supplied table or tables.
+ *
+ * @param string|array The name of the table to optimize or an array of tables to optimize.
+ * @return Zend_Db_Statement
+ */
+function Piwik_OptimizeTables( $tables )
+{
+ return Piwik_Sql::optimizeTables($tables);
+}
+
+/**
+ * Drops the supplied table or tables.
+ *
+ * @param string|array The name of the table to drop or an array of table names to drop.
+ * @return Zend_Db_Statement
+ */
+function Piwik_DropTables( $tables )
+{
+ return Piwik_Sql::dropTables($tables);
+}
+
diff --git a/core/ScheduledTask.php b/core/ScheduledTask.php
index 4f855cb495..b1e5ee63bc 100644
--- a/core/ScheduledTask.php
+++ b/core/ScheduledTask.php
@@ -18,6 +18,10 @@
*/
class Piwik_ScheduledTask
{
+ const LOW_PRIORITY = 2;
+ const NORMAL_PRIORITY = 1;
+ const HIGH_PRIORITY = 0;
+
/**
* Class name where the specified method is located
* @var string
@@ -35,12 +39,19 @@ class Piwik_ScheduledTask
* @var Piwik_ScheduledTime
*/
var $scheduledTime;
+
+ /**
+ * The priority of a task. Affects the order in which this task will be run.
+ * @var int
+ */
+ var $priority;
- function __construct( $_className, $_methodName, $_scheduledTime)
+ function __construct( $_className, $_methodName, $_scheduledTime, $_priority = self::NORMAL_PRIORITY )
{
$this->className = $_className;
$this->methodName = $_methodName;
$this->scheduledTime = $_scheduledTime;
+ $this->priority = $_priority;
}
/*
@@ -69,4 +80,15 @@ class Piwik_ScheduledTask
{
return $this->scheduledTime;
}
+
+ /**
+ * Returns the task priority. The priority will be an integer whose value is
+ * between Piwik_ScheduledTask::HIGH_PRIORITY and Piwik_ScheduledTask::LOW_PRIORITY.
+ *
+ * @return int
+ */
+ public function getPriority()
+ {
+ return $this->priority;
+ }
}
diff --git a/core/TaskScheduler.php b/core/TaskScheduler.php
index 280e94a99a..a4f06e812d 100644
--- a/core/TaskScheduler.php
+++ b/core/TaskScheduler.php
@@ -53,42 +53,54 @@ class Piwik_TaskScheduler
Piwik_PostEvent(self::GET_TASKS_EVENT, $tasks);
$return = array();
- // Loop through each task
- foreach ($tasks as $task)
+
+ // for every priority level, starting with the highest and concluding with the lowest
+ for ($priority = Piwik_ScheduledTask::HIGH_PRIORITY;
+ $priority != Piwik_ScheduledTask::LOW_PRIORITY;
+ ++$priority)
{
- $scheduledTime = $task->getScheduledTime();
- $className = $task->getClassName();
- $methodName = $task->getMethodName();
+ // Loop through each task
+ foreach ($tasks as $task)
+ {
+ // if the task does not have the current priority level, don't execute it yet
+ if ($task->getPriority() != $priority)
+ {
+ continue;
+ }
+
+ $scheduledTime = $task->getScheduledTime();
+ $className = $task->getClassName();
+ $methodName = $task->getMethodName();
- $fullyQualifiedMethodName = get_class($className) . '.' . $methodName;
+ $fullyQualifiedMethodName = get_class($className) . '.' . $methodName;
- /*
- * Task has to be executed if :
- * - it is the first time, ie. rescheduledTime is not set
- * - that task has already been executed and the current system time is greater than the
- * rescheduled time.
- */
- if ( !isset($timetable[$fullyQualifiedMethodName])
- || (isset($timetable[$fullyQualifiedMethodName])
- && time() >= $timetable[$fullyQualifiedMethodName])
- || $forceScheduledTasks)
- {
- // Updates the rescheduled time
- $timetable[$fullyQualifiedMethodName] = $scheduledTime->getRescheduledTime();
- Piwik_SetOption(self::TIMETABLE_OPTION_STRING, serialize($timetable));
+ /*
+ * Task has to be executed if :
+ * - it is the first time, ie. rescheduledTime is not set
+ * - that task has already been executed and the current system time is greater than the
+ * rescheduled time.
+ */
+ if ( !isset($timetable[$fullyQualifiedMethodName])
+ || (isset($timetable[$fullyQualifiedMethodName])
+ && time() >= $timetable[$fullyQualifiedMethodName])
+ || $forceScheduledTasks)
+ {
+ // Updates the rescheduled time
+ $timetable[$fullyQualifiedMethodName] = $scheduledTime->getRescheduledTime();
+ Piwik_SetOption(self::TIMETABLE_OPTION_STRING, serialize($timetable));
- self::$running = true;
- // Run the task
- try {
- $timer = new Piwik_Timer;
- call_user_func ( array($className,$methodName) );
- $message = $timer->__toString();
- } catch(Exception $e) {
- $message = 'ERROR: '.$e->getMessage();
+ self::$running = true;
+ // Run the task
+ try {
+ $timer = new Piwik_Timer;
+ call_user_func ( array($className,$methodName) );
+ $message = $timer->__toString();
+ } catch(Exception $e) {
+ $message = 'ERROR: '.$e->getMessage();
+ }
+ self::$running = false;
+ $return[] = array('task' => $fullyQualifiedMethodName, 'output' => $message);
}
- self::$running = false;
- $return[] = array('task' => $fullyQualifiedMethodName, 'output' => $message);
-
}
}
return $return;
diff --git a/core/ViewDataTable.php b/core/ViewDataTable.php
index 5efbd98a36..8ad1244fc3 100644
--- a/core/ViewDataTable.php
+++ b/core/ViewDataTable.php
@@ -1187,4 +1187,33 @@ abstract class Piwik_ViewDataTable
$this->queuedFilters[] = array($filterName, $parameters);
}
}
+
+ /**
+ * Returns true if it is likely that the data for this report has been purged and if the
+ * user should be told about that.
+ *
+ * In order for this function to return true, the following must also be true:
+ * - The current user must be the super user.
+ * - The data table for this report must either be empty or not have been fetched.
+ * - The period of this report is not a range.
+ * - The date of this report must be older than the delete_reports_older_than config option.
+ */
+ public function hasReportBeenPurged()
+ {
+ if ((is_null($this->dataTable) || $this->dataTable->getRowsCount() == 0)
+ && Piwik::isUserIsSuperUser()
+ && Piwik_Common::getRequestVar('period') != 'range')
+ {
+ $reportDate = Piwik_Date::factory(Piwik_Common::getRequestVar('date'));
+ $reportYear = $reportDate->toString('Y');
+ $reportMonth = $reportDate->toString('m');
+
+ if (Piwik_PrivacyManager::shouldReportBePurged($reportYear, $reportMonth))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/core/ViewDataTable/Cloud.php b/core/ViewDataTable/Cloud.php
index eafbcd2773..2410603346 100644
--- a/core/ViewDataTable/Cloud.php
+++ b/core/ViewDataTable/Cloud.php
@@ -120,6 +120,12 @@ class Piwik_ViewDataTable_Cloud extends Piwik_ViewDataTable
$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
$view->properties = $this->getViewProperties();
$view->reportDocumentation = $this->getReportDocumentation();
+
+ // if it's likely that the report data for this data table has been purged,
+ // set whether we should display a message to that effect.
+ $view->showReportDataWasPurgedMessage = $this->hasReportBeenPurged();
+ $view->deleteReportsOlderThan = Piwik_GetOption('delete_reports_older_than');
+
return $view;
}
}
diff --git a/core/ViewDataTable/GenerateGraphHTML.php b/core/ViewDataTable/GenerateGraphHTML.php
index 55e473c503..eaa61943af 100644
--- a/core/ViewDataTable/GenerateGraphHTML.php
+++ b/core/ViewDataTable/GenerateGraphHTML.php
@@ -128,6 +128,11 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable
$view->reportDocumentation = $this->getReportDocumentation();
+ // if it's likely that the report data for this data table has been purged,
+ // set whether we should display a message to that effect.
+ $view->showReportDataWasPurgedMessage = $this->hasReportBeenPurged();
+ $view->deleteReportsOlderThan = Piwik_GetOption('delete_reports_older_than');
+
return $view;
}
diff --git a/core/ViewDataTable/HtmlTable.php b/core/ViewDataTable/HtmlTable.php
index 1277ba29c5..b4bf9c42e1 100644
--- a/core/ViewDataTable/HtmlTable.php
+++ b/core/ViewDataTable/HtmlTable.php
@@ -117,6 +117,11 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
$view->columnDocumentation = $columnDocumentation;
$view->nbColumns = $nbColumns;
$view->defaultWhenColumnValueNotDefined = '-';
+
+ // if it's likely that the report data for this data table has been purged,
+ // set whether we should display a message to that effect.
+ $view->showReportDataWasPurgedMessage = $this->hasReportBeenPurged();
+ $view->deleteReportsOlderThan = Piwik_GetOption('delete_reports_older_than');
}
$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
$view->properties = $this->getViewProperties();
diff --git a/lang/be.php b/lang/be.php
index 27f973b073..b28b493299 100644
--- a/lang/be.php
+++ b/lang/be.php
@@ -377,13 +377,10 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Абярыце "Так", калі вы хочаце, каб Piwik не адсочваў поўны IP-адрас.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Выбраць, колькі байтаў IP-адрасоў наведвальнікаў павінны быць схаваныя.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s байт(ы) - напр., %s',
- 'PrivacyManager_DeleteLogSettings' => 'Выдаліць старыя запісы наведвальнікаў з базы дадзеных',
'PrivacyManager_DeleteLogInfo' => 'Запісы з наступнай табліцы будуць выдаленыя: %s',
'PrivacyManager_UseDeleteLog' => 'Рэгулярна выдаляць старыя запісы наведвальнікаў з базы дадзеных',
- 'PrivacyManager_DeleteLogDescription' => 'Вы можаце наладзіць Piwik аўтаматычна выдаляць старыя запісы наведвальнікаў з базы дадзеных, каб захаваць ваш памер базы дадзеных невялікім.',
'PrivacyManager_DeleteLogDescription2' => 'Калі вы ўключыце аўтаматычнае выдаленне запісаў, вы павінны пераканацца, што ўсе папярэднія штодзённыя справаздачы былі апрацаваны, каб пазбегнуць гублення дадзеных.',
'PrivacyManager_DeleteLogsOlderThan' => 'Выдаліць запісы старэй чым',
- 'PrivacyManager_DeleteLogInterval' => 'Выдаліць ​​старыя запісы кожны',
'PrivacyManager_DeleteMaxRows' => 'Максімальная колькасць радкоў для выдалення за адзін праход:',
'PrivacyManager_LastDelete' => 'Апошняе выдаленне было',
'PrivacyManager_NextDelete' => 'Наступнае запланавана выдаленне',
@@ -1153,8 +1150,8 @@ $translations = array(
'UserCountry_country_qa' => 'Катар',
'UserCountry_country_re' => 'Выспа Реюньон',
'UserCountry_country_ro' => 'Румынія',
- 'UserCountry_country_ru' => 'Расія',
'UserCountry_country_rs' => 'Сербія',
+ 'UserCountry_country_ru' => 'Расія',
'UserCountry_country_rw' => 'Руанда',
'UserCountry_country_sa' => 'Саудаўская Аравія',
'UserCountry_country_sb' => 'Саламонавы выспы',
diff --git a/lang/da.php b/lang/da.php
index a22f014912..c176c70f80 100644
--- a/lang/da.php
+++ b/lang/da.php
@@ -357,13 +357,10 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Vælg "Ja", hvis Piwik ikke skal spore fuldt kvalificerede IP-adresser.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Vælg hvor mange bytes af de besøgendes IP-adresser der skal maskeres.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s bytes - f.eks %s',
- 'PrivacyManager_DeleteLogSettings' => 'Slet gamle besøgs logfiler fra databasen',
'PrivacyManager_DeleteLogInfo' => 'Logfiler fra følgende tabeller vil blive slettet: %s',
'PrivacyManager_UseDeleteLog' => 'Slet regelmæssigt gamle logfiler fra databasen',
- 'PrivacyManager_DeleteLogDescription' => 'Piwik kan konfigureres til regelmæssigt at slette gamle besøgs logfiler, for at holde database størrelsen lille. Tidligere rapporter vil ikke blive slettet, kun besøgende, sider, rå konverterings logfiler vil blive slettet.',
'PrivacyManager_DeleteLogDescription2' => 'Når automatisk log sletning aktiveres, så sørg for, at alle tidligere daglige rapporter er blevet behandlet, således at ingen data går tabt.',
'PrivacyManager_DeleteLogsOlderThan' => 'Slet logfiler ældre end',
- 'PrivacyManager_DeleteLogInterval' => 'Slet gamle logfiler hver',
'PrivacyManager_DeleteMaxRows' => 'Maksimale antal rækker der slettes på én gang:',
'PrivacyManager_LastDelete' => 'Sidste sletningen var d.',
'PrivacyManager_NextDelete' => 'Næste planlagt sletning på',
@@ -1185,8 +1182,8 @@ Obs: nøglen udløber efter 24 timer.',
'UserCountry_country_qa' => 'Qatar',
'UserCountry_country_re' => 'Reunion',
'UserCountry_country_ro' => 'Rumænien',
- 'UserCountry_country_ru' => 'Rusland',
'UserCountry_country_rs' => 'Serbien',
+ 'UserCountry_country_ru' => 'Rusland',
'UserCountry_country_rw' => 'Rwanda',
'UserCountry_country_sa' => 'Saudi-Arabien',
'UserCountry_country_sb' => 'Salomonøerne',
diff --git a/lang/de.php b/lang/de.php
index 9ab1e499cb..dfafcfdda6 100644
--- a/lang/de.php
+++ b/lang/de.php
@@ -380,13 +380,10 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Wählen Sie "Ja", wenn Piwik nicht die komplette IP-Adresse speichern soll.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Wählen Sie aus, wieviele Bytes der Busucher-IP maskiert werden sollen.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s byte(s) - z.B. %s',
- 'PrivacyManager_DeleteLogSettings' => 'Alte Besucher-Logs aus der Datenbank entfernen',
'PrivacyManager_DeleteLogInfo' => 'Es werden Daten aus den folgenden Tabellen gelöscht: %s',
'PrivacyManager_UseDeleteLog' => 'Alte Besucher-Logs automatisch aus der Datenbank entfernen',
- 'PrivacyManager_DeleteLogDescription' => 'Sie können Piwik so einstellen, dass alte Besucherlogs regelmäßig gelöscht werden, um die Größe Ihrer Datenbank klein zu halten. Bereits berechnete Berichte werden nicht gelöscht, nur die Rohdaten von Besuchern, Seiten und Konversionen werden entfernt.',
'PrivacyManager_DeleteLogDescription2' => 'Wenn Sie das automatische Leeren von Logs aktivieren, müssen Sie sicherstellen, dass alle (Tages-)Berichte bereits berechnet wurden, um Datenverlust zu vermeiden.',
'PrivacyManager_DeleteLogsOlderThan' => 'Logs löschen, die älter sind als',
- 'PrivacyManager_DeleteLogInterval' => 'Logs löschen jeden',
'PrivacyManager_DeleteMaxRows' => 'Maximale Anzahl der Datensätze, die pro Durchlauf gelöscht werden dürfen:',
'PrivacyManager_LastDelete' => 'Letzter Löschvorgang war am',
'PrivacyManager_NextDelete' => 'Nächste Löschung geplant in',
@@ -1192,8 +1189,8 @@ $translations = array(
'UserCountry_country_qa' => 'Katar',
'UserCountry_country_re' => 'Reunion',
'UserCountry_country_ro' => 'Rumänien',
- 'UserCountry_country_ru' => 'Russische Förderation',
'UserCountry_country_rs' => 'Serbien',
+ 'UserCountry_country_ru' => 'Russische Förderation',
'UserCountry_country_rw' => 'Ruanda',
'UserCountry_country_sa' => 'Saudi Arabien',
'UserCountry_country_sb' => 'Salomonen',
diff --git a/lang/el.php b/lang/el.php
index 475747549c..a0da39f989 100644
--- a/lang/el.php
+++ b/lang/el.php
@@ -1,4 +1,4 @@
-<?php
+<?php
$translations = array(
'General_Locale' => 'el_GR.UTF-8',
'General_TranslatorName' => 'Jim Black www.jblack.info, Γεώργιος Τέλλος OnSite.Net VoIP & IT Solutions, Παναγιώτης Παπάζογλου Δρ. Δασολόγος-Περιβαλλοντολόγος',
@@ -385,13 +385,10 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Επιλέξτε «Ναι» αν θέλετε το Piwik να μην ανιχνεύει πλήρως ταυτοποιημένες διευθύνσεις IP.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Επιλέξτε πόσα bytes από τις διευθύνσεις IPs των επισκεπτών πρέπει να κρύβονται.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s byte(s) - π.χ.. %s',
- 'PrivacyManager_DeleteLogSettings' => 'Διαγραφή παλαιών καταγραφών επισκεπτών από την βάση δεδομένων',
'PrivacyManager_DeleteLogInfo' => 'Οι καταγραφές από τους ακόλουθους πίνακες θα διαγραφούν: %s',
'PrivacyManager_UseDeleteLog' => 'Τακτική διαγραφή παλαιών καταγραφών επισκεπτών από τη βάση δεδομένων',
- 'PrivacyManager_DeleteLogDescription' => 'Μπορείτε να ρυθμίσετε το Piwik να διαγράφει τακτικά τις παλαιές καταγραφές επισκεπτών για να διατηρείτε τη βάση δεδομένων σας σε μικρό μέγεθος. Οι ήδη καταχωρημένες αναφορές δεν θα διαγραφούν αλλά μόνο οι πρωτογενέίς καταγραφές επισκεπτών, σελίδων, μετατροπών.',
'PrivacyManager_DeleteLogDescription2' => 'Όταν ενεργοποιήσετε την αυτόματη διαγραφή καταγραφών, πρέπει να είστε σίγουροι ότι όλες οι προηγούμενες ημερήσιες αναφορές έχουν καταχωρηθεί για να μην χαθούν δεδομένα.',
'PrivacyManager_DeleteLogsOlderThan' => 'Διαγραφή καταγραφών παλαιοτέρων από',
- 'PrivacyManager_DeleteLogInterval' => 'Διαγραφή παλαιών καταγραφών κάθε',
'PrivacyManager_DeleteMaxRows' => 'Μέγιστος αριθμός εγγραφών για διαγραφή κάθε φορά:',
'PrivacyManager_DeleteMaxRowsNoLimit' => 'χωρίς περιορισμό',
'PrivacyManager_LastDelete' => 'Η τελευταία διαγραφή ήταν την',
@@ -1226,8 +1223,8 @@ $translations = array(
'UserCountry_country_qa' => 'Κατάρ',
'UserCountry_country_re' => 'Νήσος Ρεϋνιόν',
'UserCountry_country_ro' => 'Ρουμανία',
- 'UserCountry_country_ru' => 'Ρωσία',
'UserCountry_country_rs' => 'Σερβία',
+ 'UserCountry_country_ru' => 'Ρωσία',
'UserCountry_country_rw' => 'Ρουάντα',
'UserCountry_country_sa' => 'Σαουδική Αραβία',
'UserCountry_country_sb' => 'Νήσοι Σολωμώντα',
@@ -1516,4 +1513,4 @@ $translations = array(
'PDFReports_Pagination' => 'Σελίδα %s από %s',
'ImageGraph_PluginDescription' => 'Δημιουργία όμορφων στατικών εικόνων PNG Διαγραμμάτων για οποιαδήποτε αναφορά του Piwik.',
'ImageGraph_ColumnOrdinateMissing' => 'Η στήλη «%s» δεν βρέθηκε σε αυτή την αναφορά.',
-); \ No newline at end of file
+);
diff --git a/lang/en.php b/lang/en.php
index b46afa48d8..729923f297 100644
--- a/lang/en.php
+++ b/lang/en.php
@@ -190,7 +190,9 @@ $translations = array(
'General_RequiresFlash' => 'Displaying Graphs in Piwik requires Flash',
'General_GraphHelp' => 'More information about displaying graphs in Piwik.',
'General_NoDataForGraph' => 'No data for this graph.',
+ 'General_DataForThisGraphHasBeenPurged' => 'The data for this graph is more than %s months old and has been purged.',
'General_NoDataForTagCloud' => 'No data for this tag cloud.',
+ 'General_DataForThisTagCloudHasBeenPurged' => 'The data for this tag cloud is more than %s months old and has been purged.',
'General_DisplaySimpleTable' => 'Display simple table',
'General_DisplayTableWithMoreMetrics' => 'Display a table with more metrics',
'General_DisplayTableWithGoalMetrics' => 'Display a table with Goals metrics',
@@ -248,6 +250,10 @@ $translations = array(
'General_Daily' => 'Daily',
'General_Weekly' => 'Weekly',
'General_Monthly' => 'Monthly',
+ 'General_DailyReports' => 'Daily reports',
+ 'General_WeeklyReports' => 'Weekly reports',
+ 'General_MonthlyReports' => 'Monthly reports',
+ 'General_YearlyReports' => 'Yearly reports',
'General_ConfigFileIsNotWritable' => 'The Piwik configuration file %s is not writable, some of your changes might not be saved. %s Please change permissions of the config file to make it writable.',
'General_ExceptionDatabaseVersion' => 'Your %1$s version is %2$s but Piwik requires at least %3$s.',
'General_ExceptionIncompatibleClientServerVersions' => 'Your %1$s client version is %2$s which is incompatible with server version %3$s.',
@@ -387,24 +393,41 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Select "Yes" if you want Piwik not to track fully qualified IP-Addresses.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Select how many bytes of the visitors\' IPs should be masked.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s byte(s) - e.g. %s',
- 'PrivacyManager_DeleteLogSettings' => 'Delete old visitor logs from database',
+ 'PrivacyManager_DeleteDataSettings' => 'Delete old visitor logs and reports from database',
'PrivacyManager_DeleteLogInfo' => 'Logs from the following tables will be deleted: %s',
'PrivacyManager_UseDeleteLog' => 'Regularly delete old visitor logs from the database',
- 'PrivacyManager_DeleteLogDescription' => 'You can configure Piwik to regularly delete old visitor logs to keep your database size small. Pre-processed reports will not be deleted, only visitor, pages, conversions raw logs will be deleted.',
+ 'PrivacyManager_DeleteDataDescription' => 'You can configure Piwik to regularly delete old visitor logs and/or processed reports to keep your database size small. If desired, pre-processed reports will not be deleted, only visit, pageview and conversion log data will be deleted. Or, the pre-processed reports can be deleted and the log data can be kept.',
'PrivacyManager_DeleteLogDescription2' => 'When you enable automatic log deletion, you must ensure that all previous daily reports have been processed, so that no data is lost.',
'PrivacyManager_DeleteLogsOlderThan' => 'Delete logs older than',
- 'PrivacyManager_DeleteLogInterval' => 'Delete old logs every',
+ 'PrivacyManager_DeleteDataInterval' => 'Delete old data every',
'PrivacyManager_DeleteMaxRows' => 'Maximum number of rows to delete in one run:',
'PrivacyManager_DeleteMaxRowsNoLimit' => 'no limit',
'PrivacyManager_LastDelete' => 'Last deletion was on',
'PrivacyManager_NextDelete' => 'Next scheduled deletion in',
'PrivacyManager_ClickHereSettings' => 'Click here to access the %s settings.',
'PrivacyManager_LeastDaysInput' => 'Please specify a number of days greater than %s.',
+ 'PrivacyManager_LeastMonthsInput' => 'Please specify a number of months greater than %s.',
+ 'PrivacyManager_UseDeleteReports' => 'Regularly delete old reports from the database',
+ 'PrivacyManager_DeleteReportsOlderThan' => 'Delete reports older than',
+ 'PrivacyManager_DeleteReportsInfo' => 'If enabled, old reports will be deleted. If you have not enabled log data deletion, it\'s possible for these old reports to be recreated. If you have enabled it, the data will be permanently lost.',
+ 'PrivacyManager_DeleteReportsDetailedInfo' => 'Data from numeric archive tables and blob archive tables will be deleted.',
+ 'PrivacyManager_DeleteSchedulingSettings' => 'Scheduling settings',
+ 'PrivacyManager_ReportsDataSavedEstimate' => 'Database size',
+ 'PrivacyManager_KeepBasicMetrics' => 'Keep basic metrics (visits, page views, bounce rate, goal conversions, ecommerce conversions, etc.)',
+ 'PrivacyManager_KeepDataFor' => 'Keep all data for:',
+ 'PrivacyManager_DeleteLogsConfirm' => 'You are about to enable log data deletion. If old log data is removed, and reports haven\'t already been created, you will not be able to see past analytics data. Are you sure you want to do this?',
+ 'PrivacyManager_DeleteReportsConfirm' => 'You are about to enable report data deletion. If old reports are removed, you will have to re-process them in order view them. Are you sure you want to do this?',
+ 'PrivacyManager_DeleteBothConfirm' => 'You are about to enable both log data deletion & report data deletion. This will permanently remove your ability to view old analytics data. Are you sure you want to do this?',
+ 'PrivacyManager_PurgeNow' => 'Purge DB Now',
+ 'PrivacyManager_PurgingData' => 'Purging data...',
+ 'PrivacyManager_SaveSettingsBeforePurge' => 'You have changed the data deletion settings. Please save them before starting a purge.',
+ 'PrivacyManager_PurgeNowConfirm' => 'You are about to permanently delete data from your database. Are you sure you want to continue?',
'CoreHome_PluginDescription' => 'Web Analytics Reports Structure.',
'CoreHome_WebAnalyticsReports' => 'Web Analytics Reports',
'CoreHome_NoPrivilegesAskPiwikAdmin' => 'You are logged in as \'%s\' but it seems you don\'t have any permission set in Piwik. %s Ask your Piwik administrator (click to email)%s to give you \'view\' access to a website.',
'CoreHome_JavascriptDisabled' => 'JavaScript must be enabled in order for you to use Piwik in standard view.<br />However, it seems JavaScript is either disabled or not supported by your browser.<br />To use standard view, enable JavaScript by changing your browser options, then %1$stry again%2$s.<br />',
'CoreHome_ThereIsNoDataForThisReport' => 'There is no data for this report.',
+ 'CoreHome_DataForThisReportHasBeenPurged' => 'The data for this report is more than %s months old and has been purged.',
'CoreHome_CategoryNoData' => 'No data in this category. Try to "Include all population".',
'CoreHome_ShowJSCode' => 'Show the JavaScript code to insert',
'CoreHome_ConfigureView' => 'Configure view',
diff --git a/lang/es.php b/lang/es.php
index b647b34828..f8894d03fc 100644
--- a/lang/es.php
+++ b/lang/es.php
@@ -359,13 +359,10 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Seleccione "Si" si que Piwik no registre direcciones IP completas.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Seleccione cuantos bytes de las direcciones IP de los visitantes deben ser ocultados.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s byte(s) - ej. %s',
- 'PrivacyManager_DeleteLogSettings' => 'Eliminar registros antiguos de visitantes de la base de datos',
'PrivacyManager_DeleteLogInfo' => 'Registros de las siguientes tablas serán eliminados: %s',
'PrivacyManager_UseDeleteLog' => 'Eliminar registros antiguos de la base de datos regularmente',
- 'PrivacyManager_DeleteLogDescription' => 'Usted puede configurar Piwik para eliminar regularmente registros antiguos de visitantes para mantener el tamaño de la base de datos pequeño. Los reporte previamente procesados no serán eliminados, solamente serán eliminados registros de visitantes, páginas y conversiones.',
'PrivacyManager_DeleteLogDescription2' => 'Cuando habilite la eliminación automática de registros, debe comprobar que todos los reportes diarios previos han sido procesados, de modo que ningún dato es perdido.',
'PrivacyManager_DeleteLogsOlderThan' => 'Eliminar registros más antiguos que',
- 'PrivacyManager_DeleteLogInterval' => 'Eliminar registros antiguos cada',
'PrivacyManager_DeleteMaxRows' => 'Número máximo de filas que serán eliminadas por cada ejecución',
'PrivacyManager_LastDelete' => 'La última eliminación fue en',
'PrivacyManager_NextDelete' => 'La próxima eliminación programada es en',
@@ -1123,8 +1120,8 @@ $translations = array(
'UserCountry_country_qa' => 'Qatar',
'UserCountry_country_re' => 'Isla Reunión',
'UserCountry_country_ro' => 'Rumanía',
- 'UserCountry_country_ru' => 'Rusia',
'UserCountry_country_rs' => 'Serbia',
+ 'UserCountry_country_ru' => 'Rusia',
'UserCountry_country_rw' => 'Ruanda',
'UserCountry_country_sa' => 'Arabia Saudí',
'UserCountry_country_sb' => 'Islas Salomón',
diff --git a/lang/fr.php b/lang/fr.php
index c5ef58a415..716c842401 100644
--- a/lang/fr.php
+++ b/lang/fr.php
@@ -381,13 +381,10 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Sélectionnez "Oui" si vous voulez que Piwik ne trace pas les adresses IP complètes.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Sélectionnez combien de bytes de l\'adresse IP du visiteur doivent être masqués.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s byte(s) - ex %s',
- 'PrivacyManager_DeleteLogSettings' => 'Supprimer les anciens logs de visiteurs de la base de données.',
'PrivacyManager_DeleteLogInfo' => 'Les enregistrements des tables suivantes vont être supprimés: %s',
'PrivacyManager_UseDeleteLog' => 'Supprimer régulièrement les anciens logs de la base de données.',
- 'PrivacyManager_DeleteLogDescription' => 'Vous pouvez configurer Piwik pour qu\'il supprime régulièrement les logs des anciens visiteurs afin de garder une base de données de petite taille. Les rapports déjà compilés ne seront pas supprimés, seulement les logs bruts des visiteurs, pages et logs de conversions seront supprimés',
'PrivacyManager_DeleteLogDescription2' => 'Quand vous activez la suppression automatique des logs, vous devez vous assurer que tous les rapports précédents ont bien été compilés, de cette manière aucune donnée n\'est perdue.',
'PrivacyManager_DeleteLogsOlderThan' => 'Supprimer les logs plus anciens que',
- 'PrivacyManager_DeleteLogInterval' => 'Supprimer les anciens logs tous les',
'PrivacyManager_DeleteMaxRows' => 'Nombre maximal de lignes à supprimer à la fois:',
'PrivacyManager_DeleteMaxRowsNoLimit' => 'aucune limite',
'PrivacyManager_LastDelete' => 'La dernière suppression était le',
diff --git a/lang/id.php b/lang/id.php
index e8cc868811..d2315607a7 100644
--- a/lang/id.php
+++ b/lang/id.php
@@ -356,13 +356,10 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Pilih "Ya" jika Anda ingin Piwik tidak melacak Alamat IP sepenuhnya.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Pilih berapa banyak bita dari IP pengunjung harus ditutupi.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s bita - misalnya %s',
- 'PrivacyManager_DeleteLogSettings' => 'Hapus catatan pengunjung lama dari basis data',
'PrivacyManager_DeleteLogInfo' => 'Catatan tabel berikut akan dihapus: %s',
'PrivacyManager_UseDeleteLog' => 'Hapus teratur catatan pengunjung lama dari basis data',
- 'PrivacyManager_DeleteLogDescription' => 'Anda dapat mengkonfigurasi Piwik untuk secara teratur menghapus catatan pengunjung lama untuk menjaga ukuran basis data Anda tetap kecil. Laporan yang belum diolah tidak akan dihapus, hanya pengunjung, halaman, catatan konversi mentah akan dihapus.',
'PrivacyManager_DeleteLogDescription2' => 'Ketika Anda mengaktifkan catatan penghapusan otomatis, Anda harus memastikan bahwa semua laporan harian sebelumnya telah diproses, sehingga tidak ada data yang hilang.',
'PrivacyManager_DeleteLogsOlderThan' => 'Hapus catatan yang lebih lama dari',
- 'PrivacyManager_DeleteLogInterval' => 'Hapus catatan setiap',
'PrivacyManager_DeleteMaxRows' => 'Jumlah maksimum baris yang dihapus dalam sekali tindakan:',
'PrivacyManager_LastDelete' => 'Penghapusan terakhir di',
'PrivacyManager_NextDelete' => 'Jadwal penghapusan selanjutnya di',
@@ -1171,8 +1168,8 @@ Catatan: kepingan ini akan kedaluwarsa dalam 24 jam.',
'UserCountry_country_qa' => 'Qatar',
'UserCountry_country_re' => 'Pulau Reunion',
'UserCountry_country_ro' => 'Romania',
- 'UserCountry_country_ru' => 'Federasi Russian',
'UserCountry_country_rs' => 'Republik Serbia',
+ 'UserCountry_country_ru' => 'Federasi Russian',
'UserCountry_country_rw' => 'Rwanda',
'UserCountry_country_sa' => 'Arab Saudi',
'UserCountry_country_sb' => 'Kepulauan Solomon',
diff --git a/lang/it.php b/lang/it.php
index 1ff76ae31d..56c8dc780a 100644
--- a/lang/it.php
+++ b/lang/it.php
@@ -361,11 +361,9 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Seleziona "Si" se vuoi che Piwik non mostri gli indirizzi IP completi dei visitatori.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Seleziona quanti byte degli indirizzi IP dei visitatori devono essere nascosti.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s byte - e.s. %s',
- 'PrivacyManager_DeleteLogSettings' => 'Cancella i vecchi log visite dal database',
'PrivacyManager_DeleteLogInfo' => 'I log delle seguenti tabelle saranno cancellati: %s',
'PrivacyManager_UseDeleteLog' => 'Cancella regolarmente i vecchi log delle visite dal database',
'PrivacyManager_DeleteLogsOlderThan' => 'Cancella log più vecchi di',
- 'PrivacyManager_DeleteLogInterval' => 'Cancella log ogni',
'PrivacyManager_DeleteMaxRows' => 'Numero massimo di righe da cancellare in un passaggio:',
'PrivacyManager_LastDelete' => 'Ultima cancellazione è stata il',
'PrivacyManager_NextDelete' => 'Prossima cancellazione programmata per il',
@@ -1096,8 +1094,8 @@ $translations = array(
'UserCountry_country_qa' => 'Qatar',
'UserCountry_country_re' => 'Réunion',
'UserCountry_country_ro' => 'Romania',
- 'UserCountry_country_ru' => 'Russia',
'UserCountry_country_rs' => 'Serbia',
+ 'UserCountry_country_ru' => 'Russia',
'UserCountry_country_rw' => 'Ruanda',
'UserCountry_country_sa' => 'Arabia Saudita',
'UserCountry_country_sb' => 'Isole Salomone',
diff --git a/lang/lt.php b/lang/lt.php
index 9287e787ab..c53a1a51e8 100644
--- a/lang/lt.php
+++ b/lang/lt.php
@@ -292,9 +292,7 @@ $translations = array(
'PrivacyManager_TeaserHeadline' => 'Privatumo nustatymai',
'PrivacyManager_MenuPrivacySettings' => 'Privatumas',
'PrivacyManager_UseAnonymizeIp' => 'Paslėpti lankytojų IP adresus',
- 'PrivacyManager_DeleteLogSettings' => 'Ištrinti senus apsilankymų įrašus duombazėje',
'PrivacyManager_DeleteLogsOlderThan' => 'Ištrinti įrašus senesnius nei',
- 'PrivacyManager_DeleteLogInterval' => 'Ištrinti senus įrašus kas',
'PrivacyManager_DeleteMaxRows' => 'Maksimalus vienu metu trinamų eilučių kiekis:',
'PrivacyManager_LastDelete' => 'Paskutinis išvalymas atliktas',
'PrivacyManager_NextDelete' => 'Kitas suplanuotas išvalymas',
@@ -971,8 +969,8 @@ $translations = array(
'UserCountry_country_qa' => 'Qatar',
'UserCountry_country_re' => 'Reunion Island',
'UserCountry_country_ro' => 'Romania',
- 'UserCountry_country_ru' => 'Rusija',
'UserCountry_country_rs' => 'Serbia',
+ 'UserCountry_country_ru' => 'Rusija',
'UserCountry_country_rw' => 'Rwanda',
'UserCountry_country_sa' => 'Saudi Arabia',
'UserCountry_country_sb' => 'Solomon Islands',
diff --git a/lang/lv.php b/lang/lv.php
index fa1cd3906c..aec3068a9d 100644
--- a/lang/lv.php
+++ b/lang/lv.php
@@ -333,11 +333,9 @@ $translations = array(
'PrivacyManager_TeaserHeadline' => 'Privātuma iestatījumi',
'PrivacyManager_MenuPrivacySettings' => 'Privātums',
'PrivacyManager_UseAnonymizeIp' => 'Anonimizēt apmeklētāju IP adreses',
- 'PrivacyManager_DeleteLogSettings' => 'No datubāzes dzēst vecos apmeklētāju žurnālus',
'PrivacyManager_DeleteLogInfo' => 'Tiks dzēsti žurnāli no sekojošām tabulām: %s',
'PrivacyManager_UseDeleteLog' => 'Regulāri dzēst no datubāzes vecus apmeklētāju žurnālus',
'PrivacyManager_DeleteLogsOlderThan' => 'Dzēst vecākus žurnālus par',
- 'PrivacyManager_DeleteLogInterval' => 'Dzēst vecos žurnālus katru',
'PrivacyManager_DeleteMaxRows' => 'Maksimālais rindu skaits ko dzēst vienā reizē:',
'PrivacyManager_LastDelete' => 'Pēdējā dzēšana notika',
'PrivacyManager_NextDelete' => 'Nākošā dzēšana paredzēta',
@@ -987,8 +985,8 @@ $translations = array(
'UserCountry_country_qa' => 'Katara',
'UserCountry_country_re' => 'Reinjona',
'UserCountry_country_ro' => 'Rumānija',
- 'UserCountry_country_ru' => 'Krievijas Federācija',
'UserCountry_country_rs' => 'Serbija',
+ 'UserCountry_country_ru' => 'Krievijas Federācija',
'UserCountry_country_rw' => 'Ruanda',
'UserCountry_country_sa' => 'Saūda Arābija',
'UserCountry_country_sb' => 'Solomona salas',
diff --git a/lang/pl.php b/lang/pl.php
index ffafb5d4ef..3cf28fdeee 100644
--- a/lang/pl.php
+++ b/lang/pl.php
@@ -296,13 +296,10 @@ $translations = array(
'PrivacyManager_UseAnonymizeIp' => 'Anonimizacja odwiedzających\' adres IP',
'PrivacyManager_AnonymizeIpDescription' => 'Wybierz "Tak" jeśli chcesz aby nie śledzić w pełni wykwalifikowanych adresów IP.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Wybierz ile bajtów z odwiedzających\' adresów IP powinny być zamaskowane.',
- 'PrivacyManager_DeleteLogSettings' => 'Usuń stare logi odwiedzających z bazy danych',
'PrivacyManager_DeleteLogInfo' => 'Logi z poniższych tabel zostaną usunięte: %s',
'PrivacyManager_UseDeleteLog' => 'Regularnie usuwanie starych logów odwiedzających z bazy danych',
- 'PrivacyManager_DeleteLogDescription' => 'Możesz ustawić regularne usuwanie starych logiów odwiedzających, aby utrzymać mały rozmiar bazy danych. Wstępnie przetworzone raporty nie zostaną usunięte, tylko odwiedzających strony oraz konwersje raw zostaną usunięte.',
'PrivacyManager_DeleteLogDescription2' => 'Po włączeniu automatycznego usuwania logów należy się upewnić, że wszystkie poprzednie raporty dzienne zostały przetworzone, tak że żadne dane nie zostaną utracone.',
'PrivacyManager_DeleteLogsOlderThan' => 'Usuń logi starsze niż',
- 'PrivacyManager_DeleteLogInterval' => 'Usuń stare logi',
'PrivacyManager_DeleteMaxRows' => 'Maksymalna liczba wierszy, aby usunąć w jednym przebiegu:',
'PrivacyManager_DeleteMaxRowsNoLimit' => 'bez limitu',
'PrivacyManager_LastDelete' => 'Ostatnio był usunięte',
diff --git a/lang/pt.php b/lang/pt.php
index 4e231741a0..c5e8373942 100644
--- a/lang/pt.php
+++ b/lang/pt.php
@@ -376,13 +376,10 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Selecione "Sim" para o Piwik não rastrear totalmente endereços IP qualificados.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Selecione quantos bytes dos IPs dos visitantes devem ser mascarados.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s byte(s) - por exemplo %s',
- 'PrivacyManager_DeleteLogSettings' => 'Apagar logs de antigos visitantes da base de dados',
'PrivacyManager_DeleteLogInfo' => 'Logs das seguintes tabelas serão apagados: %s',
'PrivacyManager_UseDeleteLog' => 'Apagar logs de antigos visitantes da base de dados regularmente.',
- 'PrivacyManager_DeleteLogDescription' => 'Você pode configurar o Piwik para regularmente excluir logs antigos de visitantes para manter o tamanho da base de dados pequeno. Relatórios pré-processados ​​não serão eliminados, apenas visitantes, páginas e logs de conversões serão apagados.',
'PrivacyManager_DeleteLogDescription2' => 'Quando você activa a ​​eliminação automática de logs, você deve garantir que todos os relatórios diários anteriores tenham sido processados​​, de modo que nenhuns dados sejam perdidos.',
'PrivacyManager_DeleteLogsOlderThan' => 'Apagar logs mais antigos que',
- 'PrivacyManager_DeleteLogInterval' => 'Apagar logs antigos todos os',
'PrivacyManager_DeleteMaxRows' => 'Número máximo de linhas para apagar de uma vez:',
'PrivacyManager_LastDelete' => 'Última eliminação foi em',
'PrivacyManager_NextDelete' => 'Próxima eliminação agendada em',
@@ -1167,8 +1164,8 @@ $translations = array(
'UserCountry_country_qa' => 'Catar',
'UserCountry_country_re' => 'Ilha Reunião',
'UserCountry_country_ro' => 'Roménia',
- 'UserCountry_country_ru' => 'Rússia',
'UserCountry_country_rs' => 'Sérvia',
+ 'UserCountry_country_ru' => 'Rússia',
'UserCountry_country_rw' => 'Ruanda',
'UserCountry_country_sa' => 'Arábia Saudita',
'UserCountry_country_sb' => 'Ilhas Solomon',
diff --git a/lang/ru.php b/lang/ru.php
index 90f4e3e9f4..990d72d309 100644
--- a/lang/ru.php
+++ b/lang/ru.php
@@ -365,7 +365,6 @@ $translations = array(
'PrivacyManager_PluginDescription' => 'Настройки Piwik для его соответствия текущему законодательству вашей страны.',
'PrivacyManager_UseAnonymizeIp' => 'Скрытие IP-адреса посетителей',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Выберите, какое число байт IP-адреса посетителя должно быть скрыто.',
- 'PrivacyManager_DeleteLogSettings' => 'Удаление старых логов посещений из базы данных',
'PrivacyManager_NextDelete' => 'Следующее удаление по расписанию',
'CoreHome_PluginDescription' => 'Структура отчетов веб-аналитики.',
'CoreHome_WebAnalyticsReports' => 'Отчеты веб-аналитики',
@@ -1097,8 +1096,8 @@ $translations = array(
'UserCountry_country_qa' => 'Катар',
'UserCountry_country_re' => 'Остров Реюньон',
'UserCountry_country_ro' => 'Румыния',
- 'UserCountry_country_ru' => 'Россия',
'UserCountry_country_rs' => 'Сербия',
+ 'UserCountry_country_ru' => 'Россия',
'UserCountry_country_rw' => 'Руанда',
'UserCountry_country_sa' => 'Саудовская Аравия',
'UserCountry_country_sb' => 'Соломоновы острова',
diff --git a/lang/sq.php b/lang/sq.php
index ad73f79818..6c56f9bee9 100644
--- a/lang/sq.php
+++ b/lang/sq.php
@@ -386,13 +386,10 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Përzgjidhni "Po" nëse doni që Piwik-u të mos gjurmojë adresa IP të përcaktuara qartë.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Përzgjidhni sa bajte të maskohen te IP-ja e vizitorit.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s bajt(e) - p.sh. %s',
- 'PrivacyManager_DeleteLogSettings' => 'Fshiji te baza e të dhënave regjistrimet e vjetra të përdoruesve',
'PrivacyManager_DeleteLogInfo' => 'Regjistrimet nga tabelat vijuese do të fshihen: %s',
'PrivacyManager_UseDeleteLog' => 'Fshiji rregullisht te baza e të dhënave regjistrimet e vjetra të përdoruesve',
- 'PrivacyManager_DeleteLogDescription' => 'Mund ta formësoni Piwik-un të fshijë rregullisht regjistrime të vjetra vizitorësh për ta mbajtuar të kursyer bazën tuaj të të dhënave. Raportet e parapërgatitur nuk do të fshihen, do të fshihen vetëm vizitorët, faqet, dhe regjistrimet bruto për shndërrimet.',
'PrivacyManager_DeleteLogDescription2' => 'Kur aktivizoni fshirjen e vetvetishme të regjistrimeve, duhet të siguroheni që janë përpunuar krejt raportet e ditës së mëparshme, që të mos humbni të dhëna.',
'PrivacyManager_DeleteLogsOlderThan' => 'Fshi regjistrime më të vjetër se',
- 'PrivacyManager_DeleteLogInterval' => 'Regjistrimet fshiji çdo',
'PrivacyManager_DeleteMaxRows' => 'Numër maksimum rreshtash për t’u fshirë njëherazi:',
'PrivacyManager_DeleteMaxRowsNoLimit' => 'pa kufi',
'PrivacyManager_LastDelete' => 'Fshirja e fundit u krye më',
diff --git a/lang/sv.php b/lang/sv.php
index e0dff8e02e..4a6d4467fe 100644
--- a/lang/sv.php
+++ b/lang/sv.php
@@ -374,13 +374,10 @@ $translations = array(
'PrivacyManager_AnonymizeIpDescription' => 'Välj "Ja" om du vill att Piwik inte ska spåra fullständiga IP-adresser.',
'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'Välj hur många bytes av besökares IP-adresser som ska döljas.',
'PrivacyManager_AnonymizeIpMaskLength' => '%s byte(s) - t.ex. %s',
- 'PrivacyManager_DeleteLogSettings' => 'Ta bort gamla besöksloggar från databasen',
'PrivacyManager_DeleteLogInfo' => 'Loggar från följande tabeller kommer att tas bort: %s',
'PrivacyManager_UseDeleteLog' => 'Ta regelbundet bort gamla besöksloggar från databasen',
- 'PrivacyManager_DeleteLogDescription' => 'Du kan konfigurera Piwik att regelbundet ta bort gamla besöksloggar för att minimera storleken på databasen. Förbearbetade rapporter kommer inte att raderas, endast loggar för besökare, sidor och konverteringar kommer att tas bort.',
'PrivacyManager_DeleteLogDescription2' => 'När du aktiverar automatisk radering av loggar, så måste du se till att alla tidigare dagliga rapporter har behandlats så att inga data går förlorade.',
'PrivacyManager_DeleteLogsOlderThan' => 'Ta bort loggfiler äldre än',
- 'PrivacyManager_DeleteLogInterval' => 'Ta bort loggfiler varje',
'PrivacyManager_DeleteMaxRows' => 'Maximalt antal rader som ska tas bort under en körning:',
'PrivacyManager_LastDelete' => 'Senast borttaget',
'PrivacyManager_NextDelete' => 'Nästa schemalagda borttagning',
@@ -1180,8 +1177,8 @@ $translations = array(
'UserCountry_country_qa' => 'Qatar',
'UserCountry_country_re' => 'Reunion Island',
'UserCountry_country_ro' => 'Rumänien',
- 'UserCountry_country_ru' => 'Ryssland',
'UserCountry_country_rs' => 'Serbien',
+ 'UserCountry_country_ru' => 'Ryssland',
'UserCountry_country_rw' => 'Rwanda',
'UserCountry_country_sa' => 'Saudiarabien',
'UserCountry_country_sb' => 'Salomonöarna',
diff --git a/plugins/CoreAdminHome/CoreAdminHome.php b/plugins/CoreAdminHome/CoreAdminHome.php
index acdcf681ca..688d745fdd 100644
--- a/plugins/CoreAdminHome/CoreAdminHome.php
+++ b/plugins/CoreAdminHome/CoreAdminHome.php
@@ -39,9 +39,13 @@ class Piwik_CoreAdminHome extends Piwik_Plugin
function getScheduledTasks ( $notification )
{
$tasks = &$notification->getNotificationObject();
+
+ // low priority since tables should be optimized after they are modified
+ $priority = Piwik_ScheduledTask::LOW_PRIORITY;
$optimizeArchiveTableTask = new Piwik_ScheduledTask ( $this,
'optimizeArchiveTable',
- new Piwik_ScheduledTime_Daily() );
+ new Piwik_ScheduledTime_Daily(),
+ $priority );
$tasks[] = $optimizeArchiveTableTask;
}
@@ -84,8 +88,7 @@ class Piwik_CoreAdminHome extends Piwik_Plugin
{
return;
}
- $query = "OPTIMIZE TABLE " . implode(",", $archiveTables);
- Piwik_Query( $query );
+ Piwik_OptimizeTables($archiveTables);
}
private function isArchiveTable ( $tableName )
diff --git a/plugins/CoreAdminHome/templates/generalSettings.tpl b/plugins/CoreAdminHome/templates/generalSettings.tpl
index 20d54ae28f..e11c6f2669 100644
--- a/plugins/CoreAdminHome/templates/generalSettings.tpl
+++ b/plugins/CoreAdminHome/templates/generalSettings.tpl
@@ -162,10 +162,10 @@
<input type="submit" value="{'General_Save'|translate}" id="generalSettingsSubmit" class="submit" />
<br /><br />
-{capture assign=clickDeleteLogSettings}{'PrivacyManager_DeleteLogSettings'|translate}{/capture}
-<h2>{'PrivacyManager_DeleteLogSettings'|translate}</h2>
+{capture assign=clickDeleteLogSettings}{'PrivacyManager_DeleteDataSettings'|translate}{/capture}
+<h2>{'PrivacyManager_DeleteDataSettings'|translate}</h2>
<p>
- {'PrivacyManager_DeleteLogDescription'|translate}
+ {'PrivacyManager_DeleteDataDescription'|translate}
<br/>
<a href='{url module="PrivacyManager" action="privacySettings"}#deleteLogsAnchor'>
{'PrivacyManager_ClickHereSettings'|translate:"'$clickDeleteLogSettings'"}
diff --git a/plugins/CoreHome/templates/cloud.tpl b/plugins/CoreHome/templates/cloud.tpl
index dc9d630183..f6be9beaf5 100644
--- a/plugins/CoreHome/templates/cloud.tpl
+++ b/plugins/CoreHome/templates/cloud.tpl
@@ -4,7 +4,11 @@
{/if}
<div class="tagCloud">
{if count($cloudValues) == 0}
+ {if $showReportDataWasPurgedMessage}
+ <div class="pk-emptyDataTable">{'General_DataForThisTagCloudHasBeenPurged'|translate:$deleteReportsOlderThan}</div>
+ {else}
<div class="pk-emptyDataTable">{'General_NoDataForTagCloud'|translate}</div>
+ {/if}
{else}
{foreach from=$cloudValues key=word item=value}
<span title="{$value.word} ({$value.value} {$columnTranslation})" class="word size{$value.size} {* we strike tags with 0 hits *} {if $value.value == 0}valueIsZero{/if}">
diff --git a/plugins/CoreHome/templates/datatable.tpl b/plugins/CoreHome/templates/datatable.tpl
index 0a7a20be61..235e8bcc30 100644
--- a/plugins/CoreHome/templates/datatable.tpl
+++ b/plugins/CoreHome/templates/datatable.tpl
@@ -7,7 +7,11 @@
{$arrayDataTable.message}
{else}
{if count($arrayDataTable) == 0}
- <div class="pk-emptyDataTable">{'CoreHome_ThereIsNoDataForThisReport'|translate}</div>
+ {if $showReportDataWasPurgedMessage}
+ <div class="pk-emptyDataTable">{'CoreHome_DataForThisReportHasBeenPurged'|translate:$deleteReportsOlderThan}</div>
+ {else}
+ <div class="pk-emptyDataTable">{'CoreHome_ThereIsNoDataForThisReport'|translate}</div>
+ {/if}
{else}
<a name="{$properties.uniqueId}"></a>
<table cellspacing="0" class="dataTable">
diff --git a/plugins/CoreHome/templates/graph.tpl b/plugins/CoreHome/templates/graph.tpl
index 2f3dc6156f..903a3e4916 100644
--- a/plugins/CoreHome/templates/graph.tpl
+++ b/plugins/CoreHome/templates/graph.tpl
@@ -33,7 +33,11 @@
{else}
<div><div id="{$chartDivId}" class="pk-emptyGraph">
+ {if $showReportDataWasPurgedMessage}
+ {'General_DataForThisGraphHasBeenPurged'|translate:$deleteReportsOlderThan}
+ {else}
{'General_NoDataForGraph'|translate}
+ {/if}
</div></div>
{/if}
@@ -44,4 +48,4 @@
{/if}
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/plugins/DBStats/API.php b/plugins/DBStats/API.php
index 7ba5ab49ed..eb35cf86d5 100644
--- a/plugins/DBStats/API.php
+++ b/plugins/DBStats/API.php
@@ -82,18 +82,38 @@ class Piwik_DBStats_API
return $tables[0][$field];
}
}
-
- public function getAllTablesStatus()
+
+ /**
+ * Gets the result of a SHOW TABLE STATUS query for every table in the DB.
+ *
+ * @return array The table information.
+ */
+ public function getAllTablesStatus()
{
Piwik::checkUserIsSuperUser();
- $db = Zend_Registry::get('db');
+ $tablesPiwik = Piwik::getTablesInstalled();
+
+ $result = array();
+ foreach(Piwik_FetchAll("SHOW TABLE STATUS") as $t)
+ {
+ if (in_array($t['Name'], $tablesPiwik))
+ {
+ $result[] = $t;
+ }
+ }
+
+ return $result;
+ }
+
+ public function getAllTablesStatusPretty()
+ {
+ Piwik::checkUserIsSuperUser();
+
// http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html
- $tablesPiwik = Piwik::getTablesInstalled();
$total = array('Name' => 'Total', 'Data_length' => 0, 'Index_length' => 0, 'Rows' => 0);
- $table = array();
- foreach($tablesPiwik as $tableName)
+ $table = $this->getAllTablesStatus();
+ foreach($table as &$t)
{
- $t = $this->getTableStatus($tableName);
$total['Data_length'] += $t['Data_length'];
$total['Index_length'] += $t['Index_length'];
$total['Rows'] += $t['Rows'];
@@ -102,7 +122,6 @@ class Piwik_DBStats_API
$t['Data_length'] = Piwik::getPrettySizeFromBytes($t['Data_length']);
$t['Index_length'] = Piwik::getPrettySizeFromBytes($t['Index_length']);
$t['Rows'] = Piwik::getPrettySizeFromBytes($t['Rows']);
- $table[] = $t;
}
$total['Total_length'] = Piwik::getPrettySizeFromBytes($total['Data_length']+$total['Index_length']);
$total['Data_length'] = Piwik::getPrettySizeFromBytes($total['Data_length']);
diff --git a/plugins/DBStats/Controller.php b/plugins/DBStats/Controller.php
index 8feeb6e6a5..91444f91ff 100644
--- a/plugins/DBStats/Controller.php
+++ b/plugins/DBStats/Controller.php
@@ -20,7 +20,7 @@ class Piwik_DBStats_Controller extends Piwik_Controller_Admin
{
Piwik::checkUserIsSuperUser();
$view = Piwik_View::factory('DBStats');
- $view->tablesStatus = Piwik_DBStats_API::getInstance()->getAllTablesStatus();
+ $view->tablesStatus = Piwik_DBStats_API::getInstance()->getAllTablesStatusPretty();
$this->setBasicVariablesView($view);
$view->menu = Piwik_GetAdminMenu();
echo $view->render();
diff --git a/plugins/DBStats/templates/DBStats.tpl b/plugins/DBStats/templates/DBStats.tpl
index 4064e90729..686e3d1fca 100644
--- a/plugins/DBStats/templates/DBStats.tpl
+++ b/plugins/DBStats/templates/DBStats.tpl
@@ -9,8 +9,8 @@
<br />
{'DBStats_LearnMore'|translate:"<a href='?module=Proxy&action=redirect&url=http://piwik.org/docs/setup-auto-archiving/' target='_blank'>Piwik Auto Archiving</a>"}
<br />
-{'PrivacyManager_DeleteLogSettings'|translate}: <a href='{url module="PrivacyManager" action="privacySettings"}#deleteLogsAnchor'>
-{capture assign=clickDeleteLogSettings}{'PrivacyManager_DeleteLogSettings'|translate}{/capture}
+{'PrivacyManager_DeleteDataSettings'|translate}: <a href='{url module="PrivacyManager" action="privacySettings"}#deleteLogsAnchor'>
+{capture assign=clickDeleteLogSettings}{'PrivacyManager_DeleteDataSettings'|translate}{/capture}
{'PrivacyManager_ClickHereSettings'|translate:"'$clickDeleteLogSettings'"}
</a>
diff --git a/plugins/Dashboard/Dashboard.php b/plugins/Dashboard/Dashboard.php
index 1da9ea7625..cbd781b017 100644
--- a/plugins/Dashboard/Dashboard.php
+++ b/plugins/Dashboard/Dashboard.php
@@ -140,8 +140,7 @@ class Piwik_Dashboard extends Piwik_Plugin
public function uninstall()
{
- $sql = "DROP TABLE ". Piwik_Common::prefixTable('user_dashboard') ;
- Piwik_Exec($sql);
+ Piwik_DropTables(Piwik_Common::prefixTable('user_dashboard'));
}
}
diff --git a/plugins/Goals/API.php b/plugins/Goals/API.php
index af912069c0..bc3a92c1f3 100644
--- a/plugins/Goals/API.php
+++ b/plugins/Goals/API.php
@@ -191,7 +191,7 @@ class Piwik_Goals_API
WHERE idsite = ?
AND idgoal = ?",
array($idSite, $idGoal));
- Piwik_Query("DELETE FROM ".Piwik_Common::prefixTable("log_conversion")." WHERE idgoal = ?", $idGoal);
+ Piwik_DeleteAllRows(Piwik_Common::prefixTable("log_conversion"), "WHERE idgoal = ?", 100000, array($idGoal));
Piwik_Common::regenerateCacheWebsiteAttributes($idSite);
}
diff --git a/plugins/LanguagesManager/LanguagesManager.php b/plugins/LanguagesManager/LanguagesManager.php
index febbd562f7..d1345cd59a 100644
--- a/plugins/LanguagesManager/LanguagesManager.php
+++ b/plugins/LanguagesManager/LanguagesManager.php
@@ -114,8 +114,7 @@ class Piwik_LanguagesManager extends Piwik_Plugin
*/
public function uninstall()
{
- $sql = "DROP TABLE ". Piwik_Common::prefixTable('user_language') ;
- Piwik_Exec($sql);
+ Piwik_DropTables(Piwik_Common::prefixTable('user_language'));
}
/**
diff --git a/plugins/PrivacyManager/Controller.php b/plugins/PrivacyManager/Controller.php
index f48ea48b9f..08eeaee806 100644
--- a/plugins/PrivacyManager/Controller.php
+++ b/plugins/PrivacyManager/Controller.php
@@ -36,15 +36,8 @@ class Piwik_PrivacyManager_Controller extends Piwik_Controller_Admin
break;
case("formDeleteSettings"):
- $deleteLogs = Piwik_Config::getInstance()->Deletelogs;
- $deleteLogs['delete_logs_enable'] = Piwik_Common::getRequestVar("deleteEnable", 0);
- $deleteLogs['delete_logs_schedule_lowest_interval'] = Piwik_Common::getRequestVar("deleteLowestInterval", 7);
- $deleteLogs['delete_logs_older_than'] = ((int)Piwik_Common::getRequestVar("deleteOlderThan", 180) < 7) ?
- 7 : Piwik_Common::getRequestVar("deleteOlderThan", 180);
- $deleteLogs['delete_max_rows_per_run'] = Piwik_Common::getRequestVar("deleteMaxRows", 100);
-
- Piwik_Config::getInstance()->Deletelogs = $deleteLogs;
- Piwik_Config::getInstance()->forceSave();
+ $settings = $this->getPurgeSettingsFromRequest();
+ Piwik_PrivacyManager::savePurgeDataSettings($settings);
break;
default: //do nothing
@@ -54,6 +47,50 @@ class Piwik_PrivacyManager_Controller extends Piwik_Controller_Admin
return $this->redirectToIndex('PrivacyManager', 'privacySettings', null, null, null, array('updated' => 1));
}
+
+ /**
+ * Utility function. Gets the delete logs/reports settings from the request and uses
+ * them to populate config arrays.
+ *
+ * @return array An array containing the data deletion settings.
+ */
+ private function getPurgeSettingsFromRequest()
+ {
+ $settings = array();
+
+ // delete logs settings
+ $settings['delete_logs_enable'] = Piwik_Common::getRequestVar("deleteEnable", 0);
+ $settings['delete_logs_schedule_lowest_interval'] = Piwik_Common::getRequestVar("deleteLowestInterval", 7);
+ $settings['delete_logs_older_than'] = ((int)Piwik_Common::getRequestVar("deleteOlderThan", 180) < 7) ?
+ 7 : Piwik_Common::getRequestVar("deleteOlderThan", 180);
+
+ // delete reports settings
+ $settings['delete_reports_enable'] = Piwik_Common::getRequestVar("deleteReportsEnable", 0);
+ $deleteReportsOlderThan = Piwik_Common::getRequestVar("deleteReportsOlderThan", 3);
+ $settings['delete_reports_older_than'] = $deleteReportsOlderThan < 3 ? 3 : $deleteReportsOlderThan;
+ $settings['delete_reports_keep_basic_metrics'] = Piwik_Common::getRequestVar("deleteReportsKeepBasic", 0);
+ $settings['delete_reports_keep_day_reports'] = Piwik_Common::getRequestVar("deleteReportsKeepDay", 0);
+ $settings['delete_reports_keep_week_reports'] = Piwik_Common::getRequestVar("deleteReportsKeepWeek", 0);
+ $settings['delete_reports_keep_month_reports'] = Piwik_Common::getRequestVar("deleteReportsKeepMonth", 0);
+ $settings['delete_reports_keep_year_reports'] = Piwik_Common::getRequestVar("deleteReportsKeepYear", 0);
+
+ return $settings;
+ }
+
+ /**
+ * Echo's an HTML chunk describing the current database size, and the estimated space
+ * savings after the scheduled data purge is run.
+ */
+ public function getDatabaseSize()
+ {
+ Piwik::checkUserIsSuperUser();
+ $view = Piwik_View::factory('databaseSize');
+
+ $view->dbStats = $this->getDeleteDBSizeEstimate(true);
+ $view->language = Piwik_LanguagesManager::getLanguageCodeForCurrentUser();
+
+ echo $view->render();
+ }
public function privacySettings()
{
@@ -64,7 +101,8 @@ class Piwik_PrivacyManager_Controller extends Piwik_Controller_Admin
{
$deleteLogs = array();
- $view->deleteLogs = $this->getDeleteLogsInfo();
+ $view->deleteData = $this->getDeleteDataInfo();
+ $view->deleteDbStats = $this->getDeleteDBSizeEstimate();
$view->anonymizeIP = $this->getAnonymizeIPInfo();
}
$view->language = Piwik_LanguagesManager::getLanguageCodeForCurrentUser();
@@ -79,6 +117,94 @@ class Piwik_PrivacyManager_Controller extends Piwik_Controller_Admin
echo $view->render();
}
+
+ /**
+ * Executes a data purge, deleting log data and report data using the current config
+ * options. Echo's the result of getDatabaseSize after purging.
+ */
+ public function executeDataPurge()
+ {
+ Piwik::checkUserIsSuperUser();
+
+ // if the request isn't a POST, redirect to index
+ if ($_SERVER["REQUEST_METHOD"] != "POST")
+ {
+ return $this->redirectToIndex('PrivacyManager', 'privacySettings');
+ }
+
+ $settings = Piwik_PrivacyManager::getPurgeDataSettings();
+
+ // execute the purge
+ if ($settings['delete_logs_enable'])
+ {
+ $logDataPurger = Piwik_PrivacyManager_LogDataPurger::make($settings);
+ $logDataPurger->purgeData();
+ }
+
+ if ($settings['delete_reports_enable'])
+ {
+ $reportsPurger = Piwik_PrivacyManager_ReportsPurger::make(
+ $settings, Piwik_PrivacyManager::getMetricsToPurge());
+ $reportsPurger->purgeData();
+ }
+
+ // re-calculate db size estimate
+ $this->getDatabaseSize();
+ }
+
+ protected function getDeleteDBSizeEstimate( $getSettingsFromQuery = false )
+ {
+ // get the purging settings & create two purger instances
+ if ($getSettingsFromQuery)
+ {
+ $settings = $this->getPurgeSettingsFromRequest();
+ }
+ else
+ {
+ $settings = Piwik_PrivacyManager::getPurgeDataSettings();
+ }
+
+ // maps tables whose data will be deleted with number of rows that will be deleted
+ // if a value is -1, it means the table will be dropped.
+ $deletedDataSummary = Piwik_PrivacyManager::getPurgeEstimate($settings);
+
+ // determine the DB size & purged DB size
+ $tableStatuses = Piwik_DBStats_API::getInstance()->getAllTablesStatus();
+
+ $totalBytes = 0;
+ foreach ($tableStatuses as $status)
+ {
+ $totalBytes += $status['Data_length'] + $status['Index_length'];
+ }
+
+ $totalAfterPurge = $totalBytes;
+ foreach ($tableStatuses as $status)
+ {
+ $tableName = $status['Name'];
+ if (isset($deletedDataSummary[$tableName]))
+ {
+ $tableTotalBytes = $status['Data_length'] + $status['Index_length'];
+
+ // if dropping the table
+ if ($deletedDataSummary[$tableName] === Piwik_PrivacyManager_ReportsPurger::DROP_TABLE)
+ {
+ $totalAfterPurge -= $tableTotalBytes;
+ }
+ else // if just deleting rows
+ {
+ $totalAfterPurge -= ($tableTotalBytes / $status['Rows']) * $deletedDataSummary[$tableName];
+ }
+ }
+ }
+
+ $result = array(
+ 'currentSize' => Piwik::getPrettySizeFromBytes($totalBytes),
+ 'sizeAfterPurge' => Piwik::getPrettySizeFromBytes($totalAfterPurge),
+ 'spaceSaved' => Piwik::getPrettySizeFromBytes($totalBytes - $totalAfterPurge)
+ );
+
+ return $result;
+ }
protected function getAnonymizeIPInfo()
{
@@ -95,14 +221,14 @@ class Piwik_PrivacyManager_Controller extends Piwik_Controller_Admin
return $anonymizeIP;
}
- protected function getDeleteLogsInfo()
+ protected function getDeleteDataInfo()
{
Piwik::checkUserIsSuperUser();
- $deleteLogsInfos = array();
+ $deleteDataInfos = array();
$taskScheduler = new Piwik_TaskScheduler();
- $deleteLogsInfos["config"] = Piwik_Config::getInstance()->Deletelogs;
- $privacyManager = new Piwik_PrivacyManager();
- $deleteLogsInfos["deleteTables"] = implode(", ", $privacyManager->getDeleteTableLogTables());
+ $deleteDataInfos["config"] = Piwik_PrivacyManager::getPurgeDataSettings();
+ $deleteDataInfos["deleteTables"] =
+ implode(", ", Piwik_PrivacyManager_LogDataPurger::getDeleteTableLogTables());
$scheduleTimetable = $taskScheduler->getScheduledTimeForTask("Piwik_PrivacyManager", "deleteLogTables");
@@ -118,29 +244,29 @@ class Piwik_PrivacyManager_Controller extends Piwik_Controller_Admin
//deletion schedule did not run before
if (empty($optionTable)) {
- $deleteLogsInfos["lastRun"] = false;
+ $deleteDataInfos["lastRun"] = false;
//next run ASAP (with next schedule run)
$date = Piwik_Date::factory("today");
- $deleteLogsInfos["nextScheduleTime"] = $nextPossibleSchedule;
+ $deleteDataInfos["nextScheduleTime"] = $nextPossibleSchedule;
} else {
- $deleteLogsInfos["lastRun"] = $optionTable;
- $deleteLogsInfos["lastRunPretty"] = Piwik_Date::factory((int)$optionTable)->getLocalized('%day% %shortMonth% %longYear%');
+ $deleteDataInfos["lastRun"] = $optionTable;
+ $deleteDataInfos["lastRunPretty"] = Piwik_Date::factory((int)$optionTable)->getLocalized('%day% %shortMonth% %longYear%');
//Calculate next run based on last run + interval
- $nextScheduleRun = (int)($deleteLogsInfos["lastRun"] + $deleteLogsInfos["config"]["delete_logs_schedule_lowest_interval"] * 24 * 60 * 60);
+ $nextScheduleRun = (int)($deleteDataInfos["lastRun"] + $deleteDataInfos["config"]["delete_logs_schedule_lowest_interval"] * 24 * 60 * 60);
//is the calculated next run in the past? (e.g. plugin was disabled in the meantime or something) -> run ASAP
if (($nextScheduleRun - time()) <= 0) {
- $deleteLogsInfos["nextScheduleTime"] = $nextPossibleSchedule;
+ $deleteDataInfos["nextScheduleTime"] = $nextPossibleSchedule;
} else {
- $deleteLogsInfos["nextScheduleTime"] = $nextScheduleRun;
+ $deleteDataInfos["nextScheduleTime"] = $nextScheduleRun;
}
}
- $deleteLogsInfos["nextRunPretty"] = Piwik::getPrettyTimeFromSeconds($deleteLogsInfos["nextScheduleTime"] - time());
+ $deleteDataInfos["nextRunPretty"] = Piwik::getPrettyTimeFromSeconds($deleteDataInfos["nextScheduleTime"] - time());
- return $deleteLogsInfos;
+ return $deleteDataInfos;
}
protected function handlePluginState($state = 0)
diff --git a/plugins/PrivacyManager/LogDataPurger.php b/plugins/PrivacyManager/LogDataPurger.php
new file mode 100755
index 0000000000..2b8ad3dc0d
--- /dev/null
+++ b/plugins/PrivacyManager/LogDataPurger.php
@@ -0,0 +1,151 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ * @version $Id: $
+ *
+ * @category Piwik_Plugins
+ * @package Piwik_PrivacyManager
+ */
+
+/**
+ * Purges the log_visit, log_conversion and related tables of old visit data.
+ */
+class Piwik_PrivacyManager_LogDataPurger
+{
+ /**
+ * The number of days after which log entries are considered old.
+ */
+ private $deleteLogsOlderThan;
+
+ /**
+ * The number of rows to delete per DELETE query.
+ */
+ private $maxRowsToDeletePerQuery;
+
+ /**
+ * Constructor.
+ *
+ * @param int $deleteLogsOlderThan The number of days after which log entires are considered old.
+ * Visits and related data whose age is greater than this number
+ * will be purged.
+ */
+ public function __construct( $deleteLogsOlderThan, $maxRowsToDeletePerQuery )
+ {
+ $this->deleteLogsOlderThan = $deleteLogsOlderThan;
+ $this->maxRowsToDeletePerQuery = $maxRowsToDeletePerQuery;
+ }
+
+ /**
+ * Purges old data from the following tables:
+ * - log_visit
+ * - log_link_visit_action
+ * - log_conversion
+ * - log_conversion_item
+ */
+ public function purgeData()
+ {
+ $maxIdVisit = $this->getDeleteIdVisitOffset();
+
+ // break if no ID was found (nothing to delete for given period)
+ if (empty($maxIdVisit))
+ {
+ return;
+ }
+
+ $logTables = self::getDeleteTableLogTables();
+
+ // delete data from log tables
+ $where = "WHERE idvisit <= ?";
+ foreach ($logTables as $logTable)
+ {
+ Piwik_DeleteAllRows($logTable, $where, $this->maxRowsToDeletePerQuery, array($maxIdVisit));
+ }
+
+ // optimize table overhead after deletion
+ Piwik_OptimizeTables($logTables);
+ }
+
+ /**
+ * Returns an array describing what data would be purged if purging were invoked.
+ *
+ * This function returns an array that maps table names with the number of rows
+ * that will be deleted.
+ *
+ * @return array
+ */
+ public function getPurgeEstimate()
+ {
+ $result = array();
+
+ // deal w/ log tables that will be purged
+ $maxIdVisit = $this->getDeleteIdVisitOffset();
+ if (!empty($maxIdVisit))
+ {
+ foreach ($this->getDeleteTableLogTables() as $table)
+ {
+ $rowCount = $this->getLogTableDeleteCount($table, $maxIdVisit);
+ if ($rowCount > 0)
+ {
+ $result[$table] = $rowCount;
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * get highest idVisit to delete rows from
+ */
+ private function getDeleteIdVisitOffset()
+ {
+ $dateStart = Piwik_Date::factory("today")->subDay($this->deleteLogsOlderThan);
+
+ $sql = "SELECT idvisit
+ FROM ".Piwik_Common::prefixTable("log_visit")."
+ WHERE '".$dateStart->toString('Y-m-d H:i:s')."' > visit_last_action_time AND idvisit > 0
+ ORDER BY idvisit DESC
+ LIMIT 1";
+
+ return Piwik_FetchOne($sql);
+ }
+
+ private function getLogTableDeleteCount( $table, $maxIdVisit )
+ {
+ $sql = "SELECT COUNT(*) FROM $table WHERE idvisit <= ?";
+ return (int)Piwik_FetchOne($sql, array($maxIdVisit));
+ }
+
+ // let's hardcode, since these are no dynamically created tables
+ // exclude piwik_log_action since it is a lookup table
+ public static function getDeleteTableLogTables()
+ {
+ return array(Piwik_Common::prefixTable("log_conversion"),
+ Piwik_Common::prefixTable("log_link_visit_action"),
+ Piwik_Common::prefixTable("log_visit"),
+ Piwik_Common::prefixTable("log_conversion_item"));
+ }
+
+ /**
+ * Utility function. Creates a new instance of LogDataPurger with the supplied array
+ * of settings.
+ *
+ * $settings must contain values for the following keys:
+ * - 'delete_logs_older_than': The number of days after which log entries are considered
+ * old.
+ * - 'delete_logs_max_rows_per_query': Max number of rows to DELETE in one query.
+ *
+ * @param $settings Array of settings
+ */
+ public static function make( $settings )
+ {
+ return new Piwik_PrivacyManager_LogDataPurger(
+ $settings['delete_logs_older_than'],
+ $settings['delete_logs_max_rows_per_query']
+ );
+ }
+}
+
diff --git a/plugins/PrivacyManager/PrivacyManager.php b/plugins/PrivacyManager/PrivacyManager.php
index e008922f14..2706adb5f8 100644
--- a/plugins/PrivacyManager/PrivacyManager.php
+++ b/plugins/PrivacyManager/PrivacyManager.php
@@ -11,15 +11,40 @@
*/
/**
+ * @see plugins/PrivacyManager/LogDataPurger.php
+ */
+require_once PIWIK_INCLUDE_PATH . '/plugins/PrivacyManager/LogDataPurger.php';
+
+/**
+ * @see plugins/PrivacyManager/ReportsPurger.php
+ */
+require_once PIWIK_INCLUDE_PATH . '/plugins/PrivacyManager/ReportsPurger.php';
+
+/**
*
* @package Piwik_PrivacyManager
*/
class Piwik_PrivacyManager extends Piwik_Plugin
{
const OPTION_LAST_DELETE_PIWIK_LOGS = "lastDelete_piwik_logs";
+ const OPTION_LAST_DELETE_PIWIK_REPORTS = 'lastDelete_piwik_reports';
const OPTION_LAST_DELETE_PIWIK_LOGS_INITIAL = "lastDelete_piwik_logs_initial";
- const DELETE_MAX_ROWS_MULTIPLICATOR = 1000;
-
+
+ // default config options for data purging feature
+ public static $defaultPurgeDataOptions = array(
+ 'delete_logs_enable' => 0,
+ 'delete_logs_schedule_lowest_interval' => 7,
+ 'delete_logs_older_than' => 180,
+ 'delete_logs_max_rows_per_query' => 100000,
+ 'delete_reports_enable' => 0,
+ 'delete_reports_older_than' => 12,
+ 'delete_reports_keep_basic_metrics' => 1,
+ 'delete_reports_keep_day_reports' => 0,
+ 'delete_reports_keep_week_reports' => 0,
+ 'delete_reports_keep_month_reports' => 1,
+ 'delete_reports_keep_year_reports' => 1
+ );
+
public function getInformation()
{
return array(
@@ -39,14 +64,16 @@ class Piwik_PrivacyManager extends Piwik_Plugin
);
}
- function getScheduledTasks($notification)
- {
- $tasks = &$notification->getNotificationObject();
- $deleteLogTablesTask = new Piwik_ScheduledTask ($this,
- 'deleteLogTables',
- new Piwik_ScheduledTime_Daily());
- $tasks[] = $deleteLogTablesTask;
- }
+ function getScheduledTasks($notification)
+ {
+ $tasks = &$notification->getNotificationObject();
+
+ $purgeLogDataTask = new Piwik_ScheduledTask($this, 'deleteLogData', new Piwik_ScheduledTime_Daily());
+ $tasks[] = $purgeLogDataTask;
+
+ $purgeReportDataTask = new Piwik_ScheduledTask($this, 'deleteReportData', new Piwik_ScheduledTime_Daily());
+ $tasks[] = $purgeReportDataTask;
+ }
function getJsFiles($notification)
{
@@ -62,109 +89,329 @@ class Piwik_PrivacyManager extends Piwik_Plugin
Piwik::isUserHasSomeAdminAccess(),
$order = 8);
}
-
- /*
- * @ToDo: return number of Rows deleted in last run; Display age of "oldest" row to help the user setting the day offset;
+
+ /**
+ * Returns the settings for the data purging feature.
+ *
+ * @return array
+ */
+ public static function getPurgeDataSettings()
+ {
+ $settings = array();
+
+ // backwards compatibility: load old values in ini config if present
+ try
+ {
+ $oldSettings = array(
+ 'delete_logs_enable',
+ 'delete_logs_schedule_lowest_interval',
+ 'delete_logs_older_than'
+ );
+
+ $deleteLogsSettings = Piwik_Config::getInstance()->Deletelogs;
+ foreach ($oldSettings as $settingName)
+ {
+ $settings[$settingName] = $deleteLogsSettings[$settingName];
+ }
+ }
+ catch (Exception $e)
+ {
+ // ignore
+ }
+
+ // load the settings for the data purging settings
+ foreach (self::$defaultPurgeDataOptions as $optionName => $defaultValue)
+ {
+ $value = Piwik_GetOption($optionName);
+ if ($value !== false)
+ {
+ $settings[$optionName] = $value;
+ }
+ else
+ {
+ // if the option hasn't been set/created, use the default value
+ if (!isset($settings[$optionName]))
+ {
+ $settings[$optionName] = $defaultValue;
+ }
+
+ // option is not saved in the DB, so save it now
+ Piwik_SetOption($optionName, $settings[$optionName]);
+ }
+ }
+
+ return $settings;
+ }
+
+ /**
+ * Saves the supplied data purging settings.
+ *
+ * @param array $settings The settings to save.
+ */
+ public static function savePurgeDataSettings( $settings )
+ {
+ $plugin = Piwik_PluginsManager::getInstance()->getLoadedPlugin('PrivacyManager');
+
+ foreach (self::$defaultPurgeDataOptions as $optionName => $defaultValue)
+ {
+ if (isset($settings[$optionName]))
+ {
+ Piwik_SetOption($optionName, $settings[$optionName]);
+ }
+ }
+ }
+
+ /**
+ * Deletes old archived data (reports & metrics).
+ *
+ * Archive tables are not optimized after, as that is handled by a separate scheduled task
+ * in CoreAdminHome. This is a scheduled task and will only execute every N days. The number
+ * of days is determined by the delete_logs_schedule_lowest_interval config option.
+ *
+ * If delete_reports_enable is set to 1, old archive data is deleted. The following
+ * config options can tweak this behavior:
+ * - delete_reports_older_than: The number of months after which archive data is considered
+ * old. The current month is not considered when applying this
+ * value.
+ * - delete_reports_keep_basic_metrics: If set to 1, keeps certain metric data. Right now,
+ * all metric data is kept.
+ * - delete_reports_keep_day_reports: If set to 1, keeps old daily reports.
+ * - delete_reports_keep_week_reports: If set to 1, keeps old weekly reports.
+ * - delete_reports_keep_month_reports: If set to 1, keeps old monthly reports.
+ * - delete_reports_keep_year_reports: If set to 1, keeps old yearly reports.
*/
- function deleteLogTables()
- {
- $deleteSettings = Piwik_Config::getInstance()->Deletelogs;
-
- //Make sure, log deletion is enabled
- if ($deleteSettings['delete_logs_enable'] == 0) {
+ public function deleteReportData()
+ {
+ $settings = self::getPurgeDataSettings();
+
+ // Make sure, data deletion is enabled
+ if ($settings['delete_reports_enable'] == 0)
+ {
return;
}
-
- //Log deletion may not run until it is once rescheduled (initial run). This is the only way to guarantee the calculated next scheduled deletion time.
- $initialDelete = Piwik_GetOption(self::OPTION_LAST_DELETE_PIWIK_LOGS_INITIAL);
- if (empty($initialDelete)) {
- Piwik_SetOption(self::OPTION_LAST_DELETE_PIWIK_LOGS_INITIAL, 1);
+
+ // make sure purging should run at this time (unless this is a forced purge)
+ if (!$this->shouldPurgeData($settings, self::OPTION_LAST_DELETE_PIWIK_REPORTS))
+ {
+ return;
+ }
+
+ // set last run time
+ Piwik_SetOption(self::OPTION_LAST_DELETE_PIWIK_REPORTS, Piwik_Date::factory('today')->getTimestamp());
+
+ Piwik_PrivacyManager_ReportsPurger::make($settings, self::getMetricsToPurge())->purgeData();
+ }
+
+ /**
+ * Deletes old log data based on the options set in the Deletelogs config
+ * section. This is a scheduled task and will only execute every N days. The number
+ * of days is determined by the delete_logs_schedule_lowest_interval config option.
+ *
+ * If delete_logs_enable is set to 1, old data in the log_visit, log_conversion,
+ * log_conversion_item and log_link_visit_action tables is deleted. The following
+ * options can tweak this behavior:
+ * - delete_logs_older_than: The number of days after which log data is considered old.
+ *
+ * @ToDo: return number of Rows deleted in last run; Display age of "oldest" row to help the user setting
+ * the day offset;
+ */
+ public function deleteLogData()
+ {
+ $settings = self::getPurgeDataSettings();
+
+ // Make sure, data deletion is enabled
+ if ($settings['delete_logs_enable'] == 0)
+ {
return;
}
-
- //Make sure, log purging is allowed to run now
- $lastDelete = Piwik_GetOption(self::OPTION_LAST_DELETE_PIWIK_LOGS);
- $deleteIntervalSeconds = $this->getDeleteIntervalInSeconds($deleteSettings['delete_logs_schedule_lowest_interval']);
-
- if ($lastDelete === false ||
- ($lastDelete !== false && ((int)$lastDelete + $deleteIntervalSeconds) <= time())
- ) {
-
- $maxIdVisit = $this->getDeleteIdVisitOffset($deleteSettings['delete_logs_older_than']);
-
- $logTables = $this->getDeleteTableLogTables();
-
- //set lastDelete time to today
- $date = Piwik_Date::factory("today");
- $lastDeleteDate = $date->getTimestamp();
-
- /*
- * Tell the DB that log deletion has run BEFORE deletion is executed;
- * If deletion / table optimization exceeds execution time, other tasks maybe prevented of being executed every time,
- * when the schedule is triggered.
- */
- Piwik_SetOption(self::OPTION_LAST_DELETE_PIWIK_LOGS, $lastDeleteDate);
-
- //Break if no ID was found (nothing to delete for given period)
- if (empty($maxIdVisit)) {
- return;
- }
-
- foreach ($logTables as $logTable) {
- $this->deleteRowsFromTable($logTable, $maxIdVisit, $deleteSettings['delete_max_rows_per_run'] * self::DELETE_MAX_ROWS_MULTIPLICATOR);
- }
-
- //optimize table overhead after deletion
- $query = "OPTIMIZE TABLE " . implode(",", $logTables);
- Piwik_Query($query);
+
+ // make sure purging should run at this time
+ if (!$this->shouldPurgeData($settings, self::OPTION_LAST_DELETE_PIWIK_LOGS))
+ {
+ return;
}
+
+ /*
+ * Tell the DB that log deletion has run BEFORE deletion is executed;
+ * If deletion / table optimization exceeds execution time, other tasks maybe prevented of being executed
+ * every time, when the schedule is triggered.
+ */
+ $lastDeleteDate = Piwik_Date::factory("today")->getTimestamp();
+ Piwik_SetOption(self::OPTION_LAST_DELETE_PIWIK_LOGS, $lastDeleteDate);
+
+ // execute the purge
+ Piwik_PrivacyManager_LogDataPurger::make($settings)->purgeData();
}
-
- function getDeleteIntervalInSeconds($deleteInterval)
- {
- return (int)$deleteInterval * 24 * 60 * 60;
- }
-
- /*
- * get highest idVisit to delete rows from
+
+ /**
+ * Returns an array describing what data would be purged if both log data & report
+ * purging is invoked.
+ *
+ * The returned array maps table names with the number of rows that will be deleted.
+ * If the table name is mapped with -1, the table will be dropped.
+ *
+ * @param array $settings The config options to use in the estimate. If null, the real
+ * options are used.
+ * @return array
*/
- function getDeleteIdVisitOffset($deleteLogsOlderThan)
+ public static function getPurgeEstimate( $settings = null )
{
- $date = Piwik_Date::factory("today");
- $dateSubX = $date->subDay($deleteLogsOlderThan);
-
- $sql = "SELECT `idvisit` FROM " . Piwik_Common::prefixTable("log_visit")
- . " WHERE '" . $dateSubX->toString('Y-m-d H:i:s') . "' "
- . "> `visit_last_action_time` AND `idvisit` > 0 ORDER BY `idvisit` DESC LIMIT 1";
-
- $maxIdVisit = Piwik_FetchOne($sql);
-
- return $maxIdVisit;
+ if (is_null($settings))
+ {
+ $settings = self::getPurgeDataSettings();
+ }
+
+ $result = array();
+
+ if ($settings['delete_logs_enable'])
+ {
+ $logDataPurger = Piwik_PrivacyManager_LogDataPurger::make($settings);
+ $result = array_merge($result, $logDataPurger->getPurgeEstimate());
+ }
+
+ if ($settings['delete_reports_enable'])
+ {
+ $reportsPurger = Piwik_PrivacyManager_ReportsPurger::make($settings, self::getMetricsToPurge());
+ $result = array_merge($result, $reportsPurger->getPurgeEstimate());
+ }
+
+ return $result;
}
+
+ /**
+ * Returns true if a report with the given year & month should be purged or not.
+ *
+ * If reportsOlderThan is set to null or not supplied, this function will check if
+ * a report should be purged, based on existing configuration. In this case, if
+ * delete_reports_enable is set to 0, this function will return false.
+ *
+ * @param int $reportDateYear The year of the report in question.
+ * @param int $reportDateMonth The month of the report in question.
+ * @param int|Piwik_Date $reportsOlderThan If an int, the number of months a report must be older than
+ * in order to be purged. If a date, the date a report must be
+ * older than in order to be purged.
+ */
+ public static function shouldReportBePurged( $reportDateYear, $reportDateMonth, $reportsOlderThan = null )
+ {
+ // if no 'older than' value/date was supplied, use existing config
+ if (is_null($reportsOlderThan))
+ {
+ // if report deletion is not enabled, the report shouldn't be purged
+ $settings = self::getPurgeDataSettings();
+ if ($settings['delete_reports_enable'] == 0)
+ {
+ return false;
+ }
+
+ $reportsOlderThan = $settings['delete_reports_older_than'];
+ }
+
+ // if a integer was supplied, assume it is the number of months a report must be older than
+ if (!($reportsOlderThan instanceof Piwik_Date))
+ {
+ $reportsOlderThan = Piwik_Date::factory('today')->subMonth(1 + $reportsOlderThan);
+ }
+
+ return Piwik_PrivacyManager_ReportsPurger::shouldReportBePurged(
+ $reportDateYear, $reportDateMonth, $reportsOlderThan);
+ }
+
+ /**
+ * Returns the general metrics to purge when 'delete_reports_keep_basic_metrics' is set to 1.
+ * Right now, this is set to nothing, so the 'keep_basic_metrics' option will keep everything.
+ */
+ private static function getMetricsToKeep()
+ {
+ return array('nb_uniq_visitors', 'nb_visits', 'nb_actions', 'max_actions',
+ 'sum_visit_length', 'bounce_count', 'nb_visits_converted', 'nb_conversions',
+ 'revenue', 'quantity', 'price', 'orders');
+ }
+
+ /**
+ * Returns the goal metrics to purge when 'delete_reports_keep_basic_metrics' is set to 1.
+ * Right now, this is set to nothing, so the 'keep_basic_metrics' option will keep everything.
+ */
+ private static function getGoalMetricsToKeep()
+ {
+ // keep all goal metrics
+ return array_values(Piwik_Archive::$mappingFromIdToNameGoal);
+ }
+
+ /**
+ * Returns the metrics that should be purged based on the metrics that should be kept.
+ */
+ public static function getMetricsToPurge()
+ {
+ $metricsToKeep = self::getMetricsToKeep();
+
+ // the metrics to purge == all_metrics - metrics_to_keep
+ $metricsToPurge = array_diff(array_values(Piwik_Archive::$mappingFromIdToName), $metricsToKeep);
+
+ // convert goal metric names to correct archive names
+ if (Piwik_Common::isGoalPluginEnabled())
+ {
+ $goalMetricsToPurge
+ = array_diff(array_values(Piwik_Archive::$mappingFromIdToNameGoal), self::getGoalMetricsToKeep());
+
+ $maxGoalId = self::getMaxGoalId();
+
+ // for each goal metric, there's a different name for each goal, including the overview,
+ // the order report & cart report
+ foreach ($goalMetricsToPurge as $metric)
+ {
+ for ($i = 1; $i != $maxGoalId; ++$i)
+ {
+ $metricsToPurge[] = Piwik_Goals::getRecordName($metric, $i);
+ }
+
+ $metricsToPurge[] = Piwik_Goals::getRecordName($metric);
+ $metricsToPurge[] = Piwik_Goals::getRecordName($metric, Piwik_Tracker_GoalManager::IDGOAL_ORDER);
+ $metricsToPurge[] = Piwik_Goals::getRecordName($metric, Piwik_Tracker_GoalManager::IDGOAL_CART);
+ }
+ }
+
+ return $metricsToPurge;
+ }
- function deleteRowsFromTable($table, $maxIdVisit, $maxRowsPerRun)
- {
- /*
- * @ToDo: check if DELETE ... tbl_name[.*] [, tbl_name[.*]] ... Statement performance is better (but LIMIT can't be used!). So for now, this is safer.
- * LOW_PRIORITY / QUICK / IGNORE read http://dev.mysql.com/doc/refman/5.0/en/delete.html
- */
-
- $sql = 'DELETE LOW_PRIORITY QUICK IGNORE FROM ' . $table . ' WHERE `idvisit` <= ? ';
-
- if(isset($maxRowsPerRun) && $maxRowsPerRun > 0) {
- $sql .= ' LIMIT ' . (int)$maxRowsPerRun;
+ /**
+ * Returns true if one of the purge data tasks should run now, false if it shouldn't.
+ */
+ private function shouldPurgeData( $settings, $lastRanOption )
+ {
+ // Log deletion may not run until it is once rescheduled (initial run). This is the
+ // only way to guarantee the calculated next scheduled deletion time.
+ $initialDelete = Piwik_GetOption(self::OPTION_LAST_DELETE_PIWIK_LOGS_INITIAL);
+ if (empty($initialDelete))
+ {
+ Piwik_SetOption(self::OPTION_LAST_DELETE_PIWIK_LOGS_INITIAL, 1);
+ return false;
}
+
+ // Make sure, log purging is allowed to run now
+ $lastDelete = Piwik_GetOption($lastRanOption);
+ $deleteIntervalDays = $settings['delete_logs_schedule_lowest_interval'];
+ $deleteIntervalSeconds = $this->getDeleteIntervalInSeconds($deleteIntervalDays);
+
+ if ($lastDelete === false ||
+ ($lastDelete !== false && ((int)$lastDelete + $deleteIntervalSeconds) <= time())
+ )
+ {
+ return true;
+ }
+ else // not time to run data purge
+ {
+ return false;
+ }
+ }
- Piwik_Query($sql, array($maxIdVisit));
+ function getDeleteIntervalInSeconds($deleteInterval)
+ {
+ return (int)$deleteInterval * 24 * 60 * 60;
}
- //let's hardcode, since these are no dynamically created tables
- //exclude piwik_log_action since it is a lookup table
- function getDeleteTableLogTables()
+ private static function getMaxGoalId()
{
- return array(Piwik_Common::prefixTable("log_conversion"),
- Piwik_Common::prefixTable("log_link_visit_action"),
- Piwik_Common::prefixTable("log_visit"),
- Piwik_Common::prefixTable("log_conversion_item"));
+ return Piwik_FetchOne("SELECT MAX(idgoal) FROM ".Piwik_Common::prefixTable('goal'));
}
}
+
diff --git a/plugins/PrivacyManager/ReportsPurger.php b/plugins/PrivacyManager/ReportsPurger.php
new file mode 100755
index 0000000000..8e8d15e04a
--- /dev/null
+++ b/plugins/PrivacyManager/ReportsPurger.php
@@ -0,0 +1,309 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ * @version $Id: $
+ *
+ * @category Piwik_Plugins
+ * @package Piwik_PrivacyManager
+ */
+
+/**
+ * Purges archived reports and metrics that are considered old.
+ */
+class Piwik_PrivacyManager_ReportsPurger
+{
+ // constant used in database purging estimate to signify a table should be dropped
+ const DROP_TABLE = -1;
+
+ /**
+ * The number of months after which report/metric data is considered old.
+ */
+ private $deleteReportsOlderThan;
+
+ /**
+ * Whether to keep basic metrics or not.
+ */
+ private $keepBasicMetrics;
+
+ /**
+ * Array of period types. Reports for these periods will not be purged.
+ */
+ private $reportPeriodsToKeep;
+
+ /**
+ * The maximum number of rows to delete per DELETE query.
+ */
+ private $maxRowsToDeletePerQuery;
+
+ /**
+ * List of metrics that should be purged. If $keepBasicMetrics is true, only these
+ * metrics will be deleted.
+ */
+ private $metricsToPurge;
+
+ /**
+ * Constructor.
+ *
+ * @param int $deleteReportsOlderThan The number of months after which report/metric data
+ * is considered old.
+ * @param bool $keepBasicMetrics Whether to keep basic metrics or not.
+ * @param array $reportPeriodsToKeep Array of period types. Reports for these periods will not
+ * be purged.
+ * @param array $metricsToPurge List of metrics that should be purged. if $keepBasicMetrics
+ * is true, only these metrics will be deleted.
+ * @param int $maxRowsToDeletePerQuery The maximum number of rows to delete per DELETE query.
+ */
+ public function __construct( $deleteReportsOlderThan, $keepBasicMetrics, $reportPeriodsToKeep,
+ $metricsToPurge, $maxRowsToDeletePerQuery )
+ {
+ $this->deleteReportsOlderThan = $deleteReportsOlderThan;
+ $this->keepBasicMetrics = $keepBasicMetrics;
+ $this->reportPeriodsToKeep = $reportPeriodsToKeep;
+ $this->metricsToPurge = $metricsToPurge;
+ $this->maxRowsToDeletePerQuery = $maxRowsToDeletePerQuery;
+ }
+
+ /**
+ * Purges old report/metric data.
+ *
+ * If $keepBasicMetrics is false, old numeric tables will be dropped, otherwise only
+ * the metrics in $metricsToPurge will be deleted.
+ *
+ * If $reportPeriodsToKeep is an empty array, old blob tables will be dropped. Otherwise,
+ * specific reports will be deleted, except reports for periods in $reportPeriodsToKeep.
+ */
+ public function purgeData()
+ {
+ // find archive tables to purge
+ list($oldNumericTables, $oldBlobTables) = $this->getArchiveTablesToPurge();
+
+ // deal with numeric tables
+ if (!empty($oldNumericTables))
+ {
+ // if keep_basic_metrics is set, empty all numeric tables of metrics to purge
+ if ($this->keepBasicMetrics == 1)
+ {
+ if (!empty($this->metricsToPurge))
+ {
+ $where = "WHERE name IN ('".implode("','", $this->metricsToPurge)."')";
+ foreach ($oldNumericTables as $table)
+ {
+ Piwik_DeleteAllRows($table, $where, $this->maxRowsToDeletePerQuery);
+ }
+ }
+ }
+ else // drop numeric tables
+ {
+ Piwik_DropTables($oldNumericTables);
+ }
+ }
+
+ // process blob tables
+ if (!empty($oldBlobTables))
+ {
+ // if no reports should be kept, drop tables, otherwise drop individual reports
+ if (empty($this->reportPeriodsToKeep))
+ {
+ Piwik_DropTables($oldBlobTables);
+ }
+ else
+ {
+ $where = "WHERE period NOT IN (".implode(',', $this->reportPeriodsToKeep).")";
+ foreach ($oldBlobTables as $table)
+ {
+ Piwik_DeleteAllRows($table, $where, $this->maxRowsToDeletePerQuery);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns an array describing what data would be purged if purging were invoked.
+ *
+ * This function returns an array that maps table names with the number of rows
+ * that will be deleted. If a table name is mapped with self::DROP_TABLE, the table
+ * will be dropped.
+ *
+ * @return array
+ */
+ public function getPurgeEstimate()
+ {
+ $result = array();
+
+ // get archive tables that will be purged
+ list($oldNumericTables, $oldBlobTables) = $this->getArchiveTablesToPurge();
+
+ // deal w/ numeric tables
+ if ($this->keepBasicMetrics == 1)
+ {
+ // figure out which rows will be deleted
+ foreach ($oldNumericTables as $table)
+ {
+ $rowCount = $this->getNumericTableDeleteCount($table);
+ if ($rowCount > 0)
+ {
+ $result[$table] = $rowCount;
+ }
+ }
+ }
+ else
+ {
+ // not keeping any metrics, so drop the entire table
+ foreach ($oldNumericTables as $table)
+ {
+ $result[$table] = self::DROP_TABLE;
+ }
+ }
+
+ // deal w/ blob tables
+ if (!empty($this->reportPeriodsToKeep))
+ {
+ // figure out which rows will be deleted
+ foreach ($oldBlobTables as $table)
+ {
+ $rowCount = $this->getBlobTableDeleteCount($table);
+ if ($rowCount > 0)
+ {
+ $result[$table] = $rowCount;
+ }
+ }
+ }
+ else
+ {
+ // not keeping any reports, so drop all tables
+ foreach ($oldBlobTables as $table)
+ {
+ $result[$table] = self::DROP_TABLE;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Utility function that finds every archive table whose reports are considered
+ * old.
+ *
+ * @return array An array of two arrays. The first holds the numeric archive table
+ * names, and the second holds the blob archive table names.
+ */
+ private function getArchiveTablesToPurge()
+ {
+ // get month for which reports as old or older than, should be deleted
+ // reports whose creation date <= this month will be deleted
+ // (NOTE: we ignore how far we are in the current month)
+ $toRemoveDate = Piwik_Date::factory('today')->subMonth(1 + $this->deleteReportsOlderThan);
+ $toRemoveYear = (int)$toRemoveDate->toString('Y');
+ $toRemoveMonth = (int)$toRemoveDate->toString('m');
+
+ // find all archive tables that are older than N months
+ $oldNumericTables = array();
+ $oldBlobTables = array();
+ foreach (Piwik::getTablesInstalled() as $table)
+ {
+ if (preg_match("/archive_(numeric|blob)_([0-9]+)_([0-9]+)/", $table, $matches))
+ {
+ $type = $matches[1];
+ $year = (int)$matches[2];
+ $month = (int)$matches[3];
+
+ if (self::shouldReportBePurged($year, $month, $toRemoveDate))
+ {
+ if ($type == "numeric")
+ {
+ $oldNumericTables[] = $table;
+ }
+ else
+ {
+ $oldBlobTables[] = $table;
+ }
+ }
+ }
+ }
+
+ return array($oldNumericTables, $oldBlobTables);
+ }
+
+ /**
+ * Returns true if a report with the given year & month should be purged or not.
+ *
+ * @param int $reportDateYear The year of the report in question.
+ * @param int $reportDateMonth The month of the report in question.
+ * @param Piwik_Date $reportsOlderThan The date a report must be older than in order to be purged.
+ */
+ public static function shouldReportBePurged( $reportDateYear, $reportDateMonth, $toRemoveDate )
+ {
+ $toRemoveYear = (int)$toRemoveDate->toString('Y');
+ $toRemoveMonth = (int)$toRemoveDate->toString('m');
+
+ return $reportDateYear < $toRemoveYear
+ || ($reportDateYear == $toRemoveYear && $reportDateMonth <= $toRemoveMonth);
+ }
+
+ private function getNumericTableDeleteCount( $table )
+ {
+ $sql = "SELECT COUNT(*) FROM $table WHERE name IN ('".implode("','", $this->metricsToPurge)."')";
+ return (int)Piwik_FetchOne($sql);
+ }
+
+ private function getBlobTableDeleteCount( $table )
+ {
+ $sql = "SELECT COUNT(*) FROM $table WHERE period NOT IN (".implode(',', $this->reportPeriodsToKeep).")";
+ return (int)Piwik_FetchOne($sql);
+ }
+
+ /**
+ * Utility function. Creates a new instance of ReportsPurger with the supplied array
+ * of settings.
+ *
+ * $settings must contain the following keys:
+ * -'delete_reports_older_than': The number of months after which reports/metrics are
+ * considered old.
+ * -'delete_reports_keep_basic_metrics': 1 if basic metrics should be kept, 0 if otherwise.
+ * -'delete_reports_keep_day_reports': 1 if daily reports should be kept, 0 if otherwise.
+ * -'delete_reports_keep_week_reports': 1 if weekly reports should be kept, 0 if otherwise.
+ * -'delete_reports_keep_month_reports': 1 if monthly reports should be kept, 0 if otherwise.
+ * -'delete_reports_keep_year_reports': 1 if yearly reports should be kept, 0 if otherwise.
+ * -'delete_logs_max_rows_per_query': Maximum number of rows to delete in one DELETE query.
+ */
+ public static function make( $settings, $metricsToPurge )
+ {
+ return new Piwik_PrivacyManager_ReportsPurger(
+ $settings['delete_reports_older_than'],
+ $settings['delete_reports_keep_basic_metrics'] == 1,
+ self::getReportPeriodsToKeep($settings),
+ $metricsToPurge,
+ $settings['delete_logs_max_rows_per_query']
+ );
+ }
+
+ /**
+ * Utility function that returns an array period values based on the 'delete_reports_keep_*'
+ * settings. The period values returned are the integer values stored in the DB.
+ *
+ * @param array $deleteReportSettings The settings to use.
+ * @return array An array of period values that should be kept when purging old data.
+ */
+ private static function getReportPeriodsToKeep( $settings )
+ {
+ $keepReportPeriods = array();
+ foreach (Piwik::$idPeriods as $strPeriod => $intPeriod)
+ {
+ if ($strPeriod == 'range')
+ {
+ continue;
+ }
+
+ $optionName = "delete_reports_keep_{$strPeriod}_reports";
+ if ($settings[$optionName] == 1)
+ {
+ $keepReportPeriods[] = $intPeriod;
+ }
+ }
+ return $keepReportPeriods;
+ }
+}
+
diff --git a/plugins/PrivacyManager/templates/databaseSize.tpl b/plugins/PrivacyManager/templates/databaseSize.tpl
new file mode 100755
index 0000000000..fc3f6e956e
--- /dev/null
+++ b/plugins/PrivacyManager/templates/databaseSize.tpl
@@ -0,0 +1,4 @@
+<p>Current database size: {$dbStats.currentSize}</p>
+<p>Estimated database size after purge: {$dbStats.sizeAfterPurge}</p>
+<p>Estimated space saved: {$dbStats.spaceSaved}</p>
+
diff --git a/plugins/PrivacyManager/templates/privacySettings.js b/plugins/PrivacyManager/templates/privacySettings.js
index 4a778f957e..9c029cc7a0 100644
--- a/plugins/PrivacyManager/templates/privacySettings.js
+++ b/plugins/PrivacyManager/templates/privacySettings.js
@@ -5,21 +5,144 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-function toggleBlock(id, value) {
- $('#' + id).toggle(value == 1);
-}
-
$(document).ready(function() {
- $(function() {
- toggleBlock("deleteLogSettings", $("input[name=deleteEnable]:checked").val());
- toggleBlock("anonymizeIPenabled", $("input[name=anonymizeIPEnable]:checked").val());
- });
-
+ function toggleBlock(id, value) {
+ $('#' + id).toggle(value == 1);
+ }
+
+ // reloads purged database size estimate
+ var currentRequest;
+ function reloadDbStats() {
+ if (currentRequest) {
+ currentRequest.abort();
+ }
+
+ $('#deleteDataEstimate').html('');
+ $('#deleteDataEstimateSect .loadingPiwik').show();
+
+ currentRequest = $.ajax({
+ type: 'GET',
+ url: 'index.php?module=PrivacyManager&action=getDatabaseSize',
+ dataType: 'html',
+ async: true,
+ error: piwikHelper.ajaxHandleError, // Callback when the request fails
+ data: $('#formDeleteSettings').serialize(),
+ success: function(data) {
+ currentRequest = undefined;
+ $('#deleteDataEstimateSect .loadingPiwik').hide();
+ $('#deleteDataEstimate').html(data);
+ }
+ });
+ }
+
+ // make sure certain sections only display if their corresponding features are enabled
$('input[name=anonymizeIPEnable]').click(function() {
toggleBlock("anonymizeIPenabled", $(this).val());
});
$('input[name=deleteEnable]').click(function() {
toggleBlock("deleteLogSettings", $(this).val());
+ }).change(reloadDbStats);
+
+ $('input[name=deleteReportsEnable]').click(function() {
+ toggleBlock("deleteReportsSettings", $(this).val());
+ }).change(reloadDbStats);
+
+ // initial toggling calls
+ $(function() {
+ toggleBlock("deleteLogSettings", $("input[name=deleteEnable]:checked").val());
+ toggleBlock("anonymizeIPenabled", $("input[name=anonymizeIPEnable]:checked").val());
+ toggleBlock("deleteReportsSettings", $("input[name=deleteReportsEnable]:checked").val());
+ });
+
+ // make sure the DB size estimate is reloaded every time a delete logs/reports setting is changed
+ $('#formDeleteSettings input[type=text]').each(function() {
+ $(this).change(reloadDbStats);
+ });
+ $('#formDeleteSettings input[type=checkbox]').each(function() {
+ $(this).click(reloadDbStats);
+ });
+
+ // make sure when the delete log/report settings are submitted, a confirmation popup is
+ // displayed first
+ $('#deleteLogSettingsSubmit').click(function(e) {
+ var deletingLogs = $("input[name=deleteEnable]:checked").val() == 1,
+ deletingReports = $("input[name=deleteReportsEnable]:checked").val() == 1,
+ confirm_id;
+
+ // hide all confirmation texts, then show the correct one based on what
+ // type of deletion is enabled.
+ $('#confirmDeleteSettings>h2').each(function() {
+ $(this).hide();
+ });
+
+ if (deletingLogs)
+ {
+ confirm_id = deletingReports ? "deleteBothConfirm" : "deleteLogsConfirm";
+ }
+ else if (deletingReports)
+ {
+ confirm_id = "deleteReportsConfirm";
+ }
+
+ if (confirm_id)
+ {
+ $("#" + confirm_id).show();
+ e.preventDefault();
+
+ piwikHelper.modalConfirm('#confirmDeleteSettings', {
+ yes: function() {
+ $('#formDeleteSettings').submit();
+ }
+ });
+ }
+ else
+ {
+ $('#formDeleteSettings').submit();
+ }
+ });
+
+ // execute purge now link click
+ $('#purgeDataNowLink').click(function(e) {
+ e.preventDefault();
+
+ var link = this;
+
+ // if any option has been modified, abort purging and instruct user to save first
+ var modified = false;
+ $('#formDeleteSettings input').each(function() {
+ if (this.type === 'checkbox' || this.type === 'radio') {
+ modified |= this.defaultChecked !== this.checked;
+ } else {
+ modified |= this.defaultValue !== this.value;
+ }
+ });
+
+ if (modified) {
+ piwikHelper.modalConfirm('#saveSettingsBeforePurge', {yes: function() {}});
+ return;
+ }
+
+ // ask user if they really want to delete their old data
+ piwikHelper.modalConfirm('#confirmPurgeNow', {
+ yes: function() {
+ $(link).hide();
+ $('#deleteSchedulingSettings .loadingPiwik').show();
+
+ // execute a data purge
+ $.ajax({
+ type: 'POST',
+ url: 'index.php?module=PrivacyManager&action=executeDataPurge',
+ dataType: 'html',
+ async: true,
+ error: piwikHelper.ajaxHandleError, // Callback when the request fails
+ success: function(data) { // ajax request will return new database estimate
+ $('#deleteSchedulingSettings .loadingPiwik').hide();
+ $(link).show();
+ $('#deleteDataEstimate').html(data);
+ }
+ });
+ }
+ });
});
});
diff --git a/plugins/PrivacyManager/templates/privacySettings.tpl b/plugins/PrivacyManager/templates/privacySettings.tpl
index d9680f8405..b3037bb628 100644
--- a/plugins/PrivacyManager/templates/privacySettings.tpl
+++ b/plugins/PrivacyManager/templates/privacySettings.tpl
@@ -51,92 +51,139 @@ See also our official guide <b><a href='http://piwik.org/privacy/' target='_blan
<input type="submit" value="{'General_Save'|translate}" id="privacySettingsSubmit" class="submit"/>
</form>
+<div class="ui-confirm" id="confirmDeleteSettings">
+ <h2 id="deleteLogsConfirm">{'PrivacyManager_DeleteLogsConfirm'|translate}</h2>
+ <h2 id="deleteReportsConfirm">{'PrivacyManager_DeleteReportsConfirm'|translate}</h2>
+ <h2 id="deleteBothConfirm">{'PrivacyManager_DeleteBothConfirm'|translate}</h2>
+ <input role="yes" type="button" value="{'General_Yes'|translate}" />
+ <input role="no" type="button" value="{'General_No'|translate}" />
+</div>
+
+<div class="ui-confirm" id="saveSettingsBeforePurge">
+ <h2>{'PrivacyManager_SaveSettingsBeforePurge'|translate}</h2>
+ <input role="yes" type="button" value="{'General_Ok'|translate}"/>
+</div>
+
+<div class="ui-confirm" id="confirmPurgeNow">
+ <h2>{'PrivacyManager_PurgeNowConfirm'|translate}</h2>
+ <input role="yes" type="button" value="{'General_Yes'|translate}" />
+ <input role="no" type="button" value="{'General_No'|translate}" />
+</div>
+
<a name="deleteLogsAnchor"></a>
-<h2>{'PrivacyManager_DeleteLogSettings'|translate}</h2>
-<p>{'PrivacyManager_DeleteLogDescription'|translate}</p>
+<h2>{'PrivacyManager_DeleteDataSettings'|translate}</h2>
+<p>{'PrivacyManager_DeleteDataDescription'|translate}</p>
<form method="post" action="{url action=index form=formDeleteSettings}" id="formDeleteSettings" name="formMaskLength">
- <div id='deleteLogSettingEnabled'>
- <table class="adminTable" style='width:800px;'>
- <tr>
- <td width="250">{'PrivacyManager_UseDeleteLog'|translate}<br/>
-
- </td>
- <td width='500'>
- <label><input type="radio" name="deleteEnable" value="1" {if $deleteLogs.config.delete_logs_enable eq '1'}
- checked {/if}/> {'General_Yes'|translate}</label>
- <label><input type="radio" name="deleteEnable" value="0"
- style="margin-left:20px;" {if $deleteLogs.config.delete_logs_enable eq '0'}
- checked {/if}/> {'General_No'|translate}
- </label>
- <span class="ajaxSuccess">
- {'PrivacyManager_DeleteLogDescription2'|translate}
- <a href="http://piwik.org/faq/general/#faq_125" target="_blank">
- {'General_ClickHere'|translate}
- </a>
- </span>
- </td>
- <td width="200">
- {'PrivacyManager_DeleteLogInfo'|translate:$deleteLogs.deleteTables|inlineHelp}
- </td>
- </tr>
- </table>
- </div>
+ <table class="adminTable" style='width:800px;'>
+ <tr id='deleteLogSettingEnabled'>
+ <td width="250">{'PrivacyManager_UseDeleteLog'|translate}<br/>
- <div id="deleteLogSettings">
- <table class="adminTable" style='width:800px;'>
- <tr>
- <td width="250">&nbsp;</td>
- <td width="500">
- <label>{'PrivacyManager_DeleteLogsOlderThan'|translate}
- <input type="text" id="deleteOlderThan" value="{$deleteLogs.config.delete_logs_older_than}" style="width:30px;"
- name="deleteOlderThan">
- {'CoreHome_PeriodDays'|translate}</label><br/>
- <span class="form-description">{'PrivacyManager_LeastDaysInput'|translate:"7"}</span>
- </td>
- <td width="200">
+ </td>
+ <td width='500'>
+ <label><input type="radio" name="deleteEnable" value="1" {if $deleteData.config.delete_logs_enable eq '1'}
+ checked {/if}/> {'General_Yes'|translate}</label>
+ <label><input type="radio" name="deleteEnable" value="0"
+ style="margin-left:20px;" {if $deleteData.config.delete_logs_enable eq '0'}
+ checked {/if}/> {'General_No'|translate}
+ </label>
+ <span class="ajaxSuccess">
+ {'PrivacyManager_DeleteLogDescription2'|translate}
+ <a href="http://piwik.org/faq/general/#faq_125" target="_blank">
+ {'General_ClickHere'|translate}
+ </a>
+ </span>
+ </td>
+ <td width="200">
+ {'PrivacyManager_DeleteLogInfo'|translate:$deleteData.deleteTables|inlineHelp}
+ </td>
+ </tr>
+ <tr id="deleteLogSettings">
+ <td width="250">&nbsp;</td>
+ <td width="500">
+ <label>{'PrivacyManager_DeleteLogsOlderThan'|translate}
+ <input type="text" id="deleteOlderThan" value="{$deleteData.config.delete_logs_older_than}" style="width:30px;"
+ name="deleteOlderThan"/>
+ {'CoreHome_PeriodDays'|translate}</label><br/>
+ <span class="form-description">{'PrivacyManager_LeastDaysInput'|translate:"7"}</span>
+ </td>
+ <td width="200">
- </td>
- </tr>
- <tr>
- <td width="250">&nbsp;</td>
- <td width="500">
- {'PrivacyManager_DeleteLogInterval'|translate}
- <select id="deleteLowestInterval" name="deleteLowestInterval">
- <option {if $deleteLogs.config.delete_logs_schedule_lowest_interval eq '1'} selected="selected" {/if}
- value="1"> {'CoreHome_PeriodDay'|translate}</option>
- <option {if $deleteLogs.config.delete_logs_schedule_lowest_interval eq '7'} selected="selected" {/if}
- value="7">{'CoreHome_PeriodWeek'|translate}</option>
- <option {if $deleteLogs.config.delete_logs_schedule_lowest_interval eq '30'} selected="selected" {/if}
- value="30">{'CoreHome_PeriodMonth'|translate}</option>
- </select>
- </td>
- <td width="200">
- {capture assign=purgeStats}
- {if $deleteLogs.lastRun}<strong>{'PrivacyManager_LastDelete'|translate}:</strong>
- {$deleteLogs.lastRunPretty}
- <br/><br/>{/if}
- <strong>{'PrivacyManager_NextDelete'|translate}:</strong>
- {$deleteLogs.nextRunPretty}
- {/capture}
- {$purgeStats|inlineHelp}
- </td>
- </tr>
- <tr>
- <td width="250">&nbsp;</td>
- <td width="500">
- {'PrivacyManager_DeleteMaxRows'|translate}
- <select id="deleteMaxRows" name="deleteMaxRows">
- <option {if $deleteLogs.config.delete_max_rows_per_run eq '100'} selected="selected" {/if} value="100">100.000</option>
- <option {if $deleteLogs.config.delete_max_rows_per_run eq '500'} selected="selected" {/if} value="500">500.000</option>
- <option {if $deleteLogs.config.delete_max_rows_per_run eq '1000'} selected="selected" {/if} value="1000">1.000.000</option>
- <option {if $deleteLogs.config.delete_max_rows_per_run eq '0'} selected="selected" {/if} value="0">{'PrivacyManager_DeleteMaxRowsNoLimit'|translate}</option>
- </select>
- </td>
- <td width="200"></td>
- </tr>
- </table>
- </div>
- <input type="submit" value="{'General_Save'|translate}" id="deleteLogSettingsSubmit" class="submit"/>
+ </td>
+ </tr>
+ <tr id='deleteReportsSettingEnabled'>
+ <td width="250">{'PrivacyManager_UseDeleteReports'|translate}<br/>
+
+ </td>
+ <td width="500">
+ <label><input type="radio" name="deleteReportsEnable" value="1" {if $deleteData.config.delete_reports_enable eq '1'}checked="true"{/if}/> {'General_Yes'|translate}</label>
+ <label><input type="radio" name="deleteReportsEnable" value="0" {if $deleteData.config.delete_reports_enable eq '0'}checked="true"{/if} style="margin-left:20px;"/> {'General_No'|translate}</label>
+ <span class="ajaxSuccess">
+ {'PrivacyManager_DeleteReportsInfo'|translate}
+ </span>
+ </td>
+ <td width="200">
+ {'PrivacyManager_DeleteReportsDetailedInfo'|translate|inlineHelp}
+ </td>
+ </tr>
+ <tr id='deleteReportsSettings'>
+ <td width="250">&nbsp;</td>
+ <td width="500">
+ <label>{'PrivacyManager_DeleteReportsOlderThan'|translate}
+ <input type="text" id="deleteReportsOlderThan" value="{$deleteData.config.delete_reports_older_than}" style="width:30px;"
+ name="deleteReportsOlderThan"/>
+ {'CoreHome_PeriodMonths'|translate}
+ </label><br/>
+ <span class="form-description">{'PrivacyManager_LeastMonthsInput'|translate:"3"}</span><br/><br/>
+ <label><input type="checkbox" name="deleteReportsKeepBasic" value="1" {if $deleteData.config.delete_reports_keep_basic_metrics}checked="true"{/if}>{'PrivacyManager_KeepBasicMetrics'|translate}<span class="form-description">{'General_Recommended'|translate}</span></input>
+ </label><br/><br/>
+ <label>{'PrivacyManager_KeepDataFor'|translate}</label><br/><br/>
+ <input type="checkbox" name="deleteReportsKeepDay" value="1" {if $deleteData.config.delete_reports_keep_day_reports}checked="true"{/if}>{'General_DailyReports'|translate}</input><br/>
+ <input type="checkbox" name="deleteReportsKeepWeek" value="1" {if $deleteData.config.delete_reports_keep_week_reports}checked="true"{/if}>{'General_WeeklyReports'|translate}</input><br/>
+ <input type="checkbox" name="deleteReportsKeepMonth" value="1" {if $deleteData.config.delete_reports_keep_month_reports}checked="true"{/if}>{'General_MonthlyReports'|translate}<span class="form-description">{'General_Recommended'|translate}</span></input><br/>
+ <input type="checkbox" name="deleteReportsKeepYear" value="1" {if $deleteData.config.delete_reports_keep_year_reports}checked="true"{/if}>{'General_YearlyReports'|translate}<span class="form-description">{'General_Recommended'|translate}</span></input><br/>
+ </td>
+ <td width="200">
+
+ </td>
+ </tr>
+ <tr id="deleteDataEstimateSect">
+ <td width="250">{'PrivacyManager_ReportsDataSavedEstimate'|translate}<br/></td>
+ <td width="500">
+ <div id="deleteDataEstimate">{include file="PrivacyManager/templates/databaseSize.tpl" dbStats=$deleteDbStats}</div>
+ <span class='loadingPiwik' style='display:none'><img src='/themes/default/images/loading-blue.gif' /> {'General_LoadingData'|translate}</span>
+ </td>
+ <td width="200">
+
+ </td>
+ </tr>
+ <tr id="deleteSchedulingSettings">
+ <td width="250">{'PrivacyManager_DeleteSchedulingSettings'|translate}<br/></td>
+ <td width="500">
+ {'PrivacyManager_DeleteDataInterval'|translate}
+ <select id="deleteLowestInterval" name="deleteLowestInterval">
+ <option {if $deleteData.config.delete_logs_schedule_lowest_interval eq '1'} selected="selected" {/if}
+ value="1"> {'CoreHome_PeriodDay'|translate}</option>
+ <option {if $deleteData.config.delete_logs_schedule_lowest_interval eq '7'} selected="selected" {/if}
+ value="7">{'CoreHome_PeriodWeek'|translate}</option>
+ <option {if $deleteData.config.delete_logs_schedule_lowest_interval eq '30'} selected="selected" {/if}
+ value="30">{'CoreHome_PeriodMonth'|translate}</option>
+ </select><br/><br/>
+ <em><a id="purgeDataNowLink" href="#">{'PrivacyManager_PurgeNow'|translate}</a></em>
+ <span class='loadingPiwik' style='display:none'><img src='/themes/default/images/loading-blue.gif' /> {'PrivacyManager_PurgingData'|translate}</span>
+ </td>
+ <td width="200">
+ {capture assign=purgeStats}
+ {if $deleteData.lastRun}<strong>{'PrivacyManager_LastDelete'|translate}:</strong>
+ {$deleteData.lastRunPretty}
+ <br/><br/>{/if}
+ <strong>{'PrivacyManager_NextDelete'|translate}:</strong>
+ {$deleteData.nextRunPretty}
+ {/capture}
+ {$purgeStats|inlineHelp}
+ </td>
+ </tr>
+ </table>
+ <input type="button" value="{'General_Save'|translate}" id="deleteLogSettingsSubmit" class="submit"/>
</form>
{/if}
diff --git a/plugins/PrivacyManager/tests/PrivacyManager.test.php b/plugins/PrivacyManager/tests/PrivacyManager.test.php
new file mode 100755
index 0000000000..ca620b8844
--- /dev/null
+++ b/plugins/PrivacyManager/tests/PrivacyManager.test.php
@@ -0,0 +1,601 @@
+<?php
+if(!defined('PIWIK_CONFIG_TEST_INCLUDED'))
+{
+ require_once dirname(__FILE__)."/../../../tests/config_test.php";
+}
+
+require_once PIWIK_INCLUDE_PATH . '/tests/integration/Integration.php';
+
+class Test_Piwik_PrivacyManager extends Test_Integration
+{
+ // constants used in checking whether numeric tables are populated correctly.
+ // 'done' entries exist for every period, even if there's no metric data, so we need the
+ // total archive count for each month.
+ const TOTAL_JAN_ARCHIVE_COUNT = 37; // 31 + 4 + 1 + 1;
+ const TOTAL_FEB_ARCHIVE_COUNT = 34; // 29 + 4 + 1;
+
+ // the number of archive entries for a single metric if no purging is done. this #
+ // is dependent on the number of periods for which there were visits.
+ const JAN_METRIC_ARCHIVE_COUNT = 11; // 5 days + 4 weeks + 1 month + 1 year
+ const FEB_METRIC_ARCHIVE_COUNT = 11; // 6 days + 4 weeks + 1 month
+
+ private $idSite = null;
+ private $dateTime = null;
+ private $instance = null;
+ private $daysAgoStart = 50;
+
+ public function __construct( $title = '' )
+ {
+ parent::__construct($title);
+ $this->dateTime = Piwik_Date::factory('2012-02-28');
+ }
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ Piwik_TablePartitioning::$tablesAlreadyInstalled = null;
+
+ // purging depends upon today's date, so 'older_than' parts must be dependent upon today
+ $today = Piwik_Date::factory('today');
+ $daysSinceToday = ($today->getTimestamp() - $this->dateTime->getTimestamp()) / (24 * 60 * 60);
+
+ $monthsSinceToday = 0;
+ for ($date = $today; $date->toString('Y-m') != $this->dateTime->toString('Y-m'); $date = $date->subMonth(1))
+ {
+ ++$monthsSinceToday;
+ }
+
+ // set default config
+ $settings = array();
+ $settings['delete_logs_enable'] = 1;
+ // purging log data from before 2012-01-24
+ $settings['delete_logs_older_than'] = 35 + $daysSinceToday;
+ $settings['delete_max_rows_per_run'] = 0;
+ $settings['delete_logs_schedule_lowest_interval'] = 7;
+ $settings['delete_reports_enable'] = 1;
+ $settings['delete_reports_older_than'] = $monthsSinceToday;
+ $settings['delete_reports_keep_basic_metrics'] = 0;
+ $settings['delete_reports_keep_day_reports'] = 0;
+ $settings['delete_reports_keep_week_reports'] = 0;
+ $settings['delete_reports_keep_month_reports'] = 0;
+ $settings['delete_reports_keep_year_reports'] = 0;
+ Piwik_PrivacyManager::savePurgeDataSettings($settings);
+
+ $this->instance = new Piwik_PrivacyManager();
+ }
+
+ public function tearDown()
+ {
+ parent::tearDown();
+
+ // remove archive tables (integration test teardown will only truncate)
+ $archiveTables = $this->getArchiveTableNames();
+ $archiveTables = array_merge($archiveTables['numeric'], $archiveTables['blob']);
+ foreach ($archiveTables as $table)
+ {
+ Piwik_Query("DROP TABLE IF EXISTS ".Piwik_Common::prefixTable($table));
+ }
+
+ // refresh table name caches so next test will pass
+ Piwik_TablePartitioning::$tablesAlreadyInstalled = null;
+ Piwik::getTablesInstalled(true);
+ }
+
+ /** Make sure the first time deleteLogData is run, nothing happens. */
+ public function test_deleteLogData_initialRun()
+ {
+ $this->addLogData();
+ $this->addReportData();
+
+ $this->instance->deleteLogData();
+
+ // check that initial option is set
+ $this->assertEqual(
+ 1, Piwik_GetOption(Piwik_PrivacyManager::OPTION_LAST_DELETE_PIWIK_LOGS_INITIAL));
+
+ // perform other checks
+ $this->checkNoDataChanges();
+ }
+
+ /** Make sure the first time deleteReportData is run, nothing happens. */
+ public function test_deleteReportData_initialRun()
+ {
+ $this->addLogData();
+ $this->addReportData();
+
+ $this->instance->deleteReportData();
+
+ // check that initial option is set
+ $this->assertEqual(
+ 1, Piwik_GetOption(Piwik_PrivacyManager::OPTION_LAST_DELETE_PIWIK_LOGS_INITIAL));
+
+ // perform other checks
+ $this->checkNoDataChanges();
+ }
+
+ /** Make sure the task is not run when its scheduled for later. */
+ public function test_purgeData_notTimeToRun()
+ {
+ $this->addLogData();
+ $this->addReportData();
+
+ $yesterdaySecs = Piwik_Date::factory('yesterday')->getTimestamp();
+
+ Piwik_SetOption(Piwik_PrivacyManager::OPTION_LAST_DELETE_PIWIK_LOGS_INITIAL, 1);
+ Piwik_SetOption(Piwik_PrivacyManager::OPTION_LAST_DELETE_PIWIK_LOGS, $yesterdaySecs);
+ Piwik_SetOption(Piwik_PrivacyManager::OPTION_LAST_DELETE_PIWIK_REPORTS, $yesterdaySecs);
+ $this->instance->deleteLogData();
+ $this->instance->deleteReportData();
+
+ // perform checks
+ $this->checkNoDataChanges();
+ }
+
+ /** Make sure purging data runs when scheduled. */
+ public function test_purgeData_notInitialAndTimeToRun()
+ {
+ $this->addLogData();
+ $this->addReportData();
+
+ // get purge data prediction
+ $prediction = Piwik_PrivacyManager::getPurgeEstimate();
+
+ // perform checks on prediction
+ $expectedPrediction = array(
+ Piwik_Common::prefixTable('log_conversion') => 6,
+ Piwik_Common::prefixTable('log_link_visit_action') => 6,
+ Piwik_Common::prefixTable('log_visit') => 3,
+ Piwik_Common::prefixTable('log_conversion_item') => 3,
+ Piwik_Common::prefixTable('archive_numeric_2012_01') => -1,
+ Piwik_Common::prefixTable('archive_blob_2012_01') => -1
+ );
+ $this->assertEqual($expectedPrediction, $prediction);
+
+ // purge data
+ $this->setTimeToRun();
+ $this->instance->deleteLogData();
+ $this->instance->deleteReportData();
+
+ // perform checks
+ $this->checkLogDataPurged();
+
+ $archiveTables = $this->getArchiveTableNames();
+
+ // January numeric table should be dropped
+ $this->assertFalse($this->tableExists($archiveTables['numeric'][0])); // January
+
+ // Check february metric count (5 metrics per period w/ visits + 1 'done' archive for every period)
+ $febRowCount = self::FEB_METRIC_ARCHIVE_COUNT * 5 + self::TOTAL_FEB_ARCHIVE_COUNT;
+ $this->assertEqual($febRowCount, $this->getTableCount($archiveTables['numeric'][1])); // February
+
+ // January blob table should be dropped
+ $this->assertFalse($this->tableExists($archiveTables['blob'][0])); // January
+
+ // Check february blob count (1 blob per period w/ visits)
+ $this->assertEqual(self::FEB_METRIC_ARCHIVE_COUNT, $this->getTableCount($archiveTables['blob'][1])); // February
+ }
+
+ /** Make sure nothing happens when deleting logs & reports are both disabled. */
+ public function test_purgeData_bothDisabled()
+ {
+ Piwik_PrivacyManager::savePurgeDataSettings(array(
+ 'delete_logs_enable' => 0,
+ 'delete_reports_enable' => 0
+ ));
+
+ $this->addLogData();
+ $this->addReportData();
+
+ // get purge data prediction
+ $prediction = Piwik_PrivacyManager::getPurgeEstimate();
+
+ // perform checks on prediction
+ $expectedPrediction = array();
+ $this->assertEqual($expectedPrediction, $prediction);
+
+ // purge data
+ $this->setTimeToRun();
+ $this->instance->deleteLogData();
+ $this->instance->deleteReportData();
+
+ // perform checks
+ $this->checkNoDataChanges();
+ }
+
+ /** Test that purgeData works when there's no data. */
+ public function test_purgeData_deleteLogsNoData()
+ {
+ // get purge data prediction
+ $prediction = Piwik_PrivacyManager::getPurgeEstimate();
+
+ // perform checks on prediction
+ $expectedPrediction = array();
+ $this->assertEqual($expectedPrediction, $prediction);
+
+ // purge data
+ $this->setTimeToRun();
+ $this->instance->deleteLogData();
+ $this->instance->deleteReportData();
+
+ // perform checks
+ $this->assertEqual(0, $this->getTableCount('log_visit'));
+ $this->assertEqual(0, $this->getTableCount('log_conversion'));
+ $this->assertEqual(0, $this->getTableCount('log_link_visit_action'));
+ $this->assertEqual(0, $this->getTableCount('log_conversion_item'));
+
+ $archiveTables = $this->getArchiveTableNames();
+ $this->assertFalse($this->tableExists($archiveTables['numeric'][0])); // January
+ $this->assertFalse($this->tableExists($archiveTables['numeric'][1])); // February
+ $this->assertFalse($this->tableExists($archiveTables['blob'][0])); // January
+ $this->assertFalse($this->tableExists($archiveTables['blob'][1])); // February
+ }
+
+ /** Test that purgeData works correctly when the 'keep basic metrics' setting is set to true. */
+ public function test_purgeData_deleteReportsKeepBasicMetrics()
+ {
+ Piwik_PrivacyManager::savePurgeDataSettings(array(
+ 'delete_reports_keep_basic_metrics' => 1
+ ));
+
+ $this->addLogData();
+ $this->addReportData();
+
+ // get purge data prediction
+ $prediction = Piwik_PrivacyManager::getPurgeEstimate();
+
+ // perform checks on prediction
+ $expectedPrediction = array(
+ Piwik_Common::prefixTable('log_conversion') => 6,
+ Piwik_Common::prefixTable('log_link_visit_action') => 6,
+ Piwik_Common::prefixTable('log_visit') => 3,
+ Piwik_Common::prefixTable('log_conversion_item') => 3,
+ Piwik_Common::prefixTable('archive_blob_2012_01') => -1
+ );
+ $this->assertEqual($expectedPrediction, $prediction);
+
+ // purge data
+ $this->setTimeToRun();
+ $this->instance->deleteLogData();
+ $this->instance->deleteReportData();
+
+ // perform checks
+ $this->checkLogDataPurged();
+
+ $archiveTables = $this->getArchiveTableNames();
+
+ // all numeric metrics should be saved (5 metrics per period w/ visits + 1 'done' archive for every period)
+ $janRowCount = self::JAN_METRIC_ARCHIVE_COUNT * 5 + self::TOTAL_JAN_ARCHIVE_COUNT;
+ $this->assertEqual($janRowCount, $this->getTableCount($archiveTables['numeric'][0])); // January
+
+ // check february numerics not deleted (5 metrics per period w/ visits + 1 'done' archive for every period)
+ $febRowCount = self::FEB_METRIC_ARCHIVE_COUNT * 5 + self::TOTAL_FEB_ARCHIVE_COUNT;
+ $this->assertEqual($febRowCount, $this->getTableCount($archiveTables['numeric'][1])); // February
+
+ // check that the january blob table was dropped
+ $this->assertFalse($this->tableExists($archiveTables['blob'][0])); // January
+
+ // check for no changes in the february blob table
+ $this->assertEqual(self::FEB_METRIC_ARCHIVE_COUNT, $this->getTableCount($archiveTables['blob'][1])); // February
+ }
+
+ /** Test that purgeData works correctly when the 'keep daily reports' setting is set to true. */
+ public function test_purgeData_deleteReportsKeepDailyReports()
+ {
+ Piwik_PrivacyManager::savePurgeDataSettings(array(
+ 'delete_reports_keep_day_reports' => 1
+ ));
+
+ $this->addLogData();
+ $this->addReportData();
+
+ // get purge data prediction
+ $prediction = Piwik_PrivacyManager::getPurgeEstimate();
+
+ // perform checks on prediction
+ $expectedPrediction = array(
+ Piwik_Common::prefixTable('log_conversion') => 6,
+ Piwik_Common::prefixTable('log_link_visit_action') => 6,
+ Piwik_Common::prefixTable('log_visit') => 3,
+ Piwik_Common::prefixTable('log_conversion_item') => 3,
+ Piwik_Common::prefixTable('archive_numeric_2012_01') => -1,
+ Piwik_Common::prefixTable('archive_blob_2012_01') => 6 // removing 4 weeks, 1 month & 1 year
+ );
+ $this->assertEqual($expectedPrediction, $prediction);
+
+ // purge data
+ $this->setTimeToRun();
+ $this->instance->deleteLogData();
+ $this->instance->deleteReportData();
+
+ // perform checks
+ $this->checkLogDataPurged();
+ $this->checkReportsAndMetricsPurged($janBlobsRemaining = 5); // 5 blobs for 5 days
+ }
+
+ /** Test that purgeData works correctly when the 'keep weekly reports' setting is set to true. */
+ public function test_purgeData_deleteReportsKeepWeeklyReports()
+ {
+ Piwik_PrivacyManager::savePurgeDataSettings(array(
+ 'delete_reports_keep_week_reports' => 1
+ ));
+
+ $this->addLogData();
+ $this->addReportData();
+
+ // get purge data prediction
+ $prediction = Piwik_PrivacyManager::getPurgeEstimate();
+
+ // perform checks on prediction
+ $expectedPrediction = array(
+ Piwik_Common::prefixTable('log_conversion') => 6,
+ Piwik_Common::prefixTable('log_link_visit_action') => 6,
+ Piwik_Common::prefixTable('log_visit') => 3,
+ Piwik_Common::prefixTable('log_conversion_item') => 3,
+ Piwik_Common::prefixTable('archive_numeric_2012_01') => -1,
+ Piwik_Common::prefixTable('archive_blob_2012_01') => 7 // 5 days, 1 month & 1 year to remove
+ );
+ $this->assertEqual($expectedPrediction, $prediction);
+
+ // purge data
+ $this->setTimeToRun();
+ $this->instance->deleteLogData();
+ $this->instance->deleteReportData();
+
+ // perform checks
+ $this->checkLogDataPurged();
+ $this->checkReportsAndMetricsPurged($janBlobsRemaining = 4); // 4 blobs for 4 weeks
+ }
+
+ /** Test that purgeData works correctly when the 'keep monthly reports' setting is set to true. */
+ public function test_purgeData_deleteReportsKeepMonthlyReports()
+ {
+ Piwik_PrivacyManager::savePurgeDataSettings(array(
+ 'delete_reports_keep_month_reports' => 1
+ ));
+
+ $this->addLogData();
+ $this->addReportData();
+
+ // get purge data prediction
+ $prediction = Piwik_PrivacyManager::getPurgeEstimate();
+
+ // perform checks on prediction
+ $expectedPrediction = array(
+ Piwik_Common::prefixTable('log_conversion') => 6,
+ Piwik_Common::prefixTable('log_link_visit_action') => 6,
+ Piwik_Common::prefixTable('log_visit') => 3,
+ Piwik_Common::prefixTable('log_conversion_item') => 3,
+ Piwik_Common::prefixTable('archive_numeric_2012_01') => -1,
+ Piwik_Common::prefixTable('archive_blob_2012_01') => 10 // 5 days, 4 weeks, 1 year to remove
+ );
+ $this->assertEqual($expectedPrediction, $prediction);
+
+ // purge data
+ $this->setTimeToRun();
+ $this->instance->deleteLogData();
+ $this->instance->deleteReportData();
+
+ // perform checks
+ $this->checkLogDataPurged();
+ $this->checkReportsAndMetricsPurged($janBlobsRemaining = 1); // 1 blob for 1 month
+ }
+
+ /** Test that purgeData works correctly when the 'keep yearly reports' setting is set to true. */
+ public function test_purgeData_deleteReportsKeepYearlyReports()
+ {
+ Piwik_PrivacyManager::savePurgeDataSettings(array(
+ 'delete_reports_keep_year_reports' => 1
+ ));
+
+ $this->addLogData();
+ $this->addReportData();
+
+ // get purge data prediction
+ $prediction = Piwik_PrivacyManager::getPurgeEstimate();
+
+ // perform checks on prediction
+ $expectedPrediction = array(
+ Piwik_Common::prefixTable('log_conversion') => 6,
+ Piwik_Common::prefixTable('log_link_visit_action') => 6,
+ Piwik_Common::prefixTable('log_visit') => 3,
+ Piwik_Common::prefixTable('log_conversion_item') => 3,
+ Piwik_Common::prefixTable('archive_numeric_2012_01') => -1,
+ Piwik_Common::prefixTable('archive_blob_2012_01') => 10 // 5 days, 4 weeks & 1 year to remove
+ );
+ $this->assertEqual($expectedPrediction, $prediction);
+
+ // purge data
+ $this->setTimeToRun();
+ $this->instance->deleteLogData();
+ $this->instance->deleteReportData();
+
+ // perform checks
+ $this->checkLogDataPurged();
+ $this->checkReportsAndMetricsPurged($janBlobsRemaining = 1); // 1 blob for 1 year
+ }
+
+ // --- utility functions follow ---
+
+ private function addLogData()
+ {
+ // tracks visits on the following days:
+ // - 2012-01-09
+ // - 2012-01-14
+ // - 2012-01-19
+ // - 2012-01-24
+ // - 2012-01-29
+ // - 2012-02-03
+ // - 2012-02-08
+ // - 2012-02-13
+ // - 2012-02-18
+ // - 2012-02-23
+ // - 2012-02-28
+ // 6 visits in feb, 5 in jan
+
+ $start = $this->dateTime;
+ $this->idSite = $this->createWebsite('2012-01-01', $ecommerce=1);
+ $idGoal = Piwik_Goals_API::getInstance()->addGoal($this->idSite, 'match all', 'url', 'http', 'contains');
+
+ for ($daysAgo = $this->daysAgoStart; $daysAgo >= 0; $daysAgo -= 5) // one visit every 5 days
+ {
+ $dateTime = $start->subDay($daysAgo)->toString();
+ $t = $this->getTracker($this->idSite, $dateTime, $defaultInit = true);
+
+ $t->setUrl("http://whatever.com");
+ $t->doTrackPageView('First page view');
+
+ $t->setUrl("http://whatever.com/42");
+ $t->doTrackPageView('Second page view');
+
+ $t->addEcommerceItem($sku = 'SKU2', $name = 'Canon SLR' , $category = 'Electronics & Cameras',
+ $price = 1500, $quantity = 1);
+ $t->doTrackEcommerceOrder($orderId = '937nsjusu '.$dateTime, $grandTotal = 1111.11, $subTotal = 1000,
+ $tax = 111, $shipping = 0.11, $discount = 666);
+ }
+ }
+
+ private function addReportData()
+ {
+ $archive = Piwik_Archive::build($this->idSite, 'year', $this->dateTime);
+ $archive->getNumeric('nb_visits', 'nb_hits');
+
+ Piwik_VisitorInterest_API::getInstance()->getNumberOfVisitsPerVisitDuration(
+ $this->idSite, 'year', $this->dateTime);
+
+ // months are added via the 'year' period, but weeks must be done manually
+ for ($daysAgo = $this->daysAgoStart; $daysAgo > 0; $daysAgo -= 7) // every week
+ {
+ $dateTime = $this->dateTime->subDay($daysAgo);
+
+ $archive = Piwik_Archive::build($this->idSite, 'week', $dateTime);
+ $archive->getNumeric('nb_visits');
+
+ Piwik_VisitorInterest_API::getInstance()->getNumberOfVisitsPerVisitDuration(
+ $this->idSite, 'week', $dateTime);
+ }
+
+ // when archiving is initiated, the archive metrics & reports for EVERY loaded plugin
+ // are archived. don't want this test to depend on every possible metric, so get rid of
+ // the unwanted archive data now.
+ $metricsToSave = array(
+ 'nb_visits',
+ 'nb_actions',
+ Piwik_Goals::getRecordName('revenue'),
+ Piwik_Goals::getRecordName('nb_conversions', 1),
+ Piwik_Goals::getRecordName('revenue', Piwik_Tracker_GoalManager::IDGOAL_ORDER)
+ );
+
+ $archiveTables = $this->getArchiveTableNames();
+ foreach ($archiveTables['numeric'] as $table)
+ {
+ $realTable = Piwik_Common::prefixTable($table);
+ Piwik_Query("DELETE FROM $realTable WHERE name NOT IN ('".implode("','", $metricsToSave)."', 'done')");
+ }
+ foreach ($archiveTables['blob'] as $table)
+ {
+ $realTable = Piwik_Common::prefixTable($table);
+ Piwik_Query("DELETE FROM $realTable WHERE name NOT IN ('VisitorInterest_timeGap')");
+ }
+ }
+
+ private function checkNoDataChanges()
+ {
+ // 11 visits total w/ 2 actions per visit & 2 conversions per visit. 1 e-commerce order per visit.
+ $this->assertEqual(11, $this->getTableCount('log_visit'));
+ $this->assertEqual(22, $this->getTableCount('log_conversion'));
+ $this->assertEqual(22, $this->getTableCount('log_link_visit_action'));
+ $this->assertEqual(11, $this->getTableCount('log_conversion_item'));
+
+ $archiveTables = $this->getArchiveTableNames();
+
+ // 2 entries per period w/ visits (5 for each metric) + 1 entry for every period in the month (the 'done' rows)
+ $janMetricCount = self::JAN_METRIC_ARCHIVE_COUNT * 5 + self::TOTAL_JAN_ARCHIVE_COUNT;
+ $this->assertEqual($janMetricCount, $this->getTableCount($archiveTables['numeric'][0])); // January
+
+ $febMetricCount = self::FEB_METRIC_ARCHIVE_COUNT * 5 + self::TOTAL_FEB_ARCHIVE_COUNT;
+ $this->assertEqual($febMetricCount, $this->getTableCount($archiveTables['numeric'][1])); // February
+
+ // 1 entry per period w/ visits
+ $this->assertEqual(self::JAN_METRIC_ARCHIVE_COUNT, $this->getTableCount($archiveTables['blob'][0])); // January
+ $this->assertEqual(self::FEB_METRIC_ARCHIVE_COUNT, $this->getTableCount($archiveTables['blob'][1])); // February
+ }
+
+ /**
+ * Helper method. Performs checks after reports are purged. Checks that the january numeric table
+ * was dropped, that the february metric & blob tables are unaffected, and that the january blob
+ * table has a certain number of blobs.
+ */
+ private function checkReportsAndMetricsPurged( $janBlobsRemaining )
+ {
+ $archiveTables = $this->getArchiveTableNames();
+
+ // check that the january numeric table was dropped
+ $this->assertFalse($this->tableExists($archiveTables['numeric'][0])); // January
+
+ // check february numerics not deleted (5 metrics per period w/ visits + 1 'done' archive for every period)
+ $febRowCount = self::FEB_METRIC_ARCHIVE_COUNT * 5 + self::TOTAL_FEB_ARCHIVE_COUNT;
+ $this->assertEqual($febRowCount, $this->getTableCount($archiveTables['numeric'][1])); // February
+
+ // check the january blob count
+ $this->assertEqual($janBlobsRemaining, $this->getTableCount($archiveTables['blob'][0])); // January
+
+ // check for no changes in the february blob table (1 blob for every period w/ visits in feb)
+ $this->assertEqual(self::FEB_METRIC_ARCHIVE_COUNT, $this->getTableCount($archiveTables['blob'][1])); // February
+ }
+
+ private function checkLogDataPurged()
+ {
+ // 3 days removed by purge, so 3 visits, 6 conversions, 6 actions & 3 e-commerce orders removed
+ $this->assertEqual(8, $this->getTableCount('log_visit'));
+ $this->assertEqual(16, $this->getTableCount('log_conversion'));
+ $this->assertEqual(16, $this->getTableCount('log_link_visit_action'));
+ $this->assertEqual(8, $this->getTableCount('log_conversion_item'));
+ }
+
+ private function setTimeToRun()
+ {
+ $lastDateSecs = Piwik_Date::factory('today')->subDay(8)->getTimestamp();
+
+ Piwik_SetOption(Piwik_PrivacyManager::OPTION_LAST_DELETE_PIWIK_LOGS_INITIAL, 1);
+ Piwik_SetOption(Piwik_PrivacyManager::OPTION_LAST_DELETE_PIWIK_LOGS, $lastDateSecs);
+ Piwik_SetOption(Piwik_PrivacyManager::OPTION_LAST_DELETE_PIWIK_REPORTS, $lastDateSecs);
+ }
+
+ private function getTableCount( $tableName, $where = '' )
+ {
+ $sql = "SELECT COUNT(*) FROM ".Piwik_Common::prefixTable($tableName)." $where";
+ return Piwik_FetchOne($sql);
+ }
+
+ private function tableExists( $tableName )
+ {
+ $dbName = Piwik_Config::getInstance()->database['dbname'];
+
+ $sql = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = ? AND table_name = ?";
+ return Piwik_FetchOne($sql, array($dbName, Piwik_Common::prefixTable($tableName))) == 1;
+ }
+
+ private function getArchiveTableNames()
+ {
+ return array(
+ 'numeric' => array(
+ 'archive_numeric_2012_01',
+ 'archive_numeric_2012_02'
+ ),
+ 'blob' => array(
+ 'archive_blob_2012_01',
+ 'archive_blob_2012_02'
+ )
+ );
+ }
+
+ /**
+ * Irrelevant. Just needs to be defined.
+ */
+ public function getPathToTestDirectory()
+ {
+ return PIWIK_INCLUDE_PATH . '/tests/integration';
+ }
+}
+
diff --git a/tests/integration/expected/test_apiGetReportMetadata_year__LanguagesManager.getTranslationsForLanguage.xml b/tests/integration/expected/test_apiGetReportMetadata_year__LanguagesManager.getTranslationsForLanguage.xml
index c748a70c7d..1212a3018b 100644
--- a/tests/integration/expected/test_apiGetReportMetadata_year__LanguagesManager.getTranslationsForLanguage.xml
+++ b/tests/integration/expected/test_apiGetReportMetadata_year__LanguagesManager.getTranslationsForLanguage.xml
@@ -1525,10 +1525,6 @@
<value>%s byte(s) - ex %s</value>
</row>
<row>
- <label>PrivacyManager_DeleteLogSettings</label>
- <value>Supprimer les anciens logs de visiteurs de la base de données.</value>
- </row>
- <row>
<label>PrivacyManager_DeleteLogInfo</label>
<value>Les enregistrements des tables suivantes vont être supprimés: %s</value>
</row>
@@ -1537,10 +1533,6 @@
<value>Supprimer régulièrement les anciens logs de la base de données.</value>
</row>
<row>
- <label>PrivacyManager_DeleteLogDescription</label>
- <value>Vous pouvez configurer Piwik pour qu'il supprime régulièrement les logs des anciens visiteurs afin de garder une base de données de petite taille. Les rapports déjà compilés ne seront pas supprimés, seulement les logs bruts des visiteurs, pages et logs de conversions seront supprimés</value>
- </row>
- <row>
<label>PrivacyManager_DeleteLogDescription2</label>
<value>Quand vous activez la suppression automatique des logs, vous devez vous assurer que tous les rapports précédents ont bien été compilés, de cette manière aucune donnée n'est perdue.</value>
</row>
@@ -1549,10 +1541,6 @@
<value>Supprimer les logs plus anciens que</value>
</row>
<row>
- <label>PrivacyManager_DeleteLogInterval</label>
- <value>Supprimer les anciens logs tous les</value>
- </row>
- <row>
<label>PrivacyManager_DeleteMaxRows</label>
<value>Nombre maximal de lignes à supprimer à la fois:</value>
</row>