From e1c042bbb4f1729c34cbd5edcbf96ccd1d39c8db Mon Sep 17 00:00:00 2001 From: Anna Larch Date: Thu, 7 May 2026 00:43:19 +0200 Subject: [PATCH 1/3] refactor(types): add native parameter/return types to Data::get and APIv2Controller - Data::get(): type the 5 previously untyped parameters (string $user, int $since, int $limit, string $sort, string $filter) and add array return type; same for the related setOffsetFromSince() helper - APIv2Controller: replace @var docblock properties with native typed properties, all with sensible defaults matching validateParameters() Three test mocks that relied on null being assignable to untyped IUser::getUID() are updated to return 'testuser' so the string property assignment passes. Signed-off-by: Anna Larch AI-Assisted-By: Claude Sonnet 4.6 --- lib/Controller/APIv2Controller.php | 31 ++++++------------------ lib/Data.php | 6 ++--- tests/Controller/APIv2ControllerTest.php | 12 ++++++--- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/lib/Controller/APIv2Controller.php b/lib/Controller/APIv2Controller.php index 2270bef69..4c100f74c 100644 --- a/lib/Controller/APIv2Controller.php +++ b/lib/Controller/APIv2Controller.php @@ -28,29 +28,14 @@ use OCP\Notification\IManager as INotificationManager; class APIv2Controller extends OCSController { - /** @var string */ - protected $filter; - - /** @var int */ - protected $since; - - /** @var int */ - protected $limit; - - /** @var string */ - protected $sort; - - /** @var string */ - protected $objectType; - - /** @var int */ - protected $objectId; - - /** @var string */ - protected $user; - - /** @var bool */ - protected $loadPreviews; + protected string $filter = 'all'; + protected int $since = 0; + protected int $limit = 50; + protected string $sort = 'desc'; + protected string $objectType = ''; + protected int $objectId = 0; + protected string $user = ''; + protected bool $loadPreviews = false; public function __construct( $appName, diff --git a/lib/Data.php b/lib/Data.php index b4d444bdf..e11f5d164 100644 --- a/lib/Data.php +++ b/lib/Data.php @@ -226,7 +226,7 @@ public function storeMail(IEvent $event, int $latestSendTime): bool { * @return array * */ - public function get(GroupHelper $groupHelper, UserSettings $userSettings, $user, $since, $limit, $sort, $filter, $objectType = '', $objectId = 0, bool $returnEvents = false) { + public function get(GroupHelper $groupHelper, UserSettings $userSettings, string $user, int $since, int $limit, string $sort, string $filter, string $objectType = '', int $objectId = 0, bool $returnEvents = false): array { // get current user if ($user === '') { throw new \OutOfBoundsException('Invalid user', 1); @@ -323,12 +323,12 @@ public function get(GroupHelper $groupHelper, UserSettings $userSettings, $user, * * @throws \OutOfBoundsException If $since is not owned by $user */ - protected function setOffsetFromSince(IQueryBuilder $query, $user, $since, $sort) { + protected function setOffsetFromSince(IQueryBuilder $query, string $user, int $since, string $sort): array { if ($since) { $queryBuilder = $this->connection->getQueryBuilder(); $queryBuilder->select(['affecteduser', 'timestamp']) ->from('activity') - ->where($queryBuilder->expr()->eq('activity_id', $queryBuilder->createNamedParameter((int)$since))); + ->where($queryBuilder->expr()->eq('activity_id', $queryBuilder->createNamedParameter($since))); $result = $queryBuilder->executeQuery(); $activity = $result->fetch(); $result->closeCursor(); diff --git a/tests/Controller/APIv2ControllerTest.php b/tests/Controller/APIv2ControllerTest.php index ebdb1a147..552724b17 100644 --- a/tests/Controller/APIv2ControllerTest.php +++ b/tests/Controller/APIv2ControllerTest.php @@ -140,9 +140,11 @@ public function testValidateParametersFilter(string $param, string $filter): voi ->method('validateFilter') ->with($param) ->willReturn($filter); + $userMock = $this->createMock(IUser::class); + $userMock->method('getUID')->willReturn('testuser'); $this->userSession->expects($this->once()) ->method('getUser') - ->willReturn($this->createMock(IUser::class)); + ->willReturn($userMock); self::invokePrivate($this->controller, 'validateParameters', [$param, 0, 0, false, '', 0, 'desc']); $this->assertSame($filter, self::invokePrivate($this->controller, 'filter')); @@ -183,9 +185,11 @@ public function testValidateParametersObject(?string $type, mixed $id, string $e $this->data->expects($this->once()) ->method('validateFilter') ->willReturnArgument(0); + $userMock = $this->createMock(IUser::class); + $userMock->method('getUID')->willReturn('testuser'); $this->userSession->expects($this->once()) ->method('getUser') - ->willReturn($this->createMock(IUser::class)); + ->willReturn($userMock); self::invokePrivate($this->controller, 'validateParameters', ['all', 0, 0, false, $type, $id, 'desc']); $this->assertSame($expectedType, self::invokePrivate($this->controller, 'objectType')); @@ -229,9 +233,11 @@ public function testValidateParameters(string $param, mixed $value, string $memb $this->data->expects($this->once()) ->method('validateFilter') ->willReturnArgument(0); + $userMock = $this->createMock(IUser::class); + $userMock->method('getUID')->willReturn('testuser'); $this->userSession->expects($this->once()) ->method('getUser') - ->willReturn($this->createMock(IUser::class)); + ->willReturn($userMock); self::invokePrivate($this->controller, 'validateParameters', $params); $this->assertSame($expectedValue, self::invokePrivate($this->controller, $memberName)); From f1b3420bd5c35994cb805a6fa6d354fbc7c0a704 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 10 May 2026 16:42:30 +0000 Subject: [PATCH 2/3] fix(tests): update testValidateParametersObject data to use typed values Agent-Logs-Url: https://github.com/nextcloud/activity/sessions/f54c7c8a-f6d4-476c-9f7f-d9ed8f3677b6 Co-authored-by: miaulalala <7427347+miaulalala@users.noreply.github.com> --- tests/Controller/APIv2ControllerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Controller/APIv2ControllerTest.php b/tests/Controller/APIv2ControllerTest.php index 552724b17..b133a48db 100644 --- a/tests/Controller/APIv2ControllerTest.php +++ b/tests/Controller/APIv2ControllerTest.php @@ -175,13 +175,13 @@ public static function dataValidateParametersObject(): array { return [ ['type', 42, 'type', 42], ['type', '42', 'type', 42], - [null, '42', '', 0], - ['type', null, '', 0], + ['', 42, '', 0], + ['type', 0, '', 0], ]; } #[DataProvider('dataValidateParametersObject')] - public function testValidateParametersObject(?string $type, mixed $id, string $expectedType, int $expectedId): void { + public function testValidateParametersObject(string $type, mixed $id, string $expectedType, int $expectedId): void { $this->data->expects($this->once()) ->method('validateFilter') ->willReturnArgument(0); From d03aa8860a46c2974ea726440cdd9433c458c8c4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 10 May 2026 17:40:34 +0000 Subject: [PATCH 3/3] fix(psalm): remove redundant casts and dead is_string guard after native types Agent-Logs-Url: https://github.com/nextcloud/activity/sessions/e9a877c2-92db-4439-b35e-27e0ba15f897 Co-authored-by: miaulalala <7427347+miaulalala@users.noreply.github.com> --- lib/Controller/APIv2Controller.php | 12 ++++++------ lib/Data.php | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Controller/APIv2Controller.php b/lib/Controller/APIv2Controller.php index d00ee580b..e0444a0c3 100644 --- a/lib/Controller/APIv2Controller.php +++ b/lib/Controller/APIv2Controller.php @@ -60,15 +60,15 @@ public function __construct( * @throws \OutOfBoundsException when no user is given */ protected function validateParameters(string $filter, int $since, int $limit, bool $previews, string $objectType, int $objectId, string $sort): void { - $this->filter = \is_string($filter) ? $filter : 'all'; + $this->filter = $filter; if ($this->filter !== $this->data->validateFilter($this->filter)) { throw new InvalidFilterException('Invalid filter'); } - $this->since = (int)$since; - $this->limit = (int)$limit; - $this->loadPreviews = (bool)$previews; - $this->objectType = (string)$objectType; - $this->objectId = (int)$objectId; + $this->since = $since; + $this->limit = $limit; + $this->loadPreviews = $previews; + $this->objectType = $objectType; + $this->objectId = $objectId; $this->sort = \in_array($sort, ['asc', 'desc'], true) ? $sort : 'desc'; if (($this->objectType !== '' && $this->objectId === 0) || ($this->objectType === '' && $this->objectId !== 0)) { diff --git a/lib/Data.php b/lib/Data.php index c8418d955..06e7867af 100644 --- a/lib/Data.php +++ b/lib/Data.php @@ -331,7 +331,7 @@ protected function setOffsetFromSince(IQueryBuilder $query, string $user, int $s $queryBuilder = $this->connection->getQueryBuilder(); $queryBuilder->select(['affecteduser', 'timestamp']) ->from('activity') - ->where($queryBuilder->expr()->eq('activity_id', $queryBuilder->createNamedParameter((int)$since))); + ->where($queryBuilder->expr()->eq('activity_id', $queryBuilder->createNamedParameter($since))); $result = $queryBuilder->executeQuery(); $activity = $result->fetch(); $result->closeCursor();