Merge pull request #7327 from nextcloud/feature/api-time-to-live

Implement time to live
This commit is contained in:
Joas Schilling 2022-07-01 17:25:41 +02:00 committed by GitHub
commit 332352f40a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 425 additions and 13 deletions

View file

@ -16,7 +16,7 @@ And in the works for the [coming versions](https://github.com/nextcloud/spreed/m
]]></description>
<version>15.0.0-dev.4</version>
<version>15.0.0-dev.5</version>
<licence>agpl</licence>
<author>Aleksandra Lazarević</author>

View file

@ -102,5 +102,7 @@ return [
['name' => 'Room#setLobby', 'url' => '/api/{apiVersion}/room/{token}/webinar/lobby', 'verb' => 'PUT', 'requirements' => $requirementsWithToken],
/** @see \OCA\Talk\Controller\RoomController::setSIPEnabled() */
['name' => 'Room#setSIPEnabled', 'url' => '/api/{apiVersion}/room/{token}/webinar/sip', 'verb' => 'PUT', 'requirements' => $requirementsWithToken],
/** @see \OCA\Talk\Controller\RoomController::setMessageExpiration() */
['name' => 'Room#setMessageExpiration', 'url' => '/api/{apiVersion}/room/{token}/message-expiration', 'verb' => 'POST', 'requirements' => $requirements],
],
];

10
composer.lock generated
View file

@ -242,12 +242,12 @@
"source": {
"type": "git",
"url": "https://github.com/ChristophWurst/nextcloud_composer.git",
"reference": "b6789dd4128302a1d6c38c0239c762d0fab620eb"
"reference": "3bfc852196553be30c20d445a8daf4d4c343642e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ChristophWurst/nextcloud_composer/zipball/b6789dd4128302a1d6c38c0239c762d0fab620eb",
"reference": "b6789dd4128302a1d6c38c0239c762d0fab620eb",
"url": "https://api.github.com/repos/ChristophWurst/nextcloud_composer/zipball/3bfc852196553be30c20d445a8daf4d4c343642e",
"reference": "3bfc852196553be30c20d445a8daf4d4c343642e",
"shasum": ""
},
"require": {
@ -278,7 +278,7 @@
"issues": "https://github.com/ChristophWurst/nextcloud_composer/issues",
"source": "https://github.com/ChristophWurst/nextcloud_composer/tree/master"
},
"time": "2022-06-14T02:18:09+00:00"
"time": "2022-06-29T02:19:47+00:00"
},
{
"name": "composer/package-versions-deprecated",
@ -4916,5 +4916,5 @@
"platform-overrides": {
"php": "7.4"
},
"plugin-api-version": "2.1.0"
"plugin-api-version": "2.3.0"
}

View file

@ -97,6 +97,7 @@ title: Capabilities
* `unified-search` - When the extended attributes of unified search results are there
* `chat-permission` - When permission 128 is required to post chat messages, reaction or share items to the conversation
* `silent-send` - Whether the chat API allows to send chat messages without triggering notifications
* `message-expiration` - Message expiration time for a conversation
* `sip-support-nopin` - Whether SIP can be configured to not require a custom attendee PIN
* `send-call-notification` - When the API allows to resend call notifications for individual users that did not join yet
* `silent-call` - Allow to start calls without sending notification

View file

@ -384,4 +384,5 @@ See [OCP\RichObjectStrings\Definitions](https://github.com/nextcloud/server/blob
* Creating a poll is an `object_shared` with a poll object
* `poll_voted` - {actor} voted on the poll {poll}
* `poll_closed` - {actor} closed the poll {poll}
* `message_expiration_enabled` - {actor} set the message expiration to 3 hours
* `message_expiration_disabled` - {actor} disabled message expiration

View file

@ -51,6 +51,7 @@
`participantFlags` | int | v1 | | "In call" flags of the user's session making the request (only available with `in-call-flags` capability)
`readOnly` | int | v1 | | Read-only state for the current user (only available with `read-only-rooms` capability)
`listable` | int | v3 | | Listable scope for the room (only available with `listable-rooms` capability)
`messageExpiration` | int | v4 | | The message expiration time in seconds in this chat. Zero if disabled. (only available with `message-expiration` capability)
`count` | int | v1 | v2 | **Removed:** Count the users on the [Get list of participants in a conversation](participant.md#get-list-of-participants-in-a-conversation) endpoint
`numGuests` | int | v1 | v2 | **Removed:** Count the guests on the [Get list of participants in a conversation](participant.md#get-list-of-participants-in-a-conversation) endpoin
`lastPing` | int | v1 | | Timestamp of the user's session making the request
@ -336,6 +337,24 @@
+ `401 Unauthorized` When the participant is a guest
+ `404 Not Found` When the conversation could not be found for the participant
## Set message expiration
* Required capability: `message-expiration`
* Method: `POST`
* Endpoint: `/room/{token}/message-expiration`
* Data:
field | type | Description
---|---|---
`seconds` | int | The messages expiration in seconds. If is zero, messages will not be deleted automatically.
* Response:
- Status code:
+ `200 OK`
+ `400 Bad Request` Invalid value
+ `403 Forbidden` When the current user is not a moderator, owner or guest moderator
+ `404 Not Found` When the conversation could not be found for the participant
## Open a conversation
* Required capability: `listable-rooms`

View file

@ -0,0 +1,71 @@
<?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\BackgroundJob;
use OCA\Talk\Chat\ChatManager;
use OCA\Talk\Exceptions\RoomNotFoundException;
use OCA\Talk\Manager;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJob;
use OCP\BackgroundJob\IJobList;
use OCP\BackgroundJob\TimedJob;
class ExpireChatMessages extends TimedJob {
private IJobList $jobList;
private Manager $roomManager;
private ChatManager $chatManager;
public function __construct(ITimeFactory $timeFactory,
IJobList $jobList,
Manager $roomManager,
ChatManager $chatManager) {
parent::__construct($timeFactory);
$this->jobList = $jobList;
$this->roomManager = $roomManager;
$this->chatManager = $chatManager;
// Every 5 minutes
$this->setInterval(5 * 60);
$this->setTimeSensitivity(IJob::TIME_SENSITIVE);
}
/**
* @param array $argument
*/
protected function run($argument): void {
$this->chatManager->deleteExpiredMessages($argument['room_id']);
try {
$room = $this->roomManager->getRoomById($argument['room_id']);
if ($room->getMessageExpiration() === 0) {
// FIXME check if there are still messages to expire in the database
$this->jobList->remove(ExpireChatMessages::class, $argument);
}
} catch (RoomNotFoundException $e) {
$this->jobList->remove(ExpireChatMessages::class, $argument);
}
}
}

View file

@ -134,6 +134,10 @@ class Capabilities implements IPublicCapability {
'version' => $this->appManager->getAppVersion('spreed'),
];
if ($this->serverConfig->getAppValue('core', 'backgroundjobs_mode', 'ajax') === 'cron') {
$capabilities['features'][] = 'message-expiration';
}
if ($this->commentsManager->supportReactions()) {
$capabilities['features'][] = 'reactions';
}

View file

@ -24,10 +24,12 @@ declare(strict_types=1);
namespace OCA\Talk\Chat;
use DateInterval;
use OC\Memcache\ArrayCache;
use OC\Memcache\NullCache;
use OCA\Talk\Events\ChatEvent;
use OCA\Talk\Events\ChatParticipantEvent;
use OCA\Talk\Manager;
use OCA\Talk\Model\Attendee;
use OCA\Talk\Participant;
use OCA\Talk\Room;
@ -84,6 +86,7 @@ class ChatManager {
private IDBConnection $connection;
private INotificationManager $notificationManager;
private IManager $shareManager;
private Manager $manager;
private RoomShareProvider $shareProvider;
private ParticipantService $participantService;
private PollService $pollService;
@ -98,6 +101,7 @@ class ChatManager {
IDBConnection $connection,
INotificationManager $notificationManager,
IManager $shareManager,
Manager $manager,
RoomShareProvider $shareProvider,
ParticipantService $participantService,
PollService $pollService,
@ -110,6 +114,7 @@ class ChatManager {
$this->connection = $connection;
$this->notificationManager = $notificationManager;
$this->shareManager = $shareManager;
$this->manager = $manager;
$this->shareProvider = $shareProvider;
$this->participantService = $participantService;
$this->pollService = $pollService;
@ -258,6 +263,7 @@ class ChatManager {
if ($referenceId !== '') {
$comment->setReferenceId($referenceId);
}
$this->setMessageExpiration($chat, $comment);
$event = new ChatParticipantEvent($chat, $comment, $participant, $silent);
$this->dispatcher->dispatch(self::EVENT_BEFORE_MESSAGE_SEND, $event);
@ -303,6 +309,17 @@ class ChatManager {
return $comment;
}
private function setMessageExpiration(Room $room, IComment $comment): void {
$messageExpiration = $room->getMessageExpiration();
if (!$messageExpiration) {
return;
}
$dateTime = $this->timeFactory->getDateTime();
$dateTime->add(DateInterval::createFromDateString($messageExpiration . ' seconds'));
$comment->setExpireDate($dateTime);
}
/**
* @param Room $room
* @param Participant $participant
@ -693,4 +710,8 @@ class ChatManager {
}
return false;
}
public function deleteExpiredMessages(int $roomId): void {
$this->commentsManager->deleteMessageExpiredAtObject('chat', (string) $roomId);
}
}

View file

@ -456,6 +456,34 @@ class SystemMessage {
if ($currentUserIsActor) {
$parsedMessage = $this->l->t('You deleted a reaction');
}
} elseif ($message === 'message_expiration_enabled') {
$weeks = $parameters['seconds'] > (86400 * 7) ? (int) round($parameters['seconds'] / (86400 * 7)) : 0;
$days = $parameters['seconds'] > 86400 ? (int) round($parameters['seconds'] / 86400) : 0;
$hours = $parameters['seconds'] ? (int) round($parameters['seconds'] / 3600) : 0;
$parsedParameters['seconds'] = $parameters['seconds'];
if ($currentUserIsActor) {
if ($weeks > 0) {
$parsedMessage = $this->l->n('You set the message expiration to %n week', 'You set the message expiration to %n weeks', $weeks);
} elseif ($days > 0) {
$parsedMessage = $this->l->n('You set the message expiration to %n day', 'You set the message expiration to %n days', $days);
} else {
$parsedMessage = $this->l->n('You set the message expiration to %n hour', 'You set the message expiration to %n hours', $hours);
}
} else {
if ($weeks > 0) {
$parsedMessage = $this->l->n('{actor} set the message expiration to %n week', '{actor} set the message expiration to %n weeks', $weeks);
} elseif ($days > 0) {
$parsedMessage = $this->l->n('{actor} set the message expiration to %n day', '{actor} set the message expiration to %n days', $days);
} else {
$parsedMessage = $this->l->n('{actor} set the message expiration to %n hour', '{actor} set the message expiration to %n hours', $hours);
}
}
} elseif ($message === 'message_expiration_disabled') {
$parsedMessage = $this->l->t('{actor} disabled message expiration');
if ($currentUserIsActor) {
$parsedMessage = $this->l->t('You disabled message expiration');
}
} elseif ($message === 'history_cleared') {
$parsedMessage = $this->l->t('{actor} cleared the history of the conversation');
if ($currentUserIsActor) {

View file

@ -400,6 +400,7 @@ class RoomController extends AEnvironmentAwareController {
'lastCommonReadMessage' => 0,
'listable' => Room::LISTABLE_NONE,
'callFlag' => Participant::FLAG_DISCONNECTED,
'messageExpiration' => 0,
];
$lastActivity = $room->getLastActivity();
@ -466,6 +467,7 @@ class RoomController extends AEnvironmentAwareController {
'defaultPermissions' => $room->getDefaultPermissions(),
'description' => $room->getDescription(),
'listable' => $room->getListable(),
'messageExpiration' => $room->getMessageExpiration(),
]);
if ($currentParticipant->getAttendee()->getReadPrivacy() === Participant::PRIVACY_PUBLIC) {
@ -1706,4 +1708,16 @@ class RoomController extends AEnvironmentAwareController {
}
return new DataResponse();
}
/**
* @PublicPage
* @RequireModeratorParticipant
*/
public function setMessageExpiration(int $seconds): DataResponse {
if ($seconds < 0) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
$this->roomService->setMessageExpiration($this->room, $this->getParticipant(), $seconds);
return new DataResponse();
}
}

View file

@ -165,6 +165,7 @@ class Manager {
(int) $row['type'],
(int) $row['read_only'],
(int) $row['listable'],
(int) $row['message_expiration'],
(int) $row['lobby_state'],
(int) $row['sip_enabled'],
$assignedSignalingServer,

View file

@ -0,0 +1,56 @@
<?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\Migration;
use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
class Version15000Date20220506005058 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
$table = $schema->getTable('talk_rooms');
if (!$table->hasColumn('message_expiration')) {
$table->addColumn('message_expiration', Types::INTEGER, [
'default' => 0,
]);
return $schema;
}
return null;
}
}

View file

@ -51,6 +51,7 @@ class SelectHelper {
->addSelect($alias . 'object_type')
->addSelect($alias . 'object_id')
->addSelect($alias . 'listable')
->addSelect($alias . 'message_expiration')
->addSelect($alias . 'remote_server')
->addSelect($alias . 'remote_token')
->selectAlias($alias . 'id', 'r_id');

View file

@ -147,6 +147,8 @@ class Room {
public const EVENT_BEFORE_SESSION_LEAVE_CALL = self::class . '::preSessionLeaveCall';
public const EVENT_AFTER_SESSION_LEAVE_CALL = self::class . '::postSessionLeaveCall';
public const EVENT_BEFORE_SIGNALING_PROPERTIES = self::class . '::beforeSignalingProperties';
public const EVENT_BEFORE_SET_MESSAGE_EXPIRATION = self::class . '::beforeSetMessageExpiration';
public const EVENT_AFTER_SET_MESSAGE_EXPIRATION = self::class . '::afterSetMessageExpiration';
public const DESCRIPTION_MAXIMUM_LENGTH = 500;
@ -160,6 +162,7 @@ class Room {
private int $type;
private int $readOnly;
private int $listable;
private int $messageExpiration;
private int $lobbyState;
private int $sipEnabled;
private ?int $assignedSignalingServer;
@ -193,6 +196,7 @@ class Room {
int $type,
int $readOnly,
int $listable,
int $messageExpiration,
int $lobbyState,
int $sipEnabled,
?int $assignedSignalingServer,
@ -222,6 +226,7 @@ class Room {
$this->type = $type;
$this->readOnly = $readOnly;
$this->listable = $listable;
$this->messageExpiration = $messageExpiration;
$this->lobbyState = $lobbyState;
$this->sipEnabled = $sipEnabled;
$this->assignedSignalingServer = $assignedSignalingServer;
@ -283,6 +288,14 @@ class Room {
$this->listable = $newState;
}
public function getMessageExpiration(): int {
return $this->messageExpiration;
}
public function setMessageExpiration(int $messageExpiration): void {
$this->messageExpiration = $messageExpiration;
}
public function getLobbyState(): int {
$this->validateTimer();
return $this->lobbyState;

View file

@ -24,6 +24,8 @@ declare(strict_types=1);
namespace OCA\Talk\Service;
use InvalidArgumentException;
use OCA\Talk\BackgroundJob\ExpireChatMessages;
use OCA\Talk\Chat\ChatManager;
use OCA\Talk\Events\ModifyLobbyEvent;
use OCA\Talk\Events\ModifyRoomEvent;
use OCA\Talk\Events\VerifyRoomPasswordEvent;
@ -33,6 +35,8 @@ use OCA\Talk\Model\Attendee;
use OCA\Talk\Participant;
use OCA\Talk\Room;
use OCA\Talk\Webinary;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\HintException;
@ -44,24 +48,33 @@ use OCP\Share\IManager as IShareManager;
class RoomService {
protected Manager $manager;
protected ChatManager $chatManager;
protected ParticipantService $participantService;
protected IDBConnection $db;
protected ITimeFactory $timeFactory;
protected IShareManager $shareManager;
protected IHasher $hasher;
protected IEventDispatcher $dispatcher;
protected IJobList $jobList;
public function __construct(Manager $manager,
ChatManager $chatManager,
ParticipantService $participantService,
IDBConnection $db,
ITimeFactory $timeFactory,
IShareManager $shareManager,
IHasher $hasher,
IEventDispatcher $dispatcher) {
IEventDispatcher $dispatcher,
IJobList $jobList) {
$this->manager = $manager;
$this->chatManager = $chatManager;
$this->participantService = $participantService;
$this->db = $db;
$this->timeFactory = $timeFactory;
$this->shareManager = $shareManager;
$this->hasher = $hasher;
$this->dispatcher = $dispatcher;
$this->jobList = $jobList;
}
/**
@ -524,4 +537,38 @@ class RoomService {
'url' => '',
];
}
public function setMessageExpiration(Room $room, Participant $participant, int $seconds): void {
$event = new ModifyRoomEvent($room, 'messageExpiration', $seconds, null, $participant);
$this->dispatcher->dispatch(Room::EVENT_BEFORE_SET_MESSAGE_EXPIRATION, $event);
$update = $this->db->getQueryBuilder();
$update->update('talk_rooms')
->set('message_expiration', $update->createNamedParameter($seconds, IQueryBuilder::PARAM_INT))
->where($update->expr()->eq('id', $update->createNamedParameter($room->getId(), IQueryBuilder::PARAM_INT)));
$update->executeStatement();
$room->setMessageExpiration($seconds);
if ($seconds > 0) {
$this->jobList->add(ExpireChatMessages::class, ['room_id' => $room->getId()]);
$this->addMessageExpirationSystemMessage($room, $participant, $seconds, 'message_expiration_enabled');
} else {
$this->addMessageExpirationSystemMessage($room, $participant, $seconds, 'message_expiration_disabled');
}
$this->dispatcher->dispatch(Room::EVENT_AFTER_SET_MESSAGE_EXPIRATION, $event);
}
private function addMessageExpirationSystemMessage(Room $room, Participant $participant, int $seconds, string $message): void {
$this->chatManager->addSystemMessage(
$room,
$participant->getAttendee()->getActorType(),
$participant->getAttendee()->getActorId(),
json_encode([
'message' => $message,
'parameters' => ['seconds' => $seconds]
]),
$this->timeFactory->getDateTime(),
false
);
}
}

View file

@ -339,6 +339,9 @@ class FeatureContext implements Context, SnippetAcceptingContext {
if (isset($expectedRoom['unreadMentionDirect'])) {
$data['unreadMentionDirect'] = (int) $room['unreadMentionDirect'];
}
if (isset($expectedRoom['messageExpiration'])) {
$data['messageExpiration'] = (int) $room['messageExpiration'];
}
if (isset($expectedRoom['participants'])) {
throw new \Exception('participants key needs to be checked via participants endpoint');
}
@ -2567,6 +2570,38 @@ class FeatureContext implements Context, SnippetAcceptingContext {
Assert::assertCount(count($expected), $result, 'Reaction count does not match');
}
/**
* @Given user :user set the message expiration to :messageExpiration of room :identifier with :statusCode (:apiVersion)
*/
public function userSetTheMessageExpirationToXWithStatusCode(string $user, int $messageExpiration, string $identifier, int $statusCode, string $apiVersion = 'v4'): void {
$this->setCurrentUser($user);
$this->sendRequest('POST', '/apps/spreed/api/' . $apiVersion . '/room/' . self::$identifierToToken[$identifier] . '/message-expiration', [
'seconds' => $messageExpiration,
]);
$this->assertStatusCode($this->response, $statusCode);
}
/**
* @When wait for :seconds seconds
*/
public function waitForXSeconds($seconds): void {
sleep($seconds);
}
/**
* @When apply message expiration job to room :identifier
*/
public function applyMessageExpirationJobToRoom($identifier): void {
$currentUser = $this->currentUser;
$this->setCurrentUser('admin');
$this->sendRequest('GET', '/apps/spreedcheats/get_message_expiration_job/' . self::$identifierToToken[$identifier]);
$response = $this->getDataFromResponse($this->response);
Assert::assertIsArray($response, 'Room ' . $identifier . 'not found');
Assert::assertArrayHasKey('id', $response, 'Job not found by identifier "' . $identifier . '"');
$this->runOcc(['background-job:execute', $response['id']]);
$this->setCurrentUser($currentUser);
}
/*
* Requests
*/

View file

@ -0,0 +1,25 @@
Feature: room/message-expiration
Background:
Given user "participant1" exists
Given user "participant2" exists
Given user "participant3" exists
Scenario: Enable message expiration and check after expire
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" set the message expiration to -1 of room "room" with 400 (v4)
And user "participant2" set the message expiration to 3 of room "room" with 403 (v4)
And user "participant3" set the message expiration to 3 of room "room" with 404 (v4)
And user "participant1" set the message expiration to 3 of room "room" with 200 (v4)
And user "participant1" sends message "Message 2" to room "room" with 201
Then user "participant1" is participant of the following rooms (v4)
| id | type | messageExpiration |
| room | 3 | 3 |
And wait for 3 seconds
And apply message expiration job to room "room"
Then user "participant1" sees the following messages in room "room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage |
| room | users | participant1 | participant1-displayname | Message 1 | [] | |

View file

@ -26,5 +26,6 @@ declare(strict_types=1);
return [
'ocs' => [
['name' => 'Api#resetSpreed', 'url' => '/', 'verb' => 'DELETE'],
['name' => 'Api#getMessageExpirationJob', 'url' => '/get_message_expiration_job/{token}', 'verb' => 'GET'],
],
];

View file

@ -25,6 +25,8 @@ declare(strict_types=1);
namespace OCA\SpreedCheats\Controller;
use OCA\Talk\BackgroundJob\ExpireChatMessages;
use OCP\AppFramework\Http;
use OCP\AppFramework\OCSController;
use OCP\AppFramework\Http\DataResponse;
use OCP\IDBConnection;
@ -102,4 +104,40 @@ class ApiController extends OCSController {
return new DataResponse();
}
/**
* @NoCSRFRequired
*
* @return DataResponse
*/
public function getMessageExpirationJob($token): DataResponse {
$roomId = $this->getRoomIdByToken($token);
if (!$roomId) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
$query = $this->db->getQueryBuilder();
$query->select('id')
->from('jobs')
->where(
$query->expr()->andX(
$query->expr()->eq('class', $query->createNamedParameter(ExpireChatMessages::class)),
$query->expr()->eq('argument', $query->createNamedParameter(json_encode(['room_id' => (int) $roomId])))
)
);
$result = $query->executeQuery();
$job = $result->fetchOne();
if ($job) {
return new DataResponse(['id' => (int) $job]);
}
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
private function getRoomIdByToken(string $token): ?string {
$query = $this->db->getQueryBuilder();
$query->select('id')
->from('talk_rooms')
->where($query->expr()->eq('token', $query->createNamedParameter($token)));
$result = $query->executeQuery();
return $result->fetchOne();
}
}

View file

@ -59,7 +59,7 @@ class CapabilitiesTest extends TestCase {
$this->commentsManager = $this->createMock(CommentsManager::class);
$this->userSession = $this->createMock(IUserSession::class);
$this->appManager = $this->createMock(IAppManager::class);
$this->commentsManager->expects($this->any())
->method('supportReactions')
->willReturn(true);
@ -121,6 +121,7 @@ class CapabilitiesTest extends TestCase {
'silent-send',
'silent-call',
'send-call-notification',
'message-expiration',
'reactions',
];
}
@ -148,6 +149,7 @@ class CapabilitiesTest extends TestCase {
['spreed', 'max-gif-size', '3145728', '200000'],
['spreed', 'start_calls', Room::START_CALL_EVERYONE, Room::START_CALL_EVERYONE],
['spreed', 'session-ping-limit', '200', '200'],
['core', 'backgroundjobs_mode', 'ajax', 'cron'],
]);
$this->assertInstanceOf(IPublicCapability::class, $capabilities);
@ -237,6 +239,7 @@ class CapabilitiesTest extends TestCase {
['spreed', 'max-gif-size', '3145728', '200000'],
['spreed', 'start_calls', Room::START_CALL_EVERYONE, Room::START_CALL_NOONE],
['spreed', 'session-ping-limit', '200', '50'],
['core', 'backgroundjobs_mode', 'ajax', 'cron'],
]);
$this->assertInstanceOf(IPublicCapability::class, $capabilities);

View file

@ -27,6 +27,7 @@ namespace OCA\Talk\Tests\php\Chat;
use OCA\Talk\Chat\ChatManager;
use OCA\Talk\Chat\CommentsManager;
use OCA\Talk\Chat\Notifier;
use OCA\Talk\Manager;
use OCA\Talk\Model\Attendee;
use OCA\Talk\Model\AttendeeMapper;
use OCA\Talk\Participant;
@ -61,6 +62,8 @@ class ChatManagerTest extends TestCase {
protected $notificationManager;
/** @var IManager|MockObject */
protected $shareManager;
/** @var Manager|MockObject */
protected $manager;
/** @var RoomShareProvider|MockObject */
protected $shareProvider;
/** @var ParticipantService|MockObject */
@ -82,6 +85,7 @@ class ChatManagerTest extends TestCase {
$this->dispatcher = $this->createMock(IEventDispatcher::class);
$this->notificationManager = $this->createMock(INotificationManager::class);
$this->shareManager = $this->createMock(IManager::class);
$this->manager = $this->createMock(Manager::class);
$this->shareProvider = $this->createMock(RoomShareProvider::class);
$this->participantService = $this->createMock(ParticipantService::class);
$this->pollService = $this->createMock(PollService::class);
@ -96,6 +100,7 @@ class ChatManagerTest extends TestCase {
\OC::$server->getDatabaseConnection(),
$this->notificationManager,
$this->shareManager,
$this->manager,
$this->shareProvider,
$this->participantService,
$this->pollService,
@ -121,6 +126,7 @@ class ChatManagerTest extends TestCase {
\OC::$server->getDatabaseConnection(),
$this->notificationManager,
$this->shareManager,
$this->manager,
$this->shareProvider,
$this->participantService,
$this->pollService,
@ -139,6 +145,7 @@ class ChatManagerTest extends TestCase {
\OC::$server->getDatabaseConnection(),
$this->notificationManager,
$this->shareManager,
$this->manager,
$this->shareProvider,
$this->participantService,
$this->pollService,

View file

@ -25,6 +25,7 @@ namespace OCA\Talk\Tests\php\Service;
use InvalidArgumentException;
use OC\EventDispatcher\EventDispatcher;
use OCA\Talk\Chat\ChatManager;
use OCA\Talk\Events\VerifyRoomPasswordEvent;
use OCA\Talk\Exceptions\RoomNotFoundException;
use OCA\Talk\Manager;
@ -35,6 +36,7 @@ use OCA\Talk\Service\ParticipantService;
use OCA\Talk\Service\RoomService;
use OCA\Talk\Webinary;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IDBConnection;
use OCP\IUser;
@ -60,23 +62,30 @@ class RoomServiceTest extends TestCase {
/** @var IEventDispatcher|MockObject */
protected $dispatcher;
private ?RoomService $service = null;
/** @var IJobList|MockObject */
private IJobList $jobList;
public function setUp(): void {
parent::setUp();
$this->manager = $this->createMock(Manager::class);
$this->chatManager = $this->createMock(ChatManager::class);
$this->participantService = $this->createMock(ParticipantService::class);
$this->timeFactory = $this->createMock(ITimeFactory::class);
$this->shareManager = $this->createMock(IShareManager::class);
$this->hasher = $this->createMock(IHasher::class);
$this->dispatcher = $this->createMock(IEventDispatcher::class);
$this->jobList = $this->createMock(IJobList::class);
$this->service = new RoomService(
$this->manager,
$this->chatManager,
$this->participantService,
\OC::$server->get(IDBConnection::class),
$this->timeFactory,
$this->shareManager,
$this->hasher,
$this->dispatcher
$this->dispatcher,
$this->jobList
);
}
@ -335,11 +344,14 @@ class RoomServiceTest extends TestCase {
$service = new RoomService(
$this->manager,
$this->chatManager,
$this->participantService,
\OC::$server->get(IDBConnection::class),
$this->timeFactory,
$this->shareManager,
$this->hasher,
$dispatcher
$dispatcher,
$this->jobList
);
$room = new Room(
@ -352,6 +364,7 @@ class RoomServiceTest extends TestCase {
Room::TYPE_PUBLIC,
Room::READ_WRITE,
Room::LISTABLE_NONE,
0,
Webinary::LOBBY_NONE,
0,
null,

View file

@ -23,6 +23,7 @@
namespace OCA\Talk\Tests\php\Signaling;
use OCA\Talk\AppInfo\Application;
use OCA\Talk\Chat\ChatManager;
use OCA\Talk\Chat\CommentsManager;
use OCA\Talk\Config;
use OCA\Talk\Events\SignalingRoomPropertiesEvent;
@ -39,6 +40,7 @@ use OCA\Talk\TalkSession;
use OCA\Talk\Webinary;
use OCP\App\IAppManager;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Http\Client\IClientService;
use OCP\IGroupManager;
@ -87,6 +89,8 @@ class BackendNotifierTest extends TestCase {
/** @var IURLGenerator|MockObject */
private $urlGenerator;
private ?\OCA\Talk\Tests\php\Signaling\CustomBackendNotifier $controller = null;
/** @var null|ChatManager|MockObject */
private ?ChatManager $chatManager = null;
private ?Manager $manager = null;
private ?RoomService $roomService = null;
@ -98,6 +102,8 @@ class BackendNotifierTest extends TestCase {
protected Application $app;
protected BackendNotifier $originalBackendNotifier;
private ?IEventDispatcher $dispatcher = null;
/** @var IJobList|MockObject */
private IJobList $jobList;
public function setUp(): void {
parent::setUp();
@ -150,14 +156,19 @@ class BackendNotifierTest extends TestCase {
$this->createMock(IHasher::class),
$this->createMock(IL10N::class)
);
$this->chatManager = $this->createMock(ChatManager::class);
$this->jobList = $this->createMock(IJobList::class);
$this->roomService = new RoomService(
$this->manager,
$this->chatManager,
$this->participantService,
$dbConnection,
$this->timeFactory,
$this->createMock(IManager::class),
$this->createMock(IHasher::class),
$this->dispatcher
$this->dispatcher,
$this->jobList
);
}