Merge pull request #12409 from annando/diaspora-reshare
Use reshare with Diaspora like with ActivityPub
This commit is contained in:
commit
8e25660616
13 changed files with 116 additions and 89 deletions
|
@ -1,6 +1,6 @@
|
|||
-- ------------------------------------------
|
||||
-- Friendica 2023.03-dev (Giant Rhubarb)
|
||||
-- DB_UPDATE_VERSION 1502
|
||||
-- DB_UPDATE_VERSION 1503
|
||||
-- ------------------------------------------
|
||||
|
||||
|
||||
|
@ -1439,7 +1439,7 @@ CREATE TABLE IF NOT EXISTS `post-user` (
|
|||
`event-id` int unsigned COMMENT 'Used to link to the event.id',
|
||||
`unseen` boolean NOT NULL DEFAULT '1' COMMENT 'post has not been seen',
|
||||
`hidden` boolean NOT NULL DEFAULT '0' COMMENT 'Marker to hide the post from the user',
|
||||
`notification-type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '',
|
||||
`notification-type` smallint unsigned NOT NULL DEFAULT 0 COMMENT '',
|
||||
`wall` boolean NOT NULL DEFAULT '0' COMMENT 'This item was posted to the wall of uid',
|
||||
`origin` boolean NOT NULL DEFAULT '0' COMMENT 'item originated at this site',
|
||||
`psid` int unsigned COMMENT 'ID of the permission set of this post',
|
||||
|
|
|
@ -34,7 +34,7 @@ Fields
|
|||
| event-id | Used to link to the event.id | int unsigned | YES | | NULL | |
|
||||
| unseen | post has not been seen | boolean | NO | | 1 | |
|
||||
| hidden | Marker to hide the post from the user | boolean | NO | | 0 | |
|
||||
| notification-type | | tinyint unsigned | NO | | 0 | |
|
||||
| notification-type | | smallint unsigned | NO | | 0 | |
|
||||
| wall | This item was posted to the wall of uid | boolean | NO | | 0 | |
|
||||
| origin | item originated at this site | boolean | NO | | 0 | |
|
||||
| psid | ID of the permission set of this post | int unsigned | YES | | NULL | |
|
||||
|
|
|
@ -985,7 +985,8 @@ class Conversation
|
|||
|
||||
$thread_items = Post::selectForUser($uid, array_merge(ItemModel::DISPLAY_FIELDLIST, ['featured', 'contact-uid', 'gravity', 'post-type', 'post-reason']), $condition, $params);
|
||||
|
||||
$items = [];
|
||||
$items = [];
|
||||
$quote_uri_ids = [];
|
||||
|
||||
while ($row = Post::fetch($thread_items)) {
|
||||
if (!empty($items[$row['uri-id']]) && ($row['uid'] == 0)) {
|
||||
|
@ -1005,11 +1006,37 @@ class Conversation
|
|||
}
|
||||
}
|
||||
|
||||
if (in_array($row['gravity'], [ItemModel::GRAVITY_PARENT, ItemModel::GRAVITY_COMMENT])) {
|
||||
$quote_uri_ids[$row['uri-id']] = [
|
||||
'uri-id' => $row['uri-id'],
|
||||
'uri' => $row['uri'],
|
||||
'parent-uri-id' => $row['parent-uri-id'],
|
||||
'parent-uri' => $row['parent-uri'],
|
||||
];
|
||||
}
|
||||
|
||||
$items[$row['uri-id']] = $this->addRowInformation($row, $activities[$row['uri-id']] ?? [], $thr_parent[$row['thr-parent-id']] ?? []);
|
||||
}
|
||||
|
||||
DBA::close($thread_items);
|
||||
|
||||
$quotes = Post::select(array_merge(ItemModel::DISPLAY_FIELDLIST, ['featured', 'contact-uid', 'gravity', 'post-type', 'post-reason']), ['quote-uri-id' => array_column($quote_uri_ids, 'uri-id'), 'body' => '', 'uid' => 0]);
|
||||
while ($quote = Post::fetch($quotes)) {
|
||||
$row = $quote;
|
||||
|
||||
$row['uid'] = $uid;
|
||||
$row['verb'] = $row['body'] = $row['raw-body'] = Activity::ANNOUNCE;
|
||||
$row['gravity'] = ItemModel::GRAVITY_ACTIVITY;
|
||||
$row['object-type'] = Activity\ObjectType::NOTE;
|
||||
$row['parent-uri'] = $quote_uri_ids[$quote['quote-uri-id']]['parent-uri'];
|
||||
$row['parent-uri-id'] = $quote_uri_ids[$quote['quote-uri-id']]['parent-uri-id'];
|
||||
$row['thr-parent'] = $quote_uri_ids[$quote['quote-uri-id']]['uri'];
|
||||
$row['thr-parent-id'] = $quote_uri_ids[$quote['quote-uri-id']]['uri-id'];
|
||||
|
||||
$items[$row['uri-id']] = $this->addRowInformation($row, [], []);
|
||||
}
|
||||
DBA::close($quotes);
|
||||
|
||||
$items = $this->convSort($items, $order);
|
||||
|
||||
$this->profiler->stopRecording();
|
||||
|
|
|
@ -115,13 +115,18 @@ class Status extends BaseFactory
|
|||
'gravity' => Item::GRAVITY_ACTIVITY,
|
||||
'vid' => Verb::getID(Activity::ANNOUNCE),
|
||||
'deleted' => false
|
||||
], []);
|
||||
]) + Post::countPosts([
|
||||
'quote-uri-id' => $uriId,
|
||||
'body' => '',
|
||||
'deleted' => false
|
||||
]);
|
||||
|
||||
$count_like = Post::countPosts([
|
||||
'thr-parent-id' => $uriId,
|
||||
'gravity' => Item::GRAVITY_ACTIVITY,
|
||||
'vid' => Verb::getID(Activity::LIKE),
|
||||
'deleted' => false
|
||||
], []);
|
||||
]);
|
||||
|
||||
$counts = new \Friendica\Object\Api\Mastodon\Status\Counts(
|
||||
Post::countPosts(['thr-parent-id' => $uriId, 'gravity' => Item::GRAVITY_COMMENT, 'deleted' => false], []),
|
||||
|
@ -144,6 +149,12 @@ class Status extends BaseFactory
|
|||
'gravity' => Item::GRAVITY_ACTIVITY,
|
||||
'vid' => Verb::getID(Activity::ANNOUNCE),
|
||||
'deleted' => false
|
||||
]) || Post::exists([
|
||||
'quote-uri-id' => $uriId,
|
||||
'uid' => $uid,
|
||||
'origin' => true,
|
||||
'body' => '',
|
||||
'deleted' => false
|
||||
]);
|
||||
$userAttributes = new \Friendica\Object\Api\Mastodon\Status\UserAttributes(
|
||||
$origin_like,
|
||||
|
|
|
@ -1544,8 +1544,8 @@ class Contact
|
|||
$contact_field = ((($contact["contact-type"] == self::TYPE_COMMUNITY) || ($contact['network'] == Protocol::MAIL)) ? 'owner-id' : 'author-id');
|
||||
|
||||
if ($thread_mode) {
|
||||
$condition = ["((`$contact_field` = ? AND `gravity` = ?) OR (`author-id` = ? AND `gravity` = ? AND `vid` = ? AND `thr-parent-id` = `parent-uri-id`)) AND " . $sql,
|
||||
$cid, Item::GRAVITY_PARENT, $cid, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), DI::userSession()->getLocalUserId()];
|
||||
$condition = ["((`$contact_field` = ? AND `gravity` = ?) OR (`author-id` = ? AND `gravity` = ? AND `vid` = ? AND `protocol` != ? AND `thr-parent-id` = `parent-uri-id`)) AND " . $sql,
|
||||
$cid, Item::GRAVITY_PARENT, $cid, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), Conversation::PARCEL_DIASPORA, DI::userSession()->getLocalUserId()];
|
||||
} else {
|
||||
$condition = ["`$contact_field` = ? AND `gravity` IN (?, ?) AND " . $sql,
|
||||
$cid, Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, DI::userSession()->getLocalUserId()];
|
||||
|
|
|
@ -27,7 +27,6 @@ use Friendica\Core\Hook;
|
|||
use Friendica\Core\Logger;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Database\DBStructure;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Item;
|
||||
|
@ -52,6 +51,7 @@ class UserNotification
|
|||
const TYPE_DIRECT_THREAD_COMMENT = 64;
|
||||
const TYPE_SHARED = 128;
|
||||
const TYPE_FOLLOW = 256;
|
||||
const TYPE_QUOTED = 512;
|
||||
|
||||
/**
|
||||
* Insert a new user notification entry
|
||||
|
@ -273,6 +273,14 @@ class UserNotification
|
|||
}
|
||||
}
|
||||
|
||||
if (($item['verb'] != Activity::ANNOUNCE) && self::checkQuoted($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::TYPE_QUOTED;
|
||||
if (!$notified) {
|
||||
self::insertNotificationByItem(self::TYPE_QUOTED, $uid, $item);
|
||||
$notified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (($item['verb'] != Activity::ANNOUNCE) && self::checkFollowParticipation($item, $contacts)) {
|
||||
$notification_type = $notification_type | self::TYPE_FOLLOW;
|
||||
if (!$notified) {
|
||||
|
@ -581,4 +589,23 @@ class UserNotification
|
|||
$condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_ACTIVITY];
|
||||
return Post::exists($condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a quoted post of a post of the given user
|
||||
*
|
||||
* @param array $item
|
||||
* @param array $contacts Array of contact IDs
|
||||
* @return bool The item is a quoted post of a user's post or comment
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function checkQuoted(array $item, array $contacts): bool
|
||||
{
|
||||
if (empty($item['quote-uri-id'])) {
|
||||
return false;
|
||||
}
|
||||
$condition = ['uri-id' => $item['quote-uri-id'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => [item::GRAVITY_PARENT, Item::GRAVITY_COMMENT]];
|
||||
return Post::exists($condition);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ use Friendica\Core\Protocol;
|
|||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Conversation;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Model\Verb;
|
||||
|
@ -81,11 +82,11 @@ class Statuses extends BaseApi
|
|||
|
||||
if (!$request['pinned'] && !$request['only_media']) {
|
||||
if ($request['exclude_replies']) {
|
||||
$condition = DBA::mergeConditions($condition, ["(`gravity` = ? OR (`gravity` = ? AND `vid` = ?))",
|
||||
Item::GRAVITY_PARENT, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE)]);
|
||||
$condition = DBA::mergeConditions($condition, ["(`gravity` = ? OR (`gravity` = ? AND `vid` = ? AND `protocol` != ?))",
|
||||
Item::GRAVITY_PARENT, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), Conversation::PARCEL_DIASPORA]);
|
||||
} else {
|
||||
$condition = DBA::mergeConditions($condition, ["(`gravity` IN (?, ?) OR (`gravity` = ? AND `vid` = ?))",
|
||||
Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE)]);
|
||||
$condition = DBA::mergeConditions($condition, ["(`gravity` IN (?, ?) OR (`gravity` = ? AND `vid` = ? AND `protocol` != ?))",
|
||||
Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), Conversation::PARCEL_DIASPORA]);
|
||||
}
|
||||
} elseif ($request['exclude_replies']) {
|
||||
$condition = DBA::mergeConditions($condition, ['gravity' => Item::GRAVITY_PARENT]);
|
||||
|
|
|
@ -29,6 +29,7 @@ use Friendica\DI;
|
|||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Protocol\Diaspora;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/statuses/
|
||||
|
@ -49,12 +50,14 @@ class Reblog extends BaseApi
|
|||
DI::mstdnError()->RecordNotFound();
|
||||
}
|
||||
|
||||
if (!in_array($item['network'], [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::TWITTER])) {
|
||||
if ($item['network'] == Protocol::DIASPORA) {
|
||||
Diaspora::performReshare($this->parameters['id'], $uid);
|
||||
} elseif (!in_array($item['network'], [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::TWITTER])) {
|
||||
DI::mstdnError()->UnprocessableEntity(DI::l10n()->t("Posts from %s can't be shared", ContactSelector::networkToName($item['network'])));
|
||||
} else {
|
||||
Item::performActivity($item['id'], 'announce', $uid);
|
||||
}
|
||||
|
||||
Item::performActivity($item['id'], 'announce', $uid);
|
||||
|
||||
System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid)->toArray());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,12 +49,21 @@ class Unreblog extends BaseApi
|
|||
DI::mstdnError()->RecordNotFound();
|
||||
}
|
||||
|
||||
if (!in_array($item['network'], [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::TWITTER])) {
|
||||
if ($item['network'] == Protocol::DIASPORA) {
|
||||
$item = Post::selectFirstForUser($uid, ['id'], ['quote-uri-id' => $this->parameters['id'], 'body' => '', 'origin' => true, 'uid' => $uid]);
|
||||
if (empty($item['id'])) {
|
||||
DI::mstdnError()->RecordNotFound();
|
||||
}
|
||||
|
||||
if (!Item::markForDeletionById($item['id'])) {
|
||||
DI::mstdnError()->RecordNotFound();
|
||||
}
|
||||
} elseif (!in_array($item['network'], [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::TWITTER])) {
|
||||
DI::mstdnError()->UnprocessableEntity(DI::l10n()->t("Posts from %s can't be unshared", ContactSelector::networkToName($item['network'])));
|
||||
} else {
|
||||
Item::performActivity($item['id'], 'unannounce', $uid);
|
||||
}
|
||||
|
||||
Item::performActivity($item['id'], 'unannounce', $uid);
|
||||
|
||||
System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid)->toArray());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,17 +46,26 @@ class Activity extends BaseModule
|
|||
throw new HTTPException\BadRequestException();
|
||||
}
|
||||
|
||||
$verb = $this->parameters['verb'];
|
||||
$itemId = $this->parameters['id'];
|
||||
$verb = $this->parameters['verb'];
|
||||
$itemId = $this->parameters['id'];
|
||||
$handled = false;
|
||||
|
||||
if (in_array($verb, ['announce', 'unannounce'])) {
|
||||
$item = Post::selectFirst(['network', 'uri-id'], ['id' => $itemId, 'uid' => [DI::userSession()->getLocalUserId(), 0]]);
|
||||
if ($item['network'] == Protocol::DIASPORA) {
|
||||
Diaspora::performReshare($item['uri-id'], DI::userSession()->getLocalUserId());
|
||||
$quote = Post::selectFirst(['id'], ['quote-uri-id' => $item['uri-id'], 'body' => '', 'origin' => true, 'uid' => DI::userSession()->getLocalUserId()]);
|
||||
if (!empty($quote['id'])) {
|
||||
if (!Item::markForDeletionById($quote['id'])) {
|
||||
throw new HTTPException\BadRequestException();
|
||||
}
|
||||
} else {
|
||||
Diaspora::performReshare($item['uri-id'], DI::userSession()->getLocalUserId());
|
||||
}
|
||||
$handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Item::performActivity($itemId, $verb, DI::userSession()->getLocalUserId())) {
|
||||
if (!$handled && !Item::performActivity($itemId, $verb, DI::userSession()->getLocalUserId())) {
|
||||
throw new HTTPException\BadRequestException();
|
||||
}
|
||||
|
||||
|
|
|
@ -311,6 +311,10 @@ class Notification extends BaseFactory implements ICanCreateFromTableRow
|
|||
$msg = $l10n->t('%1$s shared a post');
|
||||
}
|
||||
break;
|
||||
|
||||
case Post\UserNotification::TYPE_QUOTED:
|
||||
$msg = $l10n->t('%1$s shared your post %2$s');
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -2285,65 +2285,6 @@ class Diaspora
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a reshare activity
|
||||
*
|
||||
* @param array $item Array of reshare post
|
||||
* @param integer $parent_message_id Id of the parent post
|
||||
* @param string $guid GUID string of reshare action
|
||||
* @param WebFingerUri $author Author handle
|
||||
* @return false|void
|
||||
* @throws InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function addReshareActivity(array $item, int $parent_message_id, string $guid, WebFingerUri $author)
|
||||
{
|
||||
$parent = Post::selectFirst(['uri', 'guid'], ['id' => $parent_message_id]);
|
||||
|
||||
$datarray = [];
|
||||
|
||||
$datarray['uid'] = $item['uid'];
|
||||
$datarray['contact-id'] = $item['contact-id'];
|
||||
$datarray['network'] = $item['network'];
|
||||
|
||||
$datarray['author-link'] = $item['author-link'];
|
||||
$datarray['author-id'] = $item['author-id'];
|
||||
|
||||
$datarray['owner-link'] = $datarray['author-link'];
|
||||
$datarray['owner-id'] = $datarray['author-id'];
|
||||
|
||||
$datarray['guid'] = $parent['guid'] . '-' . $guid;
|
||||
$datarray['uri'] = self::getUriFromGuid($datarray['guid'], $author);
|
||||
$datarray['thr-parent'] = $parent['uri'];
|
||||
|
||||
$datarray['verb'] = $datarray['body'] = Activity::ANNOUNCE;
|
||||
$datarray['gravity'] = Item::GRAVITY_ACTIVITY;
|
||||
$datarray['object-type'] = Activity\ObjectType::NOTE;
|
||||
|
||||
$datarray['protocol'] = $item['protocol'];
|
||||
$datarray['source'] = $item['source'];
|
||||
$datarray['direction'] = $item['direction'];
|
||||
$datarray['post-reason'] = $item['post-reason'];
|
||||
|
||||
$datarray['plink'] = self::plink($author, $datarray['guid']);
|
||||
$datarray['private'] = $item['private'];
|
||||
$datarray['changed'] = $datarray['created'] = $datarray['edited'] = $item['created'];
|
||||
|
||||
if (Item::isTooOld($datarray)) {
|
||||
Logger::info('Reshare activity is too old', ['created' => $datarray['created'], 'uid' => $datarray['uid'], 'guid' => $datarray['guid']]);
|
||||
return false;
|
||||
}
|
||||
|
||||
$message_id = Item::insert($datarray);
|
||||
|
||||
if ($message_id) {
|
||||
Logger::info('Stored reshare activity.', ['guid' => $guid, 'id' => $message_id]);
|
||||
if ($datarray['uid'] == 0) {
|
||||
Item::distribute($message_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a reshare message
|
||||
*
|
||||
|
@ -2436,11 +2377,6 @@ class Diaspora
|
|||
|
||||
self::sendParticipation($contact, $datarray);
|
||||
|
||||
$root_message_id = self::messageExists($importer['uid'], $root_guid);
|
||||
if ($root_message_id) {
|
||||
self::addReshareActivity($datarray, $root_message_id, $guid, $author);
|
||||
}
|
||||
|
||||
if ($message_id) {
|
||||
Logger::info('Stored reshare ' . $datarray['guid'] . ' with message id ' . $message_id);
|
||||
if ($datarray['uid'] == 0) {
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
use Friendica\Database\DBA;
|
||||
|
||||
if (!defined('DB_UPDATE_VERSION')) {
|
||||
define('DB_UPDATE_VERSION', 1502);
|
||||
define('DB_UPDATE_VERSION', 1503);
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -1458,7 +1458,7 @@ return [
|
|||
"event-id" => ["type" => "int unsigned", "foreign" => ["event" => "id"], "comment" => "Used to link to the event.id"],
|
||||
"unseen" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => "post has not been seen"],
|
||||
"hidden" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Marker to hide the post from the user"],
|
||||
"notification-type" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
|
||||
"notification-type" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
|
||||
"wall" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "This item was posted to the wall of uid"],
|
||||
"origin" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "item originated at this site"],
|
||||
"psid" => ["type" => "int unsigned", "foreign" => ["permissionset" => "id", "on delete" => "restrict"], "comment" => "ID of the permission set of this post"],
|
||||
|
|
Loading…
Reference in a new issue