refactor(TalkService): update TalkSession usage and improve share creation

Only 1 image share shows up now
-   Replace ParticipantSession with TalkSession and update constructor
-   Inject IUserSession to manage user context
-   Refactor setSessionOverwrite and clearSessionOverwrite to use reflection
-   Update share creation to switch context to talk-bot and support node-based sharing
-   Enhance error logging in share creation
This commit is contained in:
kyle
2026-06-13 23:53:03 -07:00
parent 4f0f2e3f81
commit 4aa779c51f
+62 -13
View File
@@ -13,14 +13,15 @@ use OCP\IDBConnection;
use OCP\IRequest; use OCP\IRequest;
use OCP\IURLGenerator; use OCP\IURLGenerator;
use OCP\IUserManager; use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Share\IManager as IShareManager; use OCP\Share\IManager as IShareManager;
use OCP\Share\IShare; use OCP\Share\IShare;
use OCA\Talk\Chat\ChatManager; use OCA\Talk\Chat\ChatManager;
use OCA\Talk\Manager as TalkManager; use OCA\Talk\Manager as TalkManager;
use OCA\Talk\Model\Attendee; use OCA\Talk\Model\Attendee;
use OCA\Talk\Model\AttendeeMapper; use OCA\Talk\Model\AttendeeMapper;
use OCA\Talk\Session\ParticipantSession;
use OCA\Talk\Service\ParticipantService; use OCA\Talk\Service\ParticipantService;
use OCA\Talk\TalkSession;
use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\DoesNotExistException;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@@ -42,7 +43,8 @@ class TalkService {
private IShareManager $shareManager; private IShareManager $shareManager;
private ParticipantService $participantService; private ParticipantService $participantService;
private ChatManager $chatManager; private ChatManager $chatManager;
private ParticipantSession $talkSession; private TalkSession $talkSession;
private IUserSession $userSession;
public function __construct( public function __construct(
IClientService $clientService, IClientService $clientService,
@@ -52,6 +54,7 @@ class TalkService {
IRequest $request, IRequest $request,
IURLGenerator $urlGenerator, IURLGenerator $urlGenerator,
IUserManager $userManager, IUserManager $userManager,
IUserSession $userSession,
LoggerInterface $logger, LoggerInterface $logger,
TalkManager $talkManager, TalkManager $talkManager,
ICrypto $crypto, ICrypto $crypto,
@@ -59,7 +62,7 @@ class TalkService {
IShareManager $shareManager, IShareManager $shareManager,
ParticipantService $participantService, ParticipantService $participantService,
ChatManager $chatManager, ChatManager $chatManager,
ParticipantSession $talkSession, TalkSession $talkSession,
) { ) {
$this->clientService = $clientService; $this->clientService = $clientService;
$this->config = $config; $this->config = $config;
@@ -68,6 +71,7 @@ class TalkService {
$this->request = $request; $this->request = $request;
$this->urlGenerator = $urlGenerator; $this->urlGenerator = $urlGenerator;
$this->userManager = $userManager; $this->userManager = $userManager;
$this->userSession = $userSession;
$this->logger = $logger; $this->logger = $logger;
$this->talkManager = $talkManager; $this->talkManager = $talkManager;
$this->crypto = $crypto; $this->crypto = $crypto;
@@ -163,14 +167,24 @@ class TalkService {
* Must be cleared after use to avoid leaking to other requests. * Must be cleared after use to avoid leaking to other requests.
*/ */
private function setSessionOverwrite(string $actorId): void { private function setSessionOverwrite(string $actorId): void {
$this->talkSession->set('talk-overwrite-actor-type', Attendee::ACTOR_USERS); $reflection = new \ReflectionObject($this->talkSession);
$this->talkSession->set('talk-overwrite-actor-id', $actorId); $property = $reflection->getProperty('session');
$property->setAccessible(true);
/** @var \OCP\ISession $session */
$session = $property->getValue($this->talkSession);
$session->set('talk-overwrite-actor-type', Attendee::ACTOR_USERS);
$session->set('talk-overwrite-actor-id', $actorId);
} }
private function clearSessionOverwrite(): void { private function clearSessionOverwrite(): void {
try { try {
$this->talkSession->remove('talk-overwrite-actor-type'); $reflection = new \ReflectionObject($this->talkSession);
$this->talkSession->remove('talk-overwrite-actor-id'); $property = $reflection->getProperty('session');
$property->setAccessible(true);
/** @var \OCP\ISession $session */
$session = $property->getValue($this->talkSession);
$session->remove('talk-overwrite-actor-type');
$session->remove('talk-overwrite-actor-id');
} catch (\Exception $e) { } catch (\Exception $e) {
// Session keys may not exist — ignore // Session keys may not exist — ignore
} }
@@ -1277,6 +1291,7 @@ class TalkService {
'filename' => $safeFilename, 'filename' => $safeFilename,
'fileCachePath' => $fileCachePath, 'fileCachePath' => $fileCachePath,
'actualSize' => $actualSize, 'actualSize' => $actualSize,
'node' => $node,
]; ];
} catch (\Exception $e) { } catch (\Exception $e) {
$this->logger->error('Failed to build rich object (Exception): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine(), ['app' => self::APP_ID]); $this->logger->error('Failed to build rich object (Exception): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine(), ['app' => self::APP_ID]);
@@ -1447,15 +1462,42 @@ class TalkService {
// active when the ShareCreatedEvent fires. This prevents the guest // active when the ShareCreatedEvent fires. This prevents the guest
// message from being posted alongside the bot's message. // message from being posted alongside the bot's message.
if ($richObject !== null && $richObject['fileId'] !== null) { if ($richObject !== null && $richObject['fileId'] !== null) {
$bot = $this->userManager->get('talk-bot');
if (!$bot) {
$this->logger->error('NCbotwebhooks: talk-bot user not found, cannot create share', [
'app' => self::APP_ID,
]);
$this->clearSessionOverwrite();
return false;
}
try { try {
// Switch user context so createShare() can resolve the file
// path from the bot's filesystem (webhook runs as anonymous).
$currentUser = $this->userSession->getUser();
$this->userSession->setUser($bot);
$share = $this->shareManager->newShare(); $share = $this->shareManager->newShare();
$share->setNodeId((int)$richObject['fileId']) // Use the already-resolved node to bypass getFirstNodeById
->setShareType(IShare::TYPE_ROOM) // which can fail on LazyUserFolder or with manually-inserted
->setSharedBy($bot->getUID()) // filecache entries. Fall back to setNodeId if node is null.
->setSharedWith($roomToken) if ($richObject['node'] !== null) {
->setPermissions(\OCP\Constants::PERMISSION_READ); $share->setNode($richObject['node'])
->setShareType(IShare::TYPE_ROOM)
->setSharedBy($bot->getUID())
->setShareOwner($bot->getUID())
->setSharedWith($roomToken)
->setPermissions(\OCP\Constants::PERMISSION_READ);
} else {
$share->setNodeId((int)$richObject['fileId'])
->setShareType(IShare::TYPE_ROOM)
->setSharedBy($bot->getUID())
->setShareOwner($bot->getUID())
->setSharedWith($roomToken)
->setPermissions(\OCP\Constants::PERMISSION_READ);
}
$created = $this->shareManager->createShare($share); $created = $this->shareManager->createShare($share);
$actualShareId = (int)$created->getId(); $actualShareId = (int)$created->getId();
$richObject['shareId'] = $actualShareId; $richObject['shareId'] = $actualShareId;
@@ -1476,9 +1518,16 @@ class TalkService {
'shareId' => $actualShareId, 'shareId' => $actualShareId,
]); ]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->logger->error('NCbotwebhooks: deferred share creation failed: ' . $e->getMessage(), [ $this->logger->error('NCbotwebhooks: deferred share creation failed: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine(), [
'app' => self::APP_ID, 'app' => self::APP_ID,
'fileId' => (int)$richObject['fileId'],
'roomToken' => $roomToken,
'botUid' => $bot ? $bot->getUID() : 'null',
'trace' => $e->getTraceAsString(),
]); ]);
} finally {
// Always restore original user context
$this->userSession->setUser($currentUser);
} }
// Clear the session overwrite to avoid leaking to other requests // Clear the session overwrite to avoid leaking to other requests