diff options
author | zotlabs <mike@macgirvin.com> | 2016-08-31 06:32:54 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-08-31 06:32:54 +1000 |
commit | b485d09847852efe935cd84f5f8f0ebf067c1f68 (patch) | |
tree | ca090d4dcb461dc46ba79d726c39cda388deeef6 | |
parent | 202b757bc46d17b324f79751ce754e16ba737386 (diff) | |
parent | ad5c93d6738d705b9ca196cc7481c26a3a9b9962 (diff) | |
download | volse-hubzilla-b485d09847852efe935cd84f5f8f0ebf067c1f68.tar.gz volse-hubzilla-b485d09847852efe935cd84f5f8f0ebf067c1f68.tar.bz2 volse-hubzilla-b485d09847852efe935cd84f5f8f0ebf067c1f68.zip |
Merge pull request #506 from anaqreon/website-export
Website export
-rw-r--r-- | Zotlabs/Lib/ExtendedZip.php | 57 | ||||
-rw-r--r-- | Zotlabs/Module/Webpages.php | 320 | ||||
-rw-r--r-- | include/attach.php | 46 | ||||
-rw-r--r-- | include/import.php | 204 | ||||
-rw-r--r-- | include/text.php | 16 | ||||
-rw-r--r-- | include/widgets.php | 4 | ||||
-rw-r--r-- | view/css/mod_webpages.css | 74 | ||||
-rw-r--r-- | view/pdl/mod_webpages.pdl | 2 | ||||
-rw-r--r-- | view/tpl/webpage_export_list.tpl | 124 | ||||
-rw-r--r-- | view/tpl/website_import_tools.tpl | 37 | ||||
-rw-r--r-- | view/tpl/website_portation_tools.tpl | 72 |
11 files changed, 903 insertions, 53 deletions
diff --git a/Zotlabs/Lib/ExtendedZip.php b/Zotlabs/Lib/ExtendedZip.php new file mode 100644 index 000000000..a40110c55 --- /dev/null +++ b/Zotlabs/Lib/ExtendedZip.php @@ -0,0 +1,57 @@ +<?php + +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +namespace Zotlabs\Lib; + +/** + * Description of ExtendedZip + * + * @author andrew + */ +class ExtendedZip extends \ZipArchive { + + // Member function to add a whole file system subtree to the archive + public function addTree($dirname, $localname = '') { + if ($localname) + $this->addEmptyDir($localname); + $this->_addTree($dirname, $localname); + } + + // Internal function, to recurse + protected function _addTree($dirname, $localname) { + $dir = opendir($dirname); + while ($filename = readdir($dir)) { + // Discard . and .. + if ($filename == '.' || $filename == '..') + continue; + + // Proceed according to type + $path = $dirname . '/' . $filename; + $localpath = $localname ? ($localname . '/' . $filename) : $filename; + if (is_dir($path)) { + // Directory: add & recurse + $this->addEmptyDir($localpath); + $this->_addTree($path, $localpath); + } + else if (is_file($path)) { + // File: just add + $this->addFile($path, $localpath); + } + } + closedir($dir); + } + + // Helper function + public static function zipTree($dirname, $zipFilename, $flags = 0, $localname = '') { + $zip = new self(); + $zip->open($zipFilename, $flags); + $zip->addTree($dirname, $localname); + $zip->close(); + } + +} diff --git a/Zotlabs/Module/Webpages.php b/Zotlabs/Module/Webpages.php index 0a48d43c6..028cc5114 100644 --- a/Zotlabs/Module/Webpages.php +++ b/Zotlabs/Module/Webpages.php @@ -41,7 +41,6 @@ class Webpages extends \Zotlabs\Web\Controller { $uid = local_channel(); $owner = 0; - $channel = null; $observer = \App::get_observer(); $channel = \App::get_channel(); @@ -62,6 +61,28 @@ class Webpages extends \Zotlabs\Web\Controller { case 'importselected': $_SESSION['action'] = null; break; + case 'export_select_list': + $_SESSION['action'] = null; + if(!$uid) { + $_SESSION['export'] = null; + break; + } + require_once('include/import.php'); + + $pages = get_webpage_elements($channel, 'pages'); + $layouts = get_webpage_elements($channel, 'layouts'); + $blocks = get_webpage_elements($channel, 'blocks'); + $o .= replace_macros(get_markup_template('webpage_export_list.tpl'), array( + '$title' => t('Export Webpage Elements'), + '$exportbtn' => t('Export selected'), + '$action' => $_SESSION['export'], // value should be 'zipfile' or 'cloud' + '$pages' => $pages['pages'], + '$layouts' => $layouts['layouts'], + '$blocks' => $blocks['blocks'], + )); + $_SESSION['export'] = null; + return $o; + default : $_SESSION['action'] = null; break; @@ -233,7 +254,6 @@ class Webpages extends \Zotlabs\Web\Controller { } function post() { - $action = $_REQUEST['action']; if( $action ){ switch ($action) { @@ -296,6 +316,7 @@ class Webpages extends \Zotlabs\Web\Controller { $path = $website; } $elements['pages'] = scan_webpage_elements($path, 'page', $cloud); + logger('$elements pages: ' . json_encode($elements['pages'])); $elements['layouts'] = scan_webpage_elements($path, 'layout', $cloud); $elements['blocks'] = scan_webpage_elements($path, 'block', $cloud); $_SESSION['blocks'] = $elements['blocks']; @@ -313,7 +334,8 @@ class Webpages extends \Zotlabs\Web\Controller { // If the website elements were imported from a zip file, delete the temporary decompressed files if ($cloud === false && $website && $elements) { - rrmdir($website); // Delete the temporary decompressed files + $_SESSION['tempimportpath'] = $website; + //rrmdir($website); // Delete the temporary decompressed files } break; @@ -381,16 +403,300 @@ class Webpages extends \Zotlabs\Web\Controller { if(!(empty($_SESSION['import_pages']) && empty($_SESSION['import_blocks']) && empty($_SESSION['import_layouts']))) { info( t('Import complete.') . EOL); } + if(isset($_SESSION['tempimportpath'])) { + rrmdir($_SESSION['tempimportpath']); // Delete the temporary decompressed files + unset($_SESSION['tempimportpath']); + } + break; + + case 'exportzipfile': + + if(isset($_POST['w_download'])) { + $_SESSION['action'] = 'export_select_list'; + $_SESSION['export'] = 'zipfile'; + if(isset($_POST['zipfilename']) && $_POST['zipfilename'] !== '') { + $filename = filter_var($_POST['zipfilename'], FILTER_SANITIZE_ENCODED); + } else { + $filename = 'website.zip'; + } + $_SESSION['zipfilename'] = $filename; + + } + + break; + + case 'exportcloud': + logger('exportcloud', LOGGER_DEBUG); + if(isset($_POST['exportcloudpath']) && $_POST['exportcloudpath'] !== '') { + $_SESSION['action'] = 'export_select_list'; + $_SESSION['export'] = 'cloud'; + $_SESSION['exportcloudpath'] = filter_var($_POST['exportcloudpath'], FILTER_SANITIZE_ENCODED); + } + + break; + + case 'cloud': + case 'zipfile': + + $channel = \App::get_channel(); + + $tmp_folder_name = random_string(10); + $zip_folder_name = random_string(10); + $zip_filename = $_SESSION['zipfilename']; + $tmp_folderpath = '/tmp/' . $tmp_folder_name; + $zip_folderpath = '/tmp/' . $zip_folder_name; + if (!mkdir($zip_folderpath, 0770, false)) { + logger('Error creating zip file export folder: ' . $zip_folderpath, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating zip file export folder')); + } + $zip_filepath = '/tmp/' . $zip_folder_name . '/' . $zip_filename; + + $checkedblocks = $_POST['block']; + $blocks = []; + if (!empty($checkedblocks)) { + foreach ($checkedblocks as $mid) { + $b = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig + left join item on item.id = iconfig.iid + where mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' order by iconfig.v asc limit 1", + dbesc($mid), + intval($channel['channel_id']) + ); + if($b) { + $b = $b[0]; + $blockinfo = array( + 'body' => $b['body'], + 'mimetype' => $b['mimetype'], + 'title' => $b['title'], + 'name' => $b['v'], + 'json' => array( + 'title' => $b['title'], + 'name' => $b['v'], + 'mimetype' => $b['mimetype'], + ) + ); + switch ($blockinfo['mimetype']) { + case 'text/html': + $block_ext = 'html'; + break; + case 'text/bbcode': + $block_ext = 'bbcode'; + break; + case 'text/markdown': + $block_ext = 'md'; + break; + case 'application/x-pdl': + $block_ext = 'pdl'; + break; + case 'application/x-php': + $block_ext = 'php'; + break; + default: + $block_ext = 'bbcode'; + break; + } + $block_filename = $blockinfo['name'] . '.' . $block_ext; + $tmp_blockfolder = $tmp_folderpath . '/blocks/' . $blockinfo['name']; + $block_filepath = $tmp_blockfolder . '/' . $block_filename; + $blockinfo['json']['contentfile'] = $block_filename; + $block_jsonpath = $tmp_blockfolder . '/block.json'; + if (!is_dir($tmp_blockfolder) && !mkdir($tmp_blockfolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_blockfolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($block_filepath, $blockinfo['body']); + file_put_contents($block_jsonpath, json_encode($blockinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + } + + $checkedlayouts = $_POST['layout']; + $layouts = []; + if (!empty($checkedlayouts)) { + foreach ($checkedlayouts as $mid) { + $l = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig + left join item on item.id = iconfig.iid + where mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' order by iconfig.v asc limit 1", + dbesc($mid), + intval($channel['channel_id']) + ); + if($l) { + $l = $l[0]; + $layoutinfo = array( + 'body' => $l['body'], + 'mimetype' => $l['mimetype'], + 'description' => $l['title'], + 'name' => $l['v'], + 'json' => array( + 'description' => $l['title'], + 'name' => $l['v'], + 'mimetype' => $l['mimetype'], + ) + ); + switch ($layoutinfo['mimetype']) { + case 'text/bbcode': + default: + $layout_ext = 'bbcode'; + break; + } + $layout_filename = $layoutinfo['name'] . '.' . $layout_ext; + $tmp_layoutfolder = $tmp_folderpath . '/layouts/' . $layoutinfo['name']; + $layout_filepath = $tmp_layoutfolder . '/' . $layout_filename; + $layoutinfo['json']['contentfile'] = $layout_filename; + $layout_jsonpath = $tmp_layoutfolder . '/layout.json'; + if (!is_dir($tmp_layoutfolder) && !mkdir($tmp_layoutfolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_layoutfolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($layout_filepath, $layoutinfo['body']); + file_put_contents($layout_jsonpath, json_encode($layoutinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + } + + $checkedpages = $_POST['page']; + $pages = []; + if (!empty($checkedpages)) { + foreach ($checkedpages as $mid) { + + $p = q("select * from iconfig left join item on iconfig.iid = item.id + where item.uid = %d and item.mid = '%s' and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d", + intval($channel['channel_id']), + dbesc($mid), + intval(ITEM_TYPE_WEBPAGE) + ); + + if($p) { + foreach ($p as $pp) { + // Get the associated layout + $layoutinfo = array(); + if($pp['layout_mid']) { + $l = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig + left join item on item.id = iconfig.iid + where mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' order by iconfig.v asc limit 1", + dbesc($pp['layout_mid']), + intval($channel['channel_id']) + ); + if($l) { + $l = $l[0]; + $layoutinfo = array( + 'body' => $l['body'], + 'mimetype' => $l['mimetype'], + 'description' => $l['title'], + 'name' => $l['v'], + 'json' => array( + 'description' => $l['title'], + 'name' => $l['v'], + ) + ); + switch ($layoutinfo['mimetype']) { + case 'text/bbcode': + default: + $layout_ext = 'bbcode'; + break; + } + $layout_filename = $layoutinfo['name'] . '.' . $layout_ext; + $tmp_layoutfolder = $tmp_folderpath . '/layouts/' . $layoutinfo['name']; + $layout_filepath = $tmp_layoutfolder . '/' . $layout_filename; + $layoutinfo['json']['contentfile'] = $layout_filename; + $layout_jsonpath = $tmp_layoutfolder . '/layout.json'; + if (!is_dir($tmp_layoutfolder) && !mkdir($tmp_layoutfolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_layoutfolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($layout_filepath, $layoutinfo['body']); + file_put_contents($layout_jsonpath, json_encode($layoutinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + switch ($pp['mimetype']) { + case 'text/html': + $page_ext = 'html'; + break; + case 'text/bbcode': + $page_ext = 'bbcode'; + break; + case 'text/markdown': + $page_ext = 'md'; + break; + case 'application/x-pdl': + $page_ext = 'pdl'; + break; + case 'application/x-php': + $page_ext = 'php'; + break; + default: + break; + } + $pageinfo = array( + 'title' => $pp['title'], + 'body' => $pp['body'], + 'pagelink' => $pp['v'], + 'mimetype' => $pp['mimetype'], + 'contentfile' => $pp['v'] . '.' . $page_ext, + 'layout' => ((x($layoutinfo,'name')) ? $layoutinfo['name'] : ''), + 'json' => array( + 'title' => $pp['title'], + 'pagelink' => $pp['v'], + 'mimetype' => $pp['mimetype'], + 'layout' => ((x($layoutinfo,'name')) ? $layoutinfo['name'] : ''), + ) + ); + $page_filename = $pageinfo['pagelink'] . '.' . $page_ext; + $tmp_pagefolder = $tmp_folderpath . '/pages/' . $pageinfo['pagelink']; + $page_filepath = $tmp_pagefolder . '/' . $page_filename; + $page_jsonpath = $tmp_pagefolder . '/page.json'; + $pageinfo['json']['contentfile'] = $page_filename; + if (!is_dir($tmp_pagefolder) && !mkdir($tmp_pagefolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_pagefolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($page_filepath, $pageinfo['body']); + file_put_contents($page_jsonpath, json_encode($pageinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + } + } + if($action === 'zipfile') { + // Generate the zip file + \Zotlabs\Lib\ExtendedZip::zipTree($tmp_folderpath, $zip_filepath, \ZipArchive::CREATE); + // Output the file for download + header('Content-disposition: attachment; filename="' . $zip_filename . '"'); + header("Content-Type: application/zip"); + $success = readfile($zip_filepath); + } elseif ($action === 'cloud') { // Only zipfile or cloud should be possible values for $action here + if(isset($_SESSION['exportcloudpath'])) { + require_once('include/attach.php'); + $cloudpath = urldecode($_SESSION['exportcloudpath']); + $channel = \App::get_channel(); + $dirpath = get_dirpath_by_cloudpath($channel, $cloudpath); + if(!$dirpath) { + $x = attach_mkdirp($channel, $channel['channel_hash'], array('pathname' => $cloudpath)); + $folder_hash = (($x['success']) ? $x['data']['hash'] : ''); + + if (!$x['success']) { + logger('Failed to create cloud file folder', LOGGER_NORMAL); + } + $dirpath = get_dirpath_by_cloudpath($channel, $cloudpath); + if (!is_dir($dirpath)) { + logger('Failed to create cloud file folder', LOGGER_NORMAL); + } + } + + $success = copy_folder_to_cloudfiles($channel, $channel['channel_hash'], $tmp_folderpath, $cloudpath); + } + } + if(!$success) { + logger('Error exporting webpage elements', LOGGER_NORMAL); + } + + rrmdir($zip_folderpath); rrmdir($tmp_folderpath); // delete temporary files + break; - default : break; } + } - - - } } diff --git a/include/attach.php b/include/attach.php index ae7d71dc7..137d2b11c 100644 --- a/include/attach.php +++ b/include/attach.php @@ -1995,6 +1995,52 @@ function get_filename_by_cloudname($cloudname, $channel, $storepath) { return null; } + +// recursively copy a directory into cloud files +function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpath) +{ + if (!is_dir($srcpath) || !is_readable($srcpath)) { + logger('Error reading source path: ' . $srcpath, LOGGER_NORMAL); + return false; + } + $nodes = array_diff(scandir($srcpath), array('.', '..')); + foreach ($nodes as $node) { + $clouddir = $cloudpath . '/' . $node; // Sub-folder in cloud files destination + $nodepath = $srcpath . '/' . $node; // Sub-folder in source path + if(is_dir($nodepath)) { + $x = attach_mkdirp($channel, $observer_hash, array('pathname' => $clouddir)); + if(!$x['success']) { + logger('Error creating cloud path: ' . $clouddir, LOGGER_NORMAL); + return false; + } + // Recursively call this function where the source and destination are the subfolders + $success = copy_folder_to_cloudfiles($channel, $observer_hash, $nodepath, $clouddir); + if(!$success) { + logger('Error copying contents of folder: ' . $nodepath, LOGGER_NORMAL); + return false; + } + } elseif (is_file($nodepath) && is_readable($nodepath)) { + $x = attach_store($channel, $observer_hash, 'import', + array( + 'directory' => $cloudpath, + 'src' => $nodepath, + 'filename' => $node, + 'filesize' => @filesize($nodepath), + 'preserve_original' => true) + ); + if(!$x['success']) { + logger('Error copying file: ' . $nodepath , LOGGER_NORMAL); + logger('Return value: ' . json_encode($x), LOGGER_NORMAL); + return false; + } + } else { + logger('Error scanning source path', LOGGER_NORMAL); + return false; + } + } + + return true; +} /** * attach_move() * This function performs an in place directory-to-directory move of a stored attachment or photo. diff --git a/include/import.php b/include/import.php index 84881a420..10664aa53 100644 --- a/include/import.php +++ b/include/import.php @@ -1311,9 +1311,15 @@ function scan_webpage_elements($path, $type, $cloud = false) { return false; } $content = file_get_contents($folder . '/' . $contentfilename); + logger('contentfile: ' . $folder . '/' . $contentfilename, LOGGER_DEBUG); + logger('content: ' . $content, LOGGER_DEBUG); if (!$content) { - logger('Failed to get file content for ' . $metadata['contentfile']); - return false; + if(is_readable($folder . '/' . $contentfilename)) { + $content = ''; + } else { + logger('Failed to get file content for ' . $metadata['contentfile']); + return false; + } } $elements[] = $metadata; } @@ -1403,6 +1409,10 @@ function scan_webpage_elements($path, $type, $cloud = false) { } // Import the actual element content $arr['body'] = file_get_contents($element['path']); + if($arr['item_type'] === ITEM_TYPE_PDL) { + logger(' body: ' . $arr['body'], LOGGER_DEBUG); + logger(' path: ' . $element['path'], LOGGER_DEBUG); + } // The element owner is the channel importing the elements $arr['owner_xchan'] = get_observer_hash(); // The author is either the owner or whomever was specified @@ -1472,3 +1482,193 @@ function scan_webpage_elements($path, $type, $cloud = false) { return $element; } + +function get_webpage_elements($channel, $type = 'all') { + $elements = array(); + if(!$channel['channel_id']) { + return null; + } + switch ($type) { + case 'all': + // If all, execute all the pages, layouts, blocks case statements + case 'pages': + $elements['pages'] = null; + $owner = $channel['channel_id']; + + $sql_extra = item_permissions_sql($owner); + + + $r = q("select * from iconfig left join item on iconfig.iid = item.id + where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d + $sql_extra order by item.created desc", + intval($owner), + intval(ITEM_TYPE_WEBPAGE) + ); + + $pages = null; + + if($r) { + $elements['pages'] = array(); + $pages = array(); + foreach($r as $rr) { + unobscure($rr); + + //$lockstate = (($rr['allow_cid'] || $rr['allow_gid'] || $rr['deny_cid'] || $rr['deny_gid']) ? 'lock' : 'unlock'); + + $element_arr = array( + 'type' => 'webpage', + 'title' => $rr['title'], + 'body' => $rr['body'], + 'created' => $rr['created'], + 'edited' => $rr['edited'], + 'mimetype' => $rr['mimetype'], + 'pagetitle' => $rr['v'], + 'mid' => $rr['mid'], + 'layout_mid' => $rr['layout_mid'] + ); + $pages[$rr['iid']][] = array( + 'url' => $rr['iid'], + 'pagetitle' => $rr['v'], + 'title' => $rr['title'], + 'created' => datetime_convert('UTC',date_default_timezone_get(),$rr['created']), + 'edited' => datetime_convert('UTC',date_default_timezone_get(),$rr['edited']), + 'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]', + //'lockstate' => $lockstate + ); + $elements['pages'][] = $element_arr; + } + + } + if($type !== 'all') { + break; + } + + case 'layouts': + $elements['layouts'] = null; + $owner = $channel['channel_id']; + + $sql_extra = item_permissions_sql($owner); + + + $r = q("select * from iconfig left join item on iconfig.iid = item.id + where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' and item_type = %d + $sql_extra order by item.created desc", + intval($owner), + intval(ITEM_TYPE_PDL) + ); + + $layouts = null; + + if($r) { + $elements['layouts'] = array(); + $layouts = array(); + foreach($r as $rr) { + unobscure($rr); + + $elements['layouts'][] = array( + 'type' => 'layout', + 'description' => $rr['title'], // description of the layout + 'body' => $rr['body'], + 'created' => $rr['created'], + 'edited' => $rr['edited'], + 'mimetype' => $rr['mimetype'], + 'name' => $rr['v'], // name of reference for the layout + 'mid' => $rr['mid'], + ); + } + + } + + if($type !== 'all') { + break; + } + + case 'blocks': + $elements['blocks'] = null; + $owner = $channel['channel_id']; + + $sql_extra = item_permissions_sql($owner); + + + $r = q("select iconfig.iid, iconfig.k, iconfig.v, mid, title, body, mimetype, created, edited from iconfig + left join item on iconfig.iid = item.id + where uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' + and item_type = %d order by item.created desc", + intval($owner), + intval(ITEM_TYPE_BLOCK) + ); + + $blocks = null; + + if($r) { + $elements['blocks'] = array(); + $blocks = array(); + foreach($r as $rr) { + unobscure($rr); + + $elements['blocks'][] = array( + 'type' => 'block', + 'title' => $rr['title'], + 'body' => $rr['body'], + 'created' => $rr['created'], + 'edited' => $rr['edited'], + 'mimetype' => $rr['mimetype'], + 'name' => $rr['v'], + 'mid' => $rr['mid'] + ); + } + + } + + if($type !== 'all') { + break; + } + + default: + break; + } + return $elements; +} + +/* creates a compressed zip file */ + +function create_zip_file($files = array(), $destination = '', $overwrite = false) { + //if the zip file already exists and overwrite is false, return false + if (file_exists($destination) && !$overwrite) { + return false; + } + //vars + $valid_files = array(); + //if files were passed in... + if (is_array($files)) { + //cycle through each file + foreach ($files as $file) { + //make sure the file exists + if (file_exists($file)) { + $valid_files[] = $file; + } + } + } + + //if we have good files... + if (count($valid_files)) { + //create the archive + $zip = new ZipArchive(); + if ($zip->open($destination, $overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) { + return false; + } + //add the files + foreach ($valid_files as $file) { + $zip->addFile($file, $file); + } + //debug + //echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status; + //close the zip -- done! + $zip->close(); + + //check to make sure the file exists + return file_exists($destination); + } else { + return false; + } +} diff --git a/include/text.php b/include/text.php index a2a6d918b..99ac59ca7 100644 --- a/include/text.php +++ b/include/text.php @@ -2267,11 +2267,11 @@ function design_tools() { } /** - * @brief Creates website import tools menu + * @brief Creates website portation tools menu * * @return string */ -function website_import_tools() { +function website_portation_tools() { $channel = App::get_channel(); $sys = false; @@ -2282,7 +2282,7 @@ function website_import_tools() { $sys = true; } - return replace_macros(get_markup_template('website_import_tools.tpl'), array( + return replace_macros(get_markup_template('website_portation_tools.tpl'), array( '$title' => t('Import'), '$import_label' => t('Import website...'), '$import_placeholder' => t('Select folder to import'), @@ -2290,7 +2290,15 @@ function website_import_tools() { '$file_import_text' => t('Import from cloud files:'), '$desc' => t('/cloud/channel/path/to/folder'), '$hint' => t('Enter path to website files'), - '$select' => t('Select folder'), + '$select' => t('Select folder'), + '$export_label' => t('Export website...'), + '$file_download_text' => t('Export to a zip file'), + '$filename_desc' => t('website.zip'), + '$filename_hint' => t('Enter a name for the zip file.'), + '$cloud_export_text' => t('Export to cloud files'), + '$cloud_export_desc' => t('/path/to/export/folder'), + '$cloud_export_hint' => t('Enter a path to a cloud files destination.'), + '$cloud_export_select' => t('Specify folder'), )); } diff --git a/include/widgets.php b/include/widgets.php index 765cb4d42..9429df249 100644 --- a/include/widgets.php +++ b/include/widgets.php @@ -779,7 +779,7 @@ function widget_design_tools($arr) { return design_tools(); } -function widget_website_import_tools($arr) { +function widget_website_portation_tools($arr) { // mod menu doesn't load a profile. For any modules which load a profile, check it. // otherwise local_channel() is sufficient for permissions. @@ -791,7 +791,7 @@ function widget_website_import_tools($arr) { if(! local_channel()) return ''; - return website_import_tools(); + return website_portation_tools(); } function widget_findpeople($arr) { diff --git a/view/css/mod_webpages.css b/view/css/mod_webpages.css index f72f632dd..805d95dc2 100644 --- a/view/css/mod_webpages.css +++ b/view/css/mod_webpages.css @@ -119,3 +119,77 @@ opacity: 1; } + +/* SQUARED THREE */ +.squaredThree { + width: 14px; + height: 14px; + background: #fcfff4; + + background: -webkit-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: -moz-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: -o-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: -ms-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fcfff4', endColorstr='#b3bead',GradientType=0 ); + margin: 5px auto; + + -webkit-box-shadow: inset 0px 1px 1px white, 0px 1px 3px rgba(0,0,0,0.5); + -moz-box-shadow: inset 0px 1px 1px white, 0px 1px 3px rgba(0,0,0,0.5); + box-shadow: inset 0px 1px 1px white, 0px 1px 3px rgba(0,0,0,0.5); + position: relative; +} + +.squaredThree label { + cursor: pointer; + position: absolute; + width: 10px; + height: 10px; + left: 2px; + top: 2px; + + -webkit-box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,1); + -moz-box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,1); + box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,1); + + background: -webkit-linear-gradient(top, #222 0%, #45484d 100%); + background: -moz-linear-gradient(top, #222 0%, #45484d 100%); + background: -o-linear-gradient(top, #222 0%, #45484d 100%); + background: -ms-linear-gradient(top, #222 0%, #45484d 100%); + background: linear-gradient(top, #222 0%, #45484d 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#222', endColorstr='#45484d',GradientType=0 ); +} + +.squaredThree label:after { + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + opacity: 0; + content: ''; + position: absolute; + width: 9px; + height: 5px; + background: transparent; + top: 2px; + left: 2px; + border: 3px solid #fcfff4; + border-top: none; + border-right: none; + + -webkit-transform: rotate(-45deg); + -moz-transform: rotate(-45deg); + -o-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +.squaredThree label:hover::after { + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)"; + filter: alpha(opacity=30); + opacity: 0.3; +} + +.squaredThree input[type=checkbox]:checked + label:after { + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; + filter: alpha(opacity=100); + opacity: 1; +}
\ No newline at end of file diff --git a/view/pdl/mod_webpages.pdl b/view/pdl/mod_webpages.pdl index b62ec6e7c..9e4d604ba 100644 --- a/view/pdl/mod_webpages.pdl +++ b/view/pdl/mod_webpages.pdl @@ -1,4 +1,4 @@ [region=aside] [widget=design_tools][/widget] -[widget=website_import_tools][/widget] +[widget=website_portation_tools][/widget] [/region]
\ No newline at end of file diff --git a/view/tpl/webpage_export_list.tpl b/view/tpl/webpage_export_list.tpl new file mode 100644 index 000000000..1d28f62df --- /dev/null +++ b/view/tpl/webpage_export_list.tpl @@ -0,0 +1,124 @@ +<div class="generic-content-wrapper"> + <form action="" method="post" autocomplete="on" > + <input type="hidden" name="action" value="{{$action}}"> + <div class="section-title-wrapper"> + <div class="pull-right"> + <button class="btn btn-md btn-success" type="submit" name="submit" value="{{$exportbtn}}">{{$exportbtn}}</button> + </div> + <h2>{{$title}}</h2> + <div class="clear"></div> + </div> + <div id="import-website-content-wrapper" class="section-content-wrapper"> + <div class="pull-left"> + <button id="toggle-select-all" class="btn btn-xs btn-primary" onclick="checkedAll(window.isChecked); return false;"><i class="fa fa-check"></i> Toggle Select All</button> + </div> + <div class="clear"></div> + <hr> + <!--<h4>Pages</h4>--> + <div> + <table class="table-striped table-responsive table-hover" style="width: 100%;"> + <thead> + <tr><th></th><th>Page Link</th><th>Page Title</th><th>Type</th></tr> + </thead> + {{foreach $pages as $page}} + <tr> + <td width="30px" style="padding-right: 20px;"> + <div class='squaredThree'> + <input type="checkbox" id="page_{{$page.mid}}" name="page[]" value="{{$page.mid}}"> + <label for="page_{{$page.mid}}"></label> + </div> + </td> + <td width="30%"> + <div class="desc"> + {{$page.pagetitle}}<br> + </div> + </td> + <td width="55%"> + <div class='desc'> + {{$page.title}}<br> + </div> + </td> + <td width="15%"> + <div class='desc'> + {{$page.mimetype}}<br> + </div> + </td> + </tr> + {{/foreach}} + </table> + </div> + <hr> + <div class="clear"></div> + <!--<h4>Layouts</h4>--> + <div> + <table class="table-striped table-responsive table-hover" style="width: 100%;"> + <thead> + <tr><th width="20px"></th><th>Layout Name</th><th>Layout Description</th><th>Type</th></tr> + </thead> + {{foreach $layouts as $layout}} + <tr> + <td width="30px" style="padding-right: 20px;"> + <div class='squaredThree'> + <input type="checkbox" id="layout_{{$layout.mid}}" name="layout[]" value="{{$layout.mid}}"> + <label for="layout_{{$layout.mid}}"></label> + </div> + </td> + <td width="30%"> + <div class="desc"> + {{$layout.name}}<br> + </div> + </td> + <td width="55%"> + <div class='desc'> + {{$layout.description}}<br> + </div> + </td> + <td width="15%"> + <div class='desc'> + {{$layout.mimetype}}<br> + </div> + </td> + </tr> + {{/foreach}} + </table> + </div> + <hr> + <div class="clear"></div> + <!--<h4>Blocks</h4>--> + <div> + <table class="table-striped table-responsive table-hover" style="width: 100%;"> + <thead> + <tr><th width="30px"></th><th>Block Name</th><th>Block Title</th><th>Type</th></tr> + </thead> + {{foreach $blocks as $block}} + <tr> + <td width="30px" style="padding-right: 20px;"> + <div class='squaredThree'> + <input type="checkbox" id="block_{{$block.mid}}" name="block[]" value="{{$block.mid}}"> + <label for="block_{{$block.mid}}"></label> + </div> + </td> + <td width="30%"> + <div class="desc"> + {{$block.name}}<br> + </div> + </td> + <td width="55%"> + <div class='desc'> + {{$block.title}}<br> + </div> + </td> + <td width=15%"> + <div class='desc'> + {{$block.mimetype}}<br> + </div> + </td> + </tr> + {{/foreach}} + </table> + </div> + + </div> + </form> +</div> + diff --git a/view/tpl/website_import_tools.tpl b/view/tpl/website_import_tools.tpl deleted file mode 100644 index cb3e6b524..000000000 --- a/view/tpl/website_import_tools.tpl +++ /dev/null @@ -1,37 +0,0 @@ -<div id="website-import-tools" class="widget"> - <h3>{{$title}}</h3> - <ul class="nav nav-pills nav-stacked"> - <li> - <a href="#" onclick="openClose('import-form'); - return false;"><i class="fa fa-cloud-upload generic-icons"></i> {{$import_label}}</a> - </li> - <li> - <form id="import-form" enctype="multipart/form-data" method="post" action="" style="display: none;" class="sub-menu"> - - <input type="hidden" name="action" value="scan"> - - <p style="margin-top: 20px;" class="descriptive-text">{{$file_import_text}}</p> - <div class="form-group"> - <div class="input-group"> - <input class="widget-input" type="text" name="path" title="{{$hint}}" placeholder="{{$desc}}" /> - <div class="input-group-btn"> - <button class="btn btn-default btn-sm" type="submit" name="cloudsubmit" value="{{$select}}"><i class="fa fa-folder-open generic-icons"></i></button> - </div> - </div> - </div> - - <!-- Or upload a zipped file containing the website --> - <p class="descriptive-text">{{$file_upload_text}}</p> - <div class="form-group"> - - <div class="input-group"> - <input class="widget-input" type="file" name="zip_file" /> - <div class="input-group-btn"> - <button class="btn btn-default btn-sm" type="submit" name="w_upload" value="w_upload"><i class="fa fa-file-archive-o generic-icons"></i></button> - </div> - </div> - </div> - </form> - </li> - </ul> -</div> diff --git a/view/tpl/website_portation_tools.tpl b/view/tpl/website_portation_tools.tpl new file mode 100644 index 000000000..10468b64e --- /dev/null +++ b/view/tpl/website_portation_tools.tpl @@ -0,0 +1,72 @@ +<div id="website-portation-tools" class="widget"> + <ul class="nav nav-pills nav-stacked"> + <li> + <a href="#" onclick="openClose('import-form'); + return false;"><i class="fa fa-cloud-upload generic-icons"></i> {{$import_label}}</a> + </li> + <li style="margin-left: 12px;" > + <form id="import-form" enctype="multipart/form-data" method="post" action="" style="display: none;" class="sub-menu"> + + <input type="hidden" name="action" value="scan"> + + <p style="margin-top: 10px;" class="descriptive-text">{{$file_import_text}}</p> + <div class="form-group"> + <div class="input-group"> + <input class="widget-input" type="text" name="path" title="{{$hint}}" placeholder="{{$desc}}" /> + <div class="input-group-btn"> + <button class="btn btn-default btn-sm" type="submit" name="cloudsubmit" value="{{$select}}"><i class="fa fa-folder-open generic-icons"></i></button> + </div> + </div> + </div> + + <!-- Or upload a zipped file containing the website --> + <p class="descriptive-text">{{$file_upload_text}}</p> + <div class="form-group"> + + <div class="input-group"> + <input class="widget-input" type="file" name="zip_file" /> + <div class="input-group-btn"> + <button class="btn btn-default btn-sm" type="submit" name="w_upload" value="w_upload"><i class="fa fa-file-archive-o generic-icons"></i></button> + </div> + </div> + </div> + </form> + </li> + </ul> + <ul class="nav nav-pills nav-stacked"> + <li> + <a href="#" onclick="openClose('export-form'); openClose('export-cloud-form'); + return false;"><i class="fa fa-share-square-o generic-icons"></i> {{$export_label}}</a> + </li> + <li style="margin-left: 12px;" > + <form id="export-form" enctype="multipart/form-data" method="post" action="" style="display: none;" class="sub-menu"> + <input type="hidden" name="action" value="exportzipfile"> + <!-- Or download a zipped file containing the website --> + <p style="margin-top: 10px;" class="descriptive-text">{{$file_download_text}}</p> + <div class="form-group"> + + <div class="input-group"> + <input class="widget-input" type="text" name="zipfilename" title="{{$filename_hint}}" placeholder="{{$filename_desc}}" value="" /> + <div class="input-group-btn"> + <button class="btn btn-default btn-sm" type="submit" name="w_download" value="w_download"><i class="fa fa-download generic-icons"></i></button> + </div> + </div> + </div> + </form> + <form id="export-cloud-form" enctype="multipart/form-data" method="post" action="" style="display: none;" class="sub-menu"> + <input type="hidden" name="action" value="exportcloud"> + <!-- Or export the website elements to a cloud files folder --> + <p style="margin-top: 10px;" class="descriptive-text">{{$cloud_export_text}}</p> + <div class="form-group"> + + <div class="input-group"> + <input class="widget-input" type="text" name="exportcloudpath" title="{{$cloud_export_hint}}" placeholder="{{$cloud_export_desc}}" /> + <div class="input-group-btn"> + <button class="btn btn-default btn-sm" type="submit" name="exportcloudsubmit" value="{{$cloud_export_select}}"><i class="fa fa-folder-open generic-icons"></i></button> + </div> + </div> + </div> + </form> + </li> + </ul> +</div> |