Skip to content

Commit

Permalink
API v3: always return projects when listing remote repositories (#11731)
Browse files Browse the repository at this point in the history
This allows us to filter by the permissions the current user has on the
projects.

Closes readthedocs/readthedocs-corporate#1876
  • Loading branch information
stsewd authored Nov 4, 2024
1 parent 7198d3d commit 01ba042
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 16 deletions.
10 changes: 5 additions & 5 deletions docs/user/api/v3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1855,12 +1855,12 @@ Remote repository listing

.. code-tab:: bash

$ curl -H "Authorization: Token <token>" https://readthedocs.org/api/v3/remote/repositories/?expand=projects,remote_organization
$ curl -H "Authorization: Token <token>" https://readthedocs.org/api/v3/remote/repositories/?expand=remote_organization

.. code-tab:: python

import requests
URL = 'https://readthedocs.org/api/v3/remote/repositories/?expand=projects,remote_organization'
URL = 'https://readthedocs.org/api/v3/remote/repositories/?expand=remote_organization'
TOKEN = '<token>'
HEADERS = {'Authorization': f'token {TOKEN}'}
response = requests.get(URL, headers=HEADERS)
Expand All @@ -1872,7 +1872,7 @@ Remote repository listing

{
"count": 20,
"next": "api/v3/remote/repositories/?expand=projects,remote_organization&limit=10&offset=10",
"next": "api/v3/remote/repositories/?expand=remote_organization&limit=10&offset=10",
"previous": null,
"results": [
{
Expand All @@ -1886,7 +1886,7 @@ Remote repository listing
"url": "https://github.com/organization",
"vcs_provider": "github"
},
"project": [{
"projects": [{
"id": 12345,
"name": "project",
"slug": "project",
Expand Down Expand Up @@ -1957,7 +1957,7 @@ Remote repository listing
:query string vcs_provider: return remote repositories for specific vcs provider (``github``, ``gitlab`` or ``bitbucket``)
:query string organization: return remote repositories for specific remote organization (using remote organization ``slug``)
:query string expand: Add additional fields in the response.
Allowed values are ``projects`` and ``remote_organization``.
Allowed values are: ``remote_organization``.
Multiple fields can be passed separated by commas.

:requestheader Authorization: token to authenticate.
Expand Down
12 changes: 11 additions & 1 deletion readthedocs/api/v3/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,7 @@ class Meta:

class RemoteRepositorySerializer(FlexFieldsModelSerializer):
admin = serializers.SerializerMethodField("is_admin")
projects = serializers.SerializerMethodField()

class Meta:
model = RemoteRepository
Expand All @@ -1268,14 +1269,14 @@ class Meta:
"default_branch",
"created",
"modified",
"projects",
]
read_only_fields = fields
expandable_fields = {
"remote_organization": (
RemoteOrganizationSerializer,
{"source": "organization"},
),
"projects": (ProjectSerializer, {"many": True}),
}

def is_admin(self, obj):
Expand All @@ -1288,3 +1289,12 @@ def is_admin(self, obj):
return obj.remote_repository_relations.filter(
user=request.user, admin=True
).exists()

def get_projects(self, obj):
request = self.context["request"]
projects = (
Project.objects.public(user=request.user)
.filter(remote_repository=obj)
.prefetch_related("users")
)
return ProjectSerializer(projects, many=True).data
12 changes: 6 additions & 6 deletions readthedocs/api/v3/tests/test_remoterepositories.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from django.urls import reverse

from allauth.socialaccount.models import SocialAccount
import django_dynamic_fixture as fixture
from allauth.socialaccount.models import SocialAccount
from django.urls import reverse

from readthedocs.oauth.constants import GITHUB
from readthedocs.oauth.models import (
Expand All @@ -11,6 +10,7 @@
RemoteRepositoryRelation,
)
from readthedocs.projects.constants import REPO_TYPE_GIT

from .mixins import APIEndpointMixin


Expand Down Expand Up @@ -65,7 +65,7 @@ def setUp(self):

def test_remote_repository_list(self):
url = reverse("remoterepositories-list")
data = {"expand": ("projects," "remote_organization")}
data = {"expand": ["remote_organization"]}

self.client.logout()
response = self.client.get(url, data)
Expand All @@ -84,7 +84,7 @@ def test_remote_repository_list_name_filter(self):
self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
response = self.client.get(
reverse("remoterepositories-list"),
{"expand": ("projects," "remote_organization"), "name": "proj"},
{"expand": ["remote_organization"], "name": "proj"},
)
self.assertEqual(response.status_code, 200)

Expand All @@ -100,7 +100,7 @@ def test_remote_repository_list_full_name_filter(self):
self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
response = self.client.get(
reverse("remoterepositories-list"),
{"expand": ("projects," "remote_organization"), "full_name": "proj"},
{"expand": ["remote_organization"], "full_name": "proj"},
)
self.assertEqual(response.status_code, 200)

Expand Down
5 changes: 1 addition & 4 deletions readthedocs/api/v3/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ class RemoteRepositoryViewSet(
serializer_class = RemoteRepositorySerializer
filterset_class = RemoteRepositoryFilter
permission_classes = (IsAuthenticated,)
permit_list_expands = ["remote_organization", "projects"]
permit_list_expands = ["remote_organization"]

def get_queryset(self):
queryset = (
Expand All @@ -615,9 +615,6 @@ def get_queryset(self):
if is_expanded(self.request, "remote_organization"):
queryset = queryset.select_related("organization")

if is_expanded(self.request, "projects"):
queryset = queryset.prefetch_related("projects__users")

return queryset.order_by("organization__name", "full_name").distinct()


Expand Down

0 comments on commit 01ba042

Please sign in to comment.