diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Chat/SystemMessage/Listener.php | 4 | ||||
-rw-r--r-- | lib/Controller/RecordingController.php | 35 | ||||
-rw-r--r-- | lib/Notification/Notifier.php | 70 | ||||
-rw-r--r-- | lib/Service/RecordingService.php | 115 |
4 files changed, 217 insertions, 7 deletions
diff --git a/lib/Chat/SystemMessage/Listener.php b/lib/Chat/SystemMessage/Listener.php index fecc384eb..9e33a8aca 100644 --- a/lib/Chat/SystemMessage/Listener.php +++ b/lib/Chat/SystemMessage/Listener.php @@ -382,6 +382,10 @@ class Listener implements IEventListener { $listener = Server::get(self::class); $manager = Server::get(Manager::class); + $request = Server::get(IRequest::class); + if ($request->getParam('_route') === 'ocs.spreed.Recording.shareToChat') { + return; + } $room = $manager->getRoomByToken($share->getSharedWith()); $metaData = Server::get(IRequest::class)->getParam('talkMetaData') ?? ''; $metaData = json_decode($metaData, true); diff --git a/lib/Controller/RecordingController.php b/lib/Controller/RecordingController.php index 0948fe538..d5ed53fa0 100644 --- a/lib/Controller/RecordingController.php +++ b/lib/Controller/RecordingController.php @@ -100,4 +100,39 @@ class RecordingController extends AEnvironmentAwareController { } return new DataResponse(); } + + /** + * @NoAdminRequired + * @RequireModeratorParticipant + */ + public function notificationDismiss(int $timestamp): DataResponse { + try { + $this->recordingService->notificationDismiss( + $this->getRoom(), + $this->participant, + $timestamp + ); + } catch (InvalidArgumentException $e) { + return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST); + } + return new DataResponse(); + } + + /** + * @NoAdminRequired + * @RequireModeratorParticipant + */ + public function shareToChat(int $fileId, int $timestamp): DataResponse { + try { + $this->recordingService->shareToChat( + $this->getRoom(), + $this->participant, + $fileId, + $timestamp + ); + } catch (InvalidArgumentException $e) { + return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST); + } + return new DataResponse(); + } } diff --git a/lib/Notification/Notifier.php b/lib/Notification/Notifier.php index 46c6b7b77..b9e65147e 100644 --- a/lib/Notification/Notifier.php +++ b/lib/Notification/Notifier.php @@ -41,6 +41,7 @@ use OCA\Talk\Webinary; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Comments\ICommentsManager; use OCP\Comments\NotFoundException; +use OCP\Files\IRootFolder; use OCP\HintException; use OCP\IL10N; use OCP\IURLGenerator; @@ -69,6 +70,8 @@ class Notifier implements INotifier { protected INotificationManager $notificationManager; protected ICommentsManager $commentManager; protected MessageParser $messageParser; + protected IURLGenerator $urlGenerator; + protected IRootFolder $rootFolder; protected ITimeFactory $timeFactory; protected Definitions $definitions; protected AddressHandler $addressHandler; @@ -89,6 +92,8 @@ class Notifier implements INotifier { INotificationManager $notificationManager, CommentsManager $commentManager, MessageParser $messageParser, + IURLGenerator $urlGenerator, + IRootFolder $rootFolder, ITimeFactory $timeFactory, Definitions $definitions, AddressHandler $addressHandler) { @@ -103,6 +108,8 @@ class Notifier implements INotifier { $this->notificationManager = $notificationManager; $this->commentManager = $commentManager; $this->messageParser = $messageParser; + $this->urlGenerator = $urlGenerator; + $this->rootFolder = $rootFolder; $this->timeFactory = $timeFactory; $this->definitions = $definitions; $this->addressHandler = $addressHandler; @@ -248,6 +255,9 @@ class Notifier implements INotifier { ->setLink($this->url->linkToRouteAbsolute('spreed.Page.showCall', ['token' => $room->getToken()])); $subject = $notification->getSubject(); + if ($subject === 'record_file_stored') { + return $this->parseStoredRecording($notification, $room, $participant, $l); + } if ($subject === 'invitation') { return $this->parseInvitation($notification, $room, $l); } @@ -287,6 +297,66 @@ class Notifier implements INotifier { return $temp; } + private function parseStoredRecording( + INotification $notification, + Room $room, + Participant $participant, + IL10N $l + ): INotification { + $parameters = $notification->getSubjectParameters(); + try { + $userFolder = $this->rootFolder->getUserFolder($notification->getUser()); + /** @var \OCP\Files\File[] */ + $files = $userFolder->getById($parameters['objectId']); + $file = array_shift($files); + } catch (\Throwable $th) { + throw new AlreadyProcessedException(); + } + $shareAction = $notification->createAction() + ->setParsedLabel($l->t('Share to chat')) + ->setPrimary(true) + ->setLink( + $this->urlGenerator->linkToOCSRouteAbsolute( + 'spreed.Recording.shareToChat', + [ + 'apiVersion' => 'v1', + 'fileId' => $file->getId(), + 'timestamp' => $notification->getDateTime()->getTimestamp(), + 'token' => $room->getToken() + ] + ), + IAction::TYPE_POST + ); + $dismissAction = $notification->createAction() + ->setParsedLabel($l->t('Dismiss notification')) + ->setLink( + $this->urlGenerator->linkToOCSRouteAbsolute( + 'spreed.Recording.notificationDismiss', + [ + 'apiVersion' => 'v1', + 'token' => $room->getToken(), + 'timestamp' => $notification->getDateTime()->getTimestamp(), + ] + ), + IAction::TYPE_DELETE + ); + + $notification + ->setRichSubject( + $l->t('Recording for the call in {call} was uploaded.'), + [ + 'call' => [ + 'type' => 'call', + 'id' => $room->getId(), + 'name' => $room->getDisplayName($participant->getAttendee()->getActorId()), + 'call-type' => $this->getRoomType($room), + ], + ]) + ->addParsedAction($shareAction) + ->addParsedAction($dismissAction); + return $notification; + } + /** * @throws HintException */ diff --git a/lib/Service/RecordingService.php b/lib/Service/RecordingService.php index 408ebf066..2eaafb999 100644 --- a/lib/Service/RecordingService.php +++ b/lib/Service/RecordingService.php @@ -27,14 +27,23 @@ namespace OCA\Talk\Service; use InvalidArgumentException; use OC\User\NoUserException; +use OCA\Talk\Chat\ChatManager; use OCA\Talk\Config; use OCA\Talk\Exceptions\ParticipantNotFoundException; +use OCA\Talk\Manager; +use OCA\Talk\Participant; use OCA\Talk\Room; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\IMimeTypeDetector; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\Notification\IManager; +use OCP\Share\IManager as ShareManager; +use OCP\Share\IShare; +use Psr\Log\LoggerInterface; class RecordingService { public const DEFAULT_ALLOWED_RECORDING_FORMATS = [ @@ -44,11 +53,17 @@ class RecordingService { ]; public function __construct( - private IMimeTypeDetector $mimeTypeDetector, - private ParticipantService $participantService, - private IRootFolder $rootFolder, - private Config $config, - private RoomService $roomService + protected IMimeTypeDetector $mimeTypeDetector, + protected ParticipantService $participantService, + protected IRootFolder $rootFolder, + protected IManager $notificationManager, + protected Manager $roomManager, + protected ITimeFactory $timeFactory, + protected Config $config, + protected RoomService $roomService, + protected ShareManager $shareManager, + protected ChatManager $chatManager, + protected LoggerInterface $logger, ) { } @@ -80,14 +95,15 @@ class RecordingService { $this->validateFileFormat($fileName, $content); try { - $this->participantService->getParticipant($room, $owner); + $participant = $this->participantService->getParticipant($room, $owner); } catch (ParticipantNotFoundException $e) { throw new InvalidArgumentException('owner_participant'); } try { $recordingFolder = $this->getRecordingFolder($owner, $room->getToken()); - $recordingFolder->newFile($fileName, $content); + $file = $recordingFolder->newFile($fileName, $content); + $this->notifyStoredRecording($room, $participant, $file); } catch (NoUserException $e) { throw new InvalidArgumentException('owner_invalid'); } catch (NotPermittedException $e) { @@ -142,4 +158,89 @@ class RecordingService { } return $recordingFolder; } + + public function notifyStoredRecording(Room $room, Participant $participant, File $file): void { + $attendee = $participant->getAttendee(); + + $notification = $this->notificationManager->createNotification(); + + $notification + ->setApp('spreed') + ->setDateTime($this->timeFactory->getDateTime()) + ->setObject('chat', $room->getToken()) + ->setUser($attendee->getActorId()) + ->setSubject('record_file_stored', [ + 'objectId' => $file->getId(), + ]); + $this->notificationManager->notify($notification); + } + + public function notificationDismiss(Room $room, Participant $participant, int $timestamp): void { + $notification = $this->notificationManager->createNotification(); + $notification->setApp('spreed') + ->setObject('chat', $room->getToken()) + ->setSubject('record_file_stored') + ->setDateTime($this->timeFactory->getDateTime('@' . $timestamp)) + ->setUser($participant->getAttendee()->getActorId()); + $this->notificationManager->markProcessed($notification); + } + + private function getTypeOfShare(string $mimetype): string { + if (str_starts_with($mimetype, 'video/')) { + return 'record-video'; + } + return 'record-audio'; + } + + public function shareToChat(Room $room, Participant $participant, int $fileId, int $timestamp): void { + try { + $userFolder = $this->rootFolder->getUserFolder( + $participant->getAttendee()->getActorId() + ); + /** @var \OCP\Files\File[] */ + $files = $userFolder->getById($fileId); + $file = array_shift($files); + } catch (\Throwable $th) { + throw new InvalidArgumentException('file'); + } + + $creationDateTime = $this->timeFactory->getDateTime(); + + $share = $this->shareManager->newShare(); + $share->setNodeId($fileId) + ->setShareTime($creationDateTime) + ->setSharedBy($participant->getAttendee()->getActorId()) + ->setNode($file) + ->setShareType(IShare::TYPE_ROOM) + ->setSharedWith($room->getToken()) + ->setPermissions(\OCP\Constants::PERMISSION_READ); + + $share = $this->shareManager->createShare($share); + + $message = json_encode([ + 'message' => 'file_shared', + 'parameters' => [ + 'share' => $share->getId(), + 'metaData' => [ + 'mimeType' => $file->getMimeType(), + 'messageType' => $this->getTypeOfShare($file->getMimeType()), + ], + ], + ]); + + try { + $this->chatManager->addSystemMessage( + $room, + $participant->getAttendee()->getActorType(), + $participant->getAttendee()->getActorId(), + $message, + $creationDateTime, + true + ); + } catch (\Exception $e) { + $this->logger->error($e->getMessage(), ['exception' => $e]); + throw new InvalidArgumentException('system'); + } + $this->notificationDismiss($room, $participant, $timestamp); + } } |