diff --git a/lib/Events/BotInvokeEvent.php b/lib/Events/BotInvokeEvent.php
index 27146d680c1..b508a463720 100644
--- a/lib/Events/BotInvokeEvent.php
+++ b/lib/Events/BotInvokeEvent.php
@@ -11,20 +11,36 @@
use OCP\EventDispatcher\Event;
/**
+ * @psalm-type ChatMessageParentData = array{
+ * type: 'Note',
+ * actor: array{
+ * type: 'Person',
+ * id: non-empty-string,
+ * name: non-empty-string,
+ * },
+ * object: array{
+ * type: 'Note',
+ * id: numeric-string,
+ * name: string,
+ * content: non-empty-string,
+ * mediaType: 'text/markdown'|'text/plain',
+ * },
+ * }
* @psalm-type ChatMessageData = array{
* type: 'Activity'|'Create',
* actor: array{
* type: 'Person',
* id: non-empty-string,
* name: non-empty-string,
- * talkParticipantType: non-empty-string,
+ * talkParticipantType: numeric-string,
* },
* object: array{
* type: 'Note',
- * id: non-empty-string,
+ * id: numeric-string,
* name: string,
* content: non-empty-string,
* mediaType: 'text/markdown'|'text/plain',
+ * inReplyTo?: ChatMessageParentData,
* },
* target: array{
* type: 'Collection',
diff --git a/lib/Service/ActivityPubHelper.php b/lib/Service/ActivityPubHelper.php
new file mode 100644
index 00000000000..cdb0155b361
--- /dev/null
+++ b/lib/Service/ActivityPubHelper.php
@@ -0,0 +1,94 @@
+ 'Application',
+ 'id' => Attendee::ACTOR_BOTS . '/' . Attendee::ACTOR_BOT_PREFIX . $bot->getUrlHash(),
+ 'name' => $bot->getName(),
+ ];
+ }
+
+ /**
+ * @return array{type: 'Collection', id: non-empty-string, name: string}
+ */
+ public function generateCollectionFromRoom(Room $room): array {
+ /** @var non-empty-string $token */
+ $token = $room->getToken();
+ return [
+ 'type' => 'Collection',
+ 'id' => $token,
+ 'name' => $room->getName(),
+ ];
+ }
+
+ /**
+ * @psalm-param ?ChatMessageParentData $inReplyTo
+ * @psalm-return NoteType&array{inReplyTo?: ChatMessageParentData}
+ */
+ public function generateNote(IComment $comment, array $messageData, string $messageType, ?array $inReplyTo = null): array {
+ /** @var string $content */
+ $content = json_encode($messageData, JSON_THROW_ON_ERROR);
+ /** @var numeric-string $messageId */
+ $messageId = $comment->getId();
+ /** @var 'text/markdown'|'text/plain' $mediaType */
+ $mediaType = 'text/markdown';// FIXME or text/plain when markdown is disabled
+ $note = [
+ 'type' => 'Note',
+ 'id' => $messageId,
+ 'name' => $messageType,
+ 'content' => $content,
+ 'mediaType' => $mediaType,
+ ];
+ if ($inReplyTo !== null) {
+ $note['inReplyTo'] = $inReplyTo;
+ }
+ return $note;
+ }
+
+ /**
+ * @return array{type: 'Person', id: non-falsy-string, name: string, talkParticipantType: numeric-string}
+ */
+ public function generatePersonFromAttendee(Attendee $attendee): array {
+ return [
+ 'type' => 'Person',
+ 'id' => $attendee->getActorType() . '/' . $attendee->getActorId(),
+ 'name' => $attendee->getDisplayName(),
+ 'talkParticipantType' => (string)$attendee->getParticipantType(),
+ ];
+ }
+
+ /**
+ * @return array{type: 'Person', id: non-falsy-string, name: string}
+ */
+ public function generatePersonFromMessageActor(Message $message): array {
+ return [
+ 'type' => 'Person',
+ 'id' => $message->getActorType() . '/' . $message->getActorId(),
+ 'name' => $message->getActorDisplayName(),
+ ];
+ }
+}
diff --git a/lib/Service/BotService.php b/lib/Service/BotService.php
index ba3f0e85684..dacee94f0af 100644
--- a/lib/Service/BotService.php
+++ b/lib/Service/BotService.php
@@ -46,6 +46,8 @@
* @psalm-import-type InvocationData from BotInvokeEvent
*/
class BotService {
+ private ActivityPubHelper $activityPubHelper;
+
public function __construct(
protected BotServerMapper $botServerMapper,
protected BotConversationMapper $botConversationMapper,
@@ -62,37 +64,22 @@ public function __construct(
protected ICertificateManager $certificateManager,
protected IEventDispatcher $dispatcher,
) {
+ $this->activityPubHelper = new ActivityPubHelper();
}
public function afterBotEnabled(BotEnabledEvent $event): void {
$this->invokeBots([$event->getBotServer()], $event->getRoom(), null, [
'type' => 'Join',
- 'actor' => [
- 'type' => 'Application',
- 'id' => Attendee::ACTOR_BOTS . '/' . Attendee::ACTOR_BOT_PREFIX . $event->getBotServer()->getUrlHash(),
- 'name' => $event->getBotServer()->getName(),
- ],
- 'object' => [
- 'type' => 'Collection',
- 'id' => $event->getRoom()->getToken(),
- 'name' => $event->getRoom()->getName(),
- ],
+ 'actor' => $this->activityPubHelper->generateApplicationFromBot($event->getBotServer()),
+ 'object' => $this->activityPubHelper->generateCollectionFromRoom($event->getRoom()),
]);
}
public function afterBotDisabled(BotDisabledEvent $event): void {
$this->invokeBots([$event->getBotServer()], $event->getRoom(), null, [
'type' => 'Leave',
- 'actor' => [
- 'type' => 'Application',
- 'id' => Attendee::ACTOR_BOTS . '/' . Attendee::ACTOR_BOT_PREFIX . $event->getBotServer()->getUrlHash(),
- 'name' => $event->getBotServer()->getName(),
- ],
- 'object' => [
- 'type' => 'Collection',
- 'id' => $event->getRoom()->getToken(),
- 'name' => $event->getRoom()->getName(),
- ],
+ 'actor' => $this->activityPubHelper->generateApplicationFromBot($event->getBotServer()),
+ 'object' => $this->activityPubHelper->generateCollectionFromRoom($event->getRoom()),
]);
}
@@ -108,6 +95,28 @@ public function afterChatMessageSent(ChatMessageSentEvent $event, MessageParser
return;
}
+ $inReplyTo = null;
+ $parent = $event->getParent();
+ if ($parent instanceof IComment) {
+ $parentMessage = $messageParser->createMessage(
+ $event->getRoom(),
+ $event->getParticipant(),
+ $parent,
+ $this->l10nFactory->get('spreed', 'en', 'en')
+ );
+ $messageParser->parseMessage($parentMessage);
+ $parentMessageData = [
+ 'message' => $parentMessage->getMessage(),
+ 'parameters' => $parentMessage->getMessageParameters(),
+ ];
+
+ $inReplyTo = [
+ 'type' => 'Note',
+ 'actor' => $this->activityPubHelper->generatePersonFromMessageActor($parentMessage),
+ 'object' => $this->activityPubHelper->generateNote($parent, $parentMessageData, 'message'),
+ ];
+ }
+
$message = $messageParser->createMessage(
$event->getRoom(),
$event->getParticipant(),
@@ -124,24 +133,9 @@ public function afterChatMessageSent(ChatMessageSentEvent $event, MessageParser
$this->invokeBots($botServers, $event->getRoom(), $event->getComment(), [
'type' => 'Create',
- 'actor' => [
- 'type' => 'Person',
- 'id' => $attendee->getActorType() . '/' . $attendee->getActorId(),
- 'name' => $attendee->getDisplayName(),
- 'talkParticipantType' => (string)$attendee->getParticipantType(),
- ],
- 'object' => [
- 'type' => 'Note',
- 'id' => $event->getComment()->getId(),
- 'name' => 'message',
- 'content' => json_encode($messageData, JSON_THROW_ON_ERROR),
- 'mediaType' => 'text/markdown', // FIXME or text/plain when markdown is disabled
- ],
- 'target' => [
- 'type' => 'Collection',
- 'id' => $event->getRoom()->getToken(),
- 'name' => $event->getRoom()->getName(),
- ]
+ 'actor' => $this->activityPubHelper->generatePersonFromAttendee($attendee),
+ 'object' => $this->activityPubHelper->generateNote($event->getComment(), $messageData, 'message', $inReplyTo),
+ 'target' => $this->activityPubHelper->generateCollectionFromRoom($event->getRoom()),
]);
}
@@ -167,23 +161,9 @@ public function afterSystemMessageSent(SystemMessageSentEvent $event, MessagePar
$this->invokeBots($botServers, $event->getRoom(), $event->getComment(), [
'type' => 'Activity',
- 'actor' => [
- 'type' => 'Person',
- 'id' => $message->getActorType() . '/' . $message->getActorId(),
- 'name' => $message->getActorDisplayName(),
- ],
- 'object' => [
- 'type' => 'Note',
- 'id' => $event->getComment()->getId(),
- 'name' => $message->getMessageRaw(),
- 'content' => json_encode($messageData),
- 'mediaType' => 'text/markdown',
- ],
- 'target' => [
- 'type' => 'Collection',
- 'id' => $event->getRoom()->getToken(),
- 'name' => $event->getRoom()->getName(),
- ]
+ 'actor' => $this->activityPubHelper->generatePersonFromMessageActor($message),
+ 'object' => $this->activityPubHelper->generateNote($event->getComment(), $messageData, $message->getMessageRaw()),
+ 'target' => $this->activityPubHelper->generateCollectionFromRoom($event->getRoom()),
]);
}
diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml
index 04b38c2ee39..661c4cabb31 100644
--- a/tests/psalm-baseline.xml
+++ b/tests/psalm-baseline.xml
@@ -89,30 +89,6 @@
-
-
- 'Activity',
- 'actor' => [
- 'type' => 'Person',
- 'id' => $message->getActorType() . '/' . $message->getActorId(),
- 'name' => $message->getActorDisplayName(),
- ],
- 'object' => [
- 'type' => 'Note',
- 'id' => $event->getComment()->getId(),
- 'name' => $message->getMessageRaw(),
- 'content' => json_encode($messageData),
- 'mediaType' => 'text/markdown',
- ],
- 'target' => [
- 'type' => 'Collection',
- 'id' => $event->getRoom()->getToken(),
- 'name' => $event->getRoom()->getName(),
- ]
- ]]]>
-
-