diff --git a/doc/Remove-Account.md b/doc/Remove-Account.md index 21e0ebf7e0..83cb941e80 100644 --- a/doc/Remove-Account.md +++ b/doc/Remove-Account.md @@ -5,7 +5,7 @@ Remove Account We don't like to see people leave Friendica, but if you need to remove your account, you should visit the URL -http://sitename/removeme +http://sitename/settings/removeme with your web browser. You will need to be logged in at the time. diff --git a/doc/de/Remove-Account.md b/doc/de/Remove-Account.md index dccb0655a1..5cba208fea 100644 --- a/doc/de/Remove-Account.md +++ b/doc/de/Remove-Account.md @@ -5,7 +5,7 @@ Accounts löschen Wir freuen uns nicht, wenn Leute Friendica verlassen, aber wenn du deinen Account löschen willst, dann besuche die folgende URL -[Lösche mich (http://NamederSeite/removeme)](../removeme) +[Lösche mich (http://NamederSeite/settings/removeme)](../settings/removeme) in deinem Webbrowser. Du musst dabei eingeloggt sein. diff --git a/src/Model/User.php b/src/Model/User.php index 005e3bbf35..3f5376e0b8 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -1418,7 +1418,7 @@ class User If you are new and do not know anybody here, they may help you to make some new and interesting friends. - If you ever want to delete your account, you can do so at %1$s/removeme + If you ever want to delete your account, you can do so at %1$s/settings/removeme Thank you and welcome to %4$s.')); @@ -1522,7 +1522,7 @@ class User If you are new and do not know anybody here, they may help you to make some new and interesting friends. - If you ever want to delete your account, you can do so at %3$s/removeme + If you ever want to delete your account, you can do so at %3$s/settings/removeme Thank you and welcome to %2$s.', $user['nickname'], diff --git a/src/Module/BaseSettings.php b/src/Module/BaseSettings.php index a9bc156f12..013783c0ab 100644 --- a/src/Module/BaseSettings.php +++ b/src/Module/BaseSettings.php @@ -111,8 +111,8 @@ class BaseSettings extends BaseModule $tabs[] = [ 'label' => DI::l10n()->t('Remove account'), - 'url' => 'removeme', - 'selected' => ((DI::args()->getArgc() == 1) && (DI::args()->getArgv() === 'removeme') ? 'active' : ''), + 'url' => 'settings/removeme', + 'selected' => static::class === Settings\RemoveMe::class ? 'active' : '', 'accesskey' => 'r', ]; diff --git a/src/Module/Settings/RemoveMe.php b/src/Module/Settings/RemoveMe.php new file mode 100644 index 0000000000..b9a7f5c62d --- /dev/null +++ b/src/Module/Settings/RemoveMe.php @@ -0,0 +1,143 @@ +. + * + */ + +namespace Friendica\Module\Settings; + +use Friendica\App; +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Database\Database; +use Friendica\DI; +use Friendica\Model\User; +use Friendica\Model\User\Cookie; +use Friendica\Module\BaseSettings; +use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; +use Friendica\Util\Emailer; +use Friendica\Util\Profiler; +use Friendica\Util\Strings; +use Psr\Log\LoggerInterface; + +class RemoveMe extends BaseSettings +{ + /** @var IHandleUserSessions */ + private $session; + /** @var IManageConfigValues */ + private $config; + /** @var Database */ + private $database; + /** @var Emailer */ + private $emailer; + /** @var SystemMessages */ + private $systemMessages; + /** @var Cookie */ + private $cookie; + + public function __construct(Cookie $cookie, SystemMessages $systemMessages, Emailer $emailer, Database $database, IManageConfigValues $config, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->session = $session; + $this->config = $config; + $this->database = $database; + $this->emailer = $emailer; + $this->systemMessages = $systemMessages; + $this->cookie = $cookie; + } + + protected function post(array $request = []) + { + if (!$this->session->getLocalUserId()) { + return; + } + + if ($this->session->getSubManagedUserId()) { + return; + } + + $hash = $this->session->pop('remove_account_verify'); + if (empty($hash) || empty($request[$hash])) { + return; + } + + try { + $userId = User::getIdFromPasswordAuthentication($this->session->getLocalUserId(), trim($request[$hash])); + } catch (\Throwable $e) { + $this->systemMessages->addNotice($e->getMessage()); + return; + } + + // send notification to admins so that they can clean up the backups + $admin_mails = explode(',', $this->config->get('config', 'admin_email')); + foreach ($admin_mails as $mail) { + $admin = $this->database->selectFirst('user', ['uid', 'language', 'email', 'username'], ['email' => trim($mail)]); + if (!$admin) { + continue; + } + + $l10n = $this->l10n->withLang($admin['language']); + + $email = $this->emailer + ->newSystemMail() + ->withMessage( + $l10n->t('[Friendica System Notify]') . ' ' . $l10n->t('User deleted their account'), + $l10n->t('On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'), + $l10n->t('The user id is %d', $this->session->getLocalUserId())) + ->forUser($admin) + ->withRecipient($admin['email']) + ->build(); + $this->emailer->send($email); + } + + User::remove($userId); + + $this->session->clear(); + $this->cookie->clear(); + + $this->systemMessages->addInfo($this->t('Your user account has been successfully removed. Bye bye!')); + $this->baseUrl->redirect(); + } + + protected function content(array $request = []): string + { + parent::content(); + + if (!$this->session->getLocalUserId()) { + $this->systemMessages->addNotice($this->t('Permission denied.')); + $this->baseUrl->redirect(); + } + + $hash = Strings::getRandomHex(); + + $this->session->set('remove_account_verify', $hash); + + $tpl = Renderer::getMarkupTemplate('settings/removeme.tpl'); + return Renderer::replaceMacros($tpl, [ + '$l10n' => [ + 'title' => DI::l10n()->t('Remove My Account'), + 'desc' => DI::l10n()->t('This will completely remove your account. Once this has been done it is not recoverable.'), + ], + '$password' => [$hash, $this->t('Please enter your password for verification:'), null, null, true], + ]); + } +} diff --git a/src/Module/Tos.php b/src/Module/Tos.php index 49d56ed6cf..31beb66515 100644 --- a/src/Module/Tos.php +++ b/src/Module/Tos.php @@ -56,7 +56,7 @@ class Tos extends BaseModule $this->privacy_operate = $this->t('At the time of registration, and for providing communications between the user account and their contacts, the user has to provide a display name (pen name), an username (nickname) and a working email address. The names will be accessible on the profile page of the account by any visitor of the page, even if other profile details are not displayed. The email address will only be used to send the user notifications about interactions, but wont be visibly displayed. The listing of an account in the node\'s user directory or the global user directory is optional and can be controlled in the user settings, it is not necessary for communication.'); $this->privacy_distribute = $this->t('This data is required for communication and is passed on to the nodes of the communication partners and is stored there. Users can enter additional private data that may be transmitted to the communication partners accounts.'); - $this->privacy_delete = $this->t('At any point in time a logged in user can export their account data from the account settings. If the user wants to delete their account they can do so at %1$s/removeme. The deletion of the account will be permanent. Deletion of the data will also be requested from the nodes of the communication partners.', $this->baseUrl); + $this->privacy_delete = $this->t('At any point in time a logged in user can export their account data from the account settings. If the user wants to delete their account they can do so at %1$s/settings/removeme. The deletion of the account will be permanent. Deletion of the data will also be requested from the nodes of the communication partners.', $this->baseUrl); // In some cases we don't need every single one of the above separate, but all in one block. // So here is an array to look over $this->privacy_complete = [$this->t('Privacy Statement'), $this->privacy_operate, @@ -90,7 +90,7 @@ class Tos extends BaseModule '$privstatementtitle' => $this->t('Privacy Statement'), '$privacy_operate' => $this->t('At the time of registration, and for providing communications between the user account and their contacts, the user has to provide a display name (pen name), an username (nickname) and a working email address. The names will be accessible on the profile page of the account by any visitor of the page, even if other profile details are not displayed. The email address will only be used to send the user notifications about interactions, but wont be visibly displayed. The listing of an account in the node\'s user directory or the global user directory is optional and can be controlled in the user settings, it is not necessary for communication.'), '$privacy_distribute' => $this->t('This data is required for communication and is passed on to the nodes of the communication partners and is stored there. Users can enter additional private data that may be transmitted to the communication partners accounts.'), - '$privacy_delete' => $this->t('At any point in time a logged in user can export their account data from the account settings. If the user wants to delete their account they can do so at %1$s/removeme. The deletion of the account will be permanent. Deletion of the data will also be requested from the nodes of the communication partners.', $this->baseUrl) + '$privacy_delete' => $this->t('At any point in time a logged in user can export their account data from the account settings. If the user wants to delete their account they can do so at %1$s/settings/removeme. The deletion of the account will be permanent. Deletion of the data will also be requested from the nodes of the communication partners.', $this->baseUrl) ]); } else { return ''; diff --git a/static/routes.config.php b/static/routes.config.php index 321e7659c4..12d68f4016 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -605,6 +605,7 @@ return [ '/photo[/new]' => [Module\Settings\Profile\Photo\Index::class, [R::GET, R::POST]], '/photo/crop/{guid}' => [Module\Settings\Profile\Photo\Crop::class, [R::GET, R::POST]], ], + '/removeme' => [Module\Settings\RemoveMe::class, [R::GET, R::POST]], '/userexport[/{action}]' => [Module\Settings\UserExport::class, [R::GET ]], ], diff --git a/view/templates/settings/removeme.tpl b/view/templates/settings/removeme.tpl new file mode 100644 index 0000000000..0532d9c695 --- /dev/null +++ b/view/templates/settings/removeme.tpl @@ -0,0 +1,16 @@ +
+ {{include file="section_title.tpl" title=$l10n.title}} + +
+
{{$l10n.desc nofilter}}
+ +
+ {{include file="field_password.tpl" field=$password}} + +
+ +
+
+
+
+