Merge pull request #11392 from annando/new-acitivities
Store all known incoming actitivies
This commit is contained in:
commit
79526564ca
8 changed files with 141 additions and 16 deletions
|
@ -1,6 +1,6 @@
|
||||||
-- ------------------------------------------
|
-- ------------------------------------------
|
||||||
-- Friendica 2022.05-dev (Siberian Iris)
|
-- Friendica 2022.05-dev (Siberian Iris)
|
||||||
-- DB_UPDATE_VERSION 1453
|
-- DB_UPDATE_VERSION 1454
|
||||||
-- ------------------------------------------
|
-- ------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@ -332,6 +332,8 @@ CREATE TABLE IF NOT EXISTS `apcontact` (
|
||||||
`inbox` varchar(255) NOT NULL COMMENT '',
|
`inbox` varchar(255) NOT NULL COMMENT '',
|
||||||
`outbox` varchar(255) COMMENT '',
|
`outbox` varchar(255) COMMENT '',
|
||||||
`sharedinbox` varchar(255) COMMENT '',
|
`sharedinbox` varchar(255) COMMENT '',
|
||||||
|
`featured` varchar(255) COMMENT 'Address for the collection of featured posts',
|
||||||
|
`featured-tags` varchar(255) COMMENT 'Address for the collection of featured tags',
|
||||||
`manually-approve` boolean COMMENT '',
|
`manually-approve` boolean COMMENT '',
|
||||||
`discoverable` boolean COMMENT 'Mastodon extension: true if profile is published in their directory',
|
`discoverable` boolean COMMENT 'Mastodon extension: true if profile is published in their directory',
|
||||||
`nick` varchar(255) NOT NULL DEFAULT '' COMMENT '',
|
`nick` varchar(255) NOT NULL DEFAULT '' COMMENT '',
|
||||||
|
|
|
@ -17,6 +17,8 @@ Fields
|
||||||
| inbox | | varchar(255) | NO | | NULL | |
|
| inbox | | varchar(255) | NO | | NULL | |
|
||||||
| outbox | | varchar(255) | YES | | NULL | |
|
| outbox | | varchar(255) | YES | | NULL | |
|
||||||
| sharedinbox | | varchar(255) | YES | | NULL | |
|
| sharedinbox | | varchar(255) | YES | | NULL | |
|
||||||
|
| featured | Address for the collection of featured posts | varchar(255) | YES | | NULL | |
|
||||||
|
| featured-tags | Address for the collection of featured tags | varchar(255) | YES | | NULL | |
|
||||||
| manually-approve | | boolean | YES | | NULL | |
|
| manually-approve | | boolean | YES | | NULL | |
|
||||||
| discoverable | Mastodon extension: true if profile is published in their directory | boolean | YES | | NULL | |
|
| discoverable | Mastodon extension: true if profile is published in their directory | boolean | YES | | NULL | |
|
||||||
| nick | | varchar(255) | NO | | | |
|
| nick | | varchar(255) | NO | | | |
|
||||||
|
|
|
@ -232,6 +232,9 @@ class APContact
|
||||||
self::unarchiveInbox($apcontact['sharedinbox'], true);
|
self::unarchiveInbox($apcontact['sharedinbox'], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$apcontact['featured'] = JsonLD::fetchElement($compacted, 'toot:featured', '@id');
|
||||||
|
$apcontact['featured-tags'] = JsonLD::fetchElement($compacted, 'toot:featuredTags', '@id');
|
||||||
|
|
||||||
$apcontact['nick'] = JsonLD::fetchElement($compacted, 'as:preferredUsername', '@value') ?? '';
|
$apcontact['nick'] = JsonLD::fetchElement($compacted, 'as:preferredUsername', '@value') ?? '';
|
||||||
$apcontact['name'] = JsonLD::fetchElement($compacted, 'as:name', '@value');
|
$apcontact['name'] = JsonLD::fetchElement($compacted, 'as:name', '@value');
|
||||||
|
|
||||||
|
|
|
@ -176,6 +176,20 @@ final class Activity
|
||||||
const O_UNFOLLOW = ActivityNamespace::OSTATUS . '/unfollow';
|
const O_UNFOLLOW = ActivityNamespace::OSTATUS . '/unfollow';
|
||||||
const O_UNFAVOURITE = ActivityNamespace::OSTATUS . '/unfavorite';
|
const O_UNFAVOURITE = ActivityNamespace::OSTATUS . '/unfavorite';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React to a post via an emoji
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const EMOJIREACT = ActivityNamespace::LITEPUB . '/emojireact';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View notification from Peertube
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const VIEW = ActivityNamespace::PEERTUBE . '/view';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* likes (etc.) can apply to other things besides posts. Check if they are post children,
|
* likes (etc.) can apply to other things besides posts. Check if they are post children,
|
||||||
* in which case we handle them specially
|
* in which case we handle them specially
|
||||||
|
@ -183,10 +197,12 @@ final class Activity
|
||||||
* Hidden activities, which doesn't need to be shown
|
* Hidden activities, which doesn't need to be shown
|
||||||
*/
|
*/
|
||||||
const HIDDEN_ACTIVITIES = [
|
const HIDDEN_ACTIVITIES = [
|
||||||
Activity::LIKE, Activity::DISLIKE,
|
self::LIKE, self::DISLIKE,
|
||||||
Activity::ATTEND, Activity::ATTENDNO, Activity::ATTENDMAYBE,
|
self::ATTEND, self::ATTENDNO, self::ATTENDMAYBE,
|
||||||
Activity::FOLLOW,
|
self::FOLLOW,
|
||||||
Activity::ANNOUNCE,
|
self::ANNOUNCE,
|
||||||
|
self::EMOJIREACT,
|
||||||
|
self::VIEW,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -144,8 +144,19 @@ final class ActivityNamespace
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const ATOM1 = 'http://www.w3.org/2005/Atom';
|
const ATOM1 = 'http://www.w3.org/2005/Atom';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const MASTODON = 'http://mastodon.social/schema/1.0';
|
const MASTODON = 'http://mastodon.social/schema/1.0';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const LITEPUB = 'http://litepub.social';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const PEERTUBE = 'https://joinpeertube.org';
|
||||||
}
|
}
|
||||||
|
|
|
@ -430,11 +430,88 @@ class Processor
|
||||||
unset($item['post-type']);
|
unset($item['post-type']);
|
||||||
$item['object-type'] = Activity\ObjectType::NOTE;
|
$item['object-type'] = Activity\ObjectType::NOTE;
|
||||||
|
|
||||||
|
if (!empty($activity['content'])) {
|
||||||
|
$item['body'] = HTML::toBBCode($activity['content']);
|
||||||
|
}
|
||||||
|
|
||||||
$item['diaspora_signed_text'] = $activity['diaspora:like'] ?? '';
|
$item['diaspora_signed_text'] = $activity['diaspora:like'] ?? '';
|
||||||
|
|
||||||
self::postItem($activity, $item);
|
self::postItem($activity, $item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the Uri-Id of a post for the "featured" collection
|
||||||
|
*
|
||||||
|
* @param array $activity
|
||||||
|
* @return null|int
|
||||||
|
*/
|
||||||
|
private static function getUriIdForFeaturedCollection(array $activity)
|
||||||
|
{
|
||||||
|
$actor = APContact::getByURL($activity['actor']);
|
||||||
|
if (empty($actor)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refetch the account when the "featured" collection is missing.
|
||||||
|
// This can be removed in a future version (end of 2022 should be good).
|
||||||
|
if (empty($actor['featured'])) {
|
||||||
|
$actor = APContact::getByURL($activity['actor'], true);
|
||||||
|
if (empty($actor)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity['target_id'] != $actor['featured']) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = Contact::getIdForURL($activity['actor']);
|
||||||
|
if (empty($id)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent = Post::selectFirst(['uri-id'], ['uri' => $activity['object_id'], 'author-id' => $id]);
|
||||||
|
if (!empty($parent['uri-id'])) {
|
||||||
|
return $parent['uri-id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a post to the "Featured" collection
|
||||||
|
*
|
||||||
|
* @param array $activity
|
||||||
|
*/
|
||||||
|
public static function addToFeaturedCollection(array $activity)
|
||||||
|
{
|
||||||
|
$uriid = self::getUriIdForFeaturedCollection($activity);
|
||||||
|
if (empty($uriid)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::debug('Add post to featured collection', ['uri-id' => $uriid]);
|
||||||
|
|
||||||
|
// @todo Add functionality
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a post to the "Featured" collection
|
||||||
|
*
|
||||||
|
* @param array $activity
|
||||||
|
*/
|
||||||
|
public static function removeFromFeaturedCollection(array $activity)
|
||||||
|
{
|
||||||
|
$uriid = self::getUriIdForFeaturedCollection($activity);
|
||||||
|
if (empty($uriid)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::debug('Remove post from featured collection', ['uri-id' => $uriid]);
|
||||||
|
|
||||||
|
// @todo Add functionality
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an event
|
* Create an event
|
||||||
*
|
*
|
||||||
|
|
|
@ -385,7 +385,7 @@ class Receiver
|
||||||
} else {
|
} else {
|
||||||
$object_data['directmessage'] = JsonLD::fetchElement($activity, 'litepub:directMessage');
|
$object_data['directmessage'] = JsonLD::fetchElement($activity, 'litepub:directMessage');
|
||||||
}
|
}
|
||||||
} elseif (in_array($type, array_merge(self::ACTIVITY_TYPES, ['as:Follow'])) && in_array($object_type, self::CONTENT_TYPES)) {
|
} elseif (in_array($type, array_merge(self::ACTIVITY_TYPES, ['as:Follow', 'litepub:EmojiReact', 'as:View'])) && in_array($object_type, self::CONTENT_TYPES)) {
|
||||||
// Create a mostly empty array out of the activity data (instead of the object).
|
// Create a mostly empty array out of the activity data (instead of the object).
|
||||||
// This way we later don't have to check for the existence of each individual array element.
|
// This way we later don't have to check for the existence of each individual array element.
|
||||||
$object_data = self::processObject($activity);
|
$object_data = self::processObject($activity);
|
||||||
|
@ -578,8 +578,7 @@ class Receiver
|
||||||
if ($object_data['object_type'] == 'as:tag') {
|
if ($object_data['object_type'] == 'as:tag') {
|
||||||
ActivityPub\Processor::addTag($object_data);
|
ActivityPub\Processor::addTag($object_data);
|
||||||
} elseif (in_array($object_data['object_type'], self::CONTENT_TYPES)) {
|
} elseif (in_array($object_data['object_type'], self::CONTENT_TYPES)) {
|
||||||
// Seems to be used by Mastodon to announce that a post is pinned
|
ActivityPub\Processor::addToFeaturedCollection($object_data);
|
||||||
self::storeUnhandledActivity(false, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer);
|
|
||||||
} elseif ($object_data['object_type'] == '') {
|
} elseif ($object_data['object_type'] == '') {
|
||||||
// The object type couldn't be determined. We don't have it and we can't fetch it. We ignore this activity.
|
// The object type couldn't be determined. We don't have it and we can't fetch it. We ignore this activity.
|
||||||
} else {
|
} else {
|
||||||
|
@ -680,8 +679,7 @@ class Receiver
|
||||||
|
|
||||||
case 'as:Remove':
|
case 'as:Remove':
|
||||||
if (in_array($object_data['object_type'], self::CONTENT_TYPES)) {
|
if (in_array($object_data['object_type'], self::CONTENT_TYPES)) {
|
||||||
// Seems to be used by Mastodon to remove the pinned status of a post
|
ActivityPub\Processor::removeFromFeaturedCollection($object_data);
|
||||||
self::storeUnhandledActivity(false, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer);
|
|
||||||
} elseif ($object_data['object_type'] == '') {
|
} elseif ($object_data['object_type'] == '') {
|
||||||
// The object type couldn't be determined. We don't have it and we can't fetch it. We ignore this activity.
|
// The object type couldn't be determined. We don't have it and we can't fetch it. We ignore this activity.
|
||||||
} else {
|
} else {
|
||||||
|
@ -745,16 +743,20 @@ class Receiver
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'as:View':
|
case 'as:View':
|
||||||
if (in_array($object_data['object_type'], ['as:Note', 'as:Video'])) {
|
if (in_array($object_data['object_type'], self::CONTENT_TYPES)) {
|
||||||
// Unhandled Peertube activity
|
ActivityPub\Processor::createActivity($object_data, Activity::VIEW);
|
||||||
|
} elseif ($object_data['object_type'] == '') {
|
||||||
|
// The object type couldn't be determined. Most likely we don't have it here. We ignore this activity.
|
||||||
} else {
|
} else {
|
||||||
self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer);
|
self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'litepub:EmojiReact':
|
case 'litepub:EmojiReact':
|
||||||
if (in_array($object_data['object_type'], array_merge([''], self::CONTENT_TYPES))) {
|
if (in_array($object_data['object_type'], self::CONTENT_TYPES)) {
|
||||||
// Unhandled Pleroma activity to react to a post via an emoji
|
ActivityPub\Processor::createActivity($object_data, Activity::EMOJIREACT);
|
||||||
|
} elseif ($object_data['object_type'] == '') {
|
||||||
|
// The object type couldn't be determined. We don't have it and we can't fetch it. We ignore this activity.
|
||||||
} else {
|
} else {
|
||||||
self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer);
|
self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer);
|
||||||
}
|
}
|
||||||
|
@ -787,7 +789,17 @@ class Receiver
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tempfile = tempnam(System::getTempPath(), ($unknown ? 'unknown-' : 'unhandled-') . str_replace(':', '-', $type) . '-' . str_replace(':', '-', $object_data['object_type']) . '-' . str_replace(':', '-', $object_data['object_object_type'] ?? '') . '-');
|
$file = ($unknown ? 'unknown-' : 'unhandled-') . str_replace(':', '-', $type) . '-';
|
||||||
|
|
||||||
|
if (!empty($object_data['object_type'])) {
|
||||||
|
$file .= str_replace(':', '-', $object_data['object_type']) . '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($object_data['object_object_type'])) {
|
||||||
|
$file .= str_replace(':', '-', $object_data['object_object_type']) . '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
$tempfile = tempnam(System::getTempPath(), $file);
|
||||||
file_put_contents($tempfile, json_encode(['activity' => $activity, 'body' => $body, 'uid' => $uid, 'trust_source' => $trust_source, 'push' => $push, 'signer' => $signer, 'object_data' => $object_data], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
file_put_contents($tempfile, json_encode(['activity' => $activity, 'body' => $body, 'uid' => $uid, 'trust_source' => $trust_source, 'push' => $push, 'signer' => $signer, 'object_data' => $object_data], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
||||||
Logger::notice('Unknown activity stored', ['type' => $type, 'object_type' => $object_data['object_type'], $object_data['object_object_type'] ?? '', 'file' => $tempfile]);
|
Logger::notice('Unknown activity stored', ['type' => $type, 'object_type' => $object_data['object_type'], $object_data['object_object_type'] ?? '', 'file' => $tempfile]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
|
|
||||||
if (!defined('DB_UPDATE_VERSION')) {
|
if (!defined('DB_UPDATE_VERSION')) {
|
||||||
define('DB_UPDATE_VERSION', 1453);
|
define('DB_UPDATE_VERSION', 1454);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
@ -394,6 +394,8 @@ return [
|
||||||
"inbox" => ["type" => "varchar(255)", "not null" => "1", "comment" => ""],
|
"inbox" => ["type" => "varchar(255)", "not null" => "1", "comment" => ""],
|
||||||
"outbox" => ["type" => "varchar(255)", "comment" => ""],
|
"outbox" => ["type" => "varchar(255)", "comment" => ""],
|
||||||
"sharedinbox" => ["type" => "varchar(255)", "comment" => ""],
|
"sharedinbox" => ["type" => "varchar(255)", "comment" => ""],
|
||||||
|
"featured" => ["type" => "varchar(255)", "comment" => "Address for the collection of featured posts"],
|
||||||
|
"featured-tags" => ["type" => "varchar(255)", "comment" => "Address for the collection of featured tags"],
|
||||||
"manually-approve" => ["type" => "boolean", "comment" => ""],
|
"manually-approve" => ["type" => "boolean", "comment" => ""],
|
||||||
"discoverable" => ["type" => "boolean", "comment" => "Mastodon extension: true if profile is published in their directory"],
|
"discoverable" => ["type" => "boolean", "comment" => "Mastodon extension: true if profile is published in their directory"],
|
||||||
"nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
"nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||||
|
|
Loading…
Reference in a new issue