Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implements possibility to unsubscribe from reports (#13214)
* Implements possibility to unsubscribe from reports * Use a nonce for better security * post event if someone unsubscribes * various improvements and tests * store information about unsubscribed reports until they are resubscribed * code improvements
- Loading branch information
Showing
16 changed files
with
644 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
/** | ||
* Piwik - free/libre analytics platform | ||
* | ||
* @link http://piwik.org | ||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later | ||
* | ||
*/ | ||
|
||
namespace Piwik\Updates; | ||
|
||
use Piwik\Common; | ||
use Piwik\Updater\Migration\Factory as MigrationFactory; | ||
use Piwik\Updater; | ||
use Piwik\Updates; | ||
|
||
/** | ||
* Update for version 3.6.0-b3. | ||
*/ | ||
class Updates_3_6_0_b3 extends Updates | ||
{ | ||
/** | ||
* @var MigrationFactory | ||
*/ | ||
private $migration; | ||
|
||
public function __construct(MigrationFactory $factory) | ||
{ | ||
$this->migration = $factory; | ||
} | ||
|
||
public function getMigrations(Updater $updater) | ||
{ | ||
$columns = array( | ||
'idreport' => 'INT(11) NOT NULL', | ||
'token' => ' VARCHAR(100) NULL', | ||
'email' => 'VARCHAR(100) NOT NULL', | ||
'ts_subscribed' => 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP', | ||
'ts_unsubscribed' => 'TIMESTAMP NULL', | ||
); | ||
return array( | ||
$this->migration->db->createTable('report_subscriptions', $columns, ['idreport', 'email']), | ||
$this->migration->db->addUniqueKey('report_subscriptions', 'token', 'unique_token') | ||
); | ||
} | ||
|
||
public function doUpdate(Updater $updater) | ||
{ | ||
$updater->executeMigrations(__FILE__, $this->getMigrations($updater)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
<?php | ||
/** | ||
* Piwik - free/libre analytics platform | ||
* | ||
* @link http://piwik.org | ||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later | ||
* | ||
*/ | ||
namespace Piwik\Plugins\ScheduledReports; | ||
|
||
use Piwik\Access; | ||
use Piwik\API\Request; | ||
use Piwik\Common; | ||
use Piwik\Db; | ||
use Piwik\DbHelper; | ||
use Piwik\Piwik; | ||
|
||
class SubscriptionModel | ||
{ | ||
private static $rawPrefix = 'report_subscriptions'; | ||
private $table; | ||
|
||
public function __construct() | ||
{ | ||
$this->table = Common::prefixTable(self::$rawPrefix); | ||
} | ||
|
||
public function unsubscribe($token) | ||
{ | ||
$details = $this->getSubscription($token); | ||
|
||
if (empty($details)) { | ||
return false; | ||
} | ||
|
||
$email = $details['email']; | ||
|
||
$report = Access::doAsSuperUser(function() use ($details) { | ||
$reports = Request::processRequest('ScheduledReports.getReports', array( | ||
'idReport' => $details['idreport'], | ||
)); | ||
return reset($reports); | ||
}); | ||
|
||
if (empty($report)) { | ||
// if the report isn't found, remove subscription as it isn't active anymore | ||
$this->removeSubscription($token); | ||
return false; | ||
} | ||
|
||
$reportParameters = $report['parameters']; | ||
|
||
$emailFound = false; | ||
|
||
if (!empty($reportParameters['additionalEmails'])) { | ||
$additionalEmails = $reportParameters['additionalEmails']; | ||
$filteredEmails = []; | ||
foreach ($additionalEmails as $additionalEmail) { | ||
if ($additionalEmail == $email) { | ||
$emailFound = true; | ||
continue; | ||
} | ||
$filteredEmails[] = $additionalEmail; | ||
} | ||
if ($emailFound) { | ||
$report['parameters']['additionalEmails'] = $filteredEmails; | ||
} | ||
} | ||
|
||
if ($reportParameters['emailMe']) { | ||
$login = $report['login']; | ||
|
||
$userModel = new \Piwik\Plugins\UsersManager\Model(); | ||
$userData = $userModel->getUser($login); | ||
|
||
if ($userData['email'] == $email) { | ||
$emailFound = true; | ||
$report['parameters']['emailMe'] = false; | ||
} | ||
} | ||
|
||
if ($emailFound) { | ||
Access::doAsSuperUser(function() use ($report) { | ||
Request::processRequest('ScheduledReports.updateReport', [ | ||
'idReport' => $report['idreport'], | ||
'idSite' => $report['idsite'], | ||
'description' => $report['description'], | ||
'period' => $report['period'], | ||
'hour' => $report['hour'], | ||
'reportType' => $report['type'], | ||
'reportFormat' => $report['format'], | ||
'reports' => $report['reports'], | ||
'parameters' => $report['parameters'], | ||
'idSegment' => $report['idsegment'], | ||
]); | ||
}); | ||
|
||
Piwik::postEvent('Report.unsubscribe', [$report['idreport'], $email]); | ||
|
||
$this->removeSubscription($token); | ||
} | ||
|
||
return $emailFound; | ||
} | ||
|
||
public function getReportSubscriptions($idReport, $includeUnsubscribed = false) | ||
{ | ||
$query = 'SELECT * FROM ' . $this->table . ' WHERE idreport = ?'; | ||
|
||
if (!$includeUnsubscribed) { | ||
$query .= ' AND ts_unsubscribed IS NULL'; | ||
} | ||
|
||
return $this->getDb()->fetchAll($query, [$idReport]); | ||
} | ||
|
||
public function getSubscription($token) | ||
{ | ||
return $this->getDb()->fetchRow('SELECT * FROM ' . $this->table . ' WHERE token = ?', [$token]); | ||
} | ||
|
||
public function updateReportSubscriptions($idReport, $emails) | ||
{ | ||
$availableSubscriptions = $this->getReportSubscriptions($idReport); | ||
$availableEmails = array_column($availableSubscriptions, 'email'); | ||
|
||
// remove available subscriptions that aren't present anymore | ||
foreach ($availableSubscriptions as $availableSubscription) { | ||
if (!in_array($availableSubscription['email'], $emails) && !empty($availableSubscription['token'])) { | ||
$this->removeSubscription($availableSubscription['token']); | ||
} | ||
} | ||
|
||
$emails = array_unique($emails); | ||
|
||
// add new subscriptions | ||
foreach ($emails as $email) { | ||
while($token = $this->generateToken($email)) { | ||
if (!$this->tokenExists($token)) { | ||
break; | ||
} | ||
} | ||
|
||
if (!in_array($email, $availableEmails)) { | ||
$subscription = [ | ||
'idreport' => $idReport, | ||
'token' => $token, | ||
'email' => $email | ||
]; | ||
// remove possible "unsubscribe" entry | ||
$this->getDb()->query('DELETE FROM ' . $this->table . ' WHERE idreport = ? AND email = ?', [$idReport, $email]); | ||
$this->getDb()->insert($this->table, $subscription); | ||
} | ||
} | ||
|
||
} | ||
|
||
private function removeSubscription($token) | ||
{ | ||
$this->getDb()->query('UPDATE ' . $this->table . ' SET token = "", ts_unsubscribed = NOW() WHERE token = ?', [$token]); | ||
} | ||
|
||
private function generateToken($email) | ||
{ | ||
return substr(Common::hash($email . time() . Common::getRandomString(5)), 0, 100); | ||
} | ||
|
||
private function tokenExists($token) | ||
{ | ||
return !!$this->getDb()->fetchOne('SELECT token FROM ' . $this->table . ' WHERE token = ?', [$token]); | ||
} | ||
|
||
private function getDb() | ||
{ | ||
return Db::get(); | ||
} | ||
|
||
public static function install() | ||
{ | ||
$reportTable = "`idreport` INT(11) NOT NULL, | ||
`token` VARCHAR(100) NULL, | ||
`email` VARCHAR(100) NOT NULL, | ||
`ts_subscribed` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | ||
`ts_unsubscribed` TIMESTAMP NULL, | ||
PRIMARY KEY (`idreport`, `email`), | ||
UNIQUE INDEX `unique_token` (`token`)"; | ||
|
||
DbHelper::createTable(self::$rawPrefix, $reportTable); | ||
} | ||
} |
Oops, something went wrong.