fix: fix phpstan validation on responses
All checks were successful
repod / xml (push) Successful in 15s
repod / php (push) Successful in 42s
repod / nodejs (push) Successful in 48s
repod / release (push) Has been skipped

This commit is contained in:
Michel Roux 2025-03-06 18:36:38 +01:00
parent 6d27ec4ac0
commit 3197873d0f
9 changed files with 119 additions and 20 deletions

View File

@ -24,6 +24,7 @@
"nextcloud/ocp": "^31.0.0",
"nextcloud/rector": "^0.3.1",
"phpstan/phpstan": "~1.12.20",
"phpstan/phpstan-deprecation-rules": "~1.2.1",
"rector/rector": "~1.2.10",
"roave/security-advisories": "dev-latest"
},

62
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0142d63c8ac24699581a19cd69148107",
"content-hash": "600a8f571b8f0aba7eacf029c105560d",
"packages": [],
"packages-dev": [
{
@ -315,6 +315,53 @@
],
"time": "2025-03-05T13:37:43+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-deprecation-rules.git",
"reference": "f94d246cc143ec5a23da868f8f7e1393b50eaa82"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/f94d246cc143ec5a23da868f8f7e1393b50eaa82",
"reference": "f94d246cc143ec5a23da868f8f7e1393b50eaa82",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.12"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.5"
},
"type": "phpstan-extension",
"extra": {
"phpstan": {
"includes": [
"rules.neon"
]
}
},
"autoload": {
"psr-4": {
"PHPStan\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.",
"support": {
"issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues",
"source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.2.1"
},
"time": "2024-09-11T15:52:35+00:00"
},
{
"name": "psr/clock",
"version": "1.0.0",
@ -581,12 +628,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "e7cacb4409da236548159072e5eff2c30cd3bf9c"
"reference": "93d6f477df354be282736a37f732e39382ff9f95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/e7cacb4409da236548159072e5eff2c30cd3bf9c",
"reference": "e7cacb4409da236548159072e5eff2c30cd3bf9c",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/93d6f477df354be282736a37f732e39382ff9f95",
"reference": "93d6f477df354be282736a37f732e39382ff9f95",
"shasum": ""
},
"conflict": {
@ -914,7 +961,7 @@
"lara-zeus/artemis": ">=1,<=1.0.6",
"lara-zeus/dynamic-dashboard": ">=3,<=3.0.1",
"laravel/fortify": "<1.11.1",
"laravel/framework": "<6.20.45|>=7,<7.30.7|>=8,<8.83.28|>=9,<9.52.17|>=10,<10.48.23|>=11,<11.31",
"laravel/framework": "<11.44.1|>=12,<12.1.1",
"laravel/laravel": ">=5.4,<5.4.22",
"laravel/pulse": "<1.3.1",
"laravel/reverb": "<1.4",
@ -934,6 +981,7 @@
"limesurvey/limesurvey": "<6.5.12",
"livehelperchat/livehelperchat": "<=3.91",
"livewire/livewire": "<2.12.7|>=3.0.0.0-beta1,<3.5.2",
"livewire/volt": "<1.7",
"lms/routes": "<2.1.1",
"localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2",
"luyadev/yii-helpers": "<1.2.1",
@ -1123,7 +1171,7 @@
"rap2hpoutre/laravel-log-viewer": "<0.13",
"react/http": ">=0.7,<1.9",
"really-simple-plugins/complianz-gdpr": "<6.4.2",
"redaxo/source": "<=5.18.1",
"redaxo/source": "<5.18.3",
"remdex/livehelperchat": "<4.29",
"reportico-web/reportico": "<=8.1",
"rhukster/dom-sanitizer": "<1.0.7",
@ -1449,7 +1497,7 @@
"type": "tidelift"
}
],
"time": "2025-03-03T20:05:19+00:00"
"time": "2025-03-05T20:05:33+00:00"
}
],
"aliases": [],

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace OCA\RePod\Controller;
use OCA\GPodderSync\Core\EpisodeAction\EpisodeAction;
use OCA\GPodderSync\Db\EpisodeAction\EpisodeActionRepository;
use OCA\RePod\AppInfo\Application;
use OCA\RePod\Core\EpisodeAction\EpisodeActionExtraData;
@ -15,9 +16,13 @@ use OCP\AppFramework\Http\Attribute\FrontpageRoute;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\Http\Client\IClientService;
use OCP\IRequest;
/**
* @phpstan-import-type EpisodeActionType from EpisodeAction
*/
class EpisodesController extends Controller
{
public function __construct(
@ -30,10 +35,13 @@ class EpisodesController extends Controller
parent::__construct(Application::APP_ID, $request);
}
/**
* @return JSONResponse<Http::STATUS_*, array<int, EpisodeActionExtraData>, array{}>
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'GET', url: '/episodes/list')]
public function list(string $url): JSONResponse {
public function list(string $url): Response {
$client = $this->clientService->newClient();
$feed = $client->get($url);
$episodes = $this->episodeActionReader->parseRssXml((string) $feed->getBody());
@ -46,16 +54,20 @@ class EpisodesController extends Controller
return new JSONResponse($episodes, $returnStatusCode);
}
/**
* @return JSONResponse<Http::STATUS_OK, EpisodeActionType, array{}>
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'GET', url: '/episodes/action')]
public function action(string $url): JSONResponse {
public function action(string $url): Response {
$action = $this->episodeActionRepository->findByEpisodeUrl($url, $this->userService->getUserUID());
if ($action) {
return new JSONResponse($action->toArray());
}
/** @phpstan-ignore-next-line */
return new JSONResponse([], Http::STATUS_NOT_FOUND);
}
}

View File

@ -10,6 +10,7 @@ use OCA\GPodderSync\Core\SubscriptionChange\SubscriptionChangeSaver;
use OCA\RePod\AppInfo\Application;
use OCA\RePod\Service\UserService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
@ -31,10 +32,13 @@ class OpmlController extends Controller
parent::__construct(Application::APP_ID, $request);
}
/**
* @return DataDownloadResponse<Http::STATUS_OK, 'application/xml', array{}>
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'GET', url: '/opml/export')]
public function export(): DataDownloadResponse {
public function export(): Response {
// https://github.com/AntennaPod/AntennaPod/blob/master/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlWriter.java
$xml = new \SimpleXMLElement('<opml/>', namespaceOrPrefix: 'http://xmlpull.org/v1/doc/features.html#indent-output');
$xml->addAttribute('version', '2.0');
@ -81,9 +85,12 @@ class OpmlController extends Controller
}
}
return new DataDownloadResponse((string) $xml->asXML(), 'repod-'.$dateCreated->getTimestamp().'.opml', ' application/xml');
return new DataDownloadResponse((string) $xml->asXML(), 'repod-'.$dateCreated->getTimestamp().'.opml', 'application/xml');
}
/**
* @return Response<Http::STATUS_OK, array{}>
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'POST', url: '/opml/import')]

View File

@ -6,10 +6,12 @@ namespace OCA\RePod\Controller;
use OCA\RePod\AppInfo\Application;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IRequest;
@ -21,10 +23,13 @@ class PageController extends Controller
parent::__construct(Application::APP_ID, $request);
}
/**
* @return TemplateResponse<Http::STATUS_OK, array{}>
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'GET', url: '/')]
public function index(): TemplateResponse {
public function index(): Response {
$csp = new ContentSecurityPolicy();
$csp->addAllowedImageDomain('*');
$csp->addAllowedMediaDomain('*');
@ -35,17 +40,23 @@ class PageController extends Controller
return $response;
}
/**
* @return TemplateResponse<Http::STATUS_OK, array{}>
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'GET', url: '/discover')]
public function discover(): TemplateResponse {
public function discover(): Response {
return $this->index();
}
/**
* @return TemplateResponse<Http::STATUS_OK, array{}>
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'GET', url: '/feed/{path}', requirements: ['path' => '.+'])]
public function feed(): TemplateResponse {
public function feed(): Response {
return $this->index();
}
}

View File

@ -13,6 +13,7 @@ use OCP\AppFramework\Http\Attribute\FrontpageRoute;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\Http\Client\IClientService;
use OCP\ICacheFactory;
use OCP\IRequest;
@ -28,10 +29,13 @@ class PodcastController extends Controller
parent::__construct(Application::APP_ID, $request);
}
/**
* @return JSONResponse<Http::STATUS_OK, PodcastData, array{}>
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'GET', url: '/podcast')]
public function index(string $url): JSONResponse {
public function index(string $url): Response {
$podcast = null;
if ($this->cacheFactory->isLocalCacheAvailable()) {
@ -59,6 +63,7 @@ class PodcastController extends Controller
/** @var Http::STATUS_* $returnStatusCode */
$returnStatusCode = $feed->getStatusCode();
/** @phpstan-ignore-next-line */
return new JSONResponse($podcast, $returnStatusCode);
}
}

View File

@ -4,13 +4,16 @@ declare(strict_types=1);
namespace OCA\RePod\Controller;
use OCA\GPodderSync\Core\PodcastData\PodcastData;
use OCA\RePod\AppInfo\Application;
use OCA\RePod\Service\MultiPodService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;
class SearchController extends Controller
@ -22,10 +25,13 @@ class SearchController extends Controller
parent::__construct(Application::APP_ID, $request);
}
/**
* @return JSONResponse<Http::STATUS_OK, PodcastData[], array{}>
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'GET', url: '/search')]
public function index(string $q): JSONResponse {
public function index(string $q): Response {
return new JSONResponse($this->multiPodService->search($q));
}
}

View File

@ -4,13 +4,16 @@ declare(strict_types=1);
namespace OCA\RePod\Controller;
use OCA\GPodderSync\Core\PodcastData\PodcastData;
use OCA\RePod\AppInfo\Application;
use OCA\RePod\Service\FyydService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;
class ToplistController extends Controller
@ -22,17 +25,23 @@ class ToplistController extends Controller
parent::__construct(Application::APP_ID, $request);
}
/**
* @return JSONResponse<Http::STATUS_OK, PodcastData[], array{}>
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'GET', url: '/toplist/hot')]
public function hot(): JSONResponse {
public function hot(): Response {
return new JSONResponse($this->fyydService->hot());
}
/**
* @return JSONResponse<Http::STATUS_OK, PodcastData[], array{}>
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'GET', url: '/toplist/new')]
public function new(): JSONResponse {
public function new(): Response {
return new JSONResponse($this->fyydService->latest());
}
}

View File

@ -2,5 +2,5 @@ parameters:
level: 9
paths:
- lib
ignoreErrors:
- '#Method [a-zA-Z0-9:\(\)\\_]+ return type with generic class OCP\\AppFramework\\Http\\[a-zA-Z]+ does not specify its types#'
includes:
- vendor/phpstan/phpstan-deprecation-rules/rules.neon