Skip to content

Commit 26287f9

Browse files
committed
feat: add internal projects API with pagination and token authentication
- Introduced InternalProjectsListView for listing projects with pagination. - Added ProjectsPageNumberPagination for handling pagination. - Implemented ProjectsAPITokenPermission for Bearer token authentication. - Created InternalProjectsListSerializer to format project data. - Updated routers to include the new internal projects endpoint.
1 parent a7f0df7 commit 26287f9

File tree

5 files changed

+85
-0
lines changed

5 files changed

+85
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from rest_framework.pagination import PageNumberPagination
2+
from django.conf import settings
3+
4+
5+
class ProjectsPageNumberPagination(PageNumberPagination):
6+
"""
7+
Pagination class for internal projects API.
8+
Returns paginated results in the format: {count, next, previous, results}
9+
"""
10+
page_size = getattr(settings, 'PROJECTS_PAGE_SIZE', 100)
11+
page_size_query_param = 'page_size'
12+
max_page_size = 1000
13+
page_query_param = 'page'
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from rest_framework.permissions import BasePermission
2+
from django.conf import settings
3+
4+
5+
class ProjectsAPITokenPermission(BasePermission):
6+
"""
7+
Permission class for internal projects API.
8+
Validates Bearer token from Authorization header against PROJECTS_API_TOKEN setting.
9+
"""
10+
def has_permission(self, request, view):
11+
token = request.META.get("HTTP_AUTHORIZATION")
12+
if token is None or not token.startswith("Bearer "):
13+
return False
14+
15+
expected_token = f"Bearer {getattr(settings, 'PROJECTS_API_TOKEN', '')}"
16+
return token == expected_token
17+
18+
def has_object_permission(self, request, view, obj):
19+
return self.has_permission(request, view)

connect/api/v2/internals/serializers.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,22 @@ def get_projects(self, obj):
231231
"""Get all organization projects"""
232232
projects = obj.project.all()
233233
return CRMProjectSerializer(projects, many=True).data
234+
235+
236+
class InternalProjectsListSerializer(serializers.ModelSerializer):
237+
"""
238+
Simplified serializer for internal projects list API.
239+
Returns only uuid and timezone fields.
240+
"""
241+
class Meta:
242+
model = Project
243+
fields = ["uuid", "timezone"]
244+
245+
uuid = serializers.UUIDField(read_only=True)
246+
timezone = serializers.SerializerMethodField()
247+
248+
def get_timezone(self, obj):
249+
"""Return timezone as string or None"""
250+
if obj.timezone:
251+
return str(obj.timezone)
252+
return None

connect/api/v2/internals/views.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@
1212
CustomParameterSerializer,
1313
InternalProjectSerializer,
1414
CRMOrganizationSerializer,
15+
InternalProjectsListSerializer,
1516
)
1617
from connect.api.v2.internals.filters import CRMOrganizationFilter
18+
from connect.api.v2.internals.permissions import ProjectsAPITokenPermission
19+
from connect.api.v2.internals.paginations import ProjectsPageNumberPagination
1720
from connect.api.v1.internal.permissions import ModuleHasPermission
1821
from connect.api.v1.organization.permissions import IsCRMUser
1922
from connect.api.v2.paginations import CustomCursorPagination
@@ -134,3 +137,30 @@ def list(self, request, *args, **kwargs):
134137
def retrieve(self, request, *args, **kwargs):
135138
"""Retrieve a specific organization by UUID"""
136139
return super().retrieve(request, *args, **kwargs)
140+
141+
142+
class InternalProjectsListView(views.APIView):
143+
"""
144+
Internal API endpoint to list all projects with pagination.
145+
Returns projects in format: {count, next, previous, results: [{uuid, timezone}]}
146+
Authentication: Bearer token via PROJECTS_API_TOKEN setting
147+
"""
148+
permission_classes = [ProjectsAPITokenPermission]
149+
pagination_class = ProjectsPageNumberPagination
150+
151+
def get(self, request, **kwargs):
152+
"""
153+
List all projects with pagination.
154+
Query params: page, page_size
155+
"""
156+
queryset = Project.objects.all().order_by('uuid')
157+
158+
paginator = self.pagination_class()
159+
page = paginator.paginate_queryset(queryset, request)
160+
161+
if page is not None:
162+
serializer = InternalProjectsListSerializer(page, many=True)
163+
return paginator.get_paginated_response(serializer.data)
164+
165+
serializer = InternalProjectsListSerializer(queryset, many=True)
166+
return Response(serializer.data)

connect/api/v2/routers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,8 @@
166166
{"patch": "partial_update"}
167167
),
168168
),
169+
path(
170+
"internals/connect/projects",
171+
connect_internal_views.InternalProjectsListView.as_view(),
172+
),
169173
]

0 commit comments

Comments
 (0)