diff --git a/lib/CurrentUser.php b/lib/CurrentUser.php index e9fe71f7b..24760545c 100644 --- a/lib/CurrentUser.php +++ b/lib/CurrentUser.php @@ -7,6 +7,7 @@ namespace OCA\Activity; +use OCP\Activity\IManager as IActivityManager; use OCP\IRequest; use OCP\IUser; use OCP\IUserSession; @@ -22,6 +23,7 @@ public function __construct( protected readonly IRequest $request, protected readonly IManager $shareManager, protected readonly IFactory $l10nFactory, + protected readonly IActivityManager $activityManager, ) { } @@ -53,9 +55,23 @@ public function getUserIdentifier(): string { } /** - * Get the current user id from the session + * Get the current user id + * + * Apps can override who an action is attributed to with + * IManager::setCurrentUserId(). That is the only way to name an actor when the + * action happens outside of that user's session, e.g. from a background job. + * Without an override this is the user of the session, as before. */ public function getUID(): ?string { + try { + $userId = $this->activityManager->getCurrentUserId(); + if ($userId !== '') { + return $userId; + } + } catch (\UnexpectedValueException) { + // Neither a session nor a valid feed token, fall back to the session below + } + $user = $this->userSession->getUser(); if ($user instanceof IUser) { return $user->getUID(); diff --git a/tests/CurrentUserTest.php b/tests/CurrentUserTest.php index 2c7151ea7..c64e98481 100644 --- a/tests/CurrentUserTest.php +++ b/tests/CurrentUserTest.php @@ -24,6 +24,7 @@ use Exception; use OCA\Activity\CurrentUser; +use OCP\Activity\IManager as IActivityManager; use OCP\IRequest; use OCP\IUser; use OCP\IUserSession; @@ -49,6 +50,7 @@ class CurrentUserTest extends TestCase { protected IUserSession&MockObject $userSession; protected IManager&MockObject $shareManager; protected IFactory&MockObject $l10nFactory; + protected IActivityManager&MockObject $activityManager; protected function setUp(): void { parent::setUp(); @@ -57,6 +59,7 @@ protected function setUp(): void { $this->userSession = $this->createMock(IUserSession::class); $this->shareManager = $this->createMock(IManager::class); $this->l10nFactory = $this->createMock(IFactory::class); + $this->activityManager = $this->createMock(IActivityManager::class); $this->request->method('getScriptName')->willReturn('/public.php'); } @@ -68,6 +71,7 @@ protected function getInstance(array $methods = []): CurrentUser|MockObject { $this->request, $this->shareManager, $this->l10nFactory, + $this->activityManager, ); } @@ -77,6 +81,7 @@ protected function getInstance(array $methods = []): CurrentUser|MockObject { $this->request, $this->shareManager, $this->l10nFactory, + $this->activityManager, ]) ->onlyMethods($methods) ->getMock(); @@ -141,6 +146,28 @@ public function testGetUID(?string $uid, ?string $expected): void { $this->assertSame($expected, $instance->getUID()); } + public function testGetUIDUsesTheActivityManagerOverride(): void { + $this->activityManager->method('getCurrentUserId') + ->willReturn('attributed-user'); + $this->userSession->expects($this->never()) + ->method('getUser'); + + $instance = $this->getInstance(); + $this->assertSame('attributed-user', $instance->getUID()); + } + + public function testGetUIDFallsBackToTheSessionWithoutAToken(): void { + $this->activityManager->method('getCurrentUserId') + ->willThrowException(new \UnexpectedValueException('The token is invalid')); + + $instance = $this->getInstance(); + $this->userSession->expects($this->once()) + ->method('getUser') + ->willReturn($this->getUserMock('session-user')); + + $this->assertSame('session-user', $instance->getUID()); + } + protected function getShareMock(array $share): IShare|Exception|null { if (empty($share)) { return null;