}
// When we hide our friends we will only show the pure number but don't allow more.
- $show_contacts = empty($owner['hide-friends']);
+ $show_contacts = ActivityPub::isAcceptedRequester($owner['uid']) && empty($owner['hide-friends']);
// Allow fetching the contact list when the requester is part of the list.
if (($owner['page-flags'] == User::PAGE_FLAGS_PRVGROUP) && !empty($requester)) {
/**
* Return the ActivityPub profile of the given user
*
- * @param int $uid User ID
+ * @param int $uid User ID
+ * @param bool $full If not full, only the basic information is returned
* @return array with profile data
* @throws HTTPException\NotFoundException
* @throws HTTPException\InternalServerErrorException
*/
- public static function getProfile(int $uid): array
+ public static function getProfile(int $uid, bool $full = true): array
{
$owner = User::getOwnerDataById($uid);
if (!isset($owner['id'])) {
- DI::logger()->error('Unable to find owner data for uid', ['uid' => $uid, 'callstack' => System::callstack(20)]);
+ DI::logger()->error('Unable to find owner data for uid', ['uid' => $uid]);
throw new HTTPException\NotFoundException('User not found.');
}
$data['preferredUsername'] = $owner['nick'];
$data['name'] = $owner['name'];
- if (!empty($owner['country-name'] . $owner['region'] . $owner['locality'])) {
+ if (!$full && !empty($owner['country-name'] . $owner['region'] . $owner['locality'])) {
$data['vcard:hasAddress'] = ['@type' => 'vcard:Home', 'vcard:country-name' => $owner['country-name'],
'vcard:region' => $owner['region'], 'vcard:locality' => $owner['locality']];
}
- if (!empty($owner['about'])) {
+ if ($full && !empty($owner['about'])) {
$data['summary'] = BBCode::convertForUriId($owner['uri-id'] ?? 0, $owner['about'], BBCode::EXTERNAL);
}
- if (!empty($owner['xmpp']) || !empty($owner['matrix'])) {
+ if ($full && (!empty($owner['xmpp']) || !empty($owner['matrix']))) {
$data['vcard:hasInstantMessage'] = [];
if (!empty($owner['xmpp'])) {
'owner' => $owner['url'],
'publicKeyPem' => $owner['pubkey']];
$data['endpoints'] = ['sharedInbox' => DI::baseUrl() . '/inbox'];
- if ($uid != 0) {
+ if ($full && $uid != 0) {
$data['icon'] = ['type' => 'Image', 'url' => User::getAvatarUrl($owner)];
$resourceid = Photo::ridFromURI($owner['photo']);
$always_bcc = false;
$is_group = false;
$follower = '';
+ $exclusive = false;
+ $mention = false;
+ $audience = [];
// Check if we should always deliver our stuff via BCC
if (!empty($item['uid'])) {
$owner = User::getOwnerDataById($item['uid']);
if (!empty($owner)) {
$always_bcc = $owner['hide-friends'];
- $is_group = ($owner['account-type'] == User::ACCOUNT_TYPE_COMMUNITY) && $owner['manually-approve'];
+ $is_group = ($owner['account-type'] == User::ACCOUNT_TYPE_COMMUNITY);
$profile = APContact::getByURL($owner['url'], false);
$follower = $profile['followers'] ?? '';
$is_group_thread = false;
}
- $exclusive = false;
- $mention = false;
- $audience = [];
-
- $parent_tags = Tag::getByURIId($item['parent-uri-id'], [Tag::AUDIENCE, Tag::MENTION]);
- if (!empty($parent_tags)) {
- $is_group_thread = false;
- foreach ($parent_tags as $tag) {
- if ($tag['type'] != Tag::AUDIENCE) {
- continue;
- }
- $profile = APContact::getByURL($tag['url'], false);
- if (!empty($profile) && ($profile['type'] == 'Group')) {
- $audience[] = $tag['url'];
- $is_group_thread = true;
- }
- }
- if ($is_group_thread) {
+ if (!$is_group) {
+ $parent_tags = Tag::getByURIId($item['parent-uri-id'], [Tag::AUDIENCE, Tag::MENTION]);
+ if (!empty($parent_tags)) {
+ $is_group_thread = false;
foreach ($parent_tags as $tag) {
- if (($tag['type'] == Tag::MENTION) && in_array($tag['url'], $audience)) {
- $mention = true;
+ if ($tag['type'] != Tag::AUDIENCE) {
+ continue;
+ }
+ $profile = APContact::getByURL($tag['url'], false);
+ if (!empty($profile) && ($profile['type'] == 'Group')) {
+ $audience[] = $tag['url'];
+ $is_group_thread = true;
}
}
- $exclusive = !$mention;
- }
- } elseif ($is_group_thread) {
- foreach (Tag::getByURIId($item['parent-uri-id'], [Tag::MENTION, Tag::EXCLUSIVE_MENTION]) as $term) {
- $profile = APContact::getByURL($term['url'], false);
- if (!empty($profile) && ($profile['type'] == 'Group')) {
- if ($term['type'] == Tag::EXCLUSIVE_MENTION) {
- $audience[] = $term['url'];
- $exclusive = true;
- } elseif ($term['type'] == Tag::MENTION) {
- $mention = true;
+ if ($is_group_thread) {
+ foreach ($parent_tags as $tag) {
+ if (($tag['type'] == Tag::MENTION) && in_array($tag['url'], $audience)) {
+ $mention = true;
+ }
+ }
+ $exclusive = !$mention;
+ }
+ } elseif ($is_group_thread) {
+ foreach (Tag::getByURIId($item['parent-uri-id'], [Tag::MENTION, Tag::EXCLUSIVE_MENTION]) as $term) {
+ $profile = APContact::getByURL($term['url'], false);
+ if (!empty($profile) && ($profile['type'] == 'Group')) {
+ if ($term['type'] == Tag::EXCLUSIVE_MENTION) {
+ $audience[] = $term['url'];
+ $exclusive = true;
+ } elseif ($term['type'] == Tag::MENTION) {
+ $mention = true;
+ }
}
}
}
+ } else {
+ $audience[] = $owner['url'];
}
if (self::isAnnounce($item) || self::isAPPost($last_id)) {
}
if (!$exclusive) {
- $data = array_merge($data, self::fetchPermissionBlockFromThreadParent($item, $is_group_thread));
+ $data = array_merge_recursive($data, self::fetchPermissionBlockFromThreadParent($item, $is_group_thread));
}
// Check if the item is completely public or unlisted
unset($data['bcc'][$key]);
}
- if (($key = array_search($item['author-link'], $data['audience'])) !== false) {
- unset($data['audience'][$key]);
- }
-
foreach ($data['to'] as $to) {
if (($key = array_search($to, $data['cc'])) !== false) {
unset($data['cc'][$key]);
}
if ($item_profile && ($receiver == $item_profile['followers']) && ($uid == $profile_uid)) {
- $inboxes = array_merge($inboxes, self::fetchTargetInboxesforUser($uid, $personal, self::isAPPost($last_id)));
+ $inboxes = array_merge_recursive($inboxes, self::fetchTargetInboxesforUser($uid, $personal, self::isAPPost($last_id)));
} else {
$profile = APContact::getByURL($receiver, false);
if (!empty($profile)) {
/**
* Creates the activity or fetches it from the cache
*
- * @param integer $item_id Item id
- * @param boolean $force Force new cache entry
+ * @param integer $item_id Item id
+ * @param boolean $force Force new cache entry
+ * @param boolean $object_mode true = Create the object, false = create the activity with the object
+ * @param boolean $announce_activity true = the announced object is the activity, false = we announce the object link
* @return array|false activity or false on failure
* @throws \Exception
*/
- public static function createCachedActivityFromItem(int $item_id, bool $force = false, bool $object_mode = false)
+ public static function createCachedActivityFromItem(int $item_id, bool $force = false, bool $object_mode = false, $announce_activity = false)
{
- $cachekey = 'APDelivery:createActivity:' . $item_id . ':' . (int)$object_mode;
+ $cachekey = 'APDelivery:createActivity:' . $item_id . ':' . (int)$object_mode . ':' . (int)$announce_activity;
if (!$force) {
$data = DI::cache()->get($cachekey);
}
}
- $data = self::createActivityFromItem($item_id, $object_mode);
+ $data = self::createActivityFromItem($item_id, $object_mode, false, $announce_activity);
DI::cache()->set($cachekey, $data, Duration::QUARTER_HOUR);
return $data;
* Creates an activity array for a given item id
*
* @param integer $item_id
- * @param boolean $object_mode Is the activity item is used inside another object?
- * @param boolean $api_mode "true" if used for the API
+ * @param boolean $object_mode true = Create the object, false = create the activity with the object
+ * @param boolean $api_mode true = used for the API
+ * @param boolean $announce_activity true = the announced object is the activity, false = we announce the object link
* @return false|array
* @throws \Exception
*/
- public static function createActivityFromItem(int $item_id, bool $object_mode = false, $api_mode = false)
+ public static function createActivityFromItem(int $item_id, bool $object_mode = false, $api_mode = false, $announce_activity = false)
{
$condition = ['id' => $item_id];
if (!$api_mode) {
if (!DBA::isResult($item)) {
return false;
}
- return self::createActivityFromArray($item, $object_mode, $api_mode);
+ return self::createActivityFromArray($item, $object_mode, $api_mode, $announce_activity);
}
/**
*
* @param integer $uri_id
* @param integer $uid
- * @param boolean $object_mode Is the activity item is used inside another object?
- * @param boolean $api_mode "true" if used for the API
+ * @param boolean $object_mode true = Create the object, false = create the activity with the object
+ * @param boolean $api_mode true = used for the API
+ * @param boolean $announce_activity true = the announced object is the activity, false = we announce the object link
* @return false|array
* @throws \Exception
*/
- public static function createActivityFromUriId(int $uri_id, int $uid, bool $object_mode = false, $api_mode = false)
+ public static function createActivityFromUriId(int $uri_id, int $uid, bool $object_mode = false, $api_mode = false, $announce_activity = false)
{
$condition = ['uri-id' => $uri_id, 'uid' => [0, $uid]];
if (!$api_mode) {
return false;
}
- return self::createActivityFromArray($item, $object_mode, $api_mode);
+ return self::createActivityFromArray($item, $object_mode, $api_mode, $announce_activity);
}
/**
* Creates an activity array for a given item id
*
* @param integer $item_id
- * @param boolean $object_mode Is the activity item is used inside another object?
- * @param boolean $api_mode "true" if used for the API
+ * @param boolean $object_mode true = Create the object, false = create the activity with the object
+ * @param boolean $api_mode true = used for the API
+ * @param boolean $announce_activity true = the announced object is the activity, false = we announce the object link
* @return false|array
* @throws \Exception
*/
- private static function createActivityFromArray(array $item, bool $object_mode = false, $api_mode = false)
+ private static function createActivityFromArray(array $item, bool $object_mode = false, $api_mode = false, $announce_activity = false)
{
if (!$api_mode && !$item['deleted'] && $item['network'] == Protocol::ACTIVITYPUB) {
$data = Post\Activity::getByURIId($item['uri-id']);
$data = self::createAddTag($item, $data);
} elseif ($data['type'] == 'Announce') {
if ($item['verb'] == ACTIVITY::ANNOUNCE) {
- $data['object'] = $item['thr-parent'];
+ if ($announce_activity) {
+ $anounced_item = Post::selectFirst(['uid'], ['uri-id' => $item['thr-parent-id'], 'origin' => true]);
+ $data['object'] = self::createActivityFromUriId($item['thr-parent-id'], $anounced_item['uid'] ?? 0);
+ unset($data['object']['@context']);
+ } else {
+ $data['object'] = $item['thr-parent'];
+ }
} else {
$data = self::createAnnounce($item, $data, $api_mode);
}
$body = BBCode::setMentionsToNicknames($body);
- if (!empty($item['quote-uri-id'])) {
+ if (!empty($item['quote-uri-id']) && ($item['quote-uri-id'] != $item['uri-id'])) {
if (Post::exists(['uri-id' => $item['quote-uri-id'], 'network' => [Protocol::ACTIVITYPUB, Protocol::DFRN]])) {
$real_quote = true;
$data['quoteUrl'] = $item['quote-uri'];
if (!empty($language)) {
$richbody = BBCode::setMentionsToNicknames($item['body'] ?? '');
$richbody = Post\Media::removeFromEndOfBody($richbody);
- if (!empty($item['quote-uri-id'])) {
+ if (!empty($item['quote-uri-id']) && ($item['quote-uri-id'] != $item['uri-id'])) {
if ($real_quote) {
$richbody = DI::contentItem()->addShareLink($richbody, $item['quote-uri-id']);
} else {
$data['contentMap'][$language] = BBCode::convertForUriId($item['uri-id'], $richbody, BBCode::EXTERNAL);
}
- if (!empty($item['quote-uri-id'])) {
+ if (!empty($item['quote-uri-id']) && ($item['quote-uri-id'] != $item['uri-id'])) {
$source = DI::contentItem()->addSharedPost($item, $item['body']);
} else {
$source = $item['body'];