addressing refactor

This commit is contained in:
Mike Macgirvin 2024-06-25 06:37:06 +10:00
parent 806b7a65b0
commit 9067a31939
4 changed files with 117 additions and 158 deletions

View file

@ -447,7 +447,7 @@ function contact_remove($channel_id, $abook_id, $atoken_sync = false)
Hook::call('connection_remove', $x);
$archive = get_pconfig($channel_id, 'system', 'archive_removed_contacts');
$archive = get_pconfig($channel_id, 'system', 'archive_removed_contacts', true);
if ($archive) {
q(
"update abook set abook_archived = 1 where abook_id = %d and abook_channel = %d",

View file

@ -145,6 +145,10 @@ define ( 'CLIENT_MODE_UPDATE', 0x0002);
define ('AUDIENCE_SENDER', 0x0001);
define ('AUDIENCE_CONVERSATION', 0x0002);
define ('AUDIENCE_FOLLOWERS', 0x0004);
define ('AUDIENCE_PUBLIC', 0x0008);
define ('AUDIENCE_UNLISTED', 0x0010);
define ('AUDIENCE_MENTIONS', 0x0020);
define ('AUDIENCE_SERVER', 0x0040);
/**
*

View file

@ -2636,6 +2636,11 @@ function ids_to_querystr($arr, $idx = 'id', $quote = false)
return(implode(',', $t));
}
function array_merge_clean($array1, $array2)
{
return array_values(array_unique(array_merge($array1, $array2)));
}
/**
* @brief array_elm_to_str($arr,$elm,$delim = ',') extract unique individual elements from an array of arrays and return them as a string separated by a delimiter
* similar to ids_to_querystr, but allows a different delimiter instead of a db-quote option

View file

@ -951,12 +951,6 @@ class Activity
$activity['inReplyTo'] = set_activity_mid($item['thr_parent']);
}
// @FIXME FEP-5624 set for comment approvals but not event approvals
// For comment approvals and rejections
// if (in_array($activity['type'], ['Accept','Reject']) && is_string($item['obj']) && strlen($item['obj'])) {
// $activity['inReplyTo'] = $item['thr_parent'];
// }
$cnv = get_iconfig($item['parent'], 'activitypub', 'context');
if (!$cnv) {
$cnv = $item['parent_mid'];
@ -1087,89 +1081,7 @@ class Activity
}
}
// addressing madness
$audience = self::getAudienceFromItem($item);
$mentions = self::map_mentions($item);
if ($activitypub) {
$parent_i = [];
$public = !$item['item_private'];
$top_level = ($item['mid'] === $item['parent_mid']);
$activity['to'] = [];
$activity['cc'] = [];
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
if ($recips) {
$parent_i['to'] = $recips['to'];
$parent_i['cc'] = $recips['cc'];
}
if ($public) {
$activity['to'] = [ACTIVITY_PUBLIC_INBOX];
if (isset($parent_i['to']) && is_array($parent_i['to'])) {
$activity['to'] = array_values(array_unique(array_merge($activity['to'], $parent_i['to'])));
}
if ($item['item_origin']) {
$activity['cc'] = [z_root() . '/followers/' . substr($item['author']['xchan_addr'], 0, strpos($item['author']['xchan_addr'], '@'))];
}
if (isset($parent_i['cc']) && is_array($parent_i['cc'])) {
$activity['cc'] = array_values(array_unique(array_merge($activity['cc'], $parent_i['cc'])));
}
} else {
// private activity
if ($top_level) {
$activity['to'] = self::map_acl($item);
if (isset($parent_i['to']) && is_array($parent_i['to'])) {
$activity['to'] = array_values(array_unique(array_merge($activity['to'], $parent_i['to'])));
}
} elseif ((int)$item['item_private'] === 1) {
if (($audience & AUDIENCE_FOLLOWERS) && $item['item_origin']) {
$activity['to'] = [z_root() . '/followers/' . substr($item['author']['xchan_addr'], 0, strpos($item['author']['xchan_addr'], '@'))];
}
else {
$activity['cc'] = self::map_acl($item);
if (isset($parent_i['cc']) && is_array($parent_i['cc'])) {
$activity['cc'] = array_values(array_unique(array_merge($activity['cc'], $parent_i['cc'])));
}
$d = q(
"select hubloc.* from hubloc left join item on hubloc_hash = owner_xchan where item.parent_mid = '%s' and item.uid = %d and hubloc_deleted = 0 order by hubloc_id desc limit 1",
dbesc($item['parent_mid']),
intval($item['uid'])
);
if ($d) {
if ($d[0]['hubloc_network'] === 'activitypub') {
$addr = $d[0]['hubloc_hash'];
} else {
$addr = $d[0]['hubloc_id_url'];
}
$activity['cc'][] = $addr;
}
}
}
}
if (count($mentions) > 0) {
if (!$activity['to']) {
$activity['to'] = $mentions;
} else {
$activity['cc'] = array_values(array_unique(array_merge($activity['cc'], $mentions)));
}
}
}
$cc = [];
if ($activity['cc'] && is_array($activity['cc'])) {
foreach ($activity['cc'] as $e) {
if (!is_array($activity['to'])) {
$cc[] = $e;
} elseif (!in_array($e, $activity['to'])) {
$cc[] = $e;
}
}
}
$activity['cc'] = $cc;
$activity = self::encodeAddressing($activity, $item);
return $activity;
}
@ -1462,91 +1374,113 @@ class Activity
}
}
// addressing madness
$activity = self::encodeAddressing($activity, $item);
return $activity;
}
public static function encodeAddressing($activity,$item)
{
/*
* addressing madness
*
* For what it's worth, Mastodons visibility scopes are a custom thing and this is generally how they map:
* public = to: [public], cc: [followers, mentions]
* unlisted = cc: [public, followers, mentions]
* followers-only = to: [followers], cc: [mentions]
* direct = to: [mentions]
*
* This software does not normally use the same mappings - and doesn't even require mappings;
* but the Mastodon mappings may need to be considered so that private audiences are not mis-identified
* when communicating with people using that software.
*/
$channel = Channel::from_id($item['uid']); // needed in future for nomadic follower addressing
$audience = self::getAudienceFromItem($item);
$mentions = self::map_mentions($item);
$followers = [z_root() . '/followers/' . substr($item['author']['xchan_addr'], 0, strpos($item['author']['xchan_addr'], '@'))];
if ($activitypub) {
$parent_i = [];
$activity['to'] = [];
$activity['cc'] = [];
$parent_i = [];
$activity['to'] = [];
$activity['cc'] = [];
$public = !$item['item_private'];
$top_level = $item['mid'] === $item['parent_mid'];
$public = !$item['item_private'];
$top_level = $item['mid'] === $item['parent_mid'];
if (!$top_level) {
if (intval($item['parent'])) {
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
if (!$top_level) {
if (intval($item['parent'])) {
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
} else {
// if we are encoding this item prior to storage there won't be a parent.
$p = q(
"select parent from item where parent_mid = '%s' and uid = %d",
dbesc($item['parent_mid']),
intval($item['uid'])
);
if ($p) {
$recips = get_iconfig($p[0]['parent'], 'activitypub', 'recips');
}
}
if ($recips) {
$parent_i['to'] = $recips['to'];
$parent_i['cc'] = $recips['cc'];
}
}
if ($public) {
$activity['to'] = [ACTIVITY_PUBLIC_INBOX];
if (isset($parent_i['to']) && is_array($parent_i['to'])) {
$activity['to'] = array_merge_clean($activity['to'], $parent_i['to']);
}
if ($item['item_origin']) {
$activity['cc'] = $followers;
}
if (isset($parent_i['cc']) && is_array($parent_i['cc'])) {
$activity['cc'] = array_merge_clean($activity['cc'], $parent_i['cc']);
}
} else {
// private activity
if ($top_level) {
$activity['to'] = self::map_acl($item);
if (isset($parent_i['to']) && is_array($parent_i['to'])) {
$activity['to'] = array_merge_clean($activity['to'], $parent_i['to']);
}
} elseif ((int)$item['item_private'] === 1) {
if (($audience & AUDIENCE_FOLLOWERS) && $item['item_origin']) {
$activity['to'] = $followers;
} else {
// if we are encoding this item prior to storage there won't be a parent.
$p = q(
"select parent from item where parent_mid = '%s' and uid = %d",
$activity['cc'] = self::map_acl($item);
if (isset($parent_i['cc']) && is_array($parent_i['cc'])) {
$activity['cc'] = array_merge_clean($activity['cc'], $parent_i['cc']);
}
$d = q(
"select hubloc.* from hubloc left join item on hubloc_hash = owner_xchan where item.parent_mid = '%s' and item.uid = %d and hubloc_deleted = 0 order by hubloc_id desc limit 1",
dbesc($item['parent_mid']),
intval($item['uid'])
);
if ($p) {
$recips = get_iconfig($p[0]['parent'], 'activitypub', 'recips');
}
}
if ($recips) {
$parent_i['to'] = $recips['to'];
$parent_i['cc'] = $recips['cc'];
}
}
if ($public) {
$activity['to'] = [ACTIVITY_PUBLIC_INBOX];
if (isset($parent_i['to']) && is_array($parent_i['to'])) {
$activity['to'] = array_values(array_unique(array_merge($activity['to'], $parent_i['to'])));
}
if ($item['item_origin']) {
$activity['cc'] = [z_root() . '/followers/' . substr($item['author']['xchan_addr'], 0, strpos($item['author']['xchan_addr'], '@'))];
}
if (isset($parent_i['cc']) && is_array($parent_i['cc'])) {
$activity['cc'] = array_values(array_unique(array_merge($activity['cc'], $parent_i['cc'])));
}
} else {
// private activity
if ($top_level) {
$activity['to'] = self::map_acl($item);
if (isset($parent_i['to']) && is_array($parent_i['to'])) {
$activity['to'] = array_values(array_unique(array_merge($activity['to'], $parent_i['to'])));
}
} elseif ((int)$item['item_private'] === 1) {
if (($audience & AUDIENCE_FOLLOWERS) && $item['item_origin']) {
$activity['to'] = [z_root() . '/followers/' . substr($item['author']['xchan_addr'], 0, strpos($item['author']['xchan_addr'], '@'))];
}
else {
$activity['cc'] = self::map_acl($item);
if (isset($parent_i['cc']) && is_array($parent_i['cc'])) {
$activity['cc'] = array_values(array_unique(array_merge($activity['cc'], $parent_i['cc'])));
}
$d = q(
"select hubloc.* from hubloc left join item on hubloc_hash = owner_xchan where item.parent_mid = '%s' and item.uid = %d and hubloc_deleted = 0 order by hubloc_id desc limit 1",
dbesc($item['parent_mid']),
intval($item['uid'])
);
if ($d) {
if ($d[0]['hubloc_network'] === 'activitypub') {
$addr = $d[0]['hubloc_hash'];
} else {
$addr = $d[0]['hubloc_id_url'];
}
$activity['cc'][] = $addr;
if ($d) {
if (in_array($d[0]['hubloc_network'], ['activitypub', 'apnomadic'])) {
$addr = $d[0]['hubloc_hash'];
} else {
$addr = $d[0]['hubloc_id_url'];
}
$activity['cc'][] = $addr;
}
}
}
}
if (count($mentions) > 0) {
// Delivery is controlled by parent ACL when AUDIENCE_CONVERSATION is in effect -
// and mentions are ignored.
if ((!$audience) || !($audience & AUDIENCE_CONVERSATION)) {
if (count($mentions)) {
if (!$activity['to']) {
$activity['to'] = $mentions;
} else {
$activity['cc'] = array_values(array_unique(array_merge($activity['to'], $mentions)));
} elseif ((int)$item['item_private'] !== 2) {
$activity['cc'] = array_merge_clean($activity['cc'], $mentions);
}
}
}
@ -1570,6 +1504,8 @@ class Activity
}
// Returns an array of URLS for any mention tags found in the item array $i.
public static function map_mentions($i)
@ -5221,10 +5157,15 @@ class Activity
return $item;
}
public static function getPostOpts($item)
{
return explode(',', $item['postopts']);
}
public static function getAudienceFromItem($item)
{
$audience = 0;
$postopts = explode(',', $item['postopts']);
$postopts = self::getPostOpts($item);
if (in_array('sender', $postopts)) {
$audience += AUDIENCE_SENDER;
}
@ -5234,6 +5175,15 @@ class Activity
if (in_array('followers', $postopts)) {
$audience += AUDIENCE_FOLLOWERS;
}
if (in_array('public', $postopts)) {
$audience += AUDIENCE_PUBLIC;
}
if (in_array('unlisted', $postopts)) {
$audience += AUDIENCE_UNLISTED;
}
if (in_array('mentions', $postopts)) {
$audience += AUDIENCE_MENTIONS;
}
return $audience;
}
}