diff --git a/lib/Config/Initializer.php b/lib/Config/Initializer.php index 4e62140558..f00af0bd8d 100644 --- a/lib/Config/Initializer.php +++ b/lib/Config/Initializer.php @@ -131,6 +131,7 @@ class Initializer { $this->setupShortcodes(); $this->setupImages(); $this->setupPersonalDataExporters(); + $this->setupPersonalDataErasers(); $this->setupChangelog(); $this->setupCronTrigger(); @@ -272,6 +273,11 @@ class Initializer { $exporters->init(); } + function setupPersonalDataErasers() { + $erasers = new PersonalDataErasers(); + $erasers->init(); + } + function setupPHPVersionWarnings() { $php_version_warnings = new PHPVersionWarnings(); $warnings = $php_version_warnings->init(phpversion(), Menu::isOnMailPoetAdminPage()); diff --git a/lib/Config/PersonalDataErasers.php b/lib/Config/PersonalDataErasers.php new file mode 100644 index 0000000000..d026db9bc5 --- /dev/null +++ b/lib/Config/PersonalDataErasers.php @@ -0,0 +1,22 @@ + __('Mailpoet Subscribers', 'mailpoet'), + 'callback' => array(new SubscriberPersonalDataEraser(), 'erase'), + ); + + return $erasers; + } + +} \ No newline at end of file diff --git a/lib/Subscribers/SubscriberPersonalDataEraser.php b/lib/Subscribers/SubscriberPersonalDataEraser.php new file mode 100644 index 0000000000..10acae0ad5 --- /dev/null +++ b/lib/Subscribers/SubscriberPersonalDataEraser.php @@ -0,0 +1,56 @@ + false, + 'items_retained' => false, + 'messages' => array(), + 'done' => true, + ); + } + + $subscriber = Subscriber::findOne(trim($email)); + $item_removed = false; + $items_retained = true; + if($subscriber) { + $this->eraseCustomFields($subscriber->id()); + $this->anonymizeSubscriberData($subscriber); + $item_removed = true; + $items_retained = false; + } + + return array( + 'items_removed' => $item_removed, + 'items_retained' => $items_retained, + 'messages' => array(), + 'done' => true, + ); + } + + private function eraseCustomFields($subscriber_id) { + $custom_fields = SubscriberCustomField::where('subscriber_id', $subscriber_id)->findMany(); + foreach($custom_fields as $custom_field) { + $custom_field->value = ''; + $custom_field->save(); + } + } + + private function anonymizeSubscriberData($subscriber) { + $subscriber->email = sprintf('deleted-%s@site.invalid', uniqid('', true)); + $subscriber->first_name = 'Anonymous'; + $subscriber->last_name = 'Anonymous'; + $subscriber->status = Subscriber::STATUS_UNSUBSCRIBED; + $subscriber->subscribed_ip = '0.0.0.0'; + $subscriber->confirmed_ip = '0.0.0.0'; + $subscriber->save(); + } + +} \ No newline at end of file diff --git a/tests/unit/Subscribers/SubscriberPersonalDataEraserTest.php b/tests/unit/Subscribers/SubscriberPersonalDataEraserTest.php new file mode 100644 index 0000000000..5e898db4b8 --- /dev/null +++ b/tests/unit/Subscribers/SubscriberPersonalDataEraserTest.php @@ -0,0 +1,80 @@ +eraser = new SubscriberPersonalDataEraser(); + } + + function testExportWorksWhenSubscriberNotFound() { + $result = $this->eraser->erase('email.that@doesnt.exists'); + expect($result)->internalType('array'); + expect($result)->hasKey('items_removed'); + expect($result['items_removed'])->equals(0); + expect($result)->hasKey('done'); + expect($result['done'])->equals(true); + } + + function testItDeletesCustomFields() { + $subscriber = Subscriber::createOrUpdate(array( + 'email' => 'email.that@has.custom.fields', + )); + $custom_field1 = CustomField::createOrUpdate(array( + 'name' => 'Custom field1', + 'type' => 'input' + )); + $custom_field2 = CustomField::createOrUpdate(array( + 'name' => 'Custom field2', + 'type' => 'input' + )); + $subscriber->setCustomField($custom_field1->id(), 'Value'); + $subscriber->setCustomField($custom_field2->id(), 'Value'); + + $this->eraser->erase('email.that@has.custom.fields'); + + $subscriber_custom_fields = SubscriberCustomField::where('subscriber_id', $subscriber->id())->findMany(); + expect($subscriber_custom_fields)->count(2); + expect($subscriber_custom_fields[0]->value)->equals(''); + expect($subscriber_custom_fields[1]->value)->equals(''); + + } + + function testItDeletesSubscriberData() { + $subscriber = Subscriber::createOrUpdate(array( + 'email' => 'subscriber@for.anon.test', + 'first_name' => 'John', + 'last_name' => 'Doe', + 'status' => 'subscribed', + 'created_at' => '2018-05-03 10:30:08', + 'subscribed_ip' => 'IP1', + 'confirmed_ip' => 'IP2', + 'unconfirmed_data' => 'xyz', + )); + $this->eraser->erase('subscriber@for.anon.test'); + $subscriber_after = Subscriber::findOne($subscriber->id()); + expect($subscriber_after->first_name)->equals('Anonymous'); + expect($subscriber_after->last_name)->equals('Anonymous'); + expect($subscriber_after->status)->equals('unsubscribed'); + expect($subscriber_after->subscribed_ip)->equals('0.0.0.0'); + expect($subscriber_after->confirmed_ip)->equals('0.0.0.0'); + expect($subscriber_after->unconfirmed_data)->equals(''); + } + + function testItDeletesSubscriberEmailAddress() { + $subscriber = Subscriber::createOrUpdate(array( + 'email' => 'subscriber@for.anon.test', + )); + $this->eraser->erase('subscriber@for.anon.test'); + $subscriber_after = Subscriber::findOne($subscriber->id()); + expect($subscriber_after->email)->notEquals('subscriber@for.anon.test'); + } +}