diff options
-rw-r--r-- | Zotlabs/Daemon/Notifier.php | 2 | ||||
-rw-r--r-- | Zotlabs/Lib/Activity.php | 8 | ||||
-rw-r--r-- | Zotlabs/Lib/Libzot.php | 67 | ||||
-rw-r--r-- | Zotlabs/Module/Item.php | 38 | ||||
-rw-r--r-- | Zotlabs/Module/Settings/Privacy.php | 7 | ||||
-rw-r--r-- | include/items.php | 42 | ||||
-rw-r--r-- | include/taxonomy.php | 9 | ||||
-rw-r--r-- | view/tpl/settings_privacy.tpl | 3 |
8 files changed, 136 insertions, 40 deletions
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index de8597081..d5fe7ee6d 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -409,8 +409,6 @@ class Notifier { self::$private = false; self::$recipients = collect_recipients($parent_item, self::$private); - // FIXME add any additional recipients such as mentions, etc. - if ($top_level_post) { // remove clones who will receive the post via sync self::$recipients = array_values(array_diff(self::$recipients, [$target_item['owner_xchan']])); diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 226f50636..d4a89d2a4 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2869,7 +2869,7 @@ class Activity { $allowed = false; // TODO: not implemented - // $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system','permit_all_mentions') && i_am_mentioned($channel,$item)); + $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system','permit_all_mentions') && i_am_mentioned($channel, $item)); if ($is_child_node) { @@ -2894,7 +2894,7 @@ class Activity { // check permissions against the author, not the sender $allowed = perm_is_allowed($channel['channel_id'], $item['author_xchan'], 'post_comments'); - if ((!$allowed)/* && $permit_mentions*/) { + if ((!$allowed) && $permit_mentions) { if ($p[0]['owner_xchan'] === $channel['channel_hash']) { $allowed = false; } @@ -2946,9 +2946,9 @@ class Activity { $allowed = true; } // TODO: not implemented - /*if ($permit_mentions) { + if ($permit_mentions) { $allowed = true; - }*/ + } } if (tgroup_check($channel['channel_id'], $item) && (!$is_child_node)) { diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 93d8a39c0..406a26910 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1233,7 +1233,6 @@ class Libzot { return; } - if ($has_data) { if (in_array($env['type'], ['activity', 'response'])) { @@ -1386,6 +1385,23 @@ class Libzot { return false; } + static function find_parent_owner_hashes($env, $act) { + $r = []; + $thread_parent = self::find_parent($env, $act); + if ($thread_parent) { + $z = q("select channel_hash as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) and channel_hash != '%s'", + dbesc($thread_parent), + dbesc($thread_parent), + dbesc($env['sender']) + ); + if ($z) { + foreach ($z as $zv) { + $r[] = $zv['hash']; + } + } + } + return $r; + } /** * @brief @@ -1466,26 +1482,23 @@ class Libzot { } } } + if ($act->obj['type'] === 'Tombstone') { + // This is a delete. There are no tags to look at - add anyone owning the item. + $parent_owners = self::find_parent_owner_hashes($msg, $act); + if ($parent_owners) { + $r = array_merge($r, $parent_owners); + } + } + } } else { // This is a comment. We need to find any parent with ITEM_UPLINK set. But in fact, let's just return // everybody that stored a copy of the parent. This way we know we're covered. We'll check the // comment permissions when we deliver them. - - $thread_parent = self::find_parent($msg, $act); - - if ($thread_parent) { - $z = q("select channel_hash as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) and channel_hash != '%s'", - dbesc($thread_parent), - dbesc($thread_parent), - dbesc($msg['sender']) - ); - if ($z) { - foreach ($z as $zv) { - $r[] = $zv['hash']; - } - } + $parent_owners = self::find_parent_owner_hashes($msg, $act); + if ($parent_owners) { + $r = array_merge($r, $parent_owners); } } @@ -1622,13 +1635,23 @@ class Libzot { if ((!$tag_delivery) && (!$local_public)) { $allowed = (perm_is_allowed($channel['channel_id'], $sender, $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($sender, $parent[0]); + $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system', 'permit_all_mentions') && i_am_mentioned($channel, $arr)); + + if (!$allowed) { + if ($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($sender, $parent[0]); + if (!$allowed && $permit_mentions) { + $allowed = true; + } + } + + } elseif ($permit_mentions) { + $allowed = true; } } diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 5ca94cd76..b3b040e96 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -1194,12 +1194,15 @@ class Item extends Controller { (($remote_id) ? $remote_id : basename($datarray['mid'])), true); } - if ($orig_post) { $datarray['id'] = $post_id; $x = item_store_update($datarray, $execflag); + if ($x['success']) { + $this->add_listeners($datarray); + } + // We only need edit activities for other federated protocols // which do not support edits natively. While this does federate // edits, it presents a number of issues locally - such as #757 and #758. @@ -1238,6 +1241,10 @@ class Item extends Controller { $post = item_store($datarray, $execflag); + if ($post['success']) { + $this->add_listeners($datarray); + } + $post_id = $post['item_id']; $datarray = $post['item']; @@ -1603,4 +1610,33 @@ class Item extends Controller { } + function add_listeners($item) { + // ONLY public items! + if ($item['item_thread_top'] && !$item['item_private'] && !empty($item['term'])) { + foreach($item['term'] as $t) { + if (empty($t['url']) || $t['ttype'] != TERM_MENTION || $t['otype'] != TERM_OBJ_POST) { + continue; + } + + $listener = q("select hubloc_hash, hubloc_network from hubloc where hubloc_id_url = '%s' and hubloc_deleted = 0 order by hubloc_id desc", + dbesc($t['url']) + ); + + if ($listener) { + $listener = Libzot::zot_record_preferred($listener); + + $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", + intval($profile_uid), + dbesc($listener['hubloc_hash']) + ); + + if (!$c) { + ThreadListener::store($item['mid'], $listener['hubloc_hash']); + } + } + } + } + } + + } diff --git a/Zotlabs/Module/Settings/Privacy.php b/Zotlabs/Module/Settings/Privacy.php index 847bb3b8f..65d5b538e 100644 --- a/Zotlabs/Module/Settings/Privacy.php +++ b/Zotlabs/Module/Settings/Privacy.php @@ -22,6 +22,9 @@ class Privacy { $autoperms = (((x($_POST, 'autoperms')) && (intval($_POST['autoperms']) == 1)) ? 1 : 0); set_pconfig(local_channel(), 'system', 'autoperms', $autoperms); + $permit_all_mentions = (((x($_POST, 'permit_all_mentions')) && (intval($_POST['permit_all_mentions']) == 1)) ? 1 : 0); + set_pconfig(local_channel(), 'system', 'permit_all_mentions', $permit_all_mentions); + $role = get_pconfig(local_channel(), 'system', 'permissions_role'); if ($role === 'custom') { @@ -99,6 +102,7 @@ class Privacy { $autoperms = get_pconfig(local_channel(), 'system', 'autoperms'); $index_opt_out = get_pconfig(local_channel(), 'system', 'index_opt_out'); $group_actor = get_pconfig(local_channel(), 'system', 'group_actor'); + $permit_all_mentions = get_pconfig(local_channel(), 'system', 'permit_all_mentions'); $permissions_role = get_pconfig(local_channel(), 'system', 'permissions_role', 'custom'); $permission_limits = ($permissions_role === 'custom'); @@ -119,7 +123,8 @@ class Privacy { ], '$autoperms' => ['autoperms', t('Automatically approve new contacts'), $autoperms, '', [t('No'), t('Yes')]], '$index_opt_out' => ['index_opt_out', t('Opt-out of search engine indexing'), $index_opt_out, '', [t('No'), t('Yes')]], - '$group_actor' => ['group_actor', t('Group actor'), $group_actor, t('Allow this channel to act as a forum'), [t('No'), t('Yes')]] + '$group_actor' => ['group_actor', t('Group actor'), $group_actor, t('Allow this channel to act as a forum'), [t('No'), t('Yes')]], + '$permit_all_mentions' => ['permit_all_mentions', t('Accept all messages which mention you'), $permit_all_mentions, t('This setting bypasses normal permissions'), [t('No'), t('Yes')]], ]); return $o; diff --git a/include/items.php b/include/items.php index b795df90d..a7d07a599 100644 --- a/include/items.php +++ b/include/items.php @@ -143,11 +143,8 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) { } - // Forward to thread listeners and pubstream (sys channel), *unless* there is even - // a remote hint that the item might have some privacy attached. - // This could be (for instance) an ActivityPub DM - // in the middle of a public thread. Unless we can guarantee beyond all doubt that - // this is public, don't allow it to go to thread listeners. + // Forward to thread listeners and pubstream (sys channel), + // *unless* there is even a remote hint that the item might have some privacy attached. if(!intval($item['item_private'])) { $sys = get_sys_channel(); @@ -212,6 +209,7 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) { $recipients[] = $item['owner_xchan']; } + return $recipients; } @@ -3043,6 +3041,40 @@ function tgroup_check($uid, $item) { } + +function i_am_mentioned($channel, $item, $check_groups = false) { + + $link = z_root() . '/channel/' . $channel['channel_address']; + + $body = preg_replace('/\[share(.*?)\[\/share]/','',$item['body']); + + $tagged = false; + $matches = []; + $tagtype = $check_groups ? TERM_FORUM : TERM_MENTION; + $terms = ((isset($item['term'])) ? get_terms_oftype($item['term'], $tagtype) : false); + + if ($terms) { + foreach ($terms as $term) { + if ($link === $term['url']) { + $pattern = '/[!@]!?\[[uz]rl=' . preg_quote($term['url'],'/') . '](.*?)\[\/[uz]rl]/'; + if (preg_match($pattern,$body,$matches)) { + $tagged = true; + } + $pattern = '/\[[uz]rl=' . preg_quote($term['url'],'/') . '][!@](.*?)\[\/[uz]rl]/'; + if (preg_match($pattern,$body,$matches)) { + $tagged = true; + } + } + } + } + $unless = intval(get_pconfig($channel['channel_id'], 'system', 'unless_mention_count', get_config('system', 'unless_mention_count', 20))); + if ($unless && $terms && count($terms) > $unless) { + $tagged = false; + } + return $tagged; +} + + /** * Sourced and tag-delivered posts are re-targetted for delivery to the connections of the channel * receiving the post. This starts the second delivery chain, by resetting permissions and ensuring diff --git a/include/taxonomy.php b/include/taxonomy.php index 671f96c2e..3f6db50d1 100644 --- a/include/taxonomy.php +++ b/include/taxonomy.php @@ -119,13 +119,14 @@ function store_item_tag($uid,$iid,$otype,$type,$term,$url = '') { } -function get_terms_oftype($arr,$type) { - $ret = array(); - if(! (is_array($arr) && count($arr))) +function get_terms_oftype($arr, $type) { + $ret = []; + + if(!is_array($arr) && count($arr)) return $ret; if(! is_array($type)) - $type = array($type); + $type = [$type]; foreach($type as $t) foreach($arr as $x) diff --git a/view/tpl/settings_privacy.tpl b/view/tpl/settings_privacy.tpl index aff9619c3..77d125e41 100644 --- a/view/tpl/settings_privacy.tpl +++ b/view/tpl/settings_privacy.tpl @@ -8,8 +8,9 @@ <div class="section-content-tools-wrapper"> - {{include file="field_checkbox.tpl" field=$autoperms}} {{include file="field_checkbox.tpl" field=$index_opt_out}} + {{include file="field_checkbox.tpl" field=$autoperms}} + {{include file="field_checkbox.tpl" field=$permit_all_mentions}} {{if $sec_addon}} {{$sec_addon}} |