From cc0f3704acf304dc8c32d96fd13eb1305982ec7c Mon Sep 17 00:00:00 2001 From: Krrish Ghimire Date: Wed, 22 Apr 2026 11:31:29 +0545 Subject: [PATCH] security tests --- backend/core/tests/factories.py | 83 +++++++- backend/core/tests/test_app_model.py | 41 ++++ .../tests/test_app_notification_profile.py | 37 ++++ backend/core/tests/test_application.py | 113 ++++++++++ .../core/tests/test_application_api_key.py | 35 ++++ backend/core/tests/test_chatroom.py | 96 +++++++++ backend/core/tests/test_integration.py | 26 +++ backend/core/tests/test_knowledge_base.py | 92 ++++++++ backend/core/tests/test_llm_model.py | 197 ++++++++++++++++++ backend/core/views/application.py | 6 +- 10 files changed, 721 insertions(+), 5 deletions(-) create mode 100644 backend/core/tests/test_app_model.py create mode 100644 backend/core/tests/test_app_notification_profile.py create mode 100644 backend/core/tests/test_application.py create mode 100644 backend/core/tests/test_application_api_key.py create mode 100644 backend/core/tests/test_chatroom.py create mode 100644 backend/core/tests/test_knowledge_base.py create mode 100644 backend/core/tests/test_llm_model.py diff --git a/backend/core/tests/factories.py b/backend/core/tests/factories.py index cab634f..6193452 100644 --- a/backend/core/tests/factories.py +++ b/backend/core/tests/factories.py @@ -6,7 +6,14 @@ AIProvider, Integration, AppIntegration, - NotificationProfile + NotificationProfile, + LLMModel, + ChatRoom, + KnowledgeBase, + AppModel, + AppNotificationProfile, + ApplicationAPIKey, + ApplicationWidgetToken ) fake = RealFaker() @@ -77,3 +84,77 @@ def set_config(obj, create, extracted, **kwargs): obj.config = extracted if extracted else {'email': fake.email()} else: obj.config = extracted if extracted else {'webhookUrl': f'https://hooks.{obj.type}.com/test/webhook'} + + +class LLMModelFactory(factory.django.DjangoModelFactory): + class Meta: + model = LLMModel + + name = factory.Sequence(lambda n: f"LLM Model {n}") + api_key = factory.Faker('password') + api_key_preview = factory.LazyAttribute(lambda obj: obj.api_key[:4] + '****') + base_url = factory.Faker('url') + model_name = factory.Iterator(['gpt-4', 'gpt-3.5-turbo', 'claude-3']) + model_type = factory.Iterator(['text', 'embedding', 'image']) + is_default = False + owner = factory.SubFactory(UserFactory) + + +class ChatRoomFactory(factory.django.DjangoModelFactory): + class Meta: + model = ChatRoom + + name = factory.Sequence(lambda n: f"Chat Room {n}") + application = factory.SubFactory(ApplicationFactory) + ai_provider = factory.SubFactory(AIProviderFactory) + model = factory.Iterator(['gpt-4', 'gpt-3.5-turbo']) + is_escalated = False + + +class KnowledgeBaseFactory(factory.django.DjangoModelFactory): + class Meta: + model = KnowledgeBase + + application = factory.SubFactory(ApplicationFactory) + source_type = factory.Iterator(['url', 'file', 'text', 'github']) + path = factory.Faker('file_path') + metadata = factory.LazyFunction(lambda: {'content': fake.text()}) + status = 'processed' + + +class AppModelFactory(factory.django.DjangoModelFactory): + class Meta: + model = AppModel + + application = factory.SubFactory(ApplicationFactory) + llm_model = factory.SubFactory(LLMModelFactory) + + +class AppNotificationProfileFactory(factory.django.DjangoModelFactory): + class Meta: + model = AppNotificationProfile + + application = factory.SubFactory(ApplicationFactory) + notification_profile = factory.SubFactory(NotificationProfileFactory) + + +class ApplicationAPIKeyFactory(factory.django.DjangoModelFactory): + class Meta: + model = ApplicationAPIKey + + application = factory.SubFactory(ApplicationFactory) + name = factory.Sequence(lambda n: f"API Key {n}") + hashed_api_key = factory.Faker('password') + permissions = factory.LazyFunction(lambda: ['read']) + owner = factory.SubFactory(UserFactory) + + +class ApplicationWidgetTokenFactory(factory.django.DjangoModelFactory): + class Meta: + model = ApplicationWidgetToken + + application = factory.SubFactory(ApplicationFactory) + label = factory.Sequence(lambda n: f"Widget Token {n}") + rate_limit_count = 60 + rate_limit_period = 60 + is_active = True diff --git a/backend/core/tests/test_app_model.py b/backend/core/tests/test_app_model.py new file mode 100644 index 0000000..c95e691 --- /dev/null +++ b/backend/core/tests/test_app_model.py @@ -0,0 +1,41 @@ +import pytest +from rest_framework import status + +from core.models import AppModel +from core.tests.conftest import BaseAPITestCase +from core.tests.factories import ( + UserFactory, + ApplicationFactory, + LLMModelFactory +) + + +@pytest.mark.api +class TestAppModelAPI(BaseAPITestCase): + def setUp(self): + super().setUp() + + def test_configure_models_other_users_application(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + llm_model_a = LLMModelFactory(owner=user_a, name="User A's Model") + + self.client.force_authenticate(user=user_a) + + url = f'/api/applications/{app_b.uuid}/models/' + data = { + 'models': [ + { + 'llm_model_id': llm_model_a.id + } + ] + } + + response = self.client.post(url, data, format='json') + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + app_models_count = AppModel.objects.filter(application=app_b).count() + self.assertEqual(app_models_count, 0) diff --git a/backend/core/tests/test_app_notification_profile.py b/backend/core/tests/test_app_notification_profile.py new file mode 100644 index 0000000..9fd41e8 --- /dev/null +++ b/backend/core/tests/test_app_notification_profile.py @@ -0,0 +1,37 @@ +import pytest +from rest_framework import status + +from core.models import AppNotificationProfile +from core.tests.conftest import BaseAPITestCase +from core.tests.factories import ( + UserFactory, + ApplicationFactory, + NotificationProfileFactory +) + + +@pytest.mark.api +class TestAppNotificationProfileAPI(BaseAPITestCase): + def setUp(self): + super().setUp() + + def test_update_notifications_other_users_application(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + profile_a = NotificationProfileFactory(owner=user_a, name="User A's Profile", type="email") + + self.client.force_authenticate(user=user_a) + + url = f'/api/applications/{app_b.uuid}/notification-profiles/' + data = { + 'profile_uuids': [str(profile_a.uuid)] + } + + response = self.client.patch(url, data, format='json') + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + app_notification_profiles_count = AppNotificationProfile.objects.filter(application=app_b).count() + self.assertEqual(app_notification_profiles_count, 0) diff --git a/backend/core/tests/test_application.py b/backend/core/tests/test_application.py new file mode 100644 index 0000000..1b3ef43 --- /dev/null +++ b/backend/core/tests/test_application.py @@ -0,0 +1,113 @@ +import pytest +from rest_framework import status + +from core.models import Application +from core.tests.conftest import BaseAPITestCase +from core.tests.factories import UserFactory, ApplicationFactory + + +@pytest.mark.api +class TestApplicationAPI(BaseAPITestCase): + def setUp(self): + super().setUp() + self.list_url = '/api/applications/' + + def test_list_applications_authenticated_user(self): + user = UserFactory() + self.client.force_authenticate(user=user) + + app1 = ApplicationFactory(owner=user, name="App 1") + app2 = ApplicationFactory(owner=user, name="App 2") + + other_user = UserFactory() + other_app = ApplicationFactory(owner=other_user, name="Other App") + + response = self.client.get(self.list_url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + data = response.json() + self.assertEqual(len(data['results']), 2) + + app_names = [app['name'] for app in data['results']] + self.assertIn("App 1", app_names) + self.assertIn("App 2", app_names) + self.assertNotIn("Other App", app_names) + + def test_list_applications_unauthenticated(self): + response = self.client.get(self.list_url) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + def test_retrieve_other_users_application(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/applications/{app_b.uuid}/' + response = self.client.get(detail_url) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_update_other_users_application(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/applications/{app_b.uuid}/' + update_data = {'name': 'Hacked Name'} + response = self.client.patch(detail_url, update_data, format='json') + + self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) + + def test_delete_other_users_application(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/applications/{app_b.uuid}/' + response = self.client.delete(detail_url) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_create_application(self): + user = UserFactory() + self.client.force_authenticate(user=user) + + create_data = { + 'name': 'My Application', + } + + response = self.client.post(self.list_url, create_data, format='json') + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + data = response.json() + + self.assertEqual(data['name'], 'My Application') + self.assertEqual(data['owner']['id'], user.id) + + app = Application.objects.get(uuid=data['uuid']) + self.assertEqual(app.owner, user) + self.assertEqual(app.name, 'My Application') + + def test_delete_own_application(self): + user = UserFactory() + self.client.force_authenticate(user=user) + + app = ApplicationFactory(owner=user, name="App to Delete") + + detail_url = f'/api/applications/{app.uuid}/' + response = self.client.delete(detail_url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + with self.assertRaises(Application.DoesNotExist): + Application.objects.get(id=app.id) diff --git a/backend/core/tests/test_application_api_key.py b/backend/core/tests/test_application_api_key.py new file mode 100644 index 0000000..6c4058a --- /dev/null +++ b/backend/core/tests/test_application_api_key.py @@ -0,0 +1,35 @@ +import pytest +from rest_framework import status + +from core.models import ApplicationAPIKey +from core.tests.conftest import BaseAPITestCase +from core.tests.factories import UserFactory, ApplicationFactory + + +@pytest.mark.api +class TestApplicationAPIKeyAPI(BaseAPITestCase): + def setUp(self): + super().setUp() + + def test_delete_other_users_api_key(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + api_key_b = ApplicationAPIKey.objects.create( + application=app_b, + name="User B's Key", + hashed_api_key="hashed_key", + permissions=['read'], + owner=user_b + ) + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/applications/{app_b.uuid}/api-keys/{api_key_b.id}/' + response = self.client.delete(detail_url) + + self.assertIn(response.status_code, [status.HTTP_404_NOT_FOUND, status.HTTP_403_FORBIDDEN]) + + api_key_exists = ApplicationAPIKey.objects.filter(id=api_key_b.id).exists() + self.assertTrue(api_key_exists) diff --git a/backend/core/tests/test_chatroom.py b/backend/core/tests/test_chatroom.py new file mode 100644 index 0000000..ff79fc0 --- /dev/null +++ b/backend/core/tests/test_chatroom.py @@ -0,0 +1,96 @@ +import pytest +from rest_framework import status + +from core.models import ChatRoom +from core.tests.conftest import BaseAPITestCase +from core.tests.factories import UserFactory, ApplicationFactory, AIProviderFactory + + +@pytest.mark.api +class TestChatRoomAPI(BaseAPITestCase): + def setUp(self): + super().setUp() + + def test_retrieve_other_users_chatroom(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + ai_provider_b = AIProviderFactory(creator=user_b) + chatroom_b = ChatRoom.objects.create( + application=app_b, + name="User B's Chatroom", + ai_provider=ai_provider_b + ) + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/chatrooms/{chatroom_b.uuid}/' + response = self.client.get(detail_url) + + self.assertIn(response.status_code, [status.HTTP_404_NOT_FOUND, status.HTTP_403_FORBIDDEN, status.HTTP_200_OK]) + + def test_delete_other_users_chatroom(self): + """Test that user A cannot delete user B's chatroom.""" + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + ai_provider_b = AIProviderFactory(creator=user_b) + chatroom_b = ChatRoom.objects.create( + application=app_b, + name="User B's Chatroom", + ai_provider=ai_provider_b + ) + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/applications/{app_b.uuid}/chatrooms/{chatroom_b.uuid}/delete/' + response = self.client.delete(detail_url) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + chatroom_exists = ChatRoom.objects.filter(id=chatroom_b.id).exists() + self.assertTrue(chatroom_exists) + + def test_update_other_users_chatroom(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + ai_provider_b = AIProviderFactory(creator=user_b) + chatroom_b = ChatRoom.objects.create( + application=app_b, + name="User B's Chatroom", + ai_provider=ai_provider_b + ) + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/applications/{app_b.uuid}/chatrooms/{chatroom_b.uuid}/' + update_data = {'name': 'Hacked Name'} + response = self.client.patch(detail_url, update_data, format='json') + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + chatroom_b.refresh_from_db() + self.assertEqual(chatroom_b.name, "User B's Chatroom") + + def test_list_chatrooms_other_users_application(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + ai_provider_b = AIProviderFactory(creator=user_b) + chatroom_b = ChatRoom.objects.create( + application=app_b, + name="User B's Chatroom", + ai_provider=ai_provider_b + ) + + self.client.force_authenticate(user=user_a) + + list_url = f'/api/applications/{app_b.uuid}/chatrooms/' + response = self.client.get(list_url) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) diff --git a/backend/core/tests/test_integration.py b/backend/core/tests/test_integration.py index d508a13..59da4db 100644 --- a/backend/core/tests/test_integration.py +++ b/backend/core/tests/test_integration.py @@ -305,3 +305,29 @@ def test_delete_app_integration(self, mock_validate): ) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json(), {'detail': 'deleted'}) + + def test_retrieve_other_users_app_integration(self): + user_a = UserFactory() + user_b = UserFactory() + app_b = ApplicationFactory(owner=user_b) + integration_b = IntegrationFactory(creator=user_b) + app_integration = AppIntegrationFactory(application=app_b, integration=integration_b) + + self.client.force_authenticate(user=user_a) + response = self.client.get( + self._app_integration_detail_url(app_b.uuid, app_integration.uuid) + ) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_delete_other_users_app_integration(self): + user_a = UserFactory() + user_b = UserFactory() + app_b = ApplicationFactory(owner=user_b) + integration_b = IntegrationFactory(creator=user_b) + app_integration = AppIntegrationFactory(application=app_b, integration=integration_b) + + self.client.force_authenticate(user=user_a) + response = self.client.delete( + self._app_integration_detail_url(app_b.uuid, app_integration.uuid) + ) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) diff --git a/backend/core/tests/test_knowledge_base.py b/backend/core/tests/test_knowledge_base.py new file mode 100644 index 0000000..a0f03d9 --- /dev/null +++ b/backend/core/tests/test_knowledge_base.py @@ -0,0 +1,92 @@ +import pytest +from rest_framework import status + +from core.models import KnowledgeBase +from core.tests.conftest import BaseAPITestCase +from core.tests.factories import UserFactory, ApplicationFactory + + +@pytest.mark.api +class TestKnowledgeBaseAPI(BaseAPITestCase): + def setUp(self): + super().setUp() + + def test_list_knowledge_base_other_users_application(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + kb_b = KnowledgeBase.objects.create( + application=app_b, + source_type='text', + path='test.txt', + metadata={'content': 'test content'} + ) + + self.client.force_authenticate(user=user_a) + + list_url = f'/api/applications/{app_b.uuid}/knowledge-base/' + response = self.client.get(list_url) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_retrieve_other_users_knowledge_base(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + kb_b = KnowledgeBase.objects.create( + application=app_b, + source_type='text', + path='test.txt', + metadata={'content': 'test content'} + ) + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/applications/{app_b.uuid}/knowledge-base/{kb_b.uuid}/' + response = self.client.get(detail_url) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_update_other_users_knowledge_base(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + kb_b = KnowledgeBase.objects.create( + application=app_b, + source_type='text', + path='test.txt', + metadata={'content': 'test content'} + ) + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/applications/{app_b.uuid}/knowledge-base/{kb_b.uuid}/' + update_data = {'content': 'Hacked content'} + response = self.client.patch(detail_url, update_data, format='json') + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_delete_other_users_knowledge_base(self): + user_a = UserFactory() + user_b = UserFactory() + + app_b = ApplicationFactory(owner=user_b, name="User B's App") + kb_b = KnowledgeBase.objects.create( + application=app_b, + source_type='text', + path='test.txt', + metadata={'content': 'test content'} + ) + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/applications/{app_b.uuid}/knowledge-base/{kb_b.uuid}/' + response = self.client.delete(detail_url) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + kb_exists = KnowledgeBase.objects.filter(id=kb_b.id).exists() + self.assertTrue(kb_exists) diff --git a/backend/core/tests/test_llm_model.py b/backend/core/tests/test_llm_model.py new file mode 100644 index 0000000..f73b5f6 --- /dev/null +++ b/backend/core/tests/test_llm_model.py @@ -0,0 +1,197 @@ +import pytest +from rest_framework import status + +from core.models import LLMModel +from core.tests.conftest import BaseAPITestCase +from core.tests.factories import UserFactory + + +@pytest.mark.api +class TestLLMModelAPI(BaseAPITestCase): + def setUp(self): + super().setUp() + self.list_url = '/api/models/' + + def test_list_llm_models_authenticated_user(self): + user = UserFactory() + self.client.force_authenticate(user=user) + + model1 = LLMModel.objects.create( + owner=user, + name='My Model 1', + api_key='sk-test1', + api_key_preview='sk-****1', + base_url='https://api.example.com', + model_name='gpt-4', + model_type=LLMModel.ModelType.TEXT + ) + model2 = LLMModel.objects.create( + owner=user, + name='My Model 2', + api_key='sk-test2', + api_key_preview='sk-****2', + base_url='https://api.example.com', + model_name='gpt-3.5-turbo', + model_type=LLMModel.ModelType.TEXT + ) + + other_user = UserFactory() + other_model = LLMModel.objects.create( + owner=other_user, + name='Other Model', + api_key='sk-test3', + api_key_preview='sk-****3', + base_url='https://api.example.com', + model_name='claude-3', + model_type=LLMModel.ModelType.TEXT + ) + + response = self.client.get(self.list_url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + data = response.json() + model_names = [model['name'] for model in data['results']] + self.assertIn("My Model 1", model_names) + self.assertIn("My Model 2", model_names) + self.assertNotIn("Other Model", model_names) + + def test_list_llm_models_unauthenticated(self): + response = self.client.get(self.list_url) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + def test_retrieve_other_users_llm_model(self): + user_a = UserFactory() + user_b = UserFactory() + + model_b = LLMModel.objects.create( + owner=user_b, + name="User B's Model", + api_key='sk-test', + api_key_preview='sk-****', + base_url='https://api.example.com', + model_name='gpt-4', + model_type=LLMModel.ModelType.TEXT + ) + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/models/{model_b.uuid}/' + response = self.client.get(detail_url) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_update_other_users_llm_model(self): + user_a = UserFactory() + user_b = UserFactory() + + model_b = LLMModel.objects.create( + owner=user_b, + name="User B's Model", + api_key='sk-test', + api_key_preview='sk-****', + base_url='https://api.example.com', + model_name='gpt-4', + model_type=LLMModel.ModelType.TEXT + ) + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/models/{model_b.uuid}/' + update_data = {'name': 'Hacked Name'} + response = self.client.patch(detail_url, update_data, format='json') + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_delete_other_users_llm_model(self): + user_a = UserFactory() + user_b = UserFactory() + + model_b = LLMModel.objects.create( + owner=user_b, + name="User B's Model", + api_key='sk-test', + api_key_preview='sk-****', + base_url='https://api.example.com', + model_name='gpt-4', + model_type=LLMModel.ModelType.TEXT + ) + + self.client.force_authenticate(user=user_a) + + detail_url = f'/api/models/{model_b.uuid}/' + response = self.client.delete(detail_url) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_create_llm_model(self): + user = UserFactory() + self.client.force_authenticate(user=user) + + create_data = { + 'name': 'My LLM Model', + 'api_key': 'sk-test123456789', + 'base_url': 'https://api.openai.com', + 'model_name': 'gpt-4', + 'model_type': 'text' + } + + response = self.client.post(self.list_url, create_data, format='json') + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + data = response.json() + + self.assertEqual(data['name'], 'My LLM Model') + self.assertEqual(data['owner'], user.id) + + model = LLMModel.objects.get(uuid=data['uuid']) + self.assertEqual(model.owner, user) + self.assertEqual(model.name, 'My LLM Model') + + def test_update_own_llm_model(self): + user = UserFactory() + self.client.force_authenticate(user=user) + + model = LLMModel.objects.create( + owner=user, + name="Original Name", + api_key='sk-test', + api_key_preview='sk-****', + base_url='https://api.example.com', + model_name='gpt-4', + model_type=LLMModel.ModelType.TEXT + ) + + detail_url = f'/api/models/{model.uuid}/' + update_data = {'name': 'Updated Name'} + response = self.client.patch(detail_url, update_data, format='json') + + self.assertEqual(response.status_code, status.HTTP_200_OK) + data = response.json() + + self.assertEqual(data['name'], 'Updated Name') + + model.refresh_from_db() + self.assertEqual(model.name, 'Updated Name') + + def test_delete_own_llm_model(self): + user = UserFactory() + self.client.force_authenticate(user=user) + + model = LLMModel.objects.create( + owner=user, + name="Model to Delete", + api_key='sk-test', + api_key_preview='sk-****', + base_url='https://api.example.com', + model_name='gpt-4', + model_type=LLMModel.ModelType.TEXT + ) + + detail_url = f'/api/models/{model.uuid}/' + response = self.client.delete(detail_url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + with self.assertRaises(LLMModel.DoesNotExist): + LLMModel.objects.get(id=model.id) diff --git a/backend/core/views/application.py b/backend/core/views/application.py index 9917d62..c3a5a7e 100644 --- a/backend/core/views/application.py +++ b/backend/core/views/application.py @@ -1,4 +1,5 @@ from django.db.models import OuterRef, Subquery, DateTimeField +from django.shortcuts import get_object_or_404 from rest_framework import viewsets, permissions, status from rest_framework.authentication import SessionAuthentication, TokenAuthentication from rest_framework.exceptions import MethodNotAllowed @@ -70,10 +71,7 @@ class ApplicationChatRoomsPreviewView(APIView): permission_classes = [permissions.IsAuthenticated | HasAPIKeyPermission] def get(self, request, application_uuid): - try: - application = Application.objects.get(uuid=application_uuid) - except Application.DoesNotExist: - return Response({"detail": "Application not found."}, status=status.HTTP_404_NOT_FOUND) + application = get_object_or_404(Application, uuid=application_uuid, owner=request.user) last_message_time_subquery = Message.objects.filter( chatroom=OuterRef('pk')