diff options
Diffstat (limited to 'lib/public/AppFramework/Http')
32 files changed, 244 insertions, 134 deletions
diff --git a/lib/public/AppFramework/Http/Attribute/ARateLimit.php b/lib/public/AppFramework/Http/Attribute/ARateLimit.php index d92fcae1ae1..c06b1180ae3 100644 --- a/lib/public/AppFramework/Http/Attribute/ARateLimit.php +++ b/lib/public/AppFramework/Http/Attribute/ARateLimit.php @@ -17,6 +17,8 @@ namespace OCP\AppFramework\Http\Attribute; */ abstract class ARateLimit { /** + * @param int $limit The maximum number of requests that can be made in the given period in seconds. + * @param int $period The time period in seconds. * @since 27.0.0 */ public function __construct( diff --git a/lib/public/AppFramework/Http/Attribute/AppApiAdminAccessWithoutUser.php b/lib/public/AppFramework/Http/Attribute/AppApiAdminAccessWithoutUser.php new file mode 100644 index 00000000000..6b78fee41af --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/AppApiAdminAccessWithoutUser.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * Attribute for (sub)administrator controller methods that allow access for ExApps when the User is not set. + * + * @since 30.0.0 + */ +#[Attribute] +class AppApiAdminAccessWithoutUser { +} diff --git a/lib/public/AppFramework/Http/Attribute/AuthorizedAdminSetting.php b/lib/public/AppFramework/Http/Attribute/AuthorizedAdminSetting.php index e81f195b298..83101143fc9 100644 --- a/lib/public/AppFramework/Http/Attribute/AuthorizedAdminSetting.php +++ b/lib/public/AppFramework/Http/Attribute/AuthorizedAdminSetting.php @@ -25,7 +25,7 @@ class AuthorizedAdminSetting { * @since 27.0.0 */ public function __construct( - protected string $settings + protected string $settings, ) { } diff --git a/lib/public/AppFramework/Http/Attribute/BruteForceProtection.php b/lib/public/AppFramework/Http/Attribute/BruteForceProtection.php index 9fd97cdc3ed..0fc1a3b9b6d 100644 --- a/lib/public/AppFramework/Http/Attribute/BruteForceProtection.php +++ b/lib/public/AppFramework/Http/Attribute/BruteForceProtection.php @@ -23,7 +23,7 @@ class BruteForceProtection { * @since 27.0.0 */ public function __construct( - protected string $action + protected string $action, ) { } diff --git a/lib/public/AppFramework/Http/Attribute/CORS.php b/lib/public/AppFramework/Http/Attribute/CORS.php index 2c3eac362cf..ff639635635 100644 --- a/lib/public/AppFramework/Http/Attribute/CORS.php +++ b/lib/public/AppFramework/Http/Attribute/CORS.php @@ -12,7 +12,9 @@ namespace OCP\AppFramework\Http\Attribute; use Attribute; /** - * Attribute for controller methods that can also be accessed by not logged-in user + * Attribute for controller methods that can also be accessed by other websites. + * See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS for an explanation of the functionality and the security implications. + * See https://docs.nextcloud.com/server/latest/developer_manual/digging_deeper/rest_apis.html on how to implement it in your controller. * * @since 27.0.0 */ diff --git a/lib/public/AppFramework/Http/Attribute/OpenAPI.php b/lib/public/AppFramework/Http/Attribute/OpenAPI.php index 26d01937cfb..1b44b2a57fe 100644 --- a/lib/public/AppFramework/Http/Attribute/OpenAPI.php +++ b/lib/public/AppFramework/Http/Attribute/OpenAPI.php @@ -60,12 +60,12 @@ class OpenAPI { /** * @param self::SCOPE_*|string $scope Scopes are used to define different clients. - * It is recommended to go with the scopes available as self::SCOPE_* constants, - * but in exotic cases other APIs might need documentation as well, - * then a free string can be provided (but it should be `a-z` only). + * It is recommended to go with the scopes available as self::SCOPE_* constants, + * but in exotic cases other APIs might need documentation as well, + * then a free string can be provided (but it should be `a-z` only). * @param ?list<string> $tags Tags can be used to group routes inside a scope - * for easier implementation and reviewing of the API specification. - * It defaults to the controller name in snake_case (should be `a-z` and underscore only). + * for easier implementation and reviewing of the API specification. + * It defaults to the controller name in snake_case (should be `a-z` and underscore only). * @since 28.0.0 */ public function __construct( diff --git a/lib/public/AppFramework/Http/Attribute/PasswordConfirmationRequired.php b/lib/public/AppFramework/Http/Attribute/PasswordConfirmationRequired.php index 0f0f4b38040..c41e5aa2445 100644 --- a/lib/public/AppFramework/Http/Attribute/PasswordConfirmationRequired.php +++ b/lib/public/AppFramework/Http/Attribute/PasswordConfirmationRequired.php @@ -18,4 +18,21 @@ use Attribute; */ #[Attribute] class PasswordConfirmationRequired { + /** + * @param bool $strict - Whether password confirmation needs to happen in the request. + * + * @since 31.0.0 + */ + public function __construct( + protected bool $strict = false, + ) { + } + + /** + * @since 31.0.0 + */ + public function getStrict(): bool { + return $this->strict; + } + } diff --git a/lib/public/AppFramework/Http/Attribute/RequestHeader.php b/lib/public/AppFramework/Http/Attribute/RequestHeader.php new file mode 100644 index 00000000000..1d0fbbfa0c3 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/RequestHeader.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * This attribute allows documenting request headers and is primarily intended for OpenAPI documentation. + * It should be added whenever you use a request header in a controller method, in order to properly describe the header and its functionality. + * There are no checks that ensure the header is set, so you will still need to do this yourself in the controller method. + * + * @since 32.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +class RequestHeader { + /** + * @param lowercase-string $name The name of the request header + * @param non-empty-string $description The description of the request header + * @param bool $indirect Allow indirect usage of the header for example in a middleware. Enabling this turns off the check which ensures that the header must be referenced in the controller method. + */ + public function __construct( + protected string $name, + protected string $description, + protected bool $indirect = false, + ) { + } +} diff --git a/lib/public/AppFramework/Http/ContentSecurityPolicy.php b/lib/public/AppFramework/Http/ContentSecurityPolicy.php index 281aaa06eb8..11ec79bbdb7 100644 --- a/lib/public/AppFramework/Http/ContentSecurityPolicy.php +++ b/lib/public/AppFramework/Http/ContentSecurityPolicy.php @@ -38,7 +38,7 @@ class ContentSecurityPolicy extends EmptyContentSecurityPolicy { ]; /** * @var bool Whether inline CSS is allowed - * TODO: Disallow per default + * TODO: Disallow per default * @link https://github.com/owncloud/core/issues/13458 */ protected $inlineStyleAllowed = true; diff --git a/lib/public/AppFramework/Http/DataDisplayResponse.php b/lib/public/AppFramework/Http/DataDisplayResponse.php index 889c57a7901..e1ded910328 100644 --- a/lib/public/AppFramework/Http/DataDisplayResponse.php +++ b/lib/public/AppFramework/Http/DataDisplayResponse.php @@ -13,9 +13,9 @@ use OCP\AppFramework\Http; * Class DataDisplayResponse * * @since 8.1.0 - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> - * @template-extends Response<int, array<string, mixed>> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class DataDisplayResponse extends Response { /** diff --git a/lib/public/AppFramework/Http/DataDownloadResponse.php b/lib/public/AppFramework/Http/DataDownloadResponse.php index 80100137c48..ee6bcf0d0c5 100644 --- a/lib/public/AppFramework/Http/DataDownloadResponse.php +++ b/lib/public/AppFramework/Http/DataDownloadResponse.php @@ -13,10 +13,10 @@ use OCP\AppFramework\Http; * Class DataDownloadResponse * * @since 8.0.0 - * @template S of int + * @template S of Http::STATUS_* * @template C of string * @template H of array<string, mixed> - * @template-extends DownloadResponse<int, string, array<string, mixed>> + * @template-extends DownloadResponse<Http::STATUS_*, string, array<string, mixed>> */ class DataDownloadResponse extends DownloadResponse { /** diff --git a/lib/public/AppFramework/Http/DataResponse.php b/lib/public/AppFramework/Http/DataResponse.php index 2ebb66f9e73..2b54ce848ef 100644 --- a/lib/public/AppFramework/Http/DataResponse.php +++ b/lib/public/AppFramework/Http/DataResponse.php @@ -14,10 +14,10 @@ use OCP\AppFramework\Http; * for responders to transform * @since 8.0.0 * @psalm-type DataResponseType = array|int|float|string|bool|object|null|\stdClass|\JsonSerializable - * @template S of int + * @template S of Http::STATUS_* * @template-covariant T of DataResponseType * @template H of array<string, mixed> - * @template-extends Response<int, array<string, mixed>> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class DataResponse extends Response { /** diff --git a/lib/public/AppFramework/Http/DownloadResponse.php b/lib/public/AppFramework/Http/DownloadResponse.php index 058b3070297..190de022d36 100644 --- a/lib/public/AppFramework/Http/DownloadResponse.php +++ b/lib/public/AppFramework/Http/DownloadResponse.php @@ -12,10 +12,10 @@ use OCP\AppFramework\Http; /** * Prompts the user to download the a file * @since 7.0.0 - * @template S of int + * @template S of Http::STATUS_* * @template C of string * @template H of array<string, mixed> - * @template-extends Response<int, array<string, mixed>> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class DownloadResponse extends Response { /** diff --git a/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php index 5b4cf7eab8b..b8bbfdb7d67 100644 --- a/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php +++ b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php @@ -26,7 +26,7 @@ class EmptyContentSecurityPolicy { protected $strictDynamicAllowedOnScripts = null; /** * @var bool Whether eval in JS scripts is allowed - * TODO: Disallow per default + * TODO: Disallow per default * @link https://github.com/owncloud/core/issues/11925 */ protected $evalScriptAllowed = null; @@ -36,7 +36,7 @@ class EmptyContentSecurityPolicy { protected $allowedScriptDomains = null; /** * @var bool Whether inline CSS is allowed - * TODO: Disallow per default + * TODO: Disallow per default * @link https://github.com/owncloud/core/issues/13458 */ protected $inlineStyleAllowed = null; @@ -89,7 +89,7 @@ class EmptyContentSecurityPolicy { } /** - * Use the according JS nonce + * The base64 encoded nonce to be used for script source. * This method is only for CSPMiddleware, custom values are ignored in mergePolicies of ContentSecurityPolicyManager * * @param string $nonce @@ -106,7 +106,7 @@ class EmptyContentSecurityPolicy { * @param bool $state * @return $this * @since 8.1.0 - * @deprecated Eval should not be used anymore. Please update your scripts. This function will stop functioning in a future version of Nextcloud. + * @deprecated 17.0.0 Eval should not be used anymore. Please update your scripts. This function will stop functioning in a future version of Nextcloud. */ public function allowEvalScript($state = true) { $this->evalScriptAllowed = $state; @@ -448,7 +448,7 @@ class EmptyContentSecurityPolicy { if ($this->strictDynamicAllowed) { $scriptSrc .= '\'strict-dynamic\' '; } - $scriptSrc .= '\'nonce-'.base64_encode($this->jsNonce).'\''; + $scriptSrc .= '\'nonce-' . $this->jsNonce . '\''; $allowedScriptDomains = array_flip($this->allowedScriptDomains); unset($allowedScriptDomains['\'self\'']); $this->allowedScriptDomains = array_flip($allowedScriptDomains); diff --git a/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php b/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php index d18cad25acc..b724b3a72ad 100644 --- a/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php +++ b/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php @@ -20,7 +20,9 @@ class BeforeLoginTemplateRenderedEvent extends Event { /** * @since 28.0.0 */ - public function __construct(private TemplateResponse $response) { + public function __construct( + private TemplateResponse $response, + ) { parent::__construct(); } diff --git a/lib/public/AppFramework/Http/FileDisplayResponse.php b/lib/public/AppFramework/Http/FileDisplayResponse.php index 0cc51f7c59f..c18404b7d91 100644 --- a/lib/public/AppFramework/Http/FileDisplayResponse.php +++ b/lib/public/AppFramework/Http/FileDisplayResponse.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -13,9 +14,9 @@ use OCP\Files\SimpleFS\ISimpleFile; * Class FileDisplayResponse * * @since 11.0.0 - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> - * @template-extends Response<int, array<string, mixed>> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class FileDisplayResponse extends Response implements ICallbackResponse { /** @var File|ISimpleFile */ diff --git a/lib/public/AppFramework/Http/JSONResponse.php b/lib/public/AppFramework/Http/JSONResponse.php index 1614cb8ce01..a226e29a1b5 100644 --- a/lib/public/AppFramework/Http/JSONResponse.php +++ b/lib/public/AppFramework/Http/JSONResponse.php @@ -12,10 +12,10 @@ use OCP\AppFramework\Http; /** * A renderer for JSON calls * @since 6.0.0 - * @template S of int - * @template-covariant T of array|object|\stdClass|\JsonSerializable + * @template S of Http::STATUS_* + * @template-covariant T of null|string|int|float|bool|array|\stdClass|\JsonSerializable * @template H of array<string, mixed> - * @template-extends Response<int, array<string, mixed>> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class JSONResponse extends Response { /** @@ -23,6 +23,11 @@ class JSONResponse extends Response { * @var T */ protected $data; + /** + * Additional `json_encode` flags + * @var int + */ + protected $encodeFlags; /** @@ -30,12 +35,20 @@ class JSONResponse extends Response { * @param T $data the object or array that should be transformed * @param S $statusCode the Http status code, defaults to 200 * @param H $headers + * @param int $encodeFlags Additional `json_encode` flags * @since 6.0.0 + * @since 30.0.0 Added `$encodeFlags` param */ - public function __construct(mixed $data = [], int $statusCode = Http::STATUS_OK, array $headers = []) { + public function __construct( + mixed $data = [], + int $statusCode = Http::STATUS_OK, + array $headers = [], + int $encodeFlags = 0, + ) { parent::__construct($statusCode, $headers); $this->data = $data; + $this->encodeFlags = $encodeFlags; $this->addHeader('Content-Type', 'application/json; charset=utf-8'); } @@ -45,16 +58,19 @@ class JSONResponse extends Response { * @return string the rendered json * @since 6.0.0 * @throws \Exception If data could not get encoded + * + * @psalm-taint-escape has_quotes + * @psalm-taint-escape html */ public function render() { - return json_encode($this->data, JSON_HEX_TAG | JSON_THROW_ON_ERROR); + return json_encode($this->data, JSON_HEX_TAG | JSON_THROW_ON_ERROR | $this->encodeFlags, 2048); } /** * Sets values in the data json array * @psalm-suppress InvalidTemplateParam * @param T $data an array or object which will be transformed - * to JSON + * to JSON * @return JSONResponse Reference to this object * @since 6.0.0 - return value was added in 7.0.0 */ diff --git a/lib/public/AppFramework/Http/NotFoundResponse.php b/lib/public/AppFramework/Http/NotFoundResponse.php index 9ebefe69be1..137d1a26655 100644 --- a/lib/public/AppFramework/Http/NotFoundResponse.php +++ b/lib/public/AppFramework/Http/NotFoundResponse.php @@ -12,9 +12,9 @@ use OCP\AppFramework\Http; /** * A generic 404 response showing an 404 error page as well to the end-user * @since 8.1.0 - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> - * @template-extends TemplateResponse<int, array<string, mixed>> + * @template-extends TemplateResponse<Http::STATUS_*, array<string, mixed>> */ class NotFoundResponse extends TemplateResponse { /** diff --git a/lib/public/AppFramework/Http/RedirectResponse.php b/lib/public/AppFramework/Http/RedirectResponse.php index 41fc4d83856..74847205976 100644 --- a/lib/public/AppFramework/Http/RedirectResponse.php +++ b/lib/public/AppFramework/Http/RedirectResponse.php @@ -12,9 +12,9 @@ use OCP\AppFramework\Http; /** * Redirects to a different URL * @since 7.0.0 - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> - * @template-extends Response<int, array<string, mixed>> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class RedirectResponse extends Response { private $redirectURL; diff --git a/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php b/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php index 3e2fcf6f6c7..0a0c04f671d 100644 --- a/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php +++ b/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php @@ -16,9 +16,9 @@ use OCP\IURLGenerator; * * @since 16.0.0 * @deprecated 23.0.0 Use RedirectResponse() with IURLGenerator::linkToDefaultPageUrl() instead - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> - * @template-extends RedirectResponse<int, array<string, mixed>> + * @template-extends RedirectResponse<Http::STATUS_*, array<string, mixed>> */ class RedirectToDefaultAppResponse extends RedirectResponse { /** @@ -30,8 +30,7 @@ class RedirectToDefaultAppResponse extends RedirectResponse { * @deprecated 23.0.0 Use RedirectResponse() with IURLGenerator::linkToDefaultPageUrl() instead */ public function __construct(int $status = Http::STATUS_SEE_OTHER, array $headers = []) { - /** @var IURLGenerator $urlGenerator */ - $urlGenerator = \OC::$server->get(IURLGenerator::class); + $urlGenerator = \OCP\Server::get(IURLGenerator::class); parent::__construct($urlGenerator->linkToDefaultPageUrl(), $status, $headers); } } diff --git a/lib/public/AppFramework/Http/Response.php b/lib/public/AppFramework/Http/Response.php index 0da290ad48b..bdebb12c00d 100644 --- a/lib/public/AppFramework/Http/Response.php +++ b/lib/public/AppFramework/Http/Response.php @@ -18,7 +18,7 @@ use Psr\Log\LoggerInterface; * * It handles headers, HTTP status code, last modified and ETag. * @since 6.0.0 - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> */ class Response { @@ -93,11 +93,10 @@ class Response { // Set expires header $expires = new \DateTime(); - /** @var ITimeFactory $time */ $time = \OCP\Server::get(ITimeFactory::class); $expires->setTimestamp($time->getTime()); - $expires->add(new \DateInterval('PT'.$cacheSeconds.'S')); - $this->addHeader('Expires', $expires->format(\DateTimeInterface::RFC2822)); + $expires->add(new \DateInterval('PT' . $cacheSeconds . 'S')); + $this->addHeader('Expires', $expires->format(\DateTimeInterface::RFC7231)); } else { $this->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); unset($this->headers['Expires']); @@ -111,8 +110,8 @@ class Response { * @param string $name The name of the cookie * @param string $value The value of the cookie * @param \DateTime|null $expireDate Date on that the cookie should expire, if set - * to null cookie will be considered as session - * cookie. + * to null cookie will be considered as session + * cookie. * @param string $sameSite The samesite value of the cookie. Defaults to Lax. Other possibilities are Strict or None * @return $this * @since 8.0.0 @@ -184,10 +183,10 @@ class Response { if ($this->status === Http::STATUS_NOT_MODIFIED && stripos($name, 'x-') === 0) { /** @var IConfig $config */ - $config = \OC::$server->get(IConfig::class); + $config = \OCP\Server::get(IConfig::class); if ($config->getSystemValueBool('debug', false)) { - \OC::$server->get(LoggerInterface::class)->error('Setting custom header on a 304 is not supported (Header: {header})', [ + \OCP\Server::get(LoggerInterface::class)->error('Setting custom header on a 304 is not supported (Header: {header})', [ 'header' => $name, ]); } @@ -229,7 +228,7 @@ class Response { /** * @psalm-suppress UndefinedClass */ - $request = \OC::$server->get(IRequest::class); + $request = \OCP\Server::get(IRequest::class); $mergeWith = [ 'X-Request-Id' => $request->getId(), 'Cache-Control' => 'no-cache, no-store, must-revalidate', @@ -239,7 +238,7 @@ class Response { ]; if ($this->lastModified) { - $mergeWith['Last-Modified'] = $this->lastModified->format(\DateTimeInterface::RFC2822); + $mergeWith['Last-Modified'] = $this->lastModified->format(\DateTimeInterface::RFC7231); } if ($this->ETag) { @@ -289,7 +288,7 @@ class Response { /** * Get the currently used Content-Security-Policy * @return EmptyContentSecurityPolicy|null Used Content-Security-Policy or null if - * none specified. + * none specified. * @since 8.1.0 */ public function getContentSecurityPolicy() { diff --git a/lib/public/AppFramework/Http/StandaloneTemplateResponse.php b/lib/public/AppFramework/Http/StandaloneTemplateResponse.php index f729bd772fb..244a6b80f9f 100644 --- a/lib/public/AppFramework/Http/StandaloneTemplateResponse.php +++ b/lib/public/AppFramework/Http/StandaloneTemplateResponse.php @@ -7,6 +7,8 @@ declare(strict_types=1); */ namespace OCP\AppFramework\Http; +use OCP\AppFramework\Http; + /** * A template response that does not emit the loadAdditionalScripts events. * @@ -14,9 +16,9 @@ namespace OCP\AppFramework\Http; * full nextcloud UI. Like the 2FA page, or the grant page in the login flow. * * @since 16.0.0 - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> - * @template-extends TemplateResponse<int, array<string, mixed>> + * @template-extends TemplateResponse<Http::STATUS_*, array<string, mixed>> */ class StandaloneTemplateResponse extends TemplateResponse { } diff --git a/lib/public/AppFramework/Http/StreamResponse.php b/lib/public/AppFramework/Http/StreamResponse.php index 1039e20e5c5..d0e6e3e148a 100644 --- a/lib/public/AppFramework/Http/StreamResponse.php +++ b/lib/public/AppFramework/Http/StreamResponse.php @@ -13,9 +13,9 @@ use OCP\AppFramework\Http; * Class StreamResponse * * @since 8.1.0 - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> - * @template-extends Response<int, array<string, mixed>> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class StreamResponse extends Response implements ICallbackResponse { /** @var string */ diff --git a/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php b/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php index cddf5d19171..281bb559a10 100644 --- a/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php +++ b/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php @@ -1,58 +1,29 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http\Template; -use OCP\Util; - /** * Class LinkMenuAction * * @since 14.0.0 */ class ExternalShareMenuAction extends SimpleMenuAction { - /** @var string */ - private $owner; - - /** @var string */ - private $displayname; - - /** @var string */ - private $shareName; /** * ExternalShareMenuAction constructor. * - * @param string $label - * @param string $icon - * @param string $owner - * @param string $displayname - * @param string $shareName + * @param string $label Translated label + * @param string $icon Icon CSS class + * @param string $owner Owner user ID (unused) + * @param string $displayname Display name of the owner (unused) + * @param string $shareName Name of the share (unused) * @since 14.0.0 */ public function __construct(string $label, string $icon, string $owner, string $displayname, string $shareName) { parent::__construct('save', $label, $icon); - $this->owner = $owner; - $this->displayname = $displayname; - $this->shareName = $shareName; - } - - /** - * @since 14.0.0 - */ - public function render(): string { - return '<li>' . - ' <button id="save-external-share" class="icon ' . Util::sanitizeHTML($this->getIcon()) . '" data-protected="false" data-owner-display-name="' . Util::sanitizeHTML($this->displayname) . '" data-owner="' . Util::sanitizeHTML($this->owner) . '" data-name="' . Util::sanitizeHTML($this->shareName) . '">' . Util::sanitizeHTML($this->getLabel()) . '</button>' . - '</li>' . - '<li id="external-share-menu-item" class="hidden">' . - ' <span class="menuitem">' . - ' <form class="save-form" action="#">' . - ' <input type="text" id="remote_address" placeholder="user@yourNextcloud.org">' . - ' <input type="submit" value=" " id="save-button-confirm" class="icon-confirm" disabled="disabled"></button>' . - ' </form>' . - ' </span>' . - '</li>'; } } diff --git a/lib/public/AppFramework/Http/Template/IMenuAction.php b/lib/public/AppFramework/Http/Template/IMenuAction.php index d3962300923..124e95fe019 100644 --- a/lib/public/AppFramework/Http/Template/IMenuAction.php +++ b/lib/public/AppFramework/Http/Template/IMenuAction.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -18,12 +19,16 @@ interface IMenuAction { public function getId(): string; /** + * The translated label of the menu item. + * * @since 14.0.0 * @return string */ public function getLabel(): string; /** + * The link this menu item points to. + * * @since 14.0.0 * @return string */ @@ -36,6 +41,9 @@ interface IMenuAction { public function getPriority(): int; /** + * Custom render function. + * The returned HTML will be wrapped within a listitem element (`<li>...</li>`). + * * @since 14.0.0 * @return string */ diff --git a/lib/public/AppFramework/Http/Template/LinkMenuAction.php b/lib/public/AppFramework/Http/Template/LinkMenuAction.php index 69e835f6b82..391802a1dce 100644 --- a/lib/public/AppFramework/Http/Template/LinkMenuAction.php +++ b/lib/public/AppFramework/Http/Template/LinkMenuAction.php @@ -1,12 +1,11 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http\Template; -use OCP\Util; - /** * Class LinkMenuAction * @@ -22,24 +21,6 @@ class LinkMenuAction extends SimpleMenuAction { * @since 14.0.0 */ public function __construct(string $label, string $icon, string $link) { - parent::__construct('directLink-container', $label, $icon, $link); - } - - /** - * @return string - * @since 14.0.0 - */ - public function render(): string { - return '<li>' . - '<a id="directLink-container">' . - '<span class="icon ' . Util::sanitizeHTML($this->getIcon()) . '"></span>' . - '<label for="directLink">' . Util::sanitizeHTML($this->getLabel()) . '</label>' . - '</a>' . - '</li>' . - '<li>' . - '<span class="menuitem">' . - '<input id="directLink" type="text" readonly="" value="' . Util::sanitizeHTML($this->getLink()) . '">' . - '</span>' . - '</li>'; + parent::__construct('directLink', $label, $icon, $link); } } diff --git a/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php b/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php index c12cf087755..4c156cdecea 100644 --- a/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php +++ b/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -8,18 +9,20 @@ namespace OCP\AppFramework\Http\Template; use InvalidArgumentException; use OCP\AppFramework\Http; use OCP\AppFramework\Http\TemplateResponse; +use OCP\IInitialStateService; /** * Class PublicTemplateResponse * * @since 14.0.0 * @template H of array<string, mixed> - * @template S of int - * @template-extends TemplateResponse<int, array<string, mixed>> + * @template S of Http::STATUS_* + * @template-extends TemplateResponse<Http::STATUS_*, array<string, mixed>> */ class PublicTemplateResponse extends TemplateResponse { private $headerTitle = ''; private $headerDetails = ''; + /** @var IMenuAction[] */ private $headerActions = []; private $footerVisible = true; @@ -33,9 +36,39 @@ class PublicTemplateResponse extends TemplateResponse { * @param H $headers * @since 14.0.0 */ - public function __construct(string $appName, string $templateName, array $params = [], $status = Http::STATUS_OK, array $headers = []) { + public function __construct( + string $appName, + string $templateName, + array $params = [], + $status = Http::STATUS_OK, + array $headers = [], + ) { parent::__construct($appName, $templateName, $params, 'public', $status, $headers); - \OC_Util::addScript('core', 'public/publicpage'); + \OCP\Util::addScript('core', 'public-page-menu'); + \OCP\Util::addScript('core', 'public-page-user-menu'); + + $state = \OCP\Server::get(IInitialStateService::class); + $state->provideLazyInitialState('core', 'public-page-menu', function () { + $response = []; + foreach ($this->headerActions as $action) { + // First try in it is a custom action that provides rendered HTML + $rendered = $action->render(); + if ($rendered === '') { + // If simple action, add the response data + if ($action instanceof SimpleMenuAction) { + $response[] = $action->getData(); + } + } else { + // custom action so add the rendered output + $response[] = [ + 'id' => $action->getId(), + 'label' => $action->getLabel(), + 'html' => $rendered, + ]; + } + } + return $response; + }); } /** @@ -138,6 +171,6 @@ class PublicTemplateResponse extends TemplateResponse { 'template' => $this, ]); $this->setParams($params); - return parent::render(); + return parent::render(); } } diff --git a/lib/public/AppFramework/Http/Template/SimpleMenuAction.php b/lib/public/AppFramework/Http/Template/SimpleMenuAction.php index 2bb60975f26..03cb9b4c7ea 100644 --- a/lib/public/AppFramework/Http/Template/SimpleMenuAction.php +++ b/lib/public/AppFramework/Http/Template/SimpleMenuAction.php @@ -1,12 +1,11 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\AppFramework\Http\Template; -use OCP\Util; - /** * Class SimpleMenuAction * @@ -68,6 +67,8 @@ class SimpleMenuAction implements IMenuAction { } /** + * The icon CSS class to use. + * * @return string * @since 14.0.0 */ @@ -92,14 +93,28 @@ class SimpleMenuAction implements IMenuAction { } /** + * Custom render function. + * The returned HTML must be wrapped within a listitem (`<li>...</li>`). + * * If an empty string is returned, the default design is used (based on the label and link specified). * @return string * @since 14.0.0 */ public function render(): string { - $detailContent = ($this->detail !== '') ? ' <span class="download-size">(' . Util::sanitizeHTML($this->detail) . ')</span>' : ''; - return sprintf( - '<li id="%s"><a href="%s"><span class="icon %s"></span>%s %s</a></li>', - Util::sanitizeHTML($this->id), Util::sanitizeHTML($this->link), Util::sanitizeHTML($this->icon), Util::sanitizeHTML($this->label), $detailContent - ); + return ''; + } + + /** + * Return JSON data to let the frontend render the menu entry. + * @return array{id: string, label: string, href: string, icon: string, details: string|null} + * @since 31.0.0 + */ + public function getData(): array { + return [ + 'id' => $this->id, + 'label' => $this->label, + 'href' => $this->link, + 'icon' => $this->icon, + 'details' => $this->detail, + ]; } } diff --git a/lib/public/AppFramework/Http/TemplateResponse.php b/lib/public/AppFramework/Http/TemplateResponse.php index f9ac80cdc80..af37a1a2313 100644 --- a/lib/public/AppFramework/Http/TemplateResponse.php +++ b/lib/public/AppFramework/Http/TemplateResponse.php @@ -1,21 +1,27 @@ <?php +declare(strict_types=1); + + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-only */ + namespace OCP\AppFramework\Http; use OCP\AppFramework\Http; +use OCP\Server; +use OCP\Template\ITemplateManager; /** * Response for a normal template * @since 6.0.0 * - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> - * @template-extends Response<int, array<string, mixed>> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class TemplateResponse extends Response { /** @@ -72,7 +78,7 @@ class TemplateResponse extends Response { * @param string $appName the name of the app to load the template from * @param string $templateName the name of the template * @param array $params an array of parameters which should be passed to the - * template + * template * @param string $renderAs how the page should be rendered, defaults to user * @param S $status * @param H $headers @@ -180,7 +186,7 @@ class TemplateResponse extends Response { $renderAs = $this->renderAs; } - $template = new \OCP\Template($this->appName, $this->templateName, $renderAs); + $template = Server::get(ITemplateManager::class)->getTemplate($this->appName, $this->templateName, $renderAs); foreach ($this->params as $key => $value) { $template->assign($key, $value); diff --git a/lib/public/AppFramework/Http/TextPlainResponse.php b/lib/public/AppFramework/Http/TextPlainResponse.php index e7c728c37ab..9dfa2c5544d 100644 --- a/lib/public/AppFramework/Http/TextPlainResponse.php +++ b/lib/public/AppFramework/Http/TextPlainResponse.php @@ -12,9 +12,9 @@ use OCP\AppFramework\Http; /** * A renderer for text responses * @since 22.0.0 - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> - * @template-extends Response<int, array<string, mixed>> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class TextPlainResponse extends Response { /** @var string */ diff --git a/lib/public/AppFramework/Http/TooManyRequestsResponse.php b/lib/public/AppFramework/Http/TooManyRequestsResponse.php index b7b0a98c9e1..f7084ec768d 100644 --- a/lib/public/AppFramework/Http/TooManyRequestsResponse.php +++ b/lib/public/AppFramework/Http/TooManyRequestsResponse.php @@ -8,14 +8,15 @@ declare(strict_types=1); namespace OCP\AppFramework\Http; use OCP\AppFramework\Http; -use OCP\Template; +use OCP\Server; +use OCP\Template\ITemplateManager; /** * A generic 429 response showing an 404 error page as well to the end-user * @since 19.0.0 - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> - * @template-extends Response<int, array<string, mixed>> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class TooManyRequestsResponse extends Response { /** @@ -34,7 +35,7 @@ class TooManyRequestsResponse extends Response { * @since 19.0.0 */ public function render() { - $template = new Template('core', '429', 'blank'); + $template = Server::get(ITemplateManager::class)->getTemplate('core', '429', TemplateResponse::RENDER_AS_BLANK); return $template->fetchPage(); } } diff --git a/lib/public/AppFramework/Http/ZipResponse.php b/lib/public/AppFramework/Http/ZipResponse.php index 3b9e251d332..a552eb1294f 100644 --- a/lib/public/AppFramework/Http/ZipResponse.php +++ b/lib/public/AppFramework/Http/ZipResponse.php @@ -15,9 +15,9 @@ use OCP\IRequest; * Public library to send several files in one zip archive. * * @since 15.0.0 - * @template S of int + * @template S of Http::STATUS_* * @template H of array<string, mixed> - * @template-extends Response<int, array<string, mixed>> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> */ class ZipResponse extends Response implements ICallbackResponse { /** @var array{internalName: string, resource: resource, size: int, time: int}[] Files to be added to the zip response */ |