diff --git a/lib/Config/PersonalDataExporters.php b/lib/Config/PersonalDataExporters.php index a6e6035698..d3ef0961bb 100644 --- a/lib/Config/PersonalDataExporters.php +++ b/lib/Config/PersonalDataExporters.php @@ -2,6 +2,7 @@ namespace MailPoet\Config; +use MailPoet\Subscribers\ImportExport\PersonalDataExporters\NewsletterClicksExporter; use MailPoet\Subscribers\ImportExport\PersonalDataExporters\NewslettersExporter; use MailPoet\Subscribers\ImportExport\PersonalDataExporters\SegmentsExporter; use MailPoet\Subscribers\ImportExport\PersonalDataExporters\SubscriberExporter; @@ -12,11 +13,12 @@ class PersonalDataExporters { add_filter('wp_privacy_personal_data_exporters', array($this, 'registerSubscriberExporter')); add_filter('wp_privacy_personal_data_exporters', array($this, 'registerSegmentsExporter')); add_filter('wp_privacy_personal_data_exporters', array($this, 'registerNewslettersExporter')); + add_filter('wp_privacy_personal_data_exporters', array($this, 'registerNewsletterClicksExporter')); } function registerSegmentsExporter($exporters) { $exporters[] = array( - 'exporter_friendly_name' => __('MailPoet Lists'), + 'exporter_friendly_name' => __('MailPoet Lists', 'mailpoet'), 'callback' => array(new SegmentsExporter(), 'export'), ); return $exporters; @@ -24,7 +26,7 @@ class PersonalDataExporters { function registerSubscriberExporter($exporters) { $exporters[] = array( - 'exporter_friendly_name' => __('MailPoet Subscriber Data'), + 'exporter_friendly_name' => __('MailPoet Subscriber Data', 'mailpoet'), 'callback' => array(new SubscriberExporter(), 'export'), ); return $exporters; @@ -32,10 +34,18 @@ class PersonalDataExporters { function registerNewslettersExporter($exporters) { $exporters[] = array( - 'exporter_friendly_name' => __('MailPoet Emails'), + 'exporter_friendly_name' => __('MailPoet Emails', 'mailpoet'), 'callback' => array(new NewslettersExporter(), 'export'), ); return $exporters; } + function registerNewsletterClicksExporter($exporters) { + $exporters[] = array( + 'exporter_friendly_name' => __('MailPoet Email Clicks', 'mailpoet'), + 'callback' => array(new NewsletterClicksExporter(), 'export'), + ); + return $exporters; + } + } diff --git a/lib/Models/StatisticsClicks.php b/lib/Models/StatisticsClicks.php index 58534efac0..e74fa37801 100644 --- a/lib/Models/StatisticsClicks.php +++ b/lib/Models/StatisticsClicks.php @@ -24,4 +24,24 @@ class StatisticsClicks extends Model { } return $statistics->save(); } + + static function getAllForSubsciber(Subscriber $subscriber) { + return static::table_alias('clicks') + ->select('clicks.id', 'id') + ->select('newsletter_rendered_subject') + ->select('clicks.created_at', 'created_at') + ->select('url') + ->join( + SendingQueue::$_table, + array('clicks.queue_id', '=', 'queue.id'), + 'queue' + ) + ->join( + NewsletterLink::$_table, + array('clicks.link_id', '=', 'link.id'), + 'link' + ) + ->where('clicks.subscriber_id', $subscriber->id()) + ->orderByAsc('url'); + } } diff --git a/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporter.php b/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporter.php new file mode 100644 index 0000000000..f268878671 --- /dev/null +++ b/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporter.php @@ -0,0 +1,59 @@ +exportSubscriber(Subscriber::findOne(trim($email)), $page); + return array( + 'data' => $data, + 'done' => count($data) < self::LIMIT, + ); + } + + private function exportSubscriber($subscriber, $page) { + if(!$subscriber) return array(); + + $result = array(); + + $statistics = StatisticsClicks::getAllForSubsciber($subscriber) + ->limit(self::LIMIT) + ->offset(self::LIMIT * ($page - 1)) + ->findArray(); + + foreach($statistics as $row) { + $result[] = $this->exportNewsletter($row); + } + + return $result; + } + + private function exportNewsletter($row) { + $newsletter_data = array(); + $newsletter_data[] = array( + 'name' => __('Email subject', 'mailpoet'), + 'value' => $row['newsletter_rendered_subject'], + ); + $newsletter_data[] = array( + 'name' => __('Timestamp of the click event', 'mailpoet'), + 'value' => $row['created_at'], + ); + $newsletter_data[] = array( + 'name' => __('Url', 'mailpoet'), + 'value' => $row['url'], + ); + return array( + 'group_id' => 'mailpoet-newsletter-clicks', + 'group_label' => __('MailPoet Emails Clicks', 'mailpoet'), + 'item_id' => 'newsletter-' . $row['id'], + 'data' => $newsletter_data, + ); + } + +} \ No newline at end of file diff --git a/lib/Subscribers/ImportExport/PersonalDataExporters/NewslettersExporter.php b/lib/Subscribers/ImportExport/PersonalDataExporters/NewslettersExporter.php index 21e3bd0f2e..d70e6a6ecf 100644 --- a/lib/Subscribers/ImportExport/PersonalDataExporters/NewslettersExporter.php +++ b/lib/Subscribers/ImportExport/PersonalDataExporters/NewslettersExporter.php @@ -12,9 +12,10 @@ class NewslettersExporter { const LIMIT = 100; function export($email, $page = 1) { + $data = $this->exportSubscriber(Subscriber::findOne(trim($email)), $page); return array( - 'data' => $this->exportSubscriber(Subscriber::findOne(trim($email)), $page), - 'done' => true, + 'data' => $data, + 'done' => count($data) < self::LIMIT, ); } diff --git a/tests/unit/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporterTest.php b/tests/unit/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporterTest.php new file mode 100644 index 0000000000..4cb7bc247c --- /dev/null +++ b/tests/unit/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporterTest.php @@ -0,0 +1,82 @@ +exporter = new NewsletterClicksExporter(); + } + + function testExportWorksWhenSubscriberNotFound() { + $result = $this->exporter->export('email.that@doesnt.exists'); + expect($result)->internalType('array'); + expect($result)->hasKey('data'); + expect($result['data'])->equals(array()); + expect($result)->hasKey('done'); + expect($result['done'])->equals(true); + } + + function testExportWorksForSubscriberWithNoNewsletters() { + Subscriber::createOrUpdate(array( + 'email' => 'email.that@has.no.newsletters', + )); + $result = $this->exporter->export('email.that@has.no.newsletters'); + expect($result)->internalType('array'); + expect($result)->hasKey('data'); + expect($result['data'])->equals(array()); + expect($result)->hasKey('done'); + expect($result['done'])->equals(true); + } + + function testExportReturnsData() { + $subscriber = Subscriber::createOrUpdate(array( + 'email' => 'email@with.clicks', + )); + $queue = SendingQueue::createOrUpdate(array( + 'newsletter_rendered_subject' => 'Email Subject', + 'task_id' => 1, + 'newsletter_id' => 8, + )); + $newsletter = Newsletter::createOrUpdate(array( + 'subject' => 'Email Subject1', + 'type' => Newsletter::TYPE_STANDARD + )); + $link = NewsletterLink::createOrUpdate(array( + 'url' => 'Link url', + 'newsletter_id' => $newsletter->id(), + 'queue_id' => $queue->id(), + 'hash' => 'xyz', + )); + StatisticsClicks::createOrUpdate(array( + 'newsletter_id' => $newsletter->id(), + 'queue_id' => $queue->id(), + 'subscriber_id' => $subscriber->id(), + 'link_id' => $link->id(), + 'count' => 1, + 'created_at' => '2018-01-02 15:16:17', + )); + $result = $this->exporter->export('email@with.clicks'); + expect($result['data'])->internalType('array'); + expect($result['data'])->count(1); + expect($result['done'])->equals(true); + expect($result['data'][0])->hasKey('group_id'); + expect($result['data'][0])->hasKey('group_label'); + expect($result['data'][0])->hasKey('item_id'); + expect($result['data'][0])->hasKey('data'); + expect($result['data'][0]['data'])->contains(array('name' => 'Email subject', 'value' => 'Email Subject')); + expect($result['data'][0]['data'])->contains(array('name' => 'Url', 'value' => 'Link url')); + expect($result['data'][0]['data'])->contains(array('name' => 'Timestamp of the click event', 'value' => '2018-01-02 15:16:17')); + } + +}