Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.

Commit a82089d

Browse files
Add gen ai endpoint
1 parent ddb4755 commit a82089d

File tree

7 files changed

+139
-28
lines changed

7 files changed

+139
-28
lines changed

api/internal/gen_ai/__init__.py

Whitespace-only changes.

api/internal/gen_ai/serializers.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from graphql_api.types.owner.owner import AI_FEATURES_GH_APP_ID
2+
from rest_framework.permissions import IsAuthenticated
3+
from rest_framework.response import Response
4+
from rest_framework.views import APIView
5+
from rest_framework import serializers
6+
7+
from codecov_auth.models import GithubAppInstallation, Owner
8+
from shared.django_apps.core.models import Repository
9+
from shared.license import get_current_license
10+
11+
12+
class GenAIAuthSerializer(serializers.Serializer):
13+
is_valid = serializers.BooleanField()
14+
repos = serializers.ListField(child=serializers.CharField(), required=False)
15+

api/internal/gen_ai/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 GenAIAuthView
4+
5+
urlpatterns = [
6+
path("", GenAIAuthView.as_view(), name="gen-ai-auth"),
7+
]

api/internal/gen_ai/views.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from graphql_api.types.owner.owner import AI_FEATURES_GH_APP_ID
2+
from rest_framework.permissions import IsAuthenticated
3+
from rest_framework.response import Response
4+
from rest_framework.views import APIView
5+
from shared.license import get_current_license
6+
7+
from .serializers import GenAIAuthSerializer, LicenseSerializer
8+
9+
from codecov_auth.models import (
10+
GithubAppInstallation,
11+
Owner,
12+
)
13+
14+
class GenAIAuthView(APIView):
15+
permission_classes = [IsAuthenticated]
16+
17+
def get(self, request, *args, **kwargs):
18+
owner_id = request.query_params.get("owner_id")
19+
owner = Owner.objects.filter(pk=owner_id, service="github").first()
20+
21+
ai_features_app_install = None
22+
repos = []
23+
24+
if owner:
25+
ai_features_app_install = GithubAppInstallation.objects.filter(
26+
app_id=AI_FEATURES_GH_APP_ID, owner=owner
27+
).first()
28+
29+
if ai_features_app_install and ai_features_app_install.repository_service_ids:
30+
repos = ai_features_app_install.repository_service_ids
31+
32+
data = {
33+
"is_valid": bool(ai_features_app_install),
34+
"repos": repos,
35+
}
36+
37+
serializer = GenAIAuthSerializer(data)
38+
return Response(serializer.data)

api/internal/tests/test_gen_ai.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from rest_framework.reverse import reverse
2+
from rest_framework.test import APITestCase
3+
from shared.django_apps.core.tests.factories import OwnerFactory, RepositoryFactory
4+
from utils.test_utils import Client
5+
from codecov_auth.models import GithubAppInstallation
6+
from graphql_api.types.owner.owner import AI_FEATURES_GH_APP_ID
7+
8+
9+
class GenAIAuthViewTests(APITestCase):
10+
def setUp(self):
11+
self.client = Client()
12+
13+
self.owner = OwnerFactory(service="github")
14+
self.repo1 = RepositoryFactory(author=self.owner, name="Repo1")
15+
self.repo2 = RepositoryFactory(author=self.owner, name="Repo2")
16+
17+
self.ai_install = GithubAppInstallation.objects.create(
18+
app_id=AI_FEATURES_GH_APP_ID,
19+
owner=self.owner,
20+
repository_service_ids=[self.repo1.service_id, self.repo2.service_id],
21+
)
22+
23+
def test_no_owner_id(self):
24+
url = reverse("gen-ai-consent")
25+
response = self.client.get(url)
26+
assert response.status_code == 200
27+
assert response.data["is_valid"] is False
28+
29+
def test_owner_without_install(self):
30+
# Remove the AI installation so it doesn't exist
31+
self.ai_install.delete()
32+
33+
url = reverse("gen-ai-consent")
34+
response = self.client.get(url, data={"owner_id": self.owner.id})
35+
assert response.status_code == 200
36+
assert response.data["is_valid"] is False
37+
38+
def test_valid_owner_with_install(self):
39+
url = reverse("gen-ai-consent")
40+
response = self.client.get(url, data={"owner_id": self.owner.id})
41+
assert response.status_code == 200
42+
assert response.data["is_valid"] is True
43+
assert len(response.data["repos"]) == 2
44+
assert set(response.data["repos"]) == {"Repo1", "Repo2"}
Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,47 @@
11
from rest_framework.reverse import reverse
22
from rest_framework.test import APITestCase
3-
from shared.django_apps.core.tests.factories import OwnerFactory
4-
3+
from shared.django_apps.core.tests.factories import OwnerFactory, RepositoryFactory
54
from utils.test_utils import Client
5+
from codecov_auth.models import GithubAppInstallation
6+
from graphql_api.types.owner.owner import AI_FEATURES_GH_APP_ID
67

78

8-
class PageNumberPaginationTests(APITestCase):
9+
class GenAIAuthViewTests(APITestCase):
910
def setUp(self):
1011
self.client = Client()
11-
self.owner = OwnerFactory(plan="users-free", plan_user_count=5)
12-
self.users = [
13-
OwnerFactory(organizations=[self.owner.ownerid]),
14-
OwnerFactory(organizations=[self.owner.ownerid]),
15-
OwnerFactory(organizations=[self.owner.ownerid]),
16-
]
17-
18-
def test_pagination_returned_page_size(self):
19-
self.client.force_login_owner(self.owner)
20-
21-
def _list(kwargs={}, query_params={}):
22-
if not kwargs:
23-
kwargs = {
24-
"service": self.owner.service,
25-
"owner_username": self.owner.username,
26-
}
27-
return self.client.get(
28-
reverse("users-list", kwargs=kwargs), data=query_params
29-
)
3012

31-
response = _list()
13+
self.owner = OwnerFactory(service="github")
14+
self.repo1 = RepositoryFactory(author=self.owner, name="Repo1")
15+
self.repo2 = RepositoryFactory(author=self.owner, name="Repo2")
3216

33-
assert response.data["total_pages"] == 1
17+
self.ai_install = GithubAppInstallation.objects.create(
18+
app_id=AI_FEATURES_GH_APP_ID,
19+
owner=self.owner,
20+
repository_service_ids=[self.repo1.service_id, self.repo2.service_id],
21+
)
3422

35-
response = _list(query_params={"page_size": "1"})
23+
def test_no_owner_id(self):
24+
url = reverse("gen-ai-consent")
25+
self.client.force_login_owner(self.owner)
26+
response = self.client.get(url)
27+
assert response.status_code == 200
28+
assert response.data["is_valid"] is False
3629

37-
assert response.data["total_pages"] == 3
30+
def test_owner_without_install(self):
31+
# Remove the AI installation so it doesn't exist
32+
self.ai_install.delete()
3833

39-
response = _list(query_params={"page_size": "100"})
34+
url = reverse("gen-ai-consent")
35+
self.client.force_login_owner(self.owner)
36+
response = self.client.get(url, data={"owner_id": self.owner.id})
37+
assert response.status_code == 200
38+
assert response.data["is_valid"] is False
4039

41-
assert response.data["total_pages"] == 1
40+
def test_valid_owner_with_install(self):
41+
url = reverse("gen-ai-consent")
42+
self.client.force_login_owner(self.owner)
43+
response = self.client.get(url, data={"owner_id": self.owner.id})
44+
assert response.status_code == 200
45+
assert response.data["is_valid"] is True
46+
assert len(response.data["repos"]) == 2
47+
assert set(response.data["repos"]) == {"Repo1", "Repo2"}

api/internal/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,5 @@
7676
include(compare_router.urls),
7777
),
7878
path("features", FeaturesView.as_view(), name="features"),
79+
path("internal/gen-ai-consent/", include("api.internal.gen_ai.urls")),
7980
]

0 commit comments

Comments
 (0)