Skip to content

Commit

Permalink
Add gen ai endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
rohitvinnakota-codecov committed Jan 15, 2025
1 parent ddb4755 commit a82089d
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 28 deletions.
Empty file added api/internal/gen_ai/__init__.py
Empty file.
15 changes: 15 additions & 0 deletions api/internal/gen_ai/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from graphql_api.types.owner.owner import AI_FEATURES_GH_APP_ID
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import serializers

from codecov_auth.models import GithubAppInstallation, Owner
from shared.django_apps.core.models import Repository
from shared.license import get_current_license


class GenAIAuthSerializer(serializers.Serializer):
is_valid = serializers.BooleanField()
repos = serializers.ListField(child=serializers.CharField(), required=False)

7 changes: 7 additions & 0 deletions api/internal/gen_ai/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.urls import path

from .views import GenAIAuthView

urlpatterns = [
path("", GenAIAuthView.as_view(), name="gen-ai-auth"),
]
38 changes: 38 additions & 0 deletions api/internal/gen_ai/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from graphql_api.types.owner.owner import AI_FEATURES_GH_APP_ID
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from shared.license import get_current_license

from .serializers import GenAIAuthSerializer, LicenseSerializer

from codecov_auth.models import (
GithubAppInstallation,
Owner,
)

class GenAIAuthView(APIView):
permission_classes = [IsAuthenticated]

def get(self, request, *args, **kwargs):
owner_id = request.query_params.get("owner_id")
owner = Owner.objects.filter(pk=owner_id, service="github").first()

ai_features_app_install = None
repos = []

if owner:
ai_features_app_install = GithubAppInstallation.objects.filter(
app_id=AI_FEATURES_GH_APP_ID, owner=owner
).first()

if ai_features_app_install and ai_features_app_install.repository_service_ids:
repos = ai_features_app_install.repository_service_ids

data = {
"is_valid": bool(ai_features_app_install),
"repos": repos,
}

serializer = GenAIAuthSerializer(data)
return Response(serializer.data)
44 changes: 44 additions & 0 deletions api/internal/tests/test_gen_ai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from rest_framework.reverse import reverse
from rest_framework.test import APITestCase
from shared.django_apps.core.tests.factories import OwnerFactory, RepositoryFactory
from utils.test_utils import Client
from codecov_auth.models import GithubAppInstallation
from graphql_api.types.owner.owner import AI_FEATURES_GH_APP_ID


class GenAIAuthViewTests(APITestCase):
def setUp(self):
self.client = Client()

self.owner = OwnerFactory(service="github")
self.repo1 = RepositoryFactory(author=self.owner, name="Repo1")
self.repo2 = RepositoryFactory(author=self.owner, name="Repo2")

self.ai_install = GithubAppInstallation.objects.create(
app_id=AI_FEATURES_GH_APP_ID,
owner=self.owner,
repository_service_ids=[self.repo1.service_id, self.repo2.service_id],
)

def test_no_owner_id(self):
url = reverse("gen-ai-consent")
response = self.client.get(url)
assert response.status_code == 200
assert response.data["is_valid"] is False

def test_owner_without_install(self):
# Remove the AI installation so it doesn't exist
self.ai_install.delete()

url = reverse("gen-ai-consent")
response = self.client.get(url, data={"owner_id": self.owner.id})
assert response.status_code == 200
assert response.data["is_valid"] is False

def test_valid_owner_with_install(self):
url = reverse("gen-ai-consent")
response = self.client.get(url, data={"owner_id": self.owner.id})
assert response.status_code == 200
assert response.data["is_valid"] is True
assert len(response.data["repos"]) == 2
assert set(response.data["repos"]) == {"Repo1", "Repo2"}
62 changes: 34 additions & 28 deletions api/internal/tests/test_pagination.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,47 @@
from rest_framework.reverse import reverse
from rest_framework.test import APITestCase
from shared.django_apps.core.tests.factories import OwnerFactory

from shared.django_apps.core.tests.factories import OwnerFactory, RepositoryFactory
from utils.test_utils import Client
from codecov_auth.models import GithubAppInstallation
from graphql_api.types.owner.owner import AI_FEATURES_GH_APP_ID


class PageNumberPaginationTests(APITestCase):
class GenAIAuthViewTests(APITestCase):
def setUp(self):
self.client = Client()
self.owner = OwnerFactory(plan="users-free", plan_user_count=5)
self.users = [
OwnerFactory(organizations=[self.owner.ownerid]),
OwnerFactory(organizations=[self.owner.ownerid]),
OwnerFactory(organizations=[self.owner.ownerid]),
]

def test_pagination_returned_page_size(self):
self.client.force_login_owner(self.owner)

def _list(kwargs={}, query_params={}):
if not kwargs:
kwargs = {
"service": self.owner.service,
"owner_username": self.owner.username,
}
return self.client.get(
reverse("users-list", kwargs=kwargs), data=query_params
)

response = _list()
self.owner = OwnerFactory(service="github")
self.repo1 = RepositoryFactory(author=self.owner, name="Repo1")
self.repo2 = RepositoryFactory(author=self.owner, name="Repo2")

assert response.data["total_pages"] == 1
self.ai_install = GithubAppInstallation.objects.create(
app_id=AI_FEATURES_GH_APP_ID,
owner=self.owner,
repository_service_ids=[self.repo1.service_id, self.repo2.service_id],
)

response = _list(query_params={"page_size": "1"})
def test_no_owner_id(self):
url = reverse("gen-ai-consent")
self.client.force_login_owner(self.owner)
response = self.client.get(url)
assert response.status_code == 200
assert response.data["is_valid"] is False

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

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

assert response.data["total_pages"] == 1
def test_valid_owner_with_install(self):
url = reverse("gen-ai-consent")
self.client.force_login_owner(self.owner)
response = self.client.get(url, data={"owner_id": self.owner.id})
assert response.status_code == 200
assert response.data["is_valid"] is True
assert len(response.data["repos"]) == 2
assert set(response.data["repos"]) == {"Repo1", "Repo2"}
1 change: 1 addition & 0 deletions api/internal/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,5 @@
include(compare_router.urls),
),
path("features", FeaturesView.as_view(), name="features"),
path("internal/gen-ai-consent/", include("api.internal.gen_ai.urls")),
]

0 comments on commit a82089d

Please sign in to comment.