diff options
-rw-r--r-- | Zotlabs/Module/Import_items.php | 44 | ||||
-rw-r--r-- | Zotlabs/Module/Uexport.php | 170 | ||||
-rw-r--r-- | include/channel.php | 46 | ||||
-rw-r--r-- | view/tpl/uexport.tpl | 61 |
4 files changed, 258 insertions, 63 deletions
diff --git a/Zotlabs/Module/Import_items.php b/Zotlabs/Module/Import_items.php index c2b2506fe..512dd88fc 100644 --- a/Zotlabs/Module/Import_items.php +++ b/Zotlabs/Module/Import_items.php @@ -38,7 +38,7 @@ class Import_items extends \Zotlabs\Web\Controller { } unlink($src); } - +/* if(! $src) { $old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : ''); @@ -71,6 +71,7 @@ class Import_items extends \Zotlabs\Web\Controller { else notice( t('Unable to download data from old server') . EOL); } +*/ if(! $data) { logger('Empty file.'); @@ -79,7 +80,6 @@ class Import_items extends \Zotlabs\Web\Controller { } $data = json_decode($data, true); - //logger('import: data: ' . print_r($data,true)); //print_r($data); @@ -97,15 +97,45 @@ class Import_items extends \Zotlabs\Web\Controller { $channel = \App::get_channel(); - if(array_key_exists('item',$data) && $data['item']) { - import_items($channel,$data['item'],false,((array_key_exists('relocate',$data)) ? $data['relocate'] : null)); + if(array_key_exists('item',$data) && is_array($data['item'])) { + import_items($channel, $data['item'], false, ((array_key_exists('relocate',$data)) ? $data['relocate'] : null)); + info( t('Content import completed') . EOL); + } + + if (array_key_exists('chatroom',$data) && is_array($data['chatroom'])) { + import_chatrooms($channel, $data['chatroom']); + info( t('Chatroom import completed') . EOL); + + } + + if (array_key_exists('event',$data) && is_array($data['event'])) { + import_events($channel, $data['event']); + info( t('Channel calendar import 1/2 completed') . EOL); + + } + + if (array_key_exists('event_item',$data) && is_array($data['event_item'])) { + import_items($channel, $data['event_item'], false, ((array_key_exists('relocate',$data)) ? $data['relocate'] : null)); + info( t('Channel calendar import 2/2 completed') . EOL); + + } + + if (array_key_exists('menu',$data) && is_array($data['menu'])) { + import_menus($channel, $data['menu']); + info( t('Menu import completed') . EOL); + } + + if (array_key_exists('wiki',$data) && is_array($data['wiki'])) { + import_items($channel, $data['wiki'], false, ((array_key_exists('relocate',$data)) ? $data['relocate'] : null)); + info( t('Wiki import completed') . EOL); + } - if(array_key_exists('item_id',$data) && $data['item_id']) { - import_item_ids($channel,$data['item_id']); + if (array_key_exists('webpages',$data) && is_array($data['webpages'])) { + import_items($channel, $data['webpages'], false, ((array_key_exists('relocate',$data)) ? $data['relocate'] : null)); + info( t('Webpages import completed') . EOL); } - info( t('Import completed') . EOL); } diff --git a/Zotlabs/Module/Uexport.php b/Zotlabs/Module/Uexport.php index d73bc40d4..c9f02fb35 100644 --- a/Zotlabs/Module/Uexport.php +++ b/Zotlabs/Module/Uexport.php @@ -2,24 +2,27 @@ namespace Zotlabs\Module; use App; +use ZipArchive; use Zotlabs\Lib\Apps; use Zotlabs\Web\Controller; class Uexport extends Controller { function init() { - if(! local_channel()) - killme(); + if(! local_channel()) { + return; + } - if(! Apps::system_app_installed(local_channel(), 'Channel Export')) + if(! Apps::system_app_installed(local_channel(), 'Channel Export')) { return; + } if(argc() > 1) { - $sections = (($_REQUEST['sections']) ? explode(',',$_REQUEST['sections']) : ''); $zap_compat = (($_REQUEST['zap_compat']) ? intval($_REQUEST['zap_compat']) : false); - $channel = App::get_channel(); + $year = null; + $month = null; if(argc() > 1 && intval(argv(1)) > 1900) { $year = intval(argv(1)); @@ -29,25 +32,110 @@ class Uexport extends Controller { $month = intval(argv(2)); } - header('content-type: application/json'); - header('content-disposition: attachment; filename="' . $channel['channel_address'] . (($year) ? '-' . $year : '') . (($month) ? '-' . $month : '') . (($_REQUEST['sections']) ? '-' . $_REQUEST['sections'] : '') . '.json"' ); + $sections = []; + $section = ''; + if(argc() > 1 && ctype_lower(argv(1))) { + $section = argv(1); + } - if($year) { - echo json_encode(identity_export_year(local_channel(),$year,$month, $zap_compat)); - killme(); + switch ($section) { + case 'channel': + $sections = get_default_export_sections(); + break; + case 'chatrooms': + $sections = ['chatrooms']; + break; + case 'events': + $sections = ['events']; + break; + case 'webpages': + $sections = ['webpages']; + break; + case 'wikis': + $sections = ['wikis']; + break; + case 'custom': + default: + $custom_sections = ['chatrooms', 'events', 'webpages', 'wikis']; + $raw_sections = (($_REQUEST['sections']) ? explode(',', $_REQUEST['sections']) : ''); + if ($raw_sections) { + foreach ($raw_sections as $raw_section) { + if(in_array($raw_section, $custom_sections)) { + $sections[] = $raw_section; + } + } + } } - if(argc() > 1 && argv(1) === 'basic') { - echo json_encode(identity_basic_export(local_channel(),$sections, $zap_compat)); + if ($sections) { + + $export = json_encode(identity_basic_export(local_channel(), $sections, $zap_compat)); + + header('Content-Type: application/json'); + header('Content-Disposition: attachment; filename="' . $channel['channel_address'] . '-' . implode('-', $sections) . '.json"'); + header('Content-Length: ' . strlen($export)); + + echo $export; + + killme(); + } + elseif ($year && !$month) { + $zip_dir = 'store/[data]/' . $channel['channel_address'] . '/tmp'; + if (!is_dir($zip_dir)) + mkdir($zip_dir, STORAGE_DEFAULT_PERMISSIONS, true); + + $zip_file = $channel['channel_address'] . '-' . $year . '.zip'; + $zip_path = $zip_dir . '/' . $zip_file; + $zip_content_available = false; + $zip = new ZipArchive(); + + if ($zip->open($zip_path, ZipArchive::CREATE) === true) { + $month = 1; + while ($month <= 12) { + $name = $channel['channel_address'] . '-' . $year . '-' . $month . '.json'; + $content = identity_export_year(local_channel(), $year, $month, $zap_compat); + if(isset($content['item'])) { + $zip_content_available = true; + $zip->addFromString($name, json_encode($content)); + } + $month++; + } + $zip->setCompressionName($zip_path, ZipArchive::CM_STORE); + $zip->close(); + } + if (!$zip_content_available) { + unlink($zip_path); + notice(t('No content available for year') . ' ' . $year . EOL); + goaway('/uexport'); + } + + header('Content-Type: application/zip'); + header('Content-Disposition: attachment; filename="' . $zip_file . '"'); + header('Content-Length: ' . filesize($zip_path)); + + $istream = fopen($zip_path, 'rb'); + $ostream = fopen('php://output', 'wb'); + if ($istream && $ostream) { + pipe_streams($istream, $ostream); + fclose($istream); + fclose($ostream); + } + + unlink($zip_path); killme(); } + elseif ($year && $month) { + $export = json_encode(identity_export_year(local_channel(), $year, $month, $zap_compat)); - // Warning: this option may consume a lot of memory + header('Content-Type: application/json'); + header('Content-Disposition: attachment; filename="' . $channel['channel_address'] . '-' . $year . '-' . $month . '.json"'); + header('Content-Length: ' . strlen($export)); - if(argc() > 1 && argv(1) === 'complete') { - $sections = get_default_export_sections(); - $sections[] = 'items'; - echo json_encode(identity_basic_export(local_channel(),$sections, $zap_compat)); + echo $export; + + killme(); + } + else { killme(); } } @@ -62,27 +150,47 @@ class Uexport extends Controller { return Apps::app_render($papp, 'module'); } - $y = datetime_convert('UTC',date_default_timezone_get(),'now','Y'); + $account = App::get_account(); + $year_start = datetime_convert('UTC', date_default_timezone_get(), $account['account_created'], 'Y'); + $year_end = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y'); + $years = []; + + while ($year_start <= $year_end) { + $years[] = $year_start; + $year_start++; + } + + $item_import_url = '/import_items'; + $channel_import_url = '/import'; - $yearurl = z_root() . '/uexport/' . $y; - $janurl = z_root() . '/uexport/' . $y . '/1'; - $impurl = '/import_items'; $o = replace_macros(get_markup_template('uexport.tpl'), array( '$title' => t('Export Channel'), - '$basictitle' => t('Export Channel'), - '$basic' => t('Export your basic channel information to a file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new server hub, but does not contain your content.'), - '$fulltitle' => t('Export Content'), - '$full' => t('Export your channel information and recent content to a JSON backup that can be restored or imported to another server hub. This backs up all of your connections, permissions, profile data and several months of posts. This file may be VERY large. Please be patient - it may take several minutes for this download to begin.'), - '$by_year' => t('Export your posts from a given year.'), + '$channel_title' => t('Export channel'), + '$channel_info' => t('This will export your identity and social graph into a file which can be used to import your channel to a new hub.'), + + '$years' => $years, + '$content_title' => t('Export content'), + '$content_info' => t('This will export your posts, direct messages, articles and cards per month stored into a zip file per year. Months with no posts will be dismissed.'), - '$extra' => t('You may also export your posts and conversations for a particular year or month. Adjust the date in your browser location bar to select other dates. If the export fails (possibly due to memory exhaustion on your server hub), please try again selecting a more limited date range.'), - '$extra2' => sprintf( t('To select all posts for a given year, such as this year, visit <a href="%1$s">%2$s</a>'),$yearurl,$yearurl), - '$extra3' => sprintf( t('To select all posts for a given month, such as January of this year, visit <a href="%1$s">%2$s</a>'),$janurl,$janurl), - '$extra4' => sprintf( t('These content files may be imported or restored by visiting <a href="%1$s">%2$s</a> on any site containing your channel. For best results please import or restore these in date order (oldest first).'),$impurl,$impurl) + '$wikis_title' => t('Export wikis'), + '$wikis_info' => t('This will export your wikis and wiki pages.'), + '$webpages_title' => t('Export webpages'), + '$webpages_info' => t('This will export your webpages and menus.'), + + '$events_title' => t('Export channel calendar'), + '$events_info' => t('This will export your channel calendar events and associated items. CalDAV calendars are not included.'), + + '$chatrooms_title' => t('Export chatrooms'), + '$chatrooms_info' => t('This will export your chatrooms. Chat history is dismissed.'), + + '$items_extra_info' => sprintf( t('This export can be imported or restored by visiting <a href="%1$s">%2$s</a> on any site containing your channel.'), $item_import_url, $item_import_url), )); - return $o; + return $o; } + + + } diff --git a/include/channel.php b/include/channel.php index 2db0434ca..7188d76f8 100644 --- a/include/channel.php +++ b/include/channel.php @@ -767,10 +767,10 @@ function get_default_export_sections() { 'connections', 'config', 'apps', - 'chatrooms', - 'events', - 'webpages', - 'wikis' +// 'chatrooms', +// 'events', +// 'webpages', +// 'wikis' ]; $cb = [ 'sections' => $sections ]; @@ -1179,7 +1179,7 @@ function identity_export_year($channel_id, $year, $month = 0, $zap_compat = fals } /** - * @brief Export items within an arbitrary date range. + * @brief Export conv items within an arbitrary date range. * * Date/time is in UTC. * @@ -1212,19 +1212,39 @@ function channel_export_items_date($channel_id, $start, $finish, $zap_compat = f } - $r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created <= '%s' and resource_type != 'photo' order by created", - intval(ITEM_TYPE_POST), + // Fetch parent items for the timeframe + $r = q("SELECT parent AS item_id FROM item + WHERE uid = %d AND (item_wall = 1 OR item_private = 2) AND item_thread_top = 1 + AND resource_type IN ('group_item', '') AND item_deleted = 0 + AND created >= '%s' AND created <= '%s' + ORDER BY created", intval($channel_id), dbesc($start), dbesc($finish) ); - if($r) { - $ret['item'] = array(); - xchan_query($r); - $r = fetch_post_tags($r, true); - foreach($r as $rr) - $ret['item'][] = encode_item($rr, true, $zap_compat); + $parents_str = ids_to_querystr($r, 'item_id'); + + $items = q("SELECT * FROM item + WHERE uid = %d + AND parent IN ( $parents_str ) + ORDER BY created", + intval($channel_id) + ); + + //$items = q("select * from item where (item_wall = 1 or item_type != %d ) and resource_type = '' and item_deleted = 0 and uid = %d and created >= '%s' and created <= '%s' order by created", + //intval(ITEM_TYPE_POST), + //intval($channel_id), + //dbesc($start), + //dbesc($finish) + //); + + if($items) { + $ret['item'] = []; + xchan_query($items); + $r = fetch_post_tags($items, true); + foreach ($items as $item) + $ret['item'][] = encode_item($item, true, $zap_compat); } return $ret; diff --git a/view/tpl/uexport.tpl b/view/tpl/uexport.tpl index 7eafd97a6..2b7967970 100644 --- a/view/tpl/uexport.tpl +++ b/view/tpl/uexport.tpl @@ -3,17 +3,54 @@ <h2>{{$title}}</h2> </div> <div class="section-content-wrapper"> - <b><a href="uexport/basic">{{$basictitle}}</a></b></p> - <p>{{$basic}}</p> - - <p><b><a href="uexport/complete">{{$fulltitle}}</a></b></p> - <p>{{$full}}</p> - - <p>{{$extra}}</p> - <p>{{$extra2}}</p> - <p>{{$extra3}}</p> - - <p>{{$extra4}}</p> - + <p class="mb-3"> + <h3>{{$channel_title}}</h3> + <p> + {{$channel_info}} + </p> + <a href="uexport/channel" class="btn btn-outline-primary"><i class="fa fa-download"></i> {{$channel_title}}</a> + </p> + <p class="mb-3"> + <h3>{{$content_title}}</h3> + <p> + {{$content_info}} + {{$items_extra_info}} + </p> + {{foreach $years as $year}} + <a href="uexport/{{$year}}" class="btn btn-outline-primary"><i class="fa fa-download"></i> {{$year}}</a> + {{/foreach}} + </p> + <p class="mb-3"> + <h3>{{$wikis_title}}</h3> + <p> + {{$wikis_info}} + {{$items_extra_info}} + </p> + <a href="uexport/wikis" class="btn btn-outline-primary"><i class="fa fa-download"></i> {{$wikis_title}}</a> + </p> + <p class="mb-3"> + <h3>{{$webpages_title}}</h3> + <p> + {{$webpages_info}} + {{$items_extra_info}} + </p> + <a href="uexport/webpages" class="btn btn-outline-primary"><i class="fa fa-download"></i> {{$webpages_title}}</a> + </p> + <p class="mb-3"> + <h3>{{$events_title}}</h3> + <p> + {{$events_info}} + {{$items_extra_info}} + </p> + <a href="uexport/events" class="btn btn-outline-primary"><i class="fa fa-download"></i> {{$events_title}}</a> + </p> + <p class="mb-3"> + <h3>{{$chatrooms_title}}</h3> + <p> + {{$chatrooms_info}} + {{$items_extra_info}} + </p> + <a href="uexport/chatrooms" class="btn btn-outline-primary"><i class="fa fa-download"></i> {{$chatrooms_title}}</a> + </p> </div> </div> |