aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorMario <mario@mariovavti.com>2022-01-21 07:28:24 +0000
committerMario <mario@mariovavti.com>2022-01-21 07:28:24 +0000
commit755d0f54f7ddfc2a932e17c425c7a1aacb8d7efb (patch)
treedb1616efe407092127a273de1889bc1cd852132f /include
parenta40babbf0d09e0131a00a1e88d359caebb997a65 (diff)
parentf62d66ff25ffac7dbfdc663d2a64c5b415b6e294 (diff)
downloadvolse-hubzilla-755d0f54f7ddfc2a932e17c425c7a1aacb8d7efb.tar.gz
volse-hubzilla-755d0f54f7ddfc2a932e17c425c7a1aacb8d7efb.tar.bz2
volse-hubzilla-755d0f54f7ddfc2a932e17c425c7a1aacb8d7efb.zip
Merge branch '7.0RC'
Diffstat (limited to 'include')
-rw-r--r--include/attach.php6
-rw-r--r--include/bbcode.php2
-rw-r--r--include/channel.php75
-rw-r--r--include/connections.php118
-rw-r--r--include/conversation.php39
-rw-r--r--include/group.php2
-rw-r--r--include/import.php58
-rw-r--r--include/items.php207
-rw-r--r--include/nav.php6
-rw-r--r--include/permissions.php83
-rw-r--r--include/plugin.php4
-rw-r--r--include/security.php34
-rw-r--r--include/selectors.php20
-rw-r--r--include/text.php195
14 files changed, 588 insertions, 261 deletions
diff --git a/include/attach.php b/include/attach.php
index 067da21ae..2109b84f1 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -15,10 +15,10 @@ use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Activity;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master;
+use Zotlabs\Lib\AccessList;
require_once('include/permissions.php');
require_once('include/security.php');
-require_once('include/group.php');
/**
* @brief Guess the mimetype from file ending.
@@ -2208,7 +2208,7 @@ function attach_recursive_perms($arr_allow_cid, $arr_allow_gid, $arr_deny_cid, $
//lookup all channels in sharee group and add them to sharee $arr_allow_cid
if($arr_allow_gid) {
- $in_group = expand_groups($arr_allow_gid);
+ $in_group = AccessList::expand($arr_allow_gid);
$arr_allow_cid = array_unique(array_merge($arr_allow_cid, $in_group));
}
@@ -2280,7 +2280,7 @@ function attach_recursive_perms($arr_allow_cid, $arr_allow_gid, $arr_deny_cid, $
//check sharee arr_allow_cid against members of allow_gid of all parent folders
foreach($parent_arr['allow_gid'] as $folder_arr_allow_gid) {
//get the group members
- $folder_arr_allow_cid = expand_groups($folder_arr_allow_gid);
+ $folder_arr_allow_cid = AccessList::expand($folder_arr_allow_gid);
foreach($folder_arr_allow_cid as $ac_hash) {
$count_values[$ac_hash]++;
}
diff --git a/include/bbcode.php b/include/bbcode.php
index 6a1a5a01e..03115effe 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -1400,7 +1400,7 @@ function bbcode($Text, $options = []) {
// Check for table of content without params
while(strpos($Text,'[toc]') !== false) {
$toc_id = 'toc-' . random_string(10);
- $Text = preg_replace("/\[toc\]/ism", '<ul id="' . $toc_id . '" class="toc" data-toc=".section-content-wrapper"></ul><script>$("#' . $toc_id . '").toc();</script>', $Text, 1);
+ $Text = preg_replace("/\[toc\]/ism", '<ul id="' . $toc_id . '" class="toc"></ul><script>$(document).ready(function() { let toc_container = $("#' . $toc_id . '").parent().closest("div").attr("id") || ".section-content-wrapper"; $("#' . $toc_id . '").toc({content: "#" + toc_container, headings: "h1,h2,h3,h4"}); });</script>', $Text, 1);
}
// Check for table of content with params
while(strpos($Text,'[toc') !== false) {
diff --git a/include/channel.php b/include/channel.php
index 102a03489..4e84b1b32 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -15,11 +15,13 @@ use Zotlabs\Render\Comanche;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Connect;
use Zotlabs\Lib\Libsync;
+use Zotlabs\Lib\AccessList;
require_once('include/crypto.php');
require_once('include/menu.php');
require_once('include/perm_upgrade.php');
require_once('include/photo/photo_driver.php');
+require_once('include/security.php');
/**
* @brief Called when creating a new channel.
@@ -240,7 +242,7 @@ function create_identity($arr) {
// Force a few things on the short term until we can provide a theme or app with choice
- $publish = 1;
+ $publish = 0;
if(array_key_exists('publish', $arr))
$publish = intval($arr['publish']);
@@ -325,6 +327,12 @@ function create_identity($arr) {
if($role_permissions && array_key_exists('perms_auto',$role_permissions))
set_pconfig($r[0]['channel_id'],'system','autoperms',intval($role_permissions['perms_auto']));
+ $group_actor = false;
+ if($role_permissions && array_key_exists('channel_type', $role_permissions) && $role_permissions['channel_type'] === 'group') {
+ set_pconfig($r[0]['channel_id'], 'system', 'group_actor', 1);
+ $group_actor = true;
+ }
+
$ret['channel'] = $r[0];
if(intval($arr['account_id']))
@@ -374,7 +382,8 @@ function create_identity($arr) {
'xchan_network' => 'zot6',
'xchan_photo_date' => datetime_convert(),
'xchan_name_date' => datetime_convert(),
- 'xchan_system' => $system
+ 'xchan_system' => $system,
+ 'xchan_pubforum' => $group_actor
]
);
if(! $r)
@@ -399,14 +408,6 @@ function create_identity($arr) {
]
);
- if($role_permissions) {
- $myperms = ((array_key_exists('perms_connect',$role_permissions)) ? $role_permissions['perms_connect'] : array());
- }
- else {
- $x = PermissionRoles::role_perms('social');
- $myperms = $x['perms_connect'];
- }
-
$r = abook_store_lowlevel(
[
'abook_account' => intval($ret['channel']['channel_account_id']),
@@ -419,19 +420,18 @@ function create_identity($arr) {
]
);
- $x = Permissions::FilledPerms($myperms);
- foreach($x as $k => $v) {
- set_abconfig($newuid,$hash,'my_perms',$k,$v);
- }
-
if(intval($ret['channel']['channel_account_id'])) {
- // Save our permissions role so we can perhaps call it up and modify it later.
+
+ // Set the default permcat
+ set_pconfig($newuid,'system','default_permcat','default');
if($role_permissions) {
+ // Save our permissions role so we can perhaps call it up and modify it later.
set_pconfig($newuid,'system','permissions_role',$arr['permissions_role']);
+
if(array_key_exists('online',$role_permissions))
- set_pconfig($newuid,'system','hide_presence',1-intval($role_permissions['online']));
+ set_pconfig($newuid,'system','show_online_status', intval($role_permissions['online']));
if(array_key_exists('perms_auto',$role_permissions)) {
$autoperms = intval($role_permissions['perms_auto']);
set_pconfig($newuid,'system','autoperms',$autoperms);
@@ -453,11 +453,10 @@ function create_identity($arr) {
// Create a group with yourself as a member. This allows somebody to use it
// right away as a default group for new contacts.
- require_once('include/group.php');
- $group_hash = group_add($newuid, t('Friends'));
+ $group_hash = AccessList::add($newuid, t('Friends'));
if($group_hash) {
- group_add_member($newuid,t('Friends'),$ret['channel']['channel_hash']);
+ AccessList::member_add($newuid,t('Friends'),$ret['channel']['channel_hash']);
$default_collection_str = '';
// if our role_permissions indicate that we're using a default collection ACL, add it.
@@ -496,8 +495,7 @@ function create_identity($arr) {
if($acct) {
$f = connect_and_sync($ret['channel'], $acct);
if($f['success']) {
- $can_view_stream = their_perms_contains($ret['channel']['channel_id'],$f['abook']['abook_xchan'],'view_stream');
-
+ $can_view_stream = intval(get_abconfig($ret['channel']['channel_id'], $f['abook']['abook_xchan'], 'their_perms', 'view_stream'));
// If we can view their stream, pull in some posts
if(($can_view_stream) || ($f['abook']['xchan_network'] === 'rss')) {
Master::Summon([ 'Onepoll',$f['abook']['abook_id'] ]);
@@ -881,6 +879,14 @@ function identity_basic_export($channel_id, $sections = null, $zap_compat = fals
}
if(in_array('connections',$sections)) {
+ $r = q("select * from atoken where atoken_uid = %d",
+ intval($channel_id)
+ );
+
+ if ($r) {
+ $ret['atoken'] = $r;
+ }
+
$xchans = array();
$r = q("select * from abook where abook_channel = %d ",
intval($channel_id)
@@ -1488,6 +1494,7 @@ function profile_load($nickname, $profile = '') {
if($can_view_profile) {
$online = get_online_status($nickname);
+
App::$profile['online_status'] = $online['result'];
}
@@ -1965,11 +1972,24 @@ function zat_init() {
);
if($r) {
$xchan = atoken_xchan($r[0]);
- atoken_create_xchan($xchan);
+ //atoken_create_xchan($xchan);
atoken_login($xchan);
}
}
+function atoken_delete_and_sync($channel_id, $atoken_guid) {
+ $r = q("select * from atoken where atoken_guid = '%s' and atoken_uid = %d",
+ dbesc($atoken_guid),
+ intval($channel_id)
+ );
+
+ if ($r) {
+ $atok = $r[0];
+ $atok['deleted'] = true;
+ atoken_delete($atok['atoken_id']);
+ Libsync::build_sync_packet($channel_id, ['atoken' => [ $atok ]]);
+ }
+}
/**
* @brief Used from within PCSS themes to set theme parameters.
@@ -2060,11 +2080,12 @@ function get_online_status($nick) {
return $ret;
$r = q("select channel_id, channel_hash from channel where channel_address = '%s' limit 1",
- dbesc(argv(1))
+ dbesc($nick)
);
+
if($r) {
- $hide = get_pconfig($r[0]['channel_id'],'system','hide_online_status');
- if($hide)
+ $show = get_pconfig($r[0]['channel_id'],'system','show_online_status');
+ if(!$show)
return $ret;
$x = q("select cp_status from chatpresence where cp_xchan = '%s' and cp_room = 0 limit 1",
@@ -2280,7 +2301,7 @@ function auto_channel_create($account_id) {
}
}
if(! $arr['permissions_role'])
- $arr['permissions_role'] = 'social';
+ $arr['permissions_role'] = 'personal';
if(validate_channelname($arr['name']))
return false;
diff --git a/include/connections.php b/include/connections.php
index 0611377ab..dcfcc3985 100644
--- a/include/connections.php
+++ b/include/connections.php
@@ -1,5 +1,6 @@
<?php /** @file */
+use Zotlabs\Daemon\Master;
function abook_store_lowlevel($arr) {
@@ -27,7 +28,8 @@ function abook_store_lowlevel($arr) {
'abook_profile' => ((array_key_exists('abook_profile',$arr)) ? $arr['abook_profile'] : ''),
'abook_incl' => ((array_key_exists('abook_incl',$arr)) ? $arr['abook_incl'] : ''),
'abook_excl' => ((array_key_exists('abook_excl',$arr)) ? $arr['abook_excl'] : ''),
- 'abook_instance' => ((array_key_exists('abook_instance',$arr)) ? $arr['abook_instance'] : '')
+ 'abook_instance' => ((array_key_exists('abook_instance',$arr)) ? $arr['abook_instance'] : ''),
+ 'abook_role' => ((array_key_exists('abook_role',$arr)) ? $arr['abook_role'] : '')
];
return create_table_from_array('abook',$store);
@@ -112,7 +114,7 @@ function vcard_from_xchan($xchan, $observer = null, $mode = '') {
// don't provide a connect button for transient or one-way identities
- if(in_array($xchan['xchan_network'],['rss','anon','unknown']) || strpos($xchan['xchan_addr'],'guest:') === 0) {
+ if(in_array($xchan['xchan_network'],['rss', 'anon', 'unknown', 'token'])) {
$connect = false;
}
@@ -284,17 +286,18 @@ function remove_all_xchan_resources($xchan, $channel_id = 0) {
$dirmode = intval(get_config('system','directory_mode'));
-
$r = q("delete from photo where xchan = '%s'",
dbesc($xchan)
);
+
$r = q("select resource_id, resource_type, uid, id from item where ( author_xchan = '%s' or owner_xchan = '%s' ) ",
dbesc($xchan),
dbesc($xchan)
);
+
if($r) {
foreach($r as $rr) {
- drop_item($rr,false);
+ drop_item($rr['id'],false);
}
}
@@ -375,52 +378,22 @@ function contact_remove($channel_id, $abook_id) {
if(intval($abook['abook_self']))
return false;
- $r = q("select id, parent from item where (owner_xchan = '%s' or author_xchan = '%s') and uid = %d and item_retained = 0 and item_starred = 0",
- dbesc($abook['abook_xchan']),
- dbesc($abook['abook_xchan']),
- intval($channel_id)
+ // if this is an atoken, delete the atoken record
+
+ $xchan = q("select * from xchan where xchan_hash = '%s'",
+ dbesc($abook['abook_xchan'])
);
- if($r) {
- $already_saved = [];
- foreach($r as $rr) {
- $w = $x = $y = null;
- // optimise so we only process newly seen parent items
- if (in_array($rr['parent'],$already_saved)) {
- continue;
- }
- // if this isn't the parent, fetch the parent's item_retained and item_starred to see if the conversation
- // should be retained
- if($rr['id'] != $rr['parent']) {
- $w = q("select id, item_retained, item_starred from item where id = %d",
- intval($rr['parent'])
- );
- if($w) {
- // see if the conversation was filed
- $x = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1",
- intval(TERM_OBJ_POST),
- intval($w[0]['id']),
- intval(TERM_FILE)
- );
- if (intval($w[0]['item_retained']) || intval($w[0]['item_starred']) || $x) {
- $already_saved[] = $rr['parent'];
- continue;
- }
- }
- }
- // see if this item was filed
- $y = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1",
- intval(TERM_OBJ_POST),
- intval($rr['id']),
- intval(TERM_FILE)
- );
- if ($y) {
- continue;
- }
- drop_item($rr['id'],false);
+ if (strpos($xchan['xchan_addr'],'guest:') === 0 && strpos($abook['abook_xchan'],'.')){
+ $atoken_guid = substr($abook['abook_xchan'],strrpos($abook['abook_xchan'],'.') + 1);
+ if ($atoken_guid) {
+ atoken_delete_and_sync($channel_id,$atoken_guid);
}
}
+ // remove items in the background as this can take some time
+ Master::Summon(['Delxitems', $channel_id, $abook['abook_xchan']]);
+
q("delete from abook where abook_id = %d and abook_channel = %d",
intval($abook['abook_id']),
intval($channel_id)
@@ -449,7 +422,62 @@ function contact_remove($channel_id, $abook_id) {
return true;
}
+function remove_abook_items($channel_id, $xchan_hash) {
+
+ $r = q("select id from item where (owner_xchan = '%s' or author_xchan = '%s') and uid = %d and item_retained = 0 and item_starred = 0",
+ dbesc($xchan_hash),
+ dbesc($xchan_hash),
+ intval($channel_id)
+ );
+ if (! $r) {
+ return;
+ }
+
+ $already_saved = [];
+ foreach ($r as $rr) {
+ $w = $x = $y = null;
+
+ // optimise so we only process newly seen parent items
+ if (in_array($rr['parent'], $already_saved)) {
+ continue;
+ }
+
+ // if this isn't the parent, fetch the parent's item_retained and item_starred to see if the conversation
+ // should be retained
+ if ($rr['id'] != $rr['parent']) {
+ $w = q("select id, item_retained, item_starred from item where id = %d",
+ intval($rr['parent'])
+ );
+
+ if ($w) {
+ // see if the conversation was filed
+ $x = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1",
+ intval(TERM_OBJ_POST),
+ intval($w[0]['id']),
+ intval(TERM_FILE)
+ );
+ if (intval($w[0]['item_retained']) || intval($w[0]['item_starred']) || $x) {
+ $already_saved[] = $rr['parent'];
+ continue;
+ }
+ }
+ }
+
+ // see if this item was filed
+ $y = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1",
+ intval(TERM_OBJ_POST),
+ intval($rr['id']),
+ intval(TERM_FILE)
+ );
+
+ if ($y) {
+ continue;
+ }
+
+ drop_item($rr['id'],false);
+ }
+}
function random_profile() {
$randfunc = db_getfunc('rand');
diff --git a/include/conversation.php b/include/conversation.php
index a7dfa6b73..17367856c 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -775,6 +775,12 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
$conv_link = ((in_array($item['item_type'],[ ITEM_TYPE_CARD, ITEM_TYPE_ARTICLE] )) ? $item['plink'] : z_root() . '/' . $conv_link_module . '/' . gen_link_id($conv_link_mid));
+ $contact = [];
+
+ if(App::$contacts && array_key_exists($item['author_xchan'],App::$contacts)) {
+ $contact = App::$contacts[$item['author_xchan']];
+ }
+
$tmp_item = array(
'template' => $tpl,
'toplevel' => 'toplevel_item',
@@ -838,7 +844,8 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
'wait' => t('Please wait'),
'thread_level' => 1,
'has_tags' => $has_tags,
- 'is_new' => $is_new
+ 'is_new' => $is_new,
+ 'contact_id' => (($contact) ? $contact['abook_id'] : '')
);
$arr = array('item' => $item, 'output' => $tmp_item);
@@ -1061,7 +1068,7 @@ function thread_author_menu($item, $mode = '') {
}
else {
$url = (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']);
- if($local_channel && $url && (! in_array($item['author']['xchan_network'],[ 'rss', 'anon','unknown', 'zot' ]))) {
+ if($local_channel && $url && (! in_array($item['author']['xchan_network'],[ 'rss', 'anon','unknown', 'zot', 'token']))) {
$follow_url = z_root() . '/follow/?f=&url=' . urlencode($url) . '&interactive=0';
}
}
@@ -1070,7 +1077,7 @@ function thread_author_menu($item, $mode = '') {
if($contact) {
$poke_link = ((Apps::system_app_installed($local_channel, 'Poke')) ? z_root() . '/poke/?f=&c=' . $contact['abook_id'] : '');
if (! intval($contact['abook_self']))
- $contact_url = z_root() . '/connedit/' . $contact['abook_id'];
+ $contact_url = z_root() . '/connections#' . $contact['abook_id'];
$posts_link = z_root() . '/network/?cid=' . $contact['abook_id'];
$clean_url = normalise_link($item['author-link']);
@@ -1086,7 +1093,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('View Profile'),
'icon' => 'fw',
'action' => '',
- 'href' => $profile_link
+ 'href' => $profile_link,
+ 'data' => '',
+ 'class' => ''
];
}
@@ -1096,7 +1105,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('Recent Activity'),
'icon' => 'fw',
'action' => '',
- 'href' => $posts_link
+ 'href' => $posts_link,
+ 'data' => '',
+ 'class' => ''
];
}
@@ -1107,6 +1118,8 @@ function thread_author_menu($item, $mode = '') {
'icon' => 'fw',
'action' => 'doFollowAuthor(\'' . $follow_url . '\'); return false;',
'href' => '#',
+ 'data' => '',
+ 'class' => ''
];
}
@@ -1116,7 +1129,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('Edit Connection'),
'icon' => 'fw',
'action' => '',
- 'href' => $contact_url
+ 'href' => $contact_url,
+ 'data' => 'data-id="' . $contact['abook_id'] . '"',
+ 'class' => 'contact-edit'
];
}
@@ -1126,7 +1141,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('Message'),
'icon' => 'fw',
'action' => '',
- 'href' => $pm_url
+ 'href' => $pm_url,
+ 'data' => '',
+ 'class' => ''
];
}
@@ -1136,7 +1153,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('Ratings'),
'icon' => 'fw',
'action' => '',
- 'href' => $ratings_url
+ 'href' => $ratings_url,
+ 'data' => '',
+ 'class' => ''
];
}
@@ -1146,7 +1165,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('Poke'),
'icon' => 'fw',
'action' => '',
- 'href' => $poke_link
+ 'href' => $poke_link,
+ 'data' => '',
+ 'class' => ''
];
}
diff --git a/include/group.php b/include/group.php
index bb1ed5ed8..4e1472900 100644
--- a/include/group.php
+++ b/include/group.php
@@ -326,7 +326,7 @@ function group_side($every="connections",$each="group",$edit = false, $group_id
$o = replace_macros($tpl, array(
'$title' => t('Privacy Groups'),
'$edittext' => t('Edit group'),
- '$createtext' => t('Add privacy group'),
+ '$createtext' => ((argv(1) == 'new' ) ? '' : t('Manage privacy groups')),
'$ungrouped' => (($every === 'contacts') ? t('Channels not in any privacy group') : ''),
'$groups' => $groups,
'$add' => t('add'),
diff --git a/include/import.php b/include/import.php
index 8707a9430..291dd2638 100644
--- a/include/import.php
+++ b/include/import.php
@@ -162,6 +162,64 @@ function import_config($channel, $configs) {
}
}
+function import_atoken($channel, $atokens) {
+ if ($channel && $atokens) {
+ foreach ($atokens as $atoken) {
+ unset($atoken['atoken_id']);
+ $atoken['atoken_aid'] = $channel['channel_account_id'];
+ $atoken['atoken_uid'] = $channel['channel_id'];
+ create_table_from_array('atoken', $atoken);
+ }
+ }
+}
+
+function sync_atoken($channel, $atokens) {
+
+ if ($channel && $atokens) {
+ foreach ($atokens as $atoken) {
+ unset($atoken['atoken_id']);
+ $atoken['atoken_aid'] = $channel['channel_account_id'];
+ $atoken['atoken_uid'] = $channel['channel_id'];
+
+ if ($atoken['deleted']) {
+ q("delete from atoken where atoken_uid = %d and atoken_guid = '%s' ",
+ intval($atoken['atoken_uid']),
+ dbesc($atoken['atoken_guid'])
+ );
+ continue;
+ }
+
+ $r = q("select * from atoken where atoken_uid = %d and atoken_guid = '%s' ",
+ intval($atoken['atoken_uid']),
+ dbesc($atoken['atoken_guid'])
+ );
+ if (! $r) {
+ create_table_from_array('atoken', $atoken);
+ }
+ else {
+ $columns = db_columns('atoken');
+ foreach ($atoken as $k => $v) {
+ if (! in_array($k,$columns)) {
+ continue;
+ }
+
+ if (in_array($k, ['atoken_guid','atoken_uid','atoken_aid'])) {
+ continue;
+ }
+
+ $r = q("UPDATE atoken SET " . TQUOT . "%s" . TQUOT . " = '%s' WHERE atoken_guid = '%s' AND atoken_uid = %d",
+ dbesc($k),
+ dbesc($v),
+ dbesc($atoken['atoken_guid']),
+ intval($channel['channel_id'])
+ );
+ }
+ }
+ }
+ }
+}
+
+
/**
* @brief Import profiles.
*
diff --git a/include/items.php b/include/items.php
index 2ee870c2f..7a899a3fd 100644
--- a/include/items.php
+++ b/include/items.php
@@ -13,9 +13,10 @@ use Zotlabs\Lib\IConfig;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\PermissionRoles;
-use Zotlabs\Access\AccessList;
+use Zotlabs\Lib\AccessList;
use Zotlabs\Daemon\Master;
require_once('include/bbcode.php');
@@ -35,8 +36,6 @@ require_once('include/permissions.php');
*/
function collect_recipients($item, &$private_envelope,$include_groups = true) {
- require_once('include/group.php');
-
$private_envelope = ((intval($item['item_private'])) ? true : false);
$recipients = array();
@@ -47,7 +46,7 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) {
$allow_people = expand_acl($item['allow_cid']);
if($include_groups) {
- $allow_groups = expand_groups(expand_acl($item['allow_gid']));
+ $allow_groups = AccessList::expand(expand_acl($item['allow_gid']));
}
else {
$allow_groups = [];
@@ -72,7 +71,7 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) {
}
$deny_people = expand_acl($item['deny_cid']);
- $deny_groups = expand_groups(expand_acl($item['deny_gid']));
+ $deny_groups = AccessList::expand(expand_acl($item['deny_gid']));
$deny = array_unique(array_merge($deny_people,$deny_groups));
@@ -344,6 +343,7 @@ function can_comment_on_post($observer_xchan, $item) {
return true;
break;
case 'any connections':
+ case 'specific':
case 'contacts':
case '':
if(local_channel() && get_abconfig(local_channel(),$item['owner_xchan'],'their_perms','post_comments')) {
@@ -476,7 +476,7 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
$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'] . '/' . (filter_var($arr['mid'], FILTER_VALIDATE_URL) === false ? '?f=&mid=' : '') . urlencode($arr['mid']),0,190);
+ $arr['plink'] = $arr['mid'];
}
@@ -1226,6 +1226,9 @@ function map_scope($scope, $strip = false) {
return 'site: ' . App::get_hostname();
case PERMS_PENDING:
return 'any connections';
+// uncomment after Hubzilla version 7.0 is running on the majority of active hubs
+// case PERMS_SPECIFIC:
+// return 'specific';
case PERMS_CONTACTS:
default:
return 'contacts';
@@ -2537,12 +2540,7 @@ function get_item_contact($item,$contacts) {
*/
function tag_deliver($uid, $item_id) {
- $role = get_pconfig($uid,'system','permissions_role');
- $rolesettings = PermissionRoles::role_perms($role);
- $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal';
-
- $is_group = (($channel_type === 'group') ? true : false);
-
+ $is_group = get_pconfig($uid, 'system', 'group_actor');
$mention = false;
/*
@@ -2579,15 +2577,18 @@ function tag_deliver($uid, $item_id) {
}
if ($is_group && intval($item['item_private']) === 2 && intval($item['item_thread_top'])) {
-
// do not turn the groups own direkt messages into group items
if($item['item_wall'] && $item['author_xchan'] === $u[0]['channel_hash'])
return;
// group delivery via DM
- if(perm_is_allowed($uid,$item['owner_xchan'],'post_wall') || perm_is_allowed($uid,$item['owner_xchan'],'tag_deliver')) {
+ if(perm_is_allowed($uid,$item['owner_xchan'],'post_wall')) {
logger('group DM delivery for ' . $u[0]['channel_address']);
start_delivery_chain($u[0], $item, $item_id, 0, true, (($item['edited'] != $item['created']) || $item['item_deleted']));
+ q("update item set item_blocked = %d where id = %d",
+ intval(ITEM_HIDDEN),
+ intval($item_id)
+ );
}
return;
}
@@ -2600,13 +2601,6 @@ function tag_deliver($uid, $item_id) {
return;
}
- /* this should not be required anymore due to the check above
- if (strpos($item['body'],'[/share]')) {
- logger('W2W post already shared');
- return;
- }
- */
-
// group delivery via W2W
logger('rewriting W2W post for ' . $u[0]['channel_address']);
start_delivery_chain($u[0], $item, $item_id, 0, true, (($item['edited'] != $item['created']) || $item['item_deleted']));
@@ -2677,9 +2671,37 @@ function tag_deliver($uid, $item_id) {
intval($uid)
);
- if(($x) && intval($x[0]['item_uplink'])) {
- start_delivery_chain($u[0],$item,$item_id,$x[0]);
+ if ($x) {
+
+ // group comments don't normally require a second delivery chain
+ // but we create a linked Announce so they will show up in the home timeline
+ // on microblog platforms and this creates a second delivery chain
+
+ if ($is_group && intval($x[0]['item_wall'])) {
+ // don't let the forked delivery chain recurse
+ if ($item['verb'] === 'Announce' && $item['author_xchan'] === $u['channel_hash']) {
+ return;
+ }
+ // don't announce moderated content until it has been approved
+ if (intval($item['item_blocked']) === ITEM_MODERATED) {
+ return;
+ }
+
+ // don't boost likes and other response activities as it is likely that
+ // few platforms will handle this in an elegant way
+
+ if (ActivityStreams::is_response_activity($item['verb'])) {
+ return;
+ }
+ logger('group_comment');
+ start_delivery_chain($u[0], $item, $item_id, $x[0], true, (($item['edited'] != $item['created']) || $item['item_deleted']));
+
+ }
+ elseif (intval($x[0]['item_uplink'])) {
+ start_delivery_chain($u,$item,$item_id,$x[0]);
+ }
}
+
}
@@ -2920,13 +2942,7 @@ function item_community_tag($channel,$item) {
*/
function tgroup_check($uid, $item) {
-
- $role = get_pconfig($uid,'system','permissions_role');
- $rolesettings = PermissionRoles::role_perms($role);
- $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal';
-
- $is_group = (($channel_type === 'group') ? true : false);
-
+ $is_group = get_pconfig($uid, 'system', 'group_actor');
$mention = false;
// check that the message originated elsewhere and is a top-level post
@@ -3125,6 +3141,10 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$arr = [];
+ q("update item set item_hidden = 1 where id = %d",
+ intval($item_id)
+ );
+
if ($edit) {
// process edit or delete action
@@ -3155,7 +3175,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
}
else {
$arr['uuid'] = item_message_id();
- $arr['mid'] = z_root() . '/activity/' . $arr['uuid'];
+ $arr['mid'] = z_root() . '/item/' . $arr['uuid'];
$arr['parent_mid'] = $arr['mid'];
}
@@ -3173,6 +3193,10 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$arr['item_private'] = (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
|| $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0);
+ if ($channel['channel_allow_cid'] && empty($channel['channel_allow_gid'])) {
+ $arr['item_private'] = 2;
+ }
+
$arr['item_origin'] = 1;
$arr['item_wall'] = 1;
$arr['item_thread_top'] = 1;
@@ -3192,6 +3216,29 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$bb .= "[/share]";
$arr['body'] = $bb;
+ // Conversational objects shouldn't be copied, but other objects should.
+ if (in_array($item['obj_type'], [ 'Image', 'Event', 'Question' ])) {
+ $arr['obj'] = $item['obj'];
+ $t = json_decode($arr['obj'],true);
+
+ if ($t !== NULL) {
+ $arr['obj'] = $t;
+ }
+ $arr['obj']['content'] = bbcode($bb);
+ $arr['obj']['source']['content'] = $bb;
+ $arr['obj']['id'] = $arr['mid'];
+
+ if (! array_path_exists('obj/source/mediaType',$arr)) {
+ $arr['obj']['source']['mediaType'] = 'text/bbcode';
+ }
+
+ $arr['obj']['directMessage'] = (intval($arr['item_private']) === 2);
+
+ }
+
+ $arr['tgt_type'] = $item['tgt_type'];
+ $arr['target'] = $item['target'];
+
$arr['term'] = $item['term'];
$arr['author_xchan'] = $channel['channel_hash'];
@@ -3222,6 +3269,92 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
}
+ if ($group && $parent) {
+ logger('comment arrived in group', LOGGER_DEBUG);
+ $arr = [];
+
+ // don't let this recurse. We checked for this before calling, but this ensures
+ // it doesn't sneak through another way because recursion is nasty.
+
+ if ($item['verb'] === 'Announce' && $item['author_xchan'] === $channel['channel_hash']) {
+ return;
+ }
+
+ // Don't send Announce activities for poll responses.
+
+ if ($item['obj_type'] === 'Answer') {
+ return;
+ }
+
+ if ($edit) {
+ if (intval($item['item_deleted'])) {
+ drop_item($item['id'],false,DROPITEM_PHASE1);
+ Master::Summon([ 'Notifier','drop',$item['id'] ]);
+ return;
+ }
+ return;
+ }
+ else {
+ $arr['uuid'] = item_message_id();
+ $arr['mid'] = z_root() . '/activity/' . $arr['uuid'];
+ $arr['parent_mid'] = $item['parent_mid'];
+ //IConfig::Set($arr,'activitypub','context', str_replace('/item/','/conversation/',$item['parent_mid']));
+ }
+ $arr['aid'] = $channel['channel_account_id'];
+ $arr['uid'] = $channel['channel_id'];
+
+ $arr['verb'] = 'Announce';
+
+ if (is_array($item['obj'])) {
+ $arr['obj'] = $item['obj'];
+ }
+ elseif (is_string($item['obj']) && strlen($item['obj'])) {
+ $arr['obj'] = json_decode($item['obj'],true);
+ }
+
+ if (! $arr['obj']) {
+ $arr['obj'] = $item['mid'];
+ }
+
+ if (is_array($arr['obj'])) {
+ $obj_actor = ((isset($arr['obj']['actor'])) ? ((is_array($arr['obj']['actor'])) ? $arr['obj']['actor']['id'] : $arr['obj']['actor']) : $arr['obj']['attributedTo']);
+ $mention = Activity::get_actor_bbmention($obj_actor);
+ $arr['body'] = sprintf( t('&#x1f501; Repeated %1$s\'s %2$s'), $mention, $arr['obj']['type']);
+ }
+
+ $arr['author_xchan'] = $channel['channel_hash'];
+
+ $arr['item_wall'] = 1;
+
+ $arr['item_private'] = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0);
+
+ $arr['item_origin'] = 1;
+ $arr['item_notshown'] = 1;
+
+ $arr['item_thread_top'] = 0;
+
+ $arr['allow_cid'] = $channel['channel_allow_cid'];
+ $arr['allow_gid'] = $channel['channel_allow_gid'];
+ $arr['deny_cid'] = $channel['channel_deny_cid'];
+ $arr['deny_gid'] = $channel['channel_deny_gid'];
+ $arr['comment_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments'));
+
+ $post = item_store($arr);
+ $post_id = $post['item_id'];
+
+ if ($post_id) {
+ Master::Summon([ 'Notifier','tgroup',$post_id ]);
+ }
+
+ q("update channel set channel_lastpost = '%s' where channel_id = %d",
+ dbesc(datetime_convert()),
+ intval($channel['channel_id'])
+ );
+
+ return;
+ }
+
+
// Change this copy of the post to a forum head message and deliver to all the tgroup members
// also reset all the privacy bits to the forum default permissions
@@ -3510,12 +3643,11 @@ function compare_permissions($obj1,$obj2) {
* @return array
*/
function enumerate_permissions($obj) {
- require_once('include/group.php');
$allow_people = expand_acl($obj['allow_cid']);
- $allow_groups = expand_groups(expand_acl($obj['allow_gid']));
+ $allow_groups = AccessList::expand(expand_acl($obj['allow_gid']));
$deny_people = expand_acl($obj['deny_cid']);
- $deny_groups = expand_groups(expand_acl($obj['deny_gid']));
+ $deny_groups = AccessList::expand(expand_acl($obj['deny_gid']));
$recipients = array_unique(array_merge($allow_people,$allow_groups));
$deny = array_unique(array_merge($deny_people,$deny_groups));
$recipients = array_diff($recipients,$deny);
@@ -4252,7 +4384,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$contact_str = '';
- $contacts = group_get_members($r[0]['id']);
+ $contacts = AccessList::members($uid, $r[0]['id']);
if ($contacts) {
foreach($contacts as $c) {
if($contact_str)
@@ -4268,7 +4400,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str)) or allow_gid like '" . protect_sprintf('%<' . dbesc($r[0]['hash']) . '>%') . "' ) and id = parent $item_normal ) ";
- $x = group_rec_byhash($uid,$r[0]['hash']);
+ $x = AccessList::by_hash($uid, $r[0]['hash']);
$result['headline'] = sprintf( t('Privacy group: %s'),$x['gname']);
}
elseif($arr['cid'] && $uid) {
@@ -4640,8 +4772,9 @@ function send_profile_photo_activity($channel,$photo,$profile) {
$arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext;
- $acl = new AccessList($channel);
+ $acl = new Zotlabs\Access\AccessList($channel);
$x = $acl->get();
+
$arr['allow_cid'] = $x['allow_cid'];
$arr['allow_gid'] = $x['allow_gid'];
diff --git a/include/nav.php b/include/nav.php
index 7cc64ab1b..9278c1587 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -26,7 +26,7 @@ function nav($template = 'default') {
intval($channel['channel_id'])
);
- if (empty($_SESSION['delegate'])) {
+ if (empty($_SESSION['delegate']) && feature_enabled(local_channel(), 'nav_channel_select')) {
$chans = q("select channel_name, channel_id from channel where channel_account_id = %d and channel_removed = 0 order by channel_name ",
intval(get_account_id())
);
@@ -97,13 +97,11 @@ function nav($template = 'default') {
if (empty($_SESSION['delegate'])) {
$nav['manage'] = ['manage', t('Channels'), "", t('Manage your channels'), 'manage_nav_btn'];
}
- if (Apps::system_app_installed(local_channel(), 'Privacy Groups'))
- $nav['group'] = ['group', t('Privacy Groups'), "", t('Manage your privacy groups'), 'group_nav_btn'];
$nav['settings'] = ['settings', t('Settings'), "", t('Account/Channel Settings'), 'settings_nav_btn'];
- if ($chans && count($chans) > 1 && feature_enabled(local_channel(), 'nav_channel_select'))
+ if ($chans && count($chans) > 1)
$nav['channels'] = $chans;
$nav['logout'] = ['logout', t('Logout'), "", t('End this session'), 'logout_nav_btn'];
diff --git a/include/permissions.php b/include/permissions.php
index d94b70da6..c3a9286c0 100644
--- a/include/permissions.php
+++ b/include/permissions.php
@@ -21,7 +21,7 @@ require_once('include/security.php');
* @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
+ * @returns array of all permissions, key is permission name, value is 1 or 0
*/
function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ignored = true) {
@@ -61,7 +61,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// The uid provided doesn't exist. This would be a big fail.
if(! $r) {
- $ret[$perm_name] = false;
+ $ret[$perm_name] = 0;
continue;
}
@@ -70,7 +70,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if($observer_xchan) {
if($channel_perm & PERMS_AUTHED) {
- $ret[$perm_name] = true;
+ $ret[$perm_name] = 1;
continue;
}
@@ -80,23 +80,6 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
intval($uid),
dbesc($observer_xchan)
);
- if(! $x) {
- // see if they've got a guest access token; these are treated as connections
- $y = atoken_abook($uid,$observer_xchan);
- if($y)
- $x = array($y);
-
- if(! $x) {
- // not in address book and no guest token, see if they've got an xchan
- // these *may* have individual (PERMS_SPECIFIC) permissions, but are not connections
- $y = q("select xchan_network from xchan where xchan_hash = '%s' limit 1",
- dbesc($observer_xchan)
- );
- if($y) {
- $x = array(pseudo_abook($y[0]));
- }
- }
- }
$abook_checked = true;
}
@@ -104,7 +87,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// If they're blocked - they can't read or write
if(($x) && intval($x[0]['abook_blocked'])) {
- $ret[$perm_name] = false;
+ $ret[$perm_name] = 0;
continue;
}
@@ -115,7 +98,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if(($x) && ($default_ignored) && in_array($perm_name,$blocked_anon_perms) && intval($x[0]['abook_ignored'])) {
- $ret[$perm_name] = false;
+ $ret[$perm_name] = 0;
continue;
}
}
@@ -123,7 +106,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// system is blocked to anybody who is not authenticated
if(($check_siteblock) && (! $observer_xchan) && intval(get_config('system', 'block_public'))) {
- $ret[$perm_name] = false;
+ $ret[$perm_name] = 0;
continue;
}
@@ -133,16 +116,16 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if(($observer_xchan) && ($r[0]['channel_hash'] === $observer_xchan)) {
if($r[0]['channel_moved'] && (in_array($perm_name,$blocked_anon_perms)))
- $ret[$perm_name] = false;
+ $ret[$perm_name] = 0;
else
- $ret[$perm_name] = true;
+ $ret[$perm_name] = 1;
continue;
}
// Anybody at all (that wasn't blocked or ignored). They have permission.
if($channel_perm & PERMS_PUBLIC) {
- $ret[$perm_name] = true;
+ $ret[$perm_name] = 1;
continue;
}
@@ -150,7 +133,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// out, permission is denied.
if(! $observer_xchan) {
- $ret[$perm_name] = false;
+ $ret[$perm_name] = 0;
continue;
}
@@ -158,7 +141,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if($channel_perm & PERMS_NETWORK) {
if($x && $x[0]['xchan_network'] === 'zot6') {
- $ret[$perm_name] = true;
+ $ret[$perm_name] = 1;
continue;
}
}
@@ -175,9 +158,9 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
}
if($c)
- $ret[$perm_name] = true;
+ $ret[$perm_name] = 1;
else
- $ret[$perm_name] = false;
+ $ret[$perm_name] = 0;
continue;
}
@@ -186,19 +169,19 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// handle whether we're allowing any, approved or specific ones
if(! $x) {
- $ret[$perm_name] = false;
+ $ret[$perm_name] = 0;
continue;
}
// They are in your address book, but haven't been approved
if($channel_perm & PERMS_PENDING && (! intval($x[0]['abook_pseudo']))) {
- $ret[$perm_name] = true;
+ $ret[$perm_name] = 1;
continue;
}
if(intval($x[0]['abook_pending'])) {
- $ret[$perm_name] = false;
+ $ret[$perm_name] = 0;
continue;
}
@@ -207,11 +190,11 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if($channel_perm & PERMS_CONTACTS) {
// it was a fake abook entry, not really a connection
if(array_key_exists('abook_pseudo',$x[0]) && intval($x[0]['abook_pseudo'])) {
- $ret[$perm_name] = false;
+ $ret[$perm_name] = 0;
continue;
}
- $ret[$perm_name] = true;
+ $ret[$perm_name] = 1;
continue;
}
@@ -221,7 +204,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if($abperms) {
foreach($abperms as $ab) {
if(($ab['cat'] == 'my_perms') && ($ab['k'] == $perm_name)) {
- $ret[$perm_name] = (intval($ab['v']) ? true : false);
+ $ret[$perm_name] = (intval($ab['v']) ? 1 : 0);
break;
}
}
@@ -231,7 +214,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// No permissions allowed.
- $ret[$perm_name] = false;
+ $ret[$perm_name] = 0;
continue;
}
@@ -309,32 +292,6 @@ function perm_is_allowed($uid, $observer_xchan, $permission, $check_siteblock =
if(($x) && in_array($permission,$blocked_anon_perms) && intval($x[0]['abook_ignored']))
return false;
- if(! $x) {
- // see if they've got a guest access token
- $y = atoken_abook($uid,$observer_xchan);
- if($y)
- $x = array($y);
-
- if(! $x) {
- // not in address book and no guest token, see if they've got an xchan
-
- $y = q("select xchan_network from xchan where xchan_hash = '%s' limit 1",
- dbesc($observer_xchan)
- );
- if($y) {
-
- // This requires an explanation and the effects are subtle.
- // The following line creates a fake connection, and this allows
- // access tokens to have specific permissions even though they are
- // not actual connections.
- // The existence of this fake entry must be checked when dealing
- // with connection related permissions.
-
- $x = array(pseudo_abook($y[0]));
- }
- }
-
- }
$abperms = load_abconfig($uid,$observer_xchan,'my_perms');
}
diff --git a/include/plugin.php b/include/plugin.php
index 5b041f228..95c9882d0 100644
--- a/include/plugin.php
+++ b/include/plugin.php
@@ -742,7 +742,9 @@ function get_theme_info($theme){
'credits' => '',
'maintainer' => array(),
'experimental' => false,
- 'unsupported' => false
+ 'unsupported' => false,
+ 'theme_color' => '',
+ 'background_color' => ''
);
if(file_exists("view/theme/$theme/experimental"))
diff --git a/include/security.php b/include/security.php
index b6c0f1511..881adb818 100644
--- a/include/security.php
+++ b/include/security.php
@@ -89,8 +89,20 @@ function authenticate_success($user_record, $channel = null, $login_initial = fa
}
function atoken_login($atoken) {
- if (!$atoken)
+ if (! $atoken) {
return false;
+ }
+
+ if (App::$cmd === 'channel' && argv(1)) {
+ $channel = channelx_by_nick(argv(1));
+ if (perm_is_allowed($channel['channel_id'],$atoken['xchan_hash'],'delegate')) {
+ $_SESSION['delegate_channel'] = $channel['channel_id'];
+ $_SESSION['delegate'] = $atoken['xchan_hash'];
+ $_SESSION['account_id'] = intval($channel['channel_account_id']);
+ change_channel($channel['channel_id']);
+ return;
+ }
+ }
$_SESSION['authenticated'] = 1;
$_SESSION['visitor_id'] = $atoken['xchan_hash'];
@@ -113,11 +125,11 @@ function atoken_xchan($atoken) {
if ($c) {
return [
'atoken_id' => $atoken['atoken_id'],
- 'xchan_hash' => substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_name'],
+ 'xchan_hash' => substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_guid'],
'xchan_name' => $atoken['atoken_name'],
'xchan_addr' => 'guest:' . $atoken['atoken_name'] . '@' . App::get_hostname(),
- 'xchan_network' => 'unknown',
- 'xchan_url' => z_root() . '/guest/' . substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_name'],
+ 'xchan_network' => 'token',
+ 'xchan_url' => z_root() . '/guest/' . substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_guid'],
'xchan_hidden' => 1,
'xchan_photo_mimetype' => 'image/png',
'xchan_photo_l' => z_root() . '/' . get_default_profile_photo(300),
@@ -143,15 +155,25 @@ function atoken_delete($atoken_id) {
if (!$c)
return;
- $atoken_xchan = substr($c[0]['channel_hash'], 0, 16) . '.' . $r[0]['atoken_name'];
+ $atoken_xchan = substr($c[0]['channel_hash'], 0, 16) . '.' . $r[0]['atoken_guid'];
q("delete from atoken where atoken_id = %d",
intval($atoken_id)
);
+
+ q("delete from abook where abook_channel = %d and abook_xchan = '%s'",
+ intval($c[0]['channel_id']),
+ dbesc($atoken_xchan)
+ );
+
q("delete from abconfig where chan = %d and xchan = '%s'",
intval($c[0]['channel_id']),
dbesc($atoken_xchan)
);
+
+ q("update xchan set xchan_deleted = 1 where xchan_hash = '%s'",
+ dbesc($atoken_xchan)
+ );
}
/**
@@ -198,7 +220,7 @@ function atoken_abook($uid, $xchan_hash) {
if (!$r)
return false;
- $x = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'",
+ $x = q("select * from atoken where atoken_uid = %d and atoken_guid = '%s'",
intval($uid),
dbesc(substr($xchan_hash, 17))
);
diff --git a/include/selectors.php b/include/selectors.php
index 71e2a387d..57a9db480 100644
--- a/include/selectors.php
+++ b/include/selectors.php
@@ -1,7 +1,7 @@
<?php /** @file */
-function contact_profile_assign($current) {
+function contact_profile_assign($current, $label = '') {
$r = q("SELECT profile_guid, profile_name FROM profile WHERE uid = %d",
intval($_SESSION['uid'])
@@ -13,9 +13,13 @@ function contact_profile_assign($current) {
}
}
+ if (!$label) {
+ $label = t('Select a profile to assign to this contact');
+ }
+
$select = [
'profile_assign',
- t('Profile to assign new connections'),
+ $label,
$current,
'',
$options
@@ -70,7 +74,7 @@ function gender_selector($current="",$suffix="") {
}
$o .= '</select>';
return $o;
-}
+}
function gender_selector_min($current="",$suffix="") {
$o = '';
@@ -87,7 +91,7 @@ function gender_selector_min($current="",$suffix="") {
}
$o .= '</select>';
return $o;
-}
+}
@@ -107,7 +111,7 @@ function sexpref_selector($current="",$suffix="") {
}
$o .= '</select>';
return $o;
-}
+}
function sexpref_selector_min($current="",$suffix="") {
@@ -125,7 +129,7 @@ function sexpref_selector_min($current="",$suffix="") {
}
$o .= '</select>';
return $o;
-}
+}
@@ -144,7 +148,7 @@ function marital_selector($current="",$suffix="") {
}
$o .= '</select>';
return $o;
-}
+}
function marital_selector_min($current="",$suffix="") {
$o = '';
@@ -161,5 +165,5 @@ function marital_selector_min($current="",$suffix="") {
}
$o .= '</select>';
return $o;
-}
+}
diff --git a/include/text.php b/include/text.php
index d46c089b5..666d90838 100644
--- a/include/text.php
+++ b/include/text.php
@@ -12,6 +12,7 @@ use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Zotlabs\Lib\Crypto;
use Zotlabs\Lib\SvgSanitizer;
use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\AccessList;
require_once("include/bbcode.php");
@@ -864,6 +865,7 @@ function get_tags($s) {
// ignore anything in a code or svg block
$s = preg_replace('/\[code(.*?)\](.*?)\[\/code\]/sm','',$s);
$s = preg_replace('/\[svg(.*?)\](.*?)\[\/svg\]/sm','',$s);
+ $s = preg_replace('/\[toc(.*?)\]/sm','',$s);
// ignore anything in [style= ]
$s = preg_replace('/\[style=(.*?)\]/sm','',$s);
@@ -994,7 +996,7 @@ function contact_block() {
$is_owner = ((local_channel() && local_channel() == App::$profile['uid']) ? true : false);
$sql_extra = '';
- $abook_flags = " and abook_pending = 0 and abook_self = 0 ";
+ $abook_flags = " and abook_pending = 0 and abook_self = 0 and abook_blocked = 0 and abook_ignored = 0 ";
if(! $is_owner) {
$abook_flags .= " and abook_hidden = 0 ";
@@ -1008,56 +1010,58 @@ function contact_block() {
$abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra",
intval(App::$profile['uid'])
);
+
if(count($r)) {
$total = intval($r[0]['total']);
}
+
if(! $total) {
- $contacts = t('No connections');
- $micropro = null;
- } else {
+ return $o;
+ }
- $randfunc = db_getfunc('RAND');
+ $randfunc = db_getfunc('RAND');
- $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash WHERE abook_channel = %d $abook_flags and abook_archived = 0 and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra ORDER BY $randfunc LIMIT %d",
- intval(App::$profile['uid']),
- intval($shown)
- );
+ $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash WHERE abook_channel = %d $abook_flags and abook_archived = 0 and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra ORDER BY $randfunc LIMIT %d",
+ intval(App::$profile['uid']),
+ intval($shown)
+ );
- if(count($r)) {
- $contacts = t('Connections');
- $micropro = [];
- foreach($r as $rr) {
-
- // There is no setting to discover if you are bi-directionally connected
- // Use the ability to post comments as an indication that this relationship is more
- // than wishful thinking; even though soapbox channels and feeds will disable it.
- $rr['perminfo']['connpermcount']=0;
- $rr['perminfo']['connperms']=t('Accepts').': ';
- if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) {
- $rr['perminfo']['connpermcount']++;
- $rr['perminfo']['connperms'] .= t('Comments');
- }
- if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','send_stream'))) {
- $rr['perminfo']['connpermcount']++;
- $rr['perminfo']['connperms'] = ($rr['perminfo']['connperms']) ? $rr['perminfo']['connperms'] . ', ' : $rr['perminfo']['connperms'] ;
- $rr['perminfo']['connperms'] .= t('Stream items');
- }
- if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_wall'))) {
- $rr['perminfo']['connpermcount']++;
- $rr['perminfo']['connperms'] = ($rr['perminfo']['connperms']) ? $rr['perminfo']['connperms'] . ', ' : $rr['perminfo']['connperms'] ;
- $rr['perminfo']['connperms'] .= t('Wall posts');
- }
+ if(! $r) {
+ return $o;
+ }
- if ($rr['perminfo']['connpermcount'] == 0) {
- $rr['perminfo']['connperms'] .= t('Nothing');
- }
+ $contacts = t('Connections');
+ $micropro = [];
+ foreach($r as $rr) {
- if(!$is_owner && $rr['perminfo']['connpermcount'] !== 0)
- unset($rr['perminfo']);
+ // There is no setting to discover if you are bi-directionally connected
+ // Use the ability to post comments as an indication that this relationship is more
+ // than wishful thinking; even though soapbox channels and feeds will disable it.
+ $rr['perminfo']['connpermcount']=0;
+ $rr['perminfo']['connperms']=t('Accepts').': ';
+ if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) {
+ $rr['perminfo']['connpermcount']++;
+ $rr['perminfo']['connperms'] .= t('Comments');
+ }
+ if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','send_stream'))) {
+ $rr['perminfo']['connpermcount']++;
+ $rr['perminfo']['connperms'] = ($rr['perminfo']['connperms']) ? $rr['perminfo']['connperms'] . ', ' : $rr['perminfo']['connperms'] ;
+ $rr['perminfo']['connperms'] .= t('Stream items');
+ }
+ if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_wall'))) {
+ $rr['perminfo']['connpermcount']++;
+ $rr['perminfo']['connperms'] = ($rr['perminfo']['connperms']) ? $rr['perminfo']['connperms'] . ', ' : $rr['perminfo']['connperms'] ;
+ $rr['perminfo']['connperms'] .= t('Wall posts');
+ }
- $micropro[] = micropro($rr,true,'mpfriend');
- }
+ if ($rr['perminfo']['connpermcount'] == 0) {
+ $rr['perminfo']['connperms'] .= t('Nothing');
}
+
+ if(!$is_owner && $rr['perminfo']['connpermcount'] !== 0)
+ unset($rr['perminfo']);
+
+ $micropro[] = micropro($rr,true,'mpfriend');
}
$tpl = get_markup_template('contact_block.tpl');
@@ -1714,7 +1718,7 @@ function prepare_body(&$item,$attach = false,$opts = false) {
if ($is_photo) {
$object = json_decode($item['obj'],true);
$ptr = null;
- if (array_key_exists('url',$object) && is_array($object['url'])) {
+ if (is_array($object) && array_key_exists('url',$object) && is_array($object['url'])) {
if (array_key_exists(0,$object['url'])) {
foreach ($object['url'] as $link) {
if(array_key_exists('width',$link) && $link['width'] >= 640 && $link['width'] <= 1024) {
@@ -1753,6 +1757,7 @@ function prepare_body(&$item,$attach = false,$opts = false) {
}
}
+
$poll = (($item['obj_type'] === 'Question' && in_array($item['verb'],[ ACTIVITY_POST, ACTIVITY_UPDATE, ACTIVITY_SHARE ])) ? format_poll($item, $s, $opts) : false);
if ($poll) {
$s = $poll;
@@ -1854,17 +1859,29 @@ function format_poll($item,$s,$opts) {
return EMPTY_STR;
}
- $commentable = can_comment_on_post(((local_channel()) ? get_observer_hash() : EMPTY_STR),$item);
+ $commentable = can_comment_on_post(((local_channel()) ? get_observer_hash() : EMPTY_STR), $item);
+
+ $activated = ((local_channel() && local_channel() == $item['uid'] && get_observer_hash() !== $item['owner_xchan']) ? true : false);
+ $output = $s;
- //logger('format_poll: ' . print_r($item,true));
- $activated = ((local_channel() && local_channel() == $item['uid']) ? true : false);
- $output = $s . EOL. EOL;
+ if (strpos($item['body'], '[/share]') !== false) {
+ $output = substr($output, 0, -12);
+ }
+
+ $output .= EOL . EOL;
if ($act['type'] === 'Question') {
if ($activated and $commentable) {
$output .= '<form id="question-form-' . $item['id'] . '" >';
}
if (array_key_exists('anyOf',$act) && is_array($act['anyOf'])) {
+ $totalResponses = 0;
+ foreach ($act['anyOf'] as $poll) {
+ if (array_path_exists('replies/totalItems',$poll)) {
+ $totalResponses += intval($poll['replies']['totalItems']);
+ }
+ }
+
foreach ($act['anyOf'] as $poll) {
if (array_key_exists('name',$poll) && $poll['name']) {
$text = html2plain(purify_html($poll['name']),256);
@@ -1875,15 +1892,34 @@ function format_poll($item,$s,$opts) {
$total = 0;
}
if ($activated && $commentable) {
- $output .= '<input type="checkbox" name="answer[]" value="' . htmlspecialchars($text) . '"> ' . $text . '</input>' . ' (' . $total . ')' . EOL;
+ //$output .= '<input type="checkbox" name="answer[]" value="' . htmlspecialchars($text) . '"> ' . $text . '</input>' . ' (' . $total . ')' . EOL;
+
+ $output .= '<input type="checkbox" name="answer[]" value="' . htmlspecialchars($text) . '">&nbsp;&nbsp;<strong>' . $text . '</strong>' . EOL;
+ $output .= '<div class="progress bg-secondary bg-opacity-25" style="height: 3px;">';
+ $output .= '<div class="progress-bar bg-info" role="progressbar" style="width: ' . (($totalResponses) ? intval($total / $totalResponses * 100) : 0). '%;" aria-valuenow="" aria-valuemin="0" aria-valuemax="100"></div>';
+ $output .= '</div>';
+ $output .= '<div class="text-muted"><small>' . sprintf(tt('%d Vote', '%d Votes', $total, 'noun'), $total) . '&nbsp;|&nbsp;' . (($totalResponses) ? intval($total / $totalResponses * 100) . '%' : '0%') . '</small></div>';
+ $output .= EOL;
}
else {
- $output .= '[ ] ' . $text . ' (' . $total . ')' . EOL;
+ //$output .= '[ ] ' . $text . ' (' . $total . ')' . EOL;
+ $output .= '<input type="checkbox" name="answer[]" value="' . htmlspecialchars($text) . '" disabled="disabled">&nbsp;&nbsp;<strong>' . $text . '</strong>' . EOL;
+ $output .= '<div class="progress bg-secondary bg-opacity-25" style="height: 3px;">';
+ $output .= '<div class="progress-bar bg-info" role="progressbar" style="width: ' . (($totalResponses) ? intval($total / $totalResponses * 100) : 0) . '%;" aria-valuenow="" aria-valuemin="0" aria-valuemax="100"></div>';
+ $output .= '</div>';
+ $output .= '<div class="text-muted"><small>' . sprintf(tt('%d Vote', '%d Votes', $total, 'noun'), $total) . '&nbsp;|&nbsp;' . (($totalResponses) ? intval($total / $totalResponses * 100) . '%' : '0%') . '</small></div>';
+ $output .= EOL;
}
}
}
}
if (array_key_exists('oneOf',$act) && is_array($act['oneOf'])) {
+ $totalResponses = 0;
+ foreach ($act['oneOf'] as $poll) {
+ if (array_path_exists('replies/totalItems',$poll)) {
+ $totalResponses += intval($poll['replies']['totalItems']);
+ }
+ }
foreach ($act['oneOf'] as $poll) {
if (array_key_exists('name',$poll) && $poll['name']) {
$text = html2plain(purify_html($poll['name']),256);
@@ -1894,29 +1930,48 @@ function format_poll($item,$s,$opts) {
$total = 0;
}
if ($activated && $commentable) {
- $output .= '<input type="radio" name="answer" value="' . htmlspecialchars($text) . '"> ' . $text . '</input>' . ' (' . $total . ')' . EOL;
+ $output .= '<input type="radio" name="answer" value="' . htmlspecialchars($text) . '">&nbsp;&nbsp;<strong>' . $text . '</strong>' . EOL;
+ $output .= '<div class="progress bg-secondary bg-opacity-25" style="height: 3px;">';
+ $output .= '<div class="progress-bar bg-info" role="progressbar" style="width: ' . (($totalResponses) ? intval($total / $totalResponses * 100) : 0). '%;" aria-valuenow="" aria-valuemin="0" aria-valuemax="100"></div>';
+ $output .= '</div>';
+ $output .= '<div class="text-muted"><small>' . sprintf(tt('%d Vote', '%d Votes', $total, 'noun'), $total) . '&nbsp;|&nbsp;' . (($totalResponses) ? intval($total / $totalResponses * 100) . '%' : '0%') . '</small></div>';
+ $output .= EOL;
}
+
else {
- $output .= '( ) ' . $text . ' (' . $total . ')' . EOL;
+ $output .= '<input type="radio" name="answer" value="' . htmlspecialchars($text) . '" disabled="disabled">&nbsp;&nbsp;<strong>' . $text . '</strong>' . EOL;
+ $output .= '<div class="progress bg-secondary bg-opacity-25" style="height: 3px;">';
+ $output .= '<div class="progress-bar bg-info" role="progressbar" style="width: ' . (($totalResponses) ? intval($total / $totalResponses * 100) : 0) . '%;" aria-valuenow="" aria-valuemin="0" aria-valuemax="100"></div>';
+ $output .= '</div>';
+ $output .= '<div class="text-muted"><small>' . sprintf(tt('%d Vote', '%d Votes', $total, 'noun'), $total) . '&nbsp;|&nbsp;' . (($totalResponses) ? intval($total / $totalResponses * 100) . '%' : '0%') . '</small></div>';
+ $output .= EOL;
}
}
}
}
+
+ $message = (($totalResponses) ? sprintf(tt('%d Vote in total', '%d Votes in total', $totalResponses, 'noun'), $totalResponses) . EOL : '');
+
if ($item['comments_closed'] > NULL_DATE) {
$t = datetime_convert('UTC',date_default_timezone_get(), $item['comments_closed'], 'Y-m-d H:i');
$closed = ((datetime_convert() > $item['comments_closed']) ? true : false);
if ($closed) {
- $message = t('Poll has ended.');
+ $message .= t('Poll has ended');
}
else {
- $message = sprintf(t('Poll ends: %s'),$t);
+ $message .= sprintf(t('Poll ends in %s'), '<span class="autotime" title="' . $t . '"></span>');
}
- $output .= EOL . '<div>' . $message . '</div>';
}
- if ($activated and $commentable) {
- $output .= EOL . '<input type="button" class="btn btn-std btn-success" name="vote" value="' . t("Vote") . '" onclick="submitPoll(' . $item['id'] . '); return false;">'. '</form>';
+
+ $output .= '<div class="mb-3">' . $message . '</div>';
+
+ if ($activated && $commentable && !$closed) {
+ $output .= '<input type="button" class="btn btn-std btn-success" name="vote" value="' . t("Vote") . '" onclick="submitPoll(' . $item['id'] . '); return false;">'. '</form>';
}
+ if (strpos($item['body'], '[/share]') !== false) {
+ $output .= '</div></div>';
+ }
}
return $output;
}
@@ -2534,7 +2589,7 @@ function xchan_query(&$items, $abook = true, $effective_uid = 0) {
$chans = q("select xchan.*,hubloc.* from xchan left join hubloc on hubloc_hash = xchan_hash
where xchan_hash in (" . protect_sprintf(implode(',', $arr)) . ") and hubloc_primary = 1");
}
- $xchans = q("select * from xchan where xchan_hash in (" . protect_sprintf(implode(',',$arr)) . ") and xchan_network in ('rss','unknown', 'anon')");
+ $xchans = q("select * from xchan where xchan_hash in (" . protect_sprintf(implode(',',$arr)) . ") and xchan_network in ('rss','unknown', 'anon', 'token')");
if(! $chans)
$chans = $xchans;
else
@@ -2989,7 +3044,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
// weird - as all the other tags are linked to something.
if(local_channel() && local_channel() == $profile_uid) {
- $grp = group_byname($profile_uid,$name);
+ $grp = AccessList::byname($profile_uid,$name);
if($grp) {
$g = q("select hash from pgrp where id = %d and visible = 1 limit 1",
@@ -3692,6 +3747,13 @@ function get_forum_channels($uid) {
if(! $uid)
return;
+ $r = q("select abook_id, xchan_pubforum, xchan_hash, xchan_network, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d and abook_pending = 0 and abook_ignored = 0 and abook_blocked = 0 and abook_archived = 0 and abook_self = 0 and xchan_pubforum = 1 order by xchan_name",
+ intval($uid)
+ );
+
+
+/*
+
if(isset(App::$data['forum_channels']))
return App::$data['forum_channels'];
@@ -3763,6 +3825,7 @@ function get_forum_channels($uid) {
}
App::$data['forum_channels'] = $r;
+*/
return $r;
@@ -3829,6 +3892,26 @@ function array_path_exists($str,$arr) {
/**
+ * @brief provide psuedo random token (string) consisting entirely of US-ASCII letters/numbers
+ * and with possibly variable length
+ *
+ * @return string
+ */
+function new_token($minlen = 36, $maxlen = 48) {
+ $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
+ $str = EMPTY_STR;
+
+ $len = (($minlen === $maxlen) ? $minlen : mt_rand($minlen, $maxlen));
+
+ for ($a = 0; $a < $len; $a++) {
+ $str .= $chars[mt_rand(0, 62)];
+ }
+
+ return $str;
+}
+
+
+/**
* @brief Generate a random v4 UUID.
*
* @return string