diff options
Diffstat (limited to 'apps/dav/lib/Controller')
-rw-r--r-- | apps/dav/lib/Controller/BirthdayCalendarController.php | 77 | ||||
-rw-r--r-- | apps/dav/lib/Controller/DirectController.php | 81 | ||||
-rw-r--r-- | apps/dav/lib/Controller/ExampleContentController.php | 98 | ||||
-rw-r--r-- | apps/dav/lib/Controller/InvitationResponseController.php | 70 | ||||
-rw-r--r-- | apps/dav/lib/Controller/OutOfOfficeController.php | 48 | ||||
-rw-r--r-- | apps/dav/lib/Controller/UpcomingEventsController.php | 57 |
6 files changed, 236 insertions, 195 deletions
diff --git a/apps/dav/lib/Controller/BirthdayCalendarController.php b/apps/dav/lib/Controller/BirthdayCalendarController.php index 5df13cefe97..f6bfb229a9c 100644 --- a/apps/dav/lib/Controller/BirthdayCalendarController.php +++ b/apps/dav/lib/Controller/BirthdayCalendarController.php @@ -1,31 +1,16 @@ <?php + /** - * @copyright 2017, Georg Ehrke <oc.list@georgehrke.com> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @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 <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\DAV\Controller; use OCA\DAV\BackgroundJob\GenerateBirthdayCalendarBackgroundJob; use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\Settings\CalDAVSettings; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\Response; use OCP\BackgroundJob\IJobList; @@ -38,31 +23,6 @@ use OCP\IUserManager; class BirthdayCalendarController extends Controller { /** - * @var IDBConnection - */ - protected $db; - - /** - * @var IConfig - */ - protected $config; - - /** - * @var IUserManager - */ - protected $userManager; - - /** - * @var CalDavBackend - */ - protected $caldavBackend; - - /** - * @var IJobList - */ - protected $jobList; - - /** * BirthdayCalendar constructor. * * @param string $appName @@ -71,30 +31,29 @@ class BirthdayCalendarController extends Controller { * @param IConfig $config * @param IJobList $jobList * @param IUserManager $userManager - * @param CalDavBackend $calDavBackend + * @param CalDavBackend $caldavBackend */ - public function __construct($appName, IRequest $request, - IDBConnection $db, IConfig $config, - IJobList $jobList, - IUserManager $userManager, - CalDavBackend $calDavBackend) { + public function __construct( + $appName, + IRequest $request, + protected IDBConnection $db, + protected IConfig $config, + protected IJobList $jobList, + protected IUserManager $userManager, + protected CalDavBackend $caldavBackend, + ) { parent::__construct($appName, $request); - $this->db = $db; - $this->config = $config; - $this->userManager = $userManager; - $this->jobList = $jobList; - $this->caldavBackend = $calDavBackend; } /** * @return Response - * @AuthorizedAdminSetting(settings=OCA\DAV\Settings\CalDAVSettings) */ + #[AuthorizedAdminSetting(settings: CalDAVSettings::class)] public function enable() { $this->config->setAppValue($this->appName, 'generateBirthdayCalendar', 'yes'); // add background job for each user - $this->userManager->callForSeenUsers(function (IUser $user) { + $this->userManager->callForSeenUsers(function (IUser $user): void { $this->jobList->add(GenerateBirthdayCalendarBackgroundJob::class, [ 'userId' => $user->getUID(), ]); @@ -105,8 +64,8 @@ class BirthdayCalendarController extends Controller { /** * @return Response - * @AuthorizedAdminSetting(settings=OCA\DAV\Settings\CalDAVSettings) */ + #[AuthorizedAdminSetting(settings: CalDAVSettings::class)] public function disable() { $this->config->setAppValue($this->appName, 'generateBirthdayCalendar', 'no'); diff --git a/apps/dav/lib/Controller/DirectController.php b/apps/dav/lib/Controller/DirectController.php index 0f618e46b22..ea209168123 100644 --- a/apps/dav/lib/Controller/DirectController.php +++ b/apps/dav/lib/Controller/DirectController.php @@ -3,33 +3,15 @@ declare(strict_types=1); /** - * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Iscle <albertiscle9@gmail.com> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Kate Döen <kate.doeen@nextcloud.com> - * - * @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 <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\DAV\Controller; use OCA\DAV\Db\Direct; use OCA\DAV\Db\DirectMapper; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSBadRequestException; use OCP\AppFramework\OCS\OCSForbiddenException; @@ -46,50 +28,21 @@ use OCP\Security\ISecureRandom; class DirectController extends OCSController { - /** @var IRootFolder */ - private $rootFolder; - - /** @var string */ - private $userId; - - /** @var DirectMapper */ - private $mapper; - - /** @var ISecureRandom */ - private $random; - - /** @var ITimeFactory */ - private $timeFactory; - - /** @var IURLGenerator */ - private $urlGenerator; - - /** @var IEventDispatcher */ - private $eventDispatcher; - - public function __construct(string $appName, + public function __construct( + string $appName, IRequest $request, - IRootFolder $rootFolder, - string $userId, - DirectMapper $mapper, - ISecureRandom $random, - ITimeFactory $timeFactory, - IURLGenerator $urlGenerator, - IEventDispatcher $eventDispatcher) { + private IRootFolder $rootFolder, + private string $userId, + private DirectMapper $mapper, + private ISecureRandom $random, + private ITimeFactory $timeFactory, + private IURLGenerator $urlGenerator, + private IEventDispatcher $eventDispatcher, + ) { parent::__construct($appName, $request); - - $this->rootFolder = $rootFolder; - $this->userId = $userId; - $this->mapper = $mapper; - $this->random = $random; - $this->timeFactory = $timeFactory; - $this->urlGenerator = $urlGenerator; - $this->eventDispatcher = $eventDispatcher; } /** - * @NoAdminRequired - * * Get a direct link to a file * * @param int $fileId ID of the file @@ -101,12 +54,13 @@ class DirectController extends OCSController { * * 200: Direct link returned */ + #[NoAdminRequired] public function getUrl(int $fileId, int $expirationTime = 60 * 60 * 8): DataResponse { $userFolder = $this->rootFolder->getUserFolder($this->userId); - $files = $userFolder->getById($fileId); + $file = $userFolder->getFirstNodeById($fileId); - if ($files === []) { + if (!$file) { throw new OCSNotFoundException(); } @@ -114,7 +68,6 @@ class DirectController extends OCSController { throw new OCSBadRequestException('Expiration time should be greater than 0 and less than or equal to ' . (60 * 60 * 24)); } - $file = array_shift($files); if (!($file instanceof File)) { throw new OCSBadRequestException('Direct download only works for files'); } @@ -137,7 +90,7 @@ class DirectController extends OCSController { $this->mapper->insert($direct); - $url = $this->urlGenerator->getAbsoluteURL('remote.php/direct/'.$token); + $url = $this->urlGenerator->getAbsoluteURL('remote.php/direct/' . $token); return new DataResponse([ 'url' => $url, diff --git a/apps/dav/lib/Controller/ExampleContentController.php b/apps/dav/lib/Controller/ExampleContentController.php new file mode 100644 index 00000000000..e20ee4b7f49 --- /dev/null +++ b/apps/dav/lib/Controller/ExampleContentController.php @@ -0,0 +1,98 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Controller; + +use OCA\DAV\AppInfo\Application; +use OCA\DAV\Service\ExampleContactService; +use OCA\DAV\Service\ExampleEventService; +use OCP\AppFramework\ApiController; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\DataDownloadResponse; +use OCP\AppFramework\Http\JSONResponse; +use OCP\IRequest; +use Psr\Log\LoggerInterface; + +class ExampleContentController extends ApiController { + public function __construct( + IRequest $request, + private readonly LoggerInterface $logger, + private readonly ExampleEventService $exampleEventService, + private readonly ExampleContactService $exampleContactService, + ) { + parent::__construct(Application::APP_ID, $request); + } + + #[FrontpageRoute(verb: 'PUT', url: '/api/defaultcontact/config')] + public function setEnableDefaultContact(bool $allow): JSONResponse { + if ($allow && !$this->exampleContactService->defaultContactExists()) { + try { + $this->exampleContactService->setCard(); + } catch (\Exception $e) { + $this->logger->error('Could not create default contact', ['exception' => $e]); + return new JSONResponse([], Http::STATUS_INTERNAL_SERVER_ERROR); + } + } + $this->exampleContactService->setDefaultContactEnabled($allow); + return new JSONResponse([], Http::STATUS_OK); + } + + #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/api/defaultcontact/contact')] + public function getDefaultContact(): DataDownloadResponse { + $cardData = $this->exampleContactService->getCard() + ?? file_get_contents(__DIR__ . '/../ExampleContentFiles/exampleContact.vcf'); + return new DataDownloadResponse($cardData, 'example_contact.vcf', 'text/vcard'); + } + + #[FrontpageRoute(verb: 'PUT', url: '/api/defaultcontact/contact')] + public function setDefaultContact(?string $contactData = null) { + if (!$this->exampleContactService->isDefaultContactEnabled()) { + return new JSONResponse([], Http::STATUS_FORBIDDEN); + } + $this->exampleContactService->setCard($contactData); + return new JSONResponse([], Http::STATUS_OK); + } + + #[FrontpageRoute(verb: 'POST', url: '/api/exampleEvent/enable')] + public function setCreateExampleEvent(bool $enable): JSONResponse { + $this->exampleEventService->setCreateExampleEvent($enable); + return new JsonResponse([]); + } + + #[FrontpageRoute(verb: 'GET', url: '/api/exampleEvent/event')] + #[NoCSRFRequired] + public function downloadExampleEvent(): DataDownloadResponse { + $exampleEvent = $this->exampleEventService->getExampleEvent(); + return new DataDownloadResponse( + $exampleEvent->getIcs(), + 'example_event.ics', + 'text/calendar', + ); + } + + #[FrontpageRoute(verb: 'POST', url: '/api/exampleEvent/event')] + public function uploadExampleEvent(string $ics): JSONResponse { + if (!$this->exampleEventService->shouldCreateExampleEvent()) { + return new JSONResponse([], Http::STATUS_FORBIDDEN); + } + + $this->exampleEventService->saveCustomExampleEvent($ics); + return new JsonResponse([]); + } + + #[FrontpageRoute(verb: 'DELETE', url: '/api/exampleEvent/event')] + public function deleteExampleEvent(): JSONResponse { + $this->exampleEventService->deleteCustomExampleEvent(); + return new JsonResponse([]); + } + +} diff --git a/apps/dav/lib/Controller/InvitationResponseController.php b/apps/dav/lib/Controller/InvitationResponseController.php index 4a32966220f..19eb4097b45 100644 --- a/apps/dav/lib/Controller/InvitationResponseController.php +++ b/apps/dav/lib/Controller/InvitationResponseController.php @@ -3,34 +3,16 @@ declare(strict_types=1); /** - * @copyright 2018, Georg Ehrke <oc.list@georgehrke.com> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * @author Kate Döen <kate.doeen@nextcloud.com> - * - * @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 <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\DAV\Controller; use OCA\DAV\CalDAV\InvitationResponse\InvitationResponseServer; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\Attribute\OpenAPI; +use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Utility\ITimeFactory; use OCP\IDBConnection; @@ -41,15 +23,6 @@ use Sabre\VObject\Reader; #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)] class InvitationResponseController extends Controller { - /** @var IDBConnection */ - private $db; - - /** @var ITimeFactory */ - private $timeFactory; - - /** @var InvitationResponseServer */ - private $responseServer; - /** * InvitationResponseController constructor. * @@ -59,25 +32,25 @@ class InvitationResponseController extends Controller { * @param ITimeFactory $timeFactory * @param InvitationResponseServer $responseServer */ - public function __construct(string $appName, IRequest $request, - IDBConnection $db, ITimeFactory $timeFactory, - InvitationResponseServer $responseServer) { + public function __construct( + string $appName, + IRequest $request, + private IDBConnection $db, + private ITimeFactory $timeFactory, + private InvitationResponseServer $responseServer, + ) { parent::__construct($appName, $request); - $this->db = $db; - $this->timeFactory = $timeFactory; - $this->responseServer = $responseServer; // Don't run `$server->exec()`, because we just need access to the // fully initialized schedule plugin, but we don't want Sabre/DAV // to actually handle and reply to the request } /** - * @PublicPage - * @NoCSRFRequired - * * @param string $token * @return TemplateResponse */ + #[PublicPage] + #[NoCSRFRequired] public function accept(string $token):TemplateResponse { $row = $this->getTokenInformation($token); if (!$row) { @@ -96,12 +69,11 @@ class InvitationResponseController extends Controller { } /** - * @PublicPage - * @NoCSRFRequired - * * @param string $token * @return TemplateResponse */ + #[PublicPage] + #[NoCSRFRequired] public function decline(string $token):TemplateResponse { $row = $this->getTokenInformation($token); if (!$row) { @@ -121,12 +93,11 @@ class InvitationResponseController extends Controller { } /** - * @PublicPage - * @NoCSRFRequired - * * @param string $token * @return TemplateResponse */ + #[PublicPage] + #[NoCSRFRequired] public function options(string $token):TemplateResponse { return new TemplateResponse($this->appName, 'schedule-response-options', [ 'token' => $token @@ -134,13 +105,12 @@ class InvitationResponseController extends Controller { } /** - * @PublicPage - * @NoCSRFRequired - * * @param string $token * * @return TemplateResponse */ + #[PublicPage] + #[NoCSRFRequired] public function processMoreOptionsResult(string $token):TemplateResponse { $partstat = $this->request->getParam('partStat'); @@ -178,7 +148,7 @@ class InvitationResponseController extends Controller { } $currentTime = $this->timeFactory->getTime(); - if (((int) $row['expiration']) < $currentTime) { + if (((int)$row['expiration']) < $currentTime) { return null; } diff --git a/apps/dav/lib/Controller/OutOfOfficeController.php b/apps/dav/lib/Controller/OutOfOfficeController.php index a2e7378f32d..d3516d092e8 100644 --- a/apps/dav/lib/Controller/OutOfOfficeController.php +++ b/apps/dav/lib/Controller/OutOfOfficeController.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2023 Richard Steinmetz <richard@steinmetz.cloud> - * - * @author Richard Steinmetz <richard@steinmetz.cloud> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\DAV\Controller; @@ -38,6 +21,7 @@ use OCP\IRequest; use OCP\IUserManager; use OCP\IUserSession; use OCP\User\IAvailabilityCoordinator; +use function mb_strlen; /** * @psalm-import-type DAVOutOfOfficeData from ResponseDefinitions @@ -57,7 +41,7 @@ class OutOfOfficeController extends OCSController { } /** - * Get the currently configured out-of-office data of a user. + * Get the currently configured out-of-office data of a user * * @param string $userId The user id to get out-of-office data for. * @return DataResponse<Http::STATUS_OK, DAVCurrentOutOfOfficeData, array{}>|DataResponse<Http::STATUS_NOT_FOUND, null, array{}> @@ -110,6 +94,8 @@ class OutOfOfficeController extends OCSController { 'lastDay' => $data->getLastDay(), 'status' => $data->getStatus(), 'message' => $data->getMessage(), + 'replacementUserId' => $data->getReplacementUserId(), + 'replacementUserDisplayName' => $data->getReplacementUserDisplayName(), ]); } @@ -120,11 +106,13 @@ class OutOfOfficeController extends OCSController { * @param string $lastDay Last day of the absence in format `YYYY-MM-DD` * @param string $status Short text that is set as user status during the absence * @param string $message Longer multiline message that is shown to others during the absence - * @return DataResponse<Http::STATUS_OK, DAVOutOfOfficeData, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'firstDay'}, array{}>|DataResponse<Http::STATUS_UNAUTHORIZED, null, array{}> + * @param ?string $replacementUserId User id of the replacement user + * @return DataResponse<Http::STATUS_OK, DAVOutOfOfficeData, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'firstDay'|'statusLength'}, array{}>|DataResponse<Http::STATUS_UNAUTHORIZED, null, array{}>|DataResponse<Http::STATUS_NOT_FOUND, null, array{}> * * 200: Absence data - * 400: When the first day is not before the last day + * 400: When validation fails, e.g. data range error or the first day is not before the last day * 401: When the user is not logged in + * 404: When the replacementUserId was provided but replacement user was not found */ #[NoAdminRequired] public function setOutOfOffice( @@ -132,11 +120,23 @@ class OutOfOfficeController extends OCSController { string $lastDay, string $status, string $message, + ?string $replacementUserId, ): DataResponse { $user = $this->userSession?->getUser(); if ($user === null) { return new DataResponse(null, Http::STATUS_UNAUTHORIZED); } + if (mb_strlen($status) > 100) { + return new DataResponse(['error' => 'statusLength'], Http::STATUS_BAD_REQUEST); + } + + $replacementUser = null; + if ($replacementUserId !== null) { + $replacementUser = $this->userManager->get($replacementUserId); + if ($replacementUser === null) { + return new DataResponse(null, Http::STATUS_NOT_FOUND); + } + } $parsedFirstDay = new DateTimeImmutable($firstDay); $parsedLastDay = new DateTimeImmutable($lastDay); @@ -150,6 +150,8 @@ class OutOfOfficeController extends OCSController { $lastDay, $status, $message, + $replacementUserId, + $replacementUser?->getDisplayName() ); $this->coordinator->clearCache($user->getUID()); @@ -160,6 +162,8 @@ class OutOfOfficeController extends OCSController { 'lastDay' => $data->getLastDay(), 'status' => $data->getStatus(), 'message' => $data->getMessage(), + 'replacementUserId' => $data->getReplacementUserId(), + 'replacementUserDisplayName' => $data->getReplacementUserDisplayName(), ]); } diff --git a/apps/dav/lib/Controller/UpcomingEventsController.php b/apps/dav/lib/Controller/UpcomingEventsController.php new file mode 100644 index 00000000000..a5d54f44754 --- /dev/null +++ b/apps/dav/lib/Controller/UpcomingEventsController.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Controller; + +use OCA\DAV\AppInfo\Application; +use OCA\DAV\CalDAV\UpcomingEvent; +use OCA\DAV\CalDAV\UpcomingEventsService; +use OCA\DAV\ResponseDefinitions; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\OCSController; +use OCP\IRequest; + +/** + * @psalm-import-type DAVUpcomingEvent from ResponseDefinitions + */ +class UpcomingEventsController extends OCSController { + public function __construct( + IRequest $request, + private ?string $userId, + private UpcomingEventsService $service, + ) { + parent::__construct(Application::APP_ID, $request); + } + + /** + * Get information about upcoming events + * + * @param string|null $location location/URL to filter by + * @return DataResponse<Http::STATUS_OK, array{events: list<DAVUpcomingEvent>}, array{}>|DataResponse<Http::STATUS_UNAUTHORIZED, null, array{}> + * + * 200: Upcoming events + * 401: When not authenticated + */ + #[NoAdminRequired] + public function getEvents(?string $location = null): DataResponse { + if ($this->userId === null) { + return new DataResponse(null, Http::STATUS_UNAUTHORIZED); + } + + return new DataResponse([ + 'events' => array_values(array_map(fn (UpcomingEvent $e) => $e->jsonSerialize(), $this->service->getEvents( + $this->userId, + $location, + ))), + ]); + } + +} |