diff options
author | Mario Vavti <mario@mariovavti.com> | 2018-10-19 11:18:28 +0200 |
---|---|---|
committer | Mario Vavti <mario@mariovavti.com> | 2018-10-19 11:18:28 +0200 |
commit | fa9e9510e5d993d183feb942fe74be5fdd07f5cf (patch) | |
tree | 41fec09f527a9346e043b8099b458a97d81b03ed /include | |
parent | 32de123db0ac526795a237ff46885fe8a332cbc0 (diff) | |
parent | 06b3ad1071c755757555baf941e2c0f446f97b21 (diff) | |
download | volse-hubzilla-fa9e9510e5d993d183feb942fe74be5fdd07f5cf.tar.gz volse-hubzilla-fa9e9510e5d993d183feb942fe74be5fdd07f5cf.tar.bz2 volse-hubzilla-fa9e9510e5d993d183feb942fe74be5fdd07f5cf.zip |
Merge branch '3.8RC'3.8
Diffstat (limited to 'include')
-rw-r--r-- | include/account.php | 13 | ||||
-rw-r--r-- | include/acl_selectors.php | 2 | ||||
-rw-r--r-- | include/api.php | 5 | ||||
-rw-r--r-- | include/api_auth.php | 37 | ||||
-rw-r--r-- | include/api_zot.php | 8 | ||||
-rw-r--r-- | include/attach.php | 5 | ||||
-rw-r--r-- | include/bbcode.php | 5 | ||||
-rw-r--r-- | include/bookmarks.php | 5 | ||||
-rw-r--r-- | include/channel.php | 59 | ||||
-rw-r--r-- | include/connections.php | 4 | ||||
-rw-r--r-- | include/conversation.php | 333 | ||||
-rw-r--r-- | include/features.php | 474 | ||||
-rw-r--r-- | include/group.php | 44 | ||||
-rw-r--r-- | include/help.php | 99 | ||||
-rw-r--r-- | include/hubloc.php | 2 | ||||
-rw-r--r-- | include/import.php | 5 | ||||
-rwxr-xr-x | include/items.php | 128 | ||||
-rw-r--r-- | include/js_strings.php | 19 | ||||
-rw-r--r-- | include/language.php | 26 | ||||
-rw-r--r-- | include/markdown.php | 132 | ||||
-rw-r--r-- | include/message.php | 8 | ||||
-rw-r--r-- | include/msglib.php | 28 | ||||
-rw-r--r-- | include/nav.php | 102 | ||||
-rw-r--r-- | include/network.php | 42 | ||||
-rw-r--r-- | include/permissions.php | 17 | ||||
-rwxr-xr-x | include/plugin.php | 164 | ||||
-rw-r--r-- | include/security.php | 4 | ||||
-rw-r--r-- | include/selectors.php | 27 | ||||
-rw-r--r-- | include/text.php | 57 | ||||
-rw-r--r-- | include/xchan.php | 2 | ||||
-rw-r--r-- | include/zot.php | 84 |
31 files changed, 1012 insertions, 928 deletions
diff --git a/include/account.php b/include/account.php index 51118c3c5..2ab99ce19 100644 --- a/include/account.php +++ b/include/account.php @@ -124,7 +124,7 @@ function account_store_lowlevel($arr) { 'account_expires' => ((array_key_exists('account_expires',$arr)) ? $arr['account_expires'] : '0001-01-01 00:00:00'), 'account_expire_notified' => ((array_key_exists('account_expire_notified',$arr)) ? $arr['account_expire_notified'] : '0001-01-01 00:00:00'), 'account_service_class' => ((array_key_exists('account_service_class',$arr)) ? $arr['account_service_class'] : ''), - 'account_level' => ((array_key_exists('account_level',$arr)) ? $arr['account_level'] : '0'), + 'account_level' => '5', 'account_password_changed' => ((array_key_exists('account_password_changed',$arr)) ? $arr['account_password_changed'] : '0001-01-01 00:00:00') ]; @@ -215,7 +215,7 @@ function create_account($arr) { 'account_created' => datetime_convert(), 'account_flags' => intval($flags), 'account_roles' => intval($roles), - 'account_level' => intval($techlevel), + 'account_level' => 5, 'account_expires' => $expires, 'account_service_class' => $default_service_class ] @@ -821,13 +821,6 @@ function upgrade_bool_message($bbcode = false) { function get_account_techlevel($account_id = 0) { - if(! $account_id) { - $x = \App::get_account(); - } - else { - $x = get_account_by_id($account_id); - } - - return (($x) ? intval($x['account_level']) : 0); + return (5); } diff --git a/include/acl_selectors.php b/include/acl_selectors.php index bada3e528..c7a87afee 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -89,7 +89,7 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti } } - $r = q("SELECT id, hash, gname FROM groups WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", + $r = q("SELECT id, hash, gname FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", intval(local_channel()) ); diff --git a/include/api.php b/include/api.php index 6a05a40a5..ed5c0d29f 100644 --- a/include/api.php +++ b/include/api.php @@ -127,7 +127,10 @@ require_once('include/api_zot.php'); } } - + + + $x = [ 'path' => App::$query_string ]; + call_hooks('api_not_found',$x); header('HTTP/1.1 404 Not Found'); logger('API call not implemented: ' . App::$query_string . ' - ' . print_r($_REQUEST,true)); diff --git a/include/api_auth.php b/include/api_auth.php index e2f7ab155..23ab9c946 100644 --- a/include/api_auth.php +++ b/include/api_auth.php @@ -12,7 +12,13 @@ function api_login(&$a){ require_once('include/oauth.php'); + + if(array_key_exists('REDIRECT_REMOTE_USER',$_SERVER) && (! array_key_exists('HTTP_AUTHORIZATION',$_SERVER))) { + $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_REMOTE_USER']; + } + // login with oauth + try { // OAuth 2.0 $storage = new \Zotlabs\Identity\OAuth2Storage(\DBA::$dba->db); @@ -66,32 +72,27 @@ function api_login(&$a){ logger($e->getMessage()); } - // workarounds for HTTP-auth in CGI mode - foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) { + if(array_key_exists('HTTP_AUTHORIZATION',$_SERVER)) { /* Basic authentication */ - if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,5) === 'Basic') { - $userpass = @base64_decode(substr(trim($_SERVER[$head]),6)) ; + if (substr(trim($_SERVER['HTTP_AUTHORIZATION']),0,5) === 'Basic') { + $userpass = @base64_decode(substr(trim($_SERVER['HTTP_AUTHORIZATION']),6)) ; if(strlen($userpass)) { list($name, $password) = explode(':', $userpass); $_SERVER['PHP_AUTH_USER'] = $name; $_SERVER['PHP_AUTH_PW'] = $password; } - break; } - /* Signature authentication */ + /* OpenWebAuth */ - if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') { + if(substr(trim($_SERVER['HTTP_AUTHORIZATION']),0,9) === 'Signature') { - if($head !== 'HTTP_AUTHORIZATION') { - $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; - continue; - } + $record = null; - $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]); + $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']); if($sigblock) { $keyId = str_replace('acct:','',$sigblock['keyId']); if($keyId) { @@ -108,16 +109,7 @@ function api_login(&$a){ $record = [ 'channel' => $c, 'account' => $a[0] ]; $channel_login = $c['channel_id']; } - else { - continue; - } } - else { - continue; - } - } - else { - continue; } if($record) { @@ -125,7 +117,6 @@ function api_login(&$a){ if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) { $record = null; } - break; } } } @@ -137,7 +128,7 @@ function api_login(&$a){ // process normal login request - if(isset($_SERVER['PHP_AUTH_USER'])) { + if(isset($_SERVER['PHP_AUTH_USER']) && (! $record)) { $channel_login = 0; $record = account_verify_password($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']); if($record && $record['channel']) { diff --git a/include/api_zot.php b/include/api_zot.php index 921242152..6a5b9a268 100644 --- a/include/api_zot.php +++ b/include/api_zot.php @@ -350,20 +350,20 @@ $r = null; if($_REQUEST['group_id']) { - $r = q("select * from groups where uid = %d and id = %d limit 1", + $r = q("select * from pgrp where uid = %d and id = %d limit 1", intval(api_user()), intval($_REQUEST['group_id']) ); } elseif($_REQUEST['group_name']) { - $r = q("select * from groups where uid = %d and gname = '%s' limit 1", + $r = q("select * from pgrp where uid = %d and gname = '%s' limit 1", intval(api_user()), dbesc($_REQUEST['group_name']) ); } if($r) { - $x = q("select * from group_member left join abook on abook_xchan = xchan and abook_channel = group_member.uid left join xchan on group_member.xchan = xchan.xchan_hash + $x = q("select * from pgrp_member left join abook on abook_xchan = xchan and abook_channel = pgrp_member.uid left join xchan on pgrp_member.xchan = xchan.xchan_hash where gid = %d", intval($r[0]['id']) ); @@ -376,7 +376,7 @@ if(api_user() === false) return false; - $r = q("select * from groups where uid = %d", + $r = q("select * from pgrp where uid = %d", intval(api_user()) ); json_return_and_die($r); diff --git a/include/attach.php b/include/attach.php index 202412263..4db5bc435 100644 --- a/include/attach.php +++ b/include/attach.php @@ -1428,6 +1428,8 @@ function attach_delete($channel_id, $resource, $is_photo = 0) { if(! $r) { attach_drop_photo($channel_id,$resource); + $arr = ['channel_id' => $channel_id, 'resource' => $resource, 'is_photo'=>$is_photo]; + call_hooks("attach_delete",$arr); return; } @@ -1486,6 +1488,9 @@ function attach_delete($channel_id, $resource, $is_photo = 0) { intval($channel_id) ); + $arr = ['channel_id' => $channel_id, 'resource' => $resource, 'is_photo'=>$is_photo]; + call_hooks("attach_delete",$arr); + file_activity($channel_id, $object, $object['allow_cid'], $object['allow_gid'], $object['deny_cid'], $object['deny_gid'], 'update', true); return; diff --git a/include/bbcode.php b/include/bbcode.php index 345b5b025..137e25a9c 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -953,12 +953,14 @@ function bbcode($Text, $options = []) { $Text = preg_replace_callback("/[^\^]\[url\]([$URLSearchString]*)\[\/url\]/ism", 'tryoembed', $Text); } } + if (strpos($Text,'[/url]') !== false) { $Text = preg_replace("/\#\^\[url\]([$URLSearchString]*)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text); $Text = preg_replace("/\#\^\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text); $Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text); $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text); } + if (strpos($Text,'[/zrl]') !== false) { $Text = preg_replace("/\#\^\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text); $Text = preg_replace("/\#\^\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text); @@ -966,9 +968,6 @@ function bbcode($Text, $options = []) { $Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a class="zrl" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text); } - if (get_account_techlevel() < 2) - $Text = str_replace('<span class="bookmark-identifier">#^</span>', '', $Text); - // Perform MAIL Search if (strpos($Text,'[/mail]') !== false) { $Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '<a href="mailto:$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text); diff --git a/include/bookmarks.php b/include/bookmarks.php index 0db103054..21456c871 100644 --- a/include/bookmarks.php +++ b/include/bookmarks.php @@ -59,9 +59,10 @@ function bookmark_add($channel,$sender,$taxonomy,$private,$opts = null) { ); if($r) logger('add_bookmark: duplicate menu entry', LOGGER_DEBUG); - if(! $r) + if(! $r) { $r = menu_add_item($menu_id,$channel_id,$iarr); - + menu_sync_packet($channel_id,get_observer_hash(),$menu_id); + } return $r; } diff --git a/include/channel.php b/include/channel.php index d7c5a2511..22cdb9fe7 100644 --- a/include/channel.php +++ b/include/channel.php @@ -4,6 +4,13 @@ * @brief Channel related functions. */ +use Zotlabs\Access\PermissionRoles; +use Zotlabs\Access\PermissionLimits; +use Zotlabs\Access\Permissions; +use Zotlabs\Daemon\Master; +use Zotlabs\Lib\System; +use Zotlabs\Render\Comanche; + require_once('include/zot.php'); require_once('include/crypto.php'); require_once('include/menu.php'); @@ -236,7 +243,7 @@ function create_identity($arr) { $role_permissions = null; if(array_key_exists('permissions_role',$arr) && $arr['permissions_role']) { - $role_permissions = \Zotlabs\Access\PermissionRoles::role_perms($arr['permissions_role']); + $role_permissions = PermissionRoles::role_perms($arr['permissions_role']); } if($role_permissions && array_key_exists('directory_publish',$role_permissions)) @@ -307,7 +314,7 @@ function create_identity($arr) { $perm_limits = site_default_perms(); foreach($perm_limits as $p => $v) - \Zotlabs\Access\PermissionLimits::Set($r[0]['channel_id'],$p,$v); + PermissionLimits::Set($r[0]['channel_id'],$p,$v); if($role_permissions && array_key_exists('perms_auto',$role_permissions)) set_pconfig($r[0]['channel_id'],'system','autoperms',intval($role_permissions['perms_auto'])); @@ -383,7 +390,7 @@ function create_identity($arr) { $myperms = ((array_key_exists('perms_connect',$role_permissions)) ? $role_permissions['perms_connect'] : array()); } else { - $x = \Zotlabs\Access\PermissionRoles::role_perms('social'); + $x = PermissionRoles::role_perms('social'); $myperms = $x['perms_connect']; } @@ -399,7 +406,7 @@ function create_identity($arr) { ] ); - $x = \Zotlabs\Access\Permissions::FilledPerms($myperms); + $x = Permissions::FilledPerms($myperms); foreach($x as $k => $v) { set_abconfig($newuid,$hash,'my_perms',$k,$v); } @@ -416,7 +423,7 @@ function create_identity($arr) { $autoperms = intval($role_permissions['perms_auto']); set_pconfig($newuid,'system','autoperms',$autoperms); if($autoperms) { - $x = \Zotlabs\Access\Permissions::FilledPerms($role_permissions['perms_connect']); + $x = Permissions::FilledPerms($role_permissions['perms_connect']); foreach($x as $k => $v) { set_pconfig($newuid,'autoperms',$k,$v); } @@ -440,7 +447,7 @@ function create_identity($arr) { // if our role_permissions indicate that we're using a default collection ACL, add it. if(is_array($role_permissions) && $role_permissions['default_collection']) { - $r = q("select hash from groups where uid = %d and gname = '%s' limit 1", + $r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1", intval($newuid), dbesc( t('Friends') ) ); @@ -482,7 +489,7 @@ function create_identity($arr) { */ call_hooks('create_identity', $newuid); - Zotlabs\Daemon\Master::Summon(array('Directory', $ret['channel']['channel_id'])); + Master::Summon(array('Directory', $ret['channel']['channel_id'])); } $ret['success'] = true; @@ -583,7 +590,7 @@ function change_channel_keys($channel) { xchan_change_key($oldxchan,$newxchan,$stored); - Zotlabs\Daemon\Master::Summon(array('Notifier', 'keychange', $channel['channel_id'])); + Master::Summon([ 'Notifier', 'keychange', $channel['channel_id'] ]); $ret['success'] = true; return $ret; @@ -666,7 +673,7 @@ function channel_change_address($channel,$new_address) { } } - Zotlabs\Daemon\Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id'])); + Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id'])); $ret['success'] = true; return $ret; @@ -759,7 +766,7 @@ function identity_basic_export($channel_id, $sections = null) { 'project' => PLATFORM_NAME, 'version' => STD_VERSION, 'database' => DB_UPDATE_VERSION, - 'server_role' => Zotlabs\Lib\System::get_server_role() + 'server_role' => System::get_server_role() ]; /* @@ -830,14 +837,14 @@ function identity_basic_export($channel_id, $sections = null) { $ret['hubloc'] = $r; } - $r = q("select * from groups where uid = %d ", + $r = q("select * from pgrp where uid = %d ", intval($channel_id) ); if($r) $ret['group'] = $r; - $r = q("select * from group_member where uid = %d ", + $r = q("select * from pgrp_member where uid = %d ", intval($channel_id) ); if($r) @@ -1425,7 +1432,7 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa } $menublock = get_pconfig($profile['uid'],'system','channel_menublock'); if ($menublock && (! $block)) { - $comanche = new Zotlabs\Render\Comanche(); + $comanche = new Comanche(); $channel_menu .= $comanche->block($menublock); } @@ -1701,7 +1708,7 @@ function zid_init() { dbesc($tmp_str) ); if(! $r) { - Zotlabs\Daemon\Master::Summon(array('Gprobe',bin2hex($tmp_str))); + Master::Summon(array('Gprobe',bin2hex($tmp_str))); } if($r && remote_channel() && remote_channel() === $r[0]['hubloc_hash']) return; @@ -1907,7 +1914,7 @@ function is_public_profile() { $channel = App::get_channel(); if($channel) { - $perm = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile'); + $perm = PermissionLimits::Get($channel['channel_id'],'view_profile'); if($perm == PERMS_PUBLIC) return true; } @@ -2526,6 +2533,12 @@ function channel_remove($channel_id, $local = true, $unset_session = false) { if(! $local) { + if(intval($r[0]['channel_removed'])) { + // already removed. do not propagate deletion of a channel which + // may have been removed locally at some previous time. + return; + } + $r = q("update channel set channel_deleted = '%s', channel_removed = 1 where channel_id = %d", dbesc(datetime_convert()), intval($channel_id) @@ -2545,11 +2558,11 @@ function channel_remove($channel_id, $local = true, $unset_session = false) { dbesc($channel['channel_hash']) ); - Zotlabs\Daemon\Master::Summon(array('Notifier','purge_all',$channel_id)); + Master::Summon(array('Notifier','purge_all',$channel_id)); } - $r = q("select * from iconfig left join item on item.id = iconfig.iid + $r = q("select iid from iconfig left join item on item.id = iconfig.iid where item.uid = %d", intval($channel_id) ); @@ -2566,8 +2579,8 @@ function channel_remove($channel_id, $local = true, $unset_session = false) { q("DELETE FROM chatroom WHERE cr_uid = %d", intval($channel_id)); q("DELETE FROM conv WHERE uid = %d", intval($channel_id)); - q("DELETE FROM groups WHERE uid = %d", intval($channel_id)); - q("DELETE FROM group_member WHERE uid = %d", intval($channel_id)); + q("DELETE FROM pgrp WHERE uid = %d", intval($channel_id)); + q("DELETE FROM pgrp_member WHERE uid = %d", intval($channel_id)); q("DELETE FROM event WHERE uid = %d", intval($channel_id)); q("DELETE FROM mail WHERE channel_id = %d", intval($channel_id)); q("DELETE FROM menu WHERE menu_channel_id = %d", intval($channel_id)); @@ -2589,8 +2602,6 @@ function channel_remove($channel_id, $local = true, $unset_session = false) { } } - - $r = q("select id from item where uid = %d", intval($channel_id)); if($r) { foreach($r as $rv) { @@ -2598,7 +2609,6 @@ function channel_remove($channel_id, $local = true, $unset_session = false) { } } - q("delete from abook where abook_xchan = '%s' and abook_self = 1 ", dbesc($channel['channel_hash']) ); @@ -2658,7 +2668,7 @@ function channel_remove($channel_id, $local = true, $unset_session = false) { @rrmdir($f); } - Zotlabs\Daemon\Master::Summon(array('Directory',$channel_id)); + Master::Summon([ 'Directory', $channel_id ]); if($channel_id == local_channel() && $unset_session) { App::$session->nuke(); @@ -2797,3 +2807,6 @@ function pchan_to_chan($pchan) { return $chan; } +function channel_url($channel) { + return (($channel) ? z_root() . '/channel/' . $channel['channel_address'] : z_root()); +} diff --git a/include/connections.php b/include/connections.php index 1135b6697..874237f97 100644 --- a/include/connections.php +++ b/include/connections.php @@ -296,7 +296,7 @@ function remove_all_xchan_resources($xchan, $channel_id = 0) { $r = q("delete from event where event_xchan = '%s'", dbesc($xchan) ); - $r = q("delete from group_member where xchan = '%s'", + $r = q("delete from pgrp_member where xchan = '%s'", dbesc($xchan) ); $r = q("delete from mail where ( from_xchan = '%s' or to_xchan = '%s' )", @@ -404,7 +404,7 @@ function contact_remove($channel_id, $abook_id) { intval($channel_id) ); - $r = q("delete from group_member where xchan = '%s' and uid = %d", + $r = q("delete from pgrp_member where xchan = '%s' and uid = %d", dbesc($abook['abook_xchan']), intval($channel_id) ); diff --git a/include/conversation.php b/include/conversation.php index 4997bc2b7..041994b90 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -888,6 +888,7 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa '$user' => App::$user, '$threads' => $threads, '$wait' => t('Loading...'), + '$conversation_tools' => t('Conversation Tools'), '$dropping' => ($page_dropping?t('Delete Selected Items'):False), )); @@ -1231,13 +1232,27 @@ function format_like($cnt, $arr, $type, $id) { return $o; } + +/** + * Wrapper to allow addons to replace the status editor if desired. + */ +function status_editor($a, $x, $popup = false, $module='') { + $hook_info = ['editor_html' => '', 'x' => $x, 'popup' => $popup, 'module' => $module]; + call_hooks('status_editor',$hook_info); + if ($hook_info['editor_html'] == '') { + return hz_status_editor($a, $x, $popup); + } else { + return $hook_info['editor_html']; + } +} + /** * This is our general purpose content editor. * It was once nicknamed "jot" and you may see references to "jot" littered throughout the code. * They are referring to the content editor or components thereof. */ -function status_editor($a, $x, $popup = false) { +function hz_status_editor($a, $x, $popup = false) { $o = ''; @@ -1447,7 +1462,8 @@ function status_editor($a, $x, $popup = false) { '$expanded' => ((x($x, 'expanded')) ? $x['expanded'] : false), '$bbcode' => ((x($x, 'bbcode')) ? $x['bbcode'] : false), '$parent' => ((array_key_exists('parent',$x) && $x['parent']) ? $x['parent'] : 0), - '$reset' => $reset + '$reset' => $reset, + '$is_owner' => ((local_channel() && (local_channel() == $x['profile_uid'])) ? true : false) )); if ($popup === true) { @@ -1644,319 +1660,6 @@ function prepare_page($item) { )); } - -function network_tabs() { - - $no_active=''; - $starred_active = ''; - $new_active = ''; - $all_active = ''; - $search_active = ''; - $conv_active = ''; - $spam_active = ''; - $postord_active = ''; - - if(x($_GET,'new')) { - $new_active = 'active'; - } - - if(x($_GET,'search')) { - $search_active = 'active'; - } - - if(x($_GET,'star')) { - $starred_active = 'active'; - } - - if(x($_GET,'conv')) { - $conv_active = 'active'; - } - - if(x($_GET,'spam')) { - $spam_active = 'active'; - } - - if (($new_active == '') - && ($starred_active == '') - && ($conv_active == '') - && ($search_active == '') - && ($spam_active == '')) { - $no_active = 'active'; - } - - if ($no_active=='active' && x($_GET,'order')) { - switch($_GET['order']){ - case 'post': $postord_active = 'active'; $no_active=''; break; - case 'comment' : $all_active = 'active'; $no_active=''; break; - } - } - - if ($no_active=='active') $all_active='active'; - - $cmd = App::$cmd; - - // tabs - $tabs = array(); - - $tabs[] = array( - 'label' => t('Commented Order'), - 'url'=>z_root() . '/' . $cmd . '?f=&order=comment' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''), - 'sel'=>$all_active, - 'title'=> t('Sort by Comment Date'), - ); - - $tabs[] = array( - 'label' => t('Posted Order'), - 'url'=>z_root() . '/' . $cmd . '?f=&order=post' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''), - 'sel'=>$postord_active, - 'title' => t('Sort by Post Date'), - ); - - if(feature_enabled(local_channel(),'personal_tab')) { - $tabs[] = array( - 'label' => t('Personal'), - 'url' => z_root() . '/' . $cmd . '?f=' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . '&conv=1', - 'sel' => $conv_active, - 'title' => t('Posts that mention or involve you'), - ); - } - - if(feature_enabled(local_channel(),'new_tab')) { - $tabs[] = array( - 'label' => t('New'), - 'url' => z_root() . '/' . $cmd . '?f=' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . '&new=1' . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''), - 'sel' => $new_active, - 'title' => t('Activity Stream - by date'), - ); - } - - if(feature_enabled(local_channel(),'star_posts')) { - $tabs[] = array( - 'label' => t('Starred'), - 'url'=>z_root() . '/' . $cmd . '/?f=' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . '&star=1', - 'sel'=>$starred_active, - 'title' => t('Favourite Posts'), - ); - } - // Not yet implemented - - if(feature_enabled(local_channel(),'spam_filter')) { - $tabs[] = array( - 'label' => t('Spam'), - 'url'=> z_root() . '/network?f=&spam=1', - 'sel'=> $spam_active, - 'title' => t('Posts flagged as SPAM'), - ); - } - - $arr = array('tabs' => $tabs); - call_hooks('network_tabs', $arr); - - $tpl = get_markup_template('common_tabs.tpl'); - - return replace_macros($tpl, array('$tabs' => $arr['tabs'])); -} - -/** - * @brief - * - * @param App $a - * @param boolean $is_owner default false - * @param string $nickname default null - * @return void|string - */ -function profile_tabs($a, $is_owner = false, $nickname = null){ - - // Don't provide any profile tabs if we're running as the sys channel - - if (App::$is_sys) - return; - - if (get_pconfig($uid, 'system', 'noprofiletabs')) - return; - - $channel = App::get_channel(); - - if (is_null($nickname)) - $nickname = $channel['channel_address']; - - - $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()) - return; - - if($uid == local_channel()) { - $cal_link = ''; - } - else { - $cal_link = '/cal/' . $nickname; - } - - require_once('include/security.php'); - $sql_options = item_permissions_sql($uid); - - $r = q("select item.* from item left join iconfig on item.id = iconfig.iid - where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' - and item.item_delayed = 0 and item.item_deleted = 0 - and ( iconfig.k = 'WEBPAGE' and item_type = %d ) - $sql_options limit 1", - intval($uid), - dbesc('home'), - intval(ITEM_TYPE_WEBPAGE) - ); - - $has_webpages = (($r) ? true : false); - - if (x($_GET, 'tab')) - $tab = notags(trim($_GET['tab'])); - - $url = z_root() . '/channel/' . $nickname; - $pr = z_root() . '/profile/' . $nickname; - - $tabs = array( - array( - 'label' => t('Channel'), - 'url' => $url, - 'sel' => ((argv(0) == 'channel') ? 'active' : ''), - 'title' => t('Status Messages and Posts'), - 'id' => 'status-tab', - 'icon' => 'home' - ), - ); - - $p = get_all_perms($uid,get_observer_hash()); - - if ($p['view_profile']) { - $tabs[] = array( - 'label' => t('About'), - 'url' => $pr, - 'sel' => ((argv(0) == 'profile') ? 'active' : ''), - 'title' => t('Profile Details'), - 'id' => 'profile-tab', - 'icon' => 'user' - ); - } - if ($p['view_storage']) { - $tabs[] = array( - 'label' => t('Photos'), - 'url' => z_root() . '/photos/' . $nickname, - 'sel' => ((argv(0) == 'photos') ? 'active' : ''), - 'title' => t('Photo Albums'), - 'id' => 'photo-tab', - 'icon' => 'photo' - ); - $tabs[] = array( - 'label' => t('Files'), - 'url' => z_root() . '/cloud/' . $nickname, - 'sel' => ((argv(0) == 'cloud' || argv(0) == 'sharedwithme') ? 'active' : ''), - 'title' => t('Files and Storage'), - 'id' => 'files-tab', - 'icon' => 'folder-open' - ); - } - - if($p['view_stream'] && $cal_link) { - $tabs[] = array( - 'label' => t('Events'), - 'url' => z_root() . $cal_link, - 'sel' => ((argv(0) == 'cal' || argv(0) == 'events') ? 'active' : ''), - 'title' => t('Events'), - 'id' => 'event-tab', - 'icon' => 'calendar' - ); - } - - - if ($p['chat'] && feature_enabled($uid,'ajaxchat')) { - $has_chats = Zotlabs\Lib\Chatroom::list_count($uid); - if ($has_chats) { - $tabs[] = array( - 'label' => t('Chatrooms'), - 'url' => z_root() . '/chat/' . $nickname, - 'sel' => ((argv(0) == 'chat') ? 'active' : '' ), - 'title' => t('Chatrooms'), - 'id' => 'chat-tab', - 'icon' => 'comments-o' - ); - } - } - - require_once('include/menu.php'); - $has_bookmarks = menu_list_count(local_channel(),'',MENU_BOOKMARK) + menu_list_count(local_channel(),'',MENU_SYSTEM|MENU_BOOKMARK); - - if($is_owner && $has_bookmarks) { - $tabs[] = array( - 'label' => t('Bookmarks'), - 'url' => z_root() . '/bookmarks', - 'sel' => ((argv(0) == 'bookmarks') ? 'active' : ''), - 'title' => t('Saved Bookmarks'), - 'id' => 'bookmarks-tab', - 'icon' => 'bookmark' - ); - } - - if(feature_enabled($uid,'cards')) { - $tabs[] = array( - 'label' => t('Cards'), - 'url' => z_root() . '/cards/' . $nickname, - 'sel' => ((argv(0) == 'cards') ? 'active' : ''), - 'title' => t('View Cards'), - 'id' => 'cards-tab', - 'icon' => 'list' - ); - } - - if(feature_enabled($uid,'articles')) { - $tabs[] = array( - 'label' => t('articles'), - 'url' => z_root() . '/articles/' . $nickname, - 'sel' => ((argv(0) == 'articles') ? 'active' : ''), - 'title' => t('View Articles'), - 'id' => 'articles-tab', - 'icon' => 'file-text-o' - ); - } - - if($has_webpages && feature_enabled($uid,'webpages')) { - $tabs[] = array( - 'label' => t('Webpages'), - 'url' => z_root() . '/page/' . $nickname . '/home', - 'sel' => ((argv(0) == 'webpages') ? 'active' : ''), - 'title' => t('View Webpages'), - 'id' => 'webpages-tab', - 'icon' => 'newspaper-o' - ); - } - - - if ($p['view_wiki']) { - if(feature_enabled($uid,'wiki') && (get_account_techlevel($account_id) > 3)) { - $tabs[] = array( - 'label' => t('Wikis'), - 'url' => z_root() . '/wiki/' . $nickname, - 'sel' => ((argv(0) == 'wiki') ? 'active' : ''), - 'title' => t('Wiki'), - 'id' => 'wiki-tab', - 'icon' => 'pencil-square-o' - ); - } - } - - $arr = array('is_owner' => $is_owner, 'nickname' => $nickname, 'tab' => (($tab) ? $tab : false), 'tabs' => $tabs); - call_hooks('profile_tabs', $arr); - - $tpl = get_markup_template('profile_tabs.tpl'); - - return replace_macros($tpl, array( - '$tabs' => $arr['tabs'], - '$name' => App::$profile['channel_name'], - '$thumb' => App::$profile['thumb'] - )); -} - - function get_responses($conv_responses,$response_verbs,$ob,$item) { $ret = array(); diff --git a/include/features.php b/include/features.php index 03f50c9a4..05ce3db32 100644 --- a/include/features.php +++ b/include/features.php @@ -44,265 +44,174 @@ function feature_level($feature,$def) { return $def; } +function process_module_features_get($uid, $features) { + unset($features[0]); + foreach($features as $f) { + $arr[] = [ + 'feature_' . $f[0], + $f[1], + ((intval(feature_enabled($uid, $f[0]))) ? "1" : ''), + $f[2], + [t('Off'),t('On')], + (($f[4] === false) ? '' : 'disabled'), + $f[5] + ]; + } + return $arr; +} + +function process_module_features_post($uid, $features, $post_arr) { + unset($features[0]); + foreach($features as $f) { + $k = $f[0]; + if(array_key_exists("feature_$k",$post_arr)) + set_pconfig($uid,'feature',$k, (string) $post_arr["feature_$k"]); + else + set_pconfig($uid,'feature', $k, ''); + } +} + function get_features($filtered = true, $level = (-1)) { $account = \App::get_account(); $arr = [ - // General - 'general' => [ + 'calendar' => [ - t('General Features'), + t('CalDAV'), [ - 'start_menu', - t('New Member Links'), - t('Display new member quick links menu'), - (($account['account_created'] > datetime_convert('','','now - 60 days')) ? true : false), - get_config('feature_lock','start_menu'), - feature_level('start_menu',1), - ], - - [ - 'advanced_profiles', - t('Advanced Profiles'), - t('Additional profile sections and selections'), + 'cal_first_day', + t('Start calendar week on Monday'), + t('Default is Sunday'), false, - get_config('feature_lock','advanced_profiles'), - feature_level('advanced_profiles',1), - ], + get_config('feature_lock','cal_first_day') + ] - [ - 'profile_export', - t('Profile Import/Export'), - t('Save and load profile details across sites/channels'), - false, - get_config('feature_lock','profile_export'), - feature_level('profile_export',3), - ], + ], - [ - 'webpages', - t('Web Pages'), - t('Provide managed web pages on your channel'), - false, - get_config('feature_lock','webpages'), - feature_level('webpages',3), - ], + 'channel_home' => [ + + t('Channel Home'), [ - 'wiki', - t('Wiki'), - t('Provide a wiki for your channel'), - false, - get_config('feature_lock','wiki'), - feature_level('wiki',2), - ], -/* - [ - 'hide_rating', - t('Hide Rating'), - t('Hide the rating buttons on your channel and profile pages. Note: People can still rate you somewhere else.'), + 'archives', + t('Search by Date'), + t('Ability to select posts by date ranges'), false, - get_config('feature_lock','hide_rating'), - feature_level('hide_rating',3), + get_config('feature_lock','archives') ], -*/ + [ - 'private_notes', - t('Private Notes'), - t('Enables a tool to store notes and reminders (note: not encrypted)'), + 'tagadelic', + t('Tag Cloud'), + t('Provide a personal tag cloud on your channel page'), false, - get_config('feature_lock','private_notes'), - feature_level('private_notes',1), + get_config('feature_lock','tagadelic'), ], [ - 'cards', - t('Cards'), - t('Create personal planning cards'), + 'channel_list_mode', + t('Use blog/list mode'), + t('Comments will be displayed separately'), false, - get_config('feature_lock','cards'), - feature_level('cards',1), - ], + get_config('feature_lock','channel_list_mode'), + ] + ], + 'connections' => [ - [ - 'articles', - t('Articles'), - t('Create interactive articles'), - false, - get_config('feature_lock','articles'), - feature_level('articles',1), - ], + t('Connections'), [ - 'nav_channel_select', - t('Navigation Channel Select'), - t('Change channels directly from within the navigation dropdown menu'), + 'connfilter', + t('Connection Filtering'), + t('Filter incoming posts from connections based on keywords/content'), false, - get_config('feature_lock','nav_channel_select'), - feature_level('nav_channel_select',3), - ], + get_config('feature_lock','connfilter') + ] + ], - [ - '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'), - feature_level('photo_location',2), - ], + 'conversation' => [ + + t('Conversation'), [ - 'ajaxchat', - t('Access Controlled Chatrooms'), - t('Provide chatrooms and chat services with access control.'), - true, - get_config('feature_lock','ajaxchat'), - feature_level('ajaxchat',1), + 'commtag', + t('Community Tagging'), + t('Ability to tag existing posts'), + false, + get_config('feature_lock','commtag'), ], - [ - 'smart_birthdays', - t('Smart Birthdays'), - t('Make birthday events timezone aware in case your friends are scattered across the planet.'), + 'emojis', + t('Emoji Reactions'), + t('Add emoji reaction ability to posts'), true, - get_config('feature_lock','smart_birthdays'), - feature_level('smart_birthdays',2), + get_config('feature_lock','emojis'), ], [ - 'event_tz_select', - t('Event Timezone Selection'), - t('Allow event creation in timezones other than your own.'), + 'dislike', + t('Dislike Posts'), + t('Ability to dislike posts/comments'), false, - get_config('feature_lock','event_tz_select'), - feature_level('event_tz_select',2), + get_config('feature_lock','dislike'), ], - [ - 'premium_channel', - t('Premium Channel'), - t('Allows you to set restrictions and terms on those that connect with your channel'), + 'star_posts', + t('Star Posts'), + t('Ability to mark special posts with a star indicator'), false, - get_config('feature_lock','premium_channel'), - feature_level('premium_channel',4), - ], - - [ - 'advanced_dirsearch', - t('Advanced Directory Search'), - t('Allows creation of complex directory search queries'), - false, - get_config('feature_lock','advanced_dirsearch'), - feature_level('advanced_dirsearch',4), - ], + get_config('feature_lock','star_posts'), + ] - [ - 'advanced_theming', - t('Advanced Theme and Layout Settings'), - t('Allows fine tuning of themes and page layouts'), - false, - get_config('feature_lock','advanced_theming'), - feature_level('advanced_theming',4), - ], ], + 'directory' => [ - 'access_control' => [ - t('Access Control and Permissions'), + t('Directory'), [ - 'groups', - t('Privacy Groups'), - t('Enable management and selection of privacy groups'), - true, - get_config('feature_lock','groups'), - feature_level('groups',0), - ], - - [ - 'multi_profiles', - t('Multiple Profiles'), - t('Ability to create multiple profiles'), - false, - get_config('feature_lock','multi_profiles'), - feature_level('multi_profiles',3), - ], - - - [ - 'permcats', - t('Permission Categories'), - t('Create custom connection permission limits'), + 'advanced_dirsearch', + t('Advanced Directory Search'), + t('Allows creation of complex directory search queries'), false, - get_config('feature_lock','permcats'), - feature_level('permcats',2), - ], + get_config('feature_lock','advanced_dirsearch'), + ] - [ - 'oauth_clients', - t('OAuth1 Clients'), - t('Manage OAuth1 authenticatication tokens for mobile and remote apps.'), - false, - get_config('feature_lock','oauth_clients'), - feature_level('oauth_clients',1), - ], + ], - [ - 'oauth2_clients', - t('OAuth2 Clients'), - t('Manage OAuth2 authenticatication tokens for mobile and remote apps.'), - false, - get_config('feature_lock','oauth2_clients'), - feature_level('oauth2_clients',1), - ], + 'editor' => [ + + t('Editor'), [ - 'access_tokens', - t('Access Tokens'), - t('Create access tokens so that non-members can access private content.'), + 'categories', + t('Post Categories'), + t('Add categories to your posts'), false, - get_config('feature_lock','access_tokens'), - feature_level('access_tokens',2), + get_config('feature_lock','categories'), + feature_level('categories',1), ], - ], - - // Post composition - 'composition' => [ - - t('Post Composition Features'), - [ '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'), - feature_level('large_photos',1), ], [ - 'channel_sources', - t('Channel Sources'), - t('Automatically import channel content from other channels or feeds'), - false, - get_config('feature_lock','channel_sources'), - feature_level('channel_sources',3), - ], - - [ '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'), - feature_level('content_encrypt',3), ], [ @@ -311,7 +220,6 @@ function get_features($filtered = true, $level = (-1)) { t('Provide a class of post which others can vote on'), false, get_config('feature_lock','consensus_tools'), - feature_level('consensus_tools',3), ], [ @@ -320,7 +228,6 @@ function get_features($filtered = true, $level = (-1)) { t('Provide the option to disable comments for a post'), false, get_config('feature_lock','disable_comments'), - feature_level('disable_comments',2), ], [ @@ -329,7 +236,6 @@ function get_features($filtered = true, $level = (-1)) { t('Allow posts to be published at a later date'), false, get_config('feature_lock','delayed_posting'), - feature_level('delayed_posting',2), ], [ @@ -338,7 +244,6 @@ function get_features($filtered = true, $level = (-1)) { t('Remove posts/comments and/or private messages at a future time'), false, get_config('feature_lock','content_expire'), - feature_level('content_expire',1), ], [ @@ -347,7 +252,6 @@ function get_features($filtered = true, $level = (-1)) { t('Prevent posts with identical content to be published with less than two minutes in between submissions.'), true, get_config('feature_lock','suppress_duplicates'), - feature_level('suppress_duplicates',1), ], [ @@ -356,33 +260,72 @@ function get_features($filtered = true, $level = (-1)) { t('Automatically saves post and comment drafts in local browser storage to help prevent accidental loss of compositions'), true, get_config('feature_lock','auto_save_draft'), - feature_level('auto_save_draft',1), - ], + ] ], - // Network Tools - 'net_module' => [ + 'events' => [ - t('Network and Stream Filtering'), + t('Events'), [ - 'archives', - t('Search by Date'), - t('Ability to select posts by date ranges'), + 'events_cal_first_day', + t('Start calendar week on Monday'), + t('Default is Sunday'), false, - get_config('feature_lock','archives'), - feature_level('archives',1), + get_config('feature_lock','events_cal_first_day') ], + [ + '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'), + ], + + [ + 'event_tz_select', + t('Event Timezone Selection'), + t('Allow event creation in timezones other than your own.'), + false, + get_config('feature_lock','event_tz_select'), + ] + + ], + + 'manage' => [ + + t('Manage'), + + [ + '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'), + ] + + ], + + 'network' => [ + + t('Network'), [ 'savedsearch', t('Saved Searches'), t('Save search terms for re-use'), false, - get_config('feature_lock','savedsearch'), - feature_level('savedsearch',2), + get_config('feature_lock','savedsearch') + ], + + [ + 'filing', + t('Saved Folders'), + t('Ability to file posts under folders'), + false, + get_config('feature_lock','filing'), ], [ @@ -390,8 +333,7 @@ function get_features($filtered = true, $level = (-1)) { t('Alternate Stream Order'), t('Ability to order the stream by last post date, last comment date or unthreaded activities'), false, - get_config('feature_lock','order_tab'), - feature_level('order_tab',2), + get_config('feature_lock','order_tab') ], [ @@ -399,8 +341,7 @@ function get_features($filtered = true, $level = (-1)) { t('Contact Filter'), t('Ability to display only posts of a selected contact'), false, - get_config('feature_lock','name_tab'), - feature_level('name_tab',1), + get_config('feature_lock','name_tab') ], [ @@ -408,8 +349,7 @@ function get_features($filtered = true, $level = (-1)) { t('Forum Filter'), t('Ability to display only posts of a specific forum'), false, - get_config('feature_lock','forums_tab'), - feature_level('forums_tab',1), + get_config('feature_lock','forums_tab') ], [ @@ -417,8 +357,7 @@ function get_features($filtered = true, $level = (-1)) { t('Personal Posts Filter'), t('Ability to display only posts that you\'ve interacted on'), false, - get_config('feature_lock','personal_tab'), - feature_level('personal_tab',1), + get_config('feature_lock','personal_tab') ], [ @@ -426,8 +365,7 @@ function get_features($filtered = true, $level = (-1)) { t('Affinity Tool'), t('Filter stream activity by depth of relationships'), false, - get_config('feature_lock','affinity'), - feature_level('affinity',1), + get_config('feature_lock','affinity') ], [ @@ -435,90 +373,64 @@ function get_features($filtered = true, $level = (-1)) { t('Suggest Channels'), t('Show friend and connection suggestions'), false, - get_config('feature_lock','suggest'), - feature_level('suggest',1), + get_config('feature_lock','suggest') ], [ - 'connfilter', - t('Connection Filtering'), - t('Filter incoming posts from connections based on keywords/content'), + 'network_list_mode', + t('Use blog/list mode'), + t('Comments will be displayed separately'), false, - get_config('feature_lock','connfilter'), - feature_level('connfilter',3), - ], - + get_config('feature_lock','network_list_mode'), + ] ], - // Item tools - 'tools' => [ + 'photos' => [ - t('Post/Comment Tools'), + t('Photos'), [ - 'commtag', - t('Community Tagging'), - t('Ability to tag existing posts'), + 'photo_location', + t('Photo Location'), + t('If location data is available on uploaded photos, link this to a map.'), false, - get_config('feature_lock','commtag'), - feature_level('commtag',1), - ], + get_config('feature_lock','photo_location'), + ] - [ - 'categories', - t('Post Categories'), - t('Add categories to your posts'), - false, - get_config('feature_lock','categories'), - feature_level('categories',1), - ], + ], - [ - 'emojis', - t('Emoji Reactions'), - t('Add emoji reaction ability to posts'), - true, - get_config('feature_lock','emojis'), - feature_level('emojis',1), - ], + 'profiles' => [ - [ - 'filing', - t('Saved Folders'), - t('Ability to file posts under folders'), - false, - get_config('feature_lock','filing'), - feature_level('filing',2), - ], + t('Profiles'), [ - 'dislike', - t('Dislike Posts'), - t('Ability to dislike posts/comments'), + 'advanced_profiles', + t('Advanced Profiles'), + t('Additional profile sections and selections'), false, - get_config('feature_lock','dislike'), - feature_level('dislike',1), + get_config('feature_lock','advanced_profiles') ], [ - 'star_posts', - t('Star Posts'), - t('Ability to mark special posts with a star indicator'), + 'profile_export', + t('Profile Import/Export'), + t('Save and load profile details across sites/channels'), false, - get_config('feature_lock','star_posts'), - feature_level('star_posts',1), + get_config('feature_lock','profile_export') ], [ - 'tagadelic', - t('Tag Cloud'), - t('Provide a personal tag cloud on your channel page'), - false, - get_config('feature_lock','tagadelic'), - feature_level('tagadelic',2), - ], - ], + 'multi_profiles', + t('Multiple Profiles'), + t('Ability to create multiple profiles'), + false, + get_config('feature_lock','multi_profiles') + ] + + ] + + ]; $x = [ 'features' => $arr, ]; @@ -526,8 +438,6 @@ function get_features($filtered = true, $level = (-1)) { $arr = $x['features']; - $techlevel = (($level >= 0) ? $level : get_account_techlevel()); - // removed any locked features and remove the entire category if this makes it empty if($filtered) { @@ -538,9 +448,6 @@ function get_features($filtered = true, $level = (-1)) { for($y = 0; $y < count($arr[$k]); $y ++) { $disabled = false; if(is_array($arr[$k][$y])) { - if($arr[$k][$y][5] > $techlevel) { - $disabled = true; - } if($arr[$k][$y][4] !== false) { $disabled = true; } @@ -561,3 +468,8 @@ function get_features($filtered = true, $level = (-1)) { return $narr; } + +function get_module_features($module) { + $features = get_features(false); + return $features[$module]; +} diff --git a/include/group.php b/include/group.php index 56bf210ff..6011af08f 100644 --- a/include/group.php +++ b/include/group.php @@ -14,11 +14,11 @@ function group_add($uid,$name,$public = 0) { // access lists. What we're doing here is reviving the dead group, but old content which // was restricted to this group may now be seen by the new group members. - $z = q("SELECT * FROM groups WHERE id = %d LIMIT 1", + $z = q("SELECT * FROM pgrp WHERE id = %d LIMIT 1", intval($r) ); if(($z) && $z[0]['deleted']) { - q('UPDATE groups SET deleted = 0 WHERE id = %d', intval($z[0]['id'])); + q('UPDATE pgrp SET deleted = 0 WHERE id = %d', intval($z[0]['id'])); notice( t('A deleted group with this name was revived. Existing item permissions <strong>may</strong> apply to this group and any future members. If this is not what you intended, please create another group with a different name.') . EOL); } return true; @@ -28,13 +28,13 @@ function group_add($uid,$name,$public = 0) { $dups = false; $hash = random_string() . $name; - $r = q("SELECT id FROM groups WHERE hash = '%s' LIMIT 1", dbesc($hash)); + $r = q("SELECT id FROM pgrp WHERE hash = '%s' LIMIT 1", dbesc($hash)); if($r) $dups = true; } while($dups == true); - $r = q("INSERT INTO groups ( hash, uid, visible, gname ) + $r = q("INSERT INTO pgrp ( hash, uid, visible, gname ) VALUES( '%s', %d, %d, '%s' ) ", dbesc($hash), intval($uid), @@ -53,7 +53,7 @@ function group_add($uid,$name,$public = 0) { function group_rmv($uid,$name) { $ret = false; if(x($uid) && x($name)) { - $r = q("SELECT id, hash FROM groups WHERE uid = %d AND gname = '%s' LIMIT 1", + $r = q("SELECT id, hash FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1", intval($uid), dbesc($name) ); @@ -98,13 +98,13 @@ function group_rmv($uid,$name) { } // remove all members - $r = q("DELETE FROM group_member WHERE uid = %d AND gid = %d ", + $r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d ", intval($uid), intval($group_id) ); // remove group - $r = q("UPDATE groups SET deleted = 1 WHERE uid = %d AND gname = '%s'", + $r = q("UPDATE pgrp SET deleted = 1 WHERE uid = %d AND gname = '%s'", intval($uid), dbesc($name) ); @@ -121,7 +121,7 @@ function group_rmv($uid,$name) { function group_byname($uid,$name) { if((! $uid) || (! strlen($name))) return false; - $r = q("SELECT * FROM groups WHERE uid = %d AND gname = '%s' LIMIT 1", + $r = q("SELECT * FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1", intval($uid), dbesc($name) ); @@ -134,7 +134,7 @@ function group_byname($uid,$name) { function group_rec_byhash($uid,$hash) { if((! $uid) || (! strlen($hash))) return false; - $r = q("SELECT * FROM groups WHERE uid = %d AND hash = '%s' LIMIT 1", + $r = q("SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1", intval($uid), dbesc($hash) ); @@ -149,7 +149,7 @@ function group_rmv_member($uid,$name,$member) { return false; if(! ( $uid && $gid && $member)) return false; - $r = q("DELETE FROM group_member WHERE uid = %d AND gid = %d AND xchan = '%s' ", + $r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' ", intval($uid), intval($gid), dbesc($member) @@ -169,7 +169,7 @@ function group_add_member($uid,$name,$member,$gid = 0) { if((! $gid) || (! $uid) || (! $member)) return false; - $r = q("SELECT * FROM group_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1", + $r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1", intval($uid), intval($gid), dbesc($member) @@ -179,7 +179,7 @@ function group_add_member($uid,$name,$member,$gid = 0) { // we indicate success because the group member was in fact created // -- It was just created at another time if(! $r) - $r = q("INSERT INTO group_member (uid, gid, xchan) + $r = q("INSERT INTO pgrp_member (uid, gid, xchan) VALUES( %d, %d, '%s' ) ", intval($uid), intval($gid), @@ -194,9 +194,9 @@ function group_add_member($uid,$name,$member,$gid = 0) { function group_get_members($gid) { $ret = array(); if(intval($gid)) { - $r = q("SELECT * FROM group_member - LEFT JOIN abook ON abook_xchan = group_member.xchan left join xchan on xchan_hash = abook_xchan - WHERE gid = %d AND abook_channel = %d and group_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ", + $r = q("SELECT * FROM pgrp_member + LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan + WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ", intval($gid), intval(local_channel()), intval(local_channel()) @@ -210,7 +210,7 @@ function group_get_members($gid) { function group_get_members_xchan($gid) { $ret = array(); if(intval($gid)) { - $r = q("SELECT xchan FROM group_member WHERE gid = %d AND uid = %d", + $r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d", intval($gid), intval(local_channel()) ); @@ -248,7 +248,7 @@ function mini_group_select($uid,$group = '') { $grps = array(); $o = ''; - $r = q("SELECT * FROM groups WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", + $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", intval($uid) ); $grps[] = array('name' => '', 'hash' => '0', 'selected' => ''); @@ -274,13 +274,13 @@ function group_side($every="connections",$each="group",$edit = false, $group_id $o = ''; - if(! (local_channel() && feature_enabled(local_channel(),'groups'))) { + if(! (local_channel() && \Zotlabs\Lib\Apps::system_app_installed(local_channel(), 'Privacy Groups'))) { return ''; } $groups = array(); - $r = q("SELECT * FROM groups WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", + $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", intval($_SESSION['uid']) ); $member_of = array(); @@ -361,7 +361,7 @@ function expand_groups($g) { stringify_array_elms($x,true); $groups = implode(',', $x); if($groups) { - $r = q("SELECT xchan FROM group_member WHERE gid IN ( select id from groups where hash in ( $groups ))"); + $r = q("SELECT xchan FROM pgrp_member WHERE gid IN ( select id from pgrp where hash in ( $groups ))"); if($r) { foreach($r as $rr) { $ret[] = $rr['xchan']; @@ -375,7 +375,7 @@ function expand_groups($g) { function member_of($c) { - $r = q("SELECT groups.gname, groups.id FROM groups LEFT JOIN group_member ON group_member.gid = groups.id WHERE group_member.xchan = '%s' AND groups.deleted = 0 ORDER BY groups.gname ASC ", + $r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id WHERE pgrp_member.xchan = '%s' AND pgrp.deleted = 0 ORDER BY pgrp.gname ASC ", dbesc($c) ); @@ -385,7 +385,7 @@ function member_of($c) { function groups_containing($uid,$c) { - $r = q("SELECT gid FROM group_member WHERE uid = %d AND group_member.xchan = '%s' ", + $r = q("SELECT gid FROM pgrp_member WHERE uid = %d AND pgrp_member.xchan = '%s' ", intval($uid), dbesc($c) ); diff --git a/include/help.php b/include/help.php index ce389b4db..3b56a7238 100644 --- a/include/help.php +++ b/include/help.php @@ -2,6 +2,50 @@ use \Michelf\MarkdownExtra; + +/** + * @brief + * + * @param string $path + * @return string|unknown + */ +function get_help_fullpath($path,$suffix=null) { + + $docroot = (\App::$override_helproot) ? \App::$override_helproot : 'doc/'; + $docroot = (substr($docroot,-1)!='/') ? $docroot .= '/' : $docroot; + + // Determine the language and modify the path accordingly + $x = determine_help_language(); + $lang = $x['language']; + $url_idx = ($x['from_url'] ? 1 : 0); + // The English translation is at the root of /doc/. Other languages are in + // subfolders named by the language code such as "de", "es", etc. + if($lang !== 'en') { + $langpath = $lang . '/' . $path; + } else { + $langpath = $path; + } + + $newpath = (isset(\App::$override_helpfiles[$langpath])) ? \App::$override_helpfiles[$langpath] : $langpath; + $newpath = ($newpath == $langpath) ? $docroot . $newpath : $newpath; + + if ($suffix) { + if (file_exists($newpath . $suffix)) { + return $newpath; + } + } elseif (file_exists($newpath . '.md') || + file_exists($newpath . '.bb') || + file_exists($newpath . '.html')) { + return $newpath; + } + + $newpath = (isset(\App::$override_helpfiles[$path])) ? \App::$override_helpfiles[$path] : null; + + $newpath = (!$newpath) ? $docroot.$path : $newpath; + return $newpath; +} + + /** * @brief * @@ -9,7 +53,6 @@ use \Michelf\MarkdownExtra; * @return string|unknown */ function get_help_content($tocpath = false) { - global $lang; $doctype = 'markdown'; @@ -17,6 +60,8 @@ function get_help_content($tocpath = false) { $text = ''; $path = (($tocpath !== false) ? $tocpath : ''); + $docroot = (\App::$override_helproot) ? \App::$override_helproot : 'doc/'; + $docroot = (substr($docroot,-1)!='/') ? $docroot .= '/' : $docroot; if($tocpath === false && argc() > 1) { $path = ''; @@ -27,8 +72,9 @@ function get_help_content($tocpath = false) { } } - if($path) { + if($path) { + $fullpath = get_help_fullpath($path); $title = basename($path); if(! $tocpath) \App::$page['title'] = t('Help:') . ' ' . ucwords(str_replace('-',' ',notags($title))); @@ -39,21 +85,22 @@ function get_help_content($tocpath = false) { // TODO: This is incompatible with the hierarchical TOC construction // defined in /Zotlabs/Widget/Helpindex.php. if($tocpath !== false && - load_doc_file('doc/' . $path . '.md') === '' && - load_doc_file('doc/' . $path . '.bb') === '' && - load_doc_file('doc/' . $path . '.html') === '' + load_doc_file($fullpath . '.md') === '' && + load_doc_file($fullpath . '.bb') === '' && + load_doc_file($fullpath . '.html') === '' ) { $path = $title; } - $text = load_doc_file('doc/' . $path . '.md'); + $fullpath = get_help_fullpath($path); + $text = load_doc_file($fullpath . '.md'); if(! $text) { - $text = load_doc_file('doc/' . $path . '.bb'); + $text = load_doc_file($fullpath . '.bb'); if($text) $doctype = 'bbcode'; } if(! $text) { - $text = load_doc_file('doc/' . $path . '.html'); + $text = load_doc_file($fullpath . '.html'); if($text) $doctype = 'html'; } @@ -64,12 +111,16 @@ function get_help_content($tocpath = false) { if($tocpath === false) { if(! $text) { - $text = load_doc_file('doc/Site.md'); + $path = 'Site'; + $fullpath = get_help_fullpath($path,'.md'); + $text = load_doc_file($fullpath . '.md'); \App::$page['title'] = t('Help'); } if(! $text) { $doctype = 'bbcode'; - $text = load_doc_file('doc/main.bb'); + $path = 'main'; + $fullpath = get_help_fullpath($path,'.md'); + $text = load_doc_file($fullpath . '.bb'); goaway('/help/about/about'); \App::$page['title'] = t('Help'); } @@ -146,35 +197,7 @@ function determine_help_language() { } function load_doc_file($s) { - $path = 'doc'; - // Determine the language and modify the path accordingly - $x = determine_help_language(); - $lang = $x['language']; - $url_idx = ($x['from_url'] ? 1 : 0); - // The English translation is at the root of /doc/. Other languages are in - // subfolders named by the language code such as "de", "es", etc. - if($lang !== 'en') { - $path .= '/' . $lang; - } - $b = basename($s); - - for($i=1+$url_idx; $i<argc()-1; $i++) { - $path .= '/' . argv($i); - } - $c = find_doc_file($path . '/' . $b); - if($c) - return $c; - // Possibly a translation was requested that has not been translated, so fall - // back to the English version - $path = 'doc'; - for($i=1+$url_idx; $i<argc()-1; $i++) { - $path .= '/' . argv($i); - } - $c = find_doc_file($path . '/' . $b); - if($c) - return $c; - // Try one last time to find the file at the explicit path input to the function $c = find_doc_file($s); if($c) return $c; diff --git a/include/hubloc.php b/include/hubloc.php index 33d5dcbb2..d1170a62c 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -24,6 +24,8 @@ function hubloc_store_lowlevel($arr) { 'hubloc_status' => ((array_key_exists('hubloc_status',$arr)) ? $arr['hubloc_status'] : 0), 'hubloc_url' => ((array_key_exists('hubloc_url',$arr)) ? $arr['hubloc_url'] : ''), 'hubloc_url_sig' => ((array_key_exists('hubloc_url_sig',$arr)) ? $arr['hubloc_url_sig'] : ''), + 'hubloc_id_url' => ((array_key_exists('hubloc_id_url',$arr)) ? $arr['hubloc_id_url'] : ''), + 'hubloc_site_id' => ((array_key_exists('hubloc_site_id',$arr)) ? $arr['hubloc_site_id'] : ''), 'hubloc_host' => ((array_key_exists('hubloc_host',$arr)) ? $arr['hubloc_host'] : ''), 'hubloc_callback' => ((array_key_exists('hubloc_callback',$arr)) ? $arr['hubloc_callback'] : ''), 'hubloc_connect' => ((array_key_exists('hubloc_connect',$arr)) ? $arr['hubloc_connect'] : ''), diff --git a/include/import.php b/include/import.php index 4953834c9..19e2bbcec 100644 --- a/include/import.php +++ b/include/import.php @@ -93,7 +93,8 @@ function import_channel($channel, $account_id, $seize, $newname = '') { 'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall', 'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish', 'channel_a_delegate', 'perm_limits', 'channel_password', 'channel_salt', - 'channel_moved' + 'channel_moved', 'channel_primary', 'channel_removed', 'channel_deleted', + 'channel_system' ]; $clean = array(); @@ -234,7 +235,7 @@ function import_hublocs($channel, $hublocs, $seize, $moving = false) { if(($x = zot_gethub($arr,false)) === false) { unset($hubloc['hubloc_id']); - create_table_from_array('hubloc', $hubloc); + hubloc_store_lowlevel($hubloc); } else { q("UPDATE hubloc set hubloc_primary = %d, hubloc_deleted = %d where hubloc_id = %d", diff --git a/include/items.php b/include/items.php index 9dd5d005b..58461cc3a 100755 --- a/include/items.php +++ b/include/items.php @@ -4,7 +4,13 @@ * @brief Items related functions. */ -use Zotlabs\Lib as Zlib; +use Zotlabs\Lib\Enotify; +use Zotlabs\Lib\MarkdownSoap; +use Zotlabs\Lib\MessageFilter; +use Zotlabs\Lib\IConfig; +use Zotlabs\Access\PermissionLimits; +use Zotlabs\Access\AccessList; +use Zotlabs\Daemon\Master; require_once('include/bbcode.php'); require_once('include/oembed.php'); @@ -234,10 +240,11 @@ function can_comment_on_post($observer_xchan, $item) { // logger('Comment_policy: ' . $item['comment_policy'], LOGGER_DEBUG); $x = [ - 'observer_hash' => $observer_xchan, - 'item' => $item, - 'allowed' => 'unset' + 'observer_hash' => $observer_xchan, + 'item' => $item, + 'allowed' => 'unset' ]; + /** * @hooks can_comment_on_post * Called when deciding whether or not to present a comment box for a post. @@ -245,26 +252,34 @@ function can_comment_on_post($observer_xchan, $item) { * * \e array \b item * * \e boolean \b allowed - return value */ + call_hooks('can_comment_on_post', $x); - if($x['allowed'] !== 'unset') + + if($x['allowed'] !== 'unset') { return $x['allowed']; + } - if(! $observer_xchan) + if(! $observer_xchan) { return false; + } - if($item['comment_policy'] === 'none') + if($item['comment_policy'] === 'none') { return false; + } - if(comments_are_now_closed($item)) + if(comments_are_now_closed($item)) { return false; + } - if($observer_xchan === $item['author_xchan'] || $observer_xchan === $item['owner_xchan']) + if($observer_xchan === $item['author_xchan'] || $observer_xchan === $item['owner_xchan']) { return true; + } switch($item['comment_policy']) { case 'self': - if($observer_xchan === $item['author_xchan'] || $observer_xchan === $item['owner_xchan']) + if($observer_xchan === $item['author_xchan'] || $observer_xchan === $item['owner_xchan']) { return true; + } break; case 'public': case 'authenticated': @@ -276,17 +291,22 @@ function can_comment_on_post($observer_xchan, $item) { case 'any connections': case 'contacts': case '': - if(array_key_exists('owner',$item) && get_abconfig($item['uid'],$item['owner']['abook_xchan'],'their_perms','post_comments')) { - return true; + if(local_channel() && get_abconfig(local_channel(),$item['owner_xchan'],'their_perms','post_comments')) { + return true; + } + if(intval($item['item_wall']) && perm_is_allowed($item['uid'],$observer_xchan,'post_comments')) { + return true; } break; default: break; } - if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'red')) + if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'red')) { return true; - if(strstr($item['comment_policy'],'site:') && strstr($item['comment_policy'],App::get_hostname())) + } + if(strstr($item['comment_policy'],'site:') && strstr($item['comment_policy'],App::get_hostname())) { return true; + } return false; } @@ -365,7 +385,7 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) { return $ret; } - $arr['public_policy'] = ((array_key_exists('public_policy',$arr)) ? escape_tags($arr['public_policy']) : map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_stream'),true)); + $arr['public_policy'] = ((array_key_exists('public_policy',$arr)) ? escape_tags($arr['public_policy']) : map_scope(PermissionLimits::Get($channel['channel_id'],'view_stream'),true)); if($arr['public_policy']) $arr['item_private'] = 1; @@ -393,7 +413,7 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) { $arr['deny_gid'] = $channel['channel_deny_gid']; } - $arr['comment_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'post_comments')); + $arr['comment_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments')); if ((! $arr['plink']) && (intval($arr['item_thread_top']))) { $arr['plink'] = substr(z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']),0,190); @@ -432,7 +452,7 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) { } if($post_id && $deliver) { - Zotlabs\Daemon\Master::Summon(array('Notifier','activity',$post_id)); + Master::Summon([ 'Notifier','activity',$post_id ]); } $ret['success'] = true; @@ -730,7 +750,7 @@ function get_item_elements($x,$allow_code = false) { // was generated on the escaped content. if($arr['mimetype'] === 'text/markdown') - $arr['body'] = \Zotlabs\Lib\MarkdownSoap::unescape($arr['body']); + $arr['body'] = MarkdownSoap::unescape($arr['body']); if(array_key_exists('revision',$x)) { @@ -989,7 +1009,7 @@ function encode_item($item,$mirror = false) { ); if($r) - $comment_scope = \Zotlabs\Access\PermissionLimits::Get($item['uid'],'post_comments'); + $comment_scope = PermissionLimits::Get($item['uid'],'post_comments'); else $comment_scope = 0; @@ -2425,7 +2445,7 @@ function send_status_notifications($post_id,$item) { return; - Zlib\Enotify::submit(array( + Enotify::submit(array( 'type' => NOTIFY_COMMENT, 'from_xchan' => $item['author_xchan'], 'to_xchan' => $r[0]['channel_hash'], @@ -2518,7 +2538,7 @@ function tag_deliver($uid, $item_id) { $verb = urldecode(substr($item['verb'],strpos($item['verb'],'#')+1)); if($poke_notify) { - Zlib\Enotify::submit(array( + Enotify::submit(array( 'to_xchan' => $u[0]['channel_hash'], 'from_xchan' => $item['author_xchan'], 'type' => NOTIFY_POKE, @@ -2672,7 +2692,7 @@ function tag_deliver($uid, $item_id) { * Kill two birds with one stone. As long as we're here, send a mention notification. */ - Zlib\Enotify::submit(array( + Enotify::submit(array( 'to_xchan' => $u[0]['channel_hash'], 'from_xchan' => $item['author_xchan'], 'type' => NOTIFY_TAGSELF, @@ -2974,7 +2994,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent) { $private = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0); - $new_public_policy = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_stream'),true); + $new_public_policy = map_scope(PermissionLimits::Get($channel['channel_id'],'view_stream'),true); if((! $private) && $new_public_policy) $private = 1; @@ -3017,7 +3037,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent) { dbesc($channel['channel_deny_gid']), intval($private), dbesc($new_public_policy), - dbesc(map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'post_comments'))), + dbesc(map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments'))), dbesc($title), dbesc($body), intval($item_wall), @@ -3026,7 +3046,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent) { ); if($r) - Zotlabs\Daemon\Master::Summon(array('Notifier','tgroup',$item_id)); + Master::Summon([ 'Notifier','tgroup',$item_id ]); else { logger('start_delivery_chain: failed to update item'); // reset the source xchan to prevent loops @@ -3091,7 +3111,7 @@ function check_item_source($uid, $item) { return true; } - if (\Zotlabs\Lib\MessageFilter::evaluate($item, $r[0]['src_patt'], EMPTY_STR)) { + if (MessageFilter::evaluate($item, $r[0]['src_patt'], EMPTY_STR)) { logger('source: text filter success'); return true; } @@ -3114,7 +3134,7 @@ function post_is_importable($item,$abook) { if(! ($abook['abook_incl'] || $abook['abook_excl'])) return true; - return \Zotlabs\Lib\MessageFilter::evaluate($item,$abook['abook_incl'],$abook['abook_excl']); + return MessageFilter::evaluate($item,$abook['abook_incl'],$abook['abook_excl']); } @@ -3250,7 +3270,7 @@ function mail_store($arr) { 'otype' => 'mail' ); - Zlib\Enotify::submit($notif_params); + Enotify::submit($notif_params); } if($arr['conv_guid']) { @@ -3533,8 +3553,9 @@ function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL,$force // multiple threads may have been deleted, send an expire notification - if($uid) - Zotlabs\Daemon\Master::Summon(array('Notifier','expire',$uid)); + if($uid) { + Master::Summon([ 'Notifier','expire',$uid ]); + } } @@ -3642,8 +3663,9 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal // We'll rely on the undocumented behaviour that DROPITEM_PHASE1 is (hopefully) only // set if we know we're going to send delete notifications out to others. - if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) - Zotlabs\Daemon\Master::Summon(array('Notifier','drop',$notify_id)); + if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) { + Master::Summon([ 'Notifier','drop',$notify_id ]); + } goaway(z_root() . '/' . $_SESSION['return_url']); } @@ -3767,21 +3789,34 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) { * @brief Return the first post date. * * @param int $uid - * @param boolean $wall (optional) default false + * @param boolean $wall (optional) no longer used * @return string|boolean date string, otherwise false */ function first_post_date($uid, $wall = false) { - $wall_sql = (($wall) ? " and item_wall = 1 " : "" ); - $item_normal = item_normal(); + $sql_extra = ''; + + switch(App::$module) { + case 'articles': + $sql_extra .= " and item_type = 7 "; + $item_normal = " and item.item_hidden = 0 and item.item_type = 7 and item.item_deleted = 0 + and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0 + and item.item_blocked = 0 "; + break; + case 'channel': + $sql_extra = " and item_wall = 1 "; + default: + $item_normal = item_normal(); + break; + } $r = q("select id, created from item - where uid = %d and id = parent $item_normal $wall_sql + where uid = %d and id = parent $item_normal $sql_extra order by created asc limit 1", intval($uid) ); + if($r) { -// logger('first_post_date: ' . $r[0]['id'] . ' ' . $r[0]['created'], LOGGER_DATA); return substr(datetime_convert('',date_default_timezone_get(),$r[0]['created']),0,10); } @@ -3962,6 +3997,7 @@ function zot_feed($uid, $observer_hash, $arr) { $result = array(); $mindate = null; $message_id = null; + $wall = true; require_once('include/security.php'); @@ -3973,6 +4009,10 @@ function zot_feed($uid, $observer_hash, $arr) { $message_id = $arr['message_id']; } + if(array_key_exists('wall',$arr)) { + $wall = intval($arr['wall']); + } + if(! $mindate) $mindate = NULL_DATE; @@ -4001,6 +4041,10 @@ function zot_feed($uid, $observer_hash, $arr) { $limit = ''; } + if($wall) { + $sql_extra .= " and item_wall = 1 "; + } + $items = []; @@ -4013,7 +4057,6 @@ function zot_feed($uid, $observer_hash, $arr) { $r = q("SELECT parent, postopts FROM item WHERE uid IN ( %s ) - AND item_wall = 1 AND item_private = 0 $item_normal $sql_extra ORDER BY created ASC $limit", @@ -4023,7 +4066,6 @@ function zot_feed($uid, $observer_hash, $arr) { else { $r = q("SELECT parent, postopts FROM item WHERE uid = %d - AND item_wall = 1 $item_normal $sql_extra ORDER BY created ASC $limit", intval($uid) @@ -4117,7 +4159,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $sql_extra .= protect_sprintf(term_query('item', $arr['cat'], TERM_CATEGORY)); if($arr['gid'] && $uid) { - $r = q("SELECT * FROM groups WHERE id = %d AND uid = %d LIMIT 1", + $r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d LIMIT 1", intval($arr['group']), intval($uid) ); @@ -4379,7 +4421,7 @@ function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remo // sixteen bytes of the mid - which makes the link portable and not quite as daunting // as the entire mid. If it were the post_id the link would be less portable. - \Zotlabs\Lib\IConfig::Set( + IConfig::Set( intval($post_id), 'system', $page_type, @@ -4512,7 +4554,7 @@ function send_profile_photo_activity($channel,$photo,$profile) { $arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext; - $acl = new Zotlabs\Access\AccessList($channel); + $acl = new AccessList($channel); $x = $acl->get(); $arr['allow_cid'] = $x['allow_cid']; @@ -4743,7 +4785,7 @@ function item_create_edit_activity($post) { } } - \Zotlabs\Daemon\Master::Summon(array('Notifier', 'edit_activity', $post_id)); + Master::Summon([ 'Notifier', 'edit_activity', $post_id ]); } /** diff --git a/include/js_strings.php b/include/js_strings.php index d9038e838..c053e5666 100644 --- a/include/js_strings.php +++ b/include/js_strings.php @@ -38,6 +38,15 @@ function js_strings() { // using the defaults set below if left untranslated, empty strings if // translated to "NONE" and the corresponding language strings // if translated to anything else + 'minutes' => tt('%d minutes', '%d minutes', '%d'), + 'hours' => tt('about %d hours', 'about %d hours', '%d'), + 'days' => tt('%d days', '%d days', '%d'), + 'months' => tt('%d months', '%d months', '%d'), + 'years' => tt('%d years', '%d years', '%d'), + + // get plural function code + 'plural_func' => tf(), + '$t01' => ((t('timeago.prefixAgo') == 'timeago.prefixAgo') ? '' : ((t('timeago.prefixAgo') == 'NONE') ? '' : t('timeago.prefixAgo'))), '$t02' => ((t('timeago.prefixFromNow') == 'timeago.prefixFromNow') ? '' : ((t('timeago.prefixFromNow') == 'NONE') ? '' : t('timeago.prefixFromNow'))), '$t03' => ((t('timeago.suffixAgo') == 'timeago.suffixAgo') ? 'ago' : ((t('timeago.suffixAgo') == 'NONE') ? '' : t('timeago.suffixAgo'))), @@ -46,15 +55,15 @@ function js_strings() { // translatable main strings for jquery.timeago '$t05' => t('less than a minute'), '$t06' => t('about a minute'), - '$t07' => t('%d minutes'), + '$t07' => ta('%d minutes'), '$t08' => t('about an hour'), - '$t09' => t('about %d hours'), + '$t09' => ta('about %d hours'), '$t10' => t('a day'), - '$t11' => t('%d days'), + '$t11' => ta('%d days'), '$t12' => t('about a month'), - '$t13' => t('%d months'), + '$t13' => ta('%d months'), '$t14' => t('about a year'), - '$t15' => t('%d years'), + '$t15' => ta('%d years'), '$t16' => t(' '), // wordSeparator '$t17' => ((t('timeago.numbers') != 'timeago.numbers') ? t('timeago.numbers') : '[]'), diff --git a/include/language.php b/include/language.php index 69a7e3004..e9d62e434 100644 --- a/include/language.php +++ b/include/language.php @@ -255,6 +255,32 @@ function tt($singular, $plural, $count, $ctx = ''){ } /** + * @brief Return slash separated string of plurals translation forms + * + * @param string $k key in translations array + * @return string + */ +function ta($k){ + + $t = App::$strings[$k]; + if (is_array($t)) + $t = implode("/", $t); + return ($t == "" ? $k : $t); +} + +/** + * @brief Return string_plural_select_xx function code + * + * @return string + */ + +function tf() { + + $s = "plural_function_code"; + return (x(App::$strings, $s) ? App::$strings[$s] : "0"); +} + +/** * @brief Provide a fallback which will not collide with a function defined in * any language file. * diff --git a/include/markdown.php b/include/markdown.php index de9862801..d2148811c 100644 --- a/include/markdown.php +++ b/include/markdown.php @@ -5,7 +5,11 @@ */ use Michelf\MarkdownExtra; + use League\HTMLToMarkdown\HtmlConverter; +use League\HTMLToMarkdown\Environment; +use League\HTMLToMarkdown\Converter\ConverterInterface; +use League\HTMLToMarkdown\ElementInterface; require_once("include/oembed.php"); require_once("include/event.php"); @@ -74,11 +78,14 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) { // Convert everything that looks like a link to a link if($use_zrl) { - $s = str_replace(['[img', '/img]'], ['[zmg', '/zmg]'], $s); - $s = preg_replace("/([^\]\=\{]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", '$1[zrl=$2$3]$2$3[/zrl]',$s); + if (strpos($s,'[/img]') !== false) { + $s = preg_replace_callback("/\[img\](.*?)\[\/img\]/ism", 'use_zrl_cb_img', $s); + $s = preg_replace_callback("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", 'use_zrl_cb_img_x', $s); + } + $s = preg_replace_callback("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", 'use_zrl_cb_link',$s); } else { - $s = preg_replace("/([^\]\=\{]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", '$1[url=$2$3]$2$3[/url]',$s); + $s = preg_replace("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", '$1[url=$2$3]$2$3[/url]',$s); } // remove duplicate adjacent code tags @@ -96,6 +103,41 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) { return $s; } +function use_zrl_cb_link($match) { + $res = ''; + $is_zid = is_matrix_url(trim($match[0])); + + if($is_zid) + $res = $match[1] . '[zrl=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/zrl]'; + else + $res = $match[1] . '[url=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/url]'; + + return $res; +} + +function use_zrl_cb_img($match) { + $res = ''; + $is_zid = is_matrix_url(trim($match[1])); + + if($is_zid) + $res = '[zmg]' . $match[1] . '[/zmg]'; + else + $res = $match[0]; + + return $res; +} + +function use_zrl_cb_img_x($match) { + $res = ''; + $is_zid = is_matrix_url(trim($match[3])); + + if($is_zid) + $res = '[zmg=' . $match[1] . 'x' . $match[2] . ']' . $match[3] . '[/zmg]'; + else + $res = $match[0]; + + return $res; +} /** * @brief @@ -213,6 +255,9 @@ function bb_to_markdown($Text, $options = []) { $Text = html2markdown($Text); + //html2markdown adds backslashes infront of hashes after a new line. remove them + $Text = str_replace("\n\#", "\n#", $Text); + // It also adds backslashes to our attempt at getting around the html entity preservation for some weird reason. //$Text = str_replace(array('&\\_lt\\_;','&\\_gt\\_;','&\\_amp\\_;'),array('<','>','&'),$Text); @@ -248,9 +293,14 @@ function bb_to_markdown($Text, $options = []) { * @param string $html The HTML code to convert * @return string Markdown representation of the given HTML text, empty on error */ -function html2markdown($html) { +function html2markdown($html,$options = []) { $markdown = ''; - $converter = new HtmlConverter(); + + $internal_errors = libxml_use_internal_errors(true); + + $environment = Environment::createDefaultEnvironment($options); + $environment->addConverter(new TableConverter()); + $converter = new HtmlConverter($environment); try { $markdown = $converter->convert($html); @@ -258,5 +308,77 @@ function html2markdown($html) { logger("Invalid HTML. HTMLToMarkdown library threw an exception."); } + libxml_use_internal_errors($internal_errors); + return $markdown; } + +// Tables are not an official part of the markdown specification. +// This interface was suggested as a workaround. +// author: Mark Hamstra +// https://github.com/Mark-H/Docs + + +class TableConverter implements ConverterInterface +{ + /** + * @param ElementInterface $element + * + * @return string + */ + public function convert(ElementInterface $element) + { + switch ($element->getTagName()) { + case 'tr': + $line = []; + $i = 1; + foreach ($element->getChildren() as $td) { + $i++; + $v = $td->getValue(); + $v = trim($v); + if ($i % 2 === 0 || $v !== '') { + $line[] = $v; + } + } + return '| ' . implode(' | ', $line) . " |\n"; + case 'td': + case 'th': + return trim($element->getValue()); + case 'tbody': + return trim($element->getValue()); + case 'thead': + $headerLine = reset($element->getChildren())->getValue(); + $headers = explode(' | ', trim(trim($headerLine, "\n"), '|')); + $hr = []; + foreach ($headers as $td) { + $length = strlen(trim($td)) + 2; + $hr[] = str_repeat('-', $length > 3 ? $length : 3); + } + $hr = '|' . implode('|', $hr) . '|'; + return $headerLine . $hr . "\n"; + case 'table': + $inner = $element->getValue(); + if (strpos($inner, '-----') === false) { + $inner = explode("\n", $inner); + $single = explode(' | ', trim($inner[0], '|')); + $hr = []; + foreach ($single as $td) { + $length = strlen(trim($td)) + 2; + $hr[] = str_repeat('-', $length > 3 ? $length : 3); + } + $hr = '|' . implode('|', $hr) . '|'; + array_splice($inner, 1, 0, $hr); + $inner = implode("\n", $inner); + } + return trim($inner) . "\n\n"; + } + return $element->getValue(); + } + /** + * @return string[] + */ + public function getSupportedTags() + { + return array('table', 'tr', 'thead', 'td', 'tbody'); + } +} diff --git a/include/message.php b/include/message.php index 4a673b961..936c01631 100644 --- a/include/message.php +++ b/include/message.php @@ -4,6 +4,7 @@ require_once('include/crypto.php'); require_once('include/attach.php'); +require_once('include/msglib.php'); function mail_prepare_binary($item) { @@ -498,11 +499,8 @@ function private_messages_drop($channel_id, $messageitem_id, $drop_conversation } else { xchan_mail_query($x[0]); - $x[0]['mail_deleted'] = true; - $r = q("DELETE FROM mail WHERE id = %d AND channel_id = %d", - intval($messageitem_id), - intval($channel_id) - ); + $x[0]['mail_deleted'] = true; + msg_drop($messageitem_id, $channel_id, $x[0]['conv_guid']); build_sync_packet($channel_id,array('mail' => array(encode_mail($x,true)))); return true; } diff --git a/include/msglib.php b/include/msglib.php new file mode 100644 index 000000000..f0bf523de --- /dev/null +++ b/include/msglib.php @@ -0,0 +1,28 @@ +<?php + +/* Common private message processing functions */ + +function msg_drop($message_id, $channel_id, $conv_guid) { + + // Delete message + $r = q("DELETE FROM mail WHERE id = %d AND channel_id = %d", + intval($message_id), + intval($channel_id) + ); + + // Get new first message... + $r = q("SELECT mid, parent_mid FROM mail WHERE conv_guid = '%s' AND channel_id = %d ORDER BY id ASC LIMIT 1", + dbesc($conv_guid), + intval($channel_id) + ); + // ...and if wasn't first before... + if ($r[0]['mid'] != $r[0]['parent_mid']) { + // ...refer whole thread to it + q("UPDATE mail SET parent_mid = '%s', mail_isreply = abs(mail_isreply - 1) WHERE conv_guid = '%s' AND channel_id = %d", + dbesc($r[0]['mid']), + dbesc($conv_guid), + intval($channel_id) + ); + } + +} diff --git a/include/nav.php b/include/nav.php index 56fe9b901..9c15552e2 100644 --- a/include/nav.php +++ b/include/nav.php @@ -1,11 +1,11 @@ <?php /** @file */ -use \Zotlabs\Lib as Zlib; +use \Zotlabs\Lib\Apps; +use \Zotlabs\Lib\Chatroom; require_once('include/security.php'); require_once('include/menu.php'); - function nav($template = 'default') { /** @@ -60,8 +60,6 @@ function nav($template = 'default') { //we could additionally use this to display important system notifications e.g. for updates )); - $techlevel = get_account_techlevel(); - // nav links: array of array('href', 'text', 'extra css classes', 'title') $nav = []; @@ -93,7 +91,7 @@ function nav($template = 'default') { if(! $_SESSION['delegate']) { $nav['manage'] = array('manage', t('Channel Manager'), "", t('Manage your channels'),'manage_nav_btn'); } - if(feature_enabled(local_channel(),'groups')) + if(Apps::system_app_installed(local_channel(), 'Privacy Groups')) $nav['group'] = array('group', t('Privacy Groups'),"", t('Manage your privacy groups'),'group_nav_btn'); $nav['settings'] = array('settings', t('Settings'),"", t('Account/Channel Settings'),'settings_nav_btn'); @@ -199,40 +197,60 @@ function nav($template = 'default') { // turned off until somebody discovers this and figures out a good location for it. $powered_by = ''; + $url = ''; + $settings_url = ''; + if(App::$profile_uid && App::$nav_sel['raw_name']) { $active_app = q("SELECT app_url FROM app WHERE app_channel = %d AND app_name = '%s' LIMIT 1", intval(App::$profile_uid), dbesc(App::$nav_sel['raw_name']) ); - + if($active_app) { - $url = $active_app[0]['app_url']; + if(strpos($active_app[0]['app_url'], ',')) { + $urls = explode(',', $active_app[0]['app_url']); + $url = trim($urls[0]); + if($is_owner) + $settings_url = trim($urls[1]); + } + else { + $url = $active_app[0]['app_url']; + } } } + if(! $settings_url && isset(App::$nav_sel['settings_url'])) + $settings_url = App::$nav_sel['settings_url']; + //app bin if($is_owner) { + //daily system apps import if(get_pconfig(local_channel(), 'system','import_system_apps') !== datetime_convert('UTC','UTC','now','Y-m-d')) { - Zlib\Apps::import_system_apps(); + Apps::import_system_apps(); set_pconfig(local_channel(), 'system','import_system_apps', datetime_convert('UTC','UTC','now','Y-m-d')); } + if(get_pconfig(local_channel(), 'system','force_import_system_apps') !== STD_VERSION) { + Apps::import_system_apps(); + set_pconfig(local_channel(), 'system','force_import_system_apps', STD_VERSION); + } + $syslist = array(); - $list = Zlib\Apps::app_list(local_channel(), false, ['nav_featured_app', 'nav_pinned_app']); + $list = Apps::app_list(local_channel(), false, ['nav_featured_app', 'nav_pinned_app']); if($list) { foreach($list as $li) { - $syslist[] = Zlib\Apps::app_encode($li); + $syslist[] = Apps::app_encode($li); } } - Zlib\Apps::translate_system_apps($syslist); + Apps::translate_system_apps($syslist); } else { - $syslist = Zlib\Apps::get_system_apps(true); + $syslist = Apps::get_system_apps(true); } usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare'); - $syslist = Zlib\Apps::app_order(local_channel(),$syslist); + $syslist = Apps::app_order(local_channel(),$syslist); foreach($syslist as $app) { if(\App::$nav_sel['name'] == $app['name']) @@ -240,18 +258,18 @@ function nav($template = 'default') { if($is_owner) { if(strpos($app['categories'],'nav_pinned_app') !== false) { - $navbar_apps[] = Zlib\Apps::app_render($app,'navbar'); + $navbar_apps[] = Apps::app_render($app,'navbar'); } else { - $nav_apps[] = Zlib\Apps::app_render($app,'nav'); + $nav_apps[] = Apps::app_render($app,'nav'); } } elseif(! $is_owner && strpos($app['requires'], 'local_channel') === false) { if(strpos($app['categories'],'nav_pinned_app') !== false) { - $navbar_apps[] = Zlib\Apps::app_render($app,'navbar'); + $navbar_apps[] = Apps::app_render($app,'navbar'); } else { - $nav_apps[] = Zlib\Apps::app_render($app,'nav'); + $nav_apps[] = Apps::app_render($app,'nav'); } } } @@ -289,7 +307,8 @@ function nav($template = 'default') { '$addapps' => t('Add Apps'), '$orderapps' => t('Arrange Apps'), '$sysapps_toggle' => t('Toggle System Apps'), - '$url' => (($url) ? $url : App::$cmd) + '$url' => (($url) ? $url : z_root() . '/' . App::$cmd), + '$settings_url' => $settings_url )); if(x($_SESSION, 'reload_avatar') && $observer) { @@ -311,14 +330,17 @@ function nav($template = 'default') { * Set a menu item in navbar as selected * */ -function nav_set_selected($item){ - App::$nav_sel['raw_name'] = $item; - $item = ['name' => $item]; - Zlib\Apps::translate_system_apps($item); - App::$nav_sel['name'] = $item['name']; -} +function nav_set_selected($raw_name, $settings_url = ''){ + App::$nav_sel['raw_name'] = $raw_name; + + $item = ['name' => $raw_name]; + Apps::translate_system_apps($item); + App::$nav_sel['name'] = $item['name']; + if($settings_url) + App::$nav_sel['settings_url'] = z_root() . '/' . $settings_url; +} function channel_apps($is_owner = false, $nickname = null) { @@ -419,8 +441,8 @@ function channel_apps($is_owner = false, $nickname = null) { } - if ($p['chat'] && feature_enabled($uid,'ajaxchat')) { - $has_chats = ZLib\Chatroom::list_count($uid); + if ($p['chat'] && Apps::system_app_installed($uid,'Chatrooms')) { + $has_chats = Chatroom::list_count($uid); if ($has_chats) { $tabs[] = [ 'label' => t('Chatrooms'), @@ -445,7 +467,7 @@ function channel_apps($is_owner = false, $nickname = null) { ]; } - if($p['view_pages'] && feature_enabled($uid,'cards')) { + if($p['view_pages'] && Apps::system_app_installed($uid, 'Cards')) { $tabs[] = [ 'label' => t('Cards'), 'url' => z_root() . '/cards/' . $nickname , @@ -456,7 +478,7 @@ function channel_apps($is_owner = false, $nickname = null) { ]; } - if($p['view_pages'] && feature_enabled($uid,'articles')) { + if($p['view_pages'] && Apps::system_app_installed($uid, 'Articles')) { $tabs[] = [ 'label' => t('Articles'), 'url' => z_root() . '/articles/' . $nickname , @@ -468,7 +490,7 @@ function channel_apps($is_owner = false, $nickname = null) { } - if($has_webpages && feature_enabled($uid,'webpages')) { + if($has_webpages && Apps::system_app_installed($uid, 'Webpages')) { $tabs[] = [ 'label' => t('Webpages'), 'url' => z_root() . '/page/' . $nickname . '/home', @@ -480,21 +502,19 @@ function channel_apps($is_owner = false, $nickname = null) { } - if ($p['view_wiki']) { - if(feature_enabled($uid,'wiki') && (get_account_techlevel($account_id) > 3)) { - $tabs[] = [ - 'label' => t('Wikis'), - 'url' => z_root() . '/wiki/' . $nickname, - 'sel' => ((argv(0) == 'wiki') ? 'active' : ''), - 'title' => t('Wiki'), - 'id' => 'wiki-tab', - 'icon' => 'pencil-square-o' - ]; - } + if ($p['view_wiki'] && Apps::system_app_installed($uid, 'Wiki')) { + $tabs[] = [ + 'label' => t('Wikis'), + 'url' => z_root() . '/wiki/' . $nickname, + 'sel' => ((argv(0) == 'wiki') ? 'active' : ''), + 'title' => t('Wiki'), + 'id' => 'wiki-tab', + 'icon' => 'pencil-square-o' + ]; } $arr = array('is_owner' => $is_owner, 'nickname' => $nickname, 'tab' => (($tab) ? $tab : false), 'tabs' => $tabs); - call_hooks('profile_tabs', $arr); + call_hooks('channel_apps', $arr); return replace_macros(get_markup_template('profile_tabs.tpl'), diff --git a/include/network.php b/include/network.php index 6961bf0ba..4c9813768 100644 --- a/include/network.php +++ b/include/network.php @@ -48,6 +48,10 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) { if(($redirects > 8) || (! $ch)) return $ret; + if(! array_key_exists('request_target',$opts)) { + $opts['request_target'] = 'get ' . get_request_string($url); + } + @curl_setopt($ch, CURLOPT_HEADER, true); @curl_setopt($ch, CURLINFO_HEADER_OUT, true); @curl_setopt($ch, CURLOPT_CAINFO, get_capath()); @@ -157,7 +161,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) { if($http_code == 301 || $http_code == 302 || $http_code == 303 || $http_code == 307 || $http_code == 308) { $matches = array(); - preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches); + preg_match('/(Location:|URI:)(.*?)\n/i', $header, $matches); $newurl = trim(array_pop($matches)); if(strpos($newurl,'/') === 0) $newurl = $url . $newurl; @@ -179,6 +183,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) { } $ret['body'] = substr($s,strlen($header)); $ret['header'] = $header; + $ret['request_target'] = $opts['request_target']; if(x($opts,'debug')) { $ret['debug'] = $curl_info; @@ -227,6 +232,10 @@ function z_post_url($url, $params, $redirects = 0, $opts = array()) { if(($redirects > 8) || (! $ch)) return $ret; + if(! array_key_exists('request_target',$opts)) { + $opts['request_target'] = 'get ' . get_request_string($url); + } + @curl_setopt($ch, CURLOPT_HEADER, true); @curl_setopt($ch, CURLINFO_HEADER_OUT, true); @curl_setopt($ch, CURLOPT_CAINFO, get_capath()); @@ -359,6 +368,7 @@ function z_post_url($url, $params, $redirects = 0, $opts = array()) { $ret['body'] = substr($s, strlen($header)); $ret['header'] = $header; + $ret['request_target'] = $opts['request_target']; if(x($opts,'debug')) { $ret['debug'] = $curl_info; @@ -2042,6 +2052,22 @@ function jsonld_document_loader($url) { require_once('library/jsonld/jsonld.php'); + $recursion = 0; + + $x = debug_backtrace(); + if($x) { + foreach($x as $n) { + if($n['function'] === __FUNCTION__) { + $recursion ++; + } + } + } + if($recursion > 5) { + logger('jsonld bomb detected at: ' . $url); + killme(); + } + + $cachepath = 'store/[data]/ldcache'; if(! is_dir($cachepath)) os_mkdir($cachepath, STORAGE_DEFAULT_PERMISSIONS, true); @@ -2064,3 +2090,17 @@ function jsonld_document_loader($url) { return []; } + +/** + * @brief Given a URL, return everything after the host portion. + * example https://foobar.com/gravy?g=5&y=6 + * returns /gravy?g=5&y=6 + * result always returns the leading slash + */ + +function get_request_string($url) { + + $a = explode('/',$url,4); + return '/' . ((count($a) > 3) ? $a[3] : EMPTY_STR); + +} diff --git a/include/permissions.php b/include/permissions.php index 185d37b6a..115d96eca 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -16,11 +16,14 @@ require_once('include/security.php'); * * @param int $uid The channel_id associated with the resource owner * @param string $observer_xchan The xchan_hash representing the observer - * @param bool $internal_use (default true) + * @param bool $check_siteblock (default true) + * if false, bypass check for "Block Public" on the site + * @param bool $default_ignored (default true) + * if false, lie and pretend the ignored person has permissions you are ignoring (used in channel discovery) * * @returns array of all permissions, key is permission name, value is true or false */ -function get_all_perms($uid, $observer_xchan, $internal_use = true) { +function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ignored = true) { $api = App::get_oauth_key(); if($api) @@ -111,7 +114,7 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) { $blocked_anon_perms = \Zotlabs\Access\Permissions::BlockedAnonPerms(); - if(($x) && ($internal_use) && in_array($perm_name,$blocked_anon_perms) && intval($x[0]['abook_ignored'])) { + if(($x) && ($default_ignored) && in_array($perm_name,$blocked_anon_perms) && intval($x[0]['abook_ignored'])) { $ret[$perm_name] = false; continue; } @@ -119,7 +122,7 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) { // system is blocked to anybody who is not authenticated - if((! $observer_xchan) && intval(get_config('system', 'block_public'))) { + if(($check_siteblock) && (! $observer_xchan) && intval(get_config('system', 'block_public'))) { $ret[$perm_name] = false; continue; } @@ -251,9 +254,11 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) { * @param int $uid The channel_id associated with the resource owner * @param string $observer_xchan The xchan_hash representing the observer * @param string $permission + * @param boolean $check_siteblock (default true) + * if false bypass check for "Block Public" at the site level * @return bool true if permission is allowed for observer on channel */ -function perm_is_allowed($uid, $observer_xchan, $permission) { +function perm_is_allowed($uid, $observer_xchan, $permission, $check_siteblock = true) { $api = App::get_oauth_key(); if($api) @@ -326,7 +331,7 @@ function perm_is_allowed($uid, $observer_xchan, $permission) { // system is blocked to anybody who is not authenticated - if((! $observer_xchan) && intval(get_config('system', 'block_public'))) + if(($check_siteblock) && (! $observer_xchan) && intval(get_config('system', 'block_public'))) return false; // Check if this $uid is actually the $observer_xchan diff --git a/include/plugin.php b/include/plugin.php index 734c20d79..8ceb6417e 100755 --- a/include/plugin.php +++ b/include/plugin.php @@ -14,17 +14,17 @@ * @param bool $uninstall uninstall plugin */ function handleerrors_plugin($plugin,$notice,$log,$uninstall=false){ - logger("Addons: [" . $plugin . "] Error: ".$log, LOGGER_ERROR); - if ($notice != '') { - notice("[" . $plugin . "] Error: ".$notice, LOGGER_ERROR); - } + logger("Addons: [" . $plugin . "] Error: ".$log, LOGGER_ERROR); + if ($notice != '') { + notice("[" . $plugin . "] Error: ".$notice, LOGGER_ERROR); + } - if ($uninstall) { - $idx = array_search($plugin, \App::$plugins); - unset(\App::$plugins[$idx]); - uninstall_plugin($plugin); - set_config("system","addon", implode(", ",\App::$plugins)); - } + if ($uninstall) { + $idx = array_search($plugin, \App::$plugins); + unset(\App::$plugins[$idx]); + uninstall_plugin($plugin); + set_config("system","addon", implode(", ",\App::$plugins)); + } } /** @@ -109,11 +109,16 @@ function install_plugin($plugin) { $plugin_admin = (function_exists($plugin . '_plugin_admin') ? 1 : 0); - q("INSERT INTO addon (aname, installed, tstamp, plugin_admin) VALUES ( '%s', 1, %d , %d ) ", - dbesc($plugin), - intval($t), - $plugin_admin + $d = q("select * from addon where aname = '%s' limit 1", + dbesc($plugin) ); + if(! $d) { + q("INSERT INTO addon (aname, installed, tstamp, plugin_admin) VALUES ( '%s', 1, %d , %d ) ", + dbesc($plugin), + intval($t), + $plugin_admin + ); + } load_plugin($plugin); } @@ -206,19 +211,19 @@ function reload_plugins() { if(function_exists($pl . '_unload')) { $func = $pl . '_unload'; try { - $func(); + $func(); } catch (Exception $e) { handleerrors_plugin($plugin,"","UNLOAD FAILED (uninstalling) : ".$e->getMessage(),true); - continue; + continue; } } if(function_exists($pl . '_load')) { $func = $pl . '_load'; try { - $func(); + $func(); } catch (Exception $e) { handleerrors_plugin($plugin,"","LOAD FAILED (uninstalling): ".$e->getMessage(),true); - continue; + continue; } } q("UPDATE addon SET tstamp = %d WHERE id = %d", @@ -366,28 +371,47 @@ function unregister_hook($hook, $file, $function) { return $r; } - -// -// It might not be obvious but themes can manually add hooks to the App::$hooks -// array in their theme_init() and use this to customise the app behaviour. -// UPDATE: use insert_hook($hookname,$function_name) to do this -// +/** + * @brief loads all active hooks into memory + * alters: App::$hooks + * Called during initialisation + * Duplicated hooks are removed and the duplicates ignored + * + * It might not be obvious but themes can manually add hooks to the App::$hooks + * array in their theme_init() and use this to customise the app behaviour. + * use insert_hook($hookname,$function_name) to do this. + */ function load_hooks() { - App::$hooks = array(); + App::$hooks = []; $r = q("SELECT * FROM hook WHERE true ORDER BY priority DESC"); if($r) { - foreach($r as $rr) { - if(! array_key_exists($rr['hook'],App::$hooks)) - App::$hooks[$rr['hook']] = array(); - App::$hooks[$rr['hook']][] = array($rr['file'],$rr['fn'],$rr['priority'],$rr['hook_version']); + foreach($r as $rv) { + $duplicated = false; + if(! array_key_exists($rv['hook'],App::$hooks)) { + App::$hooks[$rv['hook']] = []; + } + else { + foreach(App::$hooks[$rv['hook']] as $h) { + if($h[0] === $rv['file'] && $h[1] === $rv['fn']) { + $duplicated = true; + q("delete from hook where id = %d", + intval($rv['id']) + ); + logger('duplicate hook ' . $h[1] . ' removed'); + } + } + } + if(! $duplicated) { + App::$hooks[$rv['hook']][] = [ $rv['file'], $rv['fn'], $rv['priority'], $rv['hook_version']]; + } } } - //logger('hooks: ' . print_r(App::$hooks,true)); + // logger('hooks: ' . print_r(App::$hooks,true)); } /** @@ -431,8 +455,28 @@ function insert_hook($hook, $fn, $version = 0, $priority = 0) { */ function call_hooks($name, &$data = null) { $a = 0; - if((is_array(App::$hooks)) && (array_key_exists($name, App::$hooks))) { + + if (isset(App::$hooks[$name])) { foreach(App::$hooks[$name] as $hook) { + + if ($name != 'permit_hook') { // avoid looping + $checkhook = [ + 'name'=>$name, + 'hook'=>$hook, + 'data'=>$data, + // Note: Since PHP uses COPY-ON-WRITE + // for variables, there is no cost to + // passing the $data structure (unless + // the permit_hook processors change the + // information it contains. + 'permit'=>true + ]; + call_hooks('permit_hook',$checkhook); + if (!$checkhook['permit']) { + continue; + } + $data = $checkhook['data']; + } $origfn = $hook[1]; if($hook[0]) @include_once($hook[0]); @@ -958,9 +1002,8 @@ function format_js_if_exists($source) { function theme_include($file, $root = '') { // Make sure $root ends with a slash / if it's not blank - if($root !== '' && $root[strlen($root)-1] !== '/') + if($root !== '' && substr($root,-1) !== '/') $root = $root . '/'; - $theme_info = App::$theme_info; if(array_key_exists('extends',$theme_info)) @@ -991,21 +1034,54 @@ function theme_include($file, $root = '') { return ''; } - function get_intltext_template($s, $root = '') { - - $t = App::template_engine(); - - $template = $t->get_intltext_template($s, $root); - return $template; + $testroot = ($root=='') ? $testroot = "ROOT" : $root; + $t = App::template_engine(); + + if (isset(\App::$override_intltext_templates[$testroot][$s]["content"])) { + return \App::$override_intltext_templates[$testroot][$s]["content"]; + } else { + if (isset(\App::$override_intltext_templates[$testroot][$s]["root"]) && + isset(\App::$override_intltext_templates[$testroot][$s]["file"])) { + $s = \App::$override_intltext_templates[$testroot][$s]["file"]; + $root = \App::$override_intltext_templates[$testroot][$s]["root"]; + } elseif (\App::$override_templateroot) { + $newroot = \App::$override_templateroot.$root; + if ($newroot != '' && substr($newroot,-1) != '/' ) { + $newroot .= '/'; + } + $template = $t->get_intltext_template($s, $newroot); + } + $template = $t->get_intltext_template($s, $root); + return $template; + } } - function get_markup_template($s, $root = '') { - - $t = App::template_engine(); - $template = $t->get_markup_template($s, $root); - return $template; + $testroot = ($root=='') ? $testroot = "ROOT" : $root; + + $t = App::template_engine(); + + if (isset(\App::$override_markup_templates[$testroot][$s]["content"])) { + return \App::$override_markup_templates[$testroot][$s]["content"]; + } else { + if (isset(\App::$override_markup_templates[$testroot][$s]["root"]) && + isset(\App::$override_markup_templates[$testroot][$s]["file"])) { + $root = \App::$override_markup_templates[$testroot][$s]["root"]; + $s = \App::$override_markup_templates[$testroot][$s]["file"]; + $template = $t->get_markup_template($s, $root); + } elseif (\App::$override_templateroot) { + $newroot = \App::$override_templateroot; + if ($newroot != '' && substr($newroot,-1) != '/' ) { + $newroot .= '/'; + } + $newroot .= $root; + $template = $t->get_markup_template($s, $newroot); + } else { + $template = $t->get_markup_template($s, $root); + } + return $template; + } } /** diff --git a/include/security.php b/include/security.php index 88988a7c0..493d34699 100644 --- a/include/security.php +++ b/include/security.php @@ -370,7 +370,7 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '') { } /** - * @brief Creates an addiontal SQL where statement to check permissions for an item. + * @brief Creates an additional SQL where statement to check permissions for an item. * * @param int $owner_id * @param bool $remote_observer (optional) use current observer if unset @@ -577,7 +577,7 @@ function init_groups_visitor($contact_id) { // physical groups this channel is a member of - $r = q("SELECT hash FROM groups left join group_member on groups.id = group_member.gid WHERE xchan = '%s' ", + $r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE xchan = '%s' ", dbesc($contact_id) ); if($r) { diff --git a/include/selectors.php b/include/selectors.php index ab049fff6..71e2a387d 100644 --- a/include/selectors.php +++ b/include/selectors.php @@ -3,21 +3,32 @@ function contact_profile_assign($current) { - $o = ''; - - $o .= "<select id=\"contact-profile-selector\" name=\"profile_assign\" class=\"form-control\"/>\r\n"; - $r = q("SELECT profile_guid, profile_name FROM profile WHERE uid = %d", - intval($_SESSION['uid'])); + intval($_SESSION['uid']) + ); if($r) { foreach($r as $rr) { - $selected = (($rr['profile_guid'] == $current) ? " selected=\"selected\" " : ""); - $o .= "<option value=\"{$rr['profile_guid']}\" $selected >{$rr['profile_name']}</option>\r\n"; + $options[$rr['profile_guid']] = $rr['profile_name']; } } - $o .= "</select>\r\n"; + + $select = [ + 'profile_assign', + t('Profile to assign new connections'), + $current, + '', + $options + ]; + + $o = replace_macros(get_markup_template('field_select.tpl'), + [ + '$field' => $select + ] + ); + return $o; + } function contact_poll_interval($current, $disabled = false) { diff --git a/include/text.php b/include/text.php index e894c5ce5..1d884593f 100644 --- a/include/text.php +++ b/include/text.php @@ -37,7 +37,13 @@ function replace_macros($s, $r) { call_hooks('replace_macros', $arr); $t = App::template_engine(); - $output = $t->replace_macros($arr['template'], $arr['params']); + + try { + $output = $t->replace_macros($arr['template'], $arr['params']); + } catch (Exception $e) { + logger("Unable to render template: ".$e->getMessage()); + $output = "<h3>ERROR: there was an error creating the output.</h3>"; + } return $output; } @@ -2047,6 +2053,7 @@ function undo_post_tagging($s) { $cnt = preg_match_all('/([@#])(\!*)\[zrl=(.*?)\](.*?)\[\/zrl\]/ism',$s,$matches,PREG_SET_ORDER); if($cnt) { foreach($matches as $mtch) { + $x = false; if($mtch[1] === '@') { $x = q("select xchan_addr, xchan_url from xchan where xchan_url = '%s' limit 1", dbesc($mtch[3]) @@ -2730,7 +2737,7 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $i $grp = group_byname($profile_uid,$name); if($grp) { - $g = q("select hash from groups where id = %d and visible = 1 limit 1", + $g = q("select hash from pgrp where id = %d and visible = 1 limit 1", intval($grp) ); if($g && $exclusive) { @@ -2958,7 +2965,9 @@ function item_url_replace($channel,&$item,$old,$new,$oldnick = '') { json_url_replace('/' . $oldnick . '/' ,'/' . $channel['channel_address'] . '/' ,$item['target']); } - if(string_replace($old,$new,$item['body'])) { + $x = preg_replace("/".preg_quote($old,'/')."\/(search|\w+\/".$channel['channel_address'].")/", $new.'/${1}', $item['body']); + if($x) { + $item['body'] = $x; $item['sig'] = base64url_encode(rsa_sign($item['body'],$channel['channel_prvkey'])); $item['item_verified'] = 1; } @@ -3251,17 +3260,17 @@ function cleanup_bbcode($body) { * First protect any url inside certain bbcode tags so we don't double link it. */ - $body = preg_replace_callback('/\[code(.*?)\[\/(code)\]/ism','\red_escape_codeblock',$body); $body = preg_replace_callback('/\[url(.*?)\[\/(url)\]/ism','\red_escape_codeblock',$body); $body = preg_replace_callback('/\[zrl(.*?)\[\/(zrl)\]/ism','\red_escape_codeblock',$body); - $body = preg_replace_callback("/([^\]\='".'"'."\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\ +\,\(\)]+)/ismu", '\nakedoembed', $body); + $body = preg_replace_callback("/([^\]\='".'"'."\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\ +\,\(\)]+)/ismu", '\red_zrl_callback', $body); + $body = preg_replace_callback('/\[\$b64zrl(.*?)\[\/(zrl)\]/ism','\red_unescape_codeblock',$body); $body = preg_replace_callback('/\[\$b64url(.*?)\[\/(url)\]/ism','\red_unescape_codeblock',$body); $body = preg_replace_callback('/\[\$b64code(.*?)\[\/(code)\]/ism','\red_unescape_codeblock',$body); @@ -3412,3 +3421,41 @@ function get_forum_channels($uid) { return $r; } + +function print_array($arr, $level = 0) { + + $o = EMPTY_STR; + $tabs = EMPTY_STR; + + if(is_array($arr)) { + for($x = 0; $x <= $level; $x ++) { + $tabs .= "\t"; + } + $o .= '[' . "\n"; + if(count($arr)) { + foreach($arr as $k => $v) { + if(is_array($v)) { + $o .= $tabs . '[' . $k . '] => ' . print_array($v, $level + 1) . "\n"; + } + else { + $o .= $tabs . '[' . $k . '] => ' . print_val($v) . ",\n"; + } + } + } + $o .= substr($tabs,0,-1) . ']' . (($level) ? ',' : ';' ). "\n"; + return $o; + } + +} + +function print_val($v) { + if(is_bool($v)) { + if($v) return 'true'; + return 'false'; + } + if(is_string($v)) { + return "'" . $v . "'"; + } + return $v; + +} diff --git a/include/xchan.php b/include/xchan.php index 8c9c09c72..aad56063f 100644 --- a/include/xchan.php +++ b/include/xchan.php @@ -176,7 +176,7 @@ function xchan_change_key($oldx,$newx,$data) { $tables = [ 'abook' => 'abook_xchan', 'abconfig' => 'xchan', - 'group_member' => 'xchan', + 'pgrp_member' => 'xchan', 'chat' => 'chat_xchan', 'chatpresence' => 'cp_xchan', 'event' => 'event_xchan', diff --git a/include/zot.php b/include/zot.php index 19e1298c3..4a8892083 100644 --- a/include/zot.php +++ b/include/zot.php @@ -12,6 +12,7 @@ require_once('include/crypto.php'); require_once('include/items.php'); require_once('include/queue_fn.php'); require_once('include/perm_upgrade.php'); +require_once('include/msglib.php'); /** @@ -491,7 +492,7 @@ function zot_refresh($them, $channel = null, $force = false) { $profile_assign = get_pconfig($channel['channel_id'],'system','profile_assign',''); // Keep original perms to check if we need to notify them - $previous_perms = get_all_perms($channel['channel_id'],$x['hash']); + $previous_perms = get_all_perms($channel['channel_id'],$x['hash'],false); $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", dbesc($x['hash']), @@ -560,7 +561,7 @@ function zot_refresh($them, $channel = null, $force = false) { if($y) { logger("New introduction received for {$channel['channel_name']}"); - $new_perms = get_all_perms($channel['channel_id'],$x['hash']); + $new_perms = get_all_perms($channel['channel_id'],$x['hash'],false); // Send a clone sync packet and a permissions update if permissions have changed @@ -1118,6 +1119,7 @@ function zot_process_response($hub, $arr, $outq) { } foreach($x['delivery_report'] as $xx) { + call_hooks('dreport_process',$xx); if(is_array($xx) && array_key_exists('message_id',$xx) && delivery_report_is_storable($xx)) { q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s','%s','%s','%s','%s' ) ", dbesc($xx['message_id']), @@ -1807,13 +1809,28 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $ else { $arr['item_wall'] = 0; } - - if((! perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)) && (! $tag_delivery) && (! $local_public)) { - logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}"); - $DR->update('permission denied'); - $result[] = $DR->get(); - continue; - } + + + if ((! $tag_delivery) && (! $local_public)) { + $allowed = (perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)); + + if((! $allowed) && $perm == 'post_comments') { + $parent = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($arr['parent_mid']), + intval($channel['channel_id']) + ); + if ($parent) { + $allowed = can_comment_on_post($d['hash'],$parent[0]); + } + } + + if (! $allowed) { + logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}"); + $DR->update('permission denied'); + $result[] = $DR->get(); + continue; + } + } if($arr['mid'] != $arr['parent_mid']) { @@ -2315,16 +2332,13 @@ function process_mail_delivery($sender, $arr, $deliveries) { } - $r = q("select id from mail where mid = '%s' and channel_id = %d limit 1", + $r = q("select id, conv_guid from mail where mid = '%s' and channel_id = %d limit 1", dbesc($arr['mid']), intval($channel['channel_id']) ); if($r) { if(intval($arr['mail_recalled'])) { - $x = q("delete from mail where id = %d and channel_id = %d", - intval($r[0]['id']), - intval($channel['channel_id']) - ); + msg_drop($r[0]['id'], $channel['channel_id'], $r[0]['conv_guid']); $DR->update('mail recalled'); $result[] = $DR->get(); logger('mail_recalled'); @@ -3306,13 +3320,13 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { } if($groups_changed) { - $r = q("select hash as collection, visible, deleted, gname as name from groups where uid = %d", + $r = q("select hash as collection, visible, deleted, gname as name from pgrp where uid = %d", intval($uid) ); if($r) $info['collections'] = $r; - $r = q("select groups.hash as collection, group_member.xchan as member from groups left join group_member on groups.id = group_member.gid where group_member.uid = %d", + $r = q("select pgrp.hash as collection, pgrp_member.xchan as member from pgrp left join pgrp_member on pgrp.id = pgrp_member.gid where pgrp_member.uid = %d", intval($uid) ); if($r) @@ -3557,13 +3571,13 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { } $disallowed = [ - 'channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey', - 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted', - 'channel_system', 'channel_r_stream', 'channel_r_profile', 'channel_r_abook', - 'channel_r_storage', 'channel_r_pages', 'channel_w_stream', 'channel_w_wall', - 'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall', - 'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish', - 'channel_a_delegate' + 'channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey', + 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted', + 'channel_system', 'channel_r_stream', 'channel_r_profile', 'channel_r_abook', + 'channel_r_storage', 'channel_r_pages', 'channel_w_stream', 'channel_w_wall', + 'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall', + 'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish', + 'channel_a_delegate', 'channel_moved' ]; $clean = array(); @@ -3720,7 +3734,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { // sync collections (privacy groups) oh joy... if(array_key_exists('collections',$arr) && is_array($arr['collections']) && count($arr['collections'])) { - $x = q("select * from groups where uid = %d", + $x = q("select * from pgrp where uid = %d", intval($channel['channel_id']) ); foreach($arr['collections'] as $cl) { @@ -3736,7 +3750,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { if(($y['gname'] != $cl['name']) || ($y['visible'] != $cl['visible']) || ($y['deleted'] != $cl['deleted'])) { - q("update groups set gname = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d", + q("update pgrp set gname = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d", dbesc($cl['name']), intval($cl['visible']), intval($cl['deleted']), @@ -3745,14 +3759,14 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { ); } if(intval($cl['deleted']) && (! intval($y['deleted']))) { - q("delete from group_member where gid = %d", + q("delete from pgrp_member where gid = %d", intval($y['id']) ); } } } if(! $found) { - $r = q("INSERT INTO groups ( hash, uid, visible, deleted, gname ) + $r = q("INSERT INTO pgrp ( hash, uid, visible, deleted, gname ) VALUES( '%s', %d, %d, %d, '%s' ) ", dbesc($cl['collection']), intval($channel['channel_id']), @@ -3776,10 +3790,10 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { } } if(! $found_local) { - q("delete from group_member where gid = %d", + q("delete from pgrp_member where gid = %d", intval($y['id']) ); - q("update groups set deleted = 1 where id = %d and uid = %d", + q("update pgrp set deleted = 1 where id = %d and uid = %d", intval($y['id']), intval($channel['channel_id']) ); @@ -3789,7 +3803,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { } // reload the group list with any updates - $x = q("select * from groups where uid = %d", + $x = q("select * from pgrp where uid = %d", intval($channel['channel_id']) ); @@ -3816,7 +3830,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { if(isset($y['hash']) && isset($members[$y['hash']])) { foreach($members[$y['hash']] as $member) { $found = false; - $z = q("select xchan from group_member where gid = %d and uid = %d and xchan = '%s' limit 1", + $z = q("select xchan from pgrp_member where gid = %d and uid = %d and xchan = '%s' limit 1", intval($y['id']), intval($channel['channel_id']), dbesc($member) @@ -3827,7 +3841,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { // if somebody is in the group that wasn't before - add them if(! $found) { - q("INSERT INTO group_member (uid, gid, xchan) + q("INSERT INTO pgrp_member (uid, gid, xchan) VALUES( %d, %d, '%s' ) ", intval($channel['channel_id']), intval($y['id']), @@ -3838,7 +3852,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { } // now retrieve a list of members we have on this site - $m = q("select xchan from group_member where gid = %d and uid = %d", + $m = q("select xchan from pgrp_member where gid = %d and uid = %d", intval($y['id']), intval($channel['channel_id']) ); @@ -3846,7 +3860,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { foreach($m as $mm) { // if the local existing member isn't in the list we just received - remove them if(! in_array($mm['xchan'],$members[$y['hash']])) { - q("delete from group_member where xchan = '%s' and gid = %d and uid = %d", + q("delete from pgrp_member where xchan = '%s' and gid = %d and uid = %d", dbesc($mm['xchan']), intval($y['id']), intval($channel['channel_id']) @@ -4419,7 +4433,7 @@ function zotinfo($arr) { if(! $ret['follow_url']) $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; - $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false); + $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false,false); if($ztarget_hash) { $permissions['connected'] = false; |