New delivery module for ap
This commit is contained in:
parent
91d1b4de5d
commit
f772ece86f
7 changed files with 183 additions and 89 deletions
|
@ -80,7 +80,7 @@ function display_init(App $a)
|
|||
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();
|
||||
}
|
||||
|
|
|
@ -2851,7 +2851,7 @@ class Item extends BaseObject
|
|||
}
|
||||
|
||||
// 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']));
|
||||
|
|
|
@ -33,6 +33,17 @@ class Term
|
|||
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 = '';
|
||||
|
|
|
@ -13,6 +13,7 @@ use Friendica\Core\Protocol;
|
|||
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;
|
||||
|
@ -153,6 +154,111 @@ class ActivityPub
|
|||
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]);
|
||||
|
@ -177,13 +283,34 @@ class ActivityPub
|
|||
'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 = [];
|
||||
|
@ -203,9 +330,7 @@ class ActivityPub
|
|||
|
||||
$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'];
|
||||
|
|
28
src/Worker/APDelivery.php
Normal file
28
src/Worker/APDelivery.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?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;
|
||||
}
|
||||
}
|
|
@ -15,7 +15,6 @@ use Friendica\Model\Item;
|
|||
use Friendica\Model\Queue;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Protocol\DFRN;
|
||||
use Friendica\Protocol\ActivityPub;
|
||||
use Friendica\Protocol\Diaspora;
|
||||
use Friendica\Protocol\Email;
|
||||
|
||||
|
@ -166,10 +165,6 @@ class Delivery extends BaseObject
|
|||
|
||||
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;
|
||||
|
@ -388,80 +383,6 @@ class Delivery extends BaseObject
|
|||
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
|
||||
*
|
||||
|
|
|
@ -16,6 +16,7 @@ use Friendica\Model\Item;
|
|||
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;
|
||||
|
@ -363,9 +364,9 @@ class Notifier
|
|||
}
|
||||
|
||||
// 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;
|
||||
|
@ -413,6 +414,14 @@ class Notifier
|
|||
}
|
||||
}
|
||||
|
||||
$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) {
|
||||
|
@ -448,7 +457,7 @@ class Notifier
|
|||
}
|
||||
}
|
||||
|
||||
$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));
|
||||
|
|
Loading…
Reference in a new issue