Skip to content

Commit

Permalink
Merge pull request #5879 from readthedocs/humitos/api-v3-redirect-crud
Browse files Browse the repository at this point in the history
APIv3 CRUD for Redirect objects
  • Loading branch information
humitos authored Jul 9, 2019
2 parents b153e28 + ba61d0c commit 801f63b
Show file tree
Hide file tree
Showing 18 changed files with 399 additions and 30 deletions.
6 changes: 4 additions & 2 deletions readthedocs/api/v3/mixins.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from django.shortcuts import get_object_or_404
from rest_framework.exceptions import NotFound

from readthedocs.builds.models import Version
from readthedocs.projects.models import Project
Expand Down Expand Up @@ -62,7 +61,10 @@ def listing_objects(self, queryset, user):
return queryset.none()

def has_admin_permission(self, user, project):
if project in self.admin_projects(user):
# Use .only for small optimization
admin_projects = self.admin_projects(user).only('id')

if project in admin_projects:
return True

return False
Expand Down
12 changes: 11 additions & 1 deletion readthedocs/api/v3/permissions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from rest_framework.permissions import IsAuthenticated
from rest_framework.permissions import IsAuthenticated, BasePermission


class PublicDetailPrivateListing(IsAuthenticated):
Expand Down Expand Up @@ -29,3 +29,13 @@ def has_permission(self, request, view):
return True

return False


class IsProjectAdmin(BasePermission):

"""Grant permission if user has admin rights on the Project."""

def has_permission(self, request, view):
project = view._get_parent_project()
if view.has_admin_permission(request.user, project):
return True
78 changes: 78 additions & 0 deletions readthedocs/api/v3/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from readthedocs.builds.models import Build, Version
from readthedocs.projects.constants import LANGUAGES, PROGRAMMING_LANGUAGES
from readthedocs.projects.models import Project
from readthedocs.redirects.models import Redirect, TYPE_CHOICES as REDIRECT_TYPE_CHOICES


class UserSerializer(FlexFieldsModelSerializer):
Expand Down Expand Up @@ -321,6 +322,7 @@ class ProjectLinksSerializer(BaseLinksSerializer):

versions = serializers.SerializerMethodField()
builds = serializers.SerializerMethodField()
redirects = serializers.SerializerMethodField()
subprojects = serializers.SerializerMethodField()
superproject = serializers.SerializerMethodField()
translations = serializers.SerializerMethodField()
Expand All @@ -338,6 +340,15 @@ def get_versions(self, obj):
)
return self._absolute_url(path)

def get_redirects(self, obj):
path = reverse(
'projects-redirects-list',
kwargs={
'parent_lookup_project__slug': obj.slug,
},
)
return self._absolute_url(path)

def get_builds(self, obj):
path = reverse(
'projects-builds-list',
Expand Down Expand Up @@ -451,3 +462,70 @@ def get_subproject_of(self, obj):
return self.__class__(obj.superprojects.first().parent).data
except Exception:
return None


class RedirectLinksSerializer(BaseLinksSerializer):
_self = serializers.SerializerMethodField()
project = serializers.SerializerMethodField()

def get__self(self, obj):
path = reverse(
'projects-redirects-detail',
kwargs={
'parent_lookup_project__slug': obj.project.slug,
'redirect_pk': obj.pk,
},
)
return self._absolute_url(path)

def get_project(self, obj):
path = reverse(
'projects-detail',
kwargs={
'project_slug': obj.project.slug,
},
)
return self._absolute_url(path)


class RedirectSerializerBase(serializers.ModelSerializer):

project = serializers.SlugRelatedField(slug_field='slug', read_only=True)
created = serializers.DateTimeField(source='create_dt', read_only=True)
modified = serializers.DateTimeField(source='update_dt', read_only=True)
_links = RedirectLinksSerializer(source='*', read_only=True)

type = serializers.ChoiceField(source='redirect_type', choices=REDIRECT_TYPE_CHOICES)

class Meta:
model = Redirect
fields = [
'pk',
'created',
'modified',
'project',
'type',
'from_url',
'to_url',
'_links',
]


class RedirectCreateSerializer(RedirectSerializerBase):
pass


class RedirectDetailSerializer(RedirectSerializerBase):

"""Override RedirectSerializerBase to sanitize the empty fields."""

from_url = serializers.SerializerMethodField()
to_url = serializers.SerializerMethodField()

def get_from_url(self, obj):
# Overridden only to return ``None`` when the description is ``''``
return obj.from_url or None

def get_to_url(self, obj):
# Overridden only to return ``None`` when the description is ``''``
return obj.to_url or None
1 change: 1 addition & 0 deletions readthedocs/api/v3/tests/responses/projects-detail.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"_links": {
"_self": "https://readthedocs.org/api/v3/projects/project/",
"builds": "https://readthedocs.org/api/v3/projects/project/builds/",
"redirects": "https://readthedocs.org/api/v3/projects/project/redirects/",
"subprojects": "https://readthedocs.org/api/v3/projects/project/subprojects/",
"superproject": "https://readthedocs.org/api/v3/projects/project/superproject/",
"translations": "https://readthedocs.org/api/v3/projects/project/translations/",
Expand Down
1 change: 1 addition & 0 deletions readthedocs/api/v3/tests/responses/projects-list.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"_self": "https://readthedocs.org/api/v3/projects/project/",
"versions": "https://readthedocs.org/api/v3/projects/project/versions/",
"builds": "https://readthedocs.org/api/v3/projects/project/builds/",
"redirects": "https://readthedocs.org/api/v3/projects/project/redirects/",
"subprojects": "https://readthedocs.org/api/v3/projects/project/subprojects/",
"superproject": "https://readthedocs.org/api/v3/projects/project/superproject/",
"translations": "https://readthedocs.org/api/v3/projects/project/translations/"
Expand Down
13 changes: 13 additions & 0 deletions readthedocs/api/v3/tests/responses/projects-redirects-detail.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"_links": {
"_self": "https://readthedocs.org/api/v3/projects/project/redirects/1/",
"project": "https://readthedocs.org/api/v3/projects/project/"
},
"created": "2019-04-29T10:00:00Z",
"modified": "2019-04-29T12:00:00Z",
"from_url": "/docs/",
"pk": 1,
"project": "project",
"type": "page",
"to_url": "/documentation/"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"_links": {
"_self": "https://readthedocs.org/api/v3/projects/project/redirects/1/",
"project": "https://readthedocs.org/api/v3/projects/project/"
},
"created": "2019-04-29T10:00:00Z",
"modified": "2019-04-29T12:00:00Z",
"from_url": "/changed/",
"pk": 1,
"project": "project",
"type": "page",
"to_url": "/toanother/"
}
20 changes: 20 additions & 0 deletions readthedocs/api/v3/tests/responses/projects-redirects-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"_links": {
"_self": "https://readthedocs.org/api/v3/projects/project/redirects/1/",
"project": "https://readthedocs.org/api/v3/projects/project/"
},
"created": "2019-04-29T10:00:00Z",
"modified": "2019-04-29T12:00:00Z",
"from_url": "/docs/",
"pk": 1,
"project": "project",
"type": "page",
"to_url": "/documentation/"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"_links": {
"_self": "https://readthedocs.org/api/v3/projects/project/redirects/2/",
"project": "https://readthedocs.org/api/v3/projects/project/"
},
"created": "2019-04-29T10:00:00Z",
"modified": "2019-04-29T12:00:00Z",
"from_url": "/page/",
"pk": 2,
"project": "project",
"type": "page",
"to_url": "/another/"
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"_self": "https://readthedocs.org/api/v3/projects/project/",
"versions": "https://readthedocs.org/api/v3/projects/project/versions/",
"builds": "https://readthedocs.org/api/v3/projects/project/builds/",
"redirects": "https://readthedocs.org/api/v3/projects/project/redirects/",
"subprojects": "https://readthedocs.org/api/v3/projects/project/subprojects/",
"superproject": "https://readthedocs.org/api/v3/projects/project/superproject/",
"translations": "https://readthedocs.org/api/v3/projects/project/translations/"
Expand All @@ -90,6 +91,7 @@
"_self": "https://readthedocs.org/api/v3/projects/subproject/",
"versions": "https://readthedocs.org/api/v3/projects/subproject/versions/",
"builds": "https://readthedocs.org/api/v3/projects/subproject/builds/",
"redirects": "https://readthedocs.org/api/v3/projects/subproject/redirects/",
"subprojects": "https://readthedocs.org/api/v3/projects/subproject/subprojects/",
"superproject": "https://readthedocs.org/api/v3/projects/subproject/superproject/",
"translations": "https://readthedocs.org/api/v3/projects/subproject/translations/"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"_links": {
"_self": "https://readthedocs.org/api/v3/projects/project/",
"builds": "https://readthedocs.org/api/v3/projects/project/builds/",
"redirects": "https://readthedocs.org/api/v3/projects/project/redirects/",
"subprojects": "https://readthedocs.org/api/v3/projects/project/subprojects/",
"superproject": "https://readthedocs.org/api/v3/projects/project/superproject/",
"translations": "https://readthedocs.org/api/v3/projects/project/translations/",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"_links": {
"_self": "https://readthedocs.org/api/v3/projects/project/",
"builds": "https://readthedocs.org/api/v3/projects/project/builds/",
"redirects": "https://readthedocs.org/api/v3/projects/project/redirects/",
"subprojects": "https://readthedocs.org/api/v3/projects/project/subprojects/",
"superproject": "https://readthedocs.org/api/v3/projects/project/superproject/",
"translations": "https://readthedocs.org/api/v3/projects/project/translations/",
Expand Down
Loading

0 comments on commit 801f63b

Please sign in to comment.