Skip to content

Add List API Endpoint for RemoteRepository and RemoteOrganization #7510

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
May 27, 2021
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 191 additions & 0 deletions docs/api/v3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1624,6 +1624,197 @@ Organization projects list
}


Remote Organizations
~~~~~~~~~~~~~~~~~~~~

Remote Organizations are the VCS organizations connected via
``GitHub``, ``GitLab`` and ``BitBucket``.


Remote Organization listing
+++++++++++++++++++++++++++


.. http:get:: /api/v3/remote/organizations/

Retrieve a list of all Remote Organizations for the authenticated user.

**Example request**:

.. tabs::

.. code-tab:: bash

$ curl -H "Authorization: Token <token>" https://readthedocs.org/api/v3/remote/organizations/

.. code-tab:: python

import requests
URL = 'https://readthedocs.org/api/v3/remote/organizations/'
TOKEN = '<token>'
HEADERS = {'Authorization': f'token {TOKEN}'}
response = requests.get(URL, headers=HEADERS)
print(response.json())

**Example response**:

.. sourcecode:: json

{
"count": 20,
"next": "api/v3/remote/organizations/?limit=10&offset=10",
"previous": null,
"results": [
{
"avatar_url": "https://avatars.githubusercontent.com/u/12345?v=4",
"created": "2019-04-29T10:00:00Z",
"modified": "2019-04-29T12:00:00Z",
"name": "Organization Name",
"pk": 1,
"slug": "organization",
"url": "https://github.com/organization",
"vcs_provider": "github"
}
]
}


The ``results`` in response is an array of remote organizations data.

:query string name__contains: return remote organizations with containing the name
:query string vcs_provider: return remote organizations for specific vcs provider (``github``, ``gitlab`` or ``bitbucket``)

:requestheader Authorization: token to authenticate.


Remote Repositories
~~~~~~~~~~~~~~~~~~~

Remote Repositories are the importable repositories connected via
``GitHub``, ``GitLab`` and ``BitBucket``.


Remote Repository listing
+++++++++++++++++++++++++


.. http:get:: /api/v3/remote/repositories/

Retrieve a list of all Remote Repositories for the authenticated user.

**Example request**:

.. tabs::

.. code-tab:: bash

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

.. code-tab:: python

import requests
URL = 'https://readthedocs.org/api/v3/remote/repositories/?expand=project,organization'
TOKEN = '<token>'
HEADERS = {'Authorization': f'token {TOKEN}'}
response = requests.get(URL, headers=HEADERS)
print(response.json())

**Example response**:

.. sourcecode:: json

{
"count": 20,
"next": "api/v3/remote/repositories/?expand=project,organization&limit=10&offset=10",
"previous": null,
"results": [
{
"organization": {
"avatar_url": "https://avatars.githubusercontent.com/u/12345?v=4",
"created": "2019-04-29T10:00:00Z",
"modified": "2019-04-29T12:00:00Z",
"name": "Organization Name",
"pk": 1,
"slug": "organization",
"url": "https://github.com/organization",
"vcs_provider": "github"
},
"project": {
"id": 12345,
"name": "project",
"slug": "project",
"created": "2010-10-23T18:12:31+00:00",
"modified": "2018-12-11T07:21:11+00:00",
"language": {
"code": "en",
"name": "English"
},
"programming_language": {
"code": "py",
"name": "Python"
},
"repository": {
"url": "https://github.com/organization/project",
"type": "git"
},
"default_version": "stable",
"default_branch": "master",
"subproject_of": null,
"translation_of": null,
"urls": {
"documentation": "http://project.readthedocs.io/en/stable/",
"home": "https://readthedocs.org/projects/project/"
},
"tags": [
"test"
],
"users": [
{
"username": "dstufft"
}
],
"_links": {
"_self": "/api/v3/projects/project/",
"versions": "/api/v3/projects/project/versions/",
"builds": "/api/v3/projects/project/builds/",
"subprojects": "/api/v3/projects/project/subprojects/",
"superproject": "/api/v3/projects/project/superproject/",
"redirects": "/api/v3/projects/project/redirects/",
"translations": "/api/v3/projects/project/translations/"
}
}
"avatar_url": "https://avatars3.githubusercontent.com/u/test-organization?v=4",
"clone_url": "https://github.com/organization/project.git",
"created": "2019-04-29T10:00:00Z",
"description": "This is a test project.",
"full_name": "organization/project",
"html_url": "https://github.com/organization/project",
"modified": "2019-04-29T12:00:00Z",
"name": "project",
"pk": 1,
"ssh_url": "[email protected]:organization/project.git",
"vcs": "git",
"vcs_provider": "github",
"default_branch": "master",
"private": false,
"admin": true
}
]
}


The ``results`` in response is an array of remote repositories data.

:query string name__contains: return remote repositories containing the name
: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: allows to add/expand some extra fields in the response.
Allowed values are ``project`` and ``organization``.
Multiple fields can be passed separated by commas.

:requestheader Authorization: token to authenticate.


Additional APIs
---------------

Expand Down
25 changes: 25 additions & 0 deletions readthedocs/api/v3/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from readthedocs.builds.constants import BUILD_STATE_FINISHED
from readthedocs.builds.models import Build, Version
from readthedocs.oauth.models import RemoteRepository, RemoteOrganization
from readthedocs.projects.models import Project


Expand Down Expand Up @@ -47,3 +48,27 @@ def get_running(self, queryset, name, value):
return queryset.exclude(state=BUILD_STATE_FINISHED)

return queryset.filter(state=BUILD_STATE_FINISHED)


class RemoteRepositoryFilter(filters.FilterSet):
name__contains = filters.CharFilter(field_name='name', lookup_expr='icontains')
organization = filters.CharFilter(field_name='organization__slug')

class Meta:
model = RemoteRepository
fields = [
'name__contains',
'vcs_provider',
'organization',
]


class RemoteOrganizationFilter(filters.FilterSet):
name__contains = filters.CharFilter(field_name='name', lookup_expr='icontains')

class Meta:
model = RemoteOrganization
fields = [
'name__contains',
'vcs_provider',
]
6 changes: 6 additions & 0 deletions readthedocs/api/v3/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,9 @@ def update(self, request, *args, **kwargs):
# via Javascript
super().update(request, *args, **kwargs)
return Response(status=status.HTTP_204_NO_CONTENT)


class RemoteQuerySetMixin:

def get_queryset(self):
return super().get_queryset().api(self.request.user)
62 changes: 62 additions & 0 deletions readthedocs/api/v3/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from readthedocs.core.utils.extend import SettingsOverrideObject
from readthedocs.builds.models import Build, Version
from readthedocs.core.utils import slugify
from readthedocs.oauth.models import RemoteRepository, RemoteOrganization
from readthedocs.organizations.models import Organization, Team
from readthedocs.projects.constants import (
LANGUAGES,
Expand Down Expand Up @@ -891,3 +892,64 @@ class Meta:
'projects': (ProjectSerializer, {'many': True}),
'teams': (TeamSerializer, {'many': True}),
}


class RemoteOrganizationSerializer(serializers.ModelSerializer):

class Meta:
model = RemoteOrganization
fields = [
'pk',
'slug',
'name',
'avatar_url',
'url',
'vcs_provider',
'created',
'modified',
]
read_only_fields = fields


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

class Meta:
model = RemoteRepository
fields = [
'pk',
'name',
'full_name',
'description',
'admin',
'avatar_url',
'ssh_url',
'clone_url',
'html_url',
'vcs',
'vcs_provider',
'private',
'default_branch',
'created',
'modified',
]
read_only_fields = fields
expandable_fields = {
'organization': (
RemoteOrganizationSerializer, {'source': 'organization'}
),
'project': (
ProjectSerializer, {'source': 'project'}
)
}

def is_admin(self, obj):
request = self.context['request']

# Use annotated value from RemoteRepositoryViewSet queryset
if hasattr(obj, '_admin'):
return obj._admin

return obj.remote_repository_relations.filter(
user=request.user, admin=True
).exists()
17 changes: 17 additions & 0 deletions readthedocs/api/v3/tests/responses/remoteorganizations-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"avatar_url": "https://avatars.githubusercontent.com/u/366329?v=4",
"created": "2019-04-29T10:00:00Z",
"modified": "2019-04-29T12:00:00Z",
"name": "Read the Docs",
"pk": 1,
"slug": "readthedocs",
"url": "https://github.com/readthedocs",
"vcs_provider": "github"
}
]
}
Loading