Skip to content

Commit

Permalink
APIv3: bring back OrganizationsViewSet that was removed (#11052)
Browse files Browse the repository at this point in the history
* APIv3: bring back `OrganizationsViewSet` that was removed

This view was used on "Read the Docs for Business".
See https://docs.readthedocs.io/en/stable/api/v3.html#organizations

It was deleted in
https://github.com/readthedocs/readthedocs.org/pull/11009/files#diff-1b2fcccf6a94ac362220161670adaf288aaece7381f18909cdd1da5e044d134a

I put them back here and make them extendable, so we can overwrite one of them
from "Read the Docs for Business".

* Updates to reflect the changes

- Show `_links.notifications` on `OrganizationSerializer`
- Match permissions between "listing projects for an organization" and "listing
  notifications for an organization"

* Update status code from API endpoint
  • Loading branch information
humitos authored Jan 23, 2024
1 parent 5fd8bde commit 7a58acb
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 3 deletions.
10 changes: 10 additions & 0 deletions readthedocs/api/v3/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,7 @@ class Meta:
class OrganizationLinksSerializer(BaseLinksSerializer):
_self = serializers.SerializerMethodField()
projects = serializers.SerializerMethodField()
notifications = serializers.SerializerMethodField()

def get__self(self, obj):
path = reverse(
Expand All @@ -1122,6 +1123,15 @@ def get_projects(self, obj):
)
return self._absolute_url(path)

def get_notifications(self, obj):
path = reverse(
"organizations-notifications-list",
kwargs={
"parent_lookup_organization__slug": obj.slug,
},
)
return self._absolute_url(path)


class TeamSerializer(FlexFieldsModelSerializer):
# TODO: add ``projects`` as flex field when we have a
Expand Down
2 changes: 1 addition & 1 deletion readthedocs/api/v3/tests/test_organizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def test_organizations_notifications_detail_other(self):

self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.others_token.key}")
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
self.assertEqual(response.status_code, 403)

def test_organizations_notifications_detail_patch(self):
url = reverse(
Expand Down
36 changes: 34 additions & 2 deletions readthedocs/api/v3/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@
UpdateMixin,
UserQuerySetMixin,
)
from .permissions import CommonPermissions, IsProjectAdmin
from .permissions import (
CommonPermissions,
IsOrganizationAdmin,
IsOrganizationAdminMember,
IsProjectAdmin,
)
from .renderers import AlphabeticalSortedJSONRenderer
from .serializers import (
BuildCreateSerializer,
Expand Down Expand Up @@ -614,21 +619,47 @@ def get_queryset(self):
)


class OrganizationsViewSet(
class OrganizationsViewSetBase(
APIv3Settings,
GenericViewSet,
):
# NOTE: this viewset is only useful for nested URLs required for notifications:
# /api/v3/organizations/<slug>/notifications/
# However, accessing to /api/v3/organizations/ or /api/v3/organizations/<slug>/ will return 404.
# We can implement these endpoints when we need them, tho.
# Also note that Read the Docs for Business expose this endpoint already.

model = Organization
serializer_class = OrganizationSerializer
queryset = Organization.objects.none()
permission_classes = (IsAuthenticated,)


class OrganizationsViewSet(SettingsOverrideObject):
_default_class = OrganizationsViewSetBase


class OrganizationsProjectsViewSet(
APIv3Settings,
NestedViewSetMixin,
OrganizationQuerySetMixin,
ReadOnlyModelViewSet,
):
model = Project
lookup_field = "slug"
lookup_url_kwarg = "project_slug"
queryset = Project.objects.all()
serializer_class = ProjectSerializer
permission_classes = [IsAuthenticated & IsOrganizationAdminMember]
permit_list_expands = [
"organization",
"organization.teams",
]

def get_view_name(self):
return f"Organizations Projects {self.suffix}"


class NotificationsOrganizationViewSet(
APIv3Settings,
NestedViewSetMixin,
Expand All @@ -645,6 +676,7 @@ class NotificationsOrganizationViewSet(
serializer_class = NotificationSerializer
queryset = Notification.objects.all()
filterset_class = NotificationFilter
permission_classes = [IsAuthenticated & IsOrganizationAdmin]

def get_queryset(self):
content_type = ContentType.objects.get_for_model(Organization)
Expand Down

0 comments on commit 7a58acb

Please sign in to comment.