summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitor Mattos <vitor@php.rio>2022-12-07 22:45:57 -0300
committerVitor Mattos <vitor@php.rio>2022-12-09 17:02:08 -0300
commitdb88acf9beb04ab6bf1b7d423bcad0c5ad21c542 (patch)
tree37f1ed6fe23081b7132d51f03e1fab4431dac33f
parentedb7df03562c93fdfe65fe66b921498fb1b59968 (diff)
Toggle call recording status
Signed-off-by: Vitor Mattos <vitor@php.rio>
-rw-r--r--appinfo/routes/routesCallController.php4
-rw-r--r--docs/call.md28
-rw-r--r--lib/Controller/CallController.php26
-rw-r--r--lib/Manager.php3
-rw-r--r--lib/Middleware/InjectionMiddleware.php14
-rw-r--r--lib/Migration/Version16000Date20221208013745.php55
-rw-r--r--lib/Model/SelectHelper.php1
-rw-r--r--lib/Room.php15
-rw-r--r--lib/Service/RoomService.php36
-rw-r--r--tests/php/Service/RoomServiceTest.php1
10 files changed, 181 insertions, 2 deletions
diff --git a/appinfo/routes/routesCallController.php b/appinfo/routes/routesCallController.php
index 83632bc9d..11a3f6d62 100644
--- a/appinfo/routes/routesCallController.php
+++ b/appinfo/routes/routesCallController.php
@@ -40,5 +40,9 @@ return [
['name' => 'Call#updateCallFlags', 'url' => '/api/{apiVersion}/call/{token}', 'verb' => 'PUT', 'requirements' => $requirements],
/** @see \OCA\Talk\Controller\CallController::leaveCall() */
['name' => 'Call#leaveCall', 'url' => '/api/{apiVersion}/call/{token}', 'verb' => 'DELETE', 'requirements' => $requirements],
+ /** @see \OCA\Talk\Controller\CallController::startRecording() */
+ ['name' => 'Call#startRecording', 'url' => '/api/{apiVersion}/call/{token}/recording', 'verb' => 'POST', 'requirements' => $requirementsWithToken],
+ /** @see \OCA\Talk\Controller\CallController::stopRecording() */
+ ['name' => 'Call#stopRecording', 'url' => '/api/{apiVersion}/call/{token}/recording', 'verb' => 'DELETE', 'requirements' => $requirementsWithToken],
],
];
diff --git a/docs/call.md b/docs/call.md
index f0a76c8a8..60781f11e 100644
--- a/docs/call.md
+++ b/docs/call.md
@@ -102,3 +102,31 @@
+ `404 Not Found` When the conversation could not be found for the participant
+ `404 Not Found` When the user did not join the conversation before
+ `412 Precondition Failed` When the lobby is active and the user is not a moderator
+
+## Start call recording
+
+* Method: `POST`
+* Endpoint: `/call/{token}/recording`
+* Data:
+
+| Field | Type | Description |
+| ------ | ---- | ----------------------------------------------------- |
+| status | int | Type of call recording when 1 is video and 2 is audio |
+
+* Response:
+ - Status code:
+ + `200 OK`
+ + `400 Bad Request` When the status to start is invalid
+ + `400 Bad Request` The haven't the capability `recording-v1`
+ + `412 Precondition Failed` When the lobby is active and the user is not a moderator
+
+## Stop call recording
+
+* Method: `DELETE`
+* Endpoint: `/call/{token}/recording`
+
+* Response:
+ - Status code:
+ + `200 OK`
+ + `400 Bad Request` The haven't the capability `recording-v1`
+ + `412 Precondition Failed` When the lobby is active and the user is not a moderator
diff --git a/lib/Controller/CallController.php b/lib/Controller/CallController.php
index 5be4ae148..4cff9abe3 100644
--- a/lib/Controller/CallController.php
+++ b/lib/Controller/CallController.php
@@ -200,4 +200,30 @@ class CallController extends AEnvironmentAwareController {
return new DataResponse();
}
+
+ /**
+ * @PublicPage
+ * @RequireCallEnabled
+ * @RequireParticipant
+ * @RequireModeratorOrNoLobby
+ * @RequireCallRecording
+ */
+ public function startRecording(int $status): DataResponse {
+ if (!$this->roomService->startRecording($this->room, $status)) {
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+ return new DataResponse();
+ }
+
+ /**
+ * @PublicPage
+ * @RequireCallEnabled
+ * @RequireParticipant
+ * @RequireModeratorOrNoLobby
+ * @RequireCallRecording
+ */
+ public function stopRecording(): DataResponse {
+ $this->roomService->stopRecording($this->room);
+ return new DataResponse();
+ }
}
diff --git a/lib/Manager.php b/lib/Manager.php
index e038b4485..90f2ce8aa 100644
--- a/lib/Manager.php
+++ b/lib/Manager.php
@@ -187,7 +187,8 @@ class Manager {
(string) $row['object_type'],
(string) $row['object_id'],
(int) $row['breakout_room_mode'],
- (int) $row['breakout_room_status']
+ (int) $row['breakout_room_status'],
+ (int) $row['call_recording']
);
}
diff --git a/lib/Middleware/InjectionMiddleware.php b/lib/Middleware/InjectionMiddleware.php
index fc8e4bcad..cc73c66c2 100644
--- a/lib/Middleware/InjectionMiddleware.php
+++ b/lib/Middleware/InjectionMiddleware.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace OCA\Talk\Middleware;
+use OCA\Talk\Config;
use OCA\Talk\Controller\AEnvironmentAwareController;
use OCA\Talk\Exceptions\ParticipantNotFoundException;
use OCA\Talk\Exceptions\PermissionsException;
@@ -55,6 +56,7 @@ class InjectionMiddleware extends Middleware {
protected TalkSession $talkSession;
protected Manager $manager;
protected IThrottler $throttler;
+ protected Config $config;
protected ?string $userId;
public function __construct(IRequest $request,
@@ -63,6 +65,7 @@ class InjectionMiddleware extends Middleware {
TalkSession $talkSession,
Manager $manager,
IThrottler $throttler,
+ Config $config,
?string $userId) {
$this->request = $request;
$this->reflector = $reflector;
@@ -70,6 +73,7 @@ class InjectionMiddleware extends Middleware {
$this->talkSession = $talkSession;
$this->manager = $manager;
$this->throttler = $throttler;
+ $this->config = $config;
$this->userId = $userId;
}
@@ -118,6 +122,10 @@ class InjectionMiddleware extends Middleware {
$this->checkLobbyState($controller);
}
+ if ($this->reflector->hasAnnotation('RequireCallRecording')) {
+ $this->checkCallRecording($controller);
+ }
+
$requiredPermissions = $this->reflector->getAnnotationParameter('RequirePermissions', 'permissions');
if ($requiredPermissions) {
$this->checkPermissions($controller, $requiredPermissions);
@@ -247,6 +255,12 @@ class InjectionMiddleware extends Middleware {
}
}
+ protected function checkCallRecording(AEnvironmentAwareController $controller): void {
+ if (!$this->config->isCallRecordingEnabled()) {
+ throw new ReadOnlyException();
+ }
+ }
+
/**
* @param Controller $controller
* @param string $methodName
diff --git a/lib/Migration/Version16000Date20221208013745.php b/lib/Migration/Version16000Date20221208013745.php
new file mode 100644
index 000000000..45a9ccfc4
--- /dev/null
+++ b/lib/Migration/Version16000Date20221208013745.php
@@ -0,0 +1,55 @@
+<?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 Version16000Date20221208013745 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('call_recording')) {
+ $table->addColumn('call_recording', Types::INTEGER, [
+ 'default' => 0,
+ ]);
+ return $schema;
+ }
+ return null;
+ }
+}
diff --git a/lib/Model/SelectHelper.php b/lib/Model/SelectHelper.php
index 755432367..611d86753 100644
--- a/lib/Model/SelectHelper.php
+++ b/lib/Model/SelectHelper.php
@@ -57,6 +57,7 @@ class SelectHelper {
->addSelect($alias . 'remote_token')
->addSelect($alias . 'breakout_room_mode')
->addSelect($alias . 'breakout_room_status')
+ ->addSelect($alias . 'call_recording')
->selectAlias($alias . 'id', 'r_id');
}
diff --git a/lib/Room.php b/lib/Room.php
index df5d88143..7725c4c0b 100644
--- a/lib/Room.php
+++ b/lib/Room.php
@@ -147,6 +147,8 @@ class Room {
public const EVENT_AFTER_SET_BREAKOUT_ROOM_MODE = self::class . '::afterSetBreakoutRoomMode';
public const EVENT_BEFORE_SET_BREAKOUT_ROOM_STATUS = self::class . '::beforeSetBreakoutRoomStatus';
public const EVENT_AFTER_SET_BREAKOUT_ROOM_STATUS = self::class . '::afterSetBreakoutRoomStatus';
+ public const EVENT_BEFORE_SET_CALL_RECORDING = self::class . '::beforeSetCallRecording';
+ public const EVENT_AFTER_SET_CALL_RECORDING = self::class . '::afterSetCallRecording';
public const EVENT_BEFORE_AVATAR_SET = self::class . '::preSetAvatar';
public const EVENT_AFTER_AVATAR_SET = self::class . '::postSetAvatar';
@@ -185,6 +187,7 @@ class Room {
private string $objectId;
private int $breakoutRoomMode;
private int $breakoutRoomStatus;
+ private int $callRecording;
protected ?string $currentUser = null;
protected ?Participant $participant = null;
@@ -220,7 +223,8 @@ class Room {
string $objectType,
string $objectId,
int $breakoutRoomMode,
- int $breakoutRoomStatus) {
+ int $breakoutRoomStatus,
+ int $callRecording) {
$this->manager = $manager;
$this->db = $db;
$this->dispatcher = $dispatcher;
@@ -253,6 +257,7 @@ class Room {
$this->objectId = $objectId;
$this->breakoutRoomMode = $breakoutRoomMode;
$this->breakoutRoomStatus = $breakoutRoomStatus;
+ $this->callRecording = $callRecording;
}
public function getId(): int {
@@ -632,4 +637,12 @@ class Room {
public function setBreakoutRoomStatus(int $status): void {
$this->breakoutRoomStatus = $status;
}
+
+ public function getCallRecording(): int {
+ return $this->breakoutRoomStatus;
+ }
+
+ public function setCallRecording(int $status): void {
+ $this->callRecording = $status;
+ }
}
diff --git a/lib/Service/RoomService.php b/lib/Service/RoomService.php
index 08cb8ef2f..26b8eb185 100644
--- a/lib/Service/RoomService.php
+++ b/lib/Service/RoomService.php
@@ -362,6 +362,42 @@ class RoomService {
return true;
}
+ public function startRecording(Room $room, $status): bool {
+ if (!in_array($status, [1, 2])) {
+ return false;
+ }
+ return $this->setCallRecording($room, $status);
+ }
+
+ public function stopRecording(Room $room): bool {
+ return $this->setCallRecording($room);
+ }
+
+ /**
+ * Undocumented function
+ *
+ * @param Room $room
+ * @param integer $status 0 none|1 video|2 audio
+ */
+ public function setCallRecording(Room $room, int $status = 0): bool {
+ if (!in_array($status, [0, 1, 2])) {
+ return false;
+ }
+
+ $oldStatus = $room->getCallRecording();
+ $event = new ModifyRoomEvent($room, 'callRecording', $status, $oldStatus);
+ $this->dispatcher->dispatch(Room::EVENT_BEFORE_SET_CALL_RECORDING, $event);
+
+ $update = $this->db->getQueryBuilder();
+ $update->update('talk_rooms')
+ ->set('call_recording', $update->createNamedParameter($status, IQueryBuilder::PARAM_INT))
+ ->where($update->expr()->eq('id', $update->createNamedParameter($room->getId(), IQueryBuilder::PARAM_INT)));
+ $update->executeStatement();
+
+ $this->dispatcher->dispatch(Room::EVENT_AFTER_SET_CALL_RECORDING, $event);
+ return true;
+ }
+
/**
* @param Room $room
* @param int $newType Currently it is only allowed to change between `Room::TYPE_GROUP` and `Room::TYPE_PUBLIC`
diff --git a/tests/php/Service/RoomServiceTest.php b/tests/php/Service/RoomServiceTest.php
index d71502929..61798485f 100644
--- a/tests/php/Service/RoomServiceTest.php
+++ b/tests/php/Service/RoomServiceTest.php
@@ -386,6 +386,7 @@ class RoomServiceTest extends TestCase {
'',
'',
0,
+ 0,
0
);