diff --git a/src/Controller/ApiController.php b/src/Controller/ApiController.php index a62e68ff89..66d075a2c1 100644 --- a/src/Controller/ApiController.php +++ b/src/Controller/ApiController.php @@ -16,6 +16,7 @@ use App\Entity\SecurityAdvisory; use App\Entity\User; use App\Entity\Vendor; +use App\Entity\Version; use App\Model\DownloadManager; use App\Model\ProviderManager; use App\Model\VersionIdCache; @@ -24,6 +25,7 @@ use App\Service\Scheduler; use App\Util\UserAgentParser; use Composer\Pcre\Preg; +use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; @@ -183,14 +185,14 @@ public function updatePackageAction(Request $request, string $githubWebhookSecre } #[Route(path: '/api/packages/{package}', name: 'api_edit_package', requirements: ['package' => '[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+?'], defaults: ['_format' => 'json'], methods: ['PUT'])] - public function editPackageAction(Request $request, Package $package, ValidatorInterface $validator, StatsDClient $statsd): JsonResponse + public function editPackageAction(Request $request, #[MapEntity(mapping: ['package' => 'name'])] Package $package, ValidatorInterface $validator, StatsDClient $statsd): JsonResponse { $user = $this->findUser($request); if (!$user) { return new JsonResponse(['status' => 'error', 'message' => 'Missing or invalid username/apiToken in request'], 406); } if (!$package->getMaintainers()->contains($user)) { - throw new AccessDeniedException; + return new JsonResponse(['status' => 'error', 'message' => 'You are not allowed to edit this package'], 403); } $statsd->increment('edit_package_api'); @@ -225,6 +227,35 @@ public function editPackageAction(Request $request, Package $package, ValidatorI return new JsonResponse(['status' => 'success'], 200); } + #[Route(path: '/api/packages/{package}/delete-version/{version}', name: 'api_delete_package_version', requirements: ['package' => '[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+?'], defaults: ['_format' => 'json'], methods: ['POST'])] + public function deletePackageVersionAction(Request $request, #[MapEntity(mapping: ['package' => 'name'])] Package $package, string $version, StatsDClient $statsd): JsonResponse + { + $user = $this->findUser($request); + if (!$user) { + return new JsonResponse(['status' => 'error', 'message' => 'Missing or invalid username/apiToken in request'], 406); + } + if (!$package->getMaintainers()->contains($user)) { + return new JsonResponse(['status' => 'error', 'message' => 'You are not allowed to delete this package version'], 403); + } + + $statsd->increment('delete_package_version_api'); + + $packageVersion = $package->getVersions()->findFirst(static function (int $index, Version $innerVersion) use ($version) { + return $innerVersion->getVersion() === $version; + }); + + if (!$packageVersion) { + return new JsonResponse(['status' => 'error', 'message' => 'Version not found'], 404); + } + + $repo = $this->getEM()->getRepository(Version::class); + $repo->remove($packageVersion); + $this->getEM()->flush(); + $this->getEM()->clear(); + + return new JsonResponse(['status' => 'success'], 200); + } + #[Route(path: '/jobs/{id}', name: 'get_job', requirements: ['id' => '[a-f0-9]+'], defaults: ['_format' => 'json'], methods: ['GET'])] public function getJobAction(string $id, StatsDClient $statsd): JsonResponse { diff --git a/templates/api_doc/index.html.twig b/templates/api_doc/index.html.twig index f796dc959a..d043eb1fc0 100644 --- a/templates/api_doc/index.html.twig +++ b/templates/api_doc/index.html.twig @@ -523,7 +523,7 @@ PUT https://{{ packagist_host }}/api/packages/[package name]?username=[username]
This endpoint is considered SAFE and allows either your main or safe API token to be used.
-POST https://{{ packagist_host }}/api/update-package?username=[username]&apiToken=[apiToken] {"repository":"[url]"}
+PUT https://{{ packagist_host }}/api/update-package?username=[username]&apiToken=[apiToken] {"repository":"[url]"}
{
"status": "success",
@@ -531,8 +531,27 @@ POST https://{{ packagist_host }}/api/update-package?username=[username]&api
}
Working examples:
- curl -X POST -H'Content-Type:application/json' 'https://{{ packagist_host }}/api/update-package?username={{ app.user.username|default('USERNAME') }}&apiToken=********' -d '{"repository":"https://github.com/Seldaek/monolog"}'
- curl -X POST -H'Content-Type:application/json' 'https://{{ packagist_host }}/api/update-package?username={{ app.user.username|default('USERNAME') }}&apiToken=********' -d '{"repository":"https://packagist.org/monolog/monolog"}'
+ curl -X PUT -H'Content-Type:application/json' 'https://{{ packagist_host }}/api/update-package?username={{ app.user.username|default('USERNAME') }}&apiToken=********' -d '{"repository":"https://github.com/Seldaek/monolog"}'
+ curl -X PUT -H'Content-Type:application/json' 'https://{{ packagist_host }}/api/update-package?username={{ app.user.username|default('USERNAME') }}&apiToken=********' -d '{"repository":"https://packagist.org/monolog/monolog"}'
+
This endpoint deletes a package version by package name and version. Parameters username
and apiToken
are required. Only the POST
method is allowed. The content-type: application/json
header is required.
This endpoint is considered SAFE and allows either your main or safe API token to be used.
+ +
+POST https://{{ packagist_host }}/api/packages/[package name]/delete-version/[version]?username=[username]&apiToken=[apiToken]
+
+{
+ "status": "success"
+}
+
+ Working examples:
+ curl -X POST 'https://{{ packagist_host }}/api/packages/monolog/monolog/delete-version/1.0.0?username={{ app.user.username|default('USERNAME') }}&apiToken=********'