diff --git a/lib/Service/RecordingService.php b/lib/Service/RecordingService.php index 0f70e3848aa..0a408bc35e7 100644 --- a/lib/Service/RecordingService.php +++ b/lib/Service/RecordingService.php @@ -20,6 +20,7 @@ use OCA\Talk\Recording\BackendNotifier; use OCA\Talk\Room; use OCA\Talk\Settings\UserPreference; +use OCP\Activity\IManager as IActivityManager; use OCP\AppFramework\Services\IAppConfig; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Constants; @@ -94,6 +95,7 @@ public function __construct( private readonly IUserManager $userManager, private readonly IEventDispatcher $eventDispatcher, private readonly ISecureRandom $secureRandom, + private readonly IActivityManager $activityManager, ) { } @@ -157,7 +159,10 @@ public function store(Room $room, string $owner, array $file): void { try { $recordingFolder = $this->getRecordingFolder($owner, $room->getToken()); - $fileNode = $recordingFolder->newFile($fileName, $resource); + $fileNode = $this->runAsActor( + $owner, + static fn (): File => $recordingFolder->newFile($fileName, $resource), + ); } catch (NoUserException) { throw new InvalidArgumentException('owner_invalid'); } catch (NotPermittedException) { @@ -431,9 +436,12 @@ public function storeTranscript(string $owner, string $roomToken, int $recording } try { - $fileNode = $recordingFolder->newFile( - $transcriptFileName, - $output . "\n\n$warning\n", + $fileNode = $this->runAsActor( + $owner, + static fn (): File => $recordingFolder->newFile( + $transcriptFileName, + $output . "\n\n$warning\n", + ), ); $this->systemTagMapper->assignGeneratedByAITag((string)$fileNode->getId(), 'files'); $this->notifyStoredTranscript($room, $participant, $fileNode, $aiTask); @@ -623,6 +631,37 @@ private function validateMimeTypeAndExtension(string $fileName, string $mimeType * @throws NoUserException */ private function getRecordingFolder(string $owner, string $token): Folder { + return $this->runAsActor( + $owner, + fn (): Folder => $this->getRecordingFolderInternal($owner, $token), + ); + } + + /** + * Run the callback with the activity actor set to the given user. + * + * Recordings are stored by a background job, outside of any session, so + * without this the folder and the file are attributed to nobody and the + * activity stream renders them as coming from a "remote account". + * + * @template T + * @param callable():T $callback + * @return T + */ + private function runAsActor(string $userId, callable $callback) { + $this->activityManager->setCurrentUserId($userId); + try { + return $callback(); + } finally { + $this->activityManager->setCurrentUserId(null); + } + } + + /** + * @throws NotPermittedException + * @throws NoUserException + */ + private function getRecordingFolderInternal(string $owner, string $token): Folder { $userFolder = $this->rootFolder->getUserFolder($owner); $recordingRootFolderName = $this->config->getRecordingFolder($owner); try {