diff options
author | Joas Schilling <coding@schilljs.com> | 2021-01-27 16:46:34 +0300 |
---|---|---|
committer | Joas Schilling <coding@schilljs.com> | 2021-02-02 18:22:17 +0300 |
commit | 4d27b096c5e151fbf2c1d244c008e634ca33ada4 (patch) | |
tree | 900afc02c1b6123215458baa56cd24287f6552a0 | |
parent | 54fa5b2ad936b974405165911d40c66a68f1931e (diff) |
Allow to share RichObjects to chats
Signed-off-by: Joas Schilling <coding@schilljs.com>
-rw-r--r-- | appinfo/routes.php | 9 | ||||
-rw-r--r-- | lib/Chat/ChatManager.php | 5 | ||||
-rw-r--r-- | lib/Chat/Parser/SystemMessage.php | 4 | ||||
-rw-r--r-- | lib/Controller/ChatController.php | 146 |
4 files changed, 129 insertions, 35 deletions
diff --git a/appinfo/routes.php b/appinfo/routes.php index db32cbd72..87e15f034 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -181,6 +181,15 @@ return [ 'token' => '^[a-z0-9]{4,30}$', ], ], + [ + 'name' => 'Chat#shareObjectToChat', + 'url' => '/api/{apiVersion}/chat/{token}/share', + 'verb' => 'POST', + 'requirements' => [ + 'apiVersion' => 'v1', + 'token' => '^[a-z0-9]{4,30}$', + ], + ], /** * Conversation (Room) diff --git a/lib/Chat/ChatManager.php b/lib/Chat/ChatManager.php index 4202a3a46..2209dfa72 100644 --- a/lib/Chat/ChatManager.php +++ b/lib/Chat/ChatManager.php @@ -123,7 +123,10 @@ class ChatManager { $comment->setMessage($message, self::MAX_CHAT_LENGTH); $comment->setCreationDateTime($creationDateTime); if ($referenceId !== null) { - $comment->setReferenceId($referenceId); + $referenceId = trim(substr($referenceId, 0, 40)); + if ($referenceId !== '') { + $comment->setReferenceId($referenceId); + } } if ($parentId !== null) { $comment->setParentId((string) $parentId); diff --git a/lib/Chat/Parser/SystemMessage.php b/lib/Chat/Parser/SystemMessage.php index ab1534480..563351799 100644 --- a/lib/Chat/Parser/SystemMessage.php +++ b/lib/Chat/Parser/SystemMessage.php @@ -329,6 +329,10 @@ class SystemMessage { $parsedMessage = $this->l->t('You shared a file which is no longer available'); } } + } elseif ($message === 'object_shared') { + $parsedParameters['object'] = $parameters['metaData']; + $parsedMessage = '{object}'; + $chatMessage->setMessageType('comment'); } elseif ($message === 'matterbridge_config_added') { $parsedMessage = $this->l->t('{actor} set up Matterbridge to synchronize this conversation with other chats.'); if ($currentUserIsActor) { diff --git a/lib/Controller/ChatController.php b/lib/Controller/ChatController.php index 4c5706086..49257cbca 100644 --- a/lib/Controller/ChatController.php +++ b/lib/Controller/ChatController.php @@ -51,6 +51,8 @@ use OCP\EventDispatcher\IEventDispatcher; use OCP\IL10N; use OCP\IRequest; use OCP\IUserManager; +use OCP\RichObjectStrings\InvalidObjectExeption; +use OCP\RichObjectStrings\IValidator; use OCP\User\Events\UserLiveStatusEvent; use OCP\UserStatus\IManager as IUserStatusManager; use OCP\UserStatus\IUserStatus; @@ -108,6 +110,9 @@ class ChatController extends AEnvironmentAwareController { /** @var IEventDispatcher */ protected $eventDispatcher; + /** @var IValidator */ + protected $richObjectValidator; + /** @var IL10N */ private $l; @@ -129,6 +134,7 @@ class ChatController extends AEnvironmentAwareController { ISearchResult $searchResult, ITimeFactory $timeFactory, IEventDispatcher $eventDispatcher, + IValidator $richObjectValidator, IL10N $l) { parent::__construct($appName, $request); @@ -148,9 +154,58 @@ class ChatController extends AEnvironmentAwareController { $this->searchResult = $searchResult; $this->timeFactory = $timeFactory; $this->eventDispatcher = $eventDispatcher; + $this->richObjectValidator = $richObjectValidator; $this->l = $l; } + protected function getActorInfo(string $actorDisplayName = ''): array { + if ($this->userId === null) { + $actorType = Attendee::ACTOR_GUESTS; + $sessionId = $this->session->getSessionForRoom($this->room->getToken()); + // The character limit for actorId is 64, but the spreed-session is + // 256 characters long, so it has to be hashed to get an ID that + // fits (except if there is no session, as the actorId should be + // empty in that case but sha1('') would generate a hash too + // instead of returning an empty string). + $actorId = $sessionId ? sha1($sessionId) : 'failed-to-get-session'; + + if ($sessionId && $actorDisplayName) { + $this->guestManager->updateName($this->room, $this->participant, $actorDisplayName); + } + } else { + $actorType = Attendee::ACTOR_USERS; + $actorId = $this->userId; + } + + return [$actorType, $actorId]; + } + + public function parseCommentToResponse(IComment $comment, Message $parentMessage = null): DataResponse { + $chatMessage = $this->messageParser->createMessage($this->room, $this->participant, $comment, $this->l); + $this->messageParser->parseMessage($chatMessage); + + if (!$chatMessage->getVisibility()) { + $response = new DataResponse([], Http::STATUS_CREATED); + if ($this->participant->getAttendee()->getReadPrivacy() === Participant::PRIVACY_PUBLIC) { + $response->addHeader('X-Chat-Last-Common-Read', $this->chatManager->getLastCommonReadMessage($this->room)); + } + return $response; + } + + $this->participantService->updateLastReadMessage($this->participant, (int) $comment->getId()); + + $data = $chatMessage->toArray(); + if ($parentMessage instanceof Message) { + $data['parent'] = $parentMessage->toArray(); + } + + $response = new DataResponse($data, Http::STATUS_CREATED); + if ($this->participant->getAttendee()->getReadPrivacy() === Participant::PRIVACY_PUBLIC) { + $response->addHeader('X-Chat-Last-Common-Read', $this->chatManager->getLastCommonReadMessage($this->room)); + } + return $response; + } + /** * @PublicPage * @RequireParticipant @@ -171,24 +226,7 @@ class ChatController extends AEnvironmentAwareController { * found". */ public function sendMessage(string $message, string $actorDisplayName = '', string $referenceId = '', int $replyTo = 0): DataResponse { - if ($this->userId === null) { - $actorType = Attendee::ACTOR_GUESTS; - $sessionId = $this->session->getSessionForRoom($this->room->getToken()); - // The character limit for actorId is 64, but the spreed-session is - // 256 characters long, so it has to be hashed to get an ID that - // fits (except if there is no session, as the actorId should be - // empty in that case but sha1('') would generate a hash too - // instead of returning an empty string). - $actorId = $sessionId ? sha1($sessionId) : 'failed-to-get-session'; - - if ($sessionId && $actorDisplayName) { - $this->guestManager->updateName($this->room, $this->participant, $actorDisplayName); - } - } else { - $actorType = Attendee::ACTOR_USERS; - $actorId = $this->userId; - } - + [$actorType, $actorId] = $this->getActorInfo($actorDisplayName); if (!$actorId) { return new DataResponse([], Http::STATUS_NOT_FOUND); } @@ -220,29 +258,69 @@ class ChatController extends AEnvironmentAwareController { return new DataResponse([], Http::STATUS_BAD_REQUEST); } - $chatMessage = $this->messageParser->createMessage($this->room, $this->participant, $comment, $this->l); - $this->messageParser->parseMessage($chatMessage); + return $this->parseCommentToResponse($comment, $parentMessage); + } - if (!$chatMessage->getVisibility()) { - $response = new DataResponse([], Http::STATUS_CREATED); - if ($this->participant->getAttendee()->getReadPrivacy() === Participant::PRIVACY_PUBLIC) { - $response->addHeader('X-Chat-Last-Common-Read', $this->chatManager->getLastCommonReadMessage($this->room)); - } - return $response; + /** + * @PublicPage + * @RequireParticipant + * @RequireReadWriteConversation + * @RequireModeratorOrNoLobby + * + * Sends a rich-object to the given room. + * + * The author and timestamp are automatically set to the current user/guest + * and time. + * + * @param string $objectType + * @param string $objectId + * @param string $metaData + * @param string $actorDisplayName + * @param string $referenceId + * @return DataResponse the status code is "201 Created" if successful, and + * "404 Not found" if the room or session for a guest user was not + * found". + */ + public function shareObjectToChat(string $objectType, string $objectId, string $metaData = '', string $actorDisplayName = '', string $referenceId = ''): DataResponse { + [$actorType, $actorId] = $this->getActorInfo($actorDisplayName); + if (!$actorId) { + return new DataResponse([], Http::STATUS_NOT_FOUND); } - $this->participantService->updateLastReadMessage($this->participant, (int) $comment->getId()); + $data = $metaData !== '' ? json_decode($metaData, true) : []; + if (!is_array($data)) { + $data = []; + } + $data['type'] = $objectType; + $data['id'] = $objectId; - $data = $chatMessage->toArray(); - if ($parentMessage instanceof Message) { - $data['parent'] = $parentMessage->toArray(); + try { + $this->richObjectValidator->validate('{object}', ['object' => $data]); + } catch (InvalidObjectExeption $e) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); } - $response = new DataResponse($data, Http::STATUS_CREATED); - if ($this->participant->getAttendee()->getReadPrivacy() === Participant::PRIVACY_PUBLIC) { - $response->addHeader('X-Chat-Last-Common-Read', $this->chatManager->getLastCommonReadMessage($this->room)); + $this->participantService->ensureOneToOneRoomIsFilled($this->room); + $creationDateTime = $this->timeFactory->getDateTime('now', new \DateTimeZone('UTC')); + + $message = json_encode([ + 'message' => 'object_shared', + 'parameters' => [ + 'objectType' => $objectType, + 'objectId' => $objectId, + 'metaData' => $data, + ], + ]); + + try { + $comment = $this->chatManager->addSystemMessage($this->room, $actorType, $actorId, $message, $creationDateTime, true, $referenceId); + } catch (MessageTooLongException $e) { + return new DataResponse([], Http::STATUS_REQUEST_ENTITY_TOO_LARGE); + } catch (\Exception $e) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); } - return $response; + + return $this->parseCommentToResponse($comment); } /** |