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/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..52f2614d6 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -6,176 +6,14 @@ 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'], - - ] + ['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/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 667e6c2c5..242fc403c 100644 --- a/lib/Controller/AdminController.php +++ b/lib/Controller/AdminController.php @@ -13,7 +13,9 @@ 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\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\TemplateResponse; use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent; @@ -43,6 +45,8 @@ 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'); $this->eventDispatcher->dispatchTyped(new LoadAdditionalScriptsEvent()); @@ -52,6 +56,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 +65,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 +107,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/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 a07302fcc..9f05e32db 100644 --- a/lib/Controller/CommentApiController.php +++ b/lib/Controller/CommentApiController.php @@ -9,16 +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\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, @@ -34,10 +35,9 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -48,10 +48,9 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -61,9 +60,9 @@ public function add(int $pollId, string $comment): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -73,9 +72,8 @@ public function delete(int $commentId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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/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..121de26a2 100644 --- a/lib/Controller/OptionApiController.php +++ b/lib/Controller/OptionApiController.php @@ -9,16 +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\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, @@ -34,7 +35,8 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -48,7 +50,8 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -61,7 +64,8 @@ public function add(int $pollId, int $timestamp = 0, string $pollOptionText = '' #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -75,7 +79,8 @@ public function addBulk(int $pollId, string $text = ''): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -86,7 +91,8 @@ public function update(int $optionId, int $timestamp = 0, string $text = '', int #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -97,7 +103,8 @@ public function delete(int $optionId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -108,19 +115,21 @@ public function restore(int $optionId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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] - 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/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..dcd44b03c 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -11,8 +11,10 @@ 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\Attribute\OpenAPI; use OCP\AppFramework\Http\TemplateResponse; use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent; use OCP\EventDispatcher\IEventDispatcher; @@ -33,10 +35,15 @@ public function __construct( } /** - * reder index page + * render index page */ #[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')] + #[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 +51,13 @@ public function index(): TemplateResponse { } /** - * reder vote page + * render vote page * @param $id poll id */ #[NoAdminRequired] #[NoCSRFRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] + #[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..6473f9cfd 100644 --- a/lib/Controller/PollApiController.php +++ b/lib/Controller/PollApiController.php @@ -8,27 +8,26 @@ namespace OCA\Polls\Controller; -use OCA\Polls\AppConstants; -use OCA\Polls\Exceptions\Exception; 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; 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\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 { + * @psalm-import-type PollsPoll from ResponseDefinitions + * */ +class PollApiController extends BaseApiV2Controller { public function __construct( string $appName, IRequest $request, @@ -49,33 +48,11 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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()]); } - /** - * 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,7 +60,8 @@ public function get(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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), @@ -94,25 +72,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,12 +81,9 @@ public function getAcl(): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -137,17 +94,9 @@ public function add(string $type, string $title): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -157,14 +106,9 @@ public function update(int $pollId, array $pollConfiguration): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -174,14 +118,9 @@ public function toggleArchive(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -191,14 +130,9 @@ public function close(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -208,14 +142,9 @@ public function reopen(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -225,44 +154,33 @@ public function delete(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** * 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 { - try { - return new JSONResponse(['transferred' => $this->pollService->transferPolls($sourceUser, $destinationUser)], 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)]); } /** * 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 { - try { - return new JSONResponse(['transferred' => $this->pollService->transferPoll($pollId, $destinationUser)], 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)]); } /** @@ -272,14 +190,9 @@ public function transferPoll(int $pollId, string $destinationUser): JSONResponse #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -288,7 +201,8 @@ public function getParticipantsEmailAddresses(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - public function enum(): JSONResponse { - return new JSONResponse($this->pollService->getValidEnum(), Http::STATUS_OK); + #[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/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..d91a41572 100644 --- a/lib/Controller/PublicController.php +++ b/lib/Controller/PublicController.php @@ -21,7 +21,9 @@ 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\OpenAPI; use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\Template\PublicTemplateResponse; @@ -61,6 +63,8 @@ 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'); if ($this->userSession->getIsLoggedIn()) { @@ -77,6 +81,8 @@ public function votePage() { */ #[PublicPage] #[ShareTokenRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] + #[FrontpageRoute(verb: 'GET', url: '/s/{token}/poll')] public function getPoll(): JSONResponse { return $this->response(function () { return [ @@ -97,6 +103,8 @@ 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 () => [ 'acl' => $this->acl @@ -108,6 +116,8 @@ 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 () => [ 'token' => $this->request->getParam('token'), @@ -125,6 +135,8 @@ 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 () => [ 'updates' => $this->watchService->watchUpdates($this->userSession->getShare()->getPollId(), $offset) @@ -137,6 +149,8 @@ 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 () => [ 'share' => $this->shareService->request($token) @@ -148,6 +162,8 @@ 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 () => [ 'votes' => $this->voteService->list($this->userSession->getShare()->getPollId()) @@ -159,6 +175,8 @@ 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 () => [ 'deleted' => $this->voteService->deleteUserFromPoll($this->userSession->getShare()->getPollId()) @@ -170,6 +188,8 @@ 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 () => [ 'deleted' => $this->voteService->deleteUserFromPoll($this->userSession->getShare()->getPollId(), deleteOnlyOrphaned: true) @@ -181,6 +201,8 @@ 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 () => [ 'options' => $this->optionService->list($this->userSession->getShare()->getPollId()) @@ -195,6 +217,8 @@ 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 () => [ 'option' => $this->optionService->add( @@ -212,6 +236,8 @@ 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 () => [ 'option' => $this->optionService->delete($optionId) @@ -224,6 +250,8 @@ 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 () => [ 'option' => $this->optionService->delete($optionId, true) @@ -237,6 +265,8 @@ 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); return $this->response(fn () => [ @@ -251,6 +281,8 @@ 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 () => [ 'comments' => $this->commentService->list($this->userSession->getShare()->getPollId()) @@ -263,6 +295,8 @@ 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 () => [ 'comment' => $this->commentService->add($message, $this->userSession->getShare()->getPollId()) @@ -275,6 +309,8 @@ 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 () => [ 'comment' => $this->commentService->delete($commentId) @@ -287,6 +323,8 @@ 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 () => [ 'comment' => $this->commentService->delete($commentId, true) @@ -298,6 +336,8 @@ 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 () => [ 'subscribed' => $this->subscriptionService->get($this->userSession->getShare()->getPollId()) @@ -309,6 +349,8 @@ 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 () => [ 'subscribed' => $this->subscriptionService->set(true, $this->userSession->getShare()->getPollId()) @@ -320,6 +362,8 @@ 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 () => [ 'subscribed' => $this->subscriptionService->set(false, $this->userSession->getShare()->getPollId()) @@ -334,6 +378,8 @@ 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 () => [ 'name' => $this->systemService->validatePublicUsernameByToken($displayName, $token) @@ -346,6 +392,8 @@ 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 () => [ 'result' => MailService::validateEmailAddress($emailAddress), 'emailAddress' => $emailAddress @@ -359,6 +407,8 @@ 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 () => [ 'share' => $this->shareService->setDisplayname($displayName, $token) @@ -373,6 +423,8 @@ 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 () => [ 'share' => $this->shareService->setEmailAddress($this->shareService->get($token), $emailAddress) @@ -385,6 +437,8 @@ 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 () => [ 'share' => $this->shareService->deleteEmailAddress($this->shareService->get($token)) @@ -401,6 +455,8 @@ 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 () => [ 'share' => $this->shareService->register($token, $displayName, $emailAddress, $timeZone), @@ -414,6 +470,8 @@ 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); return $this->response(fn () => [ diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 2318daa67..09889d127 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -9,7 +9,9 @@ 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\OpenAPI; use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -31,6 +33,8 @@ 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()]); } @@ -39,6 +43,8 @@ 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); return $this->response(fn () => ['appSettings' => $this->settingsService->getAppSettings()]); diff --git a/lib/Controller/ShareApiController.php b/lib/Controller/ShareApiController.php index 3b7b8987d..bb498a42a 100644 --- a/lib/Controller/ShareApiController.php +++ b/lib/Controller/ShareApiController.php @@ -10,16 +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\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, @@ -36,7 +37,8 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -46,7 +48,8 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -61,7 +64,8 @@ public function get(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -72,7 +76,8 @@ public function add(int $pollId, string $type, string $userId = '', string $disp #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -83,7 +88,8 @@ public function delete(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -94,7 +100,8 @@ public function restore(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -105,7 +112,8 @@ public function lock(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -117,7 +125,8 @@ public function unlock(string $token): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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/ShareController.php b/lib/Controller/ShareController.php index dd334e12f..d784a8a67 100644 --- a/lib/Controller/ShareController.php +++ b/lib/Controller/ShareController.php @@ -10,7 +10,9 @@ 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\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -31,6 +33,8 @@ 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)]); } @@ -44,6 +48,8 @@ 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)]); } @@ -54,6 +60,8 @@ 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)]); } @@ -61,9 +69,11 @@ 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] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] + #[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 +85,8 @@ 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)]); } @@ -84,28 +96,19 @@ 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)]); } - /** - * 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] + #[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)]); } @@ -115,6 +118,8 @@ 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)]); } @@ -124,6 +129,8 @@ 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)]); } @@ -133,6 +140,8 @@ 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)]); } @@ -143,6 +152,8 @@ 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); return $this->response(fn () => [ @@ -157,6 +168,8 @@ 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 () => [ 'poll' => $pollId, @@ -169,9 +182,29 @@ 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 () => [ '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] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] + #[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..0902518f8 100644 --- a/lib/Controller/SubscriptionApiController.php +++ b/lib/Controller/SubscriptionApiController.php @@ -8,19 +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\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, @@ -36,15 +35,12 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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), + ]); } /** @@ -54,16 +50,12 @@ public function get(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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), + ]); } /** @@ -73,15 +65,11 @@ public function subscribe(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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/SubscriptionController.php b/lib/Controller/SubscriptionController.php index bd7d3db39..5ae384ff5 100644 --- a/lib/Controller/SubscriptionController.php +++ b/lib/Controller/SubscriptionController.php @@ -9,7 +9,9 @@ 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\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -30,6 +32,8 @@ 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 () => [ 'subscribed' => $this->subscriptionService->get($pollId) @@ -41,6 +45,8 @@ 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 () => [ 'subscribed' => $this->subscriptionService->set(true, $pollId) @@ -52,6 +58,8 @@ 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 () => [ 'subscribed' => $this->subscriptionService->set(false, $pollId) diff --git a/lib/Controller/SystemController.php b/lib/Controller/SystemController.php index 1091e7276..5cc62ebd5 100644 --- a/lib/Controller/SystemController.php +++ b/lib/Controller/SystemController.php @@ -10,7 +10,9 @@ 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\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -31,6 +33,8 @@ 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( $query)], Http::STATUS_OK); @@ -38,6 +42,8 @@ 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); } @@ -46,6 +52,8 @@ 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( $query)], Http::STATUS_OK); diff --git a/lib/Controller/UserApiController.php b/lib/Controller/UserApiController.php index 866c9b21c..d4721059f 100644 --- a/lib/Controller/UserApiController.php +++ b/lib/Controller/UserApiController.php @@ -10,16 +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\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, @@ -30,45 +31,24 @@ public function __construct( } /** - * Get user preferences + * Write user preferences */ #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - public function getPreferences(): JSONResponse { - return $this->response(fn () => $this->preferencesService->get()); - } - - /** - * Get user preferences - */ - #[CORS] - #[NoAdminRequired] - #[NoCSRFRequired] - public function writePreferences(array $preferences): JSONResponse { + #[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 acl for poll - * @param $pollId Poll id - * @deprecated 8.0.0 Use getSession instead - */ - #[CORS] - #[NoAdminRequired] - #[NoCSRFRequired] - public function getAcl(): JSONResponse { - return $this->response(fn () => ['acl' => $this->acl]); - } /** - * get acl for poll - * @param $pollId Poll id + * get user session */ #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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(), diff --git a/lib/Controller/UserController.php b/lib/Controller/UserController.php index 430d54167..0c46fe1d6 100644 --- a/lib/Controller/UserController.php +++ b/lib/Controller/UserController.php @@ -11,7 +11,9 @@ 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\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -33,6 +35,8 @@ 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()); } @@ -42,25 +46,18 @@ 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)); } - /** - * 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] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] + #[FrontpageRoute(verb: 'GET', url: '/session')] public function getSession(): JSONResponse { return $this->response(fn () => [ 'token' => $this->request->getParam('token'), @@ -70,14 +67,29 @@ public function getSession(): JSONResponse { 'share' => null, ]); } - + /** * Read all calendars */ #[NoAdminRequired] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] + #[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] + #[OpenAPI(OpenAPI::SCOPE_IGNORE)] + #[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..8a4792bcf 100644 --- a/lib/Controller/VoteApiController.php +++ b/lib/Controller/VoteApiController.php @@ -8,20 +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\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, @@ -37,14 +35,9 @@ public function __construct( #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -55,14 +48,9 @@ public function list(int $pollId): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } /** @@ -73,7 +61,8 @@ public function set(int $optionId, string $answer): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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)]); } @@ -85,7 +74,8 @@ public function delete(int $pollId, string $userId = ''): JSONResponse { #[CORS] #[NoAdminRequired] #[NoCSRFRequired] - 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/Controller/VoteController.php b/lib/Controller/VoteController.php index 7f58c4ef7..fcbee0f5c 100644 --- a/lib/Controller/VoteController.php +++ b/lib/Controller/VoteController.php @@ -11,8 +11,10 @@ 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\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -35,7 +37,8 @@ public function __construct( * @param int $pollId poll id */ #[NoAdminRequired] - #[NoCSRFRequired] + #[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)]); } @@ -47,6 +50,9 @@ 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 { $option = $this->optionService->get($optionId); return $this->response(fn () => [ @@ -63,6 +69,9 @@ 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 { return $this->response(fn () => ['deleted' => $this->voteService->deleteUserFromPoll($pollId, $userId)]); } @@ -73,6 +82,8 @@ 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 aaeaaef2e..10726f180 100644 --- a/lib/Controller/WatchController.php +++ b/lib/Controller/WatchController.php @@ -9,8 +9,10 @@ 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\Attribute\OpenAPI; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -33,6 +35,8 @@ 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..ff5770fdf --- /dev/null +++ b/lib/ResponseDefinitions.php @@ -0,0 +1,99 @@ +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 diff --git a/vendor-bin/openapi-extractor/composer.json b/vendor-bin/openapi-extractor/composer.json new file mode 100644 index 000000000..71320cbc6 --- /dev/null +++ b/vendor-bin/openapi-extractor/composer.json @@ -0,0 +1,5 @@ +{ + "require-dev": { + "nextcloud/openapi-extractor": "^1.0" + } +} diff --git a/vendor-bin/openapi-extractor/composer.lock b/vendor-bin/openapi-extractor/composer.lock new file mode 100644 index 000000000..23d4a7c38 --- /dev/null +++ b/vendor-bin/openapi-extractor/composer.lock @@ -0,0 +1,240 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "6964fdd288b96adcca764f7b24d4d678", + "packages": [], + "packages-dev": [ + { + "name": "adhocore/cli", + "version": "v1.7.2", + "source": { + "type": "git", + "url": "https://github.com/adhocore/php-cli.git", + "reference": "57834cbaa4fb68cda849417ab86577fba2b15298" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adhocore/php-cli/zipball/57834cbaa4fb68cda849417ab86577fba2b15298", + "reference": "57834cbaa4fb68cda849417ab86577fba2b15298", + "shasum": "" + }, + "require": { + "php": ">=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",