if (ActivityPub::isRequest()) {
$wall_item = Item::selectFirst(['id', 'uid'], ['guid' => $item['guid'], 'wall' => true]);
if ($wall_item['uid'] == 180) {
- $data = ActivityPub::createActivityFromItem($wall_item['id']);
+ $data = ActivityPub::createObjectFromItemID($wall_item['id']);
echo json_encode($data);
exit();
}
}
// returns an array of contact-ids that are allowed to see this object
- private static function enumeratePermissions($obj)
+ public static function enumeratePermissions($obj)
{
$allow_people = expand_acl($obj['allow_cid']);
$allow_groups = Group::expand(expand_acl($obj['allow_gid']));
return $tag_text;
}
+ public static function tagArrayFromItemId($itemid)
+ {
+ $condition = ['otype' => TERM_OBJ_POST, 'oid' => $itemid, 'type' => [TERM_HASHTAG, TERM_MENTION]];
+ $tags = DBA::select('term', ['type', 'term', 'url'], $condition);
+ if (!DBA::isResult($tags)) {
+ return [];
+ }
+
+ return DBA::toArray($tags);
+ }
+
public static function fileTextFromItemId($itemid)
{
$file_text = '';
use Friendica\Model\Conversation;
use Friendica\Model\Contact;
use Friendica\Model\Item;
+use Friendica\Model\Term;
use Friendica\Model\User;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Crypto;
return $data;
}
+ public static function createPermissionBlockForItem($item)
+ {
+ $data = ['to' => [], 'cc' => []];
+
+ $terms = Term::tagArrayFromItemId($item['id']);
+
+ if (!$item['private']) {
+ $data['to'][] = self::PUBLIC;
+ $data['cc'][] = System::baseUrl() . '/followers/' . $item['author-nick'];
+
+ foreach ($terms as $term) {
+ if ($term['type'] != TERM_MENTION) {
+ continue;
+ }
+ $profile = Probe::uri($term['url'], Protocol::ACTIVITYPUB);
+ if ($profile['network'] == Protocol::ACTIVITYPUB) {
+ $data['cc'][] = $profile['url'];
+ }
+ }
+ } else {
+ $receiver_list = Item::enumeratePermissions($item);
+
+ $mentioned = [];
+
+ foreach ($terms as $term) {
+ if ($term['type'] != TERM_MENTION) {
+ continue;
+ }
+ $cid = Contact::getIdForURL($term['url'], $item['uid']);
+ if (!empty($cid) && in_array($cid, $receiver_list)) {
+ $contact = DBA::selectFirst('contact', ['url'], ['id' => $cid, 'network' => Protocol::ACTIVITYPUB]);
+ $data['to'][] = $contact['url'];
+ }
+ }
+
+ foreach ($receiver_list as $receiver) {
+ $contact = DBA::selectFirst('contact', ['url'], ['id' => $receiver, 'network' => Protocol::ACTIVITYPUB]);
+ $data['cc'][] = $contact['url'];
+ }
+
+ if (empty($data['to'])) {
+ $data['to'] = $data['cc'];
+ unset($data['cc']);
+ }
+ }
+
+ return $data;
+ }
+
+ public static function fetchTargetInboxes($item)
+ {
+ $inboxes = [];
+
+ $terms = Term::tagArrayFromItemId($item['id']);
+ if (!$item['private']) {
+ $contacts = DBA::select('contact', ['notify', 'batch'], ['uid' => $item['uid'], 'network' => Protocol::ACTIVITYPUB]);
+ while ($contact = DBA::fetch($contacts)) {
+ $contact = defaults($contact, 'batch', $contact['notify']);
+ $inboxes[$contact] = $contact;
+ }
+ DBA::close($contacts);
+
+ foreach ($terms as $term) {
+ if ($term['type'] != TERM_MENTION) {
+ continue;
+ }
+ $profile = Probe::uri($term['url'], Protocol::ACTIVITYPUB);
+ if ($profile['network'] == Protocol::ACTIVITYPUB) {
+ $target = defaults($profile, 'batch', $profile['notify']);
+ $inboxes[$target] = $target;
+ }
+ }
+ } else {
+ $receiver_list = Item::enumeratePermissions($item);
+
+ $mentioned = [];
+
+ foreach ($terms as $term) {
+ if ($term['type'] != TERM_MENTION) {
+ continue;
+ }
+ $cid = Contact::getIdForURL($term['url'], $item['uid']);
+ if (!empty($cid) && in_array($cid, $receiver_list)) {
+ $contact = DBA::selectFirst('contact', ['url'], ['id' => $cid, 'network' => Protocol::ACTIVITYPUB]);
+ $profile = Probe::uri($contact['url'], Protocol::ACTIVITYPUB);
+ if ($profile['network'] == Protocol::ACTIVITYPUB) {
+ $target = defaults($profile, 'batch', $profile['notify']);
+ $inboxes[$target] = $target;
+ }
+ }
+ }
+
+ foreach ($receiver_list as $receiver) {
+ $contact = DBA::selectFirst('contact', ['url'], ['id' => $receiver, 'network' => Protocol::ACTIVITYPUB]);
+ $profile = Probe::uri($contact['url'], Protocol::ACTIVITYPUB);
+ if ($profile['network'] == Protocol::ACTIVITYPUB) {
+ $target = defaults($profile, 'batch', $profile['notify']);
+ $inboxes[$target] = $target;
+ }
+ }
+ }
+
+ return $inboxes;
+ }
+
public static function createActivityFromItem($item_id)
{
$item = Item::selectFirst([], ['id' => $item_id]);
'toot' => 'http://joinmastodon.org/ns#']]];
$data['type'] = 'Create';
- $data['id'] = $item['uri'] . '/activity';
+ $data['id'] = $item['uri'] . '#activity';
$data['actor'] = $item['author-link'];
- $data['to'] = 'https://www.w3.org/ns/activitystreams#Public';
+ $data = array_merge($data, ActivityPub::createPermissionBlockForItem($item));
+
$data['object'] = self::createNote($item);
return $data;
}
+ public static function createObjectFromItemID($item_id)
+ {
+ $item = Item::selectFirst([], ['id' => $item_id]);
+
+ if (!DBA::isResult($item)) {
+ return false;
+ }
+
+ $data = ['@context' => ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1',
+ ['Emoji' => 'toot:Emoji', 'Hashtag' => 'as:Hashtag', 'atomUri' => 'ostatus:atomUri',
+ 'conversation' => 'ostatus:conversation', 'inReplyToAtomUri' => 'ostatus:inReplyToAtomUri',
+ 'ostatus' => 'http://ostatus.org#', 'sensitive' => 'as:sensitive',
+ 'toot' => 'http://joinmastodon.org/ns#']]];
+
+ $data = array_merge($data, self::createNote($item));
+
+
+ return $data;
+ }
+
public static function createNote($item)
{
$data = [];
$data['context'] = $data['conversation'] = $conversation_uri;
$data['actor'] = $item['author-link'];
- if (!$item['private']) {
- $data['to'] = 'https://www.w3.org/ns/activitystreams#Public';
- }
+ $data = array_merge($data, ActivityPub::createPermissionBlockForItem($item));
$data['published'] = DateTimeFormat::utc($item["created"]."+00:00", DateTimeFormat::ATOM);
$data['updated'] = DateTimeFormat::utc($item["edited"]."+00:00", DateTimeFormat::ATOM);
$data['attributedTo'] = $item['author-link'];
--- /dev/null
+<?php
+/**
+ * @file src/Worker/APDelivery.php
+ */
+namespace Friendica\Worker;
+
+use Friendica\BaseObject;
+use Friendica\Protocol\ActivityPub;
+use Friendica\Model\Item;
+
+class APDelivery extends BaseObject
+{
+ public static function execute($cmd, $item_id, $inbox)
+ {
+ logger('Invoked: ' . $cmd . ': ' . $item_id . ' to ' . $inbox, LOGGER_DEBUG);
+
+ if ($cmd == Delivery::MAIL) {
+ } elseif ($cmd == Delivery::SUGGESTION) {
+ } elseif ($cmd == Delivery::RELOCATION) {
+ } else {
+ $item = Item::selectFirst(['uid'], ['id' => $item_id]);
+ $data = ActivityPub::createActivityFromItem($item_id);
+ ActivityPub::transmit($data, $inbox, $item['uid']);
+ }
+
+ return;
+ }
+}
use Friendica\Model\Queue;
use Friendica\Model\User;
use Friendica\Protocol\DFRN;
-use Friendica\Protocol\ActivityPub;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\Email;
switch ($contact['network']) {
- case Protocol::ACTIVITYPUB:
- self::deliverActivityPub($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup);
- break;
-
case Protocol::DFRN:
self::deliverDFRN($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup);
break;
logger('Unknown mode ' . $cmd . ' for ' . $loc);
}
- /**
- * @brief Deliver content via ActivityPub
-q *
- * @param string $cmd Command
- * @param array $contact Contact record of the receiver
- * @param array $owner Owner record of the sender
- * @param array $items Item record of the content and the parent
- * @param array $target_item Item record of the content
- * @param boolean $public_message Is the content public?
- * @param boolean $top_level Is it a thread starter?
- * @param boolean $followup Is it an answer to a remote post?
- */
- private static function deliverActivityPub($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup)
- {
- // We don't treat Forum posts as "wall-to-wall" to be able to post them via ActivityPub
- $walltowall = $top_level && ($owner['id'] != $items[0]['contact-id']) & ($owner['account-type'] != Contact::ACCOUNT_TYPE_COMMUNITY);
-
- if ($public_message) {
- $loc = 'public batch ' . $contact['batch'];
- } else {
- $loc = $contact['addr'];
- }
-
- logger('Deliver ' . $target_item["guid"] . ' via ActivityPub to ' . $loc);
-
-// if (Config::get('system', 'dfrn_only') || !Config::get('system', 'diaspora_enabled')) {
-// return;
-// }
- if ($cmd == self::MAIL) {
-// ActivityPub::sendMail($target_item, $owner, $contact);
- return;
- }
-
- if ($cmd == self::SUGGESTION) {
- return;
- }
-// if (!$contact['pubkey'] && !$public_message) {
-// logger('No public key, no delivery.');
-// return;
-// }
- if (($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) {
- // top-level retraction
- logger('ActivityPub retract: ' . $loc);
-// ActivityPub::sendRetraction($target_item, $owner, $contact, $public_message);
- return;
- } elseif ($cmd == self::RELOCATION) {
-// ActivityPub::sendAccountMigration($owner, $contact, $owner['uid']);
- return;
- } elseif ($followup) {
- // send comments and likes to owner to relay
- logger('ActivityPub followup: ' . $loc);
- $data = ActivityPub::createActivityFromItem($target_item['id']);
- ActivityPub::transmit($data, $contact['notify'], $owner['uid']);
-// ActivityPub::sendFollowup($target_item, $owner, $contact, $public_message);
- return;
- } elseif ($target_item['uri'] !== $target_item['parent-uri']) {
- // we are the relay - send comments, likes and relayable_retractions to our conversants
- logger('ActivityPub relay: ' . $loc);
- $data = ActivityPub::createActivityFromItem($target_item['id']);
- ActivityPub::transmit($data, $contact['notify'], $owner['uid']);
-// ActivityPub::sendRelay($target_item, $owner, $contact, $public_message);
- return;
- } elseif ($top_level && !$walltowall) {
- // currently no workable solution for sending walltowall
- logger('ActivityPub status: ' . $loc);
- $data = ActivityPub::createActivityFromItem($target_item['id']);
- ActivityPub::transmit($data, $contact['notify'], $owner['uid']);
-// ActivityPub::sendStatus($target_item, $owner, $contact, $public_message);
- return;
- }
-
- logger('Unknown mode ' . $cmd . ' for ' . $loc);
- }
-
/**
* @brief Deliver content via mail
*
use Friendica\Model\PushSubscriber;
use Friendica\Model\User;
use Friendica\Network\Probe;
+use Friendica\Protocol\ActivityPub;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\OStatus;
use Friendica\Protocol\Salmon;
}
// It only makes sense to distribute answers to OStatus messages to Friendica and OStatus - but not Diaspora
- $networks = [Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DFRN];
+ $networks = [Protocol::OSTATUS, Protocol::DFRN];
} else {
- $networks = [Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DFRN, Protocol::DIASPORA, Protocol::MAIL];
+ $networks = [Protocol::OSTATUS, Protocol::DFRN, Protocol::DIASPORA, Protocol::MAIL];
}
} else {
$public_message = false;
}
}
+ $inboxes = ActivityPub::fetchTargetInboxes($target_item);
+ foreach ($inboxes as $inbox) {
+ logger('Deliver ' . $item_id .' to ' . $inbox .' via ActivityPub', LOGGER_DEBUG);
+
+ Worker::add(['priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true],
+ 'APDelivery', $cmd, $item_id, $inbox);
+ }
+
// send salmon slaps to mentioned remote tags (@foo@example.com) in OStatus posts
// They are especially used for notifications to OStatus users that don't follow us.
if (!Config::get('system', 'dfrn_only') && count($url_recipients) && ($public_message || $push_notify) && $normal_mode) {
}
}
- $condition = ['network' => [Protocol::DFRN, Protocol::ACTIVITYPUB], 'uid' => $owner['uid'], 'blocked' => false,
+ $condition = ['network' => Protocol::DFRN, 'uid' => $owner['uid'], 'blocked' => false,
'pending' => false, 'archive' => false, 'rel' => [Contact::FOLLOWER, Contact::FRIEND]];
$r2 = DBA::toArray(DBA::select('contact', ['id', 'name', 'network'], $condition));