diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/account.php | 37 | ||||
-rw-r--r-- | include/acl_selectors.php | 7 | ||||
-rw-r--r-- | include/attach.php | 219 | ||||
-rw-r--r-- | include/bbcode.php | 7 | ||||
-rw-r--r-- | include/channel.php | 31 | ||||
-rw-r--r-- | include/contact_widgets.php | 2 | ||||
-rw-r--r-- | include/conversation.php | 25 | ||||
-rwxr-xr-x | include/dba/dba_driver.php | 2 | ||||
-rw-r--r-- | include/features.php | 53 | ||||
-rw-r--r-- | include/help.php | 111 | ||||
-rw-r--r-- | include/import.php | 215 | ||||
-rwxr-xr-x | include/items.php | 74 | ||||
-rw-r--r-- | include/nav.php | 5 | ||||
-rwxr-xr-x | include/oembed.php | 15 | ||||
-rw-r--r-- | include/permissions.php | 6 | ||||
-rw-r--r-- | include/photos.php | 3 | ||||
-rwxr-xr-x | include/plugin.php | 12 | ||||
-rw-r--r-- | include/text.php | 99 | ||||
-rw-r--r-- | include/widgets.php | 108 | ||||
-rw-r--r-- | include/zot.php | 40 |
20 files changed, 939 insertions, 132 deletions
diff --git a/include/account.php b/include/account.php index 5c44f13ca..47310912f 100644 --- a/include/account.php +++ b/include/account.php @@ -14,6 +14,13 @@ require_once('include/crypto.php'); require_once('include/channel.php'); +function get_account_by_id($account_id) { + $r = q("select * from account where account_id = %d", + intval($account_id) + ); + return (($r) ? $r[0] : false); +} + function check_account_email($email) { $result = array('error' => false, 'message' => ''); @@ -112,6 +119,7 @@ function create_account($arr) { $flags = ((x($arr,'account_flags')) ? intval($arr['account_flags']) : ACCOUNT_OK); $roles = ((x($arr,'account_roles')) ? intval($arr['account_roles']) : 0 ); $expires = ((x($arr,'expires')) ? intval($arr['expires']) : NULL_DATE); + $techlevel = ((array_key_exists('techlevel',$arr)) ? intval($arr['techlevel']) : intval(get_config('system','techlevel'))); $default_service_class = get_config('system','default_service_class'); @@ -171,16 +179,17 @@ function create_account($arr) { $r = q("INSERT INTO account ( account_parent, account_salt, account_password, account_email, account_language, - account_created, account_flags, account_roles, account_expires, account_service_class ) - VALUES ( %d, '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s' )", + account_created, account_flags, account_roles, account_level, account_expires, account_service_class ) + VALUES ( %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s' )", intval($parent), dbesc($salt), dbesc($password_encoded), dbesc($email), dbesc(get_best_language()), dbesc(datetime_convert()), - dbesc($flags), - dbesc($roles), + intval($flags), + intval($roles), + intval($techlevel), dbesc($expires), dbesc($default_service_class) ); @@ -751,3 +760,23 @@ function upgrade_bool_message($bbcode = false) { $x = upgrade_link($bbcode); return t('This action is not available under your subscription plan.') . (($x) ? ' ' . $x : '') ; } + + +function get_account_techlevel($account_id = 0) { + + $role = \Zotlabs\Lib\System::get_server_role(); + if($role == 'basic') + return 0; + if($role == 'standard') + return 5; + + if(! $account_id) { + $x = \App::get_account(); + } + else { + $x = get_account_by_id($account_id); + } + + return (($x) ? intval($x['account_level']) : 0); + +}
\ No newline at end of file diff --git a/include/acl_selectors.php b/include/acl_selectors.php index 9bee942e2..362776b44 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -148,11 +148,6 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti array_walk($deny_cid,'fixacl'); array_walk($deny_gid,'fixacl'); } - - $jotnets = ''; - if($show_jotnets) { - call_hooks('jot_networks', $jotnets); - } $r = q("SELECT id, hash, gname FROM groups WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", intval(local_channel()) @@ -181,8 +176,6 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti '$allowgid' => json_encode($allow_gid), '$denycid' => json_encode($deny_cid), '$denygid' => json_encode($deny_gid), - '$jnetModalTitle' => t('Other networks and post services'), - '$jotnets' => $jotnets, '$aclModalTitle' => t('Permissions'), '$aclModalDesc' => $dialog_description, '$aclModalDismiss' => t('Close'), diff --git a/include/attach.php b/include/attach.php index 172840b96..237b06217 100644 --- a/include/attach.php +++ b/include/attach.php @@ -1994,3 +1994,222 @@ 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. + * The data is physically moved in the store/nickname storage location and the paths adjusted + * in the attach structure (and if applicable the photo table). The new 'album name' is recorded + * for photos and will show up immediately there. + * This takes a channel_id, attach.hash of the file to move (this is the same as a photo resource_id), and + * the attach.hash of the new parent folder, which must already exist. If $new_folder_hash is blank or empty, + * the file is relocated to the root of the channel's storage area. + * + * @fixme: this operation is currently not synced to clones !! + */ + +function attach_move($channel_id,$resource_id,$new_folder_hash) { + + $c = channelx_by_n($channel_id); + if(! $c) + return false; + + $r = q("select * from attach where hash = '%s' and uid = %d limit 1", + dbesc($resource_id), + intval($channel_id) + ); + if(! $r) + return false; + + $oldstorepath = $r[0]['content']; + + if($new_folder_hash) { + $n = q("select * from attach where hash = '%s' and uid = %d limit 1", + dbesc($new_folder_hash), + intval($channel_id) + ); + if(! $n) + return; + $newdirname = $n[0]['filename']; + $newstorepath = $n[0]['content'] . '/' . $resource_id; + } + else { + $newstorepath = 'store/' . $c['channel_address'] . '/' . $resource_id; + } + + rename($oldstorepath,$newstorepath); + + // duplicate detection. If 'overwrite' is specified, return false because we can't yet do that. + + $filename = $r[0]['filename']; + + $s = q("select filename, id, hash, filesize from attach where filename = '%s' and folder = '%s' ", + dbesc($filename), + dbesc($new_folder_hash) + ); + + if($s) { + $overwrite = get_pconfig($channel_id,'system','overwrite_dup_files'); + if($overwrite) { + // @fixme + return; + } + else { + if(strpos($filename,'.') !== false) { + $basename = substr($filename,0,strrpos($filename,'.')); + $ext = substr($filename,strrpos($filename,'.')); + } + else { + $basename = $filename; + $ext = ''; + } + + $v = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' ", + dbesc($basename . $ext), + dbesc($basename . '(%)' . $ext), + dbesc($new_folder_hash) + ); + + if($v) { + $x = 1; + + do { + $found = false; + foreach($v as $vv) { + if($vv['filename'] === $basename . '(' . $x . ')' . $ext) { + $found = true; + break; + } + } + if($found) + $x++; + } + while($found); + $filename = $basename . '(' . $x . ')' . $ext; + } + else + $filename = $basename . $ext; + } + } + + $t = q("update attach set content = '%s', folder = '%s', filename = '%s' where id = %d", + dbesc($newstorepath), + dbesc($new_folder_hash), + dbesc($filename), + intval($r[0]['id']) + ); + + if($r[0]['is_photo']) { + $t = q("update photo set album = '%s', filename = '%s' where resource_id = '%s' and uid = %d", + dbesc($newdirname), + dbesc($filename), + dbesc($resource_id), + intval($channel_id) + ); + + $t = q("update photo set content = '%s' where resource_id = '%s' and uid = %d and imgscale = 0", + dbesc($newstorepath), + dbesc($resource_id), + intval($channel_id) + ); + } + + return true; + +} + + +function attach_folder_select_list($channel_id) { + + $r = q("select * from attach where is_dir = 1 and uid = %d", + intval($channel_id) + ); + + $out = []; + $out[''] = '/'; + + if($r) { + foreach($r as $rv) { + $x = attach_folder_rpaths($r,$rv); + if($x) + $out[$x[0]] = $x[1]; + } + } + return $out; +} + +function attach_folder_rpaths($all_folders,$that_folder) { + + $path = '/' . $that_folder['filename']; + $current_hash = $that_folder['hash']; + $parent_hash = $that_folder['folder']; + $error = false; + $found = false; + + if($parent_hash) { + do { + foreach($all_folders as $selected) { + if(! $selected['is_dir']) + continue; + if($selected['hash'] == $parent_hash) { + $path = '/' . $selected['filename'] . $path; + $current_hash = $selected['hash']; + $parent_hash = $selected['folder']; + $found = true; + break; + } + } + if(! $found) + $error = true; + } + while((! $found) && (! $error) && ($parent_hash != '')); + } + return (($error) ? false : [ $current_hash , $path ]); + +}
\ No newline at end of file diff --git a/include/bbcode.php b/include/bbcode.php index db3a1011b..70c75e5c4 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -666,8 +666,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) $Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a class="zrl" href="$1" target="_blank" >$2</a>', $Text); } - // Remove bookmarks from UNO - if (get_config('system','server_role') === 'basic') + if (get_account_techlevel() < 2) $Text = str_replace('<span class="bookmark-identifier">#^</span>', '', $Text); // Perform MAIL Search @@ -769,11 +768,14 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) } // Check for list text $Text = str_replace("[*]", "<li>", $Text); + $Text = str_replace("[]", "<li><input type=\"checkbox\" disabled=\"disabled\">", $Text); + $Text = str_replace("[x]", "<li><input type=\"checkbox\" checked=\"checked\" disabled=\"disabled\">", $Text); // handle nested lists $endlessloop = 0; while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) || + ((strpos($Text, "[/checklist]") !== false) && (strpos($Text, "[checklist]") !== false)) || ((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) || ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false)) || ((strpos($Text, "[/dl]") !== false) && (strpos($Text, "[dl") !== false)) || @@ -785,6 +787,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) $Text = preg_replace("/\[list=((?-i)I)\](.*?)\[\/list\]/ism", '<ul class="listupperroman" style="list-style-type: upper-roman;">$2</ul>', $Text); $Text = preg_replace("/\[list=((?-i)a)\](.*?)\[\/list\]/ism", '<ul class="listloweralpha" style="list-style-type: lower-alpha;">$2</ul>', $Text); $Text = preg_replace("/\[list=((?-i)A)\](.*?)\[\/list\]/ism", '<ul class="listupperalpha" style="list-style-type: upper-alpha;">$2</ul>', $Text); + $Text = preg_replace("/\[checklist\](.*?)\[\/checklist\]/ism", '<ul class="checklist" style="list-style-type: none;">$1</ul>', $Text); $Text = preg_replace("/\[ul\](.*?)\[\/ul\]/ism", '<ul class="listbullet" style="list-style-type: circle;">$1</ul>', $Text); $Text = preg_replace("/\[ol\](.*?)\[\/ol\]/ism", '<ul class="listdecimal" style="list-style-type: decimal;">$1</ul>', $Text); $Text = preg_replace("/\[li\](.*?)\[\/li\]/ism", '<li>$1</li>', $Text); diff --git a/include/channel.php b/include/channel.php index 1179697a4..7bfa2b6a2 100644 --- a/include/channel.php +++ b/include/channel.php @@ -1103,8 +1103,8 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa require_once('include/widgets.php'); - if(! feature_enabled($profile['uid'],'hide_rating')) - $z = widget_rating(array('target' => $profile['channel_hash'])); +// if(! feature_enabled($profile['uid'],'hide_rating')) + $z = widget_rating(array('target' => $profile['channel_hash'])); $o .= replace_macros($tpl, array( '$zcard' => $zcard, @@ -1381,6 +1381,11 @@ function zid($s,$address = '') { if (! strlen($s) || strpos($s,'zid=')) return $s; + $m = parse_url($s); + $fragment = ((array_key_exists('fragment',$m) && $m['fragment']) ? $m['fragment'] : false); + if($fragment !== false) + $s = str_replace('#' . $fragment,'',$s); + $has_params = ((strpos($s,'?')) ? true : false); $num_slashes = substr_count($s, '/'); if (! $has_params) @@ -1401,6 +1406,11 @@ function zid($s,$address = '') { else $zurl = $s; + // put fragment at the end + + if($fragment) + $zurl .= '#' . $fragment; + $arr = array('url' => $s, 'zid' => urlencode($myaddr), 'result' => $zurl); call_hooks('zid', $arr); @@ -1627,13 +1637,24 @@ function notifications_on($channel_id,$value) { function get_channel_default_perms($uid) { + + $ret = []; + $r = q("select abook_xchan from abook where abook_channel = %d and abook_self = 1 limit 1", intval($uid) ); - if($r) - return load_abconfig($uid,$r[0]['abook_xchan'],'my_perms'); + if($r) { + $x = load_abconfig($uid,$r[0]['abook_xchan'],'my_perms'); + if($x) { + foreach($x as $xv) { + if(intval($xv['v'])) { + $ret[] = $xv['k']; + } + } + } + } - return array(); + return $ret; } diff --git a/include/contact_widgets.php b/include/contact_widgets.php index 85c46b0d1..8f76bb4bc 100644 --- a/include/contact_widgets.php +++ b/include/contact_widgets.php @@ -13,7 +13,7 @@ function findpeople_widget() { } } - $advanced_search = ((local_channel() && get_pconfig(local_channel(),'feature','expert')) ? t('Advanced') : false); + $advanced_search = ((local_channel() && feature_enabled(local_channel(),'advanced_dirsearch')) ? t('Advanced') : false); return replace_macros(get_markup_template('peoplefind.tpl'),array( '$findpeople' => t('Find Channels'), diff --git a/include/conversation.php b/include/conversation.php index 7d1473fe2..e515fb26a 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -941,12 +941,9 @@ function item_photo_menu($item){ $clean_url = normalise_link($item['author-link']); } - $poco_rating = get_config('system','poco_rating_enable'); - // if unset default to enabled - if($poco_rating === false) - $poco_rating = true; + $rating_enabled = get_config('system','rating_enabled'); - $ratings_url = (($poco_rating) ? z_root() . '/ratings/' . urlencode($item['author_xchan']) : ''); + $ratings_url = (($rating_enabled) ? z_root() . '/ratings/' . urlencode($item['author_xchan']) : ''); $post_menu = Array( t("View Source") => $vsrc_link, @@ -1200,8 +1197,6 @@ function status_editor($a, $x, $popup = false) { $tpl = get_markup_template('jot.tpl'); - $jotplugins = ''; - $preview = t('Preview'); if(x($x, 'hide_preview')) $preview = ''; @@ -1218,8 +1213,18 @@ function status_editor($a, $x, $popup = false) { if(! $cipher) $cipher = 'aes256'; + // avoid illegal offset errors + if(! array_key_exists('permissions',$x)) + $x['permissions'] = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; + + $jotplugins = ''; call_hooks('jot_tool', $jotplugins); + $jotnets = ''; + if(x($x,'jotnets')) { + call_hooks('jot_networks', $jotnets); + } + $o .= replace_macros($tpl, array( '$return_path' => ((x($x, 'return_path')) ? $x['return_path'] : App::$query_string), '$action' => z_root() . '/item', @@ -1276,6 +1281,8 @@ function status_editor($a, $x, $popup = false) { '$preview' => $preview, '$source' => ((x($x, 'source')) ? $x['source'] : ''), '$jotplugins' => $jotplugins, + '$jotnets' => $jotnets, + '$jotnets_label' => t('Other networks and post services'), '$defexpire' => $defexpire, '$feature_expire' => $feature_expire, '$expires' => t('Set expiration date'), @@ -1618,6 +1625,8 @@ function profile_tabs($a, $is_owner = false, $nickname = null){ $uid = ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : local_channel()); + $account_id = ((App::$profile['profile_uid']) ? App::$profile['channel_account_id'] : App::$channel['channel_account_id']); + if($uid == local_channel()) { $cal_link = ''; @@ -1720,7 +1729,7 @@ function profile_tabs($a, $is_owner = false, $nickname = null){ ); } - if(feature_enabled($uid,'wiki') && (get_config('system','server_role') !== 'basic')) { + if(feature_enabled($uid,'wiki') && (get_account_techlevel($account_id) > 3)) { $tabs[] = array( 'label' => t('Wiki'), 'url' => z_root() . '/wiki/' . $nickname, diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php index f6091f6e1..7225a9be2 100755 --- a/include/dba/dba_driver.php +++ b/include/dba/dba_driver.php @@ -62,6 +62,8 @@ class DBA { if(is_object(self::$dba) && self::$dba->connected) { + if($server === 'localhost') + $port = $set_port; $dns = ((self::$dbtype == DBTYPE_POSTGRES) ? 'postgres' : 'mysql') . ':host=' . $server . (is_null($port) ? '' : ';port=' . $port) . ';dbname=' . $db; diff --git a/include/features.php b/include/features.php index 356de35a2..b59ab0c3e 100644 --- a/include/features.php +++ b/include/features.php @@ -38,7 +38,7 @@ function get_feature_default($feature) { function get_features($filtered = true) { - $server_role = get_config('system','server_role'); + $server_role = \Zotlabs\Lib\System::get_server_role(); if($server_role === 'basic' && $filtered) return array(); @@ -54,22 +54,18 @@ function get_features($filtered = true) { array('advanced_profiles', t('Advanced Profiles'), t('Additional profile sections and selections'),false,get_config('feature_lock','advanced_profiles')), array('profile_export', t('Profile Import/Export'), t('Save and load profile details across sites/channels'),false,get_config('feature_lock','profile_export')), array('webpages', t('Web Pages'), t('Provide managed web pages on your channel'),false,get_config('feature_lock','webpages')), - array('wiki', t('Wiki'), t('Provide a wiki for your channel'),(($server_role === 'basic') ? false : true),get_config('feature_lock','wiki')), - array('hide_rating', t('Hide Rating'), t('Hide the rating buttons on your channel and profile pages. Note: People can still rate you somewhere else.'),false,get_config('feature_lock','hide_rating')), + array('wiki', t('Wiki'), t('Provide a wiki for your channel'),(($server_role === 'basic' || get_account_techlevel() < 3) ? false : true),get_config('feature_lock','wiki')), +// array('hide_rating', t('Hide Rating'), t('Hide the rating buttons on your channel and profile pages. Note: People can still rate you somewhere else.'),false,get_config('feature_lock','hide_rating')), array('private_notes', t('Private Notes'), t('Enables a tool to store notes and reminders (note: not encrypted)'),false,get_config('feature_lock','private_notes')), array('nav_channel_select', t('Navigation Channel Select'), t('Change channels directly from within the navigation dropdown menu'),false,get_config('feature_lock','nav_channel_select')), array('photo_location', t('Photo Location'), t('If location data is available on uploaded photos, link this to a map.'),false,get_config('feature_lock','photo_location')), array('ajaxchat', t('Access Controlled Chatrooms'), t('Provide chatrooms and chat services with access control.'),true,get_config('feature_lock','ajaxchat')), array('smart_birthdays', t('Smart Birthdays'), t('Make birthday events timezone aware in case your friends are scattered across the planet.'),true,get_config('feature_lock','smart_birthdays')), - array('expert', t('Expert Mode'), t('Enable Expert Mode to provide advanced configuration options'),false,get_config('feature_lock','expert')), - array('premium_channel', t('Premium Channel'), t('Allows you to set restrictions and terms on those that connect with your channel'),false,get_config('feature_lock','premium_channel')), ), // Post composition 'composition' => array( t('Post Composition Features'), -// array('richtext', t('Richtext Editor'), t('Enable richtext editor'),falseget_config('feature_lock','richtext')), -// array('markdown', t('Use Markdown'), t('Allow use of "Markdown" to format posts'),false,get_config('feature_lock','markdown')), array('large_photos', t('Large Photos'), t('Include large (1024px) photo thumbnails in posts. If not enabled, use small (640px) photo thumbnails'),false,get_config('feature_lock','large_photos')), array('channel_sources', t('Channel Sources'), t('Automatically import channel content from other channels or feeds'),false,get_config('feature_lock','channel_sources')), array('content_encrypt', t('Even More Encryption'), t('Allow optional encryption of content end-to-end with a shared secret key'),false,get_config('feature_lock','content_encrypt')), @@ -89,8 +85,7 @@ function get_features($filtered = true) { array('personal_tab', t('Network Personal Tab'), t('Enable tab to display only Network posts that you\'ve interacted on'),false,get_config('feature_lock','personal_tab')), array('new_tab', t('Network New Tab'), t('Enable tab to display all new Network activity'),false,get_config('feature_lock','new_tab')), array('affinity', t('Affinity Tool'), t('Filter stream activity by depth of relationships'),false,get_config('feature_lock','affinity')), - array('connfilter', t('Connection Filtering'), t('Filter incoming posts from connections based on keywords/content'),false,get_config('feature_lock','connfilter')), - array('suggest', t('Suggest Channels'), t('Show channel suggestions'),false,get_config('feature_lock','suggest')), + array('suggest', t('Suggest Channels'), t('Show friend and connection suggestions'),false,get_config('feature_lock','suggest')), ), // Item tools @@ -106,6 +101,46 @@ function get_features($filtered = true) { ), ); + $techlevel = get_account_techlevel(); + + if($techlevel > 2) { + $arr['net_module'][] = [ + 'connfilter', + t('Connection Filtering'), + t('Filter incoming posts from connections based on keywords/content'), + false, + get_config('feature_lock','connfilter') + ]; + } + + if($techlevel > 3) { + if($server_role === 'pro') { + $arr['general'][] = [ + 'premium_channel', + t('Premium Channel'), + t('Allows you to set restrictions and terms on those that connect with your channel'), + false, + get_config('feature_lock','premium_channel') + ]; + } + $arr['general'][] = [ + 'advanced_dirsearch', + t('Advanced Directory Search'), + t('Allows creation of complex directory search queries'), + false, + get_config('feature_lock','advanced_dirsearch') + ]; + $arr['general'][] = [ + 'advanced_theming', + t('Advanced Theme and Layout Settings'), + t('Allows fine tuning of themes and page layouts'), + false, + get_config('feature_lock','advanced_theming') + ]; + } + + + // removed any locked features and remove the entire category if this makes it empty if($filtered) { diff --git a/include/help.php b/include/help.php index 7f57f3334..5538fbc1e 100644 --- a/include/help.php +++ b/include/help.php @@ -1,5 +1,104 @@ <?php +function get_help_content($tocpath = false) { + + global $lang; + + $doctype = 'markdown'; + + $text = ''; + + $path = (($tocpath !== false) ? $tocpath : ''); + + if($tocpath === false && argc() > 1) { + $path = ''; + for($x = 1; $x < argc(); $x ++) { + if(strlen($path)) + $path .= '/'; + $path .= argv($x); + } + } + + if($path) { + $title = basename($path); + if(! $tocpath) + \App::$page['title'] = t('Help:') . ' ' . ucwords(str_replace('-',' ',notags($title))); + + $text = load_doc_file('doc/' . $path . '.md'); + + if(! $text) { + $text = load_doc_file('doc/' . $path . '.bb'); + if($text) + $doctype = 'bbcode'; + } + if(! $text) { + $text = load_doc_file('doc/' . $path . '.html'); + if($text) + $doctype = 'html'; + } + } + + if($tocpath === false) { + if(! $text) { + $text = load_doc_file('doc/Site.md'); + \App::$page['title'] = t('Help'); + } + if(! $text) { + $doctype = 'bbcode'; + $text = load_doc_file('doc/main.bb'); + \App::$page['title'] = t('Help'); + } + + if(! $text) { + header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . t('Not Found')); + $tpl = get_markup_template("404.tpl"); + return replace_macros($tpl, array( + '$message' => t('Page not found.' ) + )); + } + } + + if($doctype === 'html') + $content = $text; + if($doctype === 'markdown') { + require_once('library/markdown.php'); + # escape #include tags + $text = preg_replace('/#include/ism', '%%include', $text); + $content = Markdown($text); + $content = preg_replace('/%%include/ism', '#include', $content); + } + if($doctype === 'bbcode') { + require_once('include/bbcode.php'); + $content = bbcode($text); + // bbcode retargets external content to new windows. This content is internal. + $content = str_replace(' target="_blank"','',$content); + } + + $content = preg_replace_callback("/#include (.*?)\;/ism", 'preg_callback_help_include', $content); + return translate_projectname($content); + +} + +function preg_callback_help_include($matches) { + + if($matches[1]) { + $include = str_replace($matches[0],load_doc_file($matches[1]),$matches[0]); + if(preg_match('/\.bb$/', $matches[1]) || preg_match('/\.txt$/', $matches[1])) { + require_once('include/bbcode.php'); + $include = bbcode($include); + $include = str_replace(' target="_blank"','',$include); + } + elseif(preg_match('/\.md$/', $matches[1])) { + require_once('library/markdown.php'); + $include = Markdown($include); + } + return $include; + } + +} + + + function load_doc_file($s) { $lang = \App::$language; if(! isset($lang)) @@ -17,8 +116,9 @@ function load_doc_file($s) { } function find_doc_file($s) { - if(file_exists($s)) + if(file_exists($s)) { return file_get_contents($s); + } return ''; } @@ -40,8 +140,13 @@ function search_doc_files($s) { $r = fetch_post_tags($r,true); for($x = 0; $x < count($r); $x ++) { - - $r[$x]['text'] = $r[$x]['body']; + $position = stripos($r[$x]['body'], $s); + $dislen = 300; + $start = $position-floor($dislen/2); + if ( $start < 0) { + $start = 0; + } + $r[$x]['text'] = substr($r[$x]['body'], $start, $dislen); $r[$x]['rank'] = 0; if($r[$x]['term']) { diff --git a/include/import.php b/include/import.php index 84881a420..ddffb2ac3 100644 --- a/include/import.php +++ b/include/import.php @@ -1312,8 +1312,12 @@ function scan_webpage_elements($path, $type, $cloud = false) { } $content = file_get_contents($folder . '/' . $contentfilename); 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; } @@ -1395,12 +1399,12 @@ function scan_webpage_elements($path, $type, $cloud = false) { ); $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['created'] = datetime_convert('UTC', 'UTC'); $arr['mid'] = $arr['parent_mid'] = item_message_id(); } + // Update the edited time whether or not the element already exists + $arr['edited'] = datetime_convert('UTC', 'UTC'); // Import the actual element content $arr['body'] = file_get_contents($element['path']); // The element owner is the channel importing the elements @@ -1415,7 +1419,7 @@ function scan_webpage_elements($path, $type, $cloud = false) { 'application/x-pdl', 'application/x-php' ]; - // Blocks and pages can have any mimetype, but layouts must be text/bbcode + // Blocks and pages can have any of the valid mimetypes, but layouts must be text/bbcode if((in_array($element['mimetype'], $mimetypes)) && ($type === 'page' || $type === 'block') ) { $arr['mimetype'] = $element['mimetype']; } else { @@ -1424,7 +1428,7 @@ function scan_webpage_elements($path, $type, $cloud = false) { // Verify ability to use html or php!!! $execflag = false; - if ($arr['mimetype'] === 'application/x-php') { + if ($arr['mimetype'] === 'application/x-php' || $arr['mimetype'] === 'text/html') { $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()) @@ -1432,10 +1436,15 @@ function scan_webpage_elements($path, $type, $cloud = false) { if ($z && (($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($z[0]['channel_pageflags'] & PAGE_ALLOWCODE))) { $execflag = true; + } else { + logger('Unable to import element "' . $name .'" because AllowCode permission is denied.'); + notice( t('Unable to import element "' . $name .'" because AllowCode permission is denied.') . EOL); + $element['import_success'] = 0; + return $element; } } - $z = q("select * from iconfig where v = '%s' and k = '%s' and cat = 'service' limit 1", + $z = q("select * from iconfig where v = '%s' and k = '%s' and cat = 'system' limit 1", dbesc($name), dbesc($namespace) ); @@ -1472,3 +1481,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/items.php b/include/items.php index 0373dcb0d..9079621a3 100755 --- a/include/items.php +++ b/include/items.php @@ -113,6 +113,26 @@ function collect_recipients($item, &$private_envelope) { // if($policy === 'pub') // $recipients[] = $sys['xchan_hash']; } + + // Add the authors of any posts in this thread, if they are known to us. + // This is specifically designed to forward wall-to-wall posts to the original author, + // in case they aren't a connection but have permission to write on our wall. + // This is important for issue tracker channels. It should be a no-op for most channels. + // Whether or not they will accept the delivery is not determined here, but should + // be taken into account by zot:process_delivery() + + $r = q("select author_xchan from item where parent = %d", + intval($item['parent']) + ); + if($r) { + foreach($r as $rv) { + if(! in_array($rv['author_xchan'],$recipients)) { + $recipients[] = $rv['author_xchan']; + } + } + } + + } // This is a somewhat expensive operation but important. @@ -214,11 +234,10 @@ function can_comment_on_post($observer_xchan, $item) { return true; break; case 'public': - // We don't allow public comments yet, until a policy - // for dealing with anonymous comments is in place with - // a means to moderate comments. Until that time, return - // false. - return false; + // We don't really allow or support public comments yet, but anonymous + // folks won't ever reach this point (as $observer_xchan will be empty). + // This means the viewer has an xchan and we can identify them. + return true; break; case 'any connections': case 'contacts': @@ -695,8 +714,9 @@ function get_item_elements($x,$allow_code = false) { // hub and verify that they are legit - or else we're going to toss the post. We only need to do this // once, and after that your hub knows them. Sure some info is in the post, but it's only a transit identifier // and not enough info to be able to look you up from your hash - which is the only thing stored with the post. - - if(($xchan_hash = import_author_xchan($x['author'])) !== false) + + $xchan_hash = import_author_xchan($x['author']); + if($xchan_hash) $arr['author_xchan'] = $xchan_hash; else return array(); @@ -705,7 +725,8 @@ function get_item_elements($x,$allow_code = false) { if($arr['author_xchan'] === make_xchan_hash($x['owner']['guid'],$x['owner']['guid_sig'])) $arr['owner_xchan'] = $arr['author_xchan']; else { - if(($xchan_hash = import_author_xchan($x['owner'])) !== false) + $xchan_hash = import_author_xchan($x['owner']); + if($xchan_hash) $arr['owner_xchan'] = $xchan_hash; else return array(); @@ -1166,7 +1187,7 @@ function encode_item_xchan($xchan) { $ret['name'] = $xchan['xchan_name']; $ret['address'] = $xchan['xchan_addr']; - $ret['url'] = (($xchan['hubloc_url']) ? $xchan['hubloc_url'] : $xchan['xchan_url']); + $ret['url'] = $xchan['xchan_url']; $ret['network'] = $xchan['xchan_network']; $ret['photo'] = array('mimetype' => $xchan['xchan_photo_mimetype'], 'src' => $xchan['xchan_photo_m']); $ret['guid'] = $xchan['xchan_guid']; @@ -1625,8 +1646,21 @@ function item_store($arr, $allow_exec = false, $deliver = true) { $arr['commented'] = ((x($arr,'commented') !== false) ? datetime_convert('UTC','UTC',$arr['commented']) : datetime_convert()); $arr['comments_closed'] = ((x($arr,'comments_closed') !== false) ? datetime_convert('UTC','UTC',$arr['comments_closed']) : NULL_DATE); - $arr['received'] = datetime_convert(); - $arr['changed'] = datetime_convert(); + if($deliver) { + $arr['received'] = datetime_convert(); + $arr['changed'] = datetime_convert(); + } + else { + + // When deliver flag is false, we are *probably* performing an import or bulk migration. + // If one updates the changed timestamp it will be made available to zotfeed and delivery + // will still take place through backdoor methods. Since these fields are rarely used + // otherwise, just preserve the original timestamp. + + $arr['received'] = ((x($arr,'received') !== false) ? datetime_convert('UTC','UTC',$arr['received']) : datetime_convert()); + $arr['changed'] = ((x($arr,'changed') !== false) ? datetime_convert('UTC','UTC',$arr['changed']) : datetime_convert()); + } + $arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : ''); $arr['coord'] = ((x($arr,'coord')) ? notags(trim($arr['coord'])) : ''); $arr['parent_mid'] = ((x($arr,'parent_mid')) ? notags(trim($arr['parent_mid'])) : ''); @@ -2033,8 +2067,22 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) { $arr['comments_closed'] = $orig[0]['comments_closed']; $arr['commented'] = $orig[0]['commented']; - $arr['received'] = datetime_convert(); - $arr['changed'] = datetime_convert(); + + if($deliver) { + $arr['received'] = datetime_convert(); + $arr['changed'] = datetime_convert(); + } + else { + + // When deliver flag is false, we are *probably* performing an import or bulk migration. + // If one updates the changed timestamp it will be made available to zotfeed and delivery + // will still take place through backdoor methods. Since these fields are rarely used + // otherwise, just preserve the original timestamp. + + $arr['received'] = $orig[0]['received']; + $arr['changed'] = $orig[0]['changed']; + } + $arr['route'] = ((array_key_exists('route',$arr)) ? trim($arr['route']) : $orig[0]['route']); $arr['diaspora_meta'] = ((x($arr,'diaspora_meta')) ? $arr['diaspora_meta'] : $orig[0]['diaspora_meta']); $arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : $orig[0]['location']); diff --git a/include/nav.php b/include/nav.php index 025da71b3..c2a058457 100644 --- a/include/nav.php +++ b/include/nav.php @@ -63,6 +63,7 @@ EOT; $server_role = get_config('system','server_role'); $basic = (($server_role === 'basic') ? true : false); + $techlevel = get_account_techlevel(); // nav links: array of array('href', 'text', 'extra css classes', 'title') $nav = Array(); @@ -144,10 +145,10 @@ EOT; $homelink = (($observer) ? $observer['xchan_url'] : ''); } - if((App::$module != 'home') && (! (local_channel()))) + if(! local_channel()) $nav['home'] = array($homelink, t('Home'), "", t('Home Page'),'home_nav_btn'); - if((App::$config['system']['register_policy'] == REGISTER_OPEN) && (! $_SESSION['authenticated'])) + if(((get_config('system','register_policy') == REGISTER_OPEN) || (get_config('system','register_policy') == REGISTER_APPROVE)) && (! $_SESSION['authenticated'])) $nav['register'] = array('register',t('Register'), "", t('Create an account'),'register_nav_btn'); if(! get_config('system','hide_help')) { diff --git a/include/oembed.php b/include/oembed.php index fe6f10d71..085637a00 100755 --- a/include/oembed.php +++ b/include/oembed.php @@ -156,9 +156,12 @@ function oembed_fetch_url($embedurl){ if ($action !== 'block') { // try oembed autodiscovery $redirects = 0; - $result = z_fetch_url($furl, false, $redirects, array('timeout' => 15, 'accept_content' => "text/*", 'novalidate' => true )); + $result = z_fetch_url($furl, false, $redirects, array('timeout' => 30, 'accept_content' => "text/*", 'novalidate' => true )); + if($result['success']) $html_text = $result['body']; + else + logger('fetch failure: ' . $furl); if($html_text) { $dom = @DOMDocument::loadHTML($html_text); @@ -171,7 +174,10 @@ function oembed_fetch_url($embedurl){ foreach($entries as $e){ $href = $e->getAttributeNode("href")->nodeValue; $x = z_fetch_url($href . '&maxwidth=' . App::$videowidth); - $txt = $x['body']; + if($x['success']) + $txt = $x['body']; + else + logger('fetch failed: ' . $href); break; } // soundcloud is now using text/json+oembed instead of application/json+oembed, @@ -180,7 +186,10 @@ function oembed_fetch_url($embedurl){ foreach($entries as $e){ $href = $e->getAttributeNode("href")->nodeValue; $x = z_fetch_url($href . '&maxwidth=' . App::$videowidth); - $txt = $x['body']; + if($x['success']) + $txt = $x['body']; + else + logger('json fetch failed: ' . $href); break; } } diff --git a/include/permissions.php b/include/permissions.php index 637193973..d21b45550 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -6,8 +6,14 @@ require_once('include/security.php'); * @file include/permissions.php * * This file conntains functions to check and work with permissions. + * + * Most of this file is obsolete and has been superceded by extensible permissions in v1.12; it is left here + * for reference and because we haven't yet checked that all functions have been replaced and are available + * elsewhere (typically Zotlabs/Access/*). */ + + /** * @brief Return an array with all available permissions. * diff --git a/include/photos.php b/include/photos.php index d14c12d84..a3018816c 100644 --- a/include/photos.php +++ b/include/photos.php @@ -588,6 +588,8 @@ function photos_album_rename($channel_id, $oldname, $newname) { ); } + + /** * @brief * @@ -713,6 +715,7 @@ function profile_photo_set_profile_perms($uid, $profileid = 0) { if($profileid) { $r = q("SELECT photo, profile_guid, id, is_default, uid FROM profile WHERE uid = %d and ( profile.id = %d OR profile.profile_guid = '%s') LIMIT 1", + intval($uid), intval($profileid), dbesc($profileid) ); diff --git a/include/plugin.php b/include/plugin.php index cb206d944..663d17959 100755 --- a/include/plugin.php +++ b/include/plugin.php @@ -404,6 +404,18 @@ function check_plugin_versions($info) { return false; } } + if(array_key_exists('serverroles',$info)) { + $role = \Zotlabs\Lib\System::get_server_role(); + if(! ( + stristr($info['serverroles'],'*') + || stristr($info['serverroles'],'any') + || stristr($info['serverroles'],$role))) { + logger('serverrole limit: ' . $info['name'],LOGGER_NORMAL,LOG_WARNING); + return false; + + } + } + if(array_key_exists('requires',$info)) { $arr = explode(',',$info['requires']); diff --git a/include/text.php b/include/text.php index a2a6d918b..8b2e8b9e0 100644 --- a/include/text.php +++ b/include/text.php @@ -138,31 +138,74 @@ function purify_html($s, $allow_position = false) { $def = $config->getHTMLDefinition(true); //data- attributes used by the foundation library - $def->info_global_attr['data-options'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-magellan-expedition'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-magellan-destination'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-magellan-arrival'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-offcanvas'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-topbar'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-orbit'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-orbit-slide-number'] = new HTMLPurifier_AttrDef_Text; + + // f6 navigation + + //dropdown menu + $def->info_global_attr['data-dropdown-menu'] = new HTMLPurifier_AttrDef_Text; + //drilldown menu + $def->info_global_attr['data-drilldown'] = new HTMLPurifier_AttrDef_Text; + //accordion menu + $def->info_global_attr['data-accordion-menu'] = new HTMLPurifier_AttrDef_Text; + //responsive navigation + $def->info_global_attr['data-responsive-menu'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-responsive-toggle'] = new HTMLPurifier_AttrDef_Text; + //magellan + $def->info_global_attr['data-magellan'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-magellan-target'] = new HTMLPurifier_AttrDef_Text; + + // f6 containers + + //accordion + $def->info_global_attr['data-accordion'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-accordion-item'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-tab-content'] = new HTMLPurifier_AttrDef_Text; + //dropdown $def->info_global_attr['data-dropdown'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-dropdown-content'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-reveal-id'] = new HTMLPurifier_AttrDef_Text; + //off-canvas + $def->info_global_attr['data-off-canvas-wrapper'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-off-canvas'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-off-canvas-content'] = new HTMLPurifier_AttrDef_Text; + //reveal $def->info_global_attr['data-reveal'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-alert'] = new HTMLPurifier_AttrDef_Text; + //tabs + $def->info_global_attr['data-tabs'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-tabs-content'] = new HTMLPurifier_AttrDef_Text; + + // f6 media + + //orbit + $def->info_global_attr['data-orbit'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-slide'] = new HTMLPurifier_AttrDef_Text; + //tooltip $def->info_global_attr['data-tooltip'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-joyride'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-id'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-text'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-class'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-prev-tex'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-button'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-accordion'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-tab'] = new HTMLPurifier_AttrDef_Text; + + // f6 plugins + + //abide - the use is pointless since we can't do anything with forms + + //equalizer $def->info_global_attr['data-equalizer'] = new HTMLPurifier_AttrDef_Text; $def->info_global_attr['data-equalizer-watch'] = new HTMLPurifier_AttrDef_Text; + //interchange - potentially dangerous since it can load content + + //toggler + $def->info_global_attr['data-toggler'] = new HTMLPurifier_AttrDef_Text; + + //sticky + $def->info_global_attr['data-sticky'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-sticky-container'] = new HTMLPurifier_AttrDef_Text; + + // f6 common + + $def->info_global_attr['data-options'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-toggle'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-close'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-open'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-position'] = new HTMLPurifier_AttrDef_Text; + + //data- attributes used by the bootstrap library $def->info_global_attr['data-dismiss'] = new HTMLPurifier_AttrDef_Text; $def->info_global_attr['data-target'] = new HTMLPurifier_AttrDef_Text; @@ -936,7 +979,7 @@ function searchbox($s,$id='search-box',$url='/search',$save = false) { '$action_url' => z_root() . '/' . $url, '$search_label' => t('Search'), '$save_label' => t('Save'), - '$savedsearch' => feature_enabled(local_channel(),'savedsearch') + '$savedsearch' => ($save && feature_enabled(local_channel(),'savedsearch')) )); } @@ -2267,11 +2310,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 +2325,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 +2333,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 68db74703..0b3a0d108 100644 --- a/include/widgets.php +++ b/include/widgets.php @@ -209,7 +209,9 @@ function widget_savedsearch($arr) { if((! local_channel()) || (! feature_enabled(local_channel(),'savedsearch'))) return ''; - $search = ((x($_GET,'search')) ? $_GET['search'] : ''); + $search = ((x($_GET,'netsearch')) ? $_GET['netsearch'] : ''); + if(! $search) + $search = ((x($_GET,'search')) ? $_GET['search'] : ''); if(x($_GET,'searchsave') && $search) { $r = q("select * from `term` where `uid` = %d and `ttype` = %d and `term` = '%s' limit 1", @@ -287,6 +289,40 @@ function widget_savedsearch($arr) { return $o; } +function widget_sitesearch($arr) { + + $search = ((x($_GET,'search')) ? $_GET['search'] : ''); + + $srchurl = App::$query_string; + + $srchurl = rtrim(preg_replace('/search\=[^\&].*?(\&|$)/is','',$srchurl),'&'); + $srchurl = rtrim(preg_replace('/submit\=[^\&].*?(\&|$)/is','',$srchurl),'&'); + $srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl); + + + $hasq = ((strpos($srchurl,'?') !== false) ? true : false); + $hasamp = ((strpos($srchurl,'&') !== false) ? true : false); + + if(($hasamp) && (! $hasq)) + $srchurl = substr($srchurl,0,strpos($srchurl,'&')) . '?f=&' . substr($srchurl,strpos($srchurl,'&')+1); + + $o = ''; + + $saved = array(); + + $tpl = get_markup_template("sitesearch.tpl"); + $o = replace_macros($tpl, array( + '$title' => t('Search'), + '$searchbox' => searchbox($search, 'netsearch-box', $srchurl . (($hasq) ? '' : '?f='), false), + '$saved' => $saved, + )); + + return $o; +} + + + + function widget_filer($arr) { if(! local_channel()) @@ -594,14 +630,11 @@ function widget_settings_menu($arr) { ); } - // IF can go away when UNO export and import is fully functional - if(get_config('system','server_role') !== 'basic') { - $tabs[] = array( - 'label' => t('Export channel'), - 'url' => z_root() . '/uexport', - 'selected' => '' - ); - } + $tabs[] = array( + 'label' => t('Export channel'), + 'url' => z_root() . '/uexport', + 'selected' => '' + ); $tabs[] = array( 'label' => t('Connected apps'), @@ -609,7 +642,7 @@ function widget_settings_menu($arr) { 'selected' => ((argv(1) === 'oauth') ? 'active' : ''), ); - if(get_config('system','server_role') !== 'basic') { + if(get_account_techlevel() > 2) { $tabs[] = array( 'label' => t('Guest Access Tokens'), 'url' => z_root() . '/settings/tokens', @@ -779,7 +812,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 +824,7 @@ function widget_website_import_tools($arr) { if(! local_channel()) return ''; - return website_import_tools(); + return website_portation_tools(); } function widget_findpeople($arr) { @@ -963,6 +996,14 @@ function widget_suggestedchats($arr) { if(! feature_enabled(App::$profile['profile_uid'],'ajaxchat')) return ''; + // There are reports that this tool does not ever remove chatrooms on dead sites, + // and also will happily link to private chats which you cannot enter. + // For those reasons, it will be disabled until somebody decides it's worth + // fixing and comes up with a plan for doing so. + + return ''; + + // probably should restrict this to your friends, but then the widget will only work // if you are logged in locally. @@ -1286,8 +1327,8 @@ function widget_random_block($arr) { function widget_rating($arr) { - $poco_rating = get_config('system','poco_rating_enable'); - if((! $poco_rating) && ($poco_rating !== false)) { + $rating_enabled = get_config('system','rating_enabled'); + if(! $rating_enabled) { return; } @@ -1459,13 +1500,38 @@ function widget_tasklist($arr) { function widget_helpindex($arr) { - $o .= '<div class="widget">' . '<h3>' . t('Documentation') . '</h3>'; - $o .= '<ul class="nav nav-pills nav-stacked">'; - $o .= '<li><a href="help/general">' . t('Project/Site Information') . '</a></li>'; - $o .= '<li><a href="help/members">' . t('For Members') . '</a></li>'; - $o .= '<li><a href="help/admins">' . t('For Administrators') . '</a></li>'; - $o .= '<li><a href="help/develop">' . t('For Developers') . '</a></li>'; - $o .= '</ul></div>'; + + $o .= '<div class="widget">'; + $o .= '<h3>' . t('Documentation') . '</h3>'; + + $level_0 = get_help_content('toc'); + + $level_0 = preg_replace('/\<ul(.*?)\>/','<ul class="nav nav-pills nav-stacked">',$level_0); + + $levels = array(); + + + if(argc() > 2) { + $path = ''; + for($x = 1; $x < argc(); $x ++) { + $path .= argv($x) . '/'; + $y = get_help_content($path . 'toc'); + if($y) + $levels[] = preg_replace('/\<ul(.*?)\>/','<ul class="nav nav-pills nav-stacked">',$y); + } + } + + if($level_0) + $o .= $level_0; + if($levels) { + foreach($levels as $l) { + $o .= '<br /><br />'; + $o .= $l; + } + } + + $o .= '</div>'; + return $o; } diff --git a/include/zot.php b/include/zot.php index 01b29f74b..8771495ff 100644 --- a/include/zot.php +++ b/include/zot.php @@ -2844,6 +2844,7 @@ function import_site($arr, $pubkey) { $site_location = htmlspecialchars($arr['location'],ENT_COMPAT,'UTF-8',false); $site_realm = htmlspecialchars($arr['realm'],ENT_COMPAT,'UTF-8',false); $site_project = htmlspecialchars($arr['project'],ENT_COMPAT,'UTF-8',false); + $site_version = ((array_key_exists('version',$arr)) ? htmlspecialchars($arr['version'],ENT_COMPAT,'UTF-8',false) : ''); // You can have one and only one primary directory per realm. // Downgrade any others claiming to be primary. As they have @@ -2863,14 +2864,16 @@ function import_site($arr, $pubkey) { || ($siterecord['site_location'] != $site_location) || ($siterecord['site_register'] != $register_policy) || ($siterecord['site_project'] != $site_project) - || ($siterecord['site_realm'] != $site_realm)) { + || ($siterecord['site_realm'] != $site_realm) + || ($siterecord['site_version'] != $site_version) ) { + $update = true; // logger('import_site: input: ' . print_r($arr,true)); // logger('import_site: stored: ' . print_r($siterecord,true)); - $r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d, site_project = '%s' + $r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d, site_project = '%s', site_version = '%s' where site_url = '%s'", dbesc($site_location), intval($site_directory), @@ -2882,6 +2885,7 @@ function import_site($arr, $pubkey) { dbesc($site_realm), intval(SITE_TYPE_ZOT), dbesc($site_project), + dbesc($site_version), dbesc($url) ); if(! $r) { @@ -2899,8 +2903,8 @@ function import_site($arr, $pubkey) { else { $update = true; - $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm, site_type, site_project ) - values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s', %d, '%s' )", + $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm, site_type, site_project, site_version ) + values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s', %d, '%s', '%s' )", dbesc($site_location), dbesc($url), intval($access_policy), @@ -2911,7 +2915,8 @@ function import_site($arr, $pubkey) { dbesc($sellpage), dbesc($site_realm), intval(SITE_TYPE_ZOT), - dbesc($site_project) + dbesc($site_project), + dbesc($site_version) ); if(! $r) { logger('import_site: record create failed. ' . print_r($arr,true)); @@ -3708,6 +3713,8 @@ function zotinfo($arr) { } } + $ztarget_hash = (($ztarget && $zsig) ? make_xchan_hash($ztarget,$zsig) : '' ); + $r = null; if(strlen($zhash)) { @@ -3785,18 +3792,12 @@ function zotinfo($arr) { } else { // check if it has characteristics of a public forum based on custom permissions. - $t = q("select * from abconfig where abconfig.cat = 'my_perms' and abconfig.chan = %d and abconfig.xchan = '%s' and abconfig.k in ('tag_deliver', 'send_stream') ", - intval($e['channel_id']), - dbesc($e['channel_hash']) - ); - - $ch = 0; - - if($t) { - foreach($t as $tt) { - if($tt['k'] == 'tag_deliver' && $tt['v'] == 1) + $m = \Zotlabs\Access\Permissions::FilledAutoperms($e['channel_id']); + if($m) { + foreach($m as $k => $v) { + if($k == 'tag_deliver' && intval($v) == 1) $ch ++; - if($tt['k'] == 'send_stream' && $tt['v'] == 0) + if($k == 'send_stream' && intval($v) == 0) $ch ++; } if($ch == 2) @@ -3889,9 +3890,6 @@ function zotinfo($arr) { $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; - $ztarget_hash = (($ztarget && $zsig) - ? make_xchan_hash($ztarget,$zsig) - : '' ); $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false); @@ -3965,9 +3963,6 @@ function zotinfo($arr) { require_once('include/channel.php'); $ret['site']['channels'] = channel_total(); - - $ret['site']['version'] = Zotlabs\Lib\System::get_platform_name() . ' ' . STD_VERSION . '[' . DB_UPDATE_VERSION . ']'; - $ret['site']['admin'] = get_config('system','admin_email'); $visible_plugins = array(); @@ -3985,6 +3980,7 @@ function zotinfo($arr) { $ret['site']['location'] = get_config('system','site_location'); $ret['site']['realm'] = get_directory_realm(); $ret['site']['project'] = Zotlabs\Lib\System::get_platform_name() . ' ' . Zotlabs\Lib\System::get_server_role(); + $ret['site']['version'] = Zotlabs\Lib\System::get_project_version(); } |