Browse Source
Merge pull request #6730 from nextcloud/feature/1920/api-reactions-to-message
Merge pull request #6730 from nextcloud/feature/1920/api-reactions-to-message
Api reactions to messagepull/6912/head
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 933 additions and 16 deletions
-
130.drone.yml
-
1appinfo/routes.php
-
41appinfo/routes/routesReactionController.php
-
1docs/capabilities.md
-
2docs/chat.md
-
1docs/index.md
-
66docs/reaction.md
-
9lib/Capabilities.php
-
44lib/Chat/Notifier.php
-
12lib/Chat/Parser/Listener.php
-
52lib/Chat/Parser/ReactionParser.php
-
153lib/Chat/ReactionManager.php
-
130lib/Controller/ReactionController.php
-
29lib/Exceptions/ReactionAlreadyExistsException.php
-
29lib/Exceptions/ReactionNotSupportedException.php
-
29lib/Exceptions/ReactionOutOfContextException.php
-
2lib/Manager.php
-
2lib/Model/Message.php
-
23lib/Notification/Notifier.php
-
1mkdocs.yml
-
63tests/integration/features/bootstrap/FeatureContext.php
-
68tests/integration/features/reaction/react.feature
-
11tests/php/CapabilitiesTest.php
-
50tests/php/Chat/NotifierTest.php
@ -0,0 +1,41 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
/** |
||||
|
* @copyright Copyright (c) 2021 Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @author Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @license GNU AGPL version 3 or any later version |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU Affero General Public License as |
||||
|
* published by the Free Software Foundation, either version 3 of the |
||||
|
* License, or (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU Affero General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU Affero General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
return [ |
||||
|
'ocs' => [ |
||||
|
['name' => 'Reaction#react', 'url' => '/api/{apiVersion}/reaction/{token}/{messageId}', 'verb' => 'POST', 'requirements' => [ |
||||
|
'apiVersion' => 'v1', |
||||
|
'token' => '^[a-z0-9]{4,30}$', |
||||
|
]], |
||||
|
['name' => 'Reaction#delete', 'url' => '/api/{apiVersion}/reaction/{token}/{messageId}', 'verb' => 'DELETE', 'requirements' => [ |
||||
|
'apiVersion' => 'v1', |
||||
|
'token' => '^[a-z0-9]{4,30}$', |
||||
|
]], |
||||
|
['name' => 'Reaction#getReactions', 'url' => '/api/{apiVersion}/reaction/{token}/{messageId}', 'verb' => 'GET', 'requirements' => [ |
||||
|
'apiVersion' => 'v1', |
||||
|
'token' => '^[a-z0-9]{4,30}$', |
||||
|
]], |
||||
|
], |
||||
|
]; |
||||
@ -0,0 +1,66 @@ |
|||||
|
# Reaction API |
||||
|
|
||||
|
Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1` |
||||
|
|
||||
|
## React to a message |
||||
|
|
||||
|
* Required capability: `reactions` |
||||
|
* Method: `POST` |
||||
|
* Endpoint: `/reaction/{token}/{messageId}` |
||||
|
* Data: |
||||
|
|
||||
|
field | type | Description |
||||
|
---|---|--- |
||||
|
`reaction` | string | the reaction emoji |
||||
|
|
||||
|
* Response: |
||||
|
- Status code: |
||||
|
+ `200 OK` Reaction already exists |
||||
|
+ `201 Created` |
||||
|
+ `400 Bad Request` In case of no reaction support, message out of reactions context or any other error |
||||
|
+ `404 Not Found` When the conversation or message to react could not be found for the participant |
||||
|
+ `409 Conflict` User already did this reaction to this message |
||||
|
|
||||
|
## Delete a reaction |
||||
|
|
||||
|
* Required capability: `reactions` |
||||
|
* Method: `DELETE` |
||||
|
* Endpoint: `/reaction/{token}/{messageId}` |
||||
|
* Data: |
||||
|
|
||||
|
field | type | Description |
||||
|
---|---|--- |
||||
|
`reaction` | string | the reaction emoji |
||||
|
|
||||
|
* Response: |
||||
|
- Status code: |
||||
|
+ `201 Created` |
||||
|
+ `400 Bad Request` In case of no reaction support, message out of reactions context or any other error |
||||
|
+ `404 Not Found` When the conversation or message to react or reaction could not be found for the participant |
||||
|
|
||||
|
## Retrieve reactions of a message by type |
||||
|
|
||||
|
* Required capability: `reactions` |
||||
|
* Method: `GET` |
||||
|
* Endpoint: `/reaction/{token}/{messageId}` |
||||
|
* Data: |
||||
|
|
||||
|
field | type | Description |
||||
|
---|---|--- |
||||
|
`reaction` | string | **Optional:** the reaction emoji |
||||
|
|
||||
|
* Response: |
||||
|
- Status code: |
||||
|
+ `200 OK` |
||||
|
+ `400 Bad Request` In case of no reaction support, message out of reactions context or any other error |
||||
|
+ `404 Not Found` When the conversation or message to react could not be found for the participant |
||||
|
|
||||
|
- Data: |
||||
|
Array with data of reactions: |
||||
|
|
||||
|
field | type | Description |
||||
|
---|---|--- |
||||
|
`actorType` | string | `guests` or `users` |
||||
|
`actorId` | string | Actor id of the reacting participant |
||||
|
`actorDisplayName` | string | Display name of the reaction author |
||||
|
`timestamp` | int | Timestamp in seconds and UTC time zone |
||||
@ -0,0 +1,52 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
/** |
||||
|
* @copyright Copyright (c) 2021 Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @author Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @license GNU AGPL version 3 or any later version |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU Affero General Public License as |
||||
|
* published by the Free Software Foundation, either version 3 of the |
||||
|
* License, or (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU Affero General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU Affero General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
namespace OCA\Talk\Chat\Parser; |
||||
|
|
||||
|
use OCA\Talk\Model\Message; |
||||
|
use OCP\IL10N; |
||||
|
|
||||
|
class ReactionParser { |
||||
|
/** @var IL10N|null */ |
||||
|
private $l; |
||||
|
/** |
||||
|
* @param Message $message |
||||
|
* @throws \OutOfBoundsException |
||||
|
*/ |
||||
|
public function parseMessage(Message $message): void { |
||||
|
$comment = $message->getComment(); |
||||
|
if (!in_array($comment->getVerb(), ['reaction', 'reaction_deleted'])) { |
||||
|
throw new \OutOfBoundsException('Not a reaction'); |
||||
|
} |
||||
|
$this->l = $message->getL10n(); |
||||
|
$message->setMessageType('system'); |
||||
|
if ($comment->getVerb() === 'reaction_deleted') { |
||||
|
// This message is necessary to make compatible with old clients
|
||||
|
$message->setMessage($this->l->t('Message deleted by author'), [], $comment->getVerb()); |
||||
|
} else { |
||||
|
$message->setMessage($message->getMessage(), [], $comment->getVerb()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,153 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
/** |
||||
|
* @copyright Copyright (c) 2021 Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @author Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @license GNU AGPL version 3 or any later version |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU Affero General Public License as |
||||
|
* published by the Free Software Foundation, either version 3 of the |
||||
|
* License, or (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU Affero General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU Affero General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
namespace OCA\Talk\Chat; |
||||
|
|
||||
|
use OCA\Talk\Exceptions\ReactionAlreadyExistsException; |
||||
|
use OCA\Talk\Exceptions\ReactionNotSupportedException; |
||||
|
use OCA\Talk\Exceptions\ReactionOutOfContextException; |
||||
|
use OCA\Talk\Participant; |
||||
|
use OCA\Talk\Room; |
||||
|
use OCP\AppFramework\Utility\ITimeFactory; |
||||
|
use OCP\Comments\IComment; |
||||
|
use OCP\Comments\ICommentsManager; |
||||
|
use OCP\Comments\NotFoundException; |
||||
|
use OCP\IL10N; |
||||
|
|
||||
|
class ReactionManager { |
||||
|
/** @var ICommentsManager|CommentsManager */ |
||||
|
private $commentsManager; |
||||
|
/** @var IL10N */ |
||||
|
private $l; |
||||
|
/** @var MessageParser */ |
||||
|
private $messageParser; |
||||
|
/** @var Notifier */ |
||||
|
private $notifier; |
||||
|
/** @var ITimeFactory */ |
||||
|
protected $timeFactory; |
||||
|
|
||||
|
public function __construct(CommentsManager $commentsManager, |
||||
|
IL10N $l, |
||||
|
MessageParser $messageParser, |
||||
|
Notifier $notifier, |
||||
|
ITimeFactory $timeFactory) { |
||||
|
$this->commentsManager = $commentsManager; |
||||
|
$this->l = $l; |
||||
|
$this->messageParser = $messageParser; |
||||
|
$this->notifier = $notifier; |
||||
|
$this->timeFactory = $timeFactory; |
||||
|
} |
||||
|
|
||||
|
public function addReactionMessage(Room $chat, Participant $participant, IComment $parentMessage, string $reaction): IComment { |
||||
|
try { |
||||
|
// Check if the user already reacted with the same reaction
|
||||
|
$comment = $this->commentsManager->getReactionComment( |
||||
|
(int) $parentMessage->getId(), |
||||
|
$participant->getAttendee()->getActorType(), |
||||
|
$participant->getAttendee()->getActorId(), |
||||
|
$reaction |
||||
|
); |
||||
|
throw new ReactionAlreadyExistsException(); |
||||
|
} catch (NotFoundException $e) { |
||||
|
} |
||||
|
|
||||
|
$comment = $this->commentsManager->create( |
||||
|
$participant->getAttendee()->getActorType(), |
||||
|
$participant->getAttendee()->getActorId(), |
||||
|
'chat', |
||||
|
(string) $chat->getId() |
||||
|
); |
||||
|
$comment->setParentId((string) $parentMessage->getId()); |
||||
|
$comment->setMessage($reaction); |
||||
|
$comment->setVerb('reaction'); |
||||
|
$this->commentsManager->save($comment); |
||||
|
|
||||
|
$this->notifier->notifyReacted($chat, $parentMessage, $comment); |
||||
|
return $comment; |
||||
|
} |
||||
|
|
||||
|
public function deleteReactionMessage(Participant $participant, int $messageId, string $reaction): IComment { |
||||
|
$comment = $this->commentsManager->getReactionComment( |
||||
|
$messageId, |
||||
|
$participant->getAttendee()->getActorType(), |
||||
|
$participant->getAttendee()->getActorId(), |
||||
|
$reaction |
||||
|
); |
||||
|
$comment->setMessage( |
||||
|
json_encode([ |
||||
|
'deleted_by_type' => $participant->getAttendee()->getActorType(), |
||||
|
'deleted_by_id' => $participant->getAttendee()->getActorId(), |
||||
|
'deleted_on' => $this->timeFactory->getDateTime()->getTimestamp(), |
||||
|
]) |
||||
|
); |
||||
|
$comment->setVerb('reaction_deleted'); |
||||
|
$this->commentsManager->save($comment); |
||||
|
return $comment; |
||||
|
} |
||||
|
|
||||
|
public function retrieveReactionMessages(Room $chat, Participant $participant, int $messageId, ?string $reaction): array { |
||||
|
if ($reaction) { |
||||
|
$comments = $this->commentsManager->retrieveAllReactionsWithSpecificReaction($messageId, $reaction); |
||||
|
} else { |
||||
|
$comments = $this->commentsManager->retrieveAllReactions($messageId); |
||||
|
} |
||||
|
|
||||
|
foreach ($comments as $comment) { |
||||
|
$message = $this->messageParser->createMessage($chat, $participant, $comment, $this->l); |
||||
|
$this->messageParser->parseMessage($message); |
||||
|
|
||||
|
$reactions[$comment->getMessage()][] = [ |
||||
|
'actorType' => $comment->getActorType(), |
||||
|
'actorId' => $comment->getActorId(), |
||||
|
'actorDisplayName' => $message->getActorDisplayName(), |
||||
|
'timestamp' => $comment->getCreationDateTime()->getTimestamp(), |
||||
|
]; |
||||
|
} |
||||
|
return $reactions; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param Room $chat |
||||
|
* @param string $messageId |
||||
|
* @return IComment |
||||
|
* @throws NotFoundException |
||||
|
* @throws ReactionNotSupportedException |
||||
|
* @throws ReactionOutOfContextException |
||||
|
*/ |
||||
|
public function getCommentToReact(Room $chat, string $messageId): IComment { |
||||
|
if (!$this->commentsManager->supportReactions()) { |
||||
|
throw new ReactionNotSupportedException(); |
||||
|
} |
||||
|
$comment = $this->commentsManager->get($messageId); |
||||
|
|
||||
|
if ($comment->getObjectType() !== 'chat' |
||||
|
|| $comment->getObjectId() !== (string) $chat->getId() |
||||
|
|| $comment->getVerb() !== 'comment') { |
||||
|
throw new ReactionOutOfContextException(); |
||||
|
} |
||||
|
|
||||
|
return $comment; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,130 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
/** |
||||
|
* @copyright Copyright (c) 2021 Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @author Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @license GNU AGPL version 3 or any later version |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU Affero General Public License as |
||||
|
* published by the Free Software Foundation, either version 3 of the |
||||
|
* License, or (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU Affero General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU Affero General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
namespace OCA\Talk\Controller; |
||||
|
|
||||
|
use OCA\Talk\Chat\ReactionManager; |
||||
|
use OCA\Talk\Exceptions\ReactionAlreadyExistsException; |
||||
|
use OCA\Talk\Exceptions\ReactionNotSupportedException; |
||||
|
use OCA\Talk\Exceptions\ReactionOutOfContextException; |
||||
|
use OCP\AppFramework\Http; |
||||
|
use OCP\AppFramework\Http\DataResponse; |
||||
|
use OCP\Comments\NotFoundException; |
||||
|
use OCP\IRequest; |
||||
|
|
||||
|
class ReactionController extends AEnvironmentAwareController { |
||||
|
/** @var ReactionManager */ |
||||
|
private $reactionManager; |
||||
|
|
||||
|
public function __construct(string $appName, |
||||
|
IRequest $request, |
||||
|
ReactionManager $reactionManager) { |
||||
|
parent::__construct($appName, $request); |
||||
|
$this->reactionManager = $reactionManager; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @NoAdminRequired |
||||
|
* @RequireParticipant |
||||
|
* @RequireReadWriteConversation |
||||
|
* @RequireModeratorOrNoLobby |
||||
|
* |
||||
|
* @param int $messageId for reaction |
||||
|
* @param string $reaction the reaction emoji |
||||
|
* @return DataResponse |
||||
|
*/ |
||||
|
public function react(int $messageId, string $reaction): DataResponse { |
||||
|
try { |
||||
|
$chat = $this->getRoom(); |
||||
|
$participant = $this->getParticipant(); |
||||
|
$parentMessage = $this->reactionManager->getCommentToReact($chat, (string) $messageId); |
||||
|
$this->reactionManager->addReactionMessage($chat, $participant, $parentMessage, $reaction); |
||||
|
} catch (NotFoundException $e) { |
||||
|
return new DataResponse([], Http::STATUS_NOT_FOUND); |
||||
|
} catch (ReactionAlreadyExistsException $e) { |
||||
|
return new DataResponse([], Http::STATUS_OK); |
||||
|
} catch (ReactionNotSupportedException | ReactionOutOfContextException | \Exception $e) { |
||||
|
return new DataResponse([], Http::STATUS_BAD_REQUEST); |
||||
|
} |
||||
|
return new DataResponse([], Http::STATUS_CREATED); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @NoAdminRequired |
||||
|
* @RequireParticipant |
||||
|
* @RequireReadWriteConversation |
||||
|
* @RequireModeratorOrNoLobby |
||||
|
* |
||||
|
* @param int $messageId for reaction |
||||
|
* @param string $reaction the reaction emoji |
||||
|
* @return DataResponse |
||||
|
*/ |
||||
|
public function delete(int $messageId, string $reaction): DataResponse { |
||||
|
$participant = $this->getParticipant(); |
||||
|
try { |
||||
|
// Verify that messageId is part of the room
|
||||
|
$this->reactionManager->getCommentToReact($this->getRoom(), (string) $messageId); |
||||
|
} catch (ReactionNotSupportedException | ReactionOutOfContextException | NotFoundException $e) { |
||||
|
return new DataResponse([], Http::STATUS_NOT_FOUND); |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
$this->reactionManager->deleteReactionMessage( |
||||
|
$participant, |
||||
|
$messageId, |
||||
|
$reaction |
||||
|
); |
||||
|
} catch (NotFoundException $e) { |
||||
|
return new DataResponse([], Http::STATUS_NOT_FOUND); |
||||
|
} catch (\Exception $e) { |
||||
|
return new DataResponse([], Http::STATUS_BAD_REQUEST); |
||||
|
} |
||||
|
|
||||
|
return new DataResponse([], Http::STATUS_OK); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @NoAdminRequired |
||||
|
* @RequireParticipant |
||||
|
* @RequireReadWriteConversation |
||||
|
* @RequireModeratorOrNoLobby |
||||
|
* |
||||
|
* @param int $messageId for reaction |
||||
|
* @param string|null $reaction the reaction emoji |
||||
|
* @return DataResponse |
||||
|
*/ |
||||
|
public function getReactions(int $messageId, ?string $reaction): DataResponse { |
||||
|
try { |
||||
|
// Verify that messageId is part of the room
|
||||
|
$this->reactionManager->getCommentToReact($this->getRoom(), (string) $messageId); |
||||
|
} catch (ReactionNotSupportedException | ReactionOutOfContextException | NotFoundException $e) { |
||||
|
return new DataResponse([], Http::STATUS_NOT_FOUND); |
||||
|
} |
||||
|
|
||||
|
$reactions = $this->reactionManager->retrieveReactionMessages($this->getRoom(), $this->getParticipant(), $messageId, $reaction); |
||||
|
|
||||
|
return new DataResponse($reactions, Http::STATUS_OK); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
/** |
||||
|
* @copyright Copyright (c) 2021 Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @author Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @license GNU AGPL version 3 or any later version |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU Affero General Public License as |
||||
|
* published by the Free Software Foundation, either version 3 of the |
||||
|
* License, or (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU Affero General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU Affero General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
namespace OCA\Talk\Exceptions; |
||||
|
|
||||
|
class ReactionAlreadyExistsException extends \OutOfBoundsException { |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
/** |
||||
|
* @copyright Copyright (c) 2022, Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @author Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @license GNU AGPL version 3 or any later version |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU Affero General Public License as |
||||
|
* published by the Free Software Foundation, either version 3 of the |
||||
|
* License, or (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU Affero General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU Affero General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
namespace OCA\Talk\Exceptions; |
||||
|
|
||||
|
class ReactionNotSupportedException extends \Exception { |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
/** |
||||
|
* @copyright Copyright (c) 2022, Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @author Vitor Mattos <vitor@php.rio> |
||||
|
* |
||||
|
* @license GNU AGPL version 3 or any later version |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU Affero General Public License as |
||||
|
* published by the Free Software Foundation, either version 3 of the |
||||
|
* License, or (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU Affero General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU Affero General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
namespace OCA\Talk\Exceptions; |
||||
|
|
||||
|
class ReactionOutOfContextException extends \Exception { |
||||
|
} |
||||
@ -0,0 +1,68 @@ |
|||||
|
Feature: reaction/react |
||||
|
Background: |
||||
|
Given user "participant1" exists |
||||
|
Given user "participant2" exists |
||||
|
|
||||
|
Scenario: React to message with success |
||||
|
Given user "participant1" creates room "room" (v4) |
||||
|
| roomType | 3 | |
||||
|
| roomName | room | |
||||
|
And user "participant1" adds user "participant2" to room "room" with 200 (v4) |
||||
|
And user "participant1" sends message "Message 1" to room "room" with 201 |
||||
|
And user "participant2" react with "👍" on message "Message 1" to room "room" with 201 |
||||
|
Then user "participant1" sees the following messages in room "room" with 200 |
||||
|
| room | actorType | actorId | actorDisplayName | message | messageParameters | reactions | |
||||
|
| room | users | participant1 | participant1-displayname | Message 1 | [] | {"👍":1} | |
||||
|
And user "participant1" react with "👍" on message "Message 1" to room "room" with 201 |
||||
|
Then user "participant1" sees the following messages in room "room" with 200 |
||||
|
| room | actorType | actorId | actorDisplayName | message | messageParameters | reactions | |
||||
|
| room | users | participant1 | participant1-displayname | Message 1 | [] | {"👍":2} | |
||||
|
|
||||
|
Scenario: React two times to same message with the same reaction |
||||
|
Given user "participant1" creates room "room" (v4) |
||||
|
| roomType | 3 | |
||||
|
| roomName | room | |
||||
|
And user "participant1" adds user "participant2" to room "room" with 200 (v4) |
||||
|
And user "participant1" sends message "Message 1" to room "room" with 201 |
||||
|
And user "participant2" react with "👍" on message "Message 1" to room "room" with 201 |
||||
|
And user "participant2" react with "👍" on message "Message 1" to room "room" with 200 |
||||
|
Then user "participant1" sees the following messages in room "room" with 200 |
||||
|
| room | actorType | actorId | actorDisplayName | message | messageParameters | reactions | |
||||
|
| room | users | participant1 | participant1-displayname | Message 1 | [] | {"👍":1} | |
||||
|
|
||||
|
Scenario: Delete reaction to message with success |
||||
|
Given user "participant1" creates room "room" (v4) |
||||
|
| roomType | 3 | |
||||
|
| roomName | room | |
||||
|
And user "participant1" adds user "participant2" to room "room" with 200 (v4) |
||||
|
And user "participant1" sends message "Message 1" to room "room" with 201 |
||||
|
And user "participant2" react with "👍" on message "Message 1" to room "room" with 201 |
||||
|
Then user "participant1" sees the following messages in room "room" with 200 |
||||
|
| room | actorType | actorId | actorDisplayName | message | messageParameters | reactions | |
||||
|
| room | users | participant1 | participant1-displayname | Message 1 | [] | {"👍":1} | |
||||
|
And user "participant2" delete react with "👍" on message "Message 1" to room "room" with 200 |
||||
|
Then user "participant1" sees the following messages in room "room" with 200 |
||||
|
| room | actorType | actorId | actorDisplayName | message | messageParameters | reactions | |
||||
|
| room | users | participant1 | participant1-displayname | Message 1 | [] | [] | |
||||
|
|
||||
|
Scenario: Retrieve reactions of a message |
||||
|
Given user "participant1" creates room "room" (v4) |
||||
|
| roomType | 3 | |
||||
|
| roomName | room | |
||||
|
And user "participant1" adds user "participant2" to room "room" with 200 (v4) |
||||
|
And user "participant1" sends message "Message 1" to room "room" with 201 |
||||
|
And user "participant1" react with "👍" on message "Message 1" to room "room" with 201 |
||||
|
And user "participant2" react with "👍" on message "Message 1" to room "room" with 201 |
||||
|
Then user "participant1" retrieve reactions "👍" of message "Message 1" in room "room" with 200 |
||||
|
| actorType | actorId | actorDisplayName | reaction | |
||||
|
| users | participant1 | participant1-displayname | 👍 | |
||||
|
| users | participant2 | participant2-displayname | 👍 | |
||||
|
And user "participant2" react with "👎" on message "Message 1" to room "room" with 201 |
||||
|
And user "participant1" retrieve reactions "👎" of message "Message 1" in room "room" with 200 |
||||
|
| actorType | actorId | actorDisplayName | reaction | |
||||
|
| users | participant2 | participant2-displayname | 👎 | |
||||
|
And user "participant1" retrieve reactions "all" of message "Message 1" in room "room" with 200 |
||||
|
| actorType | actorId | actorDisplayName | reaction | |
||||
|
| users | participant1 | participant1-displayname | 👍 | |
||||
|
| users | participant2 | participant2-displayname | 👎 | |
||||
|
| users | participant2 | participant2-displayname | 👍 | |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue