mirror of
https://github.com/nextcloud/spreed.git
synced 2025-12-18 05:20:50 +01:00
Merge pull request #7327 from nextcloud/feature/api-time-to-live
Implement time to live
This commit is contained in:
commit
332352f40a
24 changed files with 425 additions and 13 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
10
composer.lock
generated
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
71
lib/BackgroundJob/ExpireChatMessages.php
Normal file
71
lib/BackgroundJob/ExpireChatMessages.php
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
56
lib/Migration/Version15000Date20220506005058.php
Normal file
56
lib/Migration/Version15000Date20220506005058.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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');
|
||||
|
|
|
|||
13
lib/Room.php
13
lib/Room.php
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
25
tests/integration/features/chat/message-expiration.feature
Normal file
25
tests/integration/features/chat/message-expiration.feature
Normal 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 | [] | |
|
||||
|
|
@ -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'],
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue