|
42 | 42 | PackageUploadSerializer, |
43 | 43 | PackageUploadTaskSerializer, |
44 | 44 | SummarySerializer, |
| 45 | + YankSerializer, |
45 | 46 | ) |
46 | 47 | from pulp_python.app.utils import ( |
47 | 48 | PYPI_LAST_SERIAL, |
@@ -565,3 +566,70 @@ def retrieve(self, request, path, package, version, filename): |
565 | 566 | if provenance: |
566 | 567 | return Response(data=provenance.provenance) |
567 | 568 | return HttpResponseNotFound(f"{package} {version} {filename} provenance does not exist.") |
| 569 | + |
| 570 | + |
| 571 | +class YankView(PyPIMixin, ViewSet): |
| 572 | + """View for yank/unyank requests (PEP 592).""" |
| 573 | + |
| 574 | + endpoint_name = "yank" |
| 575 | + DEFAULT_ACCESS_POLICY = { |
| 576 | + "statements": [ |
| 577 | + { |
| 578 | + "action": ["yank", "unyank"], |
| 579 | + "principal": "authenticated", |
| 580 | + "effect": "allow", |
| 581 | + "condition": "index_has_repo_perm:python.modify_pythonrepository", |
| 582 | + }, |
| 583 | + ], |
| 584 | + } |
| 585 | + |
| 586 | + @extend_schema(request=YankSerializer, summary="Yank a package version") |
| 587 | + def yank(self, request, path): |
| 588 | + """Yank a package version, marking all its files with data-yanked.""" |
| 589 | + repo = self.distribution.repository |
| 590 | + if not repo: |
| 591 | + return HttpResponseBadRequest(reason="Index is not pointing to a repository") |
| 592 | + |
| 593 | + serializer = YankSerializer(data=request.data) |
| 594 | + serializer.is_valid(raise_exception=True) |
| 595 | + |
| 596 | + normalized = canonicalize_name(serializer.validated_data["name"]) |
| 597 | + version = serializer.validated_data["version"] |
| 598 | + repo_ver = self.get_repository_version(self.distribution) |
| 599 | + if not PythonPackageContent.objects.filter( |
| 600 | + pk__in=repo_ver.content, name_normalized=normalized, version=version |
| 601 | + ).exists(): |
| 602 | + return HttpResponseNotFound(f"{normalized}=={version} not found in repository") |
| 603 | + |
| 604 | + result = dispatch( |
| 605 | + tasks.ayank_package, |
| 606 | + exclusive_resources=[repo], |
| 607 | + kwargs={ |
| 608 | + "repository_pk": str(repo.pk), |
| 609 | + "name": serializer.validated_data["name"], |
| 610 | + "version": serializer.validated_data["version"], |
| 611 | + "reason": serializer.validated_data.get("yanked_reason", ""), |
| 612 | + }, |
| 613 | + ) |
| 614 | + return OperationPostponedResponse(result, request) |
| 615 | + |
| 616 | + @extend_schema(request=YankSerializer, summary="Unyank a package version") |
| 617 | + def unyank(self, request, path): |
| 618 | + """Unyank a package version, unmarking all its files with data-yanked.""" |
| 619 | + repo = self.distribution.repository |
| 620 | + if not repo: |
| 621 | + return HttpResponseBadRequest(reason="Index is not pointing to a repository") |
| 622 | + |
| 623 | + serializer = YankSerializer(data=request.data) |
| 624 | + serializer.is_valid(raise_exception=True) |
| 625 | + |
| 626 | + result = dispatch( |
| 627 | + tasks.aunyank_package, |
| 628 | + exclusive_resources=[repo], |
| 629 | + kwargs={ |
| 630 | + "repository_pk": str(repo.pk), |
| 631 | + "name": serializer.validated_data["name"], |
| 632 | + "version": serializer.validated_data["version"], |
| 633 | + }, |
| 634 | + ) |
| 635 | + return OperationPostponedResponse(result, request) |
0 commit comments