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
7 changes: 7 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
use OCP\Files\Template\RegisterTemplateCreatorEvent;
use OCP\Security\CSP\AddContentSecurityPolicyEvent;

/**
* @psalm-api
*/
class Application extends App implements IBootstrap {
public const APP_ID = 'etherpad_nextcloud';

Expand All @@ -42,6 +45,10 @@ public function register(IRegistrationContext $context): void {
);

$context->registerEventListener(AddContentSecurityPolicyEvent::class, \OCA\EtherpadNextcloud\Listeners\CSPListener::class);
// LoadAdditionalScriptsEvent is provided by the Files app, not by
// nextcloud/ocp, so Psalm can't prove it is-a OCP\EventDispatcher\Event
// and rejects the generic IEventListener<Event> listener here.
/** @psalm-suppress InvalidArgument */
$context->registerEventListener(
LoadAdditionalScriptsEvent::class,
\OCA\EtherpadNextcloud\Listeners\LoadFilesScriptsListener::class,
Expand Down
3 changes: 3 additions & 0 deletions lib/BackgroundJob/AbstractPendingDeleteRetryJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;

/**
* @psalm-api
*/
abstract class AbstractPendingDeleteRetryJob extends TimedJob {
protected const INTERVAL_SECONDS = 24 * 60 * 60;
protected const MIN_AGE_SECONDS = 0;
Expand Down
3 changes: 3 additions & 0 deletions lib/BackgroundJob/ColdPendingDeleteRetryJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

namespace OCA\EtherpadNextcloud\BackgroundJob;

/**
* @psalm-api
*/
class ColdPendingDeleteRetryJob extends AbstractPendingDeleteRetryJob {
protected const INTERVAL_SECONDS = 24 * 60 * 60;
protected const MIN_AGE_SECONDS = 24 * 60 * 60;
Expand Down
3 changes: 3 additions & 0 deletions lib/BackgroundJob/HotPendingDeleteRetryJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

namespace OCA\EtherpadNextcloud\BackgroundJob;

/**
* @psalm-api
*/
class HotPendingDeleteRetryJob extends AbstractPendingDeleteRetryJob {
protected const INTERVAL_SECONDS = 5 * 60;
protected const MIN_AGE_SECONDS = 0;
Expand Down
3 changes: 3 additions & 0 deletions lib/BackgroundJob/WarmPendingDeleteRetryJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

namespace OCA\EtherpadNextcloud\BackgroundJob;

/**
* @psalm-api
*/
class WarmPendingDeleteRetryJob extends AbstractPendingDeleteRetryJob {
protected const INTERVAL_SECONDS = 60 * 60;
protected const MIN_AGE_SECONDS = 60 * 60;
Expand Down
1 change: 1 addition & 0 deletions lib/Controller/AbstractPadController.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
*
* Each concrete controller keeps its constructor narrow — it only
* declares the services it actually uses on top of the base deps.
* @psalm-api
*/
abstract class AbstractPadController extends Controller {
public function __construct(
Expand Down
6 changes: 4 additions & 2 deletions lib/Controller/AdminController.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
use OCP\IRequest;
use OCP\IUserSession;

/**
* @psalm-api
*/
class AdminController extends Controller {
private const CONSISTENCY_SAMPLE_LIMIT = 25;
private const PENDING_DELETE_RETRY_BATCH_SIZE = 500;
Expand Down Expand Up @@ -159,8 +162,7 @@ function (): string {

/** @return array<string,mixed> */
private function readJsonPayload(): array {
$params = $this->request->getParams();
return is_array($params) ? $params : [];
return $this->request->getParams();
}

private function requireAdmin(): void {
Expand Down
3 changes: 3 additions & 0 deletions lib/Controller/EmbedController.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
use OCP\IUser;
use OCP\IUserSession;

/**
* @psalm-api
*/
class EmbedController extends Controller {
public function __construct(
string $appName,
Expand Down
1 change: 1 addition & 0 deletions lib/Controller/PadCreateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
/**
* Create-side endpoints for `.pad` files. Spans empty creates, copies in
* a parent folder, template-based creates, and external-URL imports.
* @psalm-api
*/
class PadCreateController extends AbstractPadController {
public function __construct(
Expand Down
1 change: 1 addition & 0 deletions lib/Controller/PadLifecycleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
* Lifecycle + sync endpoints — trash, restore, recover-from-snapshot,
* sync state, and the find-original lookup that the copy-of-a-pad
* recovery affordance hangs off.
* @psalm-api
*/
class PadLifecycleController extends AbstractPadController {
public function __construct(
Expand Down
1 change: 1 addition & 0 deletions lib/Controller/PadSessionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
* pad session state for a viewer: actual open flow, lazy frontmatter
* init on first open, and the metadata + resolve readouts used by
* embed-side surfaces.
* @psalm-api
*/
class PadSessionController extends AbstractPadController {
public function __construct(
Expand Down
3 changes: 3 additions & 0 deletions lib/Controller/PublicViewerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
use OCP\ISession;
use OCP\Share\IShare;

/**
* @psalm-api
*/
class PublicViewerController extends PublicShareController {
private ?IShare $share = null;

Expand Down
2 changes: 1 addition & 1 deletion lib/Controller/PublicViewerControllerErrorMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function runForData(callable $action, callable $success): DataResponse {

/**
* @param callable(): mixed $action
* @param callable(mixed): RedirectResponse|TemplateResponse $success
* @param callable(mixed): (RedirectResponse|TemplateResponse) $success
*/
public function runForTemplate(callable $action, callable $success, string $token): RedirectResponse|TemplateResponse {
try {
Expand Down
3 changes: 3 additions & 0 deletions lib/Controller/ViewerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
use OCP\IUser;
use OCP\IUserSession;

/**
* @psalm-api
*/
class ViewerController extends Controller {
public function __construct(
string $appName,
Expand Down
2 changes: 1 addition & 1 deletion lib/Controller/ViewerControllerErrorMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function __construct(

/**
* @param callable(): mixed $action
* @param callable(mixed): RedirectResponse|TemplateResponse $success
* @param callable(mixed): (RedirectResponse|TemplateResponse) $success
* @param string|null $notFoundMessage context-specific message for `NotFoundException`; defaults to the open-pad wording
*/
public function runForTemplate(
Expand Down
3 changes: 3 additions & 0 deletions lib/Hooks/TrashbinHookHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
use OCA\EtherpadNextcloud\Listeners\RestoreFromTrashListener;
use Psr\Log\LoggerInterface;

/**
* @psalm-api
*/
class TrashbinHookHandler {
/**
* @param array<string,mixed> $params
Expand Down
4 changes: 4 additions & 0 deletions lib/Listeners/CSPListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
use OCP\IConfig;
use OCP\Security\CSP\AddContentSecurityPolicyEvent;

/**
* @template-implements IEventListener<Event>
* @psalm-api
*/
class CSPListener implements IEventListener {
public function __construct(
private IConfig $config,
Expand Down
3 changes: 3 additions & 0 deletions lib/Listeners/FileCreatedFromTemplateListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
* On any skip / failure inside the source-template branch the target is
* reset to empty *and* re-initialised so a fresh blank pad still opens
* cleanly on the first call.
*
* @template-implements IEventListener<Event>
* @psalm-api
*/
class FileCreatedFromTemplateListener implements IEventListener {
public function __construct(
Expand Down
4 changes: 4 additions & 0 deletions lib/Listeners/LoadFilesScriptsListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
use OCP\EventDispatcher\IEventListener;
use OCP\Util;

/**
* @template-implements IEventListener<Event>
* @psalm-api
*/
class LoadFilesScriptsListener implements IEventListener {
public function handle(Event $event): void {
if (!$event instanceof LoadAdditionalScriptsEvent) {
Expand Down
4 changes: 4 additions & 0 deletions lib/Listeners/LoadPublicShareScriptsListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
use OCP\EventDispatcher\IEventListener;
use OCP\Util;

/**
* @template-implements IEventListener<Event>
* @psalm-api
*/
class LoadPublicShareScriptsListener implements IEventListener {
public function handle(Event $event): void {
if (!$event instanceof BeforeTemplateRenderedEvent) {
Expand Down
4 changes: 4 additions & 0 deletions lib/Listeners/LoadViewerListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
use OCP\EventDispatcher\IEventListener;
use OCP\Util;

/**
* @template-implements IEventListener<Event>
* @psalm-api
*/
class LoadViewerListener implements IEventListener {
public function handle(Event $event): void {
if (!$event instanceof LoadViewer) {
Expand Down
4 changes: 4 additions & 0 deletions lib/Listeners/MoveToTrashListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
use OCP\Files\File;
use Psr\Log\LoggerInterface;

/**
* @template-implements IEventListener<Event>
* @psalm-api
*/
class MoveToTrashListener implements IEventListener {
public function __construct(
private LifecycleService $lifecycleService,
Expand Down
4 changes: 4 additions & 0 deletions lib/Listeners/RegisterTemplateCreatorListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
use OCP\Files\Template\TemplateFileCreator;
use OCP\IL10N;

/**
* @template-implements IEventListener<Event>
* @psalm-api
*/
class RegisterTemplateCreatorListener implements IEventListener {
public function __construct(
private IL10N $l10n,
Expand Down
4 changes: 4 additions & 0 deletions lib/Listeners/RestoreFromTrashListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
use OCP\IUserSession;
use Psr\Log\LoggerInterface;

/**
* @template-implements IEventListener<Event>
* @psalm-api
*/
class RestoreFromTrashListener implements IEventListener {
public function __construct(
private LifecycleService $lifecycleService,
Expand Down
3 changes: 3 additions & 0 deletions lib/Migration/BackfillPadMimeType.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
use OCP\Migration\IRepairStep;
use OCP\IDBConnection;

/**
* @psalm-api
*/
class BackfillPadMimeType implements IRepairStep {
private const MIME_PAD = 'application/x-etherpad-nextcloud';
private const MIME_PART = 'application';
Expand Down
1 change: 1 addition & 0 deletions lib/Migration/MarkApiKeySensitive.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* {@see AdminSettingsRepository::persist()}; this only backfills the flag
* onto the value installs stored before that change. Idempotent: writing
* the same value with `sensitive: true` is a no-op once the flag is set.
* @psalm-api
*/
class MarkApiKeySensitive implements IRepairStep {
public function __construct(
Expand Down
3 changes: 3 additions & 0 deletions lib/Migration/RegisterMimeType.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;

/**
* @psalm-api
*/
class RegisterMimeType implements IRepairStep {
private const MIME = 'application/x-etherpad-nextcloud';
private const MIME_ALIAS = 'etherpad-nextcloud-pad';
Expand Down
3 changes: 3 additions & 0 deletions lib/Migration/Version000001Date20260304222000.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

/**
* @psalm-api
*/
class Version000001Date20260304222000 extends SimpleMigrationStep {
/**
* @param Closure(): ISchemaWrapper $schemaClosure
Expand Down
3 changes: 3 additions & 0 deletions lib/Migration/Version000002Date20260512170000.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

/**
* @psalm-api
*/
class Version000002Date20260512170000 extends SimpleMigrationStep {
public function __construct(
private IDBConnection $db,
Expand Down
4 changes: 3 additions & 1 deletion lib/Migration/Version000003Date20260512230000.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

/**
* @psalm-api
*/
class Version000003Date20260512230000 extends SimpleMigrationStep {
public function __construct(
private IDBConnection $db,
) {
}

public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
if (!$schema->hasTable(BindingService::TABLE)) {
return;
Expand Down
8 changes: 8 additions & 0 deletions lib/Preview/PadPreviewProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
* A future iteration could render the actual snapshot text into the
* preview (similar to how the Text app previews Markdown), but that's
* a separate feature — this exists to silence the 4xx noise.
* @psalm-api
*/
class PadPreviewProvider implements IProviderV2 {
private const ASSET_PATH = __DIR__ . '/../../img/preview-fallback.png';
Expand All @@ -44,6 +45,13 @@ public function isAvailable(FileInfo $file): bool {
return is_readable(self::ASSET_PATH);
}

/**
* `OCP\Image` is the concrete implementation of `OCP\IImage` at runtime,
* but it isn't shipped in the `nextcloud/ocp` stubs Psalm analyses against,
* so Psalm can't see that it satisfies the `?IImage` return type.
*
* @psalm-suppress InvalidReturnType, InvalidReturnStatement
*/
public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
if (!is_readable(self::ASSET_PATH)) {
return null;
Expand Down
2 changes: 1 addition & 1 deletion lib/Service/ConsistencyCheckService.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,6 @@ private function sampleBindingsWithoutFile(int $limit): array {
$result = $qb->executeQuery();
$rows = $result->fetchAll();
$result->closeCursor();
return is_array($rows) ? $rows : [];
return $rows;
}
}
2 changes: 1 addition & 1 deletion lib/Service/EtherpadHealthCheckService.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public function check(ValidatedAdminSettings $settings): HealthCheckResult {
$settings->etherpadApiHost,
$settings->etherpadApiVersion,
(int)($result['pad_count'] ?? 0),
(int)round(($this->now() - $startedAt) * 1000),
(int)round(($this->now() - $startedAt) * 1000.0),
rtrim($settings->etherpadApiHost, '/') . '/api/' . $settings->etherpadApiVersion . '/listAllPads',
$this->pendingDeleteRetryService->countPendingDeletes(),
);
Expand Down
7 changes: 6 additions & 1 deletion lib/Service/ExternalPadExportFetcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private function buildPublicExportUrl(string $padUrl, string $format): string {
}

/**
* @param array{pad_url:string,host:string,port:int,resolved_ips:list<string>} $resolved
* @param array{origin:string,pad_id:string,pad_url:string,host:string,port:int,resolved_ips:list<string>} $resolved
*/
private function getPublicTextFromResolvedExternalPad(array $resolved): string {
$url = $this->buildPublicExportUrl($resolved['pad_url'], 'txt');
Expand Down Expand Up @@ -156,6 +156,11 @@ private function sendPinnedPublicGetRequest(string $url, string $host, int $port
curl_close($curl);

if ($success === false) {
// $sizeExceeded is flipped to true inside the CURLOPT_WRITEFUNCTION
// closure above when the response exceeds the cap; Psalm doesn't
// model curl invoking that callback, so it wrongly infers the flag
// stays false here.
/** @psalm-suppress TypeDoesNotContainType */
if ($sizeExceeded) {
throw new EtherpadClientException(
'External public pad export exceeds maximum size (' . self::EXTERNAL_EXPORT_MAX_BYTES . ' bytes).'
Expand Down
Loading