aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorMario Vavti <mario@mariovavti.com>2018-10-19 11:18:28 +0200
committerMario Vavti <mario@mariovavti.com>2018-10-19 11:18:28 +0200
commitfa9e9510e5d993d183feb942fe74be5fdd07f5cf (patch)
tree41fec09f527a9346e043b8099b458a97d81b03ed /include
parent32de123db0ac526795a237ff46885fe8a332cbc0 (diff)
parent06b3ad1071c755757555baf941e2c0f446f97b21 (diff)
downloadvolse-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.php13
-rw-r--r--include/acl_selectors.php2
-rw-r--r--include/api.php5
-rw-r--r--include/api_auth.php37
-rw-r--r--include/api_zot.php8
-rw-r--r--include/attach.php5
-rw-r--r--include/bbcode.php5
-rw-r--r--include/bookmarks.php5
-rw-r--r--include/channel.php59
-rw-r--r--include/connections.php4
-rw-r--r--include/conversation.php333
-rw-r--r--include/features.php474
-rw-r--r--include/group.php44
-rw-r--r--include/help.php99
-rw-r--r--include/hubloc.php2
-rw-r--r--include/import.php5
-rwxr-xr-xinclude/items.php128
-rw-r--r--include/js_strings.php19
-rw-r--r--include/language.php26
-rw-r--r--include/markdown.php132
-rw-r--r--include/message.php8
-rw-r--r--include/msglib.php28
-rw-r--r--include/nav.php102
-rw-r--r--include/network.php42
-rw-r--r--include/permissions.php17
-rwxr-xr-xinclude/plugin.php164
-rw-r--r--include/security.php4
-rw-r--r--include/selectors.php27
-rw-r--r--include/text.php57
-rw-r--r--include/xchan.php2
-rw-r--r--include/zot.php84
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('&lt;','&gt;','&amp;'),$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;