From 7d09ce86c4e4caa97e72ca6103c512368135667a Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 15 May 2022 21:29:36 -0400 Subject: [PATCH] Move relocation feature in its separate class - Create Database->replaceInTableFields method --- src/Core/Relocate.php | 95 +++++++++++++++++++++++++++++++++++++++ src/Database/Database.php | 28 ++++++++++++ src/Module/Admin/Site.php | 72 +++++------------------------ 3 files changed, 134 insertions(+), 61 deletions(-) create mode 100644 src/Core/Relocate.php diff --git a/src/Core/Relocate.php b/src/Core/Relocate.php new file mode 100644 index 0000000000..951bbaa037 --- /dev/null +++ b/src/Core/Relocate.php @@ -0,0 +1,95 @@ +. + * + */ + +namespace Friendica\Core; + +use Friendica\App; +use Friendica\Database; +use Friendica\Util\Strings; +use Friendica\Worker\Delivery; + +class Relocate +{ + /** + * @var App\BaseURL + */ + private $baseUrl; + /** + * @var Database\Database + */ + private $database; + /** + * @var Config\Capability\IManageConfigValues + */ + private $config; + + public function __construct(App\BaseURL $baseUrl, Database\Database $database, Config\Capability\IManageConfigValues $config) + { + $this->baseUrl = $baseUrl; + $this->database = $database; + $this->config = $config; + } + + /** + * Performs relocation + * + * @param string $new_url The new node URL, including the scheme + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + */ + public function run(string $new_url) + { + $new_url = rtrim($new_url, '/'); + + $parsed = @parse_url($new_url); + if (!is_array($parsed) || empty($parsed['host']) || empty($parsed['scheme'])) { + throw new \InvalidArgumentException('Can not parse base URL. Must have at least ://'); + } + + /* steps: + * replace all "baseurl" to "new_url" in config, profile, term, items and contacts + * send relocate for every local user + * */ + $old_url = $this->baseUrl->get(true); + + // Generate host names for relocation the addresses in the format user@address.tld + $new_host = str_replace('http://', '@', Strings::normaliseLink($new_url)); + $old_host = str_replace('http://', '@', Strings::normaliseLink($old_url)); + + // update tables + // update profile links in the format "http://server.tld" + $this->database->replaceInTableFields('profile', ['photo', 'thumb'], $old_url, $new_url); + $this->database->replaceInTableFields('contact', ['photo', 'thumb', 'micro', 'url', 'nurl', 'alias', 'request', 'notify', 'poll', 'confirm', 'poco', 'avatar'], $old_url, $new_url); + $this->database->replaceInTableFields('post-content', ['body'], $old_url, $new_url); + + // update profile addresses in the format "user@server.tld" + $this->database->replaceInTableFields('contact', ['addr'], $old_host, $new_host); + + // update config + $this->config->set('system', 'url', $new_url); + $this->baseUrl->saveByURL($new_url); + + // send relocate + $users = $this->database->selectToArray('user', ['uid'], ['account_removed' => false, 'account_expired' => false]); + foreach ($users as $user) { + Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::RELOCATION, $user['uid']); + } + } +} diff --git a/src/Database/Database.php b/src/Database/Database.php index 88d8d7d0f6..711d546d80 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -1790,4 +1790,32 @@ class Database { array_walk($arr, [$this, 'escapeArrayCallback'], $add_quotation); } + + /** + * Replaces a string in the provided fields of the provided table + * + * @param string $table_name + * @param array $fields List of field names in the provided table + * @param string $search + * @param string $replace + * @throws \Exception + */ + public function replaceInTableFields(string $table_name, array $fields, string $search, string $replace) + { + $search = $this->escape($search); + $replace = $this->escape($replace); + + $upd = []; + foreach ($fields as $field) { + $field = DBA::quoteIdentifier($field); + $upd[] = "$field = REPLACE($field, '$search', '$replace')"; + } + + $upds = implode(', ', $upd); + + $r = $this->e(sprintf("UPDATE %s SET %s;", $table_name, $upds)); + if (!$this->isResult($r)) { + throw new \RuntimeException("Failed updating `$table_name`: " . $this->errorMessage()); + } + } } diff --git a/src/Module/Admin/Site.php b/src/Module/Admin/Site.php index 515fb53c87..50289ff21f 100644 --- a/src/Module/Admin/Site.php +++ b/src/Module/Admin/Site.php @@ -22,6 +22,7 @@ namespace Friendica\Module\Admin; use Friendica\App; +use Friendica\Core\Relocate; use Friendica\Core\Renderer; use Friendica\Core\Search; use Friendica\Core\System; @@ -60,70 +61,19 @@ class Site extends BaseAdmin return; } - // relocate - // @TODO This file could benefit from moving this feature away in a Module\Admin\Relocate class for example - if (!empty($_POST['relocate']) && !empty($_POST['relocate_url']) && $_POST['relocate_url'] != "") { - $new_url = $_POST['relocate_url']; - $new_url = rtrim($new_url, "/"); + if (!empty($_POST['relocate']) && !empty($_POST['relocate_url'])) { + try { + $relocate = new Relocate(DI::baseUrl(), DI::dba(), DI::config()); + $relocate->run($_POST['relocate_url']); - $parsed = @parse_url($new_url); - if (!is_array($parsed) || empty($parsed['host']) || empty($parsed['scheme'])) { - notice(DI::l10n()->t("Can not parse base url. Must have at least ://")); - DI::baseUrl()->redirect('admin/site'); + info(DI::l10n()->t('Relocation started. Could take a while to complete.')); + } catch (\InvalidArgumentException $e) { + notice(DI::l10n()->t('Can not parse base url. Must have at least ://')); + } catch (\Throwable $e) { + notice(DI::l10n()->t('Unable to perform the relocation, please retry later or check the application logs.')); + notice($e->getMessage()); } - /* steps: - * replace all "baseurl" to "new_url" in config, profile, term, items and contacts - * send relocate for every local user - * */ - - $old_url = DI::baseUrl()->get(true); - - // Generate host names for relocation the addresses in the format user@address.tld - $new_host = str_replace("http://", "@", Strings::normaliseLink($new_url)); - $old_host = str_replace("http://", "@", Strings::normaliseLink($old_url)); - - function update_table(App $a, $table_name, $fields, $old_url, $new_url) - { - $dbold = DBA::escape($old_url); - $dbnew = DBA::escape($new_url); - - $upd = []; - foreach ($fields as $f) { - $upd[] = "`$f` = REPLACE(`$f`, '$dbold', '$dbnew')"; - } - - $upds = implode(", ", $upd); - - $r = DBA::e(sprintf("UPDATE %s SET %s;", $table_name, $upds)); - if (!DBA::isResult($r)) { - notice("Failed updating '$table_name': " . DBA::errorMessage()); - DI::baseUrl()->redirect('admin/site'); - } - } - - // update tables - // update profile links in the format "http://server.tld" - update_table($a, "profile", ['photo', 'thumb'], $old_url, $new_url); - update_table($a, "contact", ['photo', 'thumb', 'micro', 'url', 'nurl', 'alias', 'request', 'notify', 'poll', 'confirm', 'poco', 'avatar'], $old_url, $new_url); - update_table($a, "post-content", ['body'], $old_url, $new_url); - - // update profile addresses in the format "user@server.tld" - update_table($a, "contact", ['addr'], $old_host, $new_host); - - // update config - DI::config()->set('system', 'url', $new_url); - DI::baseUrl()->saveByURL($new_url); - - // send relocate - $usersStmt = DBA::select('user', ['uid'], ['account_removed' => false, 'account_expired' => false]); - while ($user = DBA::fetch($usersStmt)) { - Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::RELOCATION, $user['uid']); - } - DBA::close($usersStmt); - - info(DI::l10n()->t("Relocation started. Could take a while to complete.")); - DI::baseUrl()->redirect('admin/site'); } // end relocate