Merge pull request #12087 from MrPetovan/task/4090-move-mod-uimport

Move mod/uimport.php to src/Module
This commit is contained in:
Philipp 2022-11-02 19:19:17 +01:00 committed by GitHub
commit da1c13368b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 523 additions and 507 deletions

View file

@ -9,8 +9,8 @@ How to move your account between servers
* Go to "Settings" -> "[Export personal data](uexport)" * Go to "Settings" -> "[Export personal data](uexport)"
* Click on "Export account" to save your account data. * Click on "Export account" to save your account data.
* **Save the file in a secure place!** It contains your details, your contacts, groups, and personal settings. It also contains your secret keys to authenticate yourself to your contacts. * **Save the file in a secure place!** It contains your details, your contacts, groups, and personal settings. It also contains your secret keys to authenticate yourself to your contacts.
* Go to your new server, and open *http://newserver.com/uimport* (there is not a direct link to this page at the moment). Please consider that this is only possible on servers with open registration. On other systems only the administrator can add accounts with an uploaded file. * Go to your new server, and open *http://newserver.com/user/import* (there is not a direct link to this page at the moment). Please consider that this is only possible on servers with open registration. On other systems only the administrator can add accounts with an uploaded file.
* Do NOT create a new account prior to importing your old settings - uimport should be used *instead* of register. * Do NOT create a new account prior to importing your old settings - user import should be used *instead* of register.
* Load your saved account file and click "Import". * Load your saved account file and click "Import".
* After the move, the account on the old server will not work reliably anymore, and should be not used. * After the move, the account on the old server will not work reliably anymore, and should be not used.

View file

@ -15,14 +15,14 @@ Außerdem enthält sie deinen geheimen Schlüssel mit dem du dich deinen Kontakt
**Speichere diese Datei an einem sicheren Ort**! **Speichere diese Datei an einem sicheren Ort**!
Rufe nun dem neuen Server die Seite *http://newserver.com/uimport* auf (es gibt derzeit keinen direkten Link auf diese Seite). Rufe nun dem neuen Server die Seite *http://newserver.com/user/import* auf (es gibt derzeit keinen direkten Link auf diese Seite).
Bitte beachte, dass dies nur auf Servern möglich ist, an denen man sich offen anmelden kann. Bitte beachte, dass dies nur auf Servern möglich ist, an denen man sich offen anmelden kann.
Bei Servern, bei denen der Administrator Accounts freigeben muss, ist das Hochladen nicht möglich. Bei Servern, bei denen der Administrator Accounts freigeben muss, ist das Hochladen nicht möglich.
Hier kann dies nur der Administrator selber durchführen. Hier kann dies nur der Administrator selber durchführen.
Lege auf dem neuen Server auf keinen Fall einen gleichnamigen Account an! Lege auf dem neuen Server auf keinen Fall einen gleichnamigen Account an!
uimport muss anstelle des Registrierens verwendet werden. user import muss anstelle des Registrierens verwendet werden.
Wähle die gesicherte Account Datei aus und klicke "Importieren". Wähle die gesicherte Account Datei aus und klicke "Importieren".

View file

@ -1,71 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* View for user import
*/
use Friendica\App;
use Friendica\Core\Logger;
use Friendica\Core\UserImport;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
function uimport_post(App $a)
{
if ((DI::config()->get('config', 'register_policy') != \Friendica\Module\Register::OPEN) && !$a->isSiteAdmin()) {
DI::sysmsg()->addNotice(DI::l10n()->t('Permission denied.'));
return;
}
if (!empty($_FILES['accountfile'])) {
UserImport::importAccount($_FILES['accountfile']);
return;
}
}
function uimport_content(App $a)
{
if ((DI::config()->get('config', 'register_policy') != \Friendica\Module\Register::OPEN) && !$a->isSiteAdmin()) {
DI::sysmsg()->addNotice(DI::l10n()->t('User imports on closed servers can only be done by an administrator.'));
return;
}
$max_dailies = intval(DI::config()->get('system', 'max_daily_registrations'));
if ($max_dailies) {
$total = DBA::count('user', ["`register_date` > UTC_TIMESTAMP - INTERVAL 1 DAY"]);
if ($total >= $max_dailies) {
Logger::notice('max daily registrations exceeded.');
DI::sysmsg()->addNotice(DI::l10n()->t('This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.'));
return;
}
}
$tpl = Renderer::getMarkupTemplate("uimport.tpl");
return Renderer::replaceMacros($tpl, [
'$regbutt' => DI::l10n()->t('Import'),
'$import' => [
'title' => DI::l10n()->t("Move account"),
'intro' => DI::l10n()->t("You can import an account from another Friendica server."),
'instruct' => DI::l10n()->t("You need to export your account from the old server and upload it here. We will recreate your old account here with all your contacts. We will try also to inform your friends that you moved here."),
'warn' => DI::l10n()->t("This feature is experimental. We can't import contacts from the OStatus network \x28GNU Social/Statusnet\x29 or from Diaspora"),
'field' => ['accountfile', DI::l10n()->t('Account file'), '<input id="id_accountfile" name="accountfile" type="file">', DI::l10n()->t('To export your account, go to "Settings->Export your personal data" and select "Export account"')],
],
]);
}

View file

@ -1,330 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Core;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\DI;
use Friendica\Model\Photo;
use Friendica\Model\Profile;
use Friendica\Object\Image;
use Friendica\Security\PermissionSet\Repository\PermissionSet;
use Friendica\Util\Strings;
use Friendica\Worker\Delivery;
/**
* UserImport class
*/
class UserImport
{
const IMPORT_DEBUG = false;
private static function lastInsertId()
{
if (self::IMPORT_DEBUG) {
return 1;
}
return DBA::lastInsertId();
}
/**
* Remove columns from array $arr that aren't in table $table
*
* @param string $table Table name
* @param array &$arr Column=>Value array from json (by ref)
* @throws \Exception
*/
private static function checkCols($table, &$arr)
{
$tableColumns = DBStructure::getColumns($table);
$tcols = [];
$ttype = [];
// get a plain array of column names
foreach ($tableColumns as $tcol) {
$tcols[] = $tcol['Field'];
$ttype[$tcol['Field']] = $tcol['Type'];
}
// remove inexistent columns
foreach ($arr as $icol => $ival) {
if (!in_array($icol, $tcols)) {
unset($arr[$icol]);
continue;
}
if ($ttype[$icol] === 'datetime') {
$arr[$icol] = $ival ?? DBA::NULL_DATETIME;
}
}
}
/**
* Import data into table $table
*
* @param string $table Table name
* @param array $arr Column=>Value array from json
* @return array|bool
* @throws \Exception
*/
private static function dbImportAssoc(string $table, array $arr)
{
if (isset($arr['id'])) {
unset($arr['id']);
}
self::checkCols($table, $arr);
if (self::IMPORT_DEBUG) {
return true;
}
return DBA::insert($table, $arr);
}
/**
* Import account file exported from mod/uexport
*
* @param array $file array from $_FILES
* @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public static function importAccount(array $file)
{
Logger::notice("Start user import from " . $file['tmp_name']);
/*
STEPS
1. checks
2. replace old baseurl with new baseurl
3. import data (look at user id and contacts id)
4. archive non-dfrn contacts
5. send message to dfrn contacts
*/
$account = json_decode(file_get_contents($file['tmp_name']), true);
if ($account === null) {
DI::sysmsg()->addNotice(DI::l10n()->t("Error decoding account file"));
return;
}
if (empty($account['version'])) {
DI::sysmsg()->addNotice(DI::l10n()->t("Error! No version data in file! This is not a Friendica account file?"));
return;
}
// check for username
// check if username matches deleted account
if (DBA::exists('user', ['nickname' => $account['user']['nickname']])
|| DBA::exists('userd', ['username' => $account['user']['nickname']])) {
DI::sysmsg()->addNotice(DI::l10n()->t("User '%s' already exists on this server!", $account['user']['nickname']));
return;
}
$oldbaseurl = $account['baseurl'];
$newbaseurl = DI::baseUrl();
$oldaddr = str_replace('http://', '@', Strings::normaliseLink($oldbaseurl));
$newaddr = str_replace('http://', '@', Strings::normaliseLink($newbaseurl));
if (!empty($account['profile']['addr'])) {
$old_handle = $account['profile']['addr'];
} else {
$old_handle = $account['user']['nickname'].$oldaddr;
}
// Creating a new guid to avoid problems with Diaspora
$account['user']['guid'] = System::createUUID();
$olduid = $account['user']['uid'];
unset($account['user']['uid']);
unset($account['user']['account_expired']);
unset($account['user']['account_expires_on']);
unset($account['user']['expire_notification_sent']);
$callback = function (&$value) use ($oldbaseurl, $oldaddr, $newbaseurl, $newaddr) {
$value = str_replace([$oldbaseurl, $oldaddr], [$newbaseurl, $newaddr], $value);
};
array_walk($account['user'], $callback);
// import user
$r = self::dbImportAssoc('user', $account['user']);
if ($r === false) {
Logger::warning("uimport:insert user : ERROR : " . DBA::errorMessage());
DI::sysmsg()->addNotice(DI::l10n()->t("User creation error"));
return;
}
$newuid = self::lastInsertId();
DI::pConfig()->set($newuid, 'system', 'previous_addr', $old_handle);
$errorcount = 0;
foreach ($account['contact'] as &$contact) {
if ($contact['uid'] == $olduid && $contact['self'] == '1') {
foreach ($contact as $k => &$v) {
$v = str_replace([$oldbaseurl, $oldaddr], [$newbaseurl, $newaddr], $v);
foreach (["profile", "avatar", "micro"] as $k) {
$v = str_replace($oldbaseurl . "/photo/" . $k . "/" . $olduid . ".jpg", $newbaseurl . "/photo/" . $k . "/" . $newuid . ".jpg", $v);
}
}
}
if ($contact['uid'] == $olduid && $contact['self'] == '0') {
// set contacts 'avatar-date' to NULL_DATE to let worker to update urls
$contact["avatar-date"] = DBA::NULL_DATETIME;
switch ($contact['network']) {
case Protocol::DFRN:
case Protocol::DIASPORA:
// send relocate message (below)
break;
case Protocol::FEED:
case Protocol::MAIL:
// Nothing to do
break;
default:
// archive other contacts
$contact['archive'] = "1";
}
}
$contact['uid'] = $newuid;
$r = self::dbImportAssoc('contact', $contact);
if ($r === false) {
Logger::warning("uimport:insert contact " . $contact['nick'] . "," . $contact['network'] . " : ERROR : " . DBA::errorMessage());
$errorcount++;
} else {
$contact['newid'] = self::lastInsertId();
}
}
if ($errorcount > 0) {
DI::sysmsg()->addNotice(DI::l10n()->tt("%d contact not imported", "%d contacts not imported", $errorcount));
}
foreach ($account['group'] as &$group) {
$group['uid'] = $newuid;
$r = self::dbImportAssoc('group', $group);
if ($r === false) {
Logger::warning("uimport:insert group " . $group['name'] . " : ERROR : " . DBA::errorMessage());
} else {
$group['newid'] = self::lastInsertId();
}
}
foreach ($account['group_member'] as &$group_member) {
$import = 0;
foreach ($account['group'] as $group) {
if ($group['id'] == $group_member['gid'] && isset($group['newid'])) {
$group_member['gid'] = $group['newid'];
$import++;
break;
}
}
foreach ($account['contact'] as $contact) {
if ($contact['id'] == $group_member['contact-id'] && isset($contact['newid'])) {
$group_member['contact-id'] = $contact['newid'];
$import++;
break;
}
}
if ($import == 2) {
$r = self::dbImportAssoc('group_member', $group_member);
if ($r === false) {
Logger::warning("uimport:insert group member " . $group_member['id'] . " : ERROR : " . DBA::errorMessage());
}
}
}
foreach ($account['profile'] as &$profile) {
unset($profile['id']);
$profile['uid'] = $newuid;
foreach ($profile as $k => &$v) {
$v = str_replace([$oldbaseurl, $oldaddr], [$newbaseurl, $newaddr], $v);
foreach (["profile", "avatar"] as $k) {
$v = str_replace($oldbaseurl . "/photo/" . $k . "/" . $olduid . ".jpg", $newbaseurl . "/photo/" . $k . "/" . $newuid . ".jpg", $v);
}
}
if (count($account['profile']) === 1 || $profile['is-default']) {
$r = self::dbImportAssoc('profile', $profile);
if ($r === false) {
Logger::warning("uimport:insert profile: ERROR : " . DBA::errorMessage());
DI::sysmsg()->addNotice(DI::l10n()->t("User profile creation error"));
DBA::delete('user', ['uid' => $newuid]);
DBA::delete('profile_field', ['uid' => $newuid]);
return;
}
$profile['id'] = DBA::lastInsertId();
}
Profile::migrate($profile);
}
$permissionSet = DI::permissionSet()->selectDefaultForUser($newuid);
foreach ($account['profile_fields'] ?? [] as $profile_field) {
$profile_field['uid'] = $newuid;
///@TODO Replace with permissionset import
$profile_field['psid'] = $profile_field['psid'] ? $permissionSet->uid : PermissionSet::PUBLIC;
if (self::dbImportAssoc('profile_field', $profile_field) === false) {
Logger::info("uimport:insert profile field " . $profile_field['id'] . " : ERROR : " . DBA::errorMessage());
}
}
foreach ($account['photo'] as &$photo) {
$photo['uid'] = $newuid;
$photo['data'] = hex2bin($photo['data']);
$Image = new Image($photo['data'], $photo['type']);
$r = Photo::store(
$Image,
$photo['uid'], $photo['contact-id'], //0
$photo['resource-id'], $photo['filename'], $photo['album'], $photo['scale'], $photo['profile'], //1
$photo['allow_cid'], $photo['allow_gid'], $photo['deny_cid'], $photo['deny_gid']
);
if ($r === false) {
Logger::warning("uimport:insert photo " . $photo['resource-id'] . "," . $photo['scale'] . " : ERROR : " . DBA::errorMessage());
}
}
foreach ($account['pconfig'] as &$pconfig) {
$pconfig['uid'] = $newuid;
$r = self::dbImportAssoc('pconfig', $pconfig);
if ($r === false) {
Logger::warning("uimport:insert pconfig " . $pconfig['id'] . " : ERROR : " . DBA::errorMessage());
}
}
// send relocate messages
Worker::add(Worker::PRIORITY_HIGH, 'Notifier', Delivery::RELOCATION, $newuid);
DI::sysmsg()->addInfo(DI::l10n()->t("Done. You can now login with your username and password"));
DI::baseUrl()->redirect('login');
}
}

415
src/Module/User/Import.php Normal file
View file

@ -0,0 +1,415 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Module\User;
use Friendica\App;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\L10n;
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\Database;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\Model\Photo;
use Friendica\Model\Profile;
use Friendica\Module\Response;
use Friendica\Navigation\SystemMessages;
use Friendica\Network\HTTPException;
use Friendica\Object\Image;
use Friendica\Security\PermissionSet\Repository\PermissionSet;
use Friendica\Util\Profiler;
use Friendica\Util\Strings;
use Friendica\Worker\Delivery;
use Psr\Log\LoggerInterface;
class Import extends \Friendica\BaseModule
{
const IMPORT_DEBUG = false;
/** @var App */
private $app;
/** @var IManageConfigValues */
private $config;
/** @var IManagePersonalConfigValues */
private $pconfig;
/** @var SystemMessages */
private $systemMessages;
/** @var Database */
private $database;
/** @var PermissionSet */
private $permissionSet;
public function __construct(PermissionSet $permissionSet, IManagePersonalConfigValues $pconfig, Database $database, SystemMessages $systemMessages, IManageConfigValues $config, App $app, 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->app = $app;
$this->config = $config;
$this->pconfig = $pconfig;
$this->systemMessages = $systemMessages;
$this->database = $database;
$this->permissionSet = $permissionSet;
}
protected function post(array $request = [])
{
if ($this->config->get('config', 'register_policy') != \Friendica\Module\Register::OPEN && !$this->app->isSiteAdmin()) {
throw new HttpException\ForbiddenException($this->t('Permission denied.'));
}
$max_dailies = intval($this->config->get('system', 'max_daily_registrations'));
if ($max_dailies) {
$total = $this->database->count('user', ["`register_date` > UTC_TIMESTAMP - INTERVAL 1 DAY"]);
if ($total >= $max_dailies) {
throw new HttpException\ForbiddenException($this->t('Permission denied.'));
}
}
if (!empty($_FILES['accountfile'])) {
$this->importAccount($_FILES['accountfile']);
}
}
protected function content(array $request = []): string
{
if (($this->config->get('config', 'register_policy') != \Friendica\Module\Register::OPEN) && !$this->app->isSiteAdmin()) {
$this->systemMessages->addNotice($this->t('User imports on closed servers can only be done by an administrator.'));
}
$max_dailies = intval($this->config->get('system', 'max_daily_registrations'));
if ($max_dailies) {
$total = $this->database->count('user', ["`register_date` > UTC_TIMESTAMP - INTERVAL 1 DAY"]);
if ($total >= $max_dailies) {
$this->logger->notice('max daily registrations exceeded.');
$this->systemMessages->addNotice($this->t('This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.'));
}
}
$tpl = Renderer::getMarkupTemplate('user/import.tpl');
return Renderer::replaceMacros($tpl, [
'$regbutt' => $this->t('Import'),
'$import' => [
'title' => $this->t('Move account'),
'intro' => $this->t('You can import an account from another Friendica server.'),
'instruct' => $this->t('You need to export your account from the old server and upload it here. We will recreate your old account here with all your contacts. We will try also to inform your friends that you moved here.'),
'warn' => $this->t("This feature is experimental. We can't import contacts from the OStatus network (GNU Social/Statusnet) or from Diaspora"),
'field' => ['accountfile', $this->t('Account file'), '<input id="id_accountfile" name="accountfile" type="file">', $this->t('To export your account, go to "Settings->Export your personal data" and select "Export account"')],
],
]);
}
private function lastInsertId(): int
{
if (self::IMPORT_DEBUG) {
return 1;
}
return $this->database->lastInsertId();
}
/**
* Remove columns from array $arr that aren't in table $table
*
* @param string $table Table name
* @param array &$arr Column=>Value array from json (by ref)
* @throws \Exception
*/
private function checkCols(string $table, array &$arr)
{
$tableColumns = DBStructure::getColumns($table);
$tcols = [];
$ttype = [];
// get a plain array of column names
foreach ($tableColumns as $tcol) {
$tcols[] = $tcol['Field'];
$ttype[$tcol['Field']] = $tcol['Type'];
}
// remove inexistent columns
foreach ($arr as $icol => $ival) {
if (!in_array($icol, $tcols)) {
unset($arr[$icol]);
continue;
}
if ($ttype[$icol] === 'datetime') {
$arr[$icol] = $ival ?? DBA::NULL_DATETIME;
}
}
}
/**
* Import data into table $table
*
* @param string $table Table name
* @param array $arr Column=>Value array from json
* @return bool
* @throws \Exception
*/
private function dbImportAssoc(string $table, array $arr): bool
{
if (isset($arr['id'])) {
unset($arr['id']);
}
$this->checkCols($table, $arr);
if (self::IMPORT_DEBUG) {
return true;
}
return $this->database->insert($table, $arr);
}
/**
* Import account file exported from mod/uexport
*
* @param array $file array from $_FILES
* @return void
* @throws HTTPException\FoundException
* @throws HTTPException\InternalServerErrorException
* @throws HTTPException\MovedPermanentlyException
* @throws HTTPException\TemporaryRedirectException
* @throws \ImagickException
*/
private function importAccount(array $file)
{
$this->logger->notice('Start user import from ' . $file['tmp_name']);
/*
STEPS
1. checks
2. replace old baseurl with new baseurl
3. import data (look at user id and contacts id)
4. archive non-dfrn contacts
5. send message to dfrn contacts
*/
$account = json_decode(file_get_contents($file['tmp_name']), true);
if ($account === null) {
$this->systemMessages->addNotice($this->t('Error decoding account file'));
return;
}
if (empty($account['version'])) {
$this->systemMessages->addNotice($this->t('Error! No version data in file! This is not a Friendica account file?'));
return;
}
// check for username
// check if username matches deleted account
if ($this->database->exists('user', ['nickname' => $account['user']['nickname']])
|| $this->database->exists('userd', ['username' => $account['user']['nickname']])) {
$this->systemMessages->addNotice($this->t("User '%s' already exists on this server!", $account['user']['nickname']));
return;
}
$oldBaseUrl = $account['baseurl'];
$newBaseUrl = $this->baseUrl;
$oldAddr = str_replace('http://', '@', Strings::normaliseLink($oldBaseUrl));
$newAddr = str_replace('http://', '@', Strings::normaliseLink($newBaseUrl));
if (!empty($account['profile']['addr'])) {
$oldHandle = $account['profile']['addr'];
} else {
$oldHandle = $account['user']['nickname'] . $oldAddr;
}
// Creating a new guid to avoid problems with Diaspora
$account['user']['guid'] = System::createUUID();
$oldUid = $account['user']['uid'];
unset($account['user']['uid']);
unset($account['user']['account_expired']);
unset($account['user']['account_expires_on']);
unset($account['user']['expire_notification_sent']);
array_walk($account['user'], function (&$user) use ($oldBaseUrl, $oldAddr, $newBaseUrl, $newAddr) {
$user = str_replace([$oldBaseUrl, $oldAddr], [$newBaseUrl, $newAddr], $user);
});
// import user
if ($this->dbImportAssoc('user', $account['user']) === false) {
$this->logger->warning('Error inserting user', ['user' => $account['user'], 'error' => $this->database->errorMessage()]);
$this->systemMessages->addNotice($this->t('User creation error'));
return;
}
$newUid = $this->lastInsertId();
$this->pconfig->set($newUid, 'system', 'previous_addr', $oldHandle);
$errorCount = 0;
array_walk($account['contact'], function (&$contact) use (&$errorCount, $oldUid, $oldBaseUrl, $oldAddr, $newUid, $newBaseUrl, $newAddr) {
if ($contact['uid'] == $oldUid && $contact['self'] == '1') {
array_walk($contact, function (&$field) use ($oldUid, $oldBaseUrl, $oldAddr, $newUid, $newBaseUrl, $newAddr) {
$field = str_replace([$oldBaseUrl, $oldAddr], [$newBaseUrl, $newAddr], $field);
foreach (['profile', 'avatar', 'micro'] as $key) {
$field = str_replace($oldBaseUrl . '/photo/' . $key . '/' . $oldUid . '.jpg', $newBaseUrl . '/photo/' . $key . '/' . $newUid . '.jpg', $field);
}
});
}
if ($contact['uid'] == $oldUid && $contact['self'] == '0') {
// set contacts 'avatar-date' to NULL_DATE to let worker update the URLs
$contact['avatar-date'] = DBA::NULL_DATETIME;
switch ($contact['network']) {
case Protocol::DFRN:
case Protocol::DIASPORA:
// send relocate message (below)
break;
case Protocol::FEED:
case Protocol::MAIL:
// Nothing to do
break;
default:
// archive other contacts
$contact['archive'] = '1';
}
}
$contact['uid'] = $newUid;
if ($this->dbImportAssoc('contact', $contact) === false) {
$this->logger->warning('Error inserting contact', ['nick' => $contact['nick'], 'network' => $contact['network'], 'error' => $this->database->errorMessage()]);
$errorCount++;
} else {
$contact['newid'] = $this->lastInsertId();
}
});
if ($errorCount > 0) {
$this->systemMessages->addNotice($this->tt('%d contact not imported', '%d contacts not imported', $errorCount));
}
array_walk($account['group'], function (&$group) use ($newUid) {
$group['uid'] = $newUid;
if ($this->dbImportAssoc('group', $group) === false) {
$this->logger->warning('Error inserting group', ['name' => $group['name'], 'error' => $this->database->errorMessage()]);
} else {
$group['newid'] = $this->lastInsertId();
}
});
foreach ($account['group_member'] as $group_member) {
$import = 0;
foreach ($account['group'] as $group) {
if ($group['id'] == $group_member['gid'] && isset($group['newid'])) {
$group_member['gid'] = $group['newid'];
$import++;
break;
}
}
foreach ($account['contact'] as $contact) {
if ($contact['id'] == $group_member['contact-id'] && isset($contact['newid'])) {
$group_member['contact-id'] = $contact['newid'];
$import++;
break;
}
}
if ($import == 2 && $this->dbImportAssoc('group_member', $group_member) === false) {
$this->logger->warning('Error inserting group member', ['gid' => $group_member['id'], 'error' => $this->database->errorMessage()]);
}
}
foreach ($account['profile'] as $profile) {
unset($profile['id']);
$profile['uid'] = $newUid;
array_walk($profile, function (&$field) use ($oldUid, $oldBaseUrl, $oldAddr, $newUid, $newBaseUrl, $newAddr) {
$field = str_replace([$oldBaseUrl, $oldAddr], [$newBaseUrl, $newAddr], $field);
foreach (['profile', 'avatar'] as $key) {
$field = str_replace($oldBaseUrl . '/photo/' . $key . '/' . $oldUid . '.jpg', $newBaseUrl . '/photo/' . $key . '/' . $newUid . '.jpg', $field);
}
});
if (count($account['profile']) === 1 || $profile['is-default']) {
if ($this->dbImportAssoc('profile', $profile) === false) {
$this->logger->warning('Error inserting profile', ['error' => $this->database->errorMessage()]);
$this->systemMessages->addNotice($this->t('User profile creation error'));
$this->database->delete('user', ['uid' => $newUid]);
$this->database->delete('profile_field', ['uid' => $newUid]);
return;
}
$profile['id'] = $this->database->lastInsertId();
}
Profile::migrate($profile);
}
$permissionSet = $this->permissionSet->selectDefaultForUser($newUid);
foreach ($account['profile_fields'] ?? [] as $profile_field) {
$profile_field['uid'] = $newUid;
///@TODO Replace with permissionset import
$profile_field['psid'] = $profile_field['psid'] ? $permissionSet->id : PermissionSet::PUBLIC;
if ($this->dbImportAssoc('profile_field', $profile_field) === false) {
$this->logger->info('Error inserting profile field', ['profile_id' => $profile_field['id'], 'error' => $this->database->errorMessage()]);
}
}
foreach ($account['photo'] as $photo) {
$photo['uid'] = $newUid;
$photo['data'] = hex2bin($photo['data']);
$r = Photo::store(
new Image($photo['data'], $photo['type']),
$photo['uid'], $photo['contact-id'], //0
$photo['resource-id'], $photo['filename'], $photo['album'], $photo['scale'], $photo['profile'], //1
$photo['allow_cid'], $photo['allow_gid'], $photo['deny_cid'], $photo['deny_gid']
);
if ($r === false) {
$this->logger->warning('Error inserting photo', ['resource-id' => $photo['resource-id'], 'scale' => $photo['scale'], 'error' => $this->database->errorMessage()]);
}
}
foreach ($account['pconfig'] as $pconfig) {
$pconfig['uid'] = $newUid;
if ($this->dbImportAssoc('pconfig', $pconfig) === false) {
$this->logger->warning('Error inserting pconfig', ['pconfig_id' => $pconfig['id'], 'error' => $this->database->errorMessage()]);
}
}
// send relocate messages
Worker::add(Worker::PRIORITY_HIGH, 'Notifier', Delivery::RELOCATION, $newUid);
$this->systemMessages->addInfo($this->t('Done. You can now login with your username and password'));
$this->baseUrl->redirect('login');
}
}

View file

@ -611,6 +611,8 @@ return [
'/update_profile' => [Module\Update\Profile::class, [R::GET]], '/update_profile' => [Module\Update\Profile::class, [R::GET]],
'/user/import' => [Module\User\Import::class, [R::GET, R::POST]],
'/view/theme/{theme}/style.pcss' => [Module\Theme::class, [R::GET]], '/view/theme/{theme}/style.pcss' => [Module\Theme::class, [R::GET]],
'/viewsrc/{item:\d+}' => [Module\Debug\ItemBody::class, [R::GET]], '/viewsrc/{item:\d+}' => [Module\Debug\ItemBody::class, [R::GET]],
'/webfinger' => [Module\Debug\WebFinger::class, [R::GET]], '/webfinger' => [Module\Debug\WebFinger::class, [R::GET]],

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 2022.12-dev\n" "Project-Id-Version: 2022.12-dev\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-02 14:17+0000\n" "POT-Creation-Date: 2022-11-02 11:31-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -105,15 +105,15 @@ msgstr ""
#: mod/item.php:870 mod/message.php:69 mod/message.php:114 mod/notes.php:44 #: mod/item.php:870 mod/message.php:69 mod/message.php:114 mod/notes.php:44
#: mod/ostatus_subscribe.php:33 mod/photos.php:159 mod/photos.php:886 #: mod/ostatus_subscribe.php:33 mod/photos.php:159 mod/photos.php:886
#: mod/repair_ostatus.php:31 mod/settings.php:40 mod/settings.php:50 #: mod/repair_ostatus.php:31 mod/settings.php:40 mod/settings.php:50
#: mod/settings.php:156 mod/suggest.php:34 mod/uimport.php:33 #: mod/settings.php:156 mod/suggest.php:34 src/Module/Attach.php:56
#: src/Module/Attach.php:56 src/Module/BaseApi.php:94 #: src/Module/BaseApi.php:94 src/Module/BaseNotifications.php:98
#: src/Module/BaseNotifications.php:98 src/Module/Contact/Advanced.php:60 #: src/Module/Contact/Advanced.php:60 src/Module/Contact/Follow.php:86
#: src/Module/Contact/Follow.php:86 src/Module/Contact/Follow.php:158 #: src/Module/Contact/Follow.php:158 src/Module/Contact/Unfollow.php:66
#: src/Module/Contact/Unfollow.php:66 src/Module/Contact/Unfollow.php:80 #: src/Module/Contact/Unfollow.php:80 src/Module/Contact/Unfollow.php:112
#: src/Module/Contact/Unfollow.php:112 src/Module/Delegation.php:118 #: src/Module/Delegation.php:118 src/Module/FollowConfirm.php:38
#: src/Module/FollowConfirm.php:38 src/Module/FriendSuggest.php:57 #: src/Module/FriendSuggest.php:57 src/Module/Group.php:40
#: src/Module/Group.php:40 src/Module/Group.php:83 src/Module/Invite.php:42 #: src/Module/Group.php:83 src/Module/Invite.php:42 src/Module/Invite.php:131
#: src/Module/Invite.php:131 src/Module/Notifications/Notification.php:76 #: src/Module/Notifications/Notification.php:76
#: src/Module/Notifications/Notification.php:107 #: src/Module/Notifications/Notification.php:107
#: src/Module/Profile/Attachment/Upload.php:97 src/Module/Profile/Common.php:55 #: src/Module/Profile/Attachment/Upload.php:97 src/Module/Profile/Common.php:55
#: src/Module/Profile/Contacts.php:55 src/Module/Profile/Photos/Upload.php:108 #: src/Module/Profile/Contacts.php:55 src/Module/Profile/Photos/Upload.php:108
@ -130,7 +130,8 @@ msgstr ""
#: src/Module/Settings/UserExport.php:84 src/Module/Settings/UserExport.php:118 #: src/Module/Settings/UserExport.php:84 src/Module/Settings/UserExport.php:118
#: src/Module/Settings/UserExport.php:219 #: src/Module/Settings/UserExport.php:219
#: src/Module/Settings/UserExport.php:239 #: src/Module/Settings/UserExport.php:239
#: src/Module/Settings/UserExport.php:304 #: src/Module/Settings/UserExport.php:304 src/Module/User/Import.php:84
#: src/Module/User/Import.php:91
msgid "Permission denied." msgid "Permission denied."
msgstr "" msgstr ""
@ -1357,51 +1358,6 @@ msgstr ""
msgid "Remove" msgid "Remove"
msgstr "" msgstr ""
#: mod/uimport.php:46
msgid "User imports on closed servers can only be done by an administrator."
msgstr ""
#: mod/uimport.php:55 src/Module/Register.php:99
msgid ""
"This site has exceeded the number of allowed daily account registrations. "
"Please try again tomorrow."
msgstr ""
#: mod/uimport.php:62 src/Module/Register.php:173
msgid "Import"
msgstr ""
#: mod/uimport.php:64
msgid "Move account"
msgstr ""
#: mod/uimport.php:65
msgid "You can import an account from another Friendica server."
msgstr ""
#: mod/uimport.php:66
msgid ""
"You need to export your account from the old server and upload it here. We "
"will recreate your old account here with all your contacts. We will try also "
"to inform your friends that you moved here."
msgstr ""
#: mod/uimport.php:67
msgid ""
"This feature is experimental. We can't import contacts from the OStatus "
"network (GNU Social/Statusnet) or from Diaspora"
msgstr ""
#: mod/uimport.php:68
msgid "Account file"
msgstr ""
#: mod/uimport.php:68
msgid ""
"To export your account, go to \"Settings->Export your personal data\" and "
"select \"Export account\""
msgstr ""
#: src/App.php:490 #: src/App.php:490
msgid "No system theme config value set." msgid "No system theme config value set."
msgstr "" msgstr ""
@ -3344,38 +3300,6 @@ msgid ""
"\t\t\t\t\tThe friendica database was successfully updated from %s to %s." "\t\t\t\t\tThe friendica database was successfully updated from %s to %s."
msgstr "" msgstr ""
#: src/Core/UserImport.php:126
msgid "Error decoding account file"
msgstr ""
#: src/Core/UserImport.php:132
msgid "Error! No version data in file! This is not a Friendica account file?"
msgstr ""
#: src/Core/UserImport.php:140
#, php-format
msgid "User '%s' already exists on this server!"
msgstr ""
#: src/Core/UserImport.php:176
msgid "User creation error"
msgstr ""
#: src/Core/UserImport.php:221
#, php-format
msgid "%d contact not imported"
msgid_plural "%d contacts not imported"
msgstr[0] ""
msgstr[1] ""
#: src/Core/UserImport.php:274
msgid "User profile creation error"
msgstr ""
#: src/Core/UserImport.php:327
msgid "Done. You can now login with your username and password"
msgstr ""
#: src/Database/DBStructure.php:57 #: src/Database/DBStructure.php:57
#, php-format #, php-format
msgid "The database version had been set to %s." msgid "The database version had been set to %s."
@ -8490,6 +8414,12 @@ msgstr ""
msgid "Only parent users can create additional accounts." msgid "Only parent users can create additional accounts."
msgstr "" msgstr ""
#: src/Module/Register.php:99 src/Module/User/Import.php:111
msgid ""
"This site has exceeded the number of allowed daily account registrations. "
"Please try again tomorrow."
msgstr ""
#: src/Module/Register.php:116 #: src/Module/Register.php:116
msgid "" msgid ""
"You may (optionally) fill in this form via OpenID by supplying your OpenID " "You may (optionally) fill in this form via OpenID by supplying your OpenID "
@ -8565,6 +8495,10 @@ msgstr ""
msgid "Choose a nickname: " msgid "Choose a nickname: "
msgstr "" msgstr ""
#: src/Module/Register.php:173 src/Module/User/Import.php:117
msgid "Import"
msgstr ""
#: src/Module/Register.php:174 #: src/Module/Register.php:174
msgid "Import your profile to this friendica instance" msgid "Import your profile to this friendica instance"
msgstr "" msgstr ""
@ -10139,6 +10073,73 @@ msgstr ""
msgid "Privacy Statement" msgid "Privacy Statement"
msgstr "" msgstr ""
#: src/Module/User/Import.php:103
msgid "User imports on closed servers can only be done by an administrator."
msgstr ""
#: src/Module/User/Import.php:119
msgid "Move account"
msgstr ""
#: src/Module/User/Import.php:120
msgid "You can import an account from another Friendica server."
msgstr ""
#: src/Module/User/Import.php:121
msgid ""
"You need to export your account from the old server and upload it here. We "
"will recreate your old account here with all your contacts. We will try also "
"to inform your friends that you moved here."
msgstr ""
#: src/Module/User/Import.php:122
msgid ""
"This feature is experimental. We can't import contacts from the OStatus "
"network (GNU Social/Statusnet) or from Diaspora"
msgstr ""
#: src/Module/User/Import.php:123
msgid "Account file"
msgstr ""
#: src/Module/User/Import.php:123
msgid ""
"To export your account, go to \"Settings->Export your personal data\" and "
"select \"Export account\""
msgstr ""
#: src/Module/User/Import.php:217
msgid "Error decoding account file"
msgstr ""
#: src/Module/User/Import.php:222
msgid "Error! No version data in file! This is not a Friendica account file?"
msgstr ""
#: src/Module/User/Import.php:230
#, php-format
msgid "User '%s' already exists on this server!"
msgstr ""
#: src/Module/User/Import.php:263
msgid "User creation error"
msgstr ""
#: src/Module/User/Import.php:312
#, php-format
msgid "%d contact not imported"
msgid_plural "%d contacts not imported"
msgstr[0] ""
msgstr[1] ""
#: src/Module/User/Import.php:361
msgid "User profile creation error"
msgstr ""
#: src/Module/User/Import.php:412
msgid "Done. You can now login with your username and password"
msgstr ""
#: src/Module/Welcome.php:44 #: src/Module/Welcome.php:44
msgid "Welcome to Friendica" msgid "Welcome to Friendica"
msgstr "" msgstr ""

View file

@ -1,14 +0,0 @@
<form action="uimport" method="post" id="uimport-form" enctype="multipart/form-data">
<h1>{{$import.title}}</h1>
<p>{{$import.intro}}</p>
<p>{{$import.instruct}}</p>
<p><b>{{$import.warn}}</b></p>
{{include file="field_custom.tpl" field=$import.field}}
<div id="register-submit-wrapper">
<input type="submit" name="submit" id="register-submit-button" value="{{$regbutt}}" />
</div>
<div id="register-submit-end"></div>
</form>

View file

@ -0,0 +1,13 @@
<form action="uimport" method="post" id="uimport-form" enctype="multipart/form-data">
<h2>{{$import.title}}</h2>
<p>{{$import.intro}}</p>
<p>{{$import.instruct}}</p>
<p><b>{{$import.warn}}</b></p>
{{include file="field_custom.tpl" field=$import.field}}
<div id="register-submit-wrapper">
<button type="submit" name="submit" id="register-submit-button" class="btn btn-primary">{{$regbutt}}</button>
</div>
<div id="register-submit-end"></div>
</form>