Browse Source

feat(reminders): Add API endpoint to get upcoming reminders

Signed-off-by: Joas Schilling <coding@schilljs.com>
pull/15038/head
Joas Schilling 7 months ago
parent
commit
7e30f1c07c
No known key found for this signature in database GPG Key ID: F72FA5B49FFA96B0
  1. 6
      appinfo/routes/routesChatController.php
  2. 1
      docs/capabilities.md
  3. 2
      lib/Capabilities.php
  4. 2
      lib/Chat/ChatManager.php
  5. 90
      lib/Controller/ChatController.php
  6. 6
      lib/Manager.php
  7. 2
      lib/Model/Reminder.php
  8. 11
      lib/Model/ReminderMapper.php
  9. 13
      lib/ResponseDefinitions.php
  10. 4
      lib/Service/ReminderService.php
  11. 121
      openapi-full.json
  12. 121
      openapi.json
  13. 64
      src/types/openapi/openapi-full.ts
  14. 64
      src/types/openapi/openapi.ts
  15. 22
      tests/integration/features/bootstrap/FeatureContext.php
  16. 30
      tests/integration/features/chat-3/reminder.feature
  17. 4
      tests/php/Controller/ChatControllerTest.php

6
appinfo/routes/routesChatController.php

@ -6,6 +6,10 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
$requirementsVersionOnly = [
'apiVersion' => '(v1)',
];
$requirements = [
'apiVersion' => '(v1)',
'token' => '[a-z0-9]{4,30}',
@ -39,6 +43,8 @@ return [
['name' => 'Chat#getReminder', 'url' => '/api/{apiVersion}/chat/{token}/{messageId}/reminder', 'verb' => 'GET', 'requirements' => $requirementsWithMessageId],
/** @see \OCA\Talk\Controller\ChatController::deleteReminder() */
['name' => 'Chat#deleteReminder', 'url' => '/api/{apiVersion}/chat/{token}/{messageId}/reminder', 'verb' => 'DELETE', 'requirements' => $requirementsWithMessageId],
/** @see \OCA\Talk\Controller\ChatController::getUpcomingReminders() */
['name' => 'Chat#getUpcomingReminders', 'url' => '/api/{apiVersion}/chat/upcoming-reminders', 'verb' => 'GET', 'requirements' => $requirementsVersionOnly],
/** @see \OCA\Talk\Controller\ChatController::setReadMarker() */
['name' => 'Chat#setReadMarker', 'url' => '/api/{apiVersion}/chat/{token}/read', 'verb' => 'POST', 'requirements' => $requirements],
/** @see \OCA\Talk\Controller\ChatController::markUnread() */

1
docs/capabilities.md

@ -189,3 +189,4 @@
* `config => call => predefined-backgrounds-v2` (local) - Whether virtual backgrounds should be read from the theming directory
* `dashboard-event-rooms` (local) - Whether Talk APIs offer functionality for Dashboard requests
* `mutual-calendar-events` (local) - Whether Talk APIs offer mutual calendar events for 1:1 rooms
* `upcoming-reminders` (local) - Whether the API to list upcoming reminders exists

2
lib/Capabilities.php

@ -120,6 +120,7 @@ class Capabilities implements IPublicCapability {
'sip-direct-dialin',
'dashboard-event-rooms',
'mutual-calendar-events',
'upcoming-reminders',
];
public const CONDITIONAL_FEATURES = [
@ -148,6 +149,7 @@ class Capabilities implements IPublicCapability {
'sip-direct-dialin',
'dashboard-event-rooms',
'mutual-calendar-events',
'upcoming-reminders',
];
public const LOCAL_CONFIGS = [

2
lib/Chat/ChatManager.php

@ -978,7 +978,7 @@ class ChatManager {
* Get messages by ID
*
* @param int[] $commentIds
* @return IComment[] Key is the message id
* @return array<int, IComment> Key is the message id
*/
public function getMessagesById(array $commentIds): array {
return $this->commentsManager->getCommentsById(array_map('strval', $commentIds));

90
lib/Controller/ChatController.php

@ -17,8 +17,10 @@ use OCA\Talk\Chat\Notifier;
use OCA\Talk\Chat\ReactionManager;
use OCA\Talk\Exceptions\CannotReachRemoteException;
use OCA\Talk\Exceptions\ChatSummaryException;
use OCA\Talk\Exceptions\ParticipantNotFoundException;
use OCA\Talk\Federation\Authenticator;
use OCA\Talk\GuestManager;
use OCA\Talk\Manager;
use OCA\Talk\MatterbridgeManager;
use OCA\Talk\Middleware\Attribute\FederationSupported;
use OCA\Talk\Middleware\Attribute\RequireAuthenticatedParticipant;
@ -32,6 +34,7 @@ use OCA\Talk\Model\Attachment;
use OCA\Talk\Model\Attendee;
use OCA\Talk\Model\Bot;
use OCA\Talk\Model\Message;
use OCA\Talk\Model\Reminder;
use OCA\Talk\Model\Session;
use OCA\Talk\Participant;
use OCA\Talk\ResponseDefinitions;
@ -83,6 +86,7 @@ use Psr\Log\LoggerInterface;
* @psalm-import-type TalkChatMessage from ResponseDefinitions
* @psalm-import-type TalkChatMessageWithParent from ResponseDefinitions
* @psalm-import-type TalkChatReminder from ResponseDefinitions
* @psalm-import-type TalkChatReminderUpcoming from ResponseDefinitions
* @psalm-import-type TalkRichObjectParameter from ResponseDefinitions
* @psalm-import-type TalkRoom from ResponseDefinitions
*/
@ -97,6 +101,7 @@ class ChatController extends AEnvironmentAwareOCSController {
private IUserManager $userManager,
private IAppManager $appManager,
private ChatManager $chatManager,
protected Manager $manager,
private RoomFormatter $roomFormatter,
private ReactionManager $reactionManager,
private ParticipantService $participantService,
@ -1034,6 +1039,8 @@ class ChatController extends AEnvironmentAwareOCSController {
#[UserRateLimit(limit: 60, period: 3600)]
public function setReminder(int $messageId, int $timestamp): DataResponse {
try {
// FIXME fail 400 when reminder is after expiration
// And system messages
$this->validateMessageExists($messageId, sync: true);
} catch (DoesNotExistException) {
return new DataResponse(['error' => 'message'], Http::STATUS_NOT_FOUND);
@ -1113,6 +1120,89 @@ class ChatController extends AEnvironmentAwareOCSController {
return new DataResponse([], Http::STATUS_OK);
}
/**
* Get all upcoming reminders
*
* Required capability: `upcoming-reminders`
*
* @return DataResponse<Http::STATUS_OK, list<TalkChatReminderUpcoming>, array{}>
*
* 200: Reminders returned
*/
#[NoAdminRequired]
public function getUpcomingReminders(): DataResponse {
if ($this->userId === null) {
return new DataResponse([], Http::STATUS_OK);
}
$reminders = $this->reminderService->getUpcomingReminders($this->userId, Reminder::NUM_UPCOMING_REMINDERS);
if (empty($reminders)) {
return new DataResponse([], Http::STATUS_OK);
}
$tokens = array_unique(array_map(static fn (Reminder $reminder): string => $reminder->getToken(), $reminders));
$rooms = $this->manager->getRoomsForActor(Attendee::ACTOR_USERS, $this->userId, tokens: $tokens);
$roomMap = [];
foreach ($rooms as $room) {
if ($room->isFederatedConversation()) {
// FIXME Federated chats
continue;
}
$roomMap[$room->getToken()] = $room;
}
/** @var Reminder[] $reminders */
$reminders = array_filter($reminders, static fn (Reminder $reminder): bool => isset($roomMap[$reminder->getToken()]));
if (empty($reminders)) {
return new DataResponse([], Http::STATUS_OK);
}
$messageIds = array_map(static fn (Reminder $reminder): int => $reminder->getMessageId(), $reminders);
$comments = $this->chatManager->getMessagesById($messageIds);
$now = $this->timeFactory->getDateTime();
$resultData = [];
foreach ($reminders as $reminder) {
if (!isset($comments[$reminder->getMessageId()])) {
continue;
}
$comment = $comments[$reminder->getMessageId()];
$room = $roomMap[$reminder->getToken()];
try {
$participant = $this->participantService->getParticipant($room, $this->userId);
} catch (ParticipantNotFoundException) {
continue;
}
$message = $this->messageParser->createMessage($room, $participant, $comment, $this->l);
$this->messageParser->parseMessage($message);
$expireDate = $message->getExpirationDateTime();
if ($expireDate instanceof \DateTime && $expireDate < $now) {
continue;
}
if (!$message->getVisibility()) {
continue;
}
$data = $message->toArray($this->getResponseFormat());
$resultData[] = [
'reminderTimestamp' => $reminder->getDateTime()->getTimestamp(),
'roomToken' => $reminder->getToken(),
'messageId' => $reminder->getMessageId(),
'actorType' => $data['actorType'],
'actorId' => $data['actorId'],
'actorDisplayName' => $data['actorDisplayName'],
'message' => $data['message'],
'messageParameters' => $data['messageParameters'],
];
}
return new DataResponse($resultData, Http::STATUS_OK);
}
/**
* @throws DoesNotExistException
* @throws CannotReachRemoteException

6
lib/Manager.php

@ -359,7 +359,7 @@ class Manager {
* @param bool $includeLastMessage
* @return Room[]
*/
public function getRoomsForActor(string $actorType, string $actorId, array $sessionIds = [], bool $includeLastMessage = false): array {
public function getRoomsForActor(string $actorType, string $actorId, array $sessionIds = [], bool $includeLastMessage = false, array $tokens = []): array {
$query = $this->db->getQueryBuilder();
$helper = new SelectHelper();
$helper->selectRoomsTable($query);
@ -372,6 +372,10 @@ class Manager {
))
->where($query->expr()->isNotNull('a.id'));
if (!empty($tokens)) {
$query->andWhere($query->expr()->in('r.token', $query->createNamedParameter($tokens, IQueryBuilder::PARAM_STR_ARRAY)));
}
if (!empty($sessionIds)) {
$helper->selectSessionsTable($query);
$query->leftJoin('a', 'talk_sessions', 's', $query->expr()->andX(

2
lib/Model/Reminder.php

@ -25,6 +25,8 @@ use OCP\DB\Types;
* @psalm-import-type TalkChatReminder from ResponseDefinitions
*/
class Reminder extends Entity implements \JsonSerializable {
public const NUM_UPCOMING_REMINDERS = 10;
protected string $userId = '';
protected string $token = '';
protected int $messageId = 0;

11
lib/Model/ReminderMapper.php

@ -29,6 +29,17 @@ class ReminderMapper extends QBMapper {
parent::__construct($db, 'talk_reminders', Reminder::class);
}
public function findForUser(string $userId, int $limit): array {
$query = $this->db->getQueryBuilder();
$query->select('*')
->from($this->getTableName())
->where($query->expr()->eq('user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
->orderBy('date_time', 'ASC')
->setMaxResults($limit);
return $this->findEntities($query);
}
/**
* @throws DoesNotExistException
*/

13
lib/ResponseDefinitions.php

@ -135,7 +135,18 @@ namespace OCA\Talk;
* messageId: int,
* timestamp: int,
* token: string,
* userId: string
* userId: string,
* }
*
* @psalm-type TalkChatReminderUpcoming = array{
* actorDisplayName: string,
* actorId: string,
* actorType: string,
* message: string,
* messageId: int,
* messageParameters: array<string, TalkRichObjectParameter>,
* reminderTimestamp: int,
* roomToken: string,
* }
*
* @psalm-type TalkFederationInvite = array{

4
lib/Service/ReminderService.php

@ -31,6 +31,10 @@ class ReminderService {
) {
}
public function getUpcomingReminders(string $userId, int $limit): array {
return $this->reminderMapper->findForUser($userId, $limit);
}
public function setReminder(string $userId, string $token, int $messageId, int $timestamp): Reminder {
try {
$reminder = $this->reminderMapper->findForUserAndMessage($userId, $token, $messageId);

121
openapi-full.json

@ -660,6 +660,50 @@
}
}
},
"ChatReminderUpcoming": {
"type": "object",
"required": [
"actorDisplayName",
"actorId",
"actorType",
"message",
"messageId",
"messageParameters",
"reminderTimestamp",
"roomToken"
],
"properties": {
"actorDisplayName": {
"type": "string"
},
"actorId": {
"type": "string"
},
"actorType": {
"type": "string"
},
"message": {
"type": "string"
},
"messageId": {
"type": "integer",
"format": "int64"
},
"messageParameters": {
"type": "object",
"additionalProperties": {
"$ref": "#/components/schemas/RichObjectParameter"
}
},
"reminderTimestamp": {
"type": "integer",
"format": "int64"
},
"roomToken": {
"type": "string"
}
}
},
"DashboardEvent": {
"type": "object",
"required": [
@ -8137,6 +8181,83 @@
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/chat/upcoming-reminders": {
"get": {
"operationId": "chat-get-upcoming-reminders",
"summary": "Get all upcoming reminders",
"description": "Required capability: `upcoming-reminders`",
"tags": [
"chat"
],
"security": [
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "string",
"enum": [
"v1"
],
"default": "v1"
}
},
{
"name": "OCS-APIRequest",
"in": "header",
"description": "Required to be true for the API request to pass",
"required": true,
"schema": {
"type": "boolean",
"default": true
}
}
],
"responses": {
"200": {
"description": "Reminders returned",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ChatReminderUpcoming"
}
}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/chat/{token}/read": {
"post": {
"operationId": "chat-set-read-marker",

121
openapi.json

@ -619,6 +619,50 @@
}
}
},
"ChatReminderUpcoming": {
"type": "object",
"required": [
"actorDisplayName",
"actorId",
"actorType",
"message",
"messageId",
"messageParameters",
"reminderTimestamp",
"roomToken"
],
"properties": {
"actorDisplayName": {
"type": "string"
},
"actorId": {
"type": "string"
},
"actorType": {
"type": "string"
},
"message": {
"type": "string"
},
"messageId": {
"type": "integer",
"format": "int64"
},
"messageParameters": {
"type": "object",
"additionalProperties": {
"$ref": "#/components/schemas/RichObjectParameter"
}
},
"reminderTimestamp": {
"type": "integer",
"format": "int64"
},
"roomToken": {
"type": "string"
}
}
},
"DashboardEvent": {
"type": "object",
"required": [
@ -8042,6 +8086,83 @@
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/chat/upcoming-reminders": {
"get": {
"operationId": "chat-get-upcoming-reminders",
"summary": "Get all upcoming reminders",
"description": "Required capability: `upcoming-reminders`",
"tags": [
"chat"
],
"security": [
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "string",
"enum": [
"v1"
],
"default": "v1"
}
},
{
"name": "OCS-APIRequest",
"in": "header",
"description": "Required to be true for the API request to pass",
"required": true,
"schema": {
"type": "boolean",
"default": true
}
}
],
"responses": {
"200": {
"description": "Reminders returned",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ChatReminderUpcoming"
}
}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/chat/{token}/read": {
"post": {
"operationId": "chat-set-read-marker",

64
src/types/openapi/openapi-full.ts

@ -495,6 +495,26 @@ export type paths = {
patch?: never;
trace?: never;
};
"/ocs/v2.php/apps/spreed/api/{apiVersion}/chat/upcoming-reminders": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get all upcoming reminders
* @description Required capability: `upcoming-reminders`
*/
get: operations["chat-get-upcoming-reminders"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/ocs/v2.php/apps/spreed/api/{apiVersion}/chat/{token}/read": {
parameters: {
query?: never;
@ -2240,6 +2260,20 @@ export type components = {
token: string;
userId: string;
};
ChatReminderUpcoming: {
actorDisplayName: string;
actorId: string;
actorType: string;
message: string;
/** Format: int64 */
messageId: number;
messageParameters: {
[key: string]: components["schemas"]["RichObjectParameter"];
};
/** Format: int64 */
reminderTimestamp: number;
roomToken: string;
};
DashboardEvent: {
calendars: components["schemas"]["DashboardEventCalendar"][];
eventName: string;
@ -5169,6 +5203,36 @@ export interface operations {
};
};
};
"chat-get-upcoming-reminders": {
parameters: {
query?: never;
header: {
/** @description Required to be true for the API request to pass */
"OCS-APIRequest": boolean;
};
path: {
apiVersion: "v1";
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Reminders returned */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
ocs: {
meta: components["schemas"]["OCSMeta"];
data: components["schemas"]["ChatReminderUpcoming"][];
};
};
};
};
};
};
"chat-set-read-marker": {
parameters: {
query?: never;

64
src/types/openapi/openapi.ts

@ -495,6 +495,26 @@ export type paths = {
patch?: never;
trace?: never;
};
"/ocs/v2.php/apps/spreed/api/{apiVersion}/chat/upcoming-reminders": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get all upcoming reminders
* @description Required capability: `upcoming-reminders`
*/
get: operations["chat-get-upcoming-reminders"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/ocs/v2.php/apps/spreed/api/{apiVersion}/chat/{token}/read": {
parameters: {
query?: never;
@ -1718,6 +1738,20 @@ export type components = {
token: string;
userId: string;
};
ChatReminderUpcoming: {
actorDisplayName: string;
actorId: string;
actorType: string;
message: string;
/** Format: int64 */
messageId: number;
messageParameters: {
[key: string]: components["schemas"]["RichObjectParameter"];
};
/** Format: int64 */
reminderTimestamp: number;
roomToken: string;
};
DashboardEvent: {
calendars: components["schemas"]["DashboardEventCalendar"][];
eventName: string;
@ -4631,6 +4665,36 @@ export interface operations {
};
};
};
"chat-get-upcoming-reminders": {
parameters: {
query?: never;
header: {
/** @description Required to be true for the API request to pass */
"OCS-APIRequest": boolean;
};
path: {
apiVersion: "v1";
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Reminders returned */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
ocs: {
meta: components["schemas"]["OCSMeta"];
data: components["schemas"]["ChatReminderUpcoming"][];
};
};
};
};
};
};
"chat-set-read-marker": {
parameters: {
query?: never;

22
tests/integration/features/bootstrap/FeatureContext.php

@ -1982,6 +1982,28 @@ class FeatureContext implements Context, SnippetAcceptingContext {
$this->assertStatusCode($this->response, $statusCode);
}
#[Then('/^user "([^"]*)" gets upcoming reminders \((v1)\)$/')]
public function userGetsUpcomingReminders(string $user, string $apiVersion, ?TableNode $table = null): void {
$this->setCurrentUser($user);
$this->sendRequest('GET', '/apps/spreed/api/' . $apiVersion . '/chat/upcoming-reminders');
$this->assertStatusCode($this->response, 200);
$actual = $this->getDataFromResponse($this->response);
var_dump($actual);
if ($table === null) {
Assert::assertEmpty($actual);
return;
}
Assert::assertEquals(array_map(function (array $expected): array {
$expected['messageId'] = self::$textToMessageId[$expected['messageId']];
$expected['roomToken'] = self::$identifierToToken[$expected['roomToken']];
$expected['messageParameters'] = json_decode($expected['messageParameters']);
return $expected;
}, $table->getHash()), $actual);
}
#[Then('/^user "([^"]*)" shares rich-object "([^"]*)" "([^"]*)" \'([^\']*)\' to room "([^"]*)" with (\d+)(?: \((v1)\))?$/')]
public function userSharesRichObjectToRoom(string $user, string $type, string $id, string $metaData, string $identifier, int $statusCode, string $apiVersion = 'v1'): void {
$this->setCurrentUser($user);

30
tests/integration/features/chat-3/reminder.feature

@ -150,3 +150,33 @@ Feature: chat-2/reminder
And user "participant1" deletes reminder for message "Message 1" in room "room" with 200 (v1)
And user "participant1" has the following notifications
| app | object_type | object_id | subject |
Scenario: Upcoming reminders
Given user "participant1" creates room "room1" (v4)
| roomType | 3 |
| roomName | room1 |
Given user "participant2" creates room "room2" (v4)
| roomType | 3 |
| roomName | room2 |
And user "participant2" adds user "participant1" to room "room2" with 200 (v4)
Given user "participant1" creates room "room3" (v4)
| roomType | 1 |
| invite | participant2 |
And user "participant1" sends message "Message 1" to room "room1" with 201
And user "participant2" sends message "Message 2" to room "room2" with 201
And user "participant1" sends message "Message 3" to room "room3" with 201
When user "participant1" sets reminder for message "Message 1" in room "room1" for time 1234567 with 201 (v1)
And user "participant1" sets reminder for message "Message 2" in room "room2" for time 1234568 with 201 (v1)
And user "participant1" sets reminder for message "Message 3" in room "room3" for time 1234569 with 201 (v1)
Then user "participant1" gets upcoming reminders (v1)
| reminderTimestamp | roomToken | messageId | actorType | actorId | actorDisplayName | message | messageParameters |
| 1234567 | room1 | Message 1 | users | participant1 | participant1-displayname | Message 1 | [] |
| 1234568 | room2 | Message 2 | users | participant2 | participant2-displayname | Message 2 | [] |
| 1234569 | room3 | Message 3 | users | participant1 | participant1-displayname | Message 3 | [] |
And user "participant2" removes "participant1" from room "room2" with 200 (v4)
Then user "participant1" gets upcoming reminders (v1)
| reminderTimestamp | roomToken | messageId | actorType | actorId | actorDisplayName | message | messageParameters |
| 1234567 | room1 | Message 1 | users | participant1 | participant1-displayname | Message 1 | [] |
| 1234569 | room3 | Message 3 | users | participant1 | participant1-displayname | Message 3 | [] |
And force run "OCA\Talk\BackgroundJob\Reminder" background jobs
Then user "participant1" gets upcoming reminders (v1)

4
tests/php/Controller/ChatControllerTest.php

@ -16,6 +16,7 @@ use OCA\Talk\Chat\ReactionManager;
use OCA\Talk\Controller\ChatController;
use OCA\Talk\Federation\Authenticator;
use OCA\Talk\GuestManager;
use OCA\Talk\Manager;
use OCA\Talk\MatterbridgeManager;
use OCA\Talk\Model\Attendee;
use OCA\Talk\Model\Message;
@ -59,6 +60,7 @@ class ChatControllerTest extends TestCase {
protected IUserManager&MockObject $userManager;
protected IAppManager&MockObject $appManager;
protected ChatManager&MockObject $chatManager;
protected Manager&MockObject $manager;
private RoomFormatter&MockObject $roomFormatter;
protected ReactionManager&MockObject $reactionManager;
protected ParticipantService&MockObject $participantService;
@ -102,6 +104,7 @@ class ChatControllerTest extends TestCase {
$this->userManager = $this->createMock(IUserManager::class);
$this->appManager = $this->createMock(IAppManager::class);
$this->chatManager = $this->createMock(ChatManager::class);
$this->manager = $this->createMock(Manager::class);
$this->roomFormatter = $this->createMock(RoomFormatter::class);
$this->reactionManager = $this->createMock(ReactionManager::class);
$this->participantService = $this->createMock(ParticipantService::class);
@ -151,6 +154,7 @@ class ChatControllerTest extends TestCase {
$this->userManager,
$this->appManager,
$this->chatManager,
$this->manager,
$this->roomFormatter,
$this->reactionManager,
$this->participantService,

Loading…
Cancel
Save