[COMPONENT][Notification] Make logic more generic and robust
Fixed various bugs Some important concepts to bear in mind: * Notification: Associated with activities, won't be reconstructed together with objects, can be thought of as transient * Attention: Associated with objects, will be reconstructed with them, can be thought as persistent * Notifications and Attentions have no direct implications. * Mentions are a specific form of attentions in notes, leads to the creation of Attentions. Finally, Potential PHP issue detected and reported: https://github.com/php/php-src/issues/8199 `static::method()` from a non static context (such as a class method) calls `__call`, rather than the expected `__callStatic`. Can be fixed by using `(static fn() => static::method())()`, but the usage of the magic method is strictly unnecessary in this case.
This commit is contained in:
@@ -48,7 +48,6 @@ use Component\Attachment\Entity\AttachmentToNote;
|
||||
use Component\Conversation\Conversation;
|
||||
use Component\Language\Entity\Language;
|
||||
use Component\Notification\Entity\Attention;
|
||||
use Functional as F;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
@@ -94,7 +93,7 @@ class Posting extends Component
|
||||
string $content_type,
|
||||
?string $locale = null,
|
||||
?VisibilityScope $scope = null,
|
||||
array $targets = [],
|
||||
array $attentions = [],
|
||||
null|int|Note $reply_to = null,
|
||||
array $attachments = [],
|
||||
array $processed_attachments = [],
|
||||
@@ -104,13 +103,13 @@ class Posting extends Component
|
||||
string $source = 'web',
|
||||
?string $title = null,
|
||||
): array {
|
||||
[$activity, $note, $attention_ids] = self::storeLocalNote(
|
||||
[$activity, $note, $effective_attentions] = self::storeLocalNote(
|
||||
actor: $actor,
|
||||
content: $content,
|
||||
content_type: $content_type,
|
||||
locale: $locale,
|
||||
scope: $scope,
|
||||
targets: $targets,
|
||||
attentions: $attentions,
|
||||
reply_to: $reply_to,
|
||||
attachments: $attachments,
|
||||
processed_attachments: $processed_attachments,
|
||||
@@ -125,10 +124,18 @@ class Posting extends Component
|
||||
if ($flush_and_notify) {
|
||||
// Flush before notification
|
||||
DB::flush();
|
||||
Event::handle('NewNotification', [$actor, $activity, ['object' => $attention_ids], _m('{nickname} created a page {note_id}.', ['{nickname}' => $actor->getNickname(), '{note_id}' => $activity->getObjectId()])]);
|
||||
Event::handle('NewNotification', [
|
||||
$actor,
|
||||
$activity,
|
||||
$effective_attentions,
|
||||
_m('Actor {actor_id} created page {note_id}.', [
|
||||
'{actor_id}' => $actor->getId(),
|
||||
'{note_id}' => $activity->getObjectId(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
return [$activity, $note, $attention_ids];
|
||||
return [$activity, $note, $effective_attentions];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +148,7 @@ class Posting extends Component
|
||||
* @param string $content_type Indicating one of the various supported content format (Plain Text, Markdown, LaTeX...)
|
||||
* @param null|string $locale Note's written text language, set by the default Actor language or upon filling
|
||||
* @param null|VisibilityScope $scope The visibility of this Note
|
||||
* @param array $targets Actor|int[]: In Group/To Person or Bot, registers an attention between note and target
|
||||
* @param array $attentions Actor|int[]: In Group/To Person or Bot, registers an attention between note and target
|
||||
* @param null|int|Note $reply_to The soon-to-be Note parent's id, if it's a Reply itself
|
||||
* @param array $attachments UploadedFile[] to be stored as GSFiles associated to this note
|
||||
* @param array $processed_attachments Array of [Attachment, Attachment's name][] to be associated to this $actor and Note
|
||||
@@ -154,7 +161,7 @@ class Posting extends Component
|
||||
* @throws DuplicateFoundException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return array [Activity, Note, int[]] Activity, Note, Attention Ids
|
||||
* @return array [Activity, Note, Effective Attentions]
|
||||
*/
|
||||
public static function storeLocalNote(
|
||||
Actor $actor,
|
||||
@@ -162,7 +169,7 @@ class Posting extends Component
|
||||
string $content_type,
|
||||
?string $locale = null,
|
||||
?VisibilityScope $scope = null,
|
||||
array $targets = [],
|
||||
array $attentions = [],
|
||||
null|int|Note $reply_to = null,
|
||||
array $attachments = [],
|
||||
array $processed_attachments = [],
|
||||
@@ -209,7 +216,7 @@ class Posting extends Component
|
||||
if (!\is_null($reply_to_id)) {
|
||||
Cache::incr(Note::cacheKeys($reply_to_id)['replies-count']);
|
||||
// Not having them cached doesn't mean replies don't exist, but don't push it to the
|
||||
// list, as that means they need to be refetched, or some would be missed
|
||||
// list, as that means they need to be re-fetched, or some would be missed
|
||||
if (Cache::exists(Note::cacheKeys($reply_to_id)['replies'])) {
|
||||
Cache::listPushRight(Note::cacheKeys($reply_to_id)['replies'], $note);
|
||||
}
|
||||
@@ -221,12 +228,12 @@ class Posting extends Component
|
||||
Event::handle('ProcessNoteContent', [$note, $content, $content_type, $process_note_content_extra_args]);
|
||||
}
|
||||
|
||||
// These are note attachments now, and not just attachments, ensure these relations are ensured
|
||||
// These are note attachments now, and not just attachments, ensure these relations are respected
|
||||
if ($processed_attachments !== []) {
|
||||
foreach ($processed_attachments as [$a, $fname]) {
|
||||
// Most attachments should already be associated with its author, but maybe it didn't make sense
|
||||
//for this attachment, or it's simply a repost of an attachment by a different actor
|
||||
if (DB::count('actor_to_attachment', $args = ['attachment_id' => $a->getId(), 'actor_id' => $actor->getId()]) === 0) {
|
||||
if (DB::count(ActorToAttachment::class, $args = ['attachment_id' => $a->getId(), 'actor_id' => $actor->getId()]) === 0) {
|
||||
DB::persist(ActorToAttachment::create($args));
|
||||
}
|
||||
DB::persist(AttachmentToNote::create(['attachment_id' => $a->getId(), 'note_id' => $note->getId(), 'title' => $fname]));
|
||||
@@ -242,13 +249,38 @@ class Posting extends Component
|
||||
]);
|
||||
DB::persist($activity);
|
||||
|
||||
$attention_ids = [];
|
||||
foreach ($targets as $target) {
|
||||
$target_id = \is_int($target) ? $target : $target->getId();
|
||||
DB::persist(Attention::create(['note_id' => $note->getId(), 'target_id' => $target_id]));
|
||||
$attention_ids[$target_id] = true;
|
||||
$effective_attentions = [];
|
||||
foreach ($attentions as $target) {
|
||||
if (\is_int($target)) {
|
||||
$target_id = $target;
|
||||
$add = !\array_key_exists($target_id, $effective_attentions);
|
||||
$effective_attentions[$target_id] = $target;
|
||||
} else {
|
||||
$target_id = $target->getId();
|
||||
if ($add = !\array_key_exists($target_id, $effective_attentions)) {
|
||||
$effective_attentions[$target_id] = $target_id;
|
||||
}
|
||||
}
|
||||
if ($add) {
|
||||
DB::persist(Attention::create(['object_type' => Note::schemaName(), 'object_id' => $note->getId(), 'target_id' => $target_id]));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($mentions as $m) {
|
||||
foreach ($m['mentioned'] ?? [] as $mentioned) {
|
||||
$target_id = $mentioned->getId();
|
||||
if (!\array_key_exists($target_id, $effective_attentions)) {
|
||||
DB::persist(Attention::create(['object_type' => Note::schemaName(), 'object_id' => $note->getId(), 'target_id' => $target_id]));
|
||||
}
|
||||
$effective_attentions[$target_id] = $mentioned;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($actor->getSubscribers() as $subscriber) {
|
||||
$target_id = $subscriber->getId();
|
||||
DB::persist(Attention::create(['object_type' => Activity::schemaName(), 'object_id' => $activity->getId(), 'target_id' => $target_id]));
|
||||
$effective_attentions[$target_id] = $subscriber;
|
||||
}
|
||||
$attention_ids = array_keys($attention_ids);
|
||||
|
||||
if ($flush_and_notify) {
|
||||
// Flush before notification
|
||||
@@ -256,18 +288,15 @@ class Posting extends Component
|
||||
Event::handle('NewNotification', [
|
||||
$actor,
|
||||
$activity,
|
||||
[
|
||||
'note-attention' => $attention_ids,
|
||||
'object' => F\unique(F\flat_map($mentions, fn (array $m) => F\map($m['mentioned'] ?? [], fn (Actor $a) => $a->getId()))),
|
||||
],
|
||||
_m('{nickname} created a note {note_id}.', [
|
||||
'{nickname}' => $actor->getNickname(),
|
||||
$effective_attentions,
|
||||
_m('Actor {actor_id} created note {note_id}.', [
|
||||
'{actor_id}' => $actor->getId(),
|
||||
'{note_id}' => $activity->getObjectId(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
return [$activity, $note, $attention_ids];
|
||||
return [$activity, $note, $effective_attentions];
|
||||
}
|
||||
|
||||
public function onRenderNoteContent(string $content, string $content_type, ?string &$rendered, Actor $author, ?string $language = null, array &$mentions = [])
|
||||
|
Reference in New Issue
Block a user