From 4d7525fe5e6c0ed369006d14003ea535b0218d58 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Wed, 9 Oct 2024 15:39:12 +0200 Subject: [PATCH 1/6] switch routes to attributes Signed-off-by: dartcafe --- appinfo/info.xml | 4 +- appinfo/routes.php | 171 +------------------ lib/Controller/AdminController.php | 44 +++-- lib/Controller/CommentApiController.php | 5 + lib/Controller/CommentController.php | 5 + lib/Controller/OptionApiController.php | 9 + lib/Controller/OptionController.php | 12 ++ lib/Controller/PageController.php | 10 +- lib/Controller/PollApiController.php | 101 ++++++----- lib/Controller/PollController.php | 17 +- lib/Controller/PublicController.php | 29 ++++ lib/Controller/SettingsController.php | 3 + lib/Controller/ShareApiController.php | 9 + lib/Controller/ShareController.php | 46 +++-- lib/Controller/SubscriptionApiController.php | 4 + lib/Controller/SubscriptionController.php | 4 + lib/Controller/SystemController.php | 4 + lib/Controller/UserApiController.php | 52 +++--- lib/Controller/UserController.php | 30 ++-- lib/Controller/VoteApiController.php | 5 + lib/Controller/VoteController.php | 8 +- lib/Controller/WatchController.php | 2 + 22 files changed, 296 insertions(+), 278 deletions(-) diff --git a/appinfo/info.xml b/appinfo/info.xml index a49e5bb02..ccd4d3e80 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -23,8 +23,8 @@ https://raw.githubusercontent.com/nextcloud/polls/master/screenshots/vote.png https://raw.githubusercontent.com/nextcloud/polls/master/screenshots/edit-poll.png - - + + diff --git a/appinfo/routes.php b/appinfo/routes.php index 12103d696..a123a149c 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -6,176 +6,7 @@ return [ 'routes' => [ - ['name' => 'public#get_acl', 'url' => '/s/{token}/acl', 'verb' => 'GET'], - ['name' => 'public#get_session', 'url' => '/s/{token}/session', 'verb' => 'GET'], - ['name' => 'public#vote_page', 'url' => '/s/{token}', 'verb' => 'GET'], - ['name' => 'public#get_share', 'url' => '/s/{token}/share', 'verb' => 'GET'], - ['name' => 'public#get_poll', 'url' => '/s/{token}/poll', 'verb' => 'GET'], - ['name' => 'public#get_comments', 'url' => '/s/{token}/comments', 'verb' => 'GET'], - ['name' => 'public#get_options', 'url' => '/s/{token}/options', 'verb' => 'GET'], - ['name' => 'public#get_votes', 'url' => '/s/{token}/votes', 'verb' => 'GET'], - ['name' => 'public#get_subscription', 'url' => '/s/{token}/subscription', 'verb' => 'GET'], - ['name' => 'public#set_email_address', 'url' => '/s/{token}/email/{emailAddress}', 'verb' => 'PUT'], - ['name' => 'public#set_display_name', 'url' => '/s/{token}/name/{displayName}', 'verb' => 'PUT'], - ['name' => 'public#delete_email_address', 'url' => '/s/{token}/email', 'verb' => 'DELETE'], - - ['name' => 'public#set_vote', 'url' => '/s/{token}/vote', 'verb' => 'PUT'], - ['name' => 'public#add_option', 'url' => '/s/{token}/option', 'verb' => 'POST'], - ['name' => 'public#delete_option', 'url' => '/s/{token}/option/{optionId}', 'verb' => 'DELETE'], - ['name' => 'public#restore_option', 'url' => '/s/{token}/option/{optionId}/restore', 'verb' => 'PUT'], - - ['name' => 'public#add_comment', 'url' => '/s/{token}/comment', 'verb' => 'POST'], - ['name' => 'public#restore_comment', 'url' => '/s/{token}/comment/{commentId}/restore', 'verb' => 'PUT', 'postfix' => 'auth'], - ['name' => 'public#delete_comment', 'url' => '/s/{token}/comment/{commentId}', 'verb' => 'DELETE', 'postfix' => 'public'], - ['name' => 'public#subscribe', 'url' => '/s/{token}/subscribe', 'verb' => 'PUT'], - ['name' => 'public#unsubscribe', 'url' => '/s/{token}/unsubscribe', 'verb' => 'PUT'], - ['name' => 'public#register', 'url' => '/s/{token}/register', 'verb' => 'POST'], - ['name' => 'public#resend_invitation', 'url' => '/s/{token}/resend', 'verb' => 'POST'], - ['name' => 'public#validate_public_display_name', 'url' => '/check/username', 'verb' => 'POST'], - ['name' => 'public#validate_email_address', 'url' => '/check/emailaddress/{emailAddress}', 'verb' => 'GET'], - ['name' => 'public#delete_user', 'url' => '/s/{token}/user', 'verb' => 'DELETE'], - ['name' => 'public#delete_orphaned_votes', 'url' => '/s/{token}/votes/orphaned', 'verb' => 'DELETE'], - ['name' => 'public#watch_poll', 'url' => '/s/{token}/watch', 'verb' => 'GET'], - - ['name' => 'admin#index', 'url' => '/administration', 'verb' => 'GET'], - - ['name' => 'admin#list', 'url' => '/administration/polls', 'verb' => 'GET'], - ['name' => 'admin#takeover', 'url' => '/administration/poll/{pollId}/takeover', 'verb' => 'PUT'], - ['name' => 'admin#run_auto_reminder_job', 'url' => 'administration/autoreminder/run', 'verb' => 'GET'], - ['name' => 'admin#run_janitor_job', 'url' => 'administration/janitor/run', 'verb' => 'GET'], - ['name' => 'admin#run_notification_job', 'url' => 'administration/notification/run', 'verb' => 'GET'], - - ['name' => 'page#index', 'url' => '/', 'verb' => 'GET'], - ['name' => 'page#index', 'url' => '/not-found', 'verb' => 'GET', 'postfix' => 'notfound'], - ['name' => 'page#index', 'url' => '/list/{category}', 'verb' => 'GET', 'postfix' => 'list', 'defaults' => ['category' => 'relevant']], - ['name' => 'page#index', 'url' => '/combo', 'verb' => 'GET', 'postfix' => 'combo'], - ['name' => 'page#vote', 'url' => '/vote/{id}', 'verb' => 'GET'], - - ['name' => 'poll#list', 'url' => '/polls', 'verb' => 'GET'], - ['name' => 'poll#get_full', 'url' => '/poll/{pollId}', 'verb' => 'GET'], - ['name' => 'poll#get', 'url' => '/poll/{pollId}/poll', 'verb' => 'GET'], - ['name' => 'poll#add', 'url' => '/poll/add', 'verb' => 'POST'], - ['name' => 'poll#update', 'url' => '/poll/{pollId}', 'verb' => 'PUT'], - ['name' => 'poll#delete', 'url' => '/poll/{pollId}', 'verb' => 'DELETE'], - - ['name' => 'poll#close', 'url' => '/poll/{pollId}/close', 'verb' => 'PUT'], - ['name' => 'poll#reopen', 'url' => '/poll/{pollId}/reopen', 'verb' => 'PUT'], - ['name' => 'poll#toggleArchive', 'url' => '/poll/{pollId}/toggleArchive', 'verb' => 'PUT'], - ['name' => 'poll#clone', 'url' => '/poll/{pollId}/clone', 'verb' => 'POST'], - ['name' => 'poll#getParticipantsEmailAddresses', 'url' => '/poll/{pollId}/addresses', 'verb' => 'GET'], - ['name' => 'poll#sendConfirmation', 'url' => '/poll/{pollId}/confirmation', 'verb' => 'POST'], - ['name' => 'poll#transfer_polls', 'url' => '/polls/transfer/{sourceUser}/{destinationUser}', 'verb' => 'PUT'], - - ['name' => 'option#list', 'url' => '/poll/{pollId}/options', 'verb' => 'GET'], - ['name' => 'option#add', 'url' => '/option', 'verb' => 'POST'], - ['name' => 'option#addBulk', 'url' => '/option/bulk', 'verb' => 'POST'], - ['name' => 'option#update', 'url' => '/option/{optionId}', 'verb' => 'PUT'], - ['name' => 'option#delete', 'url' => '/option/{optionId}', 'verb' => 'DELETE'], - ['name' => 'option#restore', 'url' => '/option/{optionId}/restore', 'verb' => 'PUT'], - - ['name' => 'option#shift', 'url' => '/poll/{pollId}/shift', 'verb' => 'POST'], - ['name' => 'option#reorder', 'url' => '/poll/{pollId}/options/reorder', 'verb' => 'POST'], - ['name' => 'option#confirm', 'url' => '/option/{optionId}/confirm', 'verb' => 'PUT'], - ['name' => 'option#sequence', 'url' => '/option/{optionId}/sequence', 'verb' => 'POST'], - ['name' => 'option#findCalendarEvents', 'url' => '/option/{optionId}/events', 'verb' => 'GET'], - - ['name' => 'vote#list', 'url' => '/poll/{pollId}/votes', 'verb' => 'GET'], - ['name' => 'vote#set', 'url' => '/vote', 'verb' => 'PUT'], - ['name' => 'vote#delete', 'url' => '/poll/{pollId}/user/{userId}', 'verb' => 'DELETE', 'postfix' => 'other'], - ['name' => 'vote#delete', 'url' => '/poll/{pollId}/user', 'verb' => 'DELETE', 'postfix' => 'self'], - ['name' => 'vote#delete_orphaned', 'url' => '/poll/{pollId}/votes/orphaned', 'verb' => 'DELETE'], - - ['name' => 'share#list', 'url' => '/poll/{pollId}/shares', 'verb' => 'GET'], - ['name' => 'share#add', 'url' => '/poll/{pollId}/share', 'verb' => 'POST'], - ['name' => 'share#send_all_invitations', 'url' => '/poll/{pollId}/inviteAll', 'verb' => 'PUT'], - ['name' => 'share#delete', 'url' => '/share/{token}', 'verb' => 'DELETE'], - ['name' => 'share#restore', 'url' => '/share/{token}/restore', 'verb' => 'PUT'], - ['name' => 'share#personal', 'url' => '/share/personal', 'verb' => 'POST'], - ['name' => 'share#sendInvitation', 'url' => '/share/{token}/invite', 'verb' => 'POST'], - ['name' => 'share#resolveGroup', 'url' => '/share/{token}/resolve', 'verb' => 'GET'], - ['name' => 'share#user_to_admin', 'url' => '/share/{token}/admin', 'verb' => 'PUT'], - ['name' => 'share#admin_to_user', 'url' => '/share/{token}/user', 'verb' => 'PUT'], - ['name' => 'share#set_label', 'url' => '/share/{token}/setlabel', 'verb' => 'PUT'], - ['name' => 'share#set_public_poll_email', 'url' => '/share/{token}/publicpollemail/{value}', 'verb' => 'PUT'], - ['name' => 'share#lock', 'url' => '/share/{token}/lock', 'verb' => 'PUT'], - ['name' => 'share#unlock', 'url' => '/share/{token}/unlock', 'verb' => 'PUT'], - - ['name' => 'settings#getAppSettings', 'url' => '/settings/app', 'verb' => 'GET'], - ['name' => 'settings#writeAppSettings', 'url' => '/settings/app', 'verb' => 'POST'], - - ['name' => 'subscription#get', 'url' => '/poll/{pollId}/subscription', 'verb' => 'GET'], - ['name' => 'subscription#set', 'url' => '/poll/{pollId}/subscription', 'verb' => 'PUT'], - ['name' => 'subscription#subscribe', 'url' => '/poll/{pollId}/subscribe', 'verb' => 'PUT'], - ['name' => 'subscription#unsubscribe', 'url' => '/poll/{pollId}/unsubscribe', 'verb' => 'PUT'], - - ['name' => 'comment#list', 'url' => '/poll/{pollId}/comments', 'verb' => 'GET'], - ['name' => 'comment#add', 'url' => '/poll/{pollId}/comment', 'verb' => 'POST'], - ['name' => 'comment#restore', 'url' => '/comment/{commentId}/restore', 'verb' => 'PUT', 'postfix' => 'auth'], - ['name' => 'comment#delete', 'url' => '/comment/{commentId}', 'verb' => 'DELETE', 'postfix' => 'auth'], - - ['name' => 'system#user_search', 'url' => '/search/users/{query}', 'verb' => 'GET'], - ['name' => 'system#group_search', 'url' => '/groups/{query}', 'verb' => 'GET', 'postfix' => 'query'], - ['name' => 'system#group_search', 'url' => '/groups', 'verb' => 'GET', 'postfix' => 'all'], - - ['name' => 'watch#watch_poll', 'url' => '/poll/{pollId}/watch', 'verb' => 'GET'], - - ['name' => 'user#get_acl', 'url' => '/acl', 'verb' => 'GET'], - ['name' => 'user#get_session', 'url' => '/session', 'verb' => 'GET'], - ['name' => 'user#write_preferences', 'url' => '/preferences', 'verb' => 'POST'], - ['name' => 'user#get_preferences', 'url' => '/preferences', 'verb' => 'GET'], - ['name' => 'user#get_calendars', 'url' => '/calendars', 'verb' => 'GET'], - - // REST-API calls - ['name' => 'user_api#get_acl', 'url' => '/api/v1.0/acl', 'verb' => 'GET'], - ['name' => 'user_api#get_session', 'url' => '/session', 'verb' => 'GET'], ['name' => 'base_api#preflighted_cors', 'url' => '/api/v1.0/{path}', 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], - ['name' => 'poll_api#list', 'url' => '/api/v1.0/polls', 'verb' => 'GET'], - ['name' => 'poll_api#transfer_polls', 'url' => '/api/v1.0/polls/transfer/{sourceUser}/{destinationUser}', 'verb' => 'PUT'], - ['name' => 'poll_api#transfer_poll', 'url' => '/api/v1.0/poll/{pollId}/transfer/{destinationUser}', 'verb' => 'PUT'], - ['name' => 'poll_api#add', 'url' => '/api/v1.0/poll', 'verb' => 'POST'], - ['name' => 'poll_api#get_full', 'url' => '/api/v1.0/poll/{pollId}', 'verb' => 'GET'], - ['name' => 'poll_api#get', 'url' => '/api/v1.0/poll/{pollId}', 'verb' => 'GET'], - ['name' => 'poll_api#update', 'url' => '/api/v1.0/poll/{pollId}', 'verb' => 'PUT'], - ['name' => 'poll_api#delete', 'url' => '/api/v1.0/poll/{pollId}', 'verb' => 'DELETE'], - ['name' => 'poll_api#toggleArchive', 'url' => '/api/v1.0/poll/{pollId}/toggleArchive', 'verb' => 'PUT'], - ['name' => 'poll_api#clone', 'url' => '/api/v1.0/poll/{pollId}/clone', 'verb' => 'POST'], - ['name' => 'poll_api#get_participants_email_addresses', 'url' => '/api/v1.0/poll/{pollId}/addresses', 'verb' => 'GET'], - ['name' => 'poll_api#enum', 'url' => '/api/v1.0/enum/poll', 'verb' => 'GET'], - ['name' => 'poll_api#close', 'url' => '/api/v1.0/poll/{pollId}/close', 'verb' => 'PUT'], - ['name' => 'poll_api#reopen', 'url' => '/api/v1.0/poll/{pollId}/reopen', 'verb' => 'PUT'], - - ['name' => 'option_api#list', 'url' => '/api/v1.0/poll/{pollId}/options', 'verb' => 'GET'], - ['name' => 'option_api#add', 'url' => '/api/v1.0/poll/{pollId}/option', 'verb' => 'POST'], - ['name' => 'option_api#update', 'url' => '/api/v1.0/option/{optionId}', 'verb' => 'PUT'], - ['name' => 'option_api#delete', 'url' => '/api/v1.0/option/{optionId}', 'verb' => 'DELETE'], - ['name' => 'option_api#restore', 'url' => '/api/v1.0/option/{optionId}/restore', 'verb' => 'PUT'], - ['name' => 'option_api#setOrder', 'url' => '/api/v1.0/option/{optionId}/setorder/{order}', 'verb' => 'PUT'], - ['name' => 'option_api#confirm', 'url' => '/api/v1.0/option/{optionId}/confirm', 'verb' => 'PUT'], - - ['name' => 'vote_api#list', 'url' => '/api/v1.0/poll/{pollId}/votes', 'verb' => 'GET'], - ['name' => 'vote_api#set', 'url' => '/api/v1.0/option/{optionId}/vote/{answer}', 'verb' => 'PUT'], - ['name' => 'vote_api#delete', 'url' => '/api/v1.0/poll/{pollId}/user/{userId}', 'verb' => 'DELETE', 'postfix' => 'other'], - ['name' => 'vote_api#delete', 'url' => '/api/v1.0/poll/{pollId}/user', 'verb' => 'DELETE', 'postfix' => 'self'], - ['name' => 'vote_api#delete_orphaned', 'url' => '/api/v1.0/poll/{pollId}/votes/orphaned', 'verb' => 'DELETE'], - - ['name' => 'share_api#list', 'url' => '/api/v1.0/poll/{pollId}/shares', 'verb' => 'GET'], - ['name' => 'share_api#get', 'url' => '/api/v1.0/share/{token}', 'verb' => 'GET'], - ['name' => 'share_api#add', 'url' => '/api/v1.0/poll/{pollId}/share/{type}', 'verb' => 'POST'], - ['name' => 'share_api#delete', 'url' => '/api/v1.0/share/{token}', 'verb' => 'DELETE'], - ['name' => 'share_api#restore', 'url' => '/api/v1.0/share/{token}/restore', 'verb' => 'PUT'], - ['name' => 'share_api#sendInvitation', 'url' => '/api/v1.0/share/send/{token}', 'verb' => 'PUT'], - ['name' => 'share_api#lock', 'url' => '/api/v1.0/share/lock/{token}', 'verb' => 'PUT'], - ['name' => 'share_api#unlock', 'url' => '/api/v1.0/share/unlock/{token}', 'verb' => 'PUT'], - - ['name' => 'subscription_api#get', 'url' => '/api/v1.0/poll/{pollId}/subscription', 'verb' => 'GET'], - ['name' => 'subscription_api#subscribe', 'url' => '/api/v1.0/poll/{pollId}/subscription', 'verb' => 'PUT'], - ['name' => 'subscription_api#unsubscribe', 'url' => '/api/v1.0/poll/{pollId}/subscription', 'verb' => 'DELETE'], - - ['name' => 'comment_api#list', 'url' => '/api/v1.0/poll/{pollId}/comments', 'verb' => 'GET'], - ['name' => 'comment_api#add', 'url' => '/api/v1.0/poll/{pollId}/comment', 'verb' => 'POST'], - ['name' => 'comment_api#delete', 'url' => '/api/v1.0/comment/{commentId}', 'verb' => 'DELETE'], - ['name' => 'comment_api#restore', 'url' => '/api/v1.0/comment/{commentId}/restore', 'verb' => 'PUT'], - - ] + ], ]; diff --git a/lib/Controller/AdminController.php b/lib/Controller/AdminController.php index 667e6c2c5..0738165df 100644 --- a/lib/Controller/AdminController.php +++ b/lib/Controller/AdminController.php @@ -13,6 +13,7 @@ use OCA\Polls\Cron\JanitorCron; use OCA\Polls\Cron\NotificationCron; use OCA\Polls\Service\PollService; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\TemplateResponse; @@ -43,6 +44,7 @@ public function __construct( * Load admin page */ #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/administration')] public function index(): TemplateResponse { Util::addScript(AppConstants::APP_ID, 'polls-main'); $this->eventDispatcher->dispatchTyped(new LoadAdditionalScriptsEvent()); @@ -52,6 +54,7 @@ public function index(): TemplateResponse { /** * Get list of polls for administrative purposes */ + #[FrontpageRoute(verb: 'GET', url: '/administration/polls')] public function list(): JSONResponse { return $this->response(fn () => $this->pollService->listForAdmin()); } @@ -60,14 +63,41 @@ public function list(): JSONResponse { * Takeover ownership of a poll * @param int $pollId PollId to take over */ + #[FrontpageRoute(verb: 'PUT', url: '/administration/poll/{pollId}/takeover')] public function takeover(int $pollId): JSONResponse { return $this->response(fn () => $this->pollService->takeover($pollId)); } /** - * Switch deleted status (move to deleted polls) + * Run auto reminder job + */ + #[FrontpageRoute(verb: 'GET', url: '/administration/autoReminder/run')] + public function runAutoReminderJob(): JSONResponse { + return $this->response(fn () => $this->autoReminderCron->manuallyRun()); + } + + /** + * Run janitor job + */ + #[FrontpageRoute(verb: 'GET', url: '/administration/janitor/run')] + public function runJanitorJob(): JSONResponse { + return $this->response(fn () => $this->janitorCron->manuallyRun()); + } + + /** + * Run notification job + */ + #[FrontpageRoute(verb: 'GET', url: '/administration/notification/run')] + public function runNotificationJob(): JSONResponse { + return $this->response(fn () => $this->notificationCron->manuallyRun()); + } + + /** + * Switch archived status (move to archived polls) * @param int $pollId poll id + * @deprecated 8.0.0 Not used anymore (use PUT /poll/{pollId}/toggleArchive) */ + #[FrontpageRoute(verb: 'PUT', url: '/administration/poll/{pollId}/toggleArchive')] public function toggleArchive(int $pollId): JSONResponse { return $this->response(fn () => $this->pollService->toggleArchive($pollId)); } @@ -75,18 +105,10 @@ public function toggleArchive(int $pollId): JSONResponse { /** * Delete poll * @param int $pollId poll id + * @deprecated 8.0.0 Not used anymore (use DELETE /poll/{pollId}) */ + #[FrontpageRoute(verb: 'DELETE', url: '/administration/poll/{pollId}')] public function delete(int $pollId): JSONResponse { return $this->responseDeleteTolerant(fn () => $this->pollService->delete($pollId)); } - - public function runAutoReminderJob(): JSONResponse { - return $this->response(fn () => $this->autoReminderCron->manuallyRun()); - } - public function runJanitorJob(): JSONResponse { - return $this->response(fn () => $this->janitorCron->manuallyRun()); - } - public function runNotificationJob(): JSONResponse { - return $this->response(fn () => $this->notificationCron->manuallyRun()); - } } diff --git a/lib/Controller/CommentApiController.php b/lib/Controller/CommentApiController.php index a07302fcc..87b3dafb4 100644 --- a/lib/Controller/CommentApiController.php +++ b/lib/Controller/CommentApiController.php @@ -10,6 +10,7 @@ use OCA\Polls\Service\CommentService; use OCP\AppFramework\Http\Attribute\CORS; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\JSONResponse; @@ -34,6 +35,7 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}/comments')] public function list(int $pollId): JSONResponse { return $this->response(fn () => [ 'comments' => $this->commentService->list($pollId) @@ -48,6 +50,7 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/comment')] public function add(int $pollId, string $comment): JSONResponse { return $this->response(fn () => [ 'comment' => $this->commentService->add($comment, $pollId) @@ -61,6 +64,7 @@ public function add(int $pollId, string $comment): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/comment/{commentId}')] public function delete(int $commentId): JSONResponse { return $this->response(fn () => [ 'comment' => $this->commentService->delete($commentId)]); @@ -73,6 +77,7 @@ public function delete(int $commentId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'POST', url: '/api/v1/comment/{commentId}/restore')] public function restore(int $commentId): JSONResponse { return $this->response(fn () => [ 'comment' => $this->commentService->delete($commentId, true) diff --git a/lib/Controller/CommentController.php b/lib/Controller/CommentController.php index 30c0dfecc..156ef9bcd 100644 --- a/lib/Controller/CommentController.php +++ b/lib/Controller/CommentController.php @@ -9,6 +9,7 @@ namespace OCA\Polls\Controller; use OCA\Polls\Service\CommentService; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -30,6 +31,7 @@ public function __construct( * @param int $pollId poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/comments')] public function list(int $pollId): JSONResponse { return $this->response(fn () => [ 'comments' => $this->commentService->list($pollId) @@ -42,6 +44,7 @@ public function list(int $pollId): JSONResponse { * @param string $message Comment text to add */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/poll/{pollId}/comment')] public function add(int $pollId, string $message): JSONResponse { return $this->response(fn () => [ 'comment' => $this->commentService->add($message, $pollId) @@ -53,6 +56,7 @@ public function add(int $pollId, string $message): JSONResponse { * @param int $commentId Id of comment to delete */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/comment/{commentId}')] public function delete(int $commentId): JSONResponse { return $this->response(fn () => [ 'comment' => $this->commentService->delete($commentId) @@ -64,6 +68,7 @@ public function delete(int $commentId): JSONResponse { * @param int $commentId Id of comment to restore */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/comment/{commentId}/restore')] public function restore(int $commentId): JSONResponse { return $this->response(fn () => [ 'comment' => $this->commentService->delete($commentId, true) diff --git a/lib/Controller/OptionApiController.php b/lib/Controller/OptionApiController.php index ac7c8885c..00520f8e5 100644 --- a/lib/Controller/OptionApiController.php +++ b/lib/Controller/OptionApiController.php @@ -10,6 +10,7 @@ use OCA\Polls\Service\OptionService; use OCP\AppFramework\Http\Attribute\CORS; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\JSONResponse; @@ -34,6 +35,7 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/api/v1/polls/{pollId}/options')] public function list(int $pollId): JSONResponse { return $this->response(fn () => ['options' => $this->optionService->list($pollId)]); } @@ -48,6 +50,7 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/option')] public function add(int $pollId, int $timestamp = 0, string $pollOptionText = '', int $duration = 0): JSONResponse { return $this->responseCreate(fn () => ['option' => $this->optionService->add($pollId, $timestamp, $pollOptionText, $duration)]); } @@ -61,6 +64,7 @@ public function add(int $pollId, int $timestamp = 0, string $pollOptionText = '' #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/options')] public function addBulk(int $pollId, string $text = ''): JSONResponse { return $this->responseCreate(fn () => ['options' => $this->optionService->addBulk($pollId, $text)]); } @@ -75,6 +79,7 @@ public function addBulk(int $pollId, string $text = ''): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/option/{optionId}')] public function update(int $optionId, int $timestamp = 0, string $text = '', int $duration = 0): JSONResponse { return $this->response(fn () => ['option' => $this->optionService->update($optionId, $timestamp, $text, $duration)]); } @@ -86,6 +91,7 @@ public function update(int $optionId, int $timestamp = 0, string $text = '', int #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/option/{optionId}')] public function delete(int $optionId): JSONResponse { return $this->response(fn () => ['option' => $this->optionService->delete($optionId)]); } @@ -97,6 +103,7 @@ public function delete(int $optionId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/option/{optionId}/restore')] public function restore(int $optionId): JSONResponse { return $this->response(fn () => ['option' => $this->optionService->delete($optionId, true)]); } @@ -108,6 +115,7 @@ public function restore(int $optionId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/option/{optionId}/confirm')] public function confirm(int $optionId): JSONResponse { return $this->response(fn () => ['option' => $this->optionService->confirm($optionId)]); } @@ -120,6 +128,7 @@ public function confirm(int $optionId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/option/{optionId}/order/{order}')] public function setOrder(int $optionId, int $order): JSONResponse { return $this->response(fn () => ['option' => $this->optionService->setOrder($optionId, $order)]); } diff --git a/lib/Controller/OptionController.php b/lib/Controller/OptionController.php index ede916570..67116c1f7 100644 --- a/lib/Controller/OptionController.php +++ b/lib/Controller/OptionController.php @@ -10,6 +10,7 @@ use OCA\Polls\Service\CalendarService; use OCA\Polls\Service\OptionService; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -32,6 +33,7 @@ public function __construct( * @param int $pollId Poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/options')] public function list(int $pollId): JSONResponse { return $this->response(function () use ($pollId) { return ['options' => $this->optionService->list($pollId)]; @@ -46,6 +48,7 @@ public function list(int $pollId): JSONResponse { * @param int $duration duration of option */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/option')] public function add(int $pollId, int $timestamp = 0, string $text = '', int $duration = 0): JSONResponse { return $this->responseCreate(fn () => ['option' => $this->optionService->add($pollId, $timestamp, $text, $duration)]); } @@ -56,6 +59,7 @@ public function add(int $pollId, int $timestamp = 0, string $text = '', int $dur * @param string $text Options text for text poll */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/option/bulk')] public function addBulk(int $pollId, string $text = ''): JSONResponse { return $this->responseCreate(fn () => ['options' => $this->optionService->addBulk($pollId, $text)]); } @@ -68,6 +72,7 @@ public function addBulk(int $pollId, string $text = ''): JSONResponse { * @param int duration duration of option */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/option/{optionId}')] public function update(int $optionId, int $timestamp, string $text, int $duration): JSONResponse { return $this->response(fn () => ['option' => $this->optionService->update($optionId, $timestamp, $text, $duration)]); } @@ -77,6 +82,7 @@ public function update(int $optionId, int $timestamp, string $text, int $duratio * @param int $optionId option id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/option/{optionId}')] public function delete(int $optionId): JSONResponse { return $this->response(fn () => ['option' => $this->optionService->delete($optionId)]); } @@ -86,6 +92,7 @@ public function delete(int $optionId): JSONResponse { * @param int $optionId option id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/option/{optionId}/restore')] public function restore(int $optionId): JSONResponse { return $this->response(fn () => ['option' => $this->optionService->delete($optionId, true)]); } @@ -95,6 +102,7 @@ public function restore(int $optionId): JSONResponse { * @param int $optionId option id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/option/{optionId}/confirm')] public function confirm(int $optionId): JSONResponse { return $this->response(fn () => ['option' => $this->optionService->confirm($optionId)]); } @@ -105,6 +113,7 @@ public function confirm(int $optionId): JSONResponse { * @param array $options options in new order */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/poll/{pollId}/options/reorder')] public function reorder(int $pollId, array $options): JSONResponse { return $this->response(fn () => ['options' => $this->optionService->reorder($pollId, $options)]); } @@ -117,6 +126,7 @@ public function reorder(int $pollId, array $options): JSONResponse { * @param int $amount number of new options to create */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/option/{optionId}/sequence')] public function sequence(int $optionId, int $step, string $unit, int $amount): JSONResponse { return $this->response(fn () => ['options' => $this->optionService->sequence($optionId, $step, $unit, $amount)]); } @@ -128,6 +138,7 @@ public function sequence(int $optionId, int $step, string $unit, int $amount): J * @param string $unit Unit for shift steps */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/poll/{pollId}/shift')] public function shift(int $pollId, int $step, string $unit): JSONResponse { return $this->response(fn () => ['options' => $this->optionService->shift($pollId, $step, $unit)]); } @@ -138,6 +149,7 @@ public function shift(int $pollId, int $step, string $unit): JSONResponse { * @param $tz Timezone to use */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/option/{optionId}/events')] public function findCalendarEvents(int $optionId): JSONResponse { return $this->response(fn () => ['events' => $this->calendarService->getEvents($optionId)]); } diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index 0a3c6ea51..c1b1e9862 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -11,6 +11,7 @@ use OCA\Polls\AppConstants; use OCA\Polls\Service\NotificationService; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\TemplateResponse; @@ -33,10 +34,14 @@ public function __construct( } /** - * reder index page + * render index page */ #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/', postfix: 'index')] + #[FrontpageRoute(verb: 'GET', url: '/combo', postfix: 'combo')] + #[FrontpageRoute(verb: 'GET', url: '/not-found', postfix: 'notFound')] + #[FrontpageRoute(verb: 'GET', url: '/list/{category}', postfix: 'list')] public function index(): TemplateResponse { Util::addScript(AppConstants::APP_ID, 'polls-main'); $this->eventDispatcher->dispatchTyped(new LoadAdditionalScriptsEvent()); @@ -44,11 +49,12 @@ public function index(): TemplateResponse { } /** - * reder vote page + * render vote page * @param $id poll id */ #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/vote/{id}')] public function vote(int $id): TemplateResponse { $this->notificationService->removeNotification($id); Util::addScript(AppConstants::APP_ID, 'polls-main'); diff --git a/lib/Controller/PollApiController.php b/lib/Controller/PollApiController.php index f32bc7f0a..aa8f42734 100644 --- a/lib/Controller/PollApiController.php +++ b/lib/Controller/PollApiController.php @@ -20,6 +20,7 @@ use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\CORS; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\JSONResponse; @@ -49,6 +50,7 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/api/v1/polls')] public function list(): JSONResponse { try { return new JSONResponse([AppConstants::APP_ID => $this->pollService->list()], Http::STATUS_OK); @@ -59,23 +61,6 @@ public function list(): JSONResponse { } } - /** - * get poll - * @param $pollId Poll id - */ - #[CORS] - #[NoAdminRequired] - #[NoCSRFRequired] - public function get(int $pollId): JSONResponse { - try { - return new JSONResponse(['poll' => $this->pollService->get($pollId)], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'Not found'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } - } - /** * get complete poll * @param int $pollId Poll id @@ -83,6 +68,7 @@ public function get(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}')] public function getFull(int $pollId): JSONResponse { return $this->response(fn () => [ 'poll' => $this->pollService->get($pollId), @@ -94,25 +80,7 @@ public function getFull(int $pollId): JSONResponse { 'acl' => $this->acl, ]); } - - - /** - * get acl for poll - * @param $pollId Poll id - */ - #[CORS] - #[NoAdminRequired] - #[NoCSRFRequired] - public function getAcl(): JSONResponse { - try { - return new JSONResponse(['acl' => $this->acl], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'Not found'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } - } - + /** * Add poll * @param string $title Poll title @@ -121,6 +89,7 @@ public function getAcl(): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll')] public function add(string $type, string $title): JSONResponse { try { return new JSONResponse(['poll' => $this->pollService->add($type, $title)], Http::STATUS_CREATED); @@ -137,6 +106,7 @@ public function add(string $type, string $title): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/{pollId}')] public function update(int $pollId, array $pollConfiguration): JSONResponse { try { return new JSONResponse([ @@ -157,6 +127,7 @@ public function update(int $pollId, array $pollConfiguration): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/{pollId}/archive/toggle')] public function toggleArchive(int $pollId): JSONResponse { try { return new JSONResponse(['poll' => $this->pollService->toggleArchive($pollId)], Http::STATUS_OK); @@ -174,6 +145,7 @@ public function toggleArchive(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/{pollId}/close')] public function close(int $pollId): JSONResponse { try { return new JSONResponse(['poll' => $this->pollService->close($pollId)], Http::STATUS_OK); @@ -191,6 +163,7 @@ public function close(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/{pollId}/reopen')] public function reopen(int $pollId): JSONResponse { try { return new JSONResponse(['poll' => $this->pollService->reopen($pollId)], Http::STATUS_OK); @@ -208,6 +181,7 @@ public function reopen(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/poll/{pollId}')] public function delete(int $pollId): JSONResponse { try { return new JSONResponse(['poll' => $this->pollService->delete($pollId)], Http::STATUS_OK); @@ -225,6 +199,7 @@ public function delete(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/clone')] public function clone(int $pollId): JSONResponse { try { return new JSONResponse(['poll' => $this->pollService->clone($pollId)], Http::STATUS_CREATED); @@ -238,13 +213,14 @@ public function clone(int $pollId): JSONResponse { /** * Transfer all polls from one user to another (change owner of poll) * @param string $sourceUser User to transfer polls from - * @param string $destinationUser User to transfer polls to + * @param string $targetUser User to transfer polls to */ #[CORS] #[NoCSRFRequired] - public function transferPolls(string $sourceUser, string $destinationUser): JSONResponse { + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/transfer/{sourceUser}/{targetUser}')] + public function transferPolls(string $sourceUser, string $targetUser): JSONResponse { try { - return new JSONResponse(['transferred' => $this->pollService->transferPolls($sourceUser, $destinationUser)], Http::STATUS_CREATED); + return new JSONResponse(['transferred' => $this->pollService->transferPolls($sourceUser, $targetUser)], Http::STATUS_CREATED); } catch (Exception $e) { return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); } @@ -253,13 +229,14 @@ public function transferPolls(string $sourceUser, string $destinationUser): JSON /** * Transfer singe poll to another user (change owner of poll) * @param int $pollId Poll to transfer - * @param string $destinationUser User to transfer the poll to + * @param string $targetUser User to transfer the poll to */ #[CORS] #[NoCSRFRequired] - public function transferPoll(int $pollId, string $destinationUser): JSONResponse { + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/{pollId}/transfer/{targetUser}')] + public function transferPoll(int $pollId, string $targetUser): JSONResponse { try { - return new JSONResponse(['transferred' => $this->pollService->transferPoll($pollId, $destinationUser)], Http::STATUS_CREATED); + return new JSONResponse(['transferred' => $this->pollService->transferPoll($pollId, $targetUser)], Http::STATUS_CREATED); } catch (Exception $e) { return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); } @@ -272,6 +249,7 @@ public function transferPoll(int $pollId, string $destinationUser): JSONResponse #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}/addresses')] public function getParticipantsEmailAddresses(int $pollId): JSONResponse { try { return new JSONResponse($this->pollService->getParticipantsEmailAddresses($pollId), Http::STATUS_OK); @@ -288,7 +266,46 @@ public function getParticipantsEmailAddresses(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/enum')] public function enum(): JSONResponse { return new JSONResponse($this->pollService->getValidEnum(), Http::STATUS_OK); } + + /** + * get poll + * @param $pollId Poll id + * @deprecated 8.0.0 Use getFull instead + */ + #[CORS] + #[NoAdminRequired] + #[NoCSRFRequired] + public function get(int $pollId): JSONResponse + { + try { + return new JSONResponse(['poll' => $this->pollService->get($pollId)], Http::STATUS_OK); + } catch (DoesNotExistException $e) { + return new JSONResponse(['error' => 'Not found'], Http::STATUS_NOT_FOUND); + } catch (Exception $e) { + return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); + } + } + + /** + * get acl for poll + * @param $pollId Poll id + * @deprecated 8.0.0 Use UserApiController::getSession instead + */ + #[CORS] + #[NoAdminRequired] + #[NoCSRFRequired] + public function getAcl(): JSONResponse + { + try { + return new JSONResponse(['acl' => $this->acl], Http::STATUS_OK); + } catch (DoesNotExistException $e) { + return new JSONResponse(['error' => 'Not found'], Http::STATUS_NOT_FOUND); + } catch (Exception $e) { + return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); + } + } } diff --git a/lib/Controller/PollController.php b/lib/Controller/PollController.php index ce5eed8e3..b16e96d44 100644 --- a/lib/Controller/PollController.php +++ b/lib/Controller/PollController.php @@ -17,6 +17,7 @@ use OCA\Polls\Service\ShareService; use OCA\Polls\Service\SubscriptionService; use OCA\Polls\Service\VoteService; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -45,6 +46,7 @@ public function __construct( * Get list of polls */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/polls')] public function list(): JSONResponse { return $this->response(function () { $appSettings = Server::get(AppSettings::class); @@ -63,6 +65,7 @@ public function list(): JSONResponse { * @param int $pollId Poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/poll')] public function get(int $pollId): JSONResponse { return $this->response(fn () => [ 'poll' => $this->pollService->get($pollId), @@ -75,6 +78,7 @@ public function get(int $pollId): JSONResponse { * @param int $pollId Poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}')] public function getFull(int $pollId): JSONResponse { return $this->response(fn () => [ 'poll' => $this->pollService->get($pollId), @@ -93,6 +97,7 @@ public function getFull(int $pollId): JSONResponse { * @param string $type Poll type ('datePoll', 'textPoll') */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/poll/add')] public function add(string $type, string $title): JSONResponse { return $this->responseCreate(fn () => $this->pollService->add($type, $title)); } @@ -103,6 +108,7 @@ public function add(string $type, string $title): JSONResponse { * @param array $poll poll config */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/poll/{pollId}')] public function update(int $pollId, array $poll): JSONResponse { return $this->response(fn () => [ 'poll' => $this->pollService->update($pollId, $poll), @@ -115,6 +121,7 @@ public function update(int $pollId, array $poll): JSONResponse { * @param int $pollId Poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/poll/{pollId}/confirmation')] public function sendConfirmation(int $pollId): JSONResponse { return $this->response(fn () => [ 'confirmations' => $this->mailService->sendConfirmations($pollId), @@ -122,10 +129,11 @@ public function sendConfirmation(int $pollId): JSONResponse { } /** - * Switch deleted status (move to deleted polls) + * Switch archived status (move to archive polls) * @param int $pollId Poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/poll/{pollId}/toggleArchive')] public function toggleArchive(int $pollId): JSONResponse { return $this->response(fn () => $this->pollService->toggleArchive($pollId)); } @@ -135,7 +143,7 @@ public function toggleArchive(int $pollId): JSONResponse { * @param int $pollId Poll id */ #[NoAdminRequired] - + #[FrontpageRoute(verb: 'DELETE', url: '/poll/{pollId}')] public function delete(int $pollId): JSONResponse { return $this->responseDeleteTolerant(fn () => $this->pollService->delete($pollId)); } @@ -145,6 +153,7 @@ public function delete(int $pollId): JSONResponse { * @param int $pollId Poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/poll/{pollId}/close')] public function close(int $pollId): JSONResponse { return $this->response(fn () => [ 'poll' => $this->pollService->close($pollId), @@ -157,6 +166,7 @@ public function close(int $pollId): JSONResponse { * @param int $pollId Poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/poll/{pollId}/reopen')] public function reopen(int $pollId): JSONResponse { return $this->response(fn () => [ 'poll' => $this->pollService->reopen($pollId), @@ -169,6 +179,7 @@ public function reopen(int $pollId): JSONResponse { * @param int $pollId Poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/poll/{pollId}/clone')] public function clone(int $pollId): JSONResponse { return $this->response(fn () => $this->clonePoll($pollId)); } @@ -184,6 +195,7 @@ private function clonePoll(int $pollId): JSONResponse { * @param string $sourceUser User to transfer polls from * @param string $targetUser User to transfer polls to */ + #[FrontpageRoute(verb: 'PUT', url: '/poll/transfer/{sourceUser}/{targetUser}')] public function transferPolls(string $sourceUser, string $targetUser): JSONResponse { return $this->response(fn () => $this->pollService->transferPolls($sourceUser, $targetUser)); } @@ -193,6 +205,7 @@ public function transferPolls(string $sourceUser, string $targetUser): JSONRespo * @param int $pollId Poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/addresses')] public function getParticipantsEmailAddresses(int $pollId): JSONResponse { return $this->response(fn () => $this->pollService->getParticipantsEmailAddresses($pollId)); } diff --git a/lib/Controller/PublicController.php b/lib/Controller/PublicController.php index 60bc8dbcb..48491eefd 100644 --- a/lib/Controller/PublicController.php +++ b/lib/Controller/PublicController.php @@ -21,6 +21,7 @@ use OCA\Polls\Service\VoteService; use OCA\Polls\Service\WatchService; use OCA\Polls\UserSession; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\JSONResponse; @@ -61,6 +62,7 @@ public function __construct( #[PublicPage] #[NoCSRFRequired] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'GET', url: '/s/{token}')] public function votePage() { Util::addScript(AppConstants::APP_ID, 'polls-main'); if ($this->userSession->getIsLoggedIn()) { @@ -77,6 +79,7 @@ public function votePage() { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'GET', url: '/s/{token}/poll')] public function getPoll(): JSONResponse { return $this->response(function () { return [ @@ -97,6 +100,7 @@ public function getPoll(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'GET', url: '/s/{token}/acl')] public function getAcl(): JSONResponse { return $this->response(fn () => [ 'acl' => $this->acl @@ -108,6 +112,7 @@ public function getAcl(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'GET', url: '/s/{token}/session')] public function getSession(): JSONResponse { return $this->response(fn () => [ 'token' => $this->request->getParam('token'), @@ -125,6 +130,7 @@ public function getSession(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'GET', url: '/s/{token}/watch')] public function watchPoll(?int $offset): JSONResponse { return $this->responseLong(fn () => [ 'updates' => $this->watchService->watchUpdates($this->userSession->getShare()->getPollId(), $offset) @@ -137,6 +143,7 @@ public function watchPoll(?int $offset): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'GET', url: '/s/{token}/share')] public function getShare(string $token): JSONResponse { return $this->response(fn () => [ 'share' => $this->shareService->request($token) @@ -148,6 +155,7 @@ public function getShare(string $token): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'GET', url: '/s/{token}/votes')] public function getVotes(): JSONResponse { return $this->response(fn () => [ 'votes' => $this->voteService->list($this->userSession->getShare()->getPollId()) @@ -159,6 +167,7 @@ public function getVotes(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/s/{token}/user')] public function deleteUser(): JSONResponse { return $this->response(fn () => [ 'deleted' => $this->voteService->deleteUserFromPoll($this->userSession->getShare()->getPollId()) @@ -170,6 +179,7 @@ public function deleteUser(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/s/{token}/votes/orphaned')] public function deleteOrphanedVotes(): JSONResponse { return $this->response(fn () => [ 'deleted' => $this->voteService->deleteUserFromPoll($this->userSession->getShare()->getPollId(), deleteOnlyOrphaned: true) @@ -181,6 +191,7 @@ public function deleteOrphanedVotes(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'GET', url: '/s/{token}/options')] public function getOptions(): JSONResponse { return $this->response(fn () => [ 'options' => $this->optionService->list($this->userSession->getShare()->getPollId()) @@ -195,6 +206,7 @@ public function getOptions(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'POST', url: '/s/{token}/option')] public function addOption(int $timestamp = 0, string $text = '', int $duration = 0): JSONResponse { return $this->responseCreate(fn () => [ 'option' => $this->optionService->add( @@ -212,6 +224,7 @@ public function addOption(int $timestamp = 0, string $text = '', int $duration = */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/s/{token}/option/{optionId}')] public function deleteOption(int $optionId): JSONResponse { return $this->response(fn () => [ 'option' => $this->optionService->delete($optionId) @@ -224,6 +237,7 @@ public function deleteOption(int $optionId): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'POST', url: '/s/{token}/option/{optionId}/restore')] public function restoreOption(int $optionId): JSONResponse { return $this->response(fn () => [ 'option' => $this->optionService->delete($optionId, true) @@ -237,6 +251,7 @@ public function restoreOption(int $optionId): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'PUT', url: '/s/{token}/vote')] public function setVote(int $optionId, string $setTo): JSONResponse { $option = $this->optionService->get($optionId); return $this->response(fn () => [ @@ -251,6 +266,7 @@ public function setVote(int $optionId, string $setTo): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'GET', url: '/s/{token}/comments')] public function getComments(): JSONResponse { return $this->response(fn () => [ 'comments' => $this->commentService->list($this->userSession->getShare()->getPollId()) @@ -263,6 +279,7 @@ public function getComments(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'POST', url: '/s/{token}/comment')] public function addComment(string $message): JSONResponse { return $this->response(fn () => [ 'comment' => $this->commentService->add($message, $this->userSession->getShare()->getPollId()) @@ -275,6 +292,7 @@ public function addComment(string $message): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/s/{token}/comment/{commentId}')] public function deleteComment(int $commentId): JSONResponse { return $this->response(fn () => [ 'comment' => $this->commentService->delete($commentId) @@ -287,6 +305,7 @@ public function deleteComment(int $commentId): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'PUT', url: '/s/{token}/comment/{commentId}/restore')] public function restoreComment(int $commentId): JSONResponse { return $this->response(fn () => [ 'comment' => $this->commentService->delete($commentId, true) @@ -298,6 +317,7 @@ public function restoreComment(int $commentId): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'GET', url: '/s/{token}/subscription')] public function getSubscription(): JSONResponse { return $this->response(fn () => [ 'subscribed' => $this->subscriptionService->get($this->userSession->getShare()->getPollId()) @@ -309,6 +329,7 @@ public function getSubscription(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'POST', url: '/s/{token}/subscribe')] public function subscribe(): JSONResponse { return $this->response(fn () => [ 'subscribed' => $this->subscriptionService->set(true, $this->userSession->getShare()->getPollId()) @@ -320,6 +341,7 @@ public function subscribe(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'POST', url: '/s/{token}/unsubscribe')] public function unsubscribe(): JSONResponse { return $this->response(fn () => [ 'subscribed' => $this->subscriptionService->set(false, $this->userSession->getShare()->getPollId()) @@ -334,6 +356,7 @@ public function unsubscribe(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'POST', url: '/check/username')] public function validatePublicDisplayName(string $displayName, string $token): JSONResponse { return $this->response(fn () => [ 'name' => $this->systemService->validatePublicUsernameByToken($displayName, $token) @@ -346,6 +369,7 @@ public function validatePublicDisplayName(string $displayName, string $token): J */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'GET', url: '/check/emailaddress/{emailAddress}')] public function validateEmailAddress(string $emailAddress): JSONResponse { return $this->response(fn () => [ 'result' => MailService::validateEmailAddress($emailAddress), 'emailAddress' => $emailAddress @@ -359,6 +383,7 @@ public function validateEmailAddress(string $emailAddress): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'PUT', url: '/s/{token}/name/{displayName}')] public function setDisplayName(string $token, string $displayName): JSONResponse { return $this->response(fn () => [ 'share' => $this->shareService->setDisplayname($displayName, $token) @@ -373,6 +398,7 @@ public function setDisplayName(string $token, string $displayName): JSONResponse */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'PUT', url: '/s/{token}/email/{emailAddress}')] public function setEmailAddress(string $token, string $emailAddress = ''): JSONResponse { return $this->response(fn () => [ 'share' => $this->shareService->setEmailAddress($this->shareService->get($token), $emailAddress) @@ -385,6 +411,7 @@ public function setEmailAddress(string $token, string $emailAddress = ''): JSONR */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/s/{token}/email')] public function deleteEmailAddress(string $token): JSONResponse { return $this->response(fn () => [ 'share' => $this->shareService->deleteEmailAddress($this->shareService->get($token)) @@ -401,6 +428,7 @@ public function deleteEmailAddress(string $token): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'POST', url: '/s/{token}/register')] public function register(string $token, string $displayName, string $emailAddress = '', string $timeZone = ''): JSONResponse { return $this->responseCreate(fn () => [ 'share' => $this->shareService->register($token, $displayName, $emailAddress, $timeZone), @@ -414,6 +442,7 @@ public function register(string $token, string $displayName, string $emailAddres */ #[PublicPage] #[ShareTokenRequired] + #[FrontpageRoute(verb: 'POST', url: '/s/{token}/resend')] public function resendInvitation(string $token): JSONResponse { $share = $this->shareService->get($token); return $this->response(fn () => [ diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 2318daa67..132e2d8eb 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -9,6 +9,7 @@ namespace OCA\Polls\Controller; use OCA\Polls\Service\SettingsService; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\JSONResponse; @@ -31,6 +32,7 @@ public function __construct( */ #[NoAdminRequired] #[PublicPage] + #[FrontpageRoute(verb: 'GET', url: '/settings/app')] public function getAppSettings(): JSONResponse { return $this->response(fn () => ['appSettings' => $this->settingsService->getAppSettings()]); } @@ -39,6 +41,7 @@ public function getAppSettings(): JSONResponse { * Write app settings * @param array $appSettings Settings as array */ + #[FrontpageRoute(verb: 'POST', url: '/settings/app')] public function writeAppSettings(array $appSettings): JSONResponse { $this->settingsService->writeAppSettings($appSettings); return $this->response(fn () => ['appSettings' => $this->settingsService->getAppSettings()]); diff --git a/lib/Controller/ShareApiController.php b/lib/Controller/ShareApiController.php index 3b7b8987d..af62a5cc7 100644 --- a/lib/Controller/ShareApiController.php +++ b/lib/Controller/ShareApiController.php @@ -11,6 +11,7 @@ use OCA\Polls\Service\MailService; use OCA\Polls\Service\ShareService; use OCP\AppFramework\Http\Attribute\CORS; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\JSONResponse; @@ -36,6 +37,7 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}/shares')] public function list(int $pollId): JSONResponse { return $this->response(fn () => ['shares' => $this->shareService->list($pollId)]); } @@ -46,6 +48,7 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/api/v1/share/{token}')] public function get(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->get($token)]); } @@ -61,6 +64,7 @@ public function get(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/share/{type}')] public function add(int $pollId, string $type, string $userId = '', string $displayName = '', string $emailAddress = ''): JSONResponse { return $this->responseCreate(fn () => ['share' => $this->shareService->add($pollId, $type, $userId, $displayName, $emailAddress)]); } @@ -72,6 +76,7 @@ public function add(int $pollId, string $type, string $userId = '', string $disp #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/share/{token}')] public function delete(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->deleteByToken($token)]); } @@ -83,6 +88,7 @@ public function delete(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/share/{token}/restore')] public function restore(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->deleteByToken($token, restore: true)]); } @@ -94,6 +100,7 @@ public function restore(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/share/{token}/lock')] public function lock(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->lockByToken($token)]); } @@ -105,6 +112,7 @@ public function lock(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/share/{token}/unlock')] public function unlock(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->lockByToken($token, unlock: true)]); } @@ -117,6 +125,7 @@ public function unlock(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'POST', url: '/api/v1/share/{token}/invite')] public function sendInvitation(string $token): JSONResponse { $share = $this->shareService->get($token); return $this->response(fn () => [ diff --git a/lib/Controller/ShareController.php b/lib/Controller/ShareController.php index dd334e12f..bc65a229f 100644 --- a/lib/Controller/ShareController.php +++ b/lib/Controller/ShareController.php @@ -10,6 +10,7 @@ use OCA\Polls\Db\Share; use OCA\Polls\Service\ShareService; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -31,6 +32,7 @@ public function __construct( * @param int $pollId poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/shares')] public function list(int $pollId): JSONResponse { return $this->response(fn () => ['shares' => $this->shareService->list($pollId)]); } @@ -44,6 +46,7 @@ public function list(int $pollId): JSONResponse { * @param string $emailAddress Email address of user */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/poll/{pollId}/share')] public function add(int $pollId, string $type, string $userId = '', string $displayName = '', string $emailAddress = ''): JSONResponse { return $this->responseCreate(fn () => ['share' => $this->shareService->add($pollId, $type, $userId, $displayName, $emailAddress)]); } @@ -54,6 +57,7 @@ public function add(int $pollId, string $type, string $userId = '', string $disp * @param string $value new value */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/share/{token}/publicpollemail/{value}')] public function setPublicPollEmail(string $token, string $value): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->setPublicPollEmail($token, $value)]); } @@ -61,9 +65,10 @@ public function setPublicPollEmail(string $token, string $value): JSONResponse { /** * Change Label of a public share * @param string $token Share token - * @param string $label new label of oublic poll + * @param string $label new label of public poll */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/setlabel')] public function setLabel(string $token, string $label = ''): JSONResponse { return $this->response(fn () => [ 'share' => $this->shareService->setLabel($label, $token) @@ -75,6 +80,7 @@ public function setLabel(string $token, string $label = ''): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/user')] public function adminToUser(string $token): JSONResponse { return $this->responseCreate(fn () => ['share' => $this->shareService->setType($token, Share::TYPE_USER)]); } @@ -84,28 +90,17 @@ public function adminToUser(string $token): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/admin')] public function userToAdmin(string $token): JSONResponse { return $this->responseCreate(fn () => ['share' => $this->shareService->setType($token, Share::TYPE_ADMIN)]); } - /** - * Set email address - * @param string $token Share token - * @param string $emailAddress Email address - */ - #[NoAdminRequired] - public function setEmailAddress(string $token, string $emailAddress = ''): JSONResponse { - return $this->response(fn () => [ - 'share' => $this->shareService->setEmailAddress($this->shareService->get($token), - $emailAddress) - ]); - } - /** * Delete share * @param string $token Share token */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/share/{token}')] public function delete(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->deleteByToken($token)]); } @@ -115,6 +110,7 @@ public function delete(string $token): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/restore')] public function restore(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->deleteByToken($token, restore: true)]); } @@ -124,6 +120,7 @@ public function restore(string $token): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/lock')] public function lock(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->lockByToken($token)]); } @@ -133,6 +130,7 @@ public function lock(string $token): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/unlock')] public function unlock(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->lockByToken($token, unlock: true)]); } @@ -143,6 +141,7 @@ public function unlock(string $token): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/share/{token}/invite')] public function sendInvitation(string $token): JSONResponse { $share = $this->shareService->get($token); return $this->response(fn () => [ @@ -157,6 +156,7 @@ public function sendInvitation(string $token): JSONResponse { * @param int $pollId poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/poll/{pollId}/inviteAll')] public function sendAllInvitations(int $pollId): JSONResponse { return $this->response(fn () => [ 'poll' => $pollId, @@ -169,9 +169,27 @@ public function sendAllInvitations(int $pollId): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/share/{token}/resolve')] public function resolveGroup(string $token): JSONResponse { return $this->response(fn () => [ 'shares' => $this->shareService->resolveGroupByToken($token) ]); } + + /** + * Set email address + * @param string $token Share token + * @param string $emailAddress Email address + * @deprecated 8.0.0 Use PUT /s/{token}/email/{emailAddress} + */ + #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/email')] + public function setEmailAddress(string $token, string $emailAddress = ''): JSONResponse { + return $this->response(fn () => [ + 'share' => $this->shareService->setEmailAddress( + $this->shareService->get($token), + $emailAddress + ) + ]); + } } diff --git a/lib/Controller/SubscriptionApiController.php b/lib/Controller/SubscriptionApiController.php index dad3d1249..72560411c 100644 --- a/lib/Controller/SubscriptionApiController.php +++ b/lib/Controller/SubscriptionApiController.php @@ -12,6 +12,7 @@ use OCA\Polls\Service\SubscriptionService; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\CORS; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\JSONResponse; @@ -36,6 +37,7 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}/subscription')] public function get(int $pollId): JSONResponse { try { return new JSONResponse([ @@ -54,6 +56,7 @@ public function get(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/subscription')] public function subscribe(int $pollId): JSONResponse { try { $this->subscriptionService->set(true, $pollId); @@ -73,6 +76,7 @@ public function subscribe(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/poll/{pollId}/subscription')] public function unsubscribe(int $pollId): JSONResponse { try { $this->subscriptionService->set(false, $pollId); diff --git a/lib/Controller/SubscriptionController.php b/lib/Controller/SubscriptionController.php index bd7d3db39..0fd5c13de 100644 --- a/lib/Controller/SubscriptionController.php +++ b/lib/Controller/SubscriptionController.php @@ -9,6 +9,7 @@ namespace OCA\Polls\Controller; use OCA\Polls\Service\SubscriptionService; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -30,6 +31,7 @@ public function __construct( * @param int $pollId poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/subscription')] public function get(int $pollId): JSONResponse { return $this->response(fn () => [ 'subscribed' => $this->subscriptionService->get($pollId) @@ -41,6 +43,7 @@ public function get(int $pollId): JSONResponse { * @param int $pollId poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/poll/{pollId}/subscribe')] public function subscribe(int $pollId): JSONResponse { return $this->response(fn () => [ 'subscribed' => $this->subscriptionService->set(true, $pollId) @@ -52,6 +55,7 @@ public function subscribe(int $pollId): JSONResponse { * @param int $pollId poll id */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'PUT', url: '/poll/{pollId}/unsubscribe')] public function unsubscribe(int $pollId): JSONResponse { return $this->response(fn () => [ 'subscribed' => $this->subscriptionService->set(false, $pollId) diff --git a/lib/Controller/SystemController.php b/lib/Controller/SystemController.php index 1091e7276..85b14a346 100644 --- a/lib/Controller/SystemController.php +++ b/lib/Controller/SystemController.php @@ -10,6 +10,7 @@ use OCA\Polls\Service\SystemService; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -31,6 +32,7 @@ public function __construct( * @param string $query Search string */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/search/users/{query}')] public function userSearch(string $query = ''): JSONResponse { return new JSONResponse(['siteusers' => $this->systemService->getSiteUsersAndGroups( $query)], Http::STATUS_OK); @@ -38,6 +40,7 @@ public function userSearch(string $query = ''): JSONResponse { /** * Get a combined list of all NC groups */ + #[FrontpageRoute(verb: 'GET', url: '/groups')] public function groupAll(): JSONResponse { return new JSONResponse(['groups' => $this->systemService->getGroups()], Http::STATUS_OK); } @@ -46,6 +49,7 @@ public function groupAll(): JSONResponse { * Get a combined list of NC groups matching $query * @param string $query Search string */ + #[FrontpageRoute(verb: 'GET', url: '/groups/{query}')] public function groupSearch(string $query = ''): JSONResponse { return new JSONResponse(['groups' => $this->systemService->getGroups( $query)], Http::STATUS_OK); diff --git a/lib/Controller/UserApiController.php b/lib/Controller/UserApiController.php index 866c9b21c..995a642a9 100644 --- a/lib/Controller/UserApiController.php +++ b/lib/Controller/UserApiController.php @@ -11,6 +11,7 @@ use OCA\Polls\Model\Acl as Acl; use OCA\Polls\Service\PreferencesService; use OCP\AppFramework\Http\Attribute\CORS; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\JSONResponse; @@ -19,7 +20,8 @@ /** * @psalm-api */ -class UserApiController extends BaseApiController { +class UserApiController extends BaseApiController +{ public function __construct( string $appName, IRequest $request, @@ -30,49 +32,55 @@ public function __construct( } /** - * Get user preferences + * Write user preferences */ #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - public function getPreferences(): JSONResponse { - return $this->response(fn () => $this->preferencesService->get()); + #[FrontpageRoute(verb: 'POST', url: '/api/v1/preferences')] + public function writePreferences(array $preferences): JSONResponse + { + return $this->response(fn() => $this->preferencesService->write($preferences)); } - /** - * Get user preferences + * get user session */ #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - public function writePreferences(array $preferences): JSONResponse { - return $this->response(fn () => $this->preferencesService->write($preferences)); + #[FrontpageRoute(verb: 'GET', url: '/api/v1/session')] + public function getSession(): JSONResponse + { + return new JSONResponse([ + 'token' => $this->request->getParam('token'), + 'currentUser' => $this->acl->getCurrentUser(), + 'appPermissions' => $this->acl->getPermissionsArray(), + 'appSettings' => $this->acl->getAppSettings(), + ]); } - + /** - * get acl for poll - * @param $pollId Poll id + * Get user preferences * @deprecated 8.0.0 Use getSession instead */ #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - public function getAcl(): JSONResponse { - return $this->response(fn () => ['acl' => $this->acl]); + public function getPreferences(): JSONResponse + { + return $this->response(fn() => $this->preferencesService->get()); } + /** - * get acl for poll - * @param $pollId Poll id + * get acl + * @deprecated 8.0.0 Use getSession instead */ #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - public function getSession(): JSONResponse { - return new JSONResponse([ - 'token' => $this->request->getParam('token'), - 'currentUser' => $this->acl->getCurrentUser(), - 'appPermissions' => $this->acl->getPermissionsArray(), - 'appSettings' => $this->acl->getAppSettings(), - ]); + #[FrontpageRoute(verb: 'GET', url: '/api/v1/acl')] + public function getAcl(): JSONResponse + { + return $this->response(fn() => ['acl' => $this->acl]); } } diff --git a/lib/Controller/UserController.php b/lib/Controller/UserController.php index 430d54167..54b63c3e4 100644 --- a/lib/Controller/UserController.php +++ b/lib/Controller/UserController.php @@ -11,6 +11,7 @@ use OCA\Polls\Model\Acl; use OCA\Polls\Service\CalendarService; use OCA\Polls\Service\PreferencesService; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -33,6 +34,7 @@ public function __construct( * Read all preferences */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/preferences')] public function getPreferences(): JSONResponse { return $this->response(fn () => $this->preferencesService->get()); } @@ -42,25 +44,16 @@ public function getPreferences(): JSONResponse { * @param array $preferences */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'POST', url: '/preferences')] public function writePreferences(array $preferences): JSONResponse { return $this->response(fn () => $this->preferencesService->write($preferences)); } - /** - * get acl for user - * @deprecated 8.0.0 Use getSession instead - */ - #[NoAdminRequired] - public function getAcl(): JSONResponse { - return $this->response(fn () => [ - 'acl' => $this->acl, - ]); - } - /** * get session information */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/session')] public function getSession(): JSONResponse { return $this->response(fn () => [ 'token' => $this->request->getParam('token'), @@ -70,14 +63,27 @@ public function getSession(): JSONResponse { 'share' => null, ]); } - + /** * Read all calendars */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/calendars')] public function getCalendars(): JSONResponse { return $this->response(fn () => [ 'calendars' => $this->calendarService->getCalendars(), ]); } + + /** + * get acl for user + * @deprecated 8.0.0 Use getSession instead + */ + #[NoAdminRequired] + #[FrontpageRoute(verb: 'GET', url: '/acl')] + public function getAcl(): JSONResponse { + return $this->response(fn () => [ + 'acl' => $this->acl, + ]); + } } diff --git a/lib/Controller/VoteApiController.php b/lib/Controller/VoteApiController.php index ddbed8b72..daec275d5 100644 --- a/lib/Controller/VoteApiController.php +++ b/lib/Controller/VoteApiController.php @@ -13,6 +13,7 @@ use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\CORS; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\JSONResponse; @@ -37,6 +38,7 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}/votes')] public function list(int $pollId): JSONResponse { try { return new JSONResponse(['votes' => $this->voteService->list($pollId)], Http::STATUS_OK); @@ -55,6 +57,7 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/api/v1/option/{optionId}/vote/{answer}')] public function set(int $optionId, string $answer): JSONResponse { try { return new JSONResponse(['vote' => $this->voteService->set($optionId, $answer)], Http::STATUS_OK); @@ -73,6 +76,7 @@ public function set(int $optionId, string $answer): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/poll/{pollId}/user/{userId}')] public function delete(int $pollId, string $userId = ''): JSONResponse { return $this->response(fn () => ['deleted' => $this->voteService->deleteUserFromPoll($pollId, $userId)]); } @@ -85,6 +89,7 @@ public function delete(int $pollId, string $userId = ''): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/poll/{pollId}/votes/orphaned')] public function deleteOrphaned(int $pollId, string $userId = ''): JSONResponse { return $this->response(fn () => ['deleted' => $this->voteService->deleteUserFromPoll($pollId, $userId, deleteOnlyOrphaned: true)]); } diff --git a/lib/Controller/VoteController.php b/lib/Controller/VoteController.php index 7f58c4ef7..b5d4ebdc2 100644 --- a/lib/Controller/VoteController.php +++ b/lib/Controller/VoteController.php @@ -11,6 +11,7 @@ use OCA\Polls\Service\OptionService; use OCA\Polls\Service\PollService; use OCA\Polls\Service\VoteService; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\JSONResponse; @@ -35,7 +36,7 @@ public function __construct( * @param int $pollId poll id */ #[NoAdminRequired] - #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/votes')] public function list(int $pollId): JSONResponse { return $this->response(fn () => ['votes' => $this->voteService->list($pollId)]); } @@ -47,6 +48,8 @@ public function list(int $pollId): JSONResponse { */ #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'PUT', url: '/vote')] + // #[FrontpageRoute(verb: 'PUT', url: '/vote/{optionId}/set/{setTo}')] public function set(int $optionId, string $setTo): JSONResponse { $option = $this->optionService->get($optionId); return $this->response(fn () => [ @@ -63,6 +66,8 @@ public function set(int $optionId, string $setTo): JSONResponse { * @param string $userId User to remove */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/poll/{pollId}/user/{userId}', postfix: 'named')] + #[FrontpageRoute(verb: 'DELETE', url: '/poll/{pollId}/user', postfix: 'self')] public function delete(int $pollId, string $userId = ''): JSONResponse { return $this->response(fn () => ['deleted' => $this->voteService->deleteUserFromPoll($pollId, $userId)]); } @@ -73,6 +78,7 @@ public function delete(int $pollId, string $userId = ''): JSONResponse { * @param string $userId User to delete orphan votes from */ #[NoAdminRequired] + #[FrontpageRoute(verb: 'DELETE', url: '/poll/{pollId}/votes/orphaned')] public function deleteOrphaned(int $pollId, string $userId = ''): JSONResponse { return $this->response(fn () => ['deleted' => $this->voteService->deleteUserFromPoll($pollId, $userId, deleteOnlyOrphaned: true)]); } diff --git a/lib/Controller/WatchController.php b/lib/Controller/WatchController.php index aaeaaef2e..94b90d5de 100644 --- a/lib/Controller/WatchController.php +++ b/lib/Controller/WatchController.php @@ -9,6 +9,7 @@ namespace OCA\Polls\Controller; use OCA\Polls\Service\WatchService; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\JSONResponse; @@ -33,6 +34,7 @@ public function __construct( */ #[NoAdminRequired] #[NoCSRFRequired] + #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/watch')] public function watchPoll(int $pollId, ?int $offset): JSONResponse { return $this->responseLong(fn () => ['updates' => $this->watchService->watchUpdates($pollId, $offset)]); } From fbb379b303733628417d433b8677354fc71b6fd9 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Wed, 9 Oct 2024 18:50:58 +0200 Subject: [PATCH 2/6] migrate REST API to OCS Signed-off-by: dartcafe --- appinfo/routes.php | 9 +- lib/Controller/AdminController.php | 1 + ...Controller.php => BaseApiV1Controller.php} | 2 +- lib/Controller/BaseApiV2Controller.php | 79 ++++++++ lib/Controller/CommentApiController.php | 37 ++-- lib/Controller/OptionApiController.php | 40 ++-- lib/Controller/PollApiController.php | 187 ++++-------------- lib/Controller/ShareApiController.php | 38 ++-- lib/Controller/SubscriptionApiController.php | 58 ++---- lib/Controller/UserApiController.php | 46 +---- lib/Controller/VoteApiController.php | 41 ++-- lib/Service/CommentService.php | 8 + 12 files changed, 235 insertions(+), 311 deletions(-) rename lib/Controller/{BaseApiController.php => BaseApiV1Controller.php} (97%) create mode 100644 lib/Controller/BaseApiV2Controller.php diff --git a/appinfo/routes.php b/appinfo/routes.php index a123a149c..52f2614d6 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -7,6 +7,13 @@ return [ 'routes' => [ // REST-API calls - ['name' => 'base_api#preflighted_cors', 'url' => '/api/v1.0/{path}', 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], + ['name' => 'baseApiV1#preflighted_cors', 'url' => '/api/v1.0/{path}', 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ], + // 'ocs' => [ + // // CORS Preflight + // ['name' => 'api#preflightedCors', 'url' => $apiBase . '{path}', 'verb' => 'OPTIONS', 'requirements' => [ + // 'path' => '.+', + // 'apiVersion' => 'v2' + // ]], + // ], ]; diff --git a/lib/Controller/AdminController.php b/lib/Controller/AdminController.php index 0738165df..a40441724 100644 --- a/lib/Controller/AdminController.php +++ b/lib/Controller/AdminController.php @@ -15,6 +15,7 @@ use OCA\Polls\Service\PollService; use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\TemplateResponse; use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent; diff --git a/lib/Controller/BaseApiController.php b/lib/Controller/BaseApiV1Controller.php similarity index 97% rename from lib/Controller/BaseApiController.php rename to lib/Controller/BaseApiV1Controller.php index f9b7bf79d..d6e5e13ee 100644 --- a/lib/Controller/BaseApiController.php +++ b/lib/Controller/BaseApiV1Controller.php @@ -20,7 +20,7 @@ /** * @psalm-api */ -class BaseApiController extends ApiController { +class BaseApiV1Controller extends ApiController { public function __construct( string $appName, IRequest $request, diff --git a/lib/Controller/BaseApiV2Controller.php b/lib/Controller/BaseApiV2Controller.php new file mode 100644 index 000000000..60f3d5e8e --- /dev/null +++ b/lib/Controller/BaseApiV2Controller.php @@ -0,0 +1,79 @@ +getMessage()); + } catch (Exception $e) { + throw new OCSBadRequestException($e->getMessage()); + } + } + + /** + * response + * @param Closure $callback Callback function + */ + #[NoAdminRequired] + protected function responseLong(Closure $callback): DataResponse { + try { + return new DataResponse($callback(), Http::STATUS_OK); + } catch (DoesNotExistException $e) { + throw new OCSNotFoundException($e->getMessage()); + } catch (NoUpdatesException $e) { + return new DataResponse([], Http::STATUS_NOT_MODIFIED); + } + } + + /** + * responseCreate + * @param Closure $callback Callback function + */ + #[NoAdminRequired] + protected function responseCreate(Closure $callback): DataResponse { + try { + return new DataResponse($callback(), Http::STATUS_CREATED); + } catch (Exception $e) { + throw new OCSBadRequestException($e->getMessage()); + } + } +} diff --git a/lib/Controller/CommentApiController.php b/lib/Controller/CommentApiController.php index 87b3dafb4..9f05e32db 100644 --- a/lib/Controller/CommentApiController.php +++ b/lib/Controller/CommentApiController.php @@ -9,17 +9,17 @@ namespace OCA\Polls\Controller; use OCA\Polls\Service\CommentService; +use OCP\AppFramework\Http\Attribute\ApiRoute; use OCP\AppFramework\Http\Attribute\CORS; -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\DataResponse; use OCP\IRequest; /** * @psalm-api */ -class CommentApiController extends BaseApiController { +class CommentApiController extends BaseApiV2Controller { public function __construct( string $appName, IRequest $request, @@ -35,11 +35,9 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}/comments')] - public function list(int $pollId): JSONResponse { - return $this->response(fn () => [ - 'comments' => $this->commentService->list($pollId) - ]); + #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/poll/{pollId}/comments', requirements: ['apiVersion' => '(v2)'])] + public function list(int $pollId): DataResponse { + return $this->response(fn () => ['comments' => $this->commentService->list($pollId)]); } /** @@ -50,11 +48,9 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/comment')] - public function add(int $pollId, string $comment): JSONResponse { - return $this->response(fn () => [ - 'comment' => $this->commentService->add($comment, $pollId) - ]); + #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/poll/{pollId}/comment', requirements: ['apiVersion' => '(v2)'])] + public function add(int $pollId, string $comment): DataResponse { + return $this->response(fn () => ['comment' => $this->commentService->add($comment, $pollId)]); } /** @@ -64,10 +60,9 @@ public function add(int $pollId, string $comment): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/comment/{commentId}')] - public function delete(int $commentId): JSONResponse { - return $this->response(fn () => [ - 'comment' => $this->commentService->delete($commentId)]); + #[ApiRoute(verb: 'DELETE', url: '/api/{apiVersion}/comment/{commentId}', requirements: ['apiVersion' => '(v2)'])] + public function delete(int $commentId): DataResponse { + return $this->response(fn () => ['comment' => $this->commentService->delete($commentId)]); } /** @@ -77,10 +72,8 @@ public function delete(int $commentId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'POST', url: '/api/v1/comment/{commentId}/restore')] - public function restore(int $commentId): JSONResponse { - return $this->response(fn () => [ - 'comment' => $this->commentService->delete($commentId, true) - ]); + #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/comment/{commentId}/restore', requirements: ['apiVersion' => '(v2)'])] + public function restore(int $commentId): DataResponse { + return $this->response(fn () => ['comment' => $this->commentService->restore($commentId)]); } } diff --git a/lib/Controller/OptionApiController.php b/lib/Controller/OptionApiController.php index 00520f8e5..121de26a2 100644 --- a/lib/Controller/OptionApiController.php +++ b/lib/Controller/OptionApiController.php @@ -9,17 +9,17 @@ namespace OCA\Polls\Controller; use OCA\Polls\Service\OptionService; +use OCP\AppFramework\Http\Attribute\ApiRoute; use OCP\AppFramework\Http\Attribute\CORS; -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\DataResponse; use OCP\IRequest; /** * @psalm-api */ -class OptionApiController extends BaseApiController { +class OptionApiController extends BaseApiV2Controller { public function __construct( string $appName, IRequest $request, @@ -35,8 +35,8 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/polls/{pollId}/options')] - public function list(int $pollId): JSONResponse { + #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/poll/{pollId}/options', requirements: ['apiVersion' => '(v2)'])] + public function list(int $pollId): DataResponse { return $this->response(fn () => ['options' => $this->optionService->list($pollId)]); } @@ -50,8 +50,8 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/option')] - public function add(int $pollId, int $timestamp = 0, string $pollOptionText = '', int $duration = 0): JSONResponse { + #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/poll/{pollId}/option', requirements: ['apiVersion' => '(v2)'])] + public function add(int $pollId, int $timestamp = 0, string $pollOptionText = '', int $duration = 0): DataResponse { return $this->responseCreate(fn () => ['option' => $this->optionService->add($pollId, $timestamp, $pollOptionText, $duration)]); } @@ -64,8 +64,8 @@ public function add(int $pollId, int $timestamp = 0, string $pollOptionText = '' #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/options')] - public function addBulk(int $pollId, string $text = ''): JSONResponse { + #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/poll/{pollId}/options', requirements: ['apiVersion' => '(v2)'])] + public function addBulk(int $pollId, string $text = ''): DataResponse { return $this->responseCreate(fn () => ['options' => $this->optionService->addBulk($pollId, $text)]); } @@ -79,8 +79,8 @@ public function addBulk(int $pollId, string $text = ''): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/option/{optionId}')] - public function update(int $optionId, int $timestamp = 0, string $text = '', int $duration = 0): JSONResponse { + #[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/option/{optionId}', requirements: ['apiVersion' => '(v2)'])] + public function update(int $optionId, int $timestamp = 0, string $text = '', int $duration = 0): DataResponse { return $this->response(fn () => ['option' => $this->optionService->update($optionId, $timestamp, $text, $duration)]); } @@ -91,8 +91,8 @@ public function update(int $optionId, int $timestamp = 0, string $text = '', int #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/option/{optionId}')] - public function delete(int $optionId): JSONResponse { + #[ApiRoute(verb: 'DELETE', url: '/api/{apiVersion}/option/{optionId}', requirements: ['apiVersion' => '(v2)'])] + public function delete(int $optionId): DataResponse { return $this->response(fn () => ['option' => $this->optionService->delete($optionId)]); } @@ -103,8 +103,8 @@ public function delete(int $optionId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/option/{optionId}/restore')] - public function restore(int $optionId): JSONResponse { + #[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/option/{optionId}/restore', requirements: ['apiVersion' => '(v2)'])] + public function restore(int $optionId): DataResponse { return $this->response(fn () => ['option' => $this->optionService->delete($optionId, true)]); } @@ -115,21 +115,21 @@ public function restore(int $optionId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/option/{optionId}/confirm')] - public function confirm(int $optionId): JSONResponse { + #[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/option/{optionId}/confirm', requirements: ['apiVersion' => '(v2)'])] + public function confirm(int $optionId): DataResponse { return $this->response(fn () => ['option' => $this->optionService->confirm($optionId)]); } /** * Set order position for option * @param int $optionId option id - * @param int $order place option + * @param int $order option's new position */ #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/option/{optionId}/order/{order}')] - public function setOrder(int $optionId, int $order): JSONResponse { + #[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/option/{optionId}/order/{order}', requirements: ['apiVersion' => '(v2)'])] + public function setOrder(int $optionId, int $order): DataResponse { return $this->response(fn () => ['option' => $this->optionService->setOrder($optionId, $order)]); } } diff --git a/lib/Controller/PollApiController.php b/lib/Controller/PollApiController.php index aa8f42734..9724b8ced 100644 --- a/lib/Controller/PollApiController.php +++ b/lib/Controller/PollApiController.php @@ -8,8 +8,6 @@ namespace OCA\Polls\Controller; -use OCA\Polls\AppConstants; -use OCA\Polls\Exceptions\Exception; use OCA\Polls\Model\Acl as Acl; use OCA\Polls\Service\CommentService; use OCA\Polls\Service\OptionService; @@ -17,19 +15,17 @@ use OCA\Polls\Service\ShareService; use OCA\Polls\Service\SubscriptionService; use OCA\Polls\Service\VoteService; -use OCP\AppFramework\Db\DoesNotExistException; -use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\ApiRoute; use OCP\AppFramework\Http\Attribute\CORS; -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\DataResponse; use OCP\IRequest; /** * @psalm-api */ -class PollApiController extends BaseApiController { +class PollApiController extends BaseApiV2Controller { public function __construct( string $appName, IRequest $request, @@ -50,15 +46,9 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/polls')] - public function list(): JSONResponse { - try { - return new JSONResponse([AppConstants::APP_ID => $this->pollService->list()], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse([], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/polls', requirements: ['apiVersion' => '(v2)'])] + public function list(): DataResponse { + return $this->response(fn () => ['polls' => $this->pollService->list()]); } /** @@ -68,8 +58,8 @@ public function list(): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}')] - public function getFull(int $pollId): JSONResponse { + #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/poll/{pollId}', requirements: ['apiVersion' => '(v2)'])] + public function get(int $pollId): DataResponse { return $this->response(fn () => [ 'poll' => $this->pollService->get($pollId), 'options' => $this->optionService->list($pollId), @@ -89,13 +79,9 @@ public function getFull(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll')] - public function add(string $type, string $title): JSONResponse { - try { - return new JSONResponse(['poll' => $this->pollService->add($type, $title)], Http::STATUS_CREATED); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/poll', requirements: ['apiVersion' => '(v2)'])] + public function add(string $type, string $title): DataResponse { + return $this->responseCreate(fn () => ['poll' => $this->pollService->add($type, $title)]); } /** @@ -106,18 +92,9 @@ public function add(string $type, string $title): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/{pollId}')] - public function update(int $pollId, array $pollConfiguration): JSONResponse { - try { - return new JSONResponse([ - 'poll' => $this->pollService->update($pollId, $pollConfiguration), - 'acl' => $this->acl, - ], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'Poll not found'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/poll/{pollId}', requirements: ['apiVersion' => '(v2)'])] + public function update(int $pollId, array $pollConfiguration): DataResponse { + return $this->response(fn () => ['poll' => $this->pollService->update($pollId, $pollConfiguration)]); } /** @@ -127,15 +104,9 @@ public function update(int $pollId, array $pollConfiguration): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/{pollId}/archive/toggle')] - public function toggleArchive(int $pollId): JSONResponse { - try { - return new JSONResponse(['poll' => $this->pollService->toggleArchive($pollId)], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'Poll not found'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/poll/{pollId}/archive/toggle', requirements: ['apiVersion' => '(v2)'])] + public function toggleArchive(int $pollId): DataResponse { + return $this->response(fn () => ['poll' => $this->pollService->toggleArchive($pollId)]); } /** @@ -145,15 +116,9 @@ public function toggleArchive(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/{pollId}/close')] - public function close(int $pollId): JSONResponse { - try { - return new JSONResponse(['poll' => $this->pollService->close($pollId)], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'Poll not found'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/poll/{pollId}/close', requirements: ['apiVersion' => '(v2)'])] + public function close(int $pollId): DataResponse { + return $this->response(fn () => ['poll' => $this->pollService->close($pollId)]); } /** @@ -163,15 +128,9 @@ public function close(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/{pollId}/reopen')] - public function reopen(int $pollId): JSONResponse { - try { - return new JSONResponse(['poll' => $this->pollService->reopen($pollId)], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'Poll not found'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/poll/{pollId}/reopen', requirements: ['apiVersion' => '(v2)'])] + public function reopen(int $pollId): DataResponse { + return $this->response(fn () => ['poll' => $this->pollService->reopen($pollId)]); } /** @@ -181,15 +140,9 @@ public function reopen(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/poll/{pollId}')] - public function delete(int $pollId): JSONResponse { - try { - return new JSONResponse(['poll' => $this->pollService->delete($pollId)], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_OK); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'DELETE', url: '/api/{apiVersion}/poll/{pollId}', requirements: ['apiVersion' => '(v2)'])] + public function delete(int $pollId): DataResponse { + return $this->response(fn () => ['poll' => $this->pollService->delete($pollId)]); } /** @@ -199,15 +152,9 @@ public function delete(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/clone')] - public function clone(int $pollId): JSONResponse { - try { - return new JSONResponse(['poll' => $this->pollService->clone($pollId)], Http::STATUS_CREATED); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'Poll not found'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/poll/{pollId}/clone', requirements: ['apiVersion' => '(v2)'])] + public function clone(int $pollId): DataResponse { + return $this->responseCreate(fn () => ['poll' => $this->pollService->clone($pollId)]); } /** @@ -217,13 +164,9 @@ public function clone(int $pollId): JSONResponse { */ #[CORS] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/transfer/{sourceUser}/{targetUser}')] - public function transferPolls(string $sourceUser, string $targetUser): JSONResponse { - try { - return new JSONResponse(['transferred' => $this->pollService->transferPolls($sourceUser, $targetUser)], Http::STATUS_CREATED); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/poll/transfer/{sourceUser}/{targetUser}', requirements: ['apiVersion' => '(v2)'])] + public function transferPolls(string $sourceUser, string $targetUser): DataResponse { + return $this->response(fn () => ['transferred' => $this->pollService->transferPolls($sourceUser, $targetUser)]); } /** @@ -233,13 +176,9 @@ public function transferPolls(string $sourceUser, string $targetUser): JSONRespo */ #[CORS] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/poll/{pollId}/transfer/{targetUser}')] - public function transferPoll(int $pollId, string $targetUser): JSONResponse { - try { - return new JSONResponse(['transferred' => $this->pollService->transferPoll($pollId, $targetUser)], Http::STATUS_CREATED); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/poll/{pollId}/transfer/{targetUser}', requirements: ['apiVersion' => '(v2)'])] + public function transferPoll(int $pollId, string $targetUser): DataResponse { + return $this->response(fn () => ['transferred' => $this->pollService->transferPoll($pollId, $targetUser)]); } /** @@ -249,15 +188,9 @@ public function transferPoll(int $pollId, string $targetUser): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}/addresses')] - public function getParticipantsEmailAddresses(int $pollId): JSONResponse { - try { - return new JSONResponse($this->pollService->getParticipantsEmailAddresses($pollId), Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'Poll not found'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/poll/{pollId}/addresses', requirements: ['apiVersion' => '(v2)'])] + public function getParticipantsEmailAddresses(int $pollId): DataResponse { + return $this->response(fn () => ['addresses' => $this->pollService->getParticipantsEmailAddresses($pollId)]); } /** @@ -266,46 +199,8 @@ public function getParticipantsEmailAddresses(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/enum')] - public function enum(): JSONResponse { - return new JSONResponse($this->pollService->getValidEnum(), Http::STATUS_OK); - } - - /** - * get poll - * @param $pollId Poll id - * @deprecated 8.0.0 Use getFull instead - */ - #[CORS] - #[NoAdminRequired] - #[NoCSRFRequired] - public function get(int $pollId): JSONResponse - { - try { - return new JSONResponse(['poll' => $this->pollService->get($pollId)], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'Not found'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } - } - - /** - * get acl for poll - * @param $pollId Poll id - * @deprecated 8.0.0 Use UserApiController::getSession instead - */ - #[CORS] - #[NoAdminRequired] - #[NoCSRFRequired] - public function getAcl(): JSONResponse - { - try { - return new JSONResponse(['acl' => $this->acl], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'Not found'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/poll/enum', requirements: ['apiVersion' => '(v2)'])] + public function enum(): DataResponse { + return $this->response(fn () => ['enum' => $this->pollService->getValidEnum()]); } } diff --git a/lib/Controller/ShareApiController.php b/lib/Controller/ShareApiController.php index af62a5cc7..bb498a42a 100644 --- a/lib/Controller/ShareApiController.php +++ b/lib/Controller/ShareApiController.php @@ -10,17 +10,17 @@ use OCA\Polls\Service\MailService; use OCA\Polls\Service\ShareService; +use OCP\AppFramework\Http\Attribute\ApiRoute; use OCP\AppFramework\Http\Attribute\CORS; -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\DataResponse; use OCP\IRequest; /** * @psalm-api */ -class ShareApiController extends BaseApiController { +class ShareApiController extends BaseApiV2Controller { public function __construct( string $appName, IRequest $request, @@ -37,8 +37,8 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}/shares')] - public function list(int $pollId): JSONResponse { + #[ApiRoute(verb: 'GET', url: '/api/{appVersion}/poll/{pollId}/shares', requirements: ['apiVersion' => '(v2)'])] + public function list(int $pollId): DataResponse { return $this->response(fn () => ['shares' => $this->shareService->list($pollId)]); } @@ -48,8 +48,8 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/share/{token}')] - public function get(string $token): JSONResponse { + #[ApiRoute(verb: 'GET', url: '/api/{appVersion}/share/{token}', requirements: ['apiVersion' => '(v2)'])] + public function get(string $token): DataResponse { return $this->response(fn () => ['share' => $this->shareService->get($token)]); } @@ -64,8 +64,8 @@ public function get(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/share/{type}')] - public function add(int $pollId, string $type, string $userId = '', string $displayName = '', string $emailAddress = ''): JSONResponse { + #[ApiRoute(verb: 'POST', url: '/api/{appVersion}/poll/{pollId}/share/{type}', requirements: ['apiVersion' => '(v2)'])] + public function add(int $pollId, string $type, string $userId = '', string $displayName = '', string $emailAddress = ''): DataResponse { return $this->responseCreate(fn () => ['share' => $this->shareService->add($pollId, $type, $userId, $displayName, $emailAddress)]); } @@ -76,8 +76,8 @@ public function add(int $pollId, string $type, string $userId = '', string $disp #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/share/{token}')] - public function delete(string $token): JSONResponse { + #[ApiRoute(verb: 'DELETE', url: '/api/{appVersion}/share/{token}', requirements: ['apiVersion' => '(v2)'])] + public function delete(string $token): DataResponse { return $this->response(fn () => ['share' => $this->shareService->deleteByToken($token)]); } @@ -88,8 +88,8 @@ public function delete(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/share/{token}/restore')] - public function restore(string $token): JSONResponse { + #[ApiRoute(verb: 'PUT', url: '/api/{appVersion}/share/{token}/restore', requirements: ['apiVersion' => '(v2)'])] + public function restore(string $token): DataResponse { return $this->response(fn () => ['share' => $this->shareService->deleteByToken($token, restore: true)]); } @@ -100,8 +100,8 @@ public function restore(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/share/{token}/lock')] - public function lock(string $token): JSONResponse { + #[ApiRoute(verb: 'PUT', url: '/api/{appVersion}/share/{token}/lock', requirements: ['apiVersion' => '(v2)'])] + public function lock(string $token): DataResponse { return $this->response(fn () => ['share' => $this->shareService->lockByToken($token)]); } @@ -112,8 +112,8 @@ public function lock(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/share/{token}/unlock')] - public function unlock(string $token): JSONResponse { + #[ApiRoute(verb: 'PUT', url: '/api/{appVersion}/share/{token}/unlock', requirements: ['apiVersion' => '(v2)'])] + public function unlock(string $token): DataResponse { return $this->response(fn () => ['share' => $this->shareService->lockByToken($token, unlock: true)]); } @@ -125,8 +125,8 @@ public function unlock(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'POST', url: '/api/v1/share/{token}/invite')] - public function sendInvitation(string $token): JSONResponse { + #[ApiRoute(verb: 'POST', url: '/api/{appVersion}/share/{token}/invite', requirements: ['apiVersion' => '(v2)'])] + public function sendInvitation(string $token): DataResponse { $share = $this->shareService->get($token); return $this->response(fn () => [ 'share' => $share, diff --git a/lib/Controller/SubscriptionApiController.php b/lib/Controller/SubscriptionApiController.php index 72560411c..0902518f8 100644 --- a/lib/Controller/SubscriptionApiController.php +++ b/lib/Controller/SubscriptionApiController.php @@ -8,20 +8,18 @@ namespace OCA\Polls\Controller; -use OCA\Polls\Exceptions\Exception; use OCA\Polls\Service\SubscriptionService; -use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\ApiRoute; use OCP\AppFramework\Http\Attribute\CORS; -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\DataResponse; use OCP\IRequest; /** * @psalm-api */ -class SubscriptionApiController extends BaseApiController { +class SubscriptionApiController extends BaseApiV2Controller { public function __construct( string $appName, IRequest $request, @@ -37,16 +35,12 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}/subscription')] - public function get(int $pollId): JSONResponse { - try { - return new JSONResponse([ - 'pollId' => $pollId, - 'subscribed' => $this->subscriptionService->get($pollId), - ], Http::STATUS_OK); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/poll/{pollId}/subscription', requirements: ['apiVersion' => '(v2)'])] + public function get(int $pollId): DataResponse { + return $this->response(fn () => [ + 'pollId' => $pollId, + 'subscribed' => $this->subscriptionService->get($pollId), + ]); } /** @@ -56,17 +50,12 @@ public function get(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'POST', url: '/api/v1/poll/{pollId}/subscription')] - public function subscribe(int $pollId): JSONResponse { - try { - $this->subscriptionService->set(true, $pollId); - return new JSONResponse([ - 'pollId' => $pollId, - 'subscribed' => $this->subscriptionService->get($pollId), - ], Http::STATUS_OK); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/poll/{pollId}/subscription', requirements: ['apiVersion' => '(v2)'])] + public function subscribe(int $pollId): DataResponse { + return $this->response(fn () => [ + 'pollId' => $pollId, + 'subscribed' => $this->subscriptionService->set(true, $pollId), + ]); } /** @@ -76,16 +65,11 @@ public function subscribe(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/poll/{pollId}/subscription')] - public function unsubscribe(int $pollId): JSONResponse { - try { - $this->subscriptionService->set(false, $pollId); - return new JSONResponse([ - 'pollId' => $pollId, - 'subscribed' => $this->subscriptionService->get($pollId), - ], Http::STATUS_OK); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'DELETE', url: '/api/{apiVersion}/poll/{pollId}/subscription', requirements: ['apiVersion' => '(v2)'])] + public function unsubscribe(int $pollId): DataResponse { + return $this->response(fn () => [ + 'pollId' => $pollId, + 'subscribed' => $this->subscriptionService->set(false, $pollId), + ]); } } diff --git a/lib/Controller/UserApiController.php b/lib/Controller/UserApiController.php index 995a642a9..d4721059f 100644 --- a/lib/Controller/UserApiController.php +++ b/lib/Controller/UserApiController.php @@ -10,18 +10,17 @@ use OCA\Polls\Model\Acl as Acl; use OCA\Polls\Service\PreferencesService; +use OCP\AppFramework\Http\Attribute\ApiRoute; use OCP\AppFramework\Http\Attribute\CORS; -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\DataResponse; use OCP\IRequest; /** * @psalm-api */ -class UserApiController extends BaseApiController -{ +class UserApiController extends BaseApiV2Controller { public function __construct( string $appName, IRequest $request, @@ -37,10 +36,9 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'POST', url: '/api/v1/preferences')] - public function writePreferences(array $preferences): JSONResponse - { - return $this->response(fn() => $this->preferencesService->write($preferences)); + #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/preferences', requirements: ['apiVersion' => '(v2)'])] + public function writePreferences(array $preferences): DataResponse { + return $this->response(fn () => $this->preferencesService->write($preferences)); } /** * get user session @@ -48,39 +46,13 @@ public function writePreferences(array $preferences): JSONResponse #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/session')] - public function getSession(): JSONResponse - { - return new JSONResponse([ + #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/session', requirements: ['apiVersion' => '(v2)'])] + public function getSession(): DataResponse { + return $this->response(fn () => [ 'token' => $this->request->getParam('token'), 'currentUser' => $this->acl->getCurrentUser(), 'appPermissions' => $this->acl->getPermissionsArray(), 'appSettings' => $this->acl->getAppSettings(), ]); } - - /** - * Get user preferences - * @deprecated 8.0.0 Use getSession instead - */ - #[CORS] - #[NoAdminRequired] - #[NoCSRFRequired] - public function getPreferences(): JSONResponse - { - return $this->response(fn() => $this->preferencesService->get()); - } - - /** - * get acl - * @deprecated 8.0.0 Use getSession instead - */ - #[CORS] - #[NoAdminRequired] - #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/acl')] - public function getAcl(): JSONResponse - { - return $this->response(fn() => ['acl' => $this->acl]); - } } diff --git a/lib/Controller/VoteApiController.php b/lib/Controller/VoteApiController.php index daec275d5..8a4792bcf 100644 --- a/lib/Controller/VoteApiController.php +++ b/lib/Controller/VoteApiController.php @@ -8,21 +8,18 @@ namespace OCA\Polls\Controller; -use OCA\Polls\Exceptions\Exception; use OCA\Polls\Service\VoteService; -use OCP\AppFramework\Db\DoesNotExistException; -use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\ApiRoute; use OCP\AppFramework\Http\Attribute\CORS; -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\DataResponse; use OCP\IRequest; /** * @psalm-api */ -class VoteApiController extends BaseApiController { +class VoteApiController extends BaseApiV2Controller { public function __construct( string $appName, IRequest $request, @@ -38,15 +35,9 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'GET', url: '/api/v1/poll/{pollId}/votes')] - public function list(int $pollId): JSONResponse { - try { - return new JSONResponse(['votes' => $this->voteService->list($pollId)], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'No votes'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/poll/{pollId}/votes', requirements: ['apiVersion' => '(v2)'])] + public function list(int $pollId): DataResponse { + return $this->response(fn () => ['votes' => $this->voteService->list($pollId)]); } /** @@ -57,15 +48,9 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'PUT', url: '/api/v1/option/{optionId}/vote/{answer}')] - public function set(int $optionId, string $answer): JSONResponse { - try { - return new JSONResponse(['vote' => $this->voteService->set($optionId, $answer)], Http::STATUS_OK); - } catch (DoesNotExistException $e) { - return new JSONResponse(['error' => 'Option or poll not found'], Http::STATUS_NOT_FOUND); - } catch (Exception $e) { - return new JSONResponse(['message' => $e->getMessage()], $e->getStatus()); - } + #[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/option/{optionId}/vote/{answer}', requirements: ['apiVersion' => '(v2)'])] + public function set(int $optionId, string $answer): DataResponse { + return $this->response(fn () => ['vote' => $this->voteService->set($optionId, $answer)]); } /** @@ -76,8 +61,8 @@ public function set(int $optionId, string $answer): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/poll/{pollId}/user/{userId}')] - public function delete(int $pollId, string $userId = ''): JSONResponse { + #[ApiRoute(verb: 'DELETE', url: '/api/{apiVersion}/poll/{pollId}/user/{userId}', requirements: ['apiVersion' => '(v2)'])] + public function delete(int $pollId, string $userId = ''): DataResponse { return $this->response(fn () => ['deleted' => $this->voteService->deleteUserFromPoll($pollId, $userId)]); } @@ -89,8 +74,8 @@ public function delete(int $pollId, string $userId = ''): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - #[FrontpageRoute(verb: 'DELETE', url: '/api/v1/poll/{pollId}/votes/orphaned')] - public function deleteOrphaned(int $pollId, string $userId = ''): JSONResponse { + #[ApiRoute(verb: 'DELETE', url: '/api/{apiVersion}/poll/{pollId}/votes/orphaned', requirements: ['apiVersion' => '(v2)'])] + public function deleteOrphaned(int $pollId, string $userId = ''): DataResponse { return $this->response(fn () => ['deleted' => $this->voteService->deleteUserFromPoll($pollId, $userId, deleteOnlyOrphaned: true)]); } } diff --git a/lib/Service/CommentService.php b/lib/Service/CommentService.php index 5eb6cd2a9..da6d315d3 100644 --- a/lib/Service/CommentService.php +++ b/lib/Service/CommentService.php @@ -79,6 +79,14 @@ public function add(string $message, int $pollId): Comment { return $this->comment; } + /** + * Restore comment + * @param int $commentId id of Comment to restore + */ + public function restore(int $commentId): Comment { + return $this->delete($commentId, true); + } + /** * Delete or restore comment * @param int $commentId id of Comment to delete or restore From e7034b2ec0a3cc4652e0ef023c3f23452b14b22b Mon Sep 17 00:00:00 2001 From: dartcafe Date: Wed, 9 Oct 2024 18:51:47 +0200 Subject: [PATCH 3/6] preparation for OpenAPI Signed-off-by: dartcafe --- composer.json | 4 +- composer.lock | 77 ++++--- lib/Controller/AdminController.php | 1 + lib/Controller/PageController.php | 3 + lib/Controller/PollApiController.php | 4 +- lib/Controller/PublicController.php | 29 +++ lib/Controller/SettingsController.php | 3 + lib/Controller/ShareController.php | 15 ++ lib/Controller/SubscriptionController.php | 4 + lib/Controller/SystemController.php | 4 + lib/Controller/UserController.php | 6 + lib/Controller/VoteController.php | 5 + lib/Controller/WatchController.php | 2 + lib/ResponseDefinitions.php | 98 +++++++++ openapi.json | 223 +++++++++++++++++++ vendor-bin/openapi-extractor/composer.json | 5 + vendor-bin/openapi-extractor/composer.lock | 240 +++++++++++++++++++++ vendor-bin/phpunit/composer.lock | 24 +-- 18 files changed, 693 insertions(+), 54 deletions(-) create mode 100644 lib/ResponseDefinitions.php create mode 100644 openapi.json create mode 100644 vendor-bin/openapi-extractor/composer.json create mode 100644 vendor-bin/openapi-extractor/composer.lock diff --git a/composer.json b/composer.json index 1608f6c15..eb1c5e4cf 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "optimize-autoloader": true, "autoloader-suffix": "Polls", "platform": { - "php": "8.0" + "php": "8.1" }, "allow-plugins": { "bamarni/composer-bin-plugin": true @@ -40,7 +40,7 @@ "league/factory-muffin": "^3.0", "league/factory-muffin-faker": "^2.0", "nextcloud/coding-standard": "^1.0", - "nextcloud/ocp": "dev-stable28" + "nextcloud/ocp": "dev-stable29" }, "scripts": { "cs:check": "php-cs-fixer fix --dry-run --diff", diff --git a/composer.lock b/composer.lock index 2dcf11a66..0f22b891b 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "c6fb8ef4e12b2d41fd2e180df2bea299", + "content-hash": "16e53d6f3032c0ab17cb801f8854843d", "packages": [ { "name": "dflydev/dot-access-data", @@ -271,31 +271,31 @@ }, { "name": "nette/schema", - "version": "v1.2.5", + "version": "v1.3.2", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a" + "reference": "da801d52f0354f70a638673c4a0f04e16529431d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/0462f0166e823aad657c9224d0f849ecac1ba10a", - "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a", + "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d", + "reference": "da801d52f0354f70a638673c4a0f04e16529431d", "shasum": "" }, "require": { - "nette/utils": "^2.5.7 || ^3.1.5 || ^4.0", - "php": "7.1 - 8.3" + "nette/utils": "^4.0", + "php": "8.1 - 8.4" }, "require-dev": { - "nette/tester": "^2.3 || ^2.4", + "nette/tester": "^2.5.2", "phpstan/phpstan-nette": "^1.0", - "tracy/tracy": "^2.7" + "tracy/tracy": "^2.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -327,9 +327,9 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.2.5" + "source": "https://github.com/nette/schema/tree/v1.3.2" }, - "time": "2023-10-05T20:37:59+00:00" + "time": "2024-10-06T23:10:23+00:00" }, { "name": "nette/utils", @@ -518,25 +518,25 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.3", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "80d075412b557d41002320b96a096ca65aa2c98d" + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d", - "reference": "80d075412b557d41002320b96a096ca65aa2c98d", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -565,7 +565,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" }, "funding": [ { @@ -581,7 +581,7 @@ "type": "tidelift" } ], - "time": "2023-01-24T14:02:46+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/polyfill-php80", @@ -977,30 +977,29 @@ }, { "name": "doctrine/event-manager", - "version": "1.2.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520" + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/95aa4cb529f1e96576f3fda9f5705ada4056a520", - "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e", + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e", "shasum": "" }, "require": { - "doctrine/deprecations": "^0.5.3 || ^1", - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "conflict": { "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "~1.4.10 || ^1.8.8", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.24" + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.8.8", + "phpunit/phpunit": "^10.5", + "vimeo/psalm": "^5.24" }, "type": "library", "autoload": { @@ -1049,7 +1048,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/1.2.0" + "source": "https://github.com/doctrine/event-manager/tree/2.0.1" }, "funding": [ { @@ -1065,7 +1064,7 @@ "type": "tidelift" } ], - "time": "2022-10-12T20:51:15+00:00" + "time": "2024-05-22T20:47:39+00:00" }, { "name": "fakerphp/faker", @@ -1363,16 +1362,16 @@ }, { "name": "nextcloud/ocp", - "version": "dev-stable28", + "version": "dev-stable29", "source": { "type": "git", "url": "https://github.com/nextcloud-deps/ocp.git", - "reference": "13e5e3b853c9e8e632195a4f8bd6a0c8ef34ccee" + "reference": "5054ce1e0018c7f0946df391a54861f8172d7be2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/13e5e3b853c9e8e632195a4f8bd6a0c8ef34ccee", - "reference": "13e5e3b853c9e8e632195a4f8bd6a0c8ef34ccee", + "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/5054ce1e0018c7f0946df391a54861f8172d7be2", + "reference": "5054ce1e0018c7f0946df391a54861f8172d7be2", "shasum": "" }, "require": { @@ -1385,7 +1384,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-stable28": "28.0.0-dev" + "dev-stable29": "29.0.0-dev" } }, "notification-url": "https://packagist.org/downloads/", @@ -1401,7 +1400,7 @@ "description": "Composer package containing Nextcloud's public API (classes, interfaces)", "support": { "issues": "https://github.com/nextcloud-deps/ocp/issues", - "source": "https://github.com/nextcloud-deps/ocp/tree/stable28" + "source": "https://github.com/nextcloud-deps/ocp/tree/stable29" }, "time": "2024-09-17T00:34:06+00:00" }, @@ -1668,7 +1667,7 @@ "platform": [], "platform-dev": [], "platform-overrides": { - "php": "8.0" + "php": "8.1" }, "plugin-api-version": "2.6.0" } diff --git a/lib/Controller/AdminController.php b/lib/Controller/AdminController.php index a40441724..242fc403c 100644 --- a/lib/Controller/AdminController.php +++ b/lib/Controller/AdminController.php @@ -45,6 +45,7 @@ public function __construct( * Load admin page */ #[NoCSRFRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/administration')] public function index(): TemplateResponse { Util::addScript(AppConstants::APP_ID, 'polls-main'); diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index c1b1e9862..dcd44b03c 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -14,6 +14,7 @@ use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\TemplateResponse; use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent; use OCP\EventDispatcher\IEventDispatcher; @@ -38,6 +39,7 @@ public function __construct( */ #[NoAdminRequired] #[NoCSRFRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/', postfix: 'index')] #[FrontpageRoute(verb: 'GET', url: '/combo', postfix: 'combo')] #[FrontpageRoute(verb: 'GET', url: '/not-found', postfix: 'notFound')] @@ -54,6 +56,7 @@ public function index(): TemplateResponse { */ #[NoAdminRequired] #[NoCSRFRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/vote/{id}')] public function vote(int $id): TemplateResponse { $this->notificationService->removeNotification($id); diff --git a/lib/Controller/PollApiController.php b/lib/Controller/PollApiController.php index 9724b8ced..6473f9cfd 100644 --- a/lib/Controller/PollApiController.php +++ b/lib/Controller/PollApiController.php @@ -9,6 +9,7 @@ namespace OCA\Polls\Controller; use OCA\Polls\Model\Acl as Acl; +use OCA\Polls\ResponseDefinitions as ResponseDefinitions; use OCA\Polls\Service\CommentService; use OCA\Polls\Service\OptionService; use OCA\Polls\Service\PollService; @@ -24,7 +25,8 @@ /** * @psalm-api - */ + * @psalm-import-type PollsPoll from ResponseDefinitions + * */ class PollApiController extends BaseApiV2Controller { public function __construct( string $appName, diff --git a/lib/Controller/PublicController.php b/lib/Controller/PublicController.php index 48491eefd..d91a41572 100644 --- a/lib/Controller/PublicController.php +++ b/lib/Controller/PublicController.php @@ -23,6 +23,7 @@ use OCA\Polls\UserSession; use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\Template\PublicTemplateResponse; @@ -62,6 +63,7 @@ public function __construct( #[PublicPage] #[NoCSRFRequired] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/s/{token}')] public function votePage() { Util::addScript(AppConstants::APP_ID, 'polls-main'); @@ -79,6 +81,7 @@ public function votePage() { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/s/{token}/poll')] public function getPoll(): JSONResponse { return $this->response(function () { @@ -100,6 +103,7 @@ public function getPoll(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/s/{token}/acl')] public function getAcl(): JSONResponse { return $this->response(fn () => [ @@ -112,6 +116,7 @@ public function getAcl(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/s/{token}/session')] public function getSession(): JSONResponse { return $this->response(fn () => [ @@ -130,6 +135,7 @@ public function getSession(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/s/{token}/watch')] public function watchPoll(?int $offset): JSONResponse { return $this->responseLong(fn () => [ @@ -143,6 +149,7 @@ public function watchPoll(?int $offset): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/s/{token}/share')] public function getShare(string $token): JSONResponse { return $this->response(fn () => [ @@ -155,6 +162,7 @@ public function getShare(string $token): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/s/{token}/votes')] public function getVotes(): JSONResponse { return $this->response(fn () => [ @@ -167,6 +175,7 @@ public function getVotes(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'DELETE', url: '/s/{token}/user')] public function deleteUser(): JSONResponse { return $this->response(fn () => [ @@ -179,6 +188,7 @@ public function deleteUser(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'DELETE', url: '/s/{token}/votes/orphaned')] public function deleteOrphanedVotes(): JSONResponse { return $this->response(fn () => [ @@ -191,6 +201,7 @@ public function deleteOrphanedVotes(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/s/{token}/options')] public function getOptions(): JSONResponse { return $this->response(fn () => [ @@ -206,6 +217,7 @@ public function getOptions(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/s/{token}/option')] public function addOption(int $timestamp = 0, string $text = '', int $duration = 0): JSONResponse { return $this->responseCreate(fn () => [ @@ -224,6 +236,7 @@ public function addOption(int $timestamp = 0, string $text = '', int $duration = */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'DELETE', url: '/s/{token}/option/{optionId}')] public function deleteOption(int $optionId): JSONResponse { return $this->response(fn () => [ @@ -237,6 +250,7 @@ public function deleteOption(int $optionId): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/s/{token}/option/{optionId}/restore')] public function restoreOption(int $optionId): JSONResponse { return $this->response(fn () => [ @@ -251,6 +265,7 @@ public function restoreOption(int $optionId): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/s/{token}/vote')] public function setVote(int $optionId, string $setTo): JSONResponse { $option = $this->optionService->get($optionId); @@ -266,6 +281,7 @@ public function setVote(int $optionId, string $setTo): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/s/{token}/comments')] public function getComments(): JSONResponse { return $this->response(fn () => [ @@ -279,6 +295,7 @@ public function getComments(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/s/{token}/comment')] public function addComment(string $message): JSONResponse { return $this->response(fn () => [ @@ -292,6 +309,7 @@ public function addComment(string $message): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'DELETE', url: '/s/{token}/comment/{commentId}')] public function deleteComment(int $commentId): JSONResponse { return $this->response(fn () => [ @@ -305,6 +323,7 @@ public function deleteComment(int $commentId): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/s/{token}/comment/{commentId}/restore')] public function restoreComment(int $commentId): JSONResponse { return $this->response(fn () => [ @@ -317,6 +336,7 @@ public function restoreComment(int $commentId): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/s/{token}/subscription')] public function getSubscription(): JSONResponse { return $this->response(fn () => [ @@ -329,6 +349,7 @@ public function getSubscription(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/s/{token}/subscribe')] public function subscribe(): JSONResponse { return $this->response(fn () => [ @@ -341,6 +362,7 @@ public function subscribe(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/s/{token}/unsubscribe')] public function unsubscribe(): JSONResponse { return $this->response(fn () => [ @@ -356,6 +378,7 @@ public function unsubscribe(): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/check/username')] public function validatePublicDisplayName(string $displayName, string $token): JSONResponse { return $this->response(fn () => [ @@ -369,6 +392,7 @@ public function validatePublicDisplayName(string $displayName, string $token): J */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/check/emailaddress/{emailAddress}')] public function validateEmailAddress(string $emailAddress): JSONResponse { return $this->response(fn () => [ @@ -383,6 +407,7 @@ public function validateEmailAddress(string $emailAddress): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/s/{token}/name/{displayName}')] public function setDisplayName(string $token, string $displayName): JSONResponse { return $this->response(fn () => [ @@ -398,6 +423,7 @@ public function setDisplayName(string $token, string $displayName): JSONResponse */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/s/{token}/email/{emailAddress}')] public function setEmailAddress(string $token, string $emailAddress = ''): JSONResponse { return $this->response(fn () => [ @@ -411,6 +437,7 @@ public function setEmailAddress(string $token, string $emailAddress = ''): JSONR */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'DELETE', url: '/s/{token}/email')] public function deleteEmailAddress(string $token): JSONResponse { return $this->response(fn () => [ @@ -428,6 +455,7 @@ public function deleteEmailAddress(string $token): JSONResponse { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/s/{token}/register')] public function register(string $token, string $displayName, string $emailAddress = '', string $timeZone = ''): JSONResponse { return $this->responseCreate(fn () => [ @@ -442,6 +470,7 @@ public function register(string $token, string $displayName, string $emailAddres */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/s/{token}/resend')] public function resendInvitation(string $token): JSONResponse { $share = $this->shareService->get($token); diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 132e2d8eb..09889d127 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -11,6 +11,7 @@ use OCA\Polls\Service\SettingsService; use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -32,6 +33,7 @@ public function __construct( */ #[NoAdminRequired] #[PublicPage] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/settings/app')] public function getAppSettings(): JSONResponse { return $this->response(fn () => ['appSettings' => $this->settingsService->getAppSettings()]); @@ -41,6 +43,7 @@ public function getAppSettings(): JSONResponse { * Write app settings * @param array $appSettings Settings as array */ + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/settings/app')] public function writeAppSettings(array $appSettings): JSONResponse { $this->settingsService->writeAppSettings($appSettings); diff --git a/lib/Controller/ShareController.php b/lib/Controller/ShareController.php index bc65a229f..d784a8a67 100644 --- a/lib/Controller/ShareController.php +++ b/lib/Controller/ShareController.php @@ -12,6 +12,7 @@ use OCA\Polls\Service\ShareService; use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -32,6 +33,7 @@ public function __construct( * @param int $pollId poll id */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/shares')] public function list(int $pollId): JSONResponse { return $this->response(fn () => ['shares' => $this->shareService->list($pollId)]); @@ -46,6 +48,7 @@ public function list(int $pollId): JSONResponse { * @param string $emailAddress Email address of user */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/poll/{pollId}/share')] public function add(int $pollId, string $type, string $userId = '', string $displayName = '', string $emailAddress = ''): JSONResponse { return $this->responseCreate(fn () => ['share' => $this->shareService->add($pollId, $type, $userId, $displayName, $emailAddress)]); @@ -57,6 +60,7 @@ public function add(int $pollId, string $type, string $userId = '', string $disp * @param string $value new value */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/share/{token}/publicpollemail/{value}')] public function setPublicPollEmail(string $token, string $value): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->setPublicPollEmail($token, $value)]); @@ -68,6 +72,7 @@ public function setPublicPollEmail(string $token, string $value): JSONResponse { * @param string $label new label of public poll */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/setlabel')] public function setLabel(string $token, string $label = ''): JSONResponse { return $this->response(fn () => [ @@ -80,6 +85,7 @@ public function setLabel(string $token, string $label = ''): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/user')] public function adminToUser(string $token): JSONResponse { return $this->responseCreate(fn () => ['share' => $this->shareService->setType($token, Share::TYPE_USER)]); @@ -90,6 +96,7 @@ public function adminToUser(string $token): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/admin')] public function userToAdmin(string $token): JSONResponse { return $this->responseCreate(fn () => ['share' => $this->shareService->setType($token, Share::TYPE_ADMIN)]); @@ -100,6 +107,7 @@ public function userToAdmin(string $token): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'DELETE', url: '/share/{token}')] public function delete(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->deleteByToken($token)]); @@ -110,6 +118,7 @@ public function delete(string $token): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/restore')] public function restore(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->deleteByToken($token, restore: true)]); @@ -120,6 +129,7 @@ public function restore(string $token): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/lock')] public function lock(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->lockByToken($token)]); @@ -130,6 +140,7 @@ public function lock(string $token): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/unlock')] public function unlock(string $token): JSONResponse { return $this->response(fn () => ['share' => $this->shareService->lockByToken($token, unlock: true)]); @@ -141,6 +152,7 @@ public function unlock(string $token): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/share/{token}/invite')] public function sendInvitation(string $token): JSONResponse { $share = $this->shareService->get($token); @@ -156,6 +168,7 @@ public function sendInvitation(string $token): JSONResponse { * @param int $pollId poll id */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/poll/{pollId}/inviteAll')] public function sendAllInvitations(int $pollId): JSONResponse { return $this->response(fn () => [ @@ -169,6 +182,7 @@ public function sendAllInvitations(int $pollId): JSONResponse { * @param string $token Share token */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/share/{token}/resolve')] public function resolveGroup(string $token): JSONResponse { return $this->response(fn () => [ @@ -183,6 +197,7 @@ public function resolveGroup(string $token): JSONResponse { * @deprecated 8.0.0 Use PUT /s/{token}/email/{emailAddress} */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/share/{token}/email')] public function setEmailAddress(string $token, string $emailAddress = ''): JSONResponse { return $this->response(fn () => [ diff --git a/lib/Controller/SubscriptionController.php b/lib/Controller/SubscriptionController.php index 0fd5c13de..5ae384ff5 100644 --- a/lib/Controller/SubscriptionController.php +++ b/lib/Controller/SubscriptionController.php @@ -11,6 +11,7 @@ use OCA\Polls\Service\SubscriptionService; use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -31,6 +32,7 @@ public function __construct( * @param int $pollId poll id */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/subscription')] public function get(int $pollId): JSONResponse { return $this->response(fn () => [ @@ -43,6 +45,7 @@ public function get(int $pollId): JSONResponse { * @param int $pollId poll id */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/poll/{pollId}/subscribe')] public function subscribe(int $pollId): JSONResponse { return $this->response(fn () => [ @@ -55,6 +58,7 @@ public function subscribe(int $pollId): JSONResponse { * @param int $pollId poll id */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/poll/{pollId}/unsubscribe')] public function unsubscribe(int $pollId): JSONResponse { return $this->response(fn () => [ diff --git a/lib/Controller/SystemController.php b/lib/Controller/SystemController.php index 85b14a346..5cc62ebd5 100644 --- a/lib/Controller/SystemController.php +++ b/lib/Controller/SystemController.php @@ -12,6 +12,7 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -32,6 +33,7 @@ public function __construct( * @param string $query Search string */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/search/users/{query}')] public function userSearch(string $query = ''): JSONResponse { return new JSONResponse(['siteusers' => $this->systemService->getSiteUsersAndGroups( @@ -40,6 +42,7 @@ public function userSearch(string $query = ''): JSONResponse { /** * Get a combined list of all NC groups */ + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/groups')] public function groupAll(): JSONResponse { return new JSONResponse(['groups' => $this->systemService->getGroups()], Http::STATUS_OK); @@ -49,6 +52,7 @@ public function groupAll(): JSONResponse { * Get a combined list of NC groups matching $query * @param string $query Search string */ + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/groups/{query}')] public function groupSearch(string $query = ''): JSONResponse { return new JSONResponse(['groups' => $this->systemService->getGroups( diff --git a/lib/Controller/UserController.php b/lib/Controller/UserController.php index 54b63c3e4..0c46fe1d6 100644 --- a/lib/Controller/UserController.php +++ b/lib/Controller/UserController.php @@ -13,6 +13,7 @@ use OCA\Polls\Service\PreferencesService; use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -34,6 +35,7 @@ public function __construct( * Read all preferences */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/preferences')] public function getPreferences(): JSONResponse { return $this->response(fn () => $this->preferencesService->get()); @@ -44,6 +46,7 @@ public function getPreferences(): JSONResponse { * @param array $preferences */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'POST', url: '/preferences')] public function writePreferences(array $preferences): JSONResponse { return $this->response(fn () => $this->preferencesService->write($preferences)); @@ -53,6 +56,7 @@ public function writePreferences(array $preferences): JSONResponse { * get session information */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/session')] public function getSession(): JSONResponse { return $this->response(fn () => [ @@ -68,6 +72,7 @@ public function getSession(): JSONResponse { * Read all calendars */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/calendars')] public function getCalendars(): JSONResponse { return $this->response(fn () => [ @@ -80,6 +85,7 @@ public function getCalendars(): JSONResponse { * @deprecated 8.0.0 Use getSession instead */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/acl')] public function getAcl(): JSONResponse { return $this->response(fn () => [ diff --git a/lib/Controller/VoteController.php b/lib/Controller/VoteController.php index b5d4ebdc2..fcbee0f5c 100644 --- a/lib/Controller/VoteController.php +++ b/lib/Controller/VoteController.php @@ -14,6 +14,7 @@ use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -36,6 +37,7 @@ public function __construct( * @param int $pollId poll id */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/votes')] public function list(int $pollId): JSONResponse { return $this->response(fn () => ['votes' => $this->voteService->list($pollId)]); @@ -48,6 +50,7 @@ public function list(int $pollId): JSONResponse { */ #[NoAdminRequired] #[NoCSRFRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'PUT', url: '/vote')] // #[FrontpageRoute(verb: 'PUT', url: '/vote/{optionId}/set/{setTo}')] public function set(int $optionId, string $setTo): JSONResponse { @@ -66,6 +69,7 @@ public function set(int $optionId, string $setTo): JSONResponse { * @param string $userId User to remove */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'DELETE', url: '/poll/{pollId}/user/{userId}', postfix: 'named')] #[FrontpageRoute(verb: 'DELETE', url: '/poll/{pollId}/user', postfix: 'self')] public function delete(int $pollId, string $userId = ''): JSONResponse { @@ -78,6 +82,7 @@ public function delete(int $pollId, string $userId = ''): JSONResponse { * @param string $userId User to delete orphan votes from */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'DELETE', url: '/poll/{pollId}/votes/orphaned')] public function deleteOrphaned(int $pollId, string $userId = ''): JSONResponse { return $this->response(fn () => ['deleted' => $this->voteService->deleteUserFromPoll($pollId, $userId, deleteOnlyOrphaned: true)]); diff --git a/lib/Controller/WatchController.php b/lib/Controller/WatchController.php index 94b90d5de..10726f180 100644 --- a/lib/Controller/WatchController.php +++ b/lib/Controller/WatchController.php @@ -12,6 +12,7 @@ use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -34,6 +35,7 @@ public function __construct( */ #[NoAdminRequired] #[NoCSRFRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] #[FrontpageRoute(verb: 'GET', url: '/poll/{pollId}/watch')] public function watchPoll(int $pollId, ?int $offset): JSONResponse { return $this->responseLong(fn () => ['updates' => $this->watchService->watchUpdates($pollId, $offset)]); diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php new file mode 100644 index 000000000..3eefb1084 --- /dev/null +++ b/lib/ResponseDefinitions.php @@ -0,0 +1,98 @@ +=8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ahc\\Cli\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jitendra Adhikari", + "email": "jiten.adhikary@gmail.com" + } + ], + "description": "Command line interface library for PHP", + "keywords": [ + "argument-parser", + "argv-parser", + "cli", + "cli-action", + "cli-app", + "cli-color", + "cli-option", + "cli-writer", + "command", + "console", + "console-app", + "php-cli", + "php8", + "stream-input", + "stream-output" + ], + "support": { + "issues": "https://github.com/adhocore/php-cli/issues", + "source": "https://github.com/adhocore/php-cli/tree/v1.7.2" + }, + "funding": [ + { + "url": "https://paypal.me/ji10", + "type": "custom" + }, + { + "url": "https://github.com/adhocore", + "type": "github" + } + ], + "time": "2024-09-05T00:08:47+00:00" + }, + { + "name": "nextcloud/openapi-extractor", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nextcloud-releases/openapi-extractor.git", + "reference": "88e347097db28b6e3f8f3c221502b80a4f455b1f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nextcloud-releases/openapi-extractor/zipball/88e347097db28b6e3f8f3c221502b80a4f455b1f", + "reference": "88e347097db28b6e3f8f3c221502b80a4f455b1f", + "shasum": "" + }, + "require": { + "adhocore/cli": "^1.7", + "ext-simplexml": "*", + "nikic/php-parser": "^5.0", + "php": "^8.1", + "phpstan/phpdoc-parser": "^1.28" + }, + "require-dev": { + "nextcloud/coding-standard": "^1.2", + "nextcloud/ocp": "dev-master" + }, + "bin": [ + "generate-spec", + "merge-specs" + ], + "type": "library", + "autoload": { + "psr-4": { + "OpenAPIExtractor\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "AGPL-3.0-or-later" + ], + "description": "A tool for extracting OpenAPI specifications from Nextcloud source code", + "support": { + "issues": "https://github.com/nextcloud-releases/openapi-extractor/issues", + "source": "https://github.com/nextcloud-releases/openapi-extractor/tree/v1.0.0" + }, + "time": "2024-08-20T16:46:27+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.3.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" + }, + "time": "2024-10-08T18:51:32+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.32.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6ca22b154efdd9e3c68c56f5d94670920a1c19a4", + "reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.32.0" + }, + "time": "2024-09-26T07:23:32+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/vendor-bin/phpunit/composer.lock b/vendor-bin/phpunit/composer.lock index 97ecb351a..500a932ef 100644 --- a/vendor-bin/phpunit/composer.lock +++ b/vendor-bin/phpunit/composer.lock @@ -69,16 +69,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.3.0", + "version": "v5.3.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a" + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3abf7425cd284141dc5d8d14a9ee444de3345d1a", - "reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", "shasum": "" }, "require": { @@ -121,9 +121,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" }, - "time": "2024-09-29T13:56:26+00:00" + "time": "2024-10-08T18:51:32+00:00" }, { "name": "phar-io/manifest", @@ -566,16 +566,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.35", + "version": "10.5.36", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "7ac8b4e63f456046dcb4c9787da9382831a1874b" + "reference": "aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7ac8b4e63f456046dcb4c9787da9382831a1874b", - "reference": "7ac8b4e63f456046dcb4c9787da9382831a1874b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870", + "reference": "aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870", "shasum": "" }, "require": { @@ -647,7 +647,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.35" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.36" }, "funding": [ { @@ -663,7 +663,7 @@ "type": "tidelift" } ], - "time": "2024-09-19T10:52:21+00:00" + "time": "2024-10-08T15:36:51+00:00" }, { "name": "sebastian/cli-parser", From 7293e65c7a138aa4e816e8cf967943f27d5ccecd Mon Sep 17 00:00:00 2001 From: dartcafe Date: Wed, 9 Oct 2024 20:00:53 +0200 Subject: [PATCH 4/6] cs-fix Signed-off-by: dartcafe --- lib/ResponseDefinitions.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index 3eefb1084..617ac4391 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -22,7 +22,7 @@ * view: boolean, * vote: boolean, * } - * + * * @psalm-type PollsCurrentUserStatus = array { * userRole: string, * isLocked: boolean, @@ -37,7 +37,7 @@ * shareToken: string, * groupInvitations: string[], * } - * + * * @psalm-type PollsPollsStatus = array { * lastInteraction: int, * created: int, @@ -47,7 +47,7 @@ * countOptions: int, * countParticipants: int, * } - * + * * @psalm-type PollsUser = array { * id: string, * displayName: string, @@ -63,7 +63,7 @@ * timeZone?: string, * categories?: string[], * } - * + * * @psalm-type PollsPollConfiguration = array { * title: string, * description: string, @@ -81,7 +81,7 @@ * maxVotesPerOption: int, * maxVotesPerUser: int, * } - * + * * @psalm-type PollsPoll = array { * id: int, * type: string, From dc20d9d1459602c8e365bcb80fa1bc1ff3d6d5a2 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Wed, 9 Oct 2024 20:07:16 +0200 Subject: [PATCH 5/6] help actions Signed-off-by: dartcafe --- .github/workflows/static-analysis.yml | 2 +- openapi.json | 223 -------------------------- 2 files changed, 1 insertion(+), 224 deletions(-) delete mode 100644 openapi.json diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index f7b305be4..571c8438f 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ocp-version: ['master'] + ocp-version: ['stable29'] php-versions: ['8.1', '8.2', '8.3'] name: Psalm diff --git a/openapi.json b/openapi.json deleted file mode 100644 index 83d4b0385..000000000 --- a/openapi.json +++ /dev/null @@ -1,223 +0,0 @@ -{ - "openapi": "3.0.3", - "info": { - "title": "polls", - "version": "0.0.1", - "description": "A polls app, similar to Doodle/Dudle with the possibility to restrict access.", - "license": { - "name": "agpl" - } - }, - "components": { - "securitySchemes": { - "basic_auth": { - "type": "http", - "scheme": "basic" - }, - "bearer_auth": { - "type": "http", - "scheme": "bearer" - } - }, - "schemas": { - "OCSMeta": { - "type": "object", - "required": [ - "status", - "statuscode" - ], - "properties": { - "status": { - "type": "string" - }, - "statuscode": { - "type": "integer" - }, - "message": { - "type": "string" - }, - "totalitems": { - "type": "string" - }, - "itemsperpage": { - "type": "string" - } - } - } - } - }, - "paths": { - "/ocs/v2.php/apps/polls/api/{apiVersion}/poll/{pollId}/comments": { - "get": { - "operationId": "comment_api-list", - "summary": "Read all comments of a poll based on the poll id and return list as array", - "tags": [ - "comment_api" - ], - "security": [ - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "apiVersion", - "in": "path", - "required": true, - "schema": { - "type": "string", - "enum": [ - "v2" - ], - "default": "v2" - } - }, - { - "name": "pollId", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - }, - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "nullable": true - } - } - } - } - } - } - } - }, - "404": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "nullable": true - } - } - } - } - } - } - } - }, - "500": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "nullable": true - } - } - } - } - } - } - } - } - } - } - } - }, - "tags": [ - { - "name": "public", - "description": "Always use parent's classe response* methods to make sure, the token gets set correctly. Requesting the token inside the controller is not possible, because the token is submitted as a paramter and not known while contruction time i.e. ACL requests are not valid before calling the response* method" - } - ] -} From 3693dfcc9df17bbdeceec1d8e2fcaea9707f4539 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Wed, 9 Oct 2024 20:10:23 +0200 Subject: [PATCH 6/6] suppress error Signed-off-by: dartcafe --- lib/ResponseDefinitions.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index 617ac4391..ff5770fdf 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -93,6 +93,7 @@ * permissions: PollsPollPermissions, * revealPartitians: boolean, * } + * @psalm-suppress UnusedClass */ class ResponseDefinitions { }