diff --git a/apps/theming/composer/composer/autoload_classmap.php b/apps/theming/composer/composer/autoload_classmap.php index 711ffa76dc8cc..d60aeecd8cd02 100644 --- a/apps/theming/composer/composer/autoload_classmap.php +++ b/apps/theming/composer/composer/autoload_classmap.php @@ -22,6 +22,7 @@ 'OCA\\Theming\\Migration\\InitBackgroundImagesMigration' => $baseDir . '/../lib/Migration/InitBackgroundImagesMigration.php', 'OCA\\Theming\\Migration\\MigrateAdminConfig' => $baseDir . '/../lib/Migration/MigrateAdminConfig.php', 'OCA\\Theming\\Migration\\MigrateUserConfig' => $baseDir . '/../lib/Migration/MigrateUserConfig.php', + 'OCA\\Theming\\ResponseDefinitions' => $baseDir . '/../lib/ResponseDefinitions.php', 'OCA\\Theming\\Service\\BackgroundService' => $baseDir . '/../lib/Service/BackgroundService.php', 'OCA\\Theming\\Service\\JSDataService' => $baseDir . '/../lib/Service/JSDataService.php', 'OCA\\Theming\\Service\\ThemeInjectionService' => $baseDir . '/../lib/Service/ThemeInjectionService.php', diff --git a/apps/theming/composer/composer/autoload_static.php b/apps/theming/composer/composer/autoload_static.php index b65ee4e90a8d9..bdf539bc59993 100644 --- a/apps/theming/composer/composer/autoload_static.php +++ b/apps/theming/composer/composer/autoload_static.php @@ -37,6 +37,7 @@ class ComposerStaticInitTheming 'OCA\\Theming\\Migration\\InitBackgroundImagesMigration' => __DIR__ . '/..' . '/../lib/Migration/InitBackgroundImagesMigration.php', 'OCA\\Theming\\Migration\\MigrateAdminConfig' => __DIR__ . '/..' . '/../lib/Migration/MigrateAdminConfig.php', 'OCA\\Theming\\Migration\\MigrateUserConfig' => __DIR__ . '/..' . '/../lib/Migration/MigrateUserConfig.php', + 'OCA\\Theming\\ResponseDefinitions' => __DIR__ . '/..' . '/../lib/ResponseDefinitions.php', 'OCA\\Theming\\Service\\BackgroundService' => __DIR__ . '/..' . '/../lib/Service/BackgroundService.php', 'OCA\\Theming\\Service\\JSDataService' => __DIR__ . '/..' . '/../lib/Service/JSDataService.php', 'OCA\\Theming\\Service\\ThemeInjectionService' => __DIR__ . '/..' . '/../lib/Service/ThemeInjectionService.php', diff --git a/apps/theming/lib/Capabilities.php b/apps/theming/lib/Capabilities.php index 5c063715f4387..fbb287aa41067 100644 --- a/apps/theming/lib/Capabilities.php +++ b/apps/theming/lib/Capabilities.php @@ -7,6 +7,7 @@ * @author Julien Veyssier * @author Julius Härtl * @author Morris Jobke + * @author Kate Döen * * @license GNU AGPL version 3 or any later version * @@ -64,6 +65,25 @@ public function __construct(ThemingDefaults $theming, Util $util, IURLGenerator /** * Return this classes capabilities + * + * @return array{ + * theming: array{ + * name: string, + * url: string, + * slogan: string, + * color: string, + * color-text: string, + * color-element: string, + * color-element-bright: string, + * color-element-dark: string, + * logo: string, + * background: string, + * background-plain: bool, + * background-default: bool, + * logoheader: string, + * favicon: string, + * }, + * } */ public function getCapabilities() { $backgroundLogo = $this->config->getAppValue('theming', 'backgroundMime', ''); diff --git a/apps/theming/lib/Controller/IconController.php b/apps/theming/lib/Controller/IconController.php index 1b16293a7f34c..86b45fbbc032e 100644 --- a/apps/theming/lib/Controller/IconController.php +++ b/apps/theming/lib/Controller/IconController.php @@ -8,6 +8,7 @@ * @author Julius Härtl * @author Michael Weimann * @author Roeland Jago Douma + * @author Kate Döen * * @license GNU AGPL version 3 or any later version * @@ -80,10 +81,15 @@ public function __construct( * @PublicPage * @NoCSRFRequired * - * @param $app string app name - * @param $image string image file name (svg required) - * @return FileDisplayResponse|NotFoundResponse + * Get a themed icon + * + * @param string $app ID of the app + * @param string $image image file name (svg required) + * @return FileDisplayResponse|NotFoundResponse * @throws \Exception + * + * 200: Themed icon returned + * 404: Themed icon not found */ public function getThemedIcon(string $app, string $image): Response { $color = $this->themingDefaults->getColorPrimary(); @@ -107,9 +113,12 @@ public function getThemedIcon(string $app, string $image): Response { * @PublicPage * @NoCSRFRequired * - * @param $app string app name - * @return FileDisplayResponse|DataDisplayResponse|NotFoundResponse + * @param string $app ID of the app + * @return DataDisplayResponse|FileDisplayResponse|NotFoundResponse * @throws \Exception + * + * 200: Favicon returned + * 404: Favicon not found */ public function getFavicon(string $app = 'core'): Response { $response = null; @@ -146,9 +155,12 @@ public function getFavicon(string $app = 'core'): Response { * @PublicPage * @NoCSRFRequired * - * @param $app string app name - * @return DataDisplayResponse|FileDisplayResponse|NotFoundResponse + * @param string $app ID of the app + * @return DataDisplayResponse|FileDisplayResponse|NotFoundResponse * @throws \Exception + * + * 200: Touch icon returned + * 404: Touch icon not found */ public function getTouchIcon(string $app = 'core'): Response { $response = null; diff --git a/apps/theming/lib/Controller/ThemingController.php b/apps/theming/lib/Controller/ThemingController.php index c247f2c9d566b..33af2b72183ce 100644 --- a/apps/theming/lib/Controller/ThemingController.php +++ b/apps/theming/lib/Controller/ThemingController.php @@ -18,6 +18,7 @@ * @author Robin Appelman * @author Roeland Jago Douma * @author Thomas Citharel + * @author Kate Döen * * @license GNU AGPL version 3 or any later version * @@ -46,6 +47,7 @@ use OCP\AppFramework\Http\DataDisplayResponse; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\FileDisplayResponse; +use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\NotFoundResponse; use OCP\Files\IAppData; use OCP\Files\NotFoundException; @@ -314,10 +316,15 @@ public function undoAll(): DataResponse { * @NoCSRFRequired * @NoSameSiteCookieRequired * - * @param string $key - * @param bool $useSvg - * @return FileDisplayResponse|NotFoundResponse + * Get an image + * + * @param string $key Key of the image + * @param bool $useSvg Return image as SVG + * @return FileDisplayResponse|NotFoundResponse * @throws NotPermittedException + * + * 200: Image returned + * 404: Image not found */ public function getImage(string $key, bool $useSvg = true) { try { @@ -347,7 +354,15 @@ public function getImage(string $key, bool $useSvg = true) { * @NoSameSiteCookieRequired * @NoTwoFactorRequired * - * @return DataDisplayResponse|NotFoundResponse + * Get the CSS stylesheet for a theme + * + * @param string $themeId ID of the theme + * @param bool $plain Let the browser decide the CSS priority + * @param bool $withCustomCss Include custom CSS + * @return DataDisplayResponse|NotFoundResponse + * + * 200: Stylesheet returned + * 404: Theme not found */ public function getThemeStylesheet(string $themeId, bool $plain = false, bool $withCustomCss = false) { $themes = $this->themesService->getThemes(); @@ -387,9 +402,13 @@ public function getThemeStylesheet(string $themeId, bool $plain = false, bool $w * @NoCSRFRequired * @PublicPage * - * @return Http\JSONResponse + * Get the manifest for an app + * + * @param string $app ID of the app + * @psalm-suppress LessSpecificReturnStatement The content of the Manifest doesn't need to be described in the return type + * @return JSONResponse */ - public function getManifest($app) { + public function getManifest(string $app) { $cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0'); if ($app === 'core' || $app === 'settings') { $name = $this->themingDefaults->getName(); @@ -407,6 +426,10 @@ public function getManifest($app) { } $description = $info['summary'] ?? ''; } + /** + * @var string $description + * @var string $shortName + */ $responseJS = [ 'name' => $name, 'short_name' => $shortName, @@ -431,7 +454,7 @@ public function getManifest($app) { ], 'display' => 'standalone' ]; - $response = new Http\JSONResponse($responseJS); + $response = new JSONResponse($responseJS); $response->cacheFor(3600); return $response; } diff --git a/apps/theming/lib/Controller/UserThemeController.php b/apps/theming/lib/Controller/UserThemeController.php index 6a58366c4f688..e0279bec1490e 100644 --- a/apps/theming/lib/Controller/UserThemeController.php +++ b/apps/theming/lib/Controller/UserThemeController.php @@ -11,6 +11,7 @@ * @author Janis Köhr * @author John Molakvoæ * @author Roeland Jago Douma + * @author Kate Döen * * @license GNU AGPL version 3 or any later version * @@ -32,6 +33,7 @@ use OCA\Theming\AppInfo\Application; use OCA\Theming\ITheme; +use OCA\Theming\ResponseDefinitions; use OCA\Theming\Service\BackgroundService; use OCA\Theming\Service\ThemesService; use OCA\Theming\ThemingDefaults; @@ -48,10 +50,13 @@ use OCP\IUserSession; use OCP\PreConditionNotMetException; +/** + * @psalm-import-type ThemingBackground from ResponseDefinitions + */ class UserThemeController extends OCSController { protected ?string $userId = null; - + private IConfig $config; private IUserSession $userSession; private ThemesService $themesService; @@ -84,8 +89,11 @@ public function __construct(string $appName, * Enable theme * * @param string $themeId the theme ID - * @return DataResponse - * @throws OCSBadRequestException|PreConditionNotMetException + * @return DataResponse, array{}> + * @throws OCSBadRequestException Enabling theme is not possible + * @throws PreConditionNotMetException + * + * 200: Theme enabled successfully */ public function enableTheme(string $themeId): DataResponse { $theme = $this->validateTheme($themeId); @@ -101,8 +109,11 @@ public function enableTheme(string $themeId): DataResponse { * Disable theme * * @param string $themeId the theme ID - * @return DataResponse - * @throws OCSBadRequestException|PreConditionNotMetException + * @return DataResponse, array{}> + * @throws OCSBadRequestException Disabling theme is not possible + * @throws PreConditionNotMetException + * + * 200: Theme disabled successfully */ public function disableTheme(string $themeId): DataResponse { $theme = $this->validateTheme($themeId); @@ -119,7 +130,8 @@ public function disableTheme(string $themeId): DataResponse { * * @param string $themeId the theme ID * @return ITheme - * @throws OCSBadRequestException|PreConditionNotMetException + * @throws OCSBadRequestException + * @throws PreConditionNotMetException */ private function validateTheme(string $themeId): ITheme { if ($themeId === '' || !$themeId) { @@ -143,6 +155,12 @@ private function validateTheme(string $themeId): ITheme { /** * @NoAdminRequired * @NoCSRFRequired + * + * Get the background image + * @return FileDisplayResponse|NotFoundResponse + * + * 200: Background image returned + * 404: Background image not found */ public function getBackground(): Http\Response { $file = $this->backgroundService->getBackground(); @@ -156,6 +174,10 @@ public function getBackground(): Http\Response { /** * @NoAdminRequired + * + * Delete the background + * + * @return JSONResponse */ public function deleteBackground(): JSONResponse { $currentVersion = (int)$this->config->getUserValue($this->userId, Application::APP_ID, 'userCacheBuster', '0'); @@ -169,6 +191,16 @@ public function deleteBackground(): JSONResponse { /** * @NoAdminRequired + * + * Set the background + * + * @param string $type Type of background + * @param string $value Path of the background image + * @param string|null $color Color for the background + * @return JSONResponse|JSONResponse + * + * 200: Background set successfully + * 400: Setting background is not possible */ public function setBackground(string $type = BackgroundService::BACKGROUND_DEFAULT, string $value = '', string $color = null): JSONResponse { $currentVersion = (int)$this->config->getUserValue($this->userId, Application::APP_ID, 'userCacheBuster', '0'); diff --git a/apps/theming/lib/ResponseDefinitions.php b/apps/theming/lib/ResponseDefinitions.php new file mode 100644 index 0000000000000..ddd8615e45502 --- /dev/null +++ b/apps/theming/lib/ResponseDefinitions.php @@ -0,0 +1,36 @@ + + * + * @author Kate Döen + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Theming; + +/** + * @psalm-type ThemingBackground = array{ + * backgroundImage: ?string, + * backgroundColor: string, + * version: int, + * } + */ +class ResponseDefinitions { +} diff --git a/apps/theming/openapi.json b/apps/theming/openapi.json index 9ba6919161f0e..9ab71122d4ed4 100644 --- a/apps/theming/openapi.json +++ b/apps/theming/openapi.json @@ -187,13 +187,6 @@ "responses": { "200": { "description": "Stylesheet returned", - "headers": { - "Content-Disposition": { - "schema": { - "type": "string" - } - } - }, "content": { "text/css": { "schema": { @@ -255,13 +248,6 @@ "responses": { "200": { "description": "Image returned", - "headers": { - "Content-Disposition": { - "schema": { - "type": "string" - } - } - }, "content": { "*/*": { "schema": { @@ -368,7 +354,8 @@ ], "properties": { "src": { - "type": "string" + "type": "string", + "minLength": 1 }, "type": { "type": "string" @@ -421,13 +408,6 @@ "responses": { "200": { "description": "Favicon returned", - "headers": { - "Content-Disposition": { - "schema": { - "type": "string" - } - } - }, "content": { "image/x-icon": { "schema": { @@ -491,13 +471,6 @@ "responses": { "200": { "description": "Touch icon returned", - "headers": { - "Content-Disposition": { - "schema": { - "type": "string" - } - } - }, "content": { "image/png": { "schema": { @@ -576,13 +549,6 @@ "responses": { "200": { "description": "Themed icon returned", - "headers": { - "Content-Disposition": { - "schema": { - "type": "string" - } - } - }, "content": { "image/svg+xml": { "schema": { @@ -644,13 +610,6 @@ "responses": { "200": { "description": "Background image returned", - "headers": { - "Content-Disposition": { - "schema": { - "type": "string" - } - } - }, "content": { "*/*": { "schema": { @@ -872,10 +831,7 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": { - "type": "object", - "additionalProperties": true - } + "data": {} } } } @@ -962,10 +918,7 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": { - "type": "object", - "additionalProperties": true - } + "data": {} } } }