Skip to content

Commit a6320a0

Browse files
Merge pull request #618 from weni-ai/feature/brain-on-endpoint
Endpoint to get project data
2 parents 4c446d9 + 8e99519 commit a6320a0

File tree

5 files changed

+124
-0
lines changed

5 files changed

+124
-0
lines changed

temba/api/v2/projects/__init__.py

Whitespace-only changes.

temba/api/v2/projects/tests.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import uuid
2+
from functools import wraps
3+
from unittest.mock import patch
4+
5+
from rest_framework.authentication import BasicAuthentication
6+
7+
from django.test import SimpleTestCase, override_settings
8+
from django.urls import resolve, reverse
9+
10+
from temba.api.v2.projects.views import GetProjectView
11+
from temba.tests import TembaTest
12+
13+
GET_PROJECT_VIEW_PATH = "temba.api.v2.projects.views.GetProjectView"
14+
15+
16+
def skip_auth_and_permissions(view_path: str):
17+
"""
18+
Decorator to disable authentication and permission checks for a specific endpoint class.
19+
Use when testing view logic (status codes and payload) without auth side-effects.
20+
"""
21+
22+
def decorator(func):
23+
@patch(f"{view_path}.authentication_classes", [])
24+
@patch(f"{view_path}.permission_classes", [])
25+
@wraps(func)
26+
def wrapper(*args, **kwargs):
27+
return func(*args, **kwargs)
28+
29+
return wrapper
30+
31+
return decorator
32+
33+
34+
class GetProjectViewTest(TembaTest):
35+
def setUp(self):
36+
super().setUp()
37+
38+
# Ensure org has a project UUID for lookups
39+
self.org.proj_uuid = uuid.uuid4()
40+
self.org.save(update_fields=("proj_uuid",))
41+
42+
self.url = reverse("api.v2.projects")
43+
44+
@patch(f"{GET_PROJECT_VIEW_PATH}.authentication_classes", [BasicAuthentication])
45+
def test_requires_authentication(self):
46+
# Without authentication headers, endpoint should deny access
47+
resp = self.client.get(f"{self.url}?project_uuid={self.org.proj_uuid}")
48+
self.assertEqual(resp.status_code, 401)
49+
50+
@skip_auth_and_permissions(GET_PROJECT_VIEW_PATH)
51+
def test_missing_project_uuid_returns_400(self):
52+
resp = self.client.get(self.url)
53+
self.assertEqual(resp.status_code, 400)
54+
self.assertEqual(resp.json(), {"error": "project_uuid is required"})
55+
56+
@skip_auth_and_permissions(GET_PROJECT_VIEW_PATH)
57+
def test_nonexistent_project_returns_404(self):
58+
random_proj = uuid.uuid4()
59+
resp = self.client.get(f"{self.url}?project_uuid={random_proj}")
60+
self.assertEqual(resp.status_code, 404)
61+
self.assertEqual(resp.json(), {"error": "Project not found"})
62+
63+
@skip_auth_and_permissions(GET_PROJECT_VIEW_PATH)
64+
def test_success_returns_project_data(self):
65+
resp = self.client.get(f"{self.url}?project_uuid={self.org.proj_uuid}")
66+
self.assertEqual(resp.status_code, 200)
67+
data = resp.json()
68+
69+
self.assertEqual(data["project_uuid"], str(self.org.proj_uuid))
70+
self.assertEqual(data["name"], self.org.name)
71+
self.assertEqual(data["is_active"], self.org.is_active)
72+
self.assertEqual(data["brain_on"], self.org.brain_on)
73+
74+
75+
@override_settings(ROOT_URLCONF="temba.api.v2.projects.urls")
76+
class ProjectsUrlsTest(SimpleTestCase):
77+
def test_projects_url_resolves_to_get_project_view(self):
78+
url = reverse("projects")
79+
self.assertEqual(url, "/projects")
80+
match = resolve(url)
81+
self.assertEqual(getattr(match.func, "view_class", None), GetProjectView)

temba/api/v2/projects/urls.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from django.urls import path
2+
3+
from .views import GetProjectView
4+
5+
urlpatterns = [
6+
path("projects", GetProjectView.as_view(), name="projects"),
7+
]

temba/api/v2/projects/views.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from rest_framework.permissions import IsAuthenticated
2+
from rest_framework.request import Request
3+
from rest_framework.response import Response
4+
from rest_framework.views import APIView
5+
from weni.internal.authenticators import InternalOIDCAuthentication
6+
7+
from temba.api.v2.internals.views import APIViewMixin
8+
from temba.api.v2.permissions import IsUserInOrg
9+
from temba.orgs.models import Org
10+
11+
12+
class GetProjectView(APIViewMixin, APIView):
13+
authentication_classes = [InternalOIDCAuthentication]
14+
permission_classes = [IsAuthenticated, IsUserInOrg]
15+
16+
def get(self, request: Request):
17+
params = request.query_params
18+
project_uuid = params.get("project_uuid")
19+
20+
if project_uuid is None:
21+
return Response(status=400, data={"error": "project_uuid is required"})
22+
23+
try:
24+
org = Org.objects.get(proj_uuid=project_uuid)
25+
except Org.DoesNotExist:
26+
return Response(status=404, data={"error": "Project not found"})
27+
28+
project_data = {
29+
"project_uuid": str(org.proj_uuid),
30+
"name": org.name,
31+
"is_active": org.is_active,
32+
"brain_on": org.brain_on,
33+
}
34+
return Response(project_data)

temba/api/v2/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from django.urls import include, path
55

66
from temba.api.v2.elasticsearch.views import ContactsElasticSearchEndpoint
7+
from temba.api.v2.projects.views import GetProjectView
78

89
from .flows.urls import urlpatterns as flows_urlpatterns
910
from .internals.urls import urlpatterns as internals_urlpatterns
@@ -110,6 +111,7 @@
110111
url(r"^intelligences$", IntelligencesEndpoint.as_view(), name="api.v2.intelligences"),
111112
url(r"^brain_info$", BrainInfoEndpoint.as_view(), name="api.v2.brain_info"),
112113
url(r"^whatsapp_flows$", WhatsappFlowsEndpoint.as_view(), name="api.v2.whatsapp_flows"),
114+
url(r"^projects$", GetProjectView.as_view(), name="api.v2.projects"),
113115
]
114116

115117
urlpatterns = format_suffix_patterns(urlpatterns, allowed=["json", "api"])

0 commit comments

Comments
 (0)