aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/account.php37
-rw-r--r--include/acl_selectors.php7
-rw-r--r--include/attach.php219
-rw-r--r--include/bbcode.php7
-rw-r--r--include/channel.php31
-rw-r--r--include/contact_widgets.php2
-rw-r--r--include/conversation.php25
-rwxr-xr-xinclude/dba/dba_driver.php2
-rw-r--r--include/features.php53
-rw-r--r--include/help.php111
-rw-r--r--include/import.php215
-rwxr-xr-xinclude/items.php74
-rw-r--r--include/nav.php5
-rwxr-xr-xinclude/oembed.php15
-rw-r--r--include/permissions.php6
-rw-r--r--include/photos.php3
-rwxr-xr-xinclude/plugin.php12
-rw-r--r--include/text.php99
-rw-r--r--include/widgets.php108
-rw-r--r--include/zot.php40
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();
}