We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
As a user, I would like to be able to filter all publications for a given repository
Author: wibbit (wibbit)


Redmine Issue: 7036, https://pulp.plan.io/issues/7036

---

As a user, I would like to be able to filter all publications for a given repository.






--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pulpcore/app/viewsets/publication.py`
Content:
```
1 from gettext import gettext as _
2 
3 from django_filters import Filter
4 from django_filters.rest_framework import DjangoFilterBackend, filters
5 from rest_framework import mixins, serializers
6 from rest_framework.filters import OrderingFilter
7 
8 from pulpcore.app.models import (
9     ContentGuard,
10     RBACContentGuard,
11     ContentRedirectContentGuard,
12     Distribution,
13     Publication,
14     Content,
15 )
16 from pulpcore.app.serializers import (
17     ContentGuardSerializer,
18     DistributionSerializer,
19     PublicationSerializer,
20     RBACContentGuardSerializer,
21     ContentRedirectContentGuardSerializer,
22 )
23 from pulpcore.app.viewsets import (
24     AsyncCreateMixin,
25     AsyncRemoveMixin,
26     AsyncUpdateMixin,
27     BaseFilterSet,
28     NamedModelViewSet,
29     RolesMixin,
30 )
31 from pulpcore.app.viewsets.base import DATETIME_FILTER_OPTIONS, NAME_FILTER_OPTIONS
32 from pulpcore.app.viewsets.custom_filters import (
33     IsoDateTimeFilter,
34     LabelSelectFilter,
35     RepositoryVersionFilter,
36 )
37 
38 
39 class PublicationContentFilter(Filter):
40     def __init__(self, *args, **kwargs):
41         kwargs.setdefault("help_text", _("Content Unit referenced by HREF"))
42         super().__init__(*args, **kwargs)
43 
44     def filter(self, qs, value):
45         if value is None:
46             # user didn't supply a value
47             return qs
48 
49         if not value:
50             raise serializers.ValidationError(detail=_("No value supplied for content filter"))
51 
52         # Get the content object from the content_href
53         content = NamedModelViewSet.get_resource(value, Content)
54 
55         return qs.with_content([content.pk])
56 
57 
58 class PublicationFilter(BaseFilterSet):
59     repository_version = RepositoryVersionFilter()
60     pulp_created = IsoDateTimeFilter()
61     content = PublicationContentFilter()
62     content__in = PublicationContentFilter(field_name="content", lookup_expr="in")
63 
64     class Meta:
65         model = Publication
66         fields = {
67             "repository_version": ["exact"],
68             "pulp_created": DATETIME_FILTER_OPTIONS,
69         }
70 
71 
72 class ListPublicationViewSet(NamedModelViewSet, mixins.ListModelMixin):
73     endpoint_name = "publications"
74     queryset = Publication.objects.all()
75     serializer_class = PublicationSerializer
76     filterset_class = PublicationFilter
77 
78     @classmethod
79     def is_master_viewset(cls):
80         """Do not hide from the routers."""
81         return False
82 
83 
84 class PublicationViewSet(
85     NamedModelViewSet, mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.DestroyModelMixin
86 ):
87     endpoint_name = "publications"
88     queryset = Publication.objects.exclude(complete=False)
89     serializer_class = PublicationSerializer
90     filter_backends = (OrderingFilter, DjangoFilterBackend)
91     filterset_class = PublicationFilter
92     ordering = ("-pulp_created",)
93 
94 
95 class ContentGuardFilter(BaseFilterSet):
96     name = filters.CharFilter()
97 
98     class Meta:
99         model = ContentGuard
100         fields = {
101             "name": NAME_FILTER_OPTIONS,
102         }
103 
104 
105 class BaseContentGuardViewSet(NamedModelViewSet):
106     endpoint_name = "contentguards"
107     serializer_class = ContentGuardSerializer
108     queryset = ContentGuard.objects.all()
109     filterset_class = ContentGuardFilter
110 
111 
112 class ListContentGuardViewSet(
113     BaseContentGuardViewSet,
114     mixins.ListModelMixin,
115 ):
116     """Endpoint to list all contentguards."""
117 
118     @classmethod
119     def is_master_viewset(cls):
120         """Do not hide from the routers."""
121         return False
122 
123 
124 class ContentGuardViewSet(
125     BaseContentGuardViewSet,
126     mixins.CreateModelMixin,
127     mixins.UpdateModelMixin,
128     mixins.DestroyModelMixin,
129     mixins.RetrieveModelMixin,
130     mixins.ListModelMixin,
131 ):
132     """
133     A viewset for contentguards.
134     """
135 
136 
137 class RBACContentGuardViewSet(ContentGuardViewSet, RolesMixin):
138     """
139     Viewset for creating contentguards that use RBAC to protect content.
140     Has add and remove actions for managing permission for users and groups to download content
141     protected by this guard.
142     """
143 
144     endpoint_name = "rbac"
145     serializer_class = RBACContentGuardSerializer
146     queryset = RBACContentGuard.objects.all()
147 
148     DEFAULT_ACCESS_POLICY = {
149         "statements": [
150             {
151                 "action": ["list"],
152                 "principal": "authenticated",
153                 "effect": "allow",
154             },
155             {
156                 "action": ["create"],
157                 "principal": "authenticated",
158                 "effect": "allow",
159                 "condition": "has_model_perms:core.add_rbaccontentguard",
160             },
161             {
162                 "action": ["retrieve", "my_permissions"],
163                 "principal": "authenticated",
164                 "effect": "allow",
165                 "condition": "has_model_or_obj_perms:core.view_rbaccontentguard",
166             },
167             {
168                 "action": ["update", "partial_update"],
169                 "principal": "authenticated",
170                 "effect": "allow",
171                 "condition": "has_model_or_obj_perms:core.change_rbaccontentguard",
172             },
173             {
174                 "action": ["destroy"],
175                 "principal": "authenticated",
176                 "effect": "allow",
177                 "condition": "has_model_or_obj_perms:core.delete_rbaccontentguard",
178             },
179             {
180                 "action": ["download"],  # This is the action for the content guard permit
181                 "principal": "authenticated",
182                 "effect": "allow",
183                 "condition": "has_model_or_obj_perms:core.download_rbaccontentguard",
184             },
185             {
186                 "action": ["list_roles", "add_role", "remove_role"],
187                 "principal": "authenticated",
188                 "effect": "allow",
189                 "condition": "has_model_or_obj_perms:core.manage_roles_rbaccontentguard",
190             },
191         ],
192         "creation_hooks": [
193             {
194                 "function": "add_roles_for_object_creator",
195                 "parameters": {
196                     "roles": ["core.rbaccontentguard_owner", "core.rbaccontentguard_downloader"]
197                 },
198             },
199         ],
200     }
201     LOCKED_ROLES = {
202         "core.rbaccontentguard_creator": ["core.add_rbaccontentguard"],
203         "core.rbaccontentguard_owner": [
204             "core.view_rbaccontentguard",
205             "core.change_rbaccontentguard",
206             "core.delete_rbaccontentguard",
207             "core.manage_roles_rbaccontentguard",
208         ],
209         "core.rbaccontentguard_downloader": ["core.download_rbaccontentguard"],
210     }
211 
212 
213 class ContentRedirectContentGuardViewSet(ContentGuardViewSet):
214     """
215     Content guard to protect preauthenticated redirects to the content app.
216     """
217 
218     endpoint_name = "content_redirect"
219     queryset = ContentRedirectContentGuard.objects.all()
220     serializer_class = ContentRedirectContentGuardSerializer
221 
222 
223 class DistributionFilter(BaseFilterSet):
224     # e.g.
225     # /?name=foo
226     # /?name__in=foo,bar
227     # /?base_path__contains=foo
228     # /?base_path__icontains=foo
229     name = filters.CharFilter()
230     base_path = filters.CharFilter()
231     pulp_label_select = LabelSelectFilter()
232 
233     class Meta:
234         model = Distribution
235         fields = {
236             "name": NAME_FILTER_OPTIONS,
237             "base_path": ["exact", "contains", "icontains", "in"],
238         }
239 
240 
241 class ListDistributionViewSet(NamedModelViewSet, mixins.ListModelMixin):
242     endpoint_name = "distributions"
243     queryset = Distribution.objects.all()
244     serializer_class = DistributionSerializer
245     filterset_class = DistributionFilter
246 
247     @classmethod
248     def is_master_viewset(cls):
249         """Do not hide from the routers."""
250         return False
251 
252 
253 class DistributionViewSet(
254     NamedModelViewSet,
255     mixins.RetrieveModelMixin,
256     mixins.ListModelMixin,
257     AsyncCreateMixin,
258     AsyncRemoveMixin,
259     AsyncUpdateMixin,
260 ):
261     """
262     Provides read and list methods and also provides asynchronous CUD methods to dispatch tasks
263     with reservation that lock all Distributions preventing race conditions during base_path
264     checking.
265     """
266 
267     endpoint_name = "distributions"
268     queryset = Distribution.objects.all()
269     serializer_class = DistributionSerializer
270     filterset_class = DistributionFilter
271 
272     def async_reserved_resources(self, instance):
273         """Return resource that locks all Distributions."""
274         return ["/api/v3/distributions/"]
275
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pulpcore/app/viewsets/publication.py b/pulpcore/app/viewsets/publication.py
--- a/pulpcore/app/viewsets/publication.py
+++ b/pulpcore/app/viewsets/publication.py
@@ -11,6 +11,7 @@
     ContentRedirectContentGuard,
     Distribution,
     Publication,
+    Repository,
     Content,
 )
 from pulpcore.app.serializers import (
@@ -55,7 +56,23 @@
         return qs.with_content([content.pk])
 
 
+class RepositoryThroughVersionFilter(Filter):
+    def filter(self, qs, value):
+        if value is None:
+            # user didn't supply a value
+            return qs
+
+        if not value:
+            raise serializers.ValidationError(
+                detail=_("No value supplied for {name} filter").format(name=self.field_name)
+            )
+
+        repository = NamedModelViewSet.get_resource(value, Repository)
+        return qs.filter(repository_version__repository=repository)
+
+
 class PublicationFilter(BaseFilterSet):
+    repository = RepositoryThroughVersionFilter(help_text=_("Repository referenced by HREF"))
     repository_version = RepositoryVersionFilter()
     pulp_created = IsoDateTimeFilter()
     content = PublicationContentFilter()

{"golden_diff": "diff --git a/pulpcore/app/viewsets/publication.py b/pulpcore/app/viewsets/publication.py\n--- a/pulpcore/app/viewsets/publication.py\n+++ b/pulpcore/app/viewsets/publication.py\n@@ -11,6 +11,7 @@\n     ContentRedirectContentGuard,\n     Distribution,\n     Publication,\n+    Repository,\n     Content,\n )\n from pulpcore.app.serializers import (\n@@ -55,7 +56,23 @@\n         return qs.with_content([content.pk])\n \n \n+class RepositoryThroughVersionFilter(Filter):\n+    def filter(self, qs, value):\n+        if value is None:\n+            # user didn't supply a value\n+            return qs\n+\n+        if not value:\n+            raise serializers.ValidationError(\n+                detail=_(\"No value supplied for {name} filter\").format(name=self.field_name)\n+            )\n+\n+        repository = NamedModelViewSet.get_resource(value, Repository)\n+        return qs.filter(repository_version__repository=repository)\n+\n+\n class PublicationFilter(BaseFilterSet):\n+    repository = RepositoryThroughVersionFilter(help_text=_(\"Repository referenced by HREF\"))\n     repository_version = RepositoryVersionFilter()\n     pulp_created = IsoDateTimeFilter()\n     content = PublicationContentFilter()\n", "issue": "As a user, I would like to be able to filter all publications for a given repository\nAuthor: wibbit (wibbit)\n\n\nRedmine Issue: 7036, https://pulp.plan.io/issues/7036\n\n---\n\nAs a user, I would like to be able to filter all publications for a given repository.\r\n\r\n\n\n\n\n", "before_files": [{"content": "from gettext import gettext as _\n\nfrom django_filters import Filter\nfrom django_filters.rest_framework import DjangoFilterBackend, filters\nfrom rest_framework import mixins, serializers\nfrom rest_framework.filters import OrderingFilter\n\nfrom pulpcore.app.models import (\n    ContentGuard,\n    RBACContentGuard,\n    ContentRedirectContentGuard,\n    Distribution,\n    Publication,\n    Content,\n)\nfrom pulpcore.app.serializers import (\n    ContentGuardSerializer,\n    DistributionSerializer,\n    PublicationSerializer,\n    RBACContentGuardSerializer,\n    ContentRedirectContentGuardSerializer,\n)\nfrom pulpcore.app.viewsets import (\n    AsyncCreateMixin,\n    AsyncRemoveMixin,\n    AsyncUpdateMixin,\n    BaseFilterSet,\n    NamedModelViewSet,\n    RolesMixin,\n)\nfrom pulpcore.app.viewsets.base import DATETIME_FILTER_OPTIONS, NAME_FILTER_OPTIONS\nfrom pulpcore.app.viewsets.custom_filters import (\n    IsoDateTimeFilter,\n    LabelSelectFilter,\n    RepositoryVersionFilter,\n)\n\n\nclass PublicationContentFilter(Filter):\n    def __init__(self, *args, **kwargs):\n        kwargs.setdefault(\"help_text\", _(\"Content Unit referenced by HREF\"))\n        super().__init__(*args, **kwargs)\n\n    def filter(self, qs, value):\n        if value is None:\n            # user didn't supply a value\n            return qs\n\n        if not value:\n            raise serializers.ValidationError(detail=_(\"No value supplied for content filter\"))\n\n        # Get the content object from the content_href\n        content = NamedModelViewSet.get_resource(value, Content)\n\n        return qs.with_content([content.pk])\n\n\nclass PublicationFilter(BaseFilterSet):\n    repository_version = RepositoryVersionFilter()\n    pulp_created = IsoDateTimeFilter()\n    content = PublicationContentFilter()\n    content__in = PublicationContentFilter(field_name=\"content\", lookup_expr=\"in\")\n\n    class Meta:\n        model = Publication\n        fields = {\n            \"repository_version\": [\"exact\"],\n            \"pulp_created\": DATETIME_FILTER_OPTIONS,\n        }\n\n\nclass ListPublicationViewSet(NamedModelViewSet, mixins.ListModelMixin):\n    endpoint_name = \"publications\"\n    queryset = Publication.objects.all()\n    serializer_class = PublicationSerializer\n    filterset_class = PublicationFilter\n\n    @classmethod\n    def is_master_viewset(cls):\n        \"\"\"Do not hide from the routers.\"\"\"\n        return False\n\n\nclass PublicationViewSet(\n    NamedModelViewSet, mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.DestroyModelMixin\n):\n    endpoint_name = \"publications\"\n    queryset = Publication.objects.exclude(complete=False)\n    serializer_class = PublicationSerializer\n    filter_backends = (OrderingFilter, DjangoFilterBackend)\n    filterset_class = PublicationFilter\n    ordering = (\"-pulp_created\",)\n\n\nclass ContentGuardFilter(BaseFilterSet):\n    name = filters.CharFilter()\n\n    class Meta:\n        model = ContentGuard\n        fields = {\n            \"name\": NAME_FILTER_OPTIONS,\n        }\n\n\nclass BaseContentGuardViewSet(NamedModelViewSet):\n    endpoint_name = \"contentguards\"\n    serializer_class = ContentGuardSerializer\n    queryset = ContentGuard.objects.all()\n    filterset_class = ContentGuardFilter\n\n\nclass ListContentGuardViewSet(\n    BaseContentGuardViewSet,\n    mixins.ListModelMixin,\n):\n    \"\"\"Endpoint to list all contentguards.\"\"\"\n\n    @classmethod\n    def is_master_viewset(cls):\n        \"\"\"Do not hide from the routers.\"\"\"\n        return False\n\n\nclass ContentGuardViewSet(\n    BaseContentGuardViewSet,\n    mixins.CreateModelMixin,\n    mixins.UpdateModelMixin,\n    mixins.DestroyModelMixin,\n    mixins.RetrieveModelMixin,\n    mixins.ListModelMixin,\n):\n    \"\"\"\n    A viewset for contentguards.\n    \"\"\"\n\n\nclass RBACContentGuardViewSet(ContentGuardViewSet, RolesMixin):\n    \"\"\"\n    Viewset for creating contentguards that use RBAC to protect content.\n    Has add and remove actions for managing permission for users and groups to download content\n    protected by this guard.\n    \"\"\"\n\n    endpoint_name = \"rbac\"\n    serializer_class = RBACContentGuardSerializer\n    queryset = RBACContentGuard.objects.all()\n\n    DEFAULT_ACCESS_POLICY = {\n        \"statements\": [\n            {\n                \"action\": [\"list\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n            },\n            {\n                \"action\": [\"create\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_perms:core.add_rbaccontentguard\",\n            },\n            {\n                \"action\": [\"retrieve\", \"my_permissions\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_or_obj_perms:core.view_rbaccontentguard\",\n            },\n            {\n                \"action\": [\"update\", \"partial_update\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_or_obj_perms:core.change_rbaccontentguard\",\n            },\n            {\n                \"action\": [\"destroy\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_or_obj_perms:core.delete_rbaccontentguard\",\n            },\n            {\n                \"action\": [\"download\"],  # This is the action for the content guard permit\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_or_obj_perms:core.download_rbaccontentguard\",\n            },\n            {\n                \"action\": [\"list_roles\", \"add_role\", \"remove_role\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_or_obj_perms:core.manage_roles_rbaccontentguard\",\n            },\n        ],\n        \"creation_hooks\": [\n            {\n                \"function\": \"add_roles_for_object_creator\",\n                \"parameters\": {\n                    \"roles\": [\"core.rbaccontentguard_owner\", \"core.rbaccontentguard_downloader\"]\n                },\n            },\n        ],\n    }\n    LOCKED_ROLES = {\n        \"core.rbaccontentguard_creator\": [\"core.add_rbaccontentguard\"],\n        \"core.rbaccontentguard_owner\": [\n            \"core.view_rbaccontentguard\",\n            \"core.change_rbaccontentguard\",\n            \"core.delete_rbaccontentguard\",\n            \"core.manage_roles_rbaccontentguard\",\n        ],\n        \"core.rbaccontentguard_downloader\": [\"core.download_rbaccontentguard\"],\n    }\n\n\nclass ContentRedirectContentGuardViewSet(ContentGuardViewSet):\n    \"\"\"\n    Content guard to protect preauthenticated redirects to the content app.\n    \"\"\"\n\n    endpoint_name = \"content_redirect\"\n    queryset = ContentRedirectContentGuard.objects.all()\n    serializer_class = ContentRedirectContentGuardSerializer\n\n\nclass DistributionFilter(BaseFilterSet):\n    # e.g.\n    # /?name=foo\n    # /?name__in=foo,bar\n    # /?base_path__contains=foo\n    # /?base_path__icontains=foo\n    name = filters.CharFilter()\n    base_path = filters.CharFilter()\n    pulp_label_select = LabelSelectFilter()\n\n    class Meta:\n        model = Distribution\n        fields = {\n            \"name\": NAME_FILTER_OPTIONS,\n            \"base_path\": [\"exact\", \"contains\", \"icontains\", \"in\"],\n        }\n\n\nclass ListDistributionViewSet(NamedModelViewSet, mixins.ListModelMixin):\n    endpoint_name = \"distributions\"\n    queryset = Distribution.objects.all()\n    serializer_class = DistributionSerializer\n    filterset_class = DistributionFilter\n\n    @classmethod\n    def is_master_viewset(cls):\n        \"\"\"Do not hide from the routers.\"\"\"\n        return False\n\n\nclass DistributionViewSet(\n    NamedModelViewSet,\n    mixins.RetrieveModelMixin,\n    mixins.ListModelMixin,\n    AsyncCreateMixin,\n    AsyncRemoveMixin,\n    AsyncUpdateMixin,\n):\n    \"\"\"\n    Provides read and list methods and also provides asynchronous CUD methods to dispatch tasks\n    with reservation that lock all Distributions preventing race conditions during base_path\n    checking.\n    \"\"\"\n\n    endpoint_name = \"distributions\"\n    queryset = Distribution.objects.all()\n    serializer_class = DistributionSerializer\n    filterset_class = DistributionFilter\n\n    def async_reserved_resources(self, instance):\n        \"\"\"Return resource that locks all Distributions.\"\"\"\n        return [\"/api/v3/distributions/\"]\n", "path": "pulpcore/app/viewsets/publication.py"}], "after_files": [{"content": "from gettext import gettext as _\n\nfrom django_filters import Filter\nfrom django_filters.rest_framework import DjangoFilterBackend, filters\nfrom rest_framework import mixins, serializers\nfrom rest_framework.filters import OrderingFilter\n\nfrom pulpcore.app.models import (\n    ContentGuard,\n    RBACContentGuard,\n    ContentRedirectContentGuard,\n    Distribution,\n    Publication,\n    Repository,\n    Content,\n)\nfrom pulpcore.app.serializers import (\n    ContentGuardSerializer,\n    DistributionSerializer,\n    PublicationSerializer,\n    RBACContentGuardSerializer,\n    ContentRedirectContentGuardSerializer,\n)\nfrom pulpcore.app.viewsets import (\n    AsyncCreateMixin,\n    AsyncRemoveMixin,\n    AsyncUpdateMixin,\n    BaseFilterSet,\n    NamedModelViewSet,\n    RolesMixin,\n)\nfrom pulpcore.app.viewsets.base import DATETIME_FILTER_OPTIONS, NAME_FILTER_OPTIONS\nfrom pulpcore.app.viewsets.custom_filters import (\n    IsoDateTimeFilter,\n    LabelSelectFilter,\n    RepositoryVersionFilter,\n)\n\n\nclass PublicationContentFilter(Filter):\n    def __init__(self, *args, **kwargs):\n        kwargs.setdefault(\"help_text\", _(\"Content Unit referenced by HREF\"))\n        super().__init__(*args, **kwargs)\n\n    def filter(self, qs, value):\n        if value is None:\n            # user didn't supply a value\n            return qs\n\n        if not value:\n            raise serializers.ValidationError(detail=_(\"No value supplied for content filter\"))\n\n        # Get the content object from the content_href\n        content = NamedModelViewSet.get_resource(value, Content)\n\n        return qs.with_content([content.pk])\n\n\nclass RepositoryThroughVersionFilter(Filter):\n    def filter(self, qs, value):\n        if value is None:\n            # user didn't supply a value\n            return qs\n\n        if not value:\n            raise serializers.ValidationError(\n                detail=_(\"No value supplied for {name} filter\").format(name=self.field_name)\n            )\n\n        repository = NamedModelViewSet.get_resource(value, Repository)\n        return qs.filter(repository_version__repository=repository)\n\n\nclass PublicationFilter(BaseFilterSet):\n    repository = RepositoryThroughVersionFilter(help_text=_(\"Repository referenced by HREF\"))\n    repository_version = RepositoryVersionFilter()\n    pulp_created = IsoDateTimeFilter()\n    content = PublicationContentFilter()\n    content__in = PublicationContentFilter(field_name=\"content\", lookup_expr=\"in\")\n\n    class Meta:\n        model = Publication\n        fields = {\n            \"repository_version\": [\"exact\"],\n            \"pulp_created\": DATETIME_FILTER_OPTIONS,\n        }\n\n\nclass ListPublicationViewSet(NamedModelViewSet, mixins.ListModelMixin):\n    endpoint_name = \"publications\"\n    queryset = Publication.objects.all()\n    serializer_class = PublicationSerializer\n    filterset_class = PublicationFilter\n\n    @classmethod\n    def is_master_viewset(cls):\n        \"\"\"Do not hide from the routers.\"\"\"\n        return False\n\n\nclass PublicationViewSet(\n    NamedModelViewSet, mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.DestroyModelMixin\n):\n    endpoint_name = \"publications\"\n    queryset = Publication.objects.exclude(complete=False)\n    serializer_class = PublicationSerializer\n    filter_backends = (OrderingFilter, DjangoFilterBackend)\n    filterset_class = PublicationFilter\n    ordering = (\"-pulp_created\",)\n\n\nclass ContentGuardFilter(BaseFilterSet):\n    name = filters.CharFilter()\n\n    class Meta:\n        model = ContentGuard\n        fields = {\n            \"name\": NAME_FILTER_OPTIONS,\n        }\n\n\nclass BaseContentGuardViewSet(NamedModelViewSet):\n    endpoint_name = \"contentguards\"\n    serializer_class = ContentGuardSerializer\n    queryset = ContentGuard.objects.all()\n    filterset_class = ContentGuardFilter\n\n\nclass ListContentGuardViewSet(\n    BaseContentGuardViewSet,\n    mixins.ListModelMixin,\n):\n    \"\"\"Endpoint to list all contentguards.\"\"\"\n\n    @classmethod\n    def is_master_viewset(cls):\n        \"\"\"Do not hide from the routers.\"\"\"\n        return False\n\n\nclass ContentGuardViewSet(\n    BaseContentGuardViewSet,\n    mixins.CreateModelMixin,\n    mixins.UpdateModelMixin,\n    mixins.DestroyModelMixin,\n    mixins.RetrieveModelMixin,\n    mixins.ListModelMixin,\n):\n    \"\"\"\n    A viewset for contentguards.\n    \"\"\"\n\n\nclass RBACContentGuardViewSet(ContentGuardViewSet, RolesMixin):\n    \"\"\"\n    Viewset for creating contentguards that use RBAC to protect content.\n    Has add and remove actions for managing permission for users and groups to download content\n    protected by this guard.\n    \"\"\"\n\n    endpoint_name = \"rbac\"\n    serializer_class = RBACContentGuardSerializer\n    queryset = RBACContentGuard.objects.all()\n\n    DEFAULT_ACCESS_POLICY = {\n        \"statements\": [\n            {\n                \"action\": [\"list\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n            },\n            {\n                \"action\": [\"create\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_perms:core.add_rbaccontentguard\",\n            },\n            {\n                \"action\": [\"retrieve\", \"my_permissions\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_or_obj_perms:core.view_rbaccontentguard\",\n            },\n            {\n                \"action\": [\"update\", \"partial_update\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_or_obj_perms:core.change_rbaccontentguard\",\n            },\n            {\n                \"action\": [\"destroy\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_or_obj_perms:core.delete_rbaccontentguard\",\n            },\n            {\n                \"action\": [\"download\"],  # This is the action for the content guard permit\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_or_obj_perms:core.download_rbaccontentguard\",\n            },\n            {\n                \"action\": [\"list_roles\", \"add_role\", \"remove_role\"],\n                \"principal\": \"authenticated\",\n                \"effect\": \"allow\",\n                \"condition\": \"has_model_or_obj_perms:core.manage_roles_rbaccontentguard\",\n            },\n        ],\n        \"creation_hooks\": [\n            {\n                \"function\": \"add_roles_for_object_creator\",\n                \"parameters\": {\n                    \"roles\": [\"core.rbaccontentguard_owner\", \"core.rbaccontentguard_downloader\"]\n                },\n            },\n        ],\n    }\n    LOCKED_ROLES = {\n        \"core.rbaccontentguard_creator\": [\"core.add_rbaccontentguard\"],\n        \"core.rbaccontentguard_owner\": [\n            \"core.view_rbaccontentguard\",\n            \"core.change_rbaccontentguard\",\n            \"core.delete_rbaccontentguard\",\n            \"core.manage_roles_rbaccontentguard\",\n        ],\n        \"core.rbaccontentguard_downloader\": [\"core.download_rbaccontentguard\"],\n    }\n\n\nclass ContentRedirectContentGuardViewSet(ContentGuardViewSet):\n    \"\"\"\n    Content guard to protect preauthenticated redirects to the content app.\n    \"\"\"\n\n    endpoint_name = \"content_redirect\"\n    queryset = ContentRedirectContentGuard.objects.all()\n    serializer_class = ContentRedirectContentGuardSerializer\n\n\nclass DistributionFilter(BaseFilterSet):\n    # e.g.\n    # /?name=foo\n    # /?name__in=foo,bar\n    # /?base_path__contains=foo\n    # /?base_path__icontains=foo\n    name = filters.CharFilter()\n    base_path = filters.CharFilter()\n    pulp_label_select = LabelSelectFilter()\n\n    class Meta:\n        model = Distribution\n        fields = {\n            \"name\": NAME_FILTER_OPTIONS,\n            \"base_path\": [\"exact\", \"contains\", \"icontains\", \"in\"],\n        }\n\n\nclass ListDistributionViewSet(NamedModelViewSet, mixins.ListModelMixin):\n    endpoint_name = \"distributions\"\n    queryset = Distribution.objects.all()\n    serializer_class = DistributionSerializer\n    filterset_class = DistributionFilter\n\n    @classmethod\n    def is_master_viewset(cls):\n        \"\"\"Do not hide from the routers.\"\"\"\n        return False\n\n\nclass DistributionViewSet(\n    NamedModelViewSet,\n    mixins.RetrieveModelMixin,\n    mixins.ListModelMixin,\n    AsyncCreateMixin,\n    AsyncRemoveMixin,\n    AsyncUpdateMixin,\n):\n    \"\"\"\n    Provides read and list methods and also provides asynchronous CUD methods to dispatch tasks\n    with reservation that lock all Distributions preventing race conditions during base_path\n    checking.\n    \"\"\"\n\n    endpoint_name = \"distributions\"\n    queryset = Distribution.objects.all()\n    serializer_class = DistributionSerializer\n    filterset_class = DistributionFilter\n\n    def async_reserved_resources(self, instance):\n        \"\"\"Return resource that locks all Distributions.\"\"\"\n        return [\"/api/v3/distributions/\"]\n", "path": "pulpcore/app/viewsets/publication.py"}]}