-- ------------------------------------------
-- Friendica 2022.12-rc (Giant Rhubarb)
--- DB_UPDATE_VERSION 1501
+-- DB_UPDATE_VERSION 1502
-- ------------------------------------------
`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',
| 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 | |
$thread_items = Post::selectForUser($uid, array_merge(ItemModel::DISPLAY_FIELDLIST, ['featured', 'contact-uid', 'gravity', 'post-type', 'post-reason']), $condition, $params);
- $items = [];
+ $items = [];
+ $quoteuriids = [];
while ($row = Post::fetch($thread_items)) {
if (!empty($items[$row['uri-id']]) && ($row['uid'] == 0)) {
}
}
+ if (in_array($row['gravity'], [ItemModel::GRAVITY_PARENT, ItemModel::GRAVITY_COMMENT])) {
+ $quoteuriids[$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($quoteuriids, 'uri-id'), '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'] = $quoteuriids[$quote['quote-uri-id']]['parent-uri'];
+ $row['parent-uri-id'] = $quoteuriids[$quote['quote-uri-id']]['parent-uri-id'];
+ $row['thr-parent'] = $quoteuriids[$quote['quote-uri-id']]['uri'];
+ $row['thr-parent-id'] = $quoteuriids[$quote['quote-uri-id']]['uri-id'];
+
+ $items[$row['uri-id']] = $this->addRowInformation($row, [], []);
+ }
+ DBA::close($quotes);
+
$items = $this->convSort($items, $order);
$this->profiler->stopRecording();
'gravity' => Item::GRAVITY_ACTIVITY,
'vid' => Verb::getID(Activity::ANNOUNCE),
'deleted' => false
- ], []);
+ ]) + Post::countPosts([
+ 'quote-uri-id' => $uriId,
+ '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], []),
'gravity' => Item::GRAVITY_ACTIVITY,
'vid' => Verb::getID(Activity::ANNOUNCE),
'deleted' => false
+ ]) || Post::exists([
+ 'quote-uri-id' => $uriId,
+ 'uid' => $uid,
+ 'origin' => true,
+ 'deleted' => false
]);
$userAttributes = new \Friendica\Object\Api\Mastodon\Status\UserAttributes(
$origin_like,
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;
const TYPE_DIRECT_THREAD_COMMENT = 64;
const TYPE_SHARED = 128;
const TYPE_FOLLOW = 256;
+ const TYPE_QUOTED = 512;
/**
* Insert a new user notification entry
}
}
+ 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) {
$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);
+ }
+
+
}
use Friendica\Model\Item;
use Friendica\Model\Post;
use Friendica\Module\BaseApi;
+use Friendica\Protocol\Diaspora;
/**
* @see https://docs.joinmastodon.org/methods/statuses/
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());
}
}
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'], '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());
}
}
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'], '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();
}
$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;
}
}
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
*
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) {
use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) {
- define('DB_UPDATE_VERSION', 1501);
+ define('DB_UPDATE_VERSION', 1502);
}
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"],