Merge pull request #12087 from MrPetovan/task/4090-move-mod-uimport
Move mod/uimport.php to src/Module
This commit is contained in:
commit
da1c13368b
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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".
|
||||||
|
|
||||||
|
|
|
@ -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"')],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
|
@ -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
415
src/Module/User/Import.php
Normal 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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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]],
|
||||||
|
|
|
@ -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 ""
|
||||||
|
|
|
@ -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>
|
|
13
view/templates/user/import.tpl
Normal file
13
view/templates/user/import.tpl
Normal 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>
|
Loading…
Reference in a new issue