Skip to content

Commit 14e16a0

Browse files
authored
Merge pull request #988 from weni-ai/feat/internal-projects-api
Feat/internal projects api
2 parents a7f0df7 + 088a18b commit 14e16a0

File tree

6 files changed

+89
-0
lines changed

6 files changed

+89
-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: 31 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,31 @@ 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+
authentication_classes = []
149+
permission_classes = [ProjectsAPITokenPermission]
150+
pagination_class = ProjectsPageNumberPagination
151+
152+
def get(self, request, **kwargs):
153+
"""
154+
List all projects with pagination.
155+
Query params: page, page_size
156+
"""
157+
queryset = Project.objects.all().order_by('uuid')
158+
159+
paginator = self.pagination_class()
160+
page = paginator.paginate_queryset(queryset, request)
161+
162+
if page is not None:
163+
serializer = InternalProjectsListSerializer(page, many=True)
164+
return paginator.get_paginated_response(serializer.data)
165+
166+
serializer = InternalProjectsListSerializer(queryset, many=True)
167+
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
]

connect/settings.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,3 +586,6 @@
586586
RATE_LIMIT_REQUESTS = env.int("RATE_LIMIT_REQUESTS")
587587
RATE_LIMIT_WINDOW = env.int("RATE_LIMIT_WINDOW")
588588
RATE_LIMIT_BLOCK_TIME = env.int("RATE_LIMIT_BLOCK_TIME")
589+
590+
PROJECTS_API_TOKEN = env.str("PROJECTS_API_TOKEN", default="")
591+
PROJECTS_PAGE_SIZE = env.int("PROJECTS_PAGE_SIZE", default=100)

0 commit comments

Comments
 (0)