Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ precedence = "aggregate"
SPDX-FileCopyrightText = "2025 Nextcloud GmbH and Nextcloud contributors"
SPDX-License-Identifier = "AGPL-3.0-or-later"

[[annotations]]
path = ["vendor-bin/rector/composer.json", "vendor-bin/rector/composer.lock", "tests/psalm-baseline.xml"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2026 Nextcloud GmbH and Nextcloud contributors"
SPDX-License-Identifier = "AGPL-3.0-or-later"

[[annotations]]
path = ["img/app-dark.svg", "img/app.svg", "img/view.svg", "img/view-dark.svg", "img/material/*.svg"]
precedence = "aggregate"
Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"nextcloud/ocp": "dev-stable33",
"staabm/annotate-pull-request-from-checkstyle": "^1.8.7",
"phpunit/phpunit": "9.6.36",
"psalm/phar": "^5.26.1"
"psalm/phar": "^6.16"
},
"config": {
"optimize-autoloader": true,
Expand All @@ -44,6 +44,8 @@
"psalm:fix": "./vendor/bin/psalm.phar --no-cache --alter --issues=InvalidReturnType,InvalidNullableReturnType,MismatchingDocblockParamType,MismatchingDocblockReturnType,MissingParamType,InvalidFalsableReturnType",
"psalm:fix:dry": "./vendor/bin/psalm.phar --no-cache --alter --issues=InvalidReturnType,InvalidNullableReturnType,MismatchingDocblockParamType,MismatchingDocblockReturnType,MissingParamType,InvalidFalsableReturnType --dry-run",
"openapi": "generate-spec --verbose && (npm run typescript:generate || echo 'Please manually regenerate the typescript OpenAPI models')",
"rector:check": "rector --dry-run",
"rector:fix": "rector",
"scoper:update-deps": "./update-scoper-dependencies.sh",
"post-install-cmd": [
"composer bin all install --ansi",
Expand Down
16 changes: 8 additions & 8 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 40 additions & 18 deletions lib/Activity/ActivityManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,16 @@ public function __construct(
) {
}

public function triggerEvent($objectType, $object, $subject, $additionalParams = [], $author = null) {
/**
* @param Row2|Table|View|Column $object
* @param array<string, mixed>|null|string $additionalParams
* @param string|null $author
*
* @psalm-param self::TABLES_OBJECT_* $objectType
* @psalm-param array<string, mixed>|null|string $additionalParams
* @psalm-param string|null $author
*/
public function triggerEvent(string $objectType, Row2|Table|View|Column $object, string $subject, array|string|null $additionalParams = [], array|string|null $author = null) {
if ($author === null) {
$author = $this->userId;
}
Expand All @@ -92,19 +101,22 @@ public function triggerEvent($objectType, $object, $subject, $additionalParams =
if ($event !== null) {
$this->sendToUsers($event, $object);
}
} catch (\Exception $e) {
} catch (\Exception) {
// Ignore exception for undefined activities on update events
}
}

public function triggerUpdateEvents($objectType, ChangeSet $changeSet, $subject) {
/**
* @psalm-param self::TABLES_OBJECT_* $objectType
*/
public function triggerUpdateEvents(string $objectType, ChangeSet $changeSet, string $subject) {
$previousEntity = $changeSet->getBefore();
$entity = $changeSet->getAfter();
$events = [];

if ($previousEntity !== null) {
foreach ($entity->getUpdatedFields() as $field => $value) {
$getter = 'get' . ucfirst($field);
$getter = 'get' . ucfirst((string)$field);
$subjectComplete = $subject . '_' . $field;
$changes = [
'before' => $previousEntity->$getter(),
Expand All @@ -116,15 +128,15 @@ public function triggerUpdateEvents($objectType, ChangeSet $changeSet, $subject)
if ($event !== null) {
$events[] = $event;
}
} catch (\Exception $e) {
} catch (\Exception) {
// Ignore exception for undefined activities on update events
}
}
}
} else {
try {
$events = [$this->createEvent($objectType, $entity, $subject)];
} catch (\Exception $e) {
} catch (\Exception) {
// Ignore exception for undefined activities on update events
}
}
Expand All @@ -134,7 +146,15 @@ public function triggerUpdateEvents($objectType, ChangeSet $changeSet, $subject)
}
}

private function createEvent($objectType, $object, $subject, $additionalParams = [], $author = null) {
/**
* @param Row2|Table|View|Column $object
* @param string|null $author
*
* @psalm-param self::TABLES_OBJECT_* $objectType
* @psalm-param array<string, mixed> $additionalParams
* @psalm-param string|null $author
*/
private function createEvent(string $objectType, Row2|Table|View|Column $object, string $subject, array $additionalParams = [], array|string|null $author = null) {
if ($object instanceof Table) {
$objectTitle = $object->getTitle();
$table = $object;
Expand All @@ -158,7 +178,7 @@ private function createEvent($objectType, $object, $subject, $additionalParams =
*/
$eventType = 'tables';
$subjectParams = [
'author' => $author === null ? $this->userId : $author,
'author' => $author ?? $this->userId,
'table' => $table,
'objectType' => $objectType,
];
Expand Down Expand Up @@ -295,7 +315,7 @@ private function buildSharedWithParam(mixed $share): array {
];
}

private function sendToUsers(IEvent $event, $object) {
private function sendToUsers(IEvent $event, Row2|Table|View|Column $object) {
// Handle share events with restricted recipients
$subject = $event->getSubject();
if (in_array($subject, [self::SUBJECT_SHARE_CREATE, self::SUBJECT_SHARE_UPDATE, self::SUBJECT_SHARE_DELETE], true)) {
Expand Down Expand Up @@ -405,8 +425,10 @@ public function getAffectedViewsForColumn(Column $column): array {

/**
* Send share events only to: event author, table owner, and shared-with receiver users.
*
* @param Row2|Table|View|Column $object
*/
private function sendShareEventToUsers(IEvent $event, $object): void {
private function sendShareEventToUsers(IEvent $event, Row2|Table|View|Column $object): void {
if (!$object instanceof Table && !$object instanceof View) {
Server::get(LoggerInterface::class)->error('Could not send share activity. Invalid object type.', (array)$object);
return;
Expand Down Expand Up @@ -539,7 +561,7 @@ private function getViewColumnIds(mixed $view): array {
return $columnIds;
}

public function getActivitySubject($language, $subjectIdentifier, $subjectParams = [], $ownActivity = false) {
public function getActivitySubject(string $language, $subjectIdentifier, array $subjectParams = [], bool $ownActivity = false) {
$l = $this->l10nFactory->get(Application::APP_ID, $language);
$isViewContext = $subjectParams['isViewContext'] ?? false;
$isViewObject = ($subjectParams['objectType'] ?? null) === self::TABLES_OBJECT_VIEW;
Expand Down Expand Up @@ -577,7 +599,7 @@ public function getActivitySubject($language, $subjectIdentifier, $subjectParams
return '';
}

private function formatTableActivity($l, string $subjectIdentifier, bool $ownActivity): ?string {
private function formatTableActivity(\OCP\IL10N $l, string $subjectIdentifier, bool $ownActivity): ?string {
return match ($subjectIdentifier) {
self::SUBJECT_TABLE_CREATE => $ownActivity ? $l->t('You have created a new table {table}') : $l->t('{user} has created a new table {table}'),
self::SUBJECT_TABLE_UPDATE => $ownActivity ? $l->t('You have updated the table {table}') : $l->t('{user} has updated the table {table}'),
Expand All @@ -588,7 +610,7 @@ private function formatTableActivity($l, string $subjectIdentifier, bool $ownAct
};
}

private function formatViewActivity($l, string $subjectIdentifier, bool $ownActivity): ?string {
private function formatViewActivity(\OCP\IL10N $l, string $subjectIdentifier, bool $ownActivity): ?string {
return match ($subjectIdentifier) {
self::SUBJECT_VIEW_CREATE => $ownActivity ? $l->t('You have created a new view {view} in table {table}') : $l->t('{user} has created a new view {view} in table {table}'),
self::SUBJECT_VIEW_UPDATE => $ownActivity ? $l->t('You have updated the view {view} in table {table}') : $l->t('{user} has updated the view {view} in table {table}'),
Expand All @@ -599,7 +621,7 @@ private function formatViewActivity($l, string $subjectIdentifier, bool $ownActi
};
}

private function formatRowActivity($l, string $subjectIdentifier, array $subjectParams, bool $ownActivity, bool $isViewContext): ?string {
private function formatRowActivity(\OCP\IL10N $l, string $subjectIdentifier, array $subjectParams, bool $ownActivity, bool $isViewContext): ?string {
switch ($subjectIdentifier) {
case self::SUBJECT_ROW_CREATE:
if ($isViewContext) {
Expand All @@ -620,7 +642,7 @@ private function formatRowActivity($l, string $subjectIdentifier, array $subject
}
}

private function formatRowUpdateActivity($l, array $subjectParams, bool $ownActivity, bool $isViewContext): string {
private function formatRowUpdateActivity(\OCP\IL10N $l, array $subjectParams, bool $ownActivity, bool $isViewContext): string {
$visibleChangeCols = $this->getVisibleChangeCols($subjectParams);
$columns = '';
$count = 1;
Expand Down Expand Up @@ -664,7 +686,7 @@ private function formatRowUpdateActivity($l, array $subjectParams, bool $ownActi
);
}

private function formatColumnActivity($l, string $subjectIdentifier, bool $ownActivity, bool $isViewContext): ?string {
private function formatColumnActivity(\OCP\IL10N $l, string $subjectIdentifier, bool $ownActivity, bool $isViewContext): ?string {
if ($isViewContext) {
return match ($subjectIdentifier) {
self::SUBJECT_COLUMN_CREATE => $ownActivity ? $l->t('You have created a new column {column} in view {view}') : $l->t('{user} has created a new column {column} in view {view}'),
Expand All @@ -682,7 +704,7 @@ private function formatColumnActivity($l, string $subjectIdentifier, bool $ownAc
};
}

private function formatShareActivity($l, string $subjectIdentifier, array $subjectParams, bool $ownActivity, bool $isViewObject, mixed $sharedWith): ?string {
private function formatShareActivity(\OCP\IL10N $l, string $subjectIdentifier, array $subjectParams, bool $ownActivity, bool $isViewObject, mixed $sharedWith): ?string {
$sharedWithYou = $this->isSharedWithYou($subjectParams, $ownActivity);
$isLinkShare = $this->isLinkShare($sharedWith);

Expand Down Expand Up @@ -766,7 +788,7 @@ private function isLinkShare(mixed $sharedWith): bool {
return is_array($sharedWith) && ($sharedWith['type'] ?? null) === ShareReceiverType::LINK;
}

public function getActivityMessage($language, $subjectIdentifier) {
public function getActivityMessage(string $language, $subjectIdentifier) {
$l = $this->l10nFactory->get(Application::APP_ID, $language);

switch ($subjectIdentifier) {
Expand Down
4 changes: 2 additions & 2 deletions lib/Activity/ChangeSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ public function __construct(
}
}

public function setBefore($before) {
public function setBefore(Entity $before) {
$this->before = clone $before;
}

public function setAfter($after) {
public function setAfter(Entity $after) {
$this->after = clone $after;
}

Expand Down
10 changes: 5 additions & 5 deletions lib/Activity/TablesProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ class TablesProvider implements IProvider {

public function __construct(
private $userId,
private IURLGenerator $urlGenerator,
private ActivityManager $activityManager,
private IUserManager $userManager,
private LoggerInterface $logger,
private PermissionsService $permissionsService,
private readonly IURLGenerator $urlGenerator,
private readonly ActivityManager $activityManager,
private readonly IUserManager $userManager,
private readonly LoggerInterface $logger,
private readonly PermissionsService $permissionsService,
) {
}

Expand Down
36 changes: 10 additions & 26 deletions lib/Analytics/AnalyticsDatasource.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,15 @@

class AnalyticsDatasource implements IDatasource {

private LoggerInterface $logger;
private IL10N $l10n;
private TableService $tableService;
private ViewService $viewService;
private RowService $rowService;
private ColumnService $columnService;

protected ?string $userId;

public function __construct(
IL10N $l10n,
LoggerInterface $logger,
TableService $tableService,
ViewService $viewService,
ColumnService $columnService,
RowService $rowService,
?string $userId,
private readonly IL10N $l10n,
private readonly LoggerInterface $logger,
private readonly TableService $tableService,
private readonly ViewService $viewService,
private readonly ColumnService $columnService,
private readonly RowService $rowService,
protected ?string $userId,
) {
$this->l10n = $l10n;
$this->logger = $logger;
$this->tableService = $tableService;
$this->viewService = $viewService;
$this->columnService = $columnService;
$this->rowService = $rowService;
$this->userId = $userId;
}

/**
Expand Down Expand Up @@ -110,7 +94,7 @@ public function getTemplate(): array {
// concatenate the option-string. The format is tableId:viewId-title
$tableString = $tableString . $table->getId() . ':' . $view->getId() . '-' . $view->getTitle() . '/';
}
} catch (PermissionError $e) {
} catch (PermissionError) {
// this is a shared table without shared views;
continue;
}
Expand Down Expand Up @@ -164,7 +148,7 @@ public function getTemplate(): array {
*/
public function readData($option): array {
// get the ids which come in the format tableId:viewId
$ids = explode(':', $option['tableId']);
$ids = explode(':', (string)$option['tableId']);
$this->userId = $option['user_id'];

if (count($ids) === 1) {
Expand Down Expand Up @@ -338,7 +322,7 @@ private function formatBooleanValue(mixed $value): string {
return '';
}

private function formatTextValue(Column $column, mixed $value): string {
private function formatTextValue(Column $column, string $value): string {
if ($value === null || $value === '') {
return '';
}
Expand Down
13 changes: 5 additions & 8 deletions lib/Api/V1Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,11 @@
use OCP\AppFramework\Db\MultipleObjectsReturnedException;

class V1Api {
private RowService $rowService;
private ColumnService $columnService;
private ?string $userId;

public function __construct(ColumnService $columnService, RowService $rowService, ?string $userId) {
$this->columnService = $columnService;
$this->rowService = $rowService;
$this->userId = $userId;
public function __construct(
private readonly ColumnService $columnService,
private readonly RowService $rowService,
private ?string $userId,
) {
}

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public function register(IRegistrationContext $context): void {
}

public function boot(IBootContext $context): void {
$context->injectFn([$this, 'registerCloudFederationProviderManager']);
$context->injectFn($this->registerCloudFederationProviderManager(...));
}

public function registerCloudFederationProviderManager(ICloudFederationProviderManager $manager): void {
Expand Down
Loading
Loading