This commit is contained in:
Mario Vavti 2016-08-03 21:17:08 +02:00
commit b959641ca8
37 changed files with 5632 additions and 4440 deletions

View File

@ -64,12 +64,16 @@ class Cron {
// delete expired access tokens
q("delete from atoken where atoken_expires != '%s' && atoken_expires < %s",
$r = q("select atoken_id from atoken where atoken_expires != '%s' && atoken_expires < %s",
dbesc(NULL_DATE),
db_utcnow()
);
if($r) {
require_once('include/security.php');
foreach($r as $rr) {
atoken_delete($rr['atoken_id']);
}
}
// Ensure that every channel pings a directory server once a month. This way we can discover
// channels and sites that quietly vanished and prevent the directory from accumulating stale

View File

@ -88,7 +88,11 @@ class Impel extends \Zotlabs\Web\Controller {
foreach($j['items'] as $it) {
$mitem = array();
$mitem['mitem_link'] = str_replace('[channelurl]',z_root() . '/channel/' . $channel['channel_address'],$it['link']);
$mitem['mitem_link'] = str_replace('[pageurl]',z_root() . '/page/' . $channel['channel_address'],$it['link']);
$mitem['mitem_link'] = str_replace('[cloudurl]',z_root() . '/cloud/' . $channel['channel_address'],$it['link']);
$mitem['mitem_link'] = str_replace('[baseurl]',z_root(),$it['link']);
$mitem['mitem_desc'] = escape_tags($it['desc']);
$mitem['mitem_order'] = intval($it['order']);
if(is_array($it['flags'])) {

View File

@ -495,6 +495,8 @@ class Like extends \Zotlabs\Web\Controller {
$arr['deny_gid'] = $deny_gid;
$arr['item_private'] = $private;
call_hooks('post_local',$arr);
$post = item_store($arr);
$post_id = $post['item_id'];

View File

@ -65,7 +65,7 @@ class Menu extends \Zotlabs\Web\Controller {
function get() {
function get() {
$uid = local_channel();
@ -81,7 +81,7 @@ class Menu extends \Zotlabs\Web\Controller {
if(argc() == 1) {
$channel = (($sys) ? $sys : \App::get_channel());
// list menus
$x = menu_list($uid);
@ -89,7 +89,7 @@ class Menu extends \Zotlabs\Web\Controller {
for($y = 0; $y < count($x); $y ++) {
$m = menu_fetch($x[$y]['menu_name'],$uid,get_observer_hash());
if($m)
$x[$y]['element'] = '[element]' . base64url_encode(json_encode(menu_element($m))) . '[/element]';
$x[$y]['element'] = '[element]' . base64url_encode(json_encode(menu_element($channel,$m))) . '[/element]';
$x[$y]['bookmark'] = (($x[$y]['menu_flags'] & MENU_BOOKMARK) ? true : false);
}
}

View File

@ -173,7 +173,7 @@ class Ping extends \Zotlabs\Web\Controller {
);
break;
case 'all_events':
$r = q("update event set `dimissed` = 1 where `dismissed` = 0 and uid = %d AND dtstart < '%s' AND dtstart > '%s' ",
$r = q("update event set `dismissed` = 1 where `dismissed` = 0 and uid = %d AND dtstart < '%s' AND dtstart > '%s' ",
intval(local_channel()),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))

View File

@ -2,7 +2,7 @@
namespace Zotlabs\Module; /** @file */
require_once('include/zot.php');
require_once('include/security.php');
class Settings extends \Zotlabs\Web\Controller {
@ -145,7 +145,7 @@ class Settings extends \Zotlabs\Web\Controller {
return;
}
if($atoken_id) {
$r = q("update atoken set atoken_name = '%s', atoken_token = '%s' atoken_expires = '%s'
$r = q("update atoken set atoken_name = '%s', atoken_token = '%s', atoken_expires = '%s'
where atoken_id = %d and atoken_uid = %d",
dbesc($name),
dbesc($token),
@ -164,7 +164,23 @@ class Settings extends \Zotlabs\Web\Controller {
dbesc($expires)
);
}
$atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $name;
$all_perms = \Zotlabs\Access\Permissions::Perms();
if($all_perms) {
foreach($all_perms as $perm => $desc) {
if(array_key_exists('perms_' . $perm, $_POST)) {
set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,intval($_POST['perms_' . $perm]));
}
else {
set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,0);
}
}
}
info( t('Token saved.') . EOL);
return;
}
@ -270,7 +286,7 @@ class Settings extends \Zotlabs\Web\Controller {
$email = ((x($_POST,'email')) ? trim(notags($_POST['email'])) : '');
$account = \App::get_account();
if($email != $account['account_email']) {
if(! valid_email($email))
if(! valid_email($email))
$errs[] = t('Not valid email.');
$adm = trim(get_config('system','admin_email'));
if(($adm) && (strcasecmp($email,$adm) == 0)) {
@ -378,7 +394,7 @@ class Settings extends \Zotlabs\Web\Controller {
intval(local_channel())
);
}
else {
else {
$role_permissions = \Zotlabs\Access\PermissionRoles::role_perms($_POST['permissions_role']);
if(! $role_permissions) {
notice('Permissions category could not be found.');
@ -765,6 +781,8 @@ class Settings extends \Zotlabs\Web\Controller {
if((argc() > 1) && (argv(1) === 'tokens')) {
$atoken = null;
$atoken_xchan = '';
if(argc() > 2) {
$id = argv(2);
@ -773,23 +791,56 @@ class Settings extends \Zotlabs\Web\Controller {
intval(local_channel())
);
if($atoken)
if($atoken) {
$atoken = $atoken[0];
$atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $atoken['atoken_name'];
}
if($atoken && argc() > 3 && argv(3) === 'drop') {
$r = q("delete from atoken where atoken_id = %d",
intval($id)
);
atoken_delete($id);
$atoken = null;
$atoken_xchan = '';
}
}
$t = q("select * from atoken where atoken_uid = %d",
intval(local_channel())
);
$desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access the private content.');
$desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access private content.');
$desc2 = t('You may also provide <em>dropbox</em> style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:');
$global_perms = \Zotlabs\Access\Permissions::Perms();
$existing = get_all_perms(local_channel(),(($atoken_xchan) ? $atoken_xchan : ''));
if($atoken_xchan) {
$theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'",
intval(local_channel()),
dbesc($atoken_xchan)
);
$their_perms = array();
if($theirs) {
foreach($theirs as $t) {
$their_perms[$t['k']] = $t['v'];
}
}
}
foreach($global_perms as $k => $v) {
$thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k);
//fixme
$checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k);
if($existing[$k])
$thisperm = "1";
$perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited);
}
$tpl = get_markup_template("settings_tokens.tpl");
$o .= replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("settings_tokens"),
@ -803,6 +854,13 @@ class Settings extends \Zotlabs\Web\Controller {
'$name' => array('name', t('Login Name') . ' <span class="required">*</span>', (($atoken) ? $atoken['atoken_name'] : ''),''),
'$token'=> array('token', t('Login Password') . ' <span class="required">*</span>',(($atoken) ? $atoken['atoken_token'] : autoname(8)), ''),
'$expires'=> array('expires', t('Expires (yyyy-mm-dd)'), (($atoken['atoken_expires'] && $atoken['atoken_expires'] != NULL_DATE) ? datetime_convert('UTC',date_default_timezone_get(),$atoken['atoken_expires']) : ''), ''),
'$them' => t('Their Settings'),
'$me' => t('My Settings'),
'$perms' => $perms,
'$inherited' => t('inherited'),
'$notself' => '1',
'$permlbl' => t('Individual Permissions'),
'$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'),
'$submit' => t('Submit')
));
return $o;

View File

@ -45,7 +45,29 @@ class Webpages extends \Zotlabs\Web\Controller {
$observer = \App::get_observer();
$channel = \App::get_channel();
switch ($_SESSION['action']) {
case 'import':
$_SESSION['action'] = null;
$o .= replace_macros(get_markup_template('webpage_import.tpl'), array(
'$title' => t('Import Webpage Elements'),
'$importbtn' => t('Import selected'),
'$action' => 'import',
'$pages' => $_SESSION['pages'],
'$layouts' => $_SESSION['layouts'],
'$blocks' => $_SESSION['blocks'],
));
return $o;
case 'importselected':
$_SESSION['action'] = null;
break;
default :
$_SESSION['action'] = null;
break;
}
if(\App::$is_sys && is_site_admin()) {
$sys = get_sys_channel();
if($sys && intval($sys['channel_id'])) {
@ -209,4 +231,165 @@ class Webpages extends \Zotlabs\Web\Controller {
return $o;
}
function post() {
$action = $_REQUEST['action'];
if( $action ){
switch ($action) {
case 'scan':
// the state of this variable tracks whether website files have been scanned (null, true, false)
$cloud = null;
// Website files are to be imported from an uploaded zip file
if(($_FILES) && array_key_exists('zip_file',$_FILES) && isset($_POST['w_upload'])) {
$source = $_FILES["zip_file"]["tmp_name"];
$type = $_FILES["zip_file"]["type"];
$okay = false;
$accepted_types = array('application/zip', 'application/x-zip-compressed', 'multipart/x-zip', 'application/x-compressed');
foreach ($accepted_types as $mime_type) {
if ($mime_type == $type) {
$okay = true;
break;
}
}
if(!$okay) {
notice( t('Invalid file type.') . EOL);
return;
}
$zip = new \ZipArchive();
if ($zip->open($source) === true) {
$tmp_folder_name = random_string(5);
$website = dirname($source) . '/' . $tmp_folder_name;
$zip->extractTo($website); // change this to the correct site path
$zip->close();
@unlink($source); // delete the compressed file now that the content has been extracted
$cloud = false;
} else {
notice( t('Error opening zip file') . EOL);
return null;
}
}
// Website files are to be imported from the channel cloud files
if (($_POST) && array_key_exists('path',$_POST) && isset($_POST['cloudsubmit'])) {
$channel = \App::get_channel();
$dirpath = get_dirpath_by_cloudpath($channel, $_POST['path']);
if(!$dirpath) {
notice( t('Invalid folder path.') . EOL);
return null;
}
$cloud = true;
}
// If the website files were uploaded or specified in the cloud files, then $cloud
// should be either true or false
if ($cloud !== null) {
require_once('include/import.php');
$elements = [];
if($cloud) {
$path = $_POST['path'];
} else {
$path = $website;
}
$elements['pages'] = scan_webpage_elements($path, 'page', $cloud);
$elements['layouts'] = scan_webpage_elements($path, 'layout', $cloud);
$elements['blocks'] = scan_webpage_elements($path, 'block', $cloud);
$_SESSION['blocks'] = $elements['blocks'];
$_SESSION['layouts'] = $elements['layouts'];
$_SESSION['pages'] = $elements['pages'];
if(!(empty($elements['pages']) && empty($elements['blocks']) && empty($elements['layouts']))) {
//info( t('Webpages elements detected.') . EOL);
$_SESSION['action'] = 'import';
} else {
notice( t('No webpage elements detected.') . EOL);
$_SESSION['action'] = null;
}
}
// 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
}
break;
case 'importselected':
require_once('include/import.php');
$channel = \App::get_channel();
// Import layout first so that pages that reference new layouts will find
// the mid of layout items in the database
// Obtain the user-selected layouts to import and import them
$checkedlayouts = $_POST['layout'];
$layouts = [];
if (!empty($checkedlayouts)) {
foreach ($checkedlayouts as $name) {
foreach ($_SESSION['layouts'] as &$layout) {
if ($layout['name'] === $name) {
$layout['import'] = 1;
$layoutstoimport[] = $layout;
}
}
}
foreach ($layoutstoimport as $elementtoimport) {
$layouts[] = import_webpage_element($elementtoimport, $channel, 'layout');
}
}
$_SESSION['import_layouts'] = $layouts;
// Obtain the user-selected blocks to import and import them
$checkedblocks = $_POST['block'];
$blocks = [];
if (!empty($checkedblocks)) {
foreach ($checkedblocks as $name) {
foreach ($_SESSION['blocks'] as &$block) {
if ($block['name'] === $name) {
$block['import'] = 1;
$blockstoimport[] = $block;
}
}
}
foreach ($blockstoimport as $elementtoimport) {
$blocks[] = import_webpage_element($elementtoimport, $channel, 'block');
}
}
$_SESSION['import_blocks'] = $blocks;
// Obtain the user-selected pages to import and import them
$checkedpages = $_POST['page'];
$pages = [];
if (!empty($checkedpages)) {
foreach ($checkedpages as $pagelink) {
foreach ($_SESSION['pages'] as &$page) {
if ($page['pagelink'] === $pagelink) {
$page['import'] = 1;
$pagestoimport[] = $page;
}
}
}
foreach ($pagestoimport as $elementtoimport) {
$pages[] = import_webpage_element($elementtoimport, $channel, 'page');
}
}
$_SESSION['import_pages'] = $pages;
if(!(empty($_SESSION['import_pages']) && empty($_SESSION['import_blocks']) && empty($_SESSION['import_layouts']))) {
info( t('Import complete.') . EOL);
}
break;
default :
break;
}
}
}
}

View File

@ -371,6 +371,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
);
if ($r) {
require_once('include/attach.php');
$result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash));
if($result['success']) {

View File

@ -0,0 +1,8 @@
<dl class="dl-horizontal">
<dt>General</dt>
<dd>You can create modular, identity-aware websites composed of shareable elements. </dd>
<dt>Pages</dt>
<dd>This page lists your "pages", which are assigned URLs where people can visit your site. The structure of pages are typically described by an associated <b>layout</b>, and their content is constructed from a collection of <b>blocks</b>.</dd>
<dt><a href='#' onclick='contextualHelpFocus("#website-import-tools", 1); return false;' title="Click to highlight element...">Website import tool</a></dt>
<dd>The website import tool allows you import multiple webpage elements (pages, layouts, blocks) either from an uploaded zip file or from an existing cloud files folder. <a target="_blank" href="help/webpages">Read more...</a></dd>
</dl>

View File

@ -0,0 +1,94 @@
## <a href="#webpage-element-import"></a>Webpage element import
There are two methods of importing webpage elements: uploading a zip file or
referencing a local cloud files folder. Both methods require that the webpage
elements are specified using a specific folder structure. The import tool makes
it possible to import all the elements necessary to construct an entire website
or set of websites. The goal is to accommodate external development of webpages
as well as tools to simplify and automate deployment on a hub.
### Folder structure
Element definitions must be stored in the repo root under folders called
/pages/
/blocks/
/layouts/
Each element of these types must be defined in an individual subfolder using two files: one JSON-formatted file for the metadata and one plain text file for the element content.
### Page elements
Page element metadata is specified in a JSON-formatted file called `page.json` with the following properties:
* title
* pagelink
* mimetype
* layout
* contentfile
**Example**
Files:
/pages/my-page/page.json
/pages/my-page/my-page.bbcode
Content of `page.json`:
{
"title": "My Page",
"pagelink": "mypage",
"mimetype": "text/bbcode",
"layout": "my-layout",
"contentfile": "my-page.bbcode"
}
### Layout elements
Layout element metadata is specified in a JSON-formatted file called `layout.json` with the following properties:
* name
* description
* contentfile
**Example**
Files:
/layouts/my-layout/layout.json
/layouts/my-layout/my-layout.bbcode
Content of `layout.json`:
{
"name": "my-layout",
"description": "Layout for my project page",
"contentfile": "my-layout.bbcode"
}
### Block elements
Block element metadata is specified in a JSON-formatted file called `block.json` with the following properties:
* name
* title
* mimetype
* contentfile
**Example**
Files:
/blocks/my-block/block.json
/blocks/my-block/my-block.html
Content of `block.json`:
{
"name": "my-block",
"title": "",
"mimetype": "text/html",
"contentfile": "my-block.html"
}

View File

@ -9,6 +9,9 @@ The &quot;page link title&quot; box allows a user to specify the &quot;pagelinkt
Beneath the page creation box, a list of existing pages will appear with an &quot;edit&quot; link. Clicking this will take you to an editor, similar to that of the post editor, where you can make changes to your webpages.
See also:
[zrl=[baseurl]/help/webpage-element-import]Webpage element import tool[/zrl]
[b]Using Blocks[/b]

View File

@ -13,4 +13,5 @@ Beneath the page creation box, a list of existing pages will appear with an "edi
If you are the admin of a site, you can specify a channel whose webpages we will use at key points around the site. Presently, the only place this is implemented is the home page. If you specify the channel "admin" and then the channel called "admin" creates a webpage called "home", we will display it's content on your websites home page. We expect this functionality to be extended to other areas in future.
#include doc/webpage-element-import.md;
#include doc/macros/main_footer.bb;

View File

@ -13,7 +13,7 @@ require_once('include/api_auth.php');
/*
*
* Red API. Loosely based on and possibly compatible with a Twitter-Like API but all similarities end there.
* Hubzilla API. Loosely based on and possibly compatible with Twitter-Like (v1.0) API but all similarities end there.
*
*/

View File

@ -1911,3 +1911,70 @@ function get_attach_binname($s) {
}
return $p;
}
function get_dirpath_by_cloudpath($channel, $path) {
// Warning: Do not edit the following line. The first symbol is UTF-8 &#65312;
$path = str_replace('@','@',notags(trim($path)));
$h = @parse_url($path);
if(! $h || !x($h, 'path')) {
return null;
}
if(substr($h['path'],-1,1) === '/') {
$h['path'] = substr($h['path'],0,-1);
}
if(substr($h['path'],0,1) === '/') {
$h['path'] = substr($h['path'],1);
}
$folders = explode('/', $h['path']);
$f = array_shift($folders);
$nick = $channel['channel_address'];
//check to see if the absolute path was provided (/cloud/channelname/path/to/folder)
if($f === 'cloud' ) {
$g = array_shift($folders);
if( $g !== $nick) {
// if nick does not follow "cloud", then the top level folder must be called "cloud"
// and the given path must be relative to "/cloud/channelname/".
$folders = array_unshift(array_unshift($folders, $g), $f);
}
} else {
array_unshift($folders, $f);
}
$clouddir = 'store/' . $nick . '/' ;
$subdir = '/';
$valid = true;
while($folders && $valid && is_dir($clouddir . $subdir) && is_readable($clouddir . $subdir)) {
$valid = false;
$f = array_shift($folders);
$items = array_diff(scandir($clouddir . $subdir), array('.', '..')); // hashed names
foreach($items as $item) {
$filename = find_filename_by_hash($channel['channel_id'], $item);
if($filename === $f) {
$subdir .= $item . '/';
$valid = true;
}
}
}
if(!$valid) {
return null;
} else {
return $clouddir . $subdir;
}
}
function get_filename_by_cloudname($cloudname, $channel, $storepath) {
$items = array_diff(scandir($storepath), array('.', '..')); // hashed names
foreach($items as $item) {
$filename = find_filename_by_hash($channel['channel_id'], $item);
if($filename === $cloudname) {
return $item;
}
}
return null;
}

View File

@ -57,6 +57,7 @@ function account_verify_password($login, $pass) {
);
if($x) {
$ret['xchan'] = atoken_xchan($x[0]);
atoken_create_xchan($ret['xchan']);
return $ret;
}
}

View File

@ -640,19 +640,10 @@ function identity_basic_export($channel_id, $items = false) {
for($y = 0; $y < count($x); $y ++) {
$m = menu_fetch($x[$y]['menu_name'],$channel_id,$ret['channel']['channel_hash']);
if($m)
$ret['menu'][] = menu_element($m);
$ret['menu'][] = menu_element($ret['channel'],$m);
}
}
$x = menu_list($channel_id);
if($x) {
$ret['menu'] = array();
for($y = 0; $y < count($x); $y ++) {
$m = menu_fetch($x[$y]['menu_name'],$channel_id,$ret['channel']['channel_hash']);
if($m)
$ret['menu'][] = menu_element($m);
}
}
$addon = array('channel_id' => $channel_id,'data' => $ret);
call_hooks('identity_basic_export',$addon);

View File

@ -566,6 +566,7 @@ function contact_remove($channel_id, $abook_id) {
drop_item($rr['id'],false);
}
}
q("delete from abook where abook_id = %d and abook_channel = %d",
intval($abook['abook_id']),
@ -588,6 +589,11 @@ function contact_remove($channel_id, $abook_id) {
intval($channel_id)
);
$r = q("delete from abconfig where chan = %d and xchan = '%s'",
intval($channel_id),
dbesc($abook['abook_xchan'])
);
return true;
}

View File

@ -784,7 +784,11 @@ function import_menus($channel,$menus) {
foreach($menu['items'] as $it) {
$mitem = array();
$mitem['mitem_link'] = str_replace('[channelurl]',z_root() . '/channel/' . $channel['channel_address'],$it['link']);
$mitem['mitem_link'] = str_replace('[pageurl]',z_root() . '/page/' . $channel['channel_address'],$it['link']);
$mitem['mitem_link'] = str_replace('[cloudurl]',z_root() . '/cloud/' . $channel['channel_address'],$it['link']);
$mitem['mitem_link'] = str_replace('[baseurl]',z_root(),$it['link']);
$mitem['mitem_desc'] = escape_tags($it['desc']);
$mitem['mitem_order'] = intval($it['order']);
if(is_array($it['flags'])) {
@ -864,7 +868,12 @@ function sync_menus($channel,$menus) {
foreach($menu['items'] as $it) {
$mitem = array();
$mitem['mitem_link'] = str_replace('[channelurl]',z_root() . '/channel/' . $channel['channel_address'],$it['link']);
$mitem['mitem_link'] = str_replace('[pageurl]',z_root() . '/page/' . $channel['channel_address'],$it['link']);
$mitem['mitem_link'] = str_replace('[cloudurl]',z_root() . '/cloud/' . $channel['channel_address'],$it['link']);
$mitem['mitem_link'] = str_replace('[baseurl]',z_root(),$it['link']);
$mitem['mitem_desc'] = escape_tags($it['desc']);
$mitem['mitem_order'] = intval($it['order']);
if(is_array($it['flags'])) {
@ -1246,3 +1255,216 @@ function convert_oldfields(&$arr,$old,$new) {
unset($arr[$old]);
}
}
function scan_webpage_elements($path, $type, $cloud = false) {
$channel = \App::get_channel();
$dirtoscan = $path;
switch ($type) {
case 'page':
$dirtoscan .= '/pages/';
$json_filename = 'page.json';
break;
case 'layout':
$dirtoscan .= '/layouts/';
$json_filename = 'layout.json';
break;
case 'block':
$dirtoscan .= '/blocks/';
$json_filename = 'block.json';
break;
default :
return array();
}
if($cloud) {
$dirtoscan = get_dirpath_by_cloudpath($channel, $dirtoscan);
}
$elements = [];
if (is_dir($dirtoscan)) {
$dirlist = scandir($dirtoscan);
if ($dirlist) {
foreach ($dirlist as $element) {
if ($element === '.' || $element === '..') {
continue;
}
$folder = $dirtoscan . '/' . $element;
if (is_dir($folder)) {
if($cloud) {
$jsonfilepath = $folder . '/' . get_filename_by_cloudname($json_filename, $channel, $folder);
} else {
$jsonfilepath = $folder . '/' . $json_filename;
}
if (is_file($jsonfilepath)) {
$metadata = json_decode(file_get_contents($jsonfilepath), true);
if($cloud) {
$contentfilename = get_filename_by_cloudname($metadata['contentfile'], $channel, $folder);
$metadata['path'] = $folder . '/' . $contentfilename;
} else {
$contentfilename = $metadata['contentfile'];
$metadata['path'] = $folder . '/' . $contentfilename;
}
if ($metadata['contentfile'] === '') {
logger('Invalid ' . $type . ' content file');
return false;
}
$content = file_get_contents($folder . '/' . $contentfilename);
if (!$content) {
logger('Failed to get file content for ' . $metadata['contentfile']);
return false;
}
$elements[] = $metadata;
}
}
}
}
}
return $elements;
}
function import_webpage_element($element, $channel, $type) {
$arr = array(); // construct information for the webpage element item table record
switch ($type) {
//
// PAGES
//
case 'page':
$arr['item_type'] = ITEM_TYPE_WEBPAGE;
$namespace = 'WEBPAGE';
$name = $element['pagelink'];
if($name) {
require_once('library/urlify/URLify.php');
$name = strtolower(\URLify::transliterate($name));
}
$arr['title'] = $element['title'];
$arr['term'] = $element['term'];
$arr['layout_mid'] = ''; // by default there is no layout associated with the page
// If a layout was specified, find it in the database and get its info. If
// it does not exist, leave layout_mid empty
if($element['layout'] !== '') {
$liid = q("select iid from iconfig where k = 'PDL' and v = '%s' and cat = 'system'",
dbesc($element['layout'])
);
if($liid) {
$linfo = q("select mid from item where id = %d",
intval($liid[0]['iid'])
);
$arr['layout_mid'] = $linfo[0]['mid'];
}
}
break;
//
// LAYOUTS
//
case 'layout':
$arr['item_type'] = ITEM_TYPE_PDL;
$namespace = 'PDL';
$name = $element['name'];
$arr['title'] = $element['description'];
$arr['term'] = $element['term'];
break;
//
// BLOCKS
//
case 'block':
$arr['item_type'] = ITEM_TYPE_BLOCK;
$namespace = 'BUILDBLOCK';
$name = $element['name'];
$arr['title'] = $element['title'];
break;
default :
return null; // return null if invalid element type
}
$arr['uid'] = $channel['channel_id'];
$arr['aid'] = $channel['channel_account_id'];
// Check if an item already exists based on the name
$iid = q("select iid from iconfig where k = '" . $namespace . "' and v = '%s' and cat = 'system'",
dbesc($name)
);
if($iid) { // If the item does exist, get the item metadata
$iteminfo = q("select mid,created,edited from item where id = %d",
intval($iid[0]['iid'])
);
$arr['mid'] = $arr['parent_mid'] = $iteminfo[0]['mid'];
$arr['created'] = $iteminfo[0]['created'];
$arr['edited'] = (($element['edited']) ? datetime_convert('UTC', 'UTC', $element['edited']) : datetime_convert());
} else { // otherwise, generate the creation times and unique id
$arr['created'] = (($element['created']) ? datetime_convert('UTC', 'UTC', $element['created']) : datetime_convert());
$arr['edited'] = datetime_convert('UTC', 'UTC', '0000-00-00 00:00:00');
$arr['mid'] = $arr['parent_mid'] = item_message_id();
}
// Import the actual element content
$arr['body'] = file_get_contents($element['path']);
// 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
$arr['author_xchan'] = (($element['author_xchan']) ? $element['author_xchan'] : get_observer_hash());
// Import mimetype if it is a valid mimetype for the element
$mimetypes = [ 'text/bbcode',
'text/html',
'text/markdown',
'text/plain',
'application/x-pdl',
'application/x-php'
];
// Blocks and pages can have any mimetype, but layouts must be text/bbcode
if((in_array($element['mimetype'], $mimetypes)) && ($type === 'page' || $type === 'block') ) {
$arr['mimetype'] = $element['mimetype'];
} else {
$arr['mimetype'] = 'text/bbcode';
}
// Verify ability to use html or php!!!
$execflag = false;
if ($arr['mimetype'] === 'application/x-php') {
$z = q("select account_id, account_roles, channel_pageflags from account "
. "left join channel on channel_account_id = account_id where channel_id = %d limit 1",
intval(local_channel())
);
if ($z && (($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($z[0]['channel_pageflags'] & PAGE_ALLOWCODE))) {
$execflag = true;
}
}
$z = q("select * from iconfig where v = '%s' and k = '%s' and cat = 'service' limit 1",
dbesc($name),
dbesc($namespace)
);
$i = q("select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['mid']),
intval(local_channel())
);
$remote_id = 0;
if ($z && $i) {
$remote_id = $z[0]['id'];
$arr['id'] = $i[0]['id'];
// don't update if it has the same timestamp as the original
if ($arr['edited'] > $i[0]['edited'])
$x = item_store_update($arr, $execflag);
} else {
if (($i) && (intval($i[0]['item_deleted']))) {
// was partially deleted already, finish it off
q("delete from item where mid = '%s' and uid = %d",
dbesc($arr['mid']),
intval(local_channel())
);
}
$x = item_store($arr, $execflag);
}
if ($x['success']) {
$item_id = $x['item_id'];
update_remote_id($channel, $item_id, $arr['item_type'], $name, $namespace, $remote_id, $arr['mid']);
$element['import_success'] = 1;
} else {
$element['import_success'] = 0;
}
return $element;
}

View File

@ -421,7 +421,7 @@ function post_activity_item($arr) {
$arr['deny_cid'] = ((x($arr,'deny_cid')) ? $arr['deny_cid'] : $channel['channel_deny_cid']);
$arr['deny_gid'] = ((x($arr,'deny_gid')) ? $arr['deny_gid'] : $channel['channel_deny_gid']);
$arr['comment_policy'] = map_scope(\Zotlabs\Access/PermissionLimits::Get($channel['channel_id'],'post_comments'));
$arr['comment_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'post_comments'));
if ((! $arr['plink']) && (intval($arr['item_thread_top']))) {
$arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid'];

View File

@ -25,7 +25,7 @@ function menu_fetch($name,$uid,$observer_xchan) {
return null;
}
function menu_element($menu) {
function menu_element($channel,$menu) {
$arr = array();
$arr['type'] = 'menu';
@ -46,7 +46,12 @@ function menu_element($menu) {
$arr['items'] = array();
foreach($menu['items'] as $it) {
$entry = array();
$entry['link'] = str_replace(z_root() . '/channel/' . $channel['channel_address'],'[channelurl]',$it['mitem_link']);
$entry['link'] = str_replace(z_root() . '/page/' . $channel['channel_address'],'[pageurl]',$it['mitem_link']);
$entry['link'] = str_replace(z_root() . '/cloud/' . $channel['channel_address'],'[cloudurl]',$it['mitem_link']);
$entry['link'] = str_replace(z_root(),'[baseurl]',$it['mitem_link']);
$entry['desc'] = $it['mitem_desc'];
$entry['order'] = $it['mitem_order'];
if($it['mitem_flags']) {
@ -389,12 +394,13 @@ function menu_del_item($menu_id,$uid,$item_id) {
function menu_sync_packet($uid,$observer_hash,$menu_id,$delete = false) {
$r = menu_fetch_id($menu_id,$uid);
$c = channelx_by_n($uid);
if($r) {
$m = menu_fetch($r['menu_name'],$uid,$observer_hash);
if($m) {
if($delete)
$m['menu_delete'] = 1;
build_sync_packet($uid,array('menu' => array(menu_element($m))));
build_sync_packet($uid,array('menu' => array(menu_element($c,$m))));
}
}
}

View File

@ -1,4 +1,7 @@
<?php
require_once('include/security.php');
/**
* @file include/permissions.php
*
@ -119,10 +122,21 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) {
dbesc($observer_xchan)
);
if(! $x) {
// not in address book, see if they've got an xchan
$y = q("select xchan_network from xchan where xchan_hash = '%s' limit 1",
dbesc($observer_xchan)
);
// see if they've got a guest access token; these are treated as connections
$y = atoken_abook($uid,$observer_xchan);
if($y)
$x = array($y);
if(! $x) {
// not in address book and no guest token, see if they've got an xchan
// these *may* have individual (PERMS_SPECIFIC) permissions, but are not connections
$y = q("select xchan_network from xchan where xchan_hash = '%s' limit 1",
dbesc($observer_xchan)
);
if($y) {
$x = array(pseudo_abook($y[0]));
}
}
}
$abook_checked = true;
@ -184,7 +198,7 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) {
// If we're still here, we have an observer, check the network.
if($channel_perm & PERMS_NETWORK) {
if(($x && $x[0]['xchan_network'] === 'zot') || ($y && $y[0]['xchan_network'] === 'zot')) {
if($x && $x[0]['xchan_network'] === 'zot') {
$ret[$perm_name] = true;
continue;
}
@ -232,6 +246,12 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) {
// They're a contact, so they have permission
if($channel_perm & PERMS_CONTACTS) {
// it was a fake abook entry, not really a connection
if(array_key_exists('abook_pseudo',$x[0]) && intval($x[0]['abook_pseudo'])) {
$ret[$perm_name] = false;
continue;
}
$ret[$perm_name] = true;
continue;
}
@ -328,10 +348,21 @@ function perm_is_allowed($uid, $observer_xchan, $permission) {
return false;
if(! $x) {
// not in address book, see if they've got an xchan
$y = q("select xchan_network from xchan where xchan_hash = '%s' limit 1",
dbesc($observer_xchan)
);
// see if they've got a guest access token
$y = atoken_abook($uid,$observer_xchan);
if($y)
$x = array($y);
if(! $x) {
// not in address book and no guest token, see if they've got an xchan
$y = q("select xchan_network from xchan where xchan_hash = '%s' limit 1",
dbesc($observer_xchan)
);
if($y) {
$x = array(pseudo_abook($y[0]));
}
}
}
$abperms = load_abconfig($uid,$observer_xchan,'my_perms');
}
@ -401,6 +432,10 @@ function perm_is_allowed($uid, $observer_xchan, $permission) {
// They're a contact, so they have permission
if($channel_perm & PERMS_CONTACTS) {
// it was a fake abook entry, not really a connection
if(array_key_exists('abook_pseudo',$x[0]) && intval($x[0]['abook_pseudo'])) {
return false;
}
return true;
}

View File

@ -108,6 +108,7 @@ function atoken_xchan($atoken) {
'xchan_name' => $atoken['atoken_name'],
'xchan_addr' => t('guest:') . $atoken['atoken_name'] . '@' . \App::get_hostname(),
'xchan_network' => 'unknown',
'xchan_url' => z_root(),
'xchan_hidden' => 1,
'xchan_photo_mimetype' => 'image/jpeg',
'xchan_photo_l' => get_default_profile_photo(300),
@ -119,6 +120,105 @@ function atoken_xchan($atoken) {
return null;
}
function atoken_delete($atoken_id) {
$r = q("select * from atoken where atoken_id = %d",
intval($atoken_id)
);
if(! $r)
return;
$c = q("select channel_id, channel_hash from channel where channel_id = %d",
intval($r[0]['atoken_uid'])
);
if(! $c)
return;
$atoken_xchan = substr($c[0]['channel_hash'],0,16) . '.' . $r[0]['atoken_name'];
q("delete from atoken where atoken_id = %d",
intval($atoken_id)
);
q("delete from abconfig where chan = %d and xchan = '%s'",
intval($c[0]['channel_id']),
dbesc($atoken_xchan)
);
}
// in order for atoken logins to create content (such as posts) they need a stored xchan.
// we'll create one on the first atoken_login; it can't really ever go away but perhaps
// @fixme we should set xchan_deleted if it's expired or removed
function atoken_create_xchan($xchan) {
$r = q("select xchan_hash from xchan where xchan_hash = '%s'",
dbesc($xchan['xchan_hash'])
);
if($r)
return;
$r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_addr, xchan_url, xchan_name, xchan_network, xchan_photo_mimetype, xchan_photo_l, xchan_photo_m, xchan_photo_s )
values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
dbesc($xchan['xchan_hash']),
dbesc($xchan['xchan_hash']),
dbesc($xchan['xchan_addr']),
dbesc($xchan['xchan_url']),
dbesc($xchan['xchan_name']),
dbesc($xchan['xchan_network']),
dbesc($xchan['xchan_photo_mimetype']),
dbesc($xchan['xchan_photo_l']),
dbesc($xchan['xchan_photo_m']),
dbesc($xchan['xchan_photo_s'])
);
return true;
}
function atoken_abook($uid,$xchan_hash) {
if(substr($xchan_hash,16,1) != '.')
return false;
$r = q("select channel_hash from channel where channel_id = %d limit 1",
intval($uid)
);
if(! $r)
return false;
$x = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'",
intval($uid),
dbesc(substr($xchan_hash,17))
);
if($x) {
$xchan = atoken_xchan($x[0]);
$xchan['abook_blocked'] = 0;
$xchan['abook_ignored'] = 0;
$xchan['abook_pending'] = 0;
return $xchan;
}
return false;
}
function pseudo_abook($xchan) {
if(! $xchan)
return false;
// set abook_pseudo to flag that we aren't really connected.
$xchan['abook_pseudo'] = 1;
$xchan['abook_blocked'] = 0;
$xchan['abook_ignored'] = 0;
$xchan['abook_pending'] = 0;
return $xchan;
}
/**
@ -396,7 +496,7 @@ function public_permissions_sql($observer_hash) {
* In this implementation, a security token is reusable (if the user submits a form, goes back and resubmits the form, maybe with small changes;
* or if the security token is used for ajax-calls that happen several times), but only valid for a certain amout of time (3hours).
* The "typename" seperates the security tokens of different types of forms. This could be relevant in the following case:
* A security token is used to protekt a link from CSRF (e.g. the "delete this profile"-link).
* A security token is used to protekt a link from CSRF (e.g. the "delete this profile"-link).
* If the new page contains by any chance external elements, then the used security token is exposed by the referrer.
* Actually, important actions should not be triggered by Links / GET-Requests at all, but somethimes they still are,
* so this mechanism brings in some damage control (the attacker would be able to forge a request to a form of this type, but not to forms of other types).

View File

@ -2242,6 +2242,34 @@ function design_tools() {
));
}
/**
* @brief Creates website import tools menu
*
* @return string
*/
function website_import_tools() {
$channel = App::get_channel();
$sys = false;
if(App::$is_sys && is_site_admin()) {
require_once('include/channel.php');
$channel = get_sys_channel();
$sys = true;
}
return replace_macros(get_markup_template('website_import_tools.tpl'), array(
'$title' => t('Import'),
'$import_label' => t('Import website...'),
'$import_placeholder' => t('Select folder to import'),
'$file_upload_text' => t('Import from a zipped folder:'),
'$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'),
));
}
/* case insensitive in_array() */
function in_arrayi($needle, $haystack) {

View File

@ -779,6 +779,20 @@ function widget_design_tools($arr) {
return design_tools();
}
function widget_website_import_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.
if(App::$profile['profile_uid'])
if((App::$profile['profile_uid'] != local_channel()) && (! App::$is_sys))
return '';
if(! local_channel())
return '';
return website_import_tools();
}
function widget_findpeople($arr) {
return findpeople_widget();

View File

@ -159,7 +159,7 @@ class ASN_BASE {
}
$length = $tempLength;
}
$data = substr($string, $p, $length);
$data = substr($string, $p, intval($length));
$parsed[] = self::parseASNData($type, $data, $level, $maxLevels);
$p = $p + $length;
}

File diff suppressed because it is too large Load Diff

View File

@ -34,3 +34,88 @@
.webpage-list-tool {
padding: 7px 10px;
}
.webpage-import-button {
background-color: green;
color: white;
}
.webpage-import-button:hover {
background-color: darkgreen;
}
/* SQUARED TWO */
.squaredTwo {
width: 28px;
height: 28px;
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: 20px 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;
}
.squaredTwo label {
cursor: pointer;
position: absolute;
width: 20px;
height: 20px;
left: 4px;
top: 4px;
-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 );
}
.squaredTwo 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: 4px;
left: 4px;
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);
}
.squaredTwo label:hover::after {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
filter: alpha(opacity=30);
opacity: 0.3;
}
.squaredTwo input[type=checkbox]:checked + label:after {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
filter: alpha(opacity=100);
opacity: 1;
}

15
view/js/mod_webpages.js Normal file
View File

@ -0,0 +1,15 @@
$(document).ready(function() {
$("input[type=\"checkbox\"]").hide();
});
window.isChecked = true;
function checkedAll(isChecked) {
window.isChecked = !window.isChecked ;
var c = document.getElementsByTagName('input');
for (var i = 0; i < c.length; i++){
if (c[i].type == 'checkbox'){
c[i].checked = isChecked;
}
}
}

View File

@ -1,3 +1,4 @@
[region=aside]
[widget=design_tools][/widget]
[widget=website_import_tools][/widget]
[/region]

View File

@ -3,6 +3,31 @@
background-color: transparent;
}
textarea, input, select
{
color: #BBB !important;
background: #333 !important;
border-color: #2B2B2B !important;
}
#profile-jot-submit-wrapper {
border-top: none;
padding: 10px 0;
}
#jot-title-wrap {
border-bottom: none;
margin-bottom: 5px;
}
optgroup {
color: #CCC !important;
}
option {
color: $link_colour !important;
}
.vcard, #contact-block, .widget {
background-color: transparent;
border: none;
@ -390,3 +415,21 @@ pre {
box-shadow: 0px 3px 3px #222;
}
.contextual-help-content-open {
background: $nav_bg;
top: 50px;
border-bottom: #555 1px solid;
box-shadow: 0px 3px 3px rgba(85,85,85,0.2);
}
.contextual-help-tool {
opacity: 0.5;
}
.contextual-help-tool:hover {
opacity: 1;
}
.contextual-help-tool i {
color: $link_colour;
}

View File

@ -290,3 +290,10 @@ pre {
-webkit-box-shadow: none;
box-shadow: none;
}
.contextual-help-content-open {
background: #FFF;
top: 50px;
}

View File

@ -3,6 +3,31 @@
background-color: transparent;
}
textarea, input, select
{
color: $font_colour !important;
background: $bgcolour !important;
border: 1px solid #143D12 !important;
}
#profile-jot-submit-wrapper {
border-top: none;
padding: 10px 0;
}
#jot-title-wrap {
border-bottom: none;
margin-bottom: 5px;
}
optgroup {
color: #32962D !important;
}
option {
color: $link_colour !important;
}
.vcard, #contact-block, .widget {
background-color: transparent;
border: none;
@ -153,22 +178,22 @@ input[type="submit"] {
color: #50f148 !important;
}
nav .dropdown-menu>li>a{
nav .dropdown-menu>li>a {
color: #50f148;
}
nav .dropdown-menu>li>a:hover,nav .dropdown-menu>li>a:focus{
nav .dropdown-menu>li>a:hover,nav .dropdown-menu>li>a:focus {
color: #50f148;
background-color: #143D12;
background-image: none;
}
nav .dropdown-menu .divider{
nav .dropdown-menu .divider {
background-color: #143D12;
}
nav .dropdown-menu>li>a:hover,nav .dropdown-menu>li>a:focus{
nav .dropdown-menu>li>a:hover,nav .dropdown-menu>li>a:focus {
color: #50f148;
background-color: #143D12;
background-image: none;
@ -339,3 +364,22 @@ pre {
-webkit-box-shadow: none;
box-shadow: none;
}
.contextual-help-content-open {
background: $nav_bg;
top: 50px;
border-bottom: #1C5419 1px solid;
box-shadow: 0px 3px 3px rgba(28,84,25,0.2);
}
.contextual-help-tool {
opacity: 0.5;
}
.contextual-help-tool:hover {
opacity: 1;
}
.contextual-help-tool i {
color: $link_colour;
}

View File

@ -3,6 +3,31 @@
background-color: transparent;
}
textarea, input, select
{
color: $font_colour !important;
background: $bgcolour !important;
border: 1px solid #FFF !important;
}
#profile-jot-submit-wrapper {
border-top: none;
padding: 10px 0;
}
#jot-title-wrap {
border-bottom: none;
margin-bottom: 5px;
}
optgroup {
color: #FFF !important;
}
option {
color: $link_colour !important;
}
.vcard, #contact-block, .widget {
background-color: transparent;
border: none;
@ -312,3 +337,22 @@ pre {
-webkit-box-shadow: none;
box-shadow: none;
}
.contextual-help-content-open {
background: $nav_bg;
top: 50px;
border-bottom: #FFF 1px solid;
box-shadow: 0px 3px 3px rgba(255,255,255,0.2);
}
.contextual-help-tool {
opacity: 0.5;
}
.contextual-help-tool:hover {
opacity: 1;
}
.contextual-help-tool i {
color: $link_colour;
}

View File

@ -9,7 +9,7 @@
</td>
{{/if}}
<td class="abook-me">
{{if $self || !$field.5}}
{{if $self || !$field.5 || $twocol }}
<input type="checkbox" name='{{$field.0}}' class='abook-edit-me' id='me_id_{{$field.0}}' value="{{$field.4}}" {{if $field.3}}checked="checked"{{/if}} />
{{/if}}
{{if $notself && $field.5}}

View File

@ -17,13 +17,45 @@
<div class="settings-submit-wrapper form-group">
<button type="submit" name="submit" class="btn btn-primary">{{$submit}}</button>
</div>
</form>
<div class="descriptive-text">{{$desc2}}</div>
<ul>
<li>{{$url1}}<span class="zat-example">?f=&zat=<span class="token-mirror"></span></span></li>
<li>{{$url2}}<span class="zat-example">?f=&zat=<span class="token-mirror"></span></span></li>
</ul>
</div>
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="perms-tool">
<h3>
<a data-toggle="collapse" data-parent="#contact-edit-tools" href="#perms-tool-collapse" aria-expanded="true" aria-controls="perms-tool-collapse">
{{$permlbl}}
</a>
</h3>
</div>
<div id="perms-tool-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="perms-tool">
<div class="section-content-tools-wrapper">
<div class="section-content-warning-wrapper">
{{$permnote}}
</div>
<table id="perms-tool-table" class=form-group>
<tr>
<td></td><td class="abook-them">{{$them}}</td><td colspan="2" class="abook-me">{{$me}}</td>
</tr>
{{foreach $perms as $prm}}
{{include file="field_acheckbox.tpl" field=$prm}}
{{/foreach}}
</table>
<div class="settings-submit-wrapper" >
<button type="submit" name="submit" class="btn btn-primary">{{$submit}}</button>
</div>
</div>
</div>
</div>
</form>
<div class="descriptive-text">{{$desc2}}</div>
<ul>
<li>{{$url1}}<span class="zat-example">?f=&zat=<span class="token-mirror"></span></span></li>
<li>{{$url2}}<span class="zat-example">?f=&zat=<span class="token-mirror"></span></span></li>
</ul>
{{if $tokens}}
<div class="section-content-wrapper-np">
<table id="atoken-index">

126
view/tpl/webpage_import.tpl Normal file
View File

@ -0,0 +1,126 @@
<div class="generic-content-wrapper">
<form action="" method="post" autocomplete="on" >
<input type="hidden" name="action" value="importselected">
<div class="section-title-wrapper">
<div class="pull-right">
<button class="btn btn-md btn-success" type="submit" name="submit" value="{{$importbtn}}">{{$importbtn}}</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>&nbsp;Toggle Select All</button>
</div>
<div class="clear"></div>
<h4>Scanned Pages</h4>
<div>
<table class="table-striped table-responsive table-hover" style="width: 100%;">
<tr><td>Import?</td><td>Page</td><!--<td>Existing Page</td>--></tr>
{{foreach $pages as $page}}
<tr>
<td>
<div class='squaredTwo'>
<input type="checkbox" id="page_{{$page.pagelink}}" name="page[]" value="{{$page.pagelink}}">
<label for="page_{{$page.pagelink}}"></label>
</div>
</td>
<td>
<div class='desc'>
Page Link: {{$page.pagelink}}<br>
Layout: {{$page.layout}}<br>
Title: {{$page.title}}<br>
Content File: {{$page.contentfile}}<br>
Type: {{$page.type}}<br>
</div>
</td>
<!-- TODO: Retrieve existing element information to avoid accidental overwriting
<td>
<div class='desc'>
Name: {{$page.curpage.pagelink}}<br>
Layout: {{$page.curpage.layout}}<br>
Title: {{$page.curpage.title}}<br>
Last edit: {{$page.curpage.edited}}<br>
Type: {{$page.curpage.type}}<br>
</div>
</td>
-->
</tr>
{{/foreach}}
</table>
</div>
<h4>Scanned Layouts</h4>
<div>
<table class="table-striped table-responsive table-hover" style="width: 100%;">
<tr><td>Import?</td><td>Layout</td><!--<td>Existing Layout</td>--></tr>
{{foreach $layouts as $layout}}
<tr>
<td>
<div class='squaredTwo'>
<input type="checkbox" id="layout_{{$layout.name}}" name="layout[]" value="{{$layout.name}}">
<label for="layout_{{$layout.name}}"></label>
</div>
</td>
<td>
<div class='desc'>
Name: {{$layout.name}}<br>
Description: {{$layout.description}}<br>
Content File: {{$layout.contentfile}}<br>
</div>
</td>
<!-- TODO: Retrieve existing element information to avoid accidental overwriting
<td>
<div class='desc'>
Name: {{$layout.curblock.name}}<br>
Title: {{$layout.curblock.description}}<br>
Last edit: {{$layout.curblock.edited}}<br>
</div>
</td>
-->
</tr>
{{/foreach}}
</table>
</div>
<h4>Scanned Blocks</h4>
<div>
<table class="table-striped table-responsive table-hover" style="width: 100%;">
<tr><td>Import?</td><td>Block</td><!--<td>Existing Block</td>--></tr>
{{foreach $blocks as $block}}
<tr>
<td>
<div class='squaredTwo'>
<input type="checkbox" id="block_{{$block.name}}" name="block[]" value="{{$block.name}}">
<label for="block_{{$block.name}}"></label>
</div>
</td>
<td>
<div class='desc'>
Name: {{$block.name}}<br>
Title: {{$block.title}}<br>
Content File: {{$block.contentfile}}<br>
Type: {{$block.type}}<br>
</div>
</td>
<!-- TODO: Retrieve existing element information to avoid accidental overwriting
<td>
<div class='desc'>
Name: {{$block.curblock.name}}<br>
Title: {{$block.curblock.title}}<br>
Last edit: {{$block.curblock.edited}}<br>
Type: {{$block.curblock.type}}<br>
</div>
</td>
-->
</tr>
{{/foreach}}
</table>
</div>
</div>
<div class="clear"></div>
</form>
</div>

View File

@ -0,0 +1,37 @@
<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>