diff --git a/doc/Export-Import-Contacts.md b/doc/Export-Import-Contacts.md new file mode 100644 index 000000000..3e1e91109 --- /dev/null +++ b/doc/Export-Import-Contacts.md @@ -0,0 +1,23 @@ +# Export / Import of followed Contacts + +* [Home](help) + +In addition to [move your account](help/Move-Account) you can export and import the list of accounts you follow. +The exported list is stored as CSV file that is compatible to the format used by other platforms as e.g. Mastodon or Pleroma. + +## Export of followed Contacts + +To export the list of accounts that you follow, go to the [Settings Export personal date](settings/userexport) and click the [Export Contacts to CSV](settings/userexport/contact). + +## Import of followed Contacts + +To import contacts from a CSV file, go to the [Settings page](settings). +At the bottom of the *account settings* page you'll find the *import contacts* section. +Upload the CSV file there. + +### Supported File Format + +The CSV file *must* contain at least one column. +In the first column the table should contain either the handle or URL of an followed account. +(one account per row.) +Other columns in the CSV file will be ignored. diff --git a/doc/Home.md b/doc/Home.md index 03e214257..095be1bb6 100644 --- a/doc/Home.md +++ b/doc/Home.md @@ -21,6 +21,7 @@ Friendica Documentation and Resources * [Chats](help/Chats) * Further information * [Move your account](help/Move-Account) + * [Export / Import of followed Contacts](help/Export-Import-Contacts) * [Delete your account](help/Remove-Account) * [Frequently asked questions (FAQ)](help/FAQ) diff --git a/doc/de/Export-Import-Contacts.md b/doc/de/Export-Import-Contacts.md new file mode 100644 index 000000000..73905567c --- /dev/null +++ b/doc/de/Export-Import-Contacts.md @@ -0,0 +1,23 @@ +# Export / Import von gefolgten Kontakte + +* [Home](help) + +Zusätzlich zum [Umziehen des Accounts](help/Move-Account) kannst du die Liste der von dir gefolgten Kontakte exportieren und importieren. +Die exportierte Liste wird als CSV Datei in einem zu anderen Plattformen, z.B. Mastodon oder Pleroma, kompatiblen Format gespeichert. + +## Export der gefolgten Kontakte + +Um die Liste der Kontakte *denen du folgst* zu exportieren, geht die [Einstellungen Persönliche Daten exportieren](settings/userexport) und klicke den [Exportiere Kontakte als CSV](settings/userexport/contact) an. + +## Import der gefolgten Kontakte + +Um die Kontakt CSV Datei zu importieren, gehe in die [Einstellungen](settings). +Am Ende der Einstellungen zum Nutzerkonto findest du den Abschnitt "Kontakte Importieren". +Hier kannst du die CSV Datei auswählen und hoch laden. + +### Unterstütztes Datei Format + +Die CSV Datei *muss* mindestens eine Spalte beinhalten. +In der ersten Spalte der Tabelle sollte *sollte* entweder das Handle oder die URL des gefolgten Kontakts. +(Ein Kontakt pro Zeile.) +Alle anderen Spalten der CSV Datei werden beim Importieren ignoriert. diff --git a/doc/de/Home.md b/doc/de/Home.md index 1498ccff1..536bff720 100644 --- a/doc/de/Home.md +++ b/doc/de/Home.md @@ -21,6 +21,7 @@ Friendica - Dokumentation und Ressourcen * [Chats](help/Chats) * Weiterführende Informationen * [Account umziehen](help/Move-Account) + * [Export / Import gefolgter Kontakte](help/Export-Import-Contacts) * [Account löschen](help/Remove-Account) * [Bugs und Probleme](help/Bugs-and-Issues) * [Häufig gestellte Fragen (FAQ)](help/FAQ) diff --git a/mod/settings.php b/mod/settings.php index 3d471a5cc..5709df720 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -390,6 +390,33 @@ function settings_post(App $a) BaseModule::checkFormSecurityTokenRedirectOnError('/settings', 'settings'); + // Import Contacts from CSV file + if (!empty($_POST['importcontact-submit'])) { + if (isset($_FILES['importcontact-filename'])) { + // was there an error + if ($_FILES['importcontact-filename']['error'] > 0) { + Logger::notice('Contact CSV file upload error'); + info(L10n::t('Contact CSV file upload error')); + } else { + $csvArray = array_map('str_getcsv', file($_FILES['importcontact-filename']['tmp_name'])); + // import contacts + foreach ($csvArray as $csvRow) { + // The 1st row may, or may not contain the headers of the table + // We expect the 1st field of the row to contain either the URL + // or the handle of the account, therefore we check for either + // "http" or "@" to be present in the string. + // All other fields from the row will be ignored + if ((strpos($csvRow[0],'@') !== false) || (strpos($csvRow[0],'http') !== false)) { + $arr = Contact::createFromProbe($_SESSION['uid'], $csvRow[0], '', false); + } + } + info(L10n::t('Importing Contacts done')); + // delete temp file + unlink($filename); + } + } + } + if (!empty($_POST['resend_relocate'])) { Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::RELOCATION, local_user()); info(L10n::t("Relocate message has been send to your contacts")); @@ -1223,6 +1250,10 @@ function settings_content(App $a) '$h_descadvn' => L10n::t('Change the behaviour of this account for special situations'), '$pagetype' => $pagetype, + '$importcontact' => L10n::t('Import Contacts'), + '$importcontact_text' => L10n::t('Upload a CSV file that contains the handle of your followed accounts in the first column you exported from the old account.'), + '$importcontact_button' => L10n::t('Upload File'), + '$importcontact_maxsize' => Config::get('system', max_csv_file_size, 30720), '$relocate' => L10n::t('Relocate'), '$relocate_text' => L10n::t("If you have moved this profile from another server, and some of your contacts don't receive your updates, try pushing this button."), '$relocate_button' => L10n::t("Resend relocate message to contacts"), diff --git a/src/Module/Settings/UserExport.php b/src/Module/Settings/UserExport.php index 41072d7ef..d5b8f88ec 100644 --- a/src/Module/Settings/UserExport.php +++ b/src/Module/Settings/UserExport.php @@ -23,10 +23,11 @@ class UserExport extends BaseSettingsModule { /** * Handle the request to export data. - * At the moment one can export two different data set + * At the moment one can export three different data set * 1. The profile data that can be used by uimport to resettle * to a different Friendica instance * 2. The entire data-set, profile plus postings + * 3. A list of contacts as CSV file similar to the export of Mastodon * * If there is an action required through the URL / path, react * accordingly and export the requested data. @@ -42,6 +43,7 @@ class UserExport extends BaseSettingsModule $options = [ ['settings/userexport/account', L10n::t('Export account'), L10n::t('Export your account info and contacts. Use this to make a backup of your account and/or to move it to another server.')], ['settings/userexport/backup', L10n::t('Export all'), L10n::t("Export your accout info, contacts and all your items as json. Could be a very big file, and could take a lot of time. Use this to make a full backup of your account \x28photos are not exported\x29")], + ['settings/userexport/contact', L10n::t('Export Contacts to CSV'), L10n::t("Export the list of the accounts you are following as CSV file. Compatible to e.g. Mastodon.")], ]; Hook::callAll('uexport_options', $options); @@ -64,17 +66,25 @@ class UserExport extends BaseSettingsModule // @TODO Replace with router-provided arguments $action = $args->get(2); $user = self::getApp()->user; - header("Content-type: application/json"); - header('Content-Disposition: attachment; filename="' . $user['nickname'] . '.' . $action . '"'); switch ($action) { case "backup": + header("Content-type: application/json"); + header('Content-Disposition: attachment; filename="' . $user['nickname'] . '.' . $action . '"'); self::exportAll(self::getApp()); exit(); break; case "account": + header("Content-type: application/json"); + header('Content-Disposition: attachment; filename="' . $user['nickname'] . '.' . $action . '"'); self::exportAccount(self::getApp()); exit(); break; + case "contact": + header("Content-type: application/csv"); + header('Content-Disposition: attachment; filename="' . $user['nickname'] . '-contacts.csv'. '"'); + self::exportContactsAsCSV(); + exit(); + break; default: exit(); } @@ -134,6 +144,20 @@ class UserExport extends BaseSettingsModule return $result; } + /** + * Export a list of the contacts as CSV file as e.g. Mastodon and Pleroma are doing. + **/ + private static function exportContactsAsCSV() + { + // write the table header (like Mastodon) + echo "Account address, Show boosts\n"; + // get all the contacts + $contacts = DBA::select('contact', ['addr'], ['uid' => $_SESSION['uid'], 'self' => false, 'rel' => [1,3], 'deleted' => false]); + while ($contact = DBA::fetch($contacts)) { + echo $contact['addr'] . ", true\n"; + } + DBA::close($contacts); + } private static function exportAccount(App $a) { $user = self::exportRow( diff --git a/static/settings.config.php b/static/settings.config.php index bf8b62f15..a5c6c3aea 100644 --- a/static/settings.config.php +++ b/static/settings.config.php @@ -124,6 +124,12 @@ return [ // The fully-qualified URL of this Friendica node. // Used by the worker in a non-HTTP execution environment. 'url' => '', + + // max_csv_file_size (Integer) + // When uploading a CSV with account addresses to follow + // in the user settings, this controls the maximum file + // size of the upload file. + 'max_csv_file_size' => 30720, ], // Used in the admin settings to lock certain features diff --git a/view/templates/settings/settings.tpl b/view/templates/settings/settings.tpl index c95c0b143..af1352c4c 100644 --- a/view/templates/settings/settings.tpl +++ b/view/templates/settings/settings.tpl @@ -2,7 +2,7 @@ {{$nickname_block nofilter}} -
+

{{$h_pass}}

@@ -196,6 +196,17 @@ +

{{$importcontact}}

+
+ +
{{$importcontact_text}}
+ + +
+ +
+
+

{{$relocate}}

{{$relocate_text}}
diff --git a/view/theme/frio/templates/settings/settings.tpl b/view/theme/frio/templates/settings/settings.tpl index 700c2c06c..4ed94b182 100644 --- a/view/theme/frio/templates/settings/settings.tpl +++ b/view/theme/frio/templates/settings/settings.tpl @@ -270,6 +270,31 @@
+ {{* Import contacts CSV *}} +
+ +
+
+ +
{{$importcontact_text}}
+ + + +
+
+ +
+
+
+
+
+ {{* The relocate setting section *}}