From ee150ff4e814686ab225400dca4fd48829d9e77d Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Mon, 22 Sep 2025 13:03:15 -0400 Subject: [PATCH 01/12] Rename the organization model, experimental --- .../test_api_telemetry_settings_views.py | 14 +++--- .../ai/api/tests/test_chat_view.py | 32 +++++++------- .../ai/api/tests/test_completion_wca_view.py | 44 +++++++++---------- .../ai/api/tests/test_feedback_view.py | 6 +-- ansible_ai_connect/ai/api/tests/test_views.py | 18 ++++---- .../api/utils/segment_analytics_telemetry.py | 2 +- .../tests/test_segment_analytics_telemetry.py | 6 +-- .../ai/api/wca/api_key_views.py | 2 +- .../ai/api/wca/model_id_views.py | 2 +- .../ai/api/wca/tests/test_api_key_views.py | 38 ++++++++-------- .../ai/api/wca/tests/test_model_id_views.py | 40 ++++++++--------- .../main/tests/test_console_views.py | 6 +-- ansible_ai_connect/main/tests/test_views.py | 4 +- .../organizations/migrations/0001_initial.py | 2 +- .../0002_user_organization_fix_id.py | 2 +- ...03_alter_organization_telemetry_opt_out.py | 2 +- .../0004_organization_enable_anonymization.py | 2 +- .../test_0002_user_organization_fix_id.py | 2 +- ansible_ai_connect/organizations/models.py | 2 +- .../organizations/serializers.py | 4 +- .../organizations/tests/test_organizations.py | 22 +++++----- ansible_ai_connect/test_utils.py | 6 +-- .../users/management/commands/createtoken.py | 4 +- .../commands/tests/test_createtoken.py | 4 +- .../migrations/0009_user_organization.py | 2 +- ansible_ai_connect/users/models.py | 4 +- ansible_ai_connect/users/pipeline.py | 4 +- ansible_ai_connect/users/tests/test_users.py | 4 +- 28 files changed, 140 insertions(+), 140 deletions(-) diff --git a/ansible_ai_connect/ai/api/telemetry/tests/test_api_telemetry_settings_views.py b/ansible_ai_connect/ai/api/telemetry/tests/test_api_telemetry_settings_views.py index 161ab2442..49f79c08b 100644 --- a/ansible_ai_connect/ai/api/telemetry/tests/test_api_telemetry_settings_views.py +++ b/ansible_ai_connect/ai/api/telemetry/tests/test_api_telemetry_settings_views.py @@ -27,7 +27,7 @@ IsOrganisationLightspeedSubscriber, ) from ansible_ai_connect.ai.api.tests.test_views import WisdomServiceAPITestCaseBase -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.test_utils import APIVersionTestCaseBase @@ -71,7 +71,7 @@ def test_get_settings_without_org_id(self, *args): @patch.object(feature_flags, "LDClient") def test_get_settings_when_undefined(self, LDClient, *args): LDClient.return_value.variation.return_value = True - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) with self.assertLogs(logger="root", level="DEBUG") as log: @@ -85,7 +85,7 @@ def test_get_settings_when_undefined(self, LDClient, *args): @patch.object(feature_flags, "LDClient") def test_get_settings_when_defined(self, LDClient, *args): LDClient.return_value.variation.return_value = True - self.user.organization = Organization.objects.get_or_create(id=123, telemetry_opt_out=True)[ + self.user.organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=True)[ 0 ] self.client.force_authenticate(user=self.user) @@ -115,7 +115,7 @@ def test_set_settings_without_org_id(self, *args): @patch.object(feature_flags, "LDClient") def test_set_settings_with_valid_value(self, LDClient, *args): LDClient.return_value.variation.return_value = True - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) # Settings should initially be False r = self.client.get(self.api_version_reverse("telemetry_settings")) @@ -150,7 +150,7 @@ def test_set_settings_with_valid_value(self, LDClient, *args): @patch.object(feature_flags, "LDClient") def test_set_settings_throws_exception(self, LDClient, *args): LDClient.return_value.variation.return_value = True - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) with patch("django.db.models.base.Model.save", side_effect=DatabaseError()): @@ -168,7 +168,7 @@ def test_set_settings_throws_exception(self, LDClient, *args): @patch.object(feature_flags, "LDClient") def test_set_settings_throws_validation_exception(self, LDClient, *args): LDClient.return_value.variation.return_value = True - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) with self.assertLogs(logger="root", level="DEBUG") as log: @@ -187,7 +187,7 @@ class TestTelemetrySettingsViewAsNonSubscriber( APIVersionTestCaseBase, WisdomServiceAPITestCaseBase ): def test_get_settings_as_non_subscriber(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) r = self.client.get(self.api_version_reverse("telemetry_settings")) self.assertEqual(r.status_code, HTTPStatus.FORBIDDEN) diff --git a/ansible_ai_connect/ai/api/tests/test_chat_view.py b/ansible_ai_connect/ai/api/tests/test_chat_view.py index 1d002b1c4..19f448214 100644 --- a/ansible_ai_connect/ai/api/tests/test_chat_view.py +++ b/ansible_ai_connect/ai/api/tests/test_chat_view.py @@ -41,7 +41,7 @@ ) from ansible_ai_connect.ai.api.model_pipelines.tests import mock_pipeline_config from ansible_ai_connect.main import ssl_manager -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.test_utils import ( APIVersionTestCaseBase, WisdomServiceAPITestCaseBase, @@ -114,7 +114,7 @@ class TestChatView(APIVersionTestCaseBase, WisdomServiceAPITestCaseBase): def setUp(self): super().setUp() - (org, _) = Organization.objects.get_or_create(id=123, telemetry_opt_out=False) + (org, _) = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False) self.user.organization = org self.user.rh_internal = True @@ -307,7 +307,7 @@ def test_chat_with_system_prompt_override(self): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_operational_telemetry(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) with ( patch.object( @@ -390,7 +390,7 @@ def test_operational_telemetry_limit_exceeded(self): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_operational_telemetry_anonymizer(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) with ( patch.object( @@ -414,7 +414,7 @@ def test_operational_telemetry_anonymizer(self): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_operational_telemetry_with_system_prompt_override(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) with ( patch.object( @@ -450,7 +450,7 @@ def test_operational_telemetry_with_system_prompt_override(self): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_operational_telemetry_with_no_tools_option(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) with ( patch.object( @@ -491,7 +491,7 @@ def test_chat_rate_limit(self): email=email, password=password, ) - (org, _) = Organization.objects.get_or_create(id=123, telemetry_opt_out=False) + (org, _) = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False) self.user2.organization = org self.user2.rh_internal = True # Call chart API five times using self.user2 @@ -507,7 +507,7 @@ def test_chat_rate_limit(self): def test_operational_telemetry_excludes_chat_prompt_by_default(self): """Test that chat_prompt is excluded from telemetry by default (via allow list)""" self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) with ( patch.object( @@ -538,7 +538,7 @@ def test_not_rh_internal_user(self): self.user2 = get_user_model().objects.create_user( username=username, ) - self.user2.organization = Organization.objects.get_or_create( + self.user2.organization = ExternalOrganization.objects.get_or_create( id=123, telemetry_opt_out=False )[0] self.user2.rh_internal = False @@ -553,7 +553,7 @@ class TestStreamingChatView(APIVersionTestCaseBase, WisdomServiceAPITestCaseBase def setUp(self): super().setUp() - (org, _) = Organization.objects.get_or_create(id=123, telemetry_opt_out=False) + (org, _) = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False) self.user.organization = org self.user.rh_internal = True @@ -663,7 +663,7 @@ def test_chat_internal_server_exception(self): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_operational_telemetry(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) with ( patch.object( @@ -723,7 +723,7 @@ def test_operational_telemetry_limit_exceeded(self): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_operational_telemetry_anonymizer(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) with ( patch.object( @@ -747,7 +747,7 @@ def test_operational_telemetry_anonymizer(self): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_operational_telemetry_with_system_prompt_override(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) with ( patch.object( @@ -781,7 +781,7 @@ def test_operational_telemetry_with_system_prompt_override(self): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_operational_telemetry_with_no_tools_option(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) with ( patch.object( @@ -821,7 +821,7 @@ def test_chat_rate_limit(self): email=email, password=password, ) - (org, _) = Organization.objects.get_or_create(id=123, telemetry_opt_out=False) + (org, _) = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False) self.user2.organization = org self.user2.rh_internal = True # Call chart API five times using self.user2 @@ -839,7 +839,7 @@ def test_not_rh_internal_user(self): self.user2 = get_user_model().objects.create_user( username=username, ) - self.user2.organization = Organization.objects.get_or_create( + self.user2.organization = ExternalOrganization.objects.get_or_create( id=123, telemetry_opt_out=False )[0] self.user2.rh_internal = False diff --git a/ansible_ai_connect/ai/api/tests/test_completion_wca_view.py b/ansible_ai_connect/ai/api/tests/test_completion_wca_view.py index 94941e80a..4c43d2043 100644 --- a/ansible_ai_connect/ai/api/tests/test_completion_wca_view.py +++ b/ansible_ai_connect/ai/api/tests/test_completion_wca_view.py @@ -51,7 +51,7 @@ from ansible_ai_connect.ai.api.model_pipelines.wca.pipelines_saas import ( WCASaaSCompletionsPipeline, ) -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.test_utils import ( APIVersionTestCaseBase, WisdomAppsBackendMocking, @@ -96,7 +96,7 @@ def stub_wca_client( @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -124,7 +124,7 @@ def test_wca_completion(self): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_wca_completion_seated_user_missing_api_key(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -185,7 +185,7 @@ def test_wca_completion_user_not_linked_to_org(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_seated_user_missing_model_id(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -212,7 +212,7 @@ def test_wca_completion_seated_user_missing_model_id(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_seated_user_garbage_model_id(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -240,7 +240,7 @@ def test_wca_completion_seated_user_garbage_model_id(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_seated_user_not_quite_valid_model_id(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -274,7 +274,7 @@ def test_wca_completion_seated_user_not_quite_valid_model_id(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_seated_user_invalid_model_id_for_api_key(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -300,7 +300,7 @@ def test_wca_completion_seated_user_invalid_model_id_for_api_key(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_seated_user_empty_response(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -326,7 +326,7 @@ def test_wca_completion_seated_user_empty_response(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_seated_user_cloudflare_rejection(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) model_client, model_input = self.stub_wca_client() @@ -355,7 +355,7 @@ def test_wca_completion_seated_user_cloudflare_rejection(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_seated_user_hap_filter_rejection(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) model_client, model_input = self.stub_wca_client() @@ -383,7 +383,7 @@ def test_wca_completion_seated_user_hap_filter_rejection(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_wml_api_call_failed(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) model_client, model_input = self.stub_wca_client() @@ -412,7 +412,7 @@ def test_wca_completion_wml_api_call_failed(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_seated_user_trial_expired_rejection(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) model_client, model_input = self.stub_wca_client() @@ -436,7 +436,7 @@ def test_wca_completion_seated_user_trial_expired_rejection(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_seated_user_trial_expired(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -462,7 +462,7 @@ def test_wca_completion_seated_user_trial_expired(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_seated_user_model_id_error(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) model_client, model_input = self.stub_wca_client() @@ -490,7 +490,7 @@ def test_wca_completion_seated_user_model_id_error(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_timeout_single_task(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -514,7 +514,7 @@ def test_wca_completion_timeout_single_task(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_timeout_multi_task(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -547,7 +547,7 @@ def test_wca_completion_timeout_multi_task(self): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_wca_completion_timed_out(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -586,7 +586,7 @@ def test_wca_completion_timed_out(self): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_wca_completion_request_id_correlation_failure(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -636,7 +636,7 @@ def test_wca_completion_segment_event_with_invalid_model_id_error( self, mock_send_segment_event ): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) stub = self.stub_wca_client( @@ -670,7 +670,7 @@ def test_wca_completion_segment_event_with_invalid_model_id_error( @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_completion_wca_instance_deleted(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) model_client, model_input = self.stub_wca_client() @@ -703,7 +703,7 @@ def test_wca_completion_wca_instance_deleted(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_inference_failed(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) model_client, model_input = self.stub_wca_client() @@ -732,7 +732,7 @@ def test_wca_inference_failed(self): @override_settings(ENABLE_ARI_POSTPROCESS=False) def test_wca_validation_failed(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) model_client, model_input = self.stub_wca_client() diff --git a/ansible_ai_connect/ai/api/tests/test_feedback_view.py b/ansible_ai_connect/ai/api/tests/test_feedback_view.py index 49478881a..7a9010c7c 100644 --- a/ansible_ai_connect/ai/api/tests/test_feedback_view.py +++ b/ansible_ai_connect/ai/api/tests/test_feedback_view.py @@ -30,7 +30,7 @@ from ansible_ai_connect.ai.api.model_pipelines.wca.pipelines_saas import ( WCASaaSCompletionsPipeline, ) -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.test_utils import ( APIVersionTestCaseBase, WisdomServiceAPITestCaseBase, @@ -50,7 +50,7 @@ class TestFeedbackView(APIVersionTestCaseBase, WisdomServiceAPITestCaseBase): def setUp(self): super().setUp() - (org, _) = Organization.objects.get_or_create(id=123, telemetry_opt_out=False) + (org, _) = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False) self.user.organization = org def test_feedback_full_payload(self): @@ -423,7 +423,7 @@ def test_feedback_chatbot(self): } } self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) with self.assertLogs(logger="root", level="DEBUG") as log: r = self.client.post(self.api_version_reverse("feedback"), payload, format="json") diff --git a/ansible_ai_connect/ai/api/tests/test_views.py b/ansible_ai_connect/ai/api/tests/test_views.py index 0c840b171..ba8052913 100644 --- a/ansible_ai_connect/ai/api/tests/test_views.py +++ b/ansible_ai_connect/ai/api/tests/test_views.py @@ -87,7 +87,7 @@ from ansible_ai_connect.ai.api.serializers import CompletionRequestSerializer from ansible_ai_connect.healthcheck.backends import HealthCheckSummary from ansible_ai_connect.main.tests.test_views import create_user_with_provider -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.test_utils import ( APIVersionTestCaseBase, WisdomAppsBackendMocking, @@ -203,7 +203,7 @@ class TestContentMatchesWCAView( ): def test_wca_contentmatch_single_task(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) payload = { "suggestions": [ @@ -295,7 +295,7 @@ def test_wca_contentmatch_single_task(self): def test_wca_contentmatch_multi_task(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) payload = { "suggestions": [ @@ -395,7 +395,7 @@ def test_wca_contentmatch_multi_task(self): def test_wca_contentmatch_with_custom_model_id(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) payload = { "suggestions": [ @@ -452,7 +452,7 @@ def test_wca_contentmatch_with_custom_model_id(self): def test_wca_contentmatch_without_custom_model_id(self): self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) payload = { "suggestions": [ @@ -518,7 +518,7 @@ def setUp(self): super().setUp() self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) self.payload = { @@ -699,7 +699,7 @@ def setUp(self): super().setUp() self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=1)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=1)[0] self.client.force_authenticate(user=self.user) self.payload = { @@ -1735,7 +1735,7 @@ def setUp(self): self.aap_user.save() def tearDown(self): - Organization.objects.filter(id=1981).delete() + ExternalOrganization.objects.filter(id=1981).delete() self.aap_user.delete() super().tearDown() @@ -1808,7 +1808,7 @@ def setUp(self): self.aap_user.save() def tearDown(self): - Organization.objects.filter(id=1981).delete() + ExternalOrganization.objects.filter(id=1981).delete() self.aap_user.delete() super().tearDown() diff --git a/ansible_ai_connect/ai/api/utils/segment_analytics_telemetry.py b/ansible_ai_connect/ai/api/utils/segment_analytics_telemetry.py index e5541bf1d..58672d2cf 100644 --- a/ansible_ai_connect/ai/api/utils/segment_analytics_telemetry.py +++ b/ansible_ai_connect/ai/api/utils/segment_analytics_telemetry.py @@ -23,7 +23,7 @@ base_send_segment_event, send_segment_event, ) -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.users.models import User logger = logging.getLogger(__name__) diff --git a/ansible_ai_connect/ai/api/utils/tests/test_segment_analytics_telemetry.py b/ansible_ai_connect/ai/api/utils/tests/test_segment_analytics_telemetry.py index 628d11601..c70e35872 100644 --- a/ansible_ai_connect/ai/api/utils/tests/test_segment_analytics_telemetry.py +++ b/ansible_ai_connect/ai/api/utils/tests/test_segment_analytics_telemetry.py @@ -30,7 +30,7 @@ send_segment_analytics_error_event, send_segment_analytics_event, ) -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization @override_settings(DEPLOYMENT_MODE="saas") @@ -43,13 +43,13 @@ def setUpClass(cls): def setUp(self): super().setUp() self.user.rh_user_has_seat = True - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.user.organization.telemetry_opt_out = False self.user.organization.save() feature_flags.FeatureFlags.instance = None def tearDown(self): - Organization.objects.filter(id=123).delete() + ExternalOrganization.objects.filter(id=123).delete() super().tearDown() @staticmethod diff --git a/ansible_ai_connect/ai/api/wca/api_key_views.py b/ansible_ai_connect/ai/api/wca/api_key_views.py index 2a712315b..028872a7e 100644 --- a/ansible_ai_connect/ai/api/wca/api_key_views.py +++ b/ansible_ai_connect/ai/api/wca/api_key_views.py @@ -45,7 +45,7 @@ from ansible_ai_connect.ai.api.serializers import WcaKeyRequestSerializer from ansible_ai_connect.ai.api.utils.segment import send_segment_event from ansible_ai_connect.ai.api.views import ServiceUnavailable -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.users.signals import ( user_delete_wca_api_key, user_delete_wca_model_id, diff --git a/ansible_ai_connect/ai/api/wca/model_id_views.py b/ansible_ai_connect/ai/api/wca/model_id_views.py index 2fee74c7e..9b4d3d676 100644 --- a/ansible_ai_connect/ai/api/wca/model_id_views.py +++ b/ansible_ai_connect/ai/api/wca/model_id_views.py @@ -55,7 +55,7 @@ ) from ansible_ai_connect.ai.api.serializers import WcaModelIdRequestSerializer from ansible_ai_connect.ai.api.utils.segment import send_segment_event -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.users.signals import user_set_wca_model_id UNKNOWN_MODEL_ID = "Unknown" diff --git a/ansible_ai_connect/ai/api/wca/tests/test_api_key_views.py b/ansible_ai_connect/ai/api/wca/tests/test_api_key_views.py index 628023a3c..11c9fdbea 100644 --- a/ansible_ai_connect/ai/api/wca/tests/test_api_key_views.py +++ b/ansible_ai_connect/ai/api/wca/tests/test_api_key_views.py @@ -38,7 +38,7 @@ IsOrganisationLightspeedSubscriber, IsWCASaaSModelPipeline, ) -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.test_utils import ( APIVersionTestCaseBase, WisdomAppsBackendMocking, @@ -100,7 +100,7 @@ def test_permission_classes(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_get_key_when_undefined(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() self.client.force_authenticate(user=self.user) mock_secret_manager.get_secret = Mock(return_value=None) @@ -120,7 +120,7 @@ def test_get_key_when_defined_seated_user(self, *args): self._test_get_key_when_defined(True) def _test_get_key_when_defined(self, has_seat): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.user.rh_user_has_seat = has_seat mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() self.client.force_authenticate(user=self.user) @@ -136,7 +136,7 @@ def _test_get_key_when_defined(self, has_seat): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_get_key_when_defined_throws_exception(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() self.client.force_authenticate(user=self.user) mock_secret_manager.get_secret.side_effect = WcaSecretManagerError("Test") @@ -168,7 +168,7 @@ def test_set_key_with_valid_value_seated_user(self, *args): self._test_set_key_with_valid_value(True) def _test_set_key_with_valid_value(self, has_seat): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.user.rh_user_has_seat = has_seat _md = apps.get_app_config("ai").get_model_pipeline(MetaData) mock_model_meta_data: WCASaaSMetaData = cast(WCASaaSMetaData, _md) @@ -212,7 +212,7 @@ def _test_set_key_with_valid_value(self, has_seat): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_set_key_with_invalid_value(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] _md = apps.get_app_config("ai").get_model_pipeline(MetaData) mock_model_meta_data: WCASaaSMetaData = cast(WCASaaSMetaData, _md) mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() @@ -240,7 +240,7 @@ def test_set_key_with_invalid_value(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_set_key_throws_secret_manager_exception(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() _md = apps.get_app_config("ai").get_model_pipeline(MetaData) mock_model_meta_data: WCASaaSMetaData = cast(WCASaaSMetaData, _md) @@ -259,7 +259,7 @@ def test_set_key_throws_secret_manager_exception(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_set_key_throws_http_exception(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] _md = apps.get_app_config("ai").get_model_pipeline(MetaData) mock_model_meta_data: WCASaaSMetaData = cast(WCASaaSMetaData, _md) self.client.force_authenticate(user=self.user) @@ -275,7 +275,7 @@ def test_set_key_throws_http_exception(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_set_key_throws_validation_exception(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) with self.assertLogs(logger="root", level="DEBUG") as log: @@ -297,7 +297,7 @@ def test_delete_key_without_org_id(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_delete_key(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] _md = apps.get_app_config("ai").get_model_pipeline(MetaData) mock_model_meta_data: WCASaaSMetaData = cast(WCASaaSMetaData, _md) mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() @@ -369,7 +369,7 @@ def delete_secret(*args, **kwargs): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_delete_key_with_model_id_deletion_error(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] _md = apps.get_app_config("ai").get_model_pipeline(MetaData) mock_model_meta_data: WCASaaSMetaData = cast(WCASaaSMetaData, _md) mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() @@ -419,7 +419,7 @@ def delete_secret(*args, **kwargs): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_delete_key_with_api_key_deletion_error(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] _md = apps.get_app_config("ai").get_model_pipeline(MetaData) mock_model_meta_data: WCASaaSMetaData = cast(WCASaaSMetaData, _md) mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() @@ -469,7 +469,7 @@ def delete_secret(*args, **kwargs): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_delete_key_with_no_model_id(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] _md = apps.get_app_config("ai").get_model_pipeline(MetaData) mock_model_meta_data: WCASaaSMetaData = cast(WCASaaSMetaData, _md) mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() @@ -517,7 +517,7 @@ def get_secret(*args, **kwargs): ) def test_delete_key_with_no_key_no_model_id(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() self.client.force_authenticate(user=self.user) @@ -543,7 +543,7 @@ def get_secret(*args, **kwargs): @patch.object(IsOrganisationLightspeedSubscriber, "has_permission", return_value=False) class TestWCAApiKeyViewAsNonSubscriber(APIVersionTestCaseBase, WisdomServiceAPITestCaseBaseOIDC): def test_get_api_key_as_non_subscriber(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) r = self.client.get(self.api_version_reverse("wca_api_key")) self.assertEqual(r.status_code, HTTPStatus.FORBIDDEN) @@ -595,7 +595,7 @@ def test_validate_key_with_valid_value_seated_user(self, *args): self._test_validate_key_with_valid_value(True) def _test_validate_key_with_valid_value(self, has_seat): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.user.rh_user_has_seat = has_seat mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() _md = apps.get_app_config("ai").get_model_pipeline(MetaData) @@ -612,7 +612,7 @@ def _test_validate_key_with_valid_value(self, has_seat): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_validate_key_with_missing_value(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() self.client.force_authenticate(user=self.user) mock_secret_manager.get_secret = Mock(return_value=None) @@ -624,7 +624,7 @@ def test_validate_key_with_missing_value(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_validate_key_with_invalid_value(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] _md = apps.get_app_config("ai").get_model_pipeline(MetaData) mock_model_meta_data: WCASaaSMetaData = cast(WCASaaSMetaData, _md) self.client.force_authenticate(user=self.user) @@ -639,7 +639,7 @@ def test_validate_key_with_invalid_value(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_validate_key_throws_http_exception(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] _md = apps.get_app_config("ai").get_model_pipeline(MetaData) mock_model_meta_data: WCASaaSMetaData = cast(WCASaaSMetaData, _md) self.client.force_authenticate(user=self.user) diff --git a/ansible_ai_connect/ai/api/wca/tests/test_model_id_views.py b/ansible_ai_connect/ai/api/wca/tests/test_model_id_views.py index 1ed00151a..cb3d277dc 100644 --- a/ansible_ai_connect/ai/api/wca/tests/test_model_id_views.py +++ b/ansible_ai_connect/ai/api/wca/tests/test_model_id_views.py @@ -40,7 +40,7 @@ IsWCASaaSModelPipeline, ) from ansible_ai_connect.ai.api.tests.test_views import WisdomServiceAPITestCaseBase -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.test_utils import ( APIVersionTestCaseBase, WisdomAppsBackendMocking, @@ -110,7 +110,7 @@ def test_permission_classes(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_get_model_id_when_undefined(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() self.client.force_authenticate(user=self.user) mock_secret_manager.get_secret.return_value = None @@ -130,7 +130,7 @@ def test_get_model_id_when_defined_seated_user(self, *args): self._test_get_model_id_when_defined(True) def _test_get_model_id_when_defined(self, has_seat): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.user.rh_user_has_seat = has_seat mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() self.client.force_authenticate(user=self.user) @@ -150,7 +150,7 @@ def _test_get_model_id_when_defined(self, has_seat): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_get_model_id_when_defined_throws_exception(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() self.client.force_authenticate(user=self.user) mock_secret_manager.get_secret.side_effect = WcaSecretManagerError("Test") @@ -184,7 +184,7 @@ def test_set_model_id_seated_user(self, *args): self._test_set_model_id(True) def _test_set_model_id(self, has_seat): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.user.rh_user_has_seat = has_seat mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() mock_wca_client: ModelPipelineCompletions = apps.get_app_config("ai").get_model_pipeline( @@ -251,7 +251,7 @@ def _test_set_model_id(self, has_seat): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_set_model_id_not_valid(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() mock_wca_client: ModelPipelineCompletions = apps.get_app_config("ai").get_model_pipeline( ModelPipelineCompletions @@ -282,7 +282,7 @@ def test_set_model_id_not_valid(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_set_model_id_throws_secret_manager_exception(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() mock_secret_manager.save_secret.side_effect = WcaSecretManagerError("Test") @@ -299,7 +299,7 @@ def test_set_model_id_throws_secret_manager_exception(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_set_model_id_throws_validation_exception(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() mock_secret_manager.save_secret.side_effect = WcaSecretManagerError("Test") @@ -315,7 +315,7 @@ def test_set_model_id_throws_validation_exception(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_set_model_id_empty_response(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() mock_wca_client: ModelPipelineCompletions = apps.get_app_config("ai").get_model_pipeline( ModelPipelineCompletions @@ -347,7 +347,7 @@ class TestWCAModelIdViewAsNonSubscriber( APIVersionTestCaseBase, WisdomAppsBackendMocking, WisdomServiceAPITestCaseBase ): def test_get_model_id_as_non_subscriber(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) r = self.client.get(self.api_version_reverse("wca_model_id")) self.assertEqual(r.status_code, HTTPStatus.FORBIDDEN) @@ -381,7 +381,7 @@ def tearDown(self): super().tearDown() def test_validate(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) mock_wca_client: ModelPipelineCompletions = apps.get_app_config("ai").get_model_pipeline( ModelPipelineCompletions @@ -406,7 +406,7 @@ def test_validate_error_no_org_id(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_validate_error_no_api_key(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() self.client.force_authenticate(user=self.user) @@ -426,7 +426,7 @@ def mock_get_secret_no_api_key(*args, **kwargs): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_validate_error_no_model_id(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() self.client.force_authenticate(user=self.user) @@ -453,7 +453,7 @@ def test_validate_ok_seated_user(self, *args): self._test_validate_ok(True) def _test_validate_ok(self, has_seat): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.user.rh_user_has_seat = has_seat mock_secret_manager = apps.get_app_config("ai").get_wca_secret_manager() mock_wca_client: ModelPipelineCompletions = apps.get_app_config("ai").get_model_pipeline( @@ -498,7 +498,7 @@ def mock_get_secret_side_effect(*args, **kwargs): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_validate_error_wrong_model_id(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_wca_client: ModelPipelineCompletions = apps.get_app_config("ai").get_model_pipeline( ModelPipelineCompletions ) @@ -513,7 +513,7 @@ def test_validate_error_wrong_model_id(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_validate_error_api_key_not_found(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_wca_client: ModelPipelineCompletions = apps.get_app_config("ai").get_model_pipeline( ModelPipelineCompletions ) @@ -530,7 +530,7 @@ def test_validate_error_api_key_not_found(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_validate_error_user_trial_expired(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_wca_client: ModelPipelineCompletions = apps.get_app_config("ai").get_model_pipeline( ModelPipelineCompletions ) @@ -551,7 +551,7 @@ def test_validate_error_user_trial_expired(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_validate_error_model_id_bad_request(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_wca_client: ModelPipelineCompletions = apps.get_app_config("ai").get_model_pipeline( ModelPipelineCompletions ) @@ -568,7 +568,7 @@ def test_validate_error_model_id_bad_request(self, *args): @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_validate_error_model_id_exception(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_wca_client: ModelPipelineCompletions = apps.get_app_config("ai").get_model_pipeline( ModelPipelineCompletions ) @@ -585,7 +585,7 @@ def test_validate_error_model_id_exception(self, *args): @override_settings(WCA_SECRET_DUMMY_SECRETS="123:my-model-id") @override_settings(SEGMENT_WRITE_KEY="DUMMY_KEY_VALUE") def test_validate_error_model_id_empty_response(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] mock_wca_client: ModelPipelineCompletions = apps.get_app_config("ai").get_model_pipeline( ModelPipelineCompletions ) diff --git a/ansible_ai_connect/main/tests/test_console_views.py b/ansible_ai_connect/main/tests/test_console_views.py index 9b72fb684..691765417 100644 --- a/ansible_ai_connect/main/tests/test_console_views.py +++ b/ansible_ai_connect/main/tests/test_console_views.py @@ -25,7 +25,7 @@ IsOrganisationAdministrator, IsOrganisationLightspeedSubscriber, ) -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.test_utils import WisdomServiceAPITestCaseBaseOIDC @@ -81,7 +81,7 @@ def test_permission_classes(self, *args): @patch.object(IsOrganisationAdministrator, "has_permission", return_value=True) @patch.object(IsOrganisationLightspeedSubscriber, "has_permission", return_value=True) def test_extra_data(self, *args): - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) response = self.client.get(reverse("console")) self.assertIsInstance(response.context_data, dict) @@ -93,7 +93,7 @@ def test_extra_data(self, *args): @patch.object(feature_flags, "LDClient") def test_extra_data_telemetry_feature(self, LDClient, *args): LDClient.return_value.variation.return_value = True - self.user.organization = Organization.objects.get_or_create(id=123)[0] + self.user.organization = ExternalOrganization.objects.get_or_create(id=123)[0] self.client.force_authenticate(user=self.user) response = self.client.get(reverse("console")) self.assertIsInstance(response.context_data, dict) diff --git a/ansible_ai_connect/main/tests/test_views.py b/ansible_ai_connect/main/tests/test_views.py index 6837cb65e..7741fc767 100644 --- a/ansible_ai_connect/main/tests/test_views.py +++ b/ansible_ai_connect/main/tests/test_views.py @@ -33,7 +33,7 @@ ) from ansible_ai_connect.main.settings.base import SOCIAL_AUTH_OIDC_KEY from ansible_ai_connect.main.views import LoginView -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.test_utils import ( APIVersionTestCaseBase, create_user_with_provider, @@ -365,7 +365,7 @@ def tearDown(self): self.non_rh_test_user.delete() self.test_group.delete() self.non_rh_user_with_subscription.delete() - Organization.objects.filter(id=12345).delete() + ExternalOrganization.objects.filter(id=12345).delete() def test_chatbot_view_with_anonymous_user(self): r = self.client.get(reverse("chatbot")) diff --git a/ansible_ai_connect/organizations/migrations/0001_initial.py b/ansible_ai_connect/organizations/migrations/0001_initial.py index 521ce75a2..91bdef9d5 100644 --- a/ansible_ai_connect/organizations/migrations/0001_initial.py +++ b/ansible_ai_connect/organizations/migrations/0001_initial.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name="Organization", + name="ExternalOrganization", fields=[ ("id", models.IntegerField(primary_key=True, serialize=False)), ("telemetry_opt_out", models.BooleanField(default=False)), diff --git a/ansible_ai_connect/organizations/migrations/0002_user_organization_fix_id.py b/ansible_ai_connect/organizations/migrations/0002_user_organization_fix_id.py index c890d7a90..be56af437 100644 --- a/ansible_ai_connect/organizations/migrations/0002_user_organization_fix_id.py +++ b/ansible_ai_connect/organizations/migrations/0002_user_organization_fix_id.py @@ -8,7 +8,7 @@ class Migration(migrations.Migration): migrations.RunSQL( """ insert into - organizations_organization + organizations_externalorganization select organization_id, false from diff --git a/ansible_ai_connect/organizations/migrations/0003_alter_organization_telemetry_opt_out.py b/ansible_ai_connect/organizations/migrations/0003_alter_organization_telemetry_opt_out.py index 0df90bfc3..31b4a5cf2 100644 --- a/ansible_ai_connect/organizations/migrations/0003_alter_organization_telemetry_opt_out.py +++ b/ansible_ai_connect/organizations/migrations/0003_alter_organization_telemetry_opt_out.py @@ -11,7 +11,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="organization", + model_name="externalorganization", name="telemetry_opt_out", field=models.BooleanField(db_column="telemetry_opt_out", default=False), ), diff --git a/ansible_ai_connect/organizations/migrations/0004_organization_enable_anonymization.py b/ansible_ai_connect/organizations/migrations/0004_organization_enable_anonymization.py index dd63a1b64..2f665bdc1 100644 --- a/ansible_ai_connect/organizations/migrations/0004_organization_enable_anonymization.py +++ b/ansible_ai_connect/organizations/migrations/0004_organization_enable_anonymization.py @@ -11,7 +11,7 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name="organization", + model_name="externalorganization", name="enable_anonymization", field=models.BooleanField(default=True), ), diff --git a/ansible_ai_connect/organizations/migrations/tests/test_0002_user_organization_fix_id.py b/ansible_ai_connect/organizations/migrations/tests/test_0002_user_organization_fix_id.py index 8379c088e..fa3a3eef4 100644 --- a/ansible_ai_connect/organizations/migrations/tests/test_0002_user_organization_fix_id.py +++ b/ansible_ai_connect/organizations/migrations/tests/test_0002_user_organization_fix_id.py @@ -14,7 +14,7 @@ def assert_organization_relationship(self): self.assertIsNotNone(users[0].organization) self.assertEqual(123, users[0].organization.id) - organization_new = self.new_state.apps.get_model("organizations", "Organization") + organization_new = self.new_state.apps.get_model("organizations", "ExternalOrganization") organizations = organization_new.objects.all() self.assertEqual(1, len(organizations)) self.assertTrue(hasattr(users[0], "organization")) diff --git a/ansible_ai_connect/organizations/models.py b/ansible_ai_connect/organizations/models.py index d5e66bdf1..7d575ec05 100644 --- a/ansible_ai_connect/organizations/models.py +++ b/ansible_ai_connect/organizations/models.py @@ -31,7 +31,7 @@ def get_feature_flags(): return FeatureFlags() -class Organization(models.Model): +class ExternalOrganization(models.Model): id = models.IntegerField(primary_key=True) telemetry_opt_out = models.BooleanField(default=False, db_column="telemetry_opt_out") enable_anonymization = models.BooleanField(default=True) diff --git a/ansible_ai_connect/organizations/serializers.py b/ansible_ai_connect/organizations/serializers.py index 83941c8de..afd8f2d59 100644 --- a/ansible_ai_connect/organizations/serializers.py +++ b/ansible_ai_connect/organizations/serializers.py @@ -14,11 +14,11 @@ from rest_framework import serializers -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization class OrganizationSerializer(serializers.ModelSerializer): class Meta: - model = Organization + model = ExternalOrganization fields = ["id", "name", "has_api_key", "has_telemetry_opt_out"] diff --git a/ansible_ai_connect/organizations/tests/test_organizations.py b/ansible_ai_connect/organizations/tests/test_organizations.py index e82ccfdd9..26d31ed97 100644 --- a/ansible_ai_connect/organizations/tests/test_organizations.py +++ b/ansible_ai_connect/organizations/tests/test_organizations.py @@ -16,7 +16,7 @@ from django.test import TestCase, override_settings -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.test_utils import WisdomServiceAPITestCaseBaseOIDC @@ -38,11 +38,11 @@ def check_flag(self, flag=None, query_dict=None): class TestOrganization(TestCase): def test_org_with_telemetry_schema_2_opted_in(self): - organization = Organization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] self.assertFalse(organization.has_telemetry_opt_out) def test_org_with_telemetry_schema_2_opted_out(self): - organization = Organization.objects.get_or_create(id=123, telemetry_opt_out=True)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=True)[0] self.assertTrue(organization.has_telemetry_opt_out) @override_settings(LAUNCHDARKLY_SDK_KEY="dummy_key") @@ -50,7 +50,7 @@ def test_org_with_telemetry_schema_2_opted_out(self): "ansible_ai_connect.organizations.models.get_feature_flags", get_feature_flags_that_say_True ) def test_org_with_telemetry_schema_2_opted_in_with_feature_flag_override(self): - organization = Organization.objects.get_or_create(id=123, telemetry_opt_out=True)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=True)[0] self.assertTrue(organization.has_telemetry_opt_out) @override_settings(LAUNCHDARKLY_SDK_KEY="dummy_key") @@ -59,7 +59,7 @@ def test_org_with_telemetry_schema_2_opted_in_with_feature_flag_override(self): get_feature_flags_that_say_False, ) def test_org_with_telemetry_schema_2_opted_in_with_feature_flag_no_override(self): - organization = Organization.objects.get_or_create(id=123, telemetry_opt_out=True)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=True)[0] self.assertTrue(organization.has_telemetry_opt_out) @override_settings(LAUNCHDARKLY_SDK_KEY="dummy_key") @@ -67,7 +67,7 @@ def test_org_with_telemetry_schema_2_opted_in_with_feature_flag_no_override(self "ansible_ai_connect.organizations.models.get_feature_flags", get_feature_flags_that_say_True ) def test_org_with_telemetry_schema_2_opted_out_with_feature_flag_override(self): - organization = Organization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] self.assertFalse(organization.has_telemetry_opt_out) @override_settings(LAUNCHDARKLY_SDK_KEY="dummy_key") @@ -76,7 +76,7 @@ def test_org_with_telemetry_schema_2_opted_out_with_feature_flag_override(self): get_feature_flags_that_say_False, ) def test_org_with_telemetry_schema_2_opted_out_with_feature_flag_no_override(self): - organization = Organization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] self.assertFalse(organization.has_telemetry_opt_out) @override_settings(LAUNCHDARKLY_SDK_KEY="dummy_key") @@ -84,7 +84,7 @@ def test_org_with_telemetry_schema_2_opted_out_with_feature_flag_no_override(sel "ansible_ai_connect.organizations.models.get_feature_flags", get_feature_flags_that_say_True ) def test_org_with_unlimited_access_allowed_with_feature_flag_override(self): - organization = Organization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] self.assertTrue(organization.is_subscription_check_should_be_bypassed) @override_settings(LAUNCHDARKLY_SDK_KEY="dummy_key") @@ -93,7 +93,7 @@ def test_org_with_unlimited_access_allowed_with_feature_flag_override(self): get_feature_flags_that_say_False, ) def test_org_with_no_unlimited_access_allowed_with_feature_flag_no_override(self): - organization = Organization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] self.assertFalse(organization.is_subscription_check_should_be_bypassed) @@ -101,10 +101,10 @@ def test_org_with_no_unlimited_access_allowed_with_feature_flag_no_override(self class TestOrganizationAPIKey(WisdomServiceAPITestCaseBaseOIDC): @override_settings(WCA_SECRET_DUMMY_SECRETS="1981:valid") def test_org_has_api_key(self): - organization = Organization.objects.get_or_create(id=1981, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=1981, telemetry_opt_out=False)[0] self.assertTrue(organization.has_api_key) @override_settings(WCA_SECRET_DUMMY_SECRETS="") def test_org_does_not_have_api_key(self): - organization = Organization.objects.get_or_create(id=1981, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=1981, telemetry_opt_out=False)[0] self.assertFalse(organization.has_api_key) diff --git a/ansible_ai_connect/test_utils.py b/ansible_ai_connect/test_utils.py index cb3f977ab..1758dc9b4 100644 --- a/ansible_ai_connect/test_utils.py +++ b/ansible_ai_connect/test_utils.py @@ -34,7 +34,7 @@ from ansible_ai_connect.ai.api.utils import segment_analytics_telemetry from ansible_ai_connect.ai.api.utils.version import api_version_reverse -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.users.constants import USER_SOCIAL_AUTH_PROVIDER_OIDC from ansible_ai_connect.users.models import Plan @@ -51,7 +51,7 @@ def create_user( org_opt_out: bool = False, **kwargs, ): - (org, _) = Organization.objects.get_or_create(id=rh_org_id, telemetry_opt_out=org_opt_out) + (org, _) = ExternalOrganization.objects.get_or_create(id=rh_org_id, telemetry_opt_out=org_opt_out) kwargs.setdefault("username", "u" + "".join(random.choices(string.digits, k=5))) kwargs.setdefault("password", "secret") kwargs.setdefault("email", kwargs["username"] + "@example.com") @@ -232,7 +232,7 @@ def setUp(self): cache.clear() def tearDown(self): - Organization.objects.filter(id=1).delete() + ExternalOrganization.objects.filter(id=1).delete() self.user.delete() super().tearDown() diff --git a/ansible_ai_connect/users/management/commands/createtoken.py b/ansible_ai_connect/users/management/commands/createtoken.py index c66c44e10..579e611f4 100644 --- a/ansible_ai_connect/users/management/commands/createtoken.py +++ b/ansible_ai_connect/users/management/commands/createtoken.py @@ -23,7 +23,7 @@ from oauth2_provider.models import AccessToken from oauthlib.common import generate_token -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization class Command(BaseCommand): @@ -78,7 +78,7 @@ def handle( commercial_terms_accepted=n, ) if organization_id: - u.organization = Organization.objects.get_or_create(id=organization_id)[0] + u.organization = ExternalOrganization.objects.get_or_create(id=organization_id)[0] u.save() else: raise CommandError(f"Cannot find user {username}") diff --git a/ansible_ai_connect/users/management/commands/tests/test_createtoken.py b/ansible_ai_connect/users/management/commands/tests/test_createtoken.py index 40dbef7c0..4baa8acc5 100644 --- a/ansible_ai_connect/users/management/commands/tests/test_createtoken.py +++ b/ansible_ai_connect/users/management/commands/tests/test_createtoken.py @@ -22,7 +22,7 @@ from django.test import TestCase from oauth2_provider.models import AccessToken -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization class TestCreateToken(TestCase): @@ -30,7 +30,7 @@ def tearDown(self): User = get_user_model() AccessToken.objects.filter(token="test-token").delete() User.objects.filter(username="my-test-token-user").delete() - Organization.objects.filter(id=12345).delete() + ExternalOrganization.objects.filter(id=12345).delete() def call_command(self, *args, **kwargs): out = StringIO() diff --git a/ansible_ai_connect/users/migrations/0009_user_organization.py b/ansible_ai_connect/users/migrations/0009_user_organization.py index aa96f48cd..07c95a382 100644 --- a/ansible_ai_connect/users/migrations/0009_user_organization.py +++ b/ansible_ai_connect/users/migrations/0009_user_organization.py @@ -20,7 +20,7 @@ class Migration(migrations.Migration): default=None, null=True, on_delete=django.db.models.deletion.CASCADE, - to="organizations.organization", + to="organizations.externalorganization", ), ), ] diff --git a/ansible_ai_connect/users/models.py b/ansible_ai_connect/users/models.py index d7040a045..13ba9089f 100644 --- a/ansible_ai_connect/users/models.py +++ b/ansible_ai_connect/users/models.py @@ -26,7 +26,7 @@ from django_deprecate_fields import deprecate_field from django_prometheus.models import ExportModelOperationsMixin -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from .constants import USER_SOCIAL_AUTH_PROVIDER_AAP, USER_SOCIAL_AUTH_PROVIDER_OIDC @@ -57,7 +57,7 @@ class User(ExportModelOperationsMixin("user"), AbstractUser): commercial_terms_accepted = models.DateTimeField(default=None, null=True) organization_id = deprecate_field(models.IntegerField(default=None, null=True)) organization = NonClashingForeignKey( - Organization, + ExternalOrganization, default=None, null=True, on_delete=models.CASCADE, diff --git a/ansible_ai_connect/users/pipeline.py b/ansible_ai_connect/users/pipeline.py index bc5505b32..a47b69db0 100644 --- a/ansible_ai_connect/users/pipeline.py +++ b/ansible_ai_connect/users/pipeline.py @@ -22,7 +22,7 @@ from social_django.models import UserSocialAuth from ansible_ai_connect.ai.api.utils.segment import send_segment_group -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.users.constants import RHSSO_LIGHTSPEED_SCOPE logger = logging.getLogger(__name__) @@ -126,7 +126,7 @@ def redhat_organization(backend, user, response, *args, **kwargs): else: logger.error("AUTHZ_DUMMY_RH_ORG_ADMINS has an invalid format.") - user.organization = Organization.objects.get_or_create(id=int(payload["organization"]["id"]))[0] + user.organization = ExternalOrganization.objects.get_or_create(id=int(payload["organization"]["id"]))[0] user.save() send_segment_group( f"rhsso-{user.organization.id}", "Red Hat Organization", user.organization.id, user diff --git a/ansible_ai_connect/users/tests/test_users.py b/ansible_ai_connect/users/tests/test_users.py index becdcdd29..484af55ba 100644 --- a/ansible_ai_connect/users/tests/test_users.py +++ b/ansible_ai_connect/users/tests/test_users.py @@ -30,7 +30,7 @@ IsOrganisationAdministrator, IsOrganisationLightspeedSubscriber, ) -from ansible_ai_connect.organizations.models import Organization +from ansible_ai_connect.organizations.models import ExternalOrganization from ansible_ai_connect.test_utils import ( APIVersionTestCaseBase, WisdomAppsBackendMocking, @@ -119,7 +119,7 @@ def test_rh_user_has_seat_with_no_seat_checker(self): @override_settings(DEPLOYMENT_MODE="saas") def test_rh_user_in_unlimited_org(self): user = create_user(provider=USER_SOCIAL_AUTH_PROVIDER_OIDC) - org = Organization(None, None) + org = ExternalOrganization(None, None) org.is_subscription_check_should_be_bypassed = True user.organization = org self.assertTrue(user.rh_org_has_subscription) From 79715e4ecca5c14e43fddb6c963bd6e143a848f8 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Mon, 22 Sep 2025 13:11:54 -0400 Subject: [PATCH 02/12] Fix other case --- ansible_ai_connect/ai/api/wca/api_key_views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ansible_ai_connect/ai/api/wca/api_key_views.py b/ansible_ai_connect/ai/api/wca/api_key_views.py index 028872a7e..2ae1f7a23 100644 --- a/ansible_ai_connect/ai/api/wca/api_key_views.py +++ b/ansible_ai_connect/ai/api/wca/api_key_views.py @@ -138,7 +138,7 @@ def post(self, request, *args, **kwargs): # See https://issues.redhat.com/browse/AAP-16009 if not request._request.user.organization: return Response(status=HTTP_400_BAD_REQUEST) - organization: Organization = request._request.user.organization + organization: ExternalOrganization = request._request.user.organization try: # Extract API Key from request @@ -293,7 +293,7 @@ def get(self, request, *args, **kwargs): # See https://issues.redhat.com/browse/AAP-16009 if not request._request.user.organization: return Response(status=HTTP_400_BAD_REQUEST) - organization: Organization = request._request.user.organization + organization: ExternalOrganization = request._request.user.organization try: # Validate API Key _md = apps.get_app_config("ai").get_model_pipeline(MetaData) From 5e678730c012a9ed1d9fa83fe8ba4cf8f90f078b Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Mon, 22 Sep 2025 13:36:35 -0400 Subject: [PATCH 03/12] Remove team relationshisp and add new AAP organization --- .../migrations/0005_organization.py | 32 +++++++++++++++++++ ansible_ai_connect/organizations/models.py | 10 ++++++ .../0017_alter_user_options_team.py | 24 -------------- ansible_ai_connect/users/models.py | 13 -------- 4 files changed, 42 insertions(+), 37 deletions(-) create mode 100644 ansible_ai_connect/organizations/migrations/0005_organization.py diff --git a/ansible_ai_connect/organizations/migrations/0005_organization.py b/ansible_ai_connect/organizations/migrations/0005_organization.py new file mode 100644 index 000000000..5453c1d63 --- /dev/null +++ b/ansible_ai_connect/organizations/migrations/0005_organization.py @@ -0,0 +1,32 @@ +# Generated manually to create new Organization model + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("organizations", "0004_organization_enable_anonymization"), + ] + + operations = [ + migrations.CreateModel( + name="Organization", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ("name", models.CharField(help_text="The name of this organization.", max_length=512)), + ( + "description", + models.TextField(blank=True, default="", help_text="The organization description."), + ), + ], + options={ + "ordering": ["id"], + }, + ), + ] \ No newline at end of file diff --git a/ansible_ai_connect/organizations/models.py b/ansible_ai_connect/organizations/models.py index 7d575ec05..d31367b9e 100644 --- a/ansible_ai_connect/organizations/models.py +++ b/ansible_ai_connect/organizations/models.py @@ -78,3 +78,13 @@ def __make_organization_request_to_launchdarkly(self, flag: str) -> bool: flag, {"kind": "organization", "key": str(self.id)}, ) + + +class Organization(models.Model): + id = models.BigAutoField(primary_key=True) + name = models.CharField(max_length=512, help_text="The name of this organization.") + description = models.TextField(blank=True, default="", help_text="The organization description.") + + class Meta: + app_label = "organizations" + ordering = ["id"] diff --git a/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py b/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py index 579526204..32f7b74f5 100644 --- a/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py +++ b/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py @@ -45,15 +45,6 @@ class Migration(migrations.Migration): "description", models.TextField(blank=True, default="", help_text="The team description."), ), - ( - "admins", - models.ManyToManyField( - blank=True, - help_text="The list of admins for this team", - related_name="teams_administered", - to=settings.AUTH_USER_MODEL, - ), - ), ( "created_by", models.ForeignKey( @@ -87,21 +78,6 @@ class Migration(migrations.Migration): to="organizations.organization", ), ), - ( - "team_parents", - models.ManyToManyField( - blank=True, related_name="team_children", to="users.team" - ), - ), - ( - "users", - models.ManyToManyField( - blank=True, - help_text="The list of users on this team", - related_name="teams", - to=settings.AUTH_USER_MODEL, - ), - ), ], options={ "ordering": ["id"], diff --git a/ansible_ai_connect/users/models.py b/ansible_ai_connect/users/models.py index 13ba9089f..40189e9a4 100644 --- a/ansible_ai_connect/users/models.py +++ b/ansible_ai_connect/users/models.py @@ -182,7 +182,6 @@ class Team(AbstractTeam): """A Team compatible with Django Ansible Base Teams""" resource = AnsibleResourceField(primary_key_field="id") - team_parents = models.ManyToManyField("Team", related_name="team_children", blank=True) ignore_relations = [] @@ -191,16 +190,4 @@ class Meta: ordering = ["id"] abstract = False - users = models.ManyToManyField( - User, - related_name="teams", - blank=True, - help_text="The list of users on this team", - ) - admins = models.ManyToManyField( - User, - related_name="teams_administered", - blank=True, - help_text="The list of admins for this team", - ) From 2ddf2ee2b0ec572fbacd86adee771d9a87990aff Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Mon, 22 Sep 2025 09:30:59 -0400 Subject: [PATCH 04/12] Remove loading of RBAC application and prevent the JWT consumer from trying to process RBAC permissions --- ansible_ai_connect/main/settings/base.py | 1 - ansible_ai_connect/users/authentication.py | 4 ++++ .../users/migrations/0017_alter_user_options_team.py | 2 -- requirements.in | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ansible_ai_connect/main/settings/base.py b/ansible_ai_connect/main/settings/base.py index af2ca681a..db840c6fb 100644 --- a/ansible_ai_connect/main/settings/base.py +++ b/ansible_ai_connect/main/settings/base.py @@ -77,7 +77,6 @@ "ansible_ai_connect.healthcheck", "oauth2_provider", "import_export", - "ansible_base.rbac", "ansible_base.resource_registry", "ansible_base.jwt_consumer", ] diff --git a/ansible_ai_connect/users/authentication.py b/ansible_ai_connect/users/authentication.py index e73b32022..c2ad73499 100644 --- a/ansible_ai_connect/users/authentication.py +++ b/ansible_ai_connect/users/authentication.py @@ -10,3 +10,7 @@ def authenticate(self, request): user.aap_user = True user.save() return userdata + + def process_permissions(self): + # Prevent processing of RBAC permissions + pass diff --git a/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py b/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py index 32f7b74f5..922eda903 100644 --- a/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py +++ b/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py @@ -12,8 +12,6 @@ class Migration(migrations.Migration): ("users", "0016_user_aap_user"), ] - run_before = [("dab_rbac", "__first__")] - operations = [ migrations.AlterModelOptions( name="user", diff --git a/requirements.in b/requirements.in index c9f83abbc..55e04550d 100644 --- a/requirements.in +++ b/requirements.in @@ -71,4 +71,4 @@ uwsgi==2.0.22 uwsgi-readiness-check==0.2.0 django-allow-cidr==0.6.0 django-csp==3.7 -django-ansible-base[jwt-consumer,resource-registry]==2025.8.18 +django-ansible-base[jwt-consumer,resource-registry]==2025.9.22 From fd7d793f901e04debbd03e513aa77af863d47c7c Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Tue, 23 Sep 2025 12:20:14 -0400 Subject: [PATCH 05/12] Revert migration changes, reforat migration stages --- .../0006_alter_externalorganization_table.py | 17 ++++++++++++ ansible_ai_connect/organizations/models.py | 3 +++ .../migrations/0009_user_organization.py | 2 +- .../0017_alter_user_options_team.py | 26 +++++++++++++++++++ .../0018_remove_team_relationships.py | 25 ++++++++++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 ansible_ai_connect/organizations/migrations/0006_alter_externalorganization_table.py create mode 100644 ansible_ai_connect/users/migrations/0018_remove_team_relationships.py diff --git a/ansible_ai_connect/organizations/migrations/0006_alter_externalorganization_table.py b/ansible_ai_connect/organizations/migrations/0006_alter_externalorganization_table.py new file mode 100644 index 000000000..5ec0956fe --- /dev/null +++ b/ansible_ai_connect/organizations/migrations/0006_alter_externalorganization_table.py @@ -0,0 +1,17 @@ +# Generated manually to rename ExternalOrganization table to organizations_organization + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("organizations", "0005_organization"), + ] + + operations = [ + migrations.AlterModelTable( + name="externalorganization", + table="organizations_organization", + ), + ] \ No newline at end of file diff --git a/ansible_ai_connect/organizations/models.py b/ansible_ai_connect/organizations/models.py index d31367b9e..acce4a023 100644 --- a/ansible_ai_connect/organizations/models.py +++ b/ansible_ai_connect/organizations/models.py @@ -36,6 +36,9 @@ class ExternalOrganization(models.Model): telemetry_opt_out = models.BooleanField(default=False, db_column="telemetry_opt_out") enable_anonymization = models.BooleanField(default=True) + class Meta: + db_table = "organizations_organization" + @property # NOTE: The info dict is already cache in the seat_checker def name(self): seat_checker = apps.get_app_config("ai").get_seat_checker() diff --git a/ansible_ai_connect/users/migrations/0009_user_organization.py b/ansible_ai_connect/users/migrations/0009_user_organization.py index 07c95a382..aa96f48cd 100644 --- a/ansible_ai_connect/users/migrations/0009_user_organization.py +++ b/ansible_ai_connect/users/migrations/0009_user_organization.py @@ -20,7 +20,7 @@ class Migration(migrations.Migration): default=None, null=True, on_delete=django.db.models.deletion.CASCADE, - to="organizations.externalorganization", + to="organizations.organization", ), ), ] diff --git a/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py b/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py index 922eda903..579526204 100644 --- a/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py +++ b/ansible_ai_connect/users/migrations/0017_alter_user_options_team.py @@ -12,6 +12,8 @@ class Migration(migrations.Migration): ("users", "0016_user_aap_user"), ] + run_before = [("dab_rbac", "__first__")] + operations = [ migrations.AlterModelOptions( name="user", @@ -43,6 +45,15 @@ class Migration(migrations.Migration): "description", models.TextField(blank=True, default="", help_text="The team description."), ), + ( + "admins", + models.ManyToManyField( + blank=True, + help_text="The list of admins for this team", + related_name="teams_administered", + to=settings.AUTH_USER_MODEL, + ), + ), ( "created_by", models.ForeignKey( @@ -76,6 +87,21 @@ class Migration(migrations.Migration): to="organizations.organization", ), ), + ( + "team_parents", + models.ManyToManyField( + blank=True, related_name="team_children", to="users.team" + ), + ), + ( + "users", + models.ManyToManyField( + blank=True, + help_text="The list of users on this team", + related_name="teams", + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ "ordering": ["id"], diff --git a/ansible_ai_connect/users/migrations/0018_remove_team_relationships.py b/ansible_ai_connect/users/migrations/0018_remove_team_relationships.py new file mode 100644 index 000000000..3d7d82a11 --- /dev/null +++ b/ansible_ai_connect/users/migrations/0018_remove_team_relationships.py @@ -0,0 +1,25 @@ +# Generated by Django makemigrations after removing Team.admins, Team.users, and Team.team_parents + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("users", "0017_alter_user_options_team"), + ] + + operations = [ + migrations.RemoveField( + model_name="team", + name="admins", + ), + migrations.RemoveField( + model_name="team", + name="team_parents", + ), + migrations.RemoveField( + model_name="team", + name="users", + ), + ] \ No newline at end of file From 5c16bae281a329451cdf2fc5f2f585975724ab47 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Tue, 23 Sep 2025 13:13:42 -0400 Subject: [PATCH 06/12] Clear RBAC data in intermediate step --- ansible_ai_connect/main/settings/base.py | 1 + .../migrations/0005_organization.py | 29 ++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/ansible_ai_connect/main/settings/base.py b/ansible_ai_connect/main/settings/base.py index db840c6fb..79b0bda27 100644 --- a/ansible_ai_connect/main/settings/base.py +++ b/ansible_ai_connect/main/settings/base.py @@ -79,6 +79,7 @@ "import_export", "ansible_base.resource_registry", "ansible_base.jwt_consumer", + "ansible_base.rbac", ] MIDDLEWARE = [ diff --git a/ansible_ai_connect/organizations/migrations/0005_organization.py b/ansible_ai_connect/organizations/migrations/0005_organization.py index 5453c1d63..db393095b 100644 --- a/ansible_ai_connect/organizations/migrations/0005_organization.py +++ b/ansible_ai_connect/organizations/migrations/0005_organization.py @@ -1,12 +1,35 @@ -# Generated manually to create new Organization model +# Generated manually to create new Organization model and clear dab_rbac data from django.db import migrations, models +def clear_dab_rbac_data(apps, schema_editor): + """Delete all entries from dab_rbac models""" + db_alias = schema_editor.connection.alias + + # Get all dab_rbac models + from django.apps import apps as django_apps + dab_rbac_config = django_apps.get_app_config('dab_rbac') + + # Delete all data from dab_rbac models in reverse dependency order + for model in reversed(dab_rbac_config.get_models()): + model.objects.using(db_alias).all().delete() + + +def reverse_clear_dab_rbac_data(apps, schema_editor): + """Reverse operation - no-op since we can't restore deleted data""" + pass + + class Migration(migrations.Migration): dependencies = [ ("organizations", "0004_organization_enable_anonymization"), + ("dab_rbac", "0004_remote_permissions_additions"), + ] + + run_before = [ + ("dab_rbac", "0005_remote_permissions_data"), ] operations = [ @@ -29,4 +52,8 @@ class Migration(migrations.Migration): "ordering": ["id"], }, ), + migrations.RunPython( + clear_dab_rbac_data, + reverse_clear_dab_rbac_data, + ), ] \ No newline at end of file From 88cb4bb3dcefd3a03371d7969e707fd6b513e938 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Tue, 23 Sep 2025 13:44:03 -0400 Subject: [PATCH 07/12] Set names back to intended --- .../organizations/migrations/0001_initial.py | 3 ++- .../migrations/0002_user_organization_fix_id.py | 2 +- ...0003_alter_organization_telemetry_opt_out.py | 2 +- .../0004_organization_enable_anonymization.py | 2 +- ...name_organization_to_externalorganization.py | 17 +++++++++++++++++ .../0006_alter_externalorganization_table.py | 17 ----------------- ...005_organization.py => 0006_organization.py} | 2 +- ansible_ai_connect/organizations/models.py | 3 --- 8 files changed, 23 insertions(+), 25 deletions(-) create mode 100644 ansible_ai_connect/organizations/migrations/0005_rename_organization_to_externalorganization.py delete mode 100644 ansible_ai_connect/organizations/migrations/0006_alter_externalorganization_table.py rename ansible_ai_connect/organizations/migrations/{0005_organization.py => 0006_organization.py} (95%) diff --git a/ansible_ai_connect/organizations/migrations/0001_initial.py b/ansible_ai_connect/organizations/migrations/0001_initial.py index 91bdef9d5..ffd363b81 100644 --- a/ansible_ai_connect/organizations/migrations/0001_initial.py +++ b/ansible_ai_connect/organizations/migrations/0001_initial.py @@ -1,4 +1,5 @@ # Generated by Django 4.2.3 on 2023-11-29 09:16 +# Modified to show rename of original Organization model to ExternalOrganization from django.db import migrations, models @@ -10,7 +11,7 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name="ExternalOrganization", + name="Organization", fields=[ ("id", models.IntegerField(primary_key=True, serialize=False)), ("telemetry_opt_out", models.BooleanField(default=False)), diff --git a/ansible_ai_connect/organizations/migrations/0002_user_organization_fix_id.py b/ansible_ai_connect/organizations/migrations/0002_user_organization_fix_id.py index be56af437..c890d7a90 100644 --- a/ansible_ai_connect/organizations/migrations/0002_user_organization_fix_id.py +++ b/ansible_ai_connect/organizations/migrations/0002_user_organization_fix_id.py @@ -8,7 +8,7 @@ class Migration(migrations.Migration): migrations.RunSQL( """ insert into - organizations_externalorganization + organizations_organization select organization_id, false from diff --git a/ansible_ai_connect/organizations/migrations/0003_alter_organization_telemetry_opt_out.py b/ansible_ai_connect/organizations/migrations/0003_alter_organization_telemetry_opt_out.py index 31b4a5cf2..0df90bfc3 100644 --- a/ansible_ai_connect/organizations/migrations/0003_alter_organization_telemetry_opt_out.py +++ b/ansible_ai_connect/organizations/migrations/0003_alter_organization_telemetry_opt_out.py @@ -11,7 +11,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="externalorganization", + model_name="organization", name="telemetry_opt_out", field=models.BooleanField(db_column="telemetry_opt_out", default=False), ), diff --git a/ansible_ai_connect/organizations/migrations/0004_organization_enable_anonymization.py b/ansible_ai_connect/organizations/migrations/0004_organization_enable_anonymization.py index 2f665bdc1..dd63a1b64 100644 --- a/ansible_ai_connect/organizations/migrations/0004_organization_enable_anonymization.py +++ b/ansible_ai_connect/organizations/migrations/0004_organization_enable_anonymization.py @@ -11,7 +11,7 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name="externalorganization", + model_name="organization", name="enable_anonymization", field=models.BooleanField(default=True), ), diff --git a/ansible_ai_connect/organizations/migrations/0005_rename_organization_to_externalorganization.py b/ansible_ai_connect/organizations/migrations/0005_rename_organization_to_externalorganization.py new file mode 100644 index 000000000..f9ac3ce9b --- /dev/null +++ b/ansible_ai_connect/organizations/migrations/0005_rename_organization_to_externalorganization.py @@ -0,0 +1,17 @@ +# Generated migration to rename Organization model to ExternalOrganization + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("organizations", "0004_organization_enable_anonymization"), + ] + + operations = [ + migrations.RenameModel( + old_name="Organization", + new_name="ExternalOrganization", + ), + ] \ No newline at end of file diff --git a/ansible_ai_connect/organizations/migrations/0006_alter_externalorganization_table.py b/ansible_ai_connect/organizations/migrations/0006_alter_externalorganization_table.py deleted file mode 100644 index 5ec0956fe..000000000 --- a/ansible_ai_connect/organizations/migrations/0006_alter_externalorganization_table.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated manually to rename ExternalOrganization table to organizations_organization - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("organizations", "0005_organization"), - ] - - operations = [ - migrations.AlterModelTable( - name="externalorganization", - table="organizations_organization", - ), - ] \ No newline at end of file diff --git a/ansible_ai_connect/organizations/migrations/0005_organization.py b/ansible_ai_connect/organizations/migrations/0006_organization.py similarity index 95% rename from ansible_ai_connect/organizations/migrations/0005_organization.py rename to ansible_ai_connect/organizations/migrations/0006_organization.py index db393095b..82907ad63 100644 --- a/ansible_ai_connect/organizations/migrations/0005_organization.py +++ b/ansible_ai_connect/organizations/migrations/0006_organization.py @@ -24,7 +24,7 @@ def reverse_clear_dab_rbac_data(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ("organizations", "0004_organization_enable_anonymization"), + ("organizations", "0005_rename_organization_to_externalorganization"), ("dab_rbac", "0004_remote_permissions_additions"), ] diff --git a/ansible_ai_connect/organizations/models.py b/ansible_ai_connect/organizations/models.py index acce4a023..d31367b9e 100644 --- a/ansible_ai_connect/organizations/models.py +++ b/ansible_ai_connect/organizations/models.py @@ -36,9 +36,6 @@ class ExternalOrganization(models.Model): telemetry_opt_out = models.BooleanField(default=False, db_column="telemetry_opt_out") enable_anonymization = models.BooleanField(default=True) - class Meta: - db_table = "organizations_organization" - @property # NOTE: The info dict is already cache in the seat_checker def name(self): seat_checker = apps.get_app_config("ai").get_seat_checker() From d09ee891657066f7669384f915244903ba541859 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Wed, 24 Sep 2025 10:16:12 -0400 Subject: [PATCH 08/12] Run linters --- .../test_api_telemetry_settings_views.py | 6 ++-- .../api/utils/segment_analytics_telemetry.py | 2 +- .../ai/api/wca/model_id_views.py | 2 +- .../main/tests/test_ssl_manager.py | 2 +- ...me_organization_to_externalorganization.py | 2 +- .../migrations/0006_organization.py | 14 +++++++--- ansible_ai_connect/organizations/models.py | 4 ++- .../organizations/tests/test_organizations.py | 28 ++++++++++++++----- ansible_ai_connect/test_utils.py | 4 ++- .../users/management/commands/createtoken.py | 4 ++- .../0018_remove_team_relationships.py | 2 +- ansible_ai_connect/users/models.py | 2 -- ansible_ai_connect/users/pipeline.py | 4 ++- 13 files changed, 51 insertions(+), 25 deletions(-) diff --git a/ansible_ai_connect/ai/api/telemetry/tests/test_api_telemetry_settings_views.py b/ansible_ai_connect/ai/api/telemetry/tests/test_api_telemetry_settings_views.py index 49f79c08b..9ab65697a 100644 --- a/ansible_ai_connect/ai/api/telemetry/tests/test_api_telemetry_settings_views.py +++ b/ansible_ai_connect/ai/api/telemetry/tests/test_api_telemetry_settings_views.py @@ -85,9 +85,9 @@ def test_get_settings_when_undefined(self, LDClient, *args): @patch.object(feature_flags, "LDClient") def test_get_settings_when_defined(self, LDClient, *args): LDClient.return_value.variation.return_value = True - self.user.organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=True)[ - 0 - ] + self.user.organization = ExternalOrganization.objects.get_or_create( + id=123, telemetry_opt_out=True + )[0] self.client.force_authenticate(user=self.user) with self.assertLogs(logger="root", level="DEBUG") as log: diff --git a/ansible_ai_connect/ai/api/utils/segment_analytics_telemetry.py b/ansible_ai_connect/ai/api/utils/segment_analytics_telemetry.py index 58672d2cf..56af7c03d 100644 --- a/ansible_ai_connect/ai/api/utils/segment_analytics_telemetry.py +++ b/ansible_ai_connect/ai/api/utils/segment_analytics_telemetry.py @@ -73,7 +73,7 @@ def send_segment_analytics_event( ) return - organization: Organization = user.organization + organization: ExternalOrganization = user.organization if not organization: logger.info("Analytics telemetry not active, because of no organization assigned for user.") return diff --git a/ansible_ai_connect/ai/api/wca/model_id_views.py b/ansible_ai_connect/ai/api/wca/model_id_views.py index 9b4d3d676..b48a7c1fa 100644 --- a/ansible_ai_connect/ai/api/wca/model_id_views.py +++ b/ansible_ai_connect/ai/api/wca/model_id_views.py @@ -246,7 +246,7 @@ def do_validated_operation(request, api_key_provider, model_id_provider, on_succ # See https://issues.redhat.com/browse/AAP-16009 if not request._request.user.organization: return Response(status=HTTP_400_BAD_REQUEST) - organization: Organization = request._request.user.organization + organization: ExternalOrganization = request._request.user.organization try: api_key = api_key_provider(organization.id) model_id = model_id_provider(organization.id) diff --git a/ansible_ai_connect/main/tests/test_ssl_manager.py b/ansible_ai_connect/main/tests/test_ssl_manager.py index 14bb6936d..b96a794bc 100644 --- a/ansible_ai_connect/main/tests/test_ssl_manager.py +++ b/ansible_ai_connect/main/tests/test_ssl_manager.py @@ -876,7 +876,7 @@ def test_corrupted_ca_bundle_file(self): """Test SSL manager with corrupted CA bundle file.""" # Create corrupted CA bundle with tempfile.NamedTemporaryFile(mode="w", suffix=".pem", delete=False) as temp_file: - temp_file.write("CORRUPTED CERTIFICATE DATA\x00\xFF\x00") + temp_file.write("CORRUPTED CERTIFICATE DATA\x00\xff\x00") temp_file_path = temp_file.name try: diff --git a/ansible_ai_connect/organizations/migrations/0005_rename_organization_to_externalorganization.py b/ansible_ai_connect/organizations/migrations/0005_rename_organization_to_externalorganization.py index f9ac3ce9b..bd23ddd7e 100644 --- a/ansible_ai_connect/organizations/migrations/0005_rename_organization_to_externalorganization.py +++ b/ansible_ai_connect/organizations/migrations/0005_rename_organization_to_externalorganization.py @@ -14,4 +14,4 @@ class Migration(migrations.Migration): old_name="Organization", new_name="ExternalOrganization", ), - ] \ No newline at end of file + ] diff --git a/ansible_ai_connect/organizations/migrations/0006_organization.py b/ansible_ai_connect/organizations/migrations/0006_organization.py index 82907ad63..52bdd67f1 100644 --- a/ansible_ai_connect/organizations/migrations/0006_organization.py +++ b/ansible_ai_connect/organizations/migrations/0006_organization.py @@ -9,7 +9,8 @@ def clear_dab_rbac_data(apps, schema_editor): # Get all dab_rbac models from django.apps import apps as django_apps - dab_rbac_config = django_apps.get_app_config('dab_rbac') + + dab_rbac_config = django_apps.get_app_config("dab_rbac") # Delete all data from dab_rbac models in reverse dependency order for model in reversed(dab_rbac_config.get_models()): @@ -42,10 +43,15 @@ class Migration(migrations.Migration): auto_created=True, primary_key=True, serialize=False, verbose_name="ID" ), ), - ("name", models.CharField(help_text="The name of this organization.", max_length=512)), + ( + "name", + models.CharField(help_text="The name of this organization.", max_length=512), + ), ( "description", - models.TextField(blank=True, default="", help_text="The organization description."), + models.TextField( + blank=True, default="", help_text="The organization description." + ), ), ], options={ @@ -56,4 +62,4 @@ class Migration(migrations.Migration): clear_dab_rbac_data, reverse_clear_dab_rbac_data, ), - ] \ No newline at end of file + ] diff --git a/ansible_ai_connect/organizations/models.py b/ansible_ai_connect/organizations/models.py index d31367b9e..3a4c6b04a 100644 --- a/ansible_ai_connect/organizations/models.py +++ b/ansible_ai_connect/organizations/models.py @@ -83,7 +83,9 @@ def __make_organization_request_to_launchdarkly(self, flag: str) -> bool: class Organization(models.Model): id = models.BigAutoField(primary_key=True) name = models.CharField(max_length=512, help_text="The name of this organization.") - description = models.TextField(blank=True, default="", help_text="The organization description.") + description = models.TextField( + blank=True, default="", help_text="The organization description." + ) class Meta: app_label = "organizations" diff --git a/ansible_ai_connect/organizations/tests/test_organizations.py b/ansible_ai_connect/organizations/tests/test_organizations.py index 26d31ed97..070877686 100644 --- a/ansible_ai_connect/organizations/tests/test_organizations.py +++ b/ansible_ai_connect/organizations/tests/test_organizations.py @@ -38,7 +38,9 @@ def check_flag(self, flag=None, query_dict=None): class TestOrganization(TestCase): def test_org_with_telemetry_schema_2_opted_in(self): - organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[ + 0 + ] self.assertFalse(organization.has_telemetry_opt_out) def test_org_with_telemetry_schema_2_opted_out(self): @@ -67,7 +69,9 @@ def test_org_with_telemetry_schema_2_opted_in_with_feature_flag_no_override(self "ansible_ai_connect.organizations.models.get_feature_flags", get_feature_flags_that_say_True ) def test_org_with_telemetry_schema_2_opted_out_with_feature_flag_override(self): - organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[ + 0 + ] self.assertFalse(organization.has_telemetry_opt_out) @override_settings(LAUNCHDARKLY_SDK_KEY="dummy_key") @@ -76,7 +80,9 @@ def test_org_with_telemetry_schema_2_opted_out_with_feature_flag_override(self): get_feature_flags_that_say_False, ) def test_org_with_telemetry_schema_2_opted_out_with_feature_flag_no_override(self): - organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[ + 0 + ] self.assertFalse(organization.has_telemetry_opt_out) @override_settings(LAUNCHDARKLY_SDK_KEY="dummy_key") @@ -84,7 +90,9 @@ def test_org_with_telemetry_schema_2_opted_out_with_feature_flag_no_override(sel "ansible_ai_connect.organizations.models.get_feature_flags", get_feature_flags_that_say_True ) def test_org_with_unlimited_access_allowed_with_feature_flag_override(self): - organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[ + 0 + ] self.assertTrue(organization.is_subscription_check_should_be_bypassed) @override_settings(LAUNCHDARKLY_SDK_KEY="dummy_key") @@ -93,7 +101,9 @@ def test_org_with_unlimited_access_allowed_with_feature_flag_override(self): get_feature_flags_that_say_False, ) def test_org_with_no_unlimited_access_allowed_with_feature_flag_no_override(self): - organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=123, telemetry_opt_out=False)[ + 0 + ] self.assertFalse(organization.is_subscription_check_should_be_bypassed) @@ -101,10 +111,14 @@ def test_org_with_no_unlimited_access_allowed_with_feature_flag_no_override(self class TestOrganizationAPIKey(WisdomServiceAPITestCaseBaseOIDC): @override_settings(WCA_SECRET_DUMMY_SECRETS="1981:valid") def test_org_has_api_key(self): - organization = ExternalOrganization.objects.get_or_create(id=1981, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=1981, telemetry_opt_out=False)[ + 0 + ] self.assertTrue(organization.has_api_key) @override_settings(WCA_SECRET_DUMMY_SECRETS="") def test_org_does_not_have_api_key(self): - organization = ExternalOrganization.objects.get_or_create(id=1981, telemetry_opt_out=False)[0] + organization = ExternalOrganization.objects.get_or_create(id=1981, telemetry_opt_out=False)[ + 0 + ] self.assertFalse(organization.has_api_key) diff --git a/ansible_ai_connect/test_utils.py b/ansible_ai_connect/test_utils.py index 1758dc9b4..75f964cf2 100644 --- a/ansible_ai_connect/test_utils.py +++ b/ansible_ai_connect/test_utils.py @@ -51,7 +51,9 @@ def create_user( org_opt_out: bool = False, **kwargs, ): - (org, _) = ExternalOrganization.objects.get_or_create(id=rh_org_id, telemetry_opt_out=org_opt_out) + (org, _) = ExternalOrganization.objects.get_or_create( + id=rh_org_id, telemetry_opt_out=org_opt_out + ) kwargs.setdefault("username", "u" + "".join(random.choices(string.digits, k=5))) kwargs.setdefault("password", "secret") kwargs.setdefault("email", kwargs["username"] + "@example.com") diff --git a/ansible_ai_connect/users/management/commands/createtoken.py b/ansible_ai_connect/users/management/commands/createtoken.py index 579e611f4..051e1fbce 100644 --- a/ansible_ai_connect/users/management/commands/createtoken.py +++ b/ansible_ai_connect/users/management/commands/createtoken.py @@ -78,7 +78,9 @@ def handle( commercial_terms_accepted=n, ) if organization_id: - u.organization = ExternalOrganization.objects.get_or_create(id=organization_id)[0] + u.organization = ExternalOrganization.objects.get_or_create(id=organization_id)[ + 0 + ] u.save() else: raise CommandError(f"Cannot find user {username}") diff --git a/ansible_ai_connect/users/migrations/0018_remove_team_relationships.py b/ansible_ai_connect/users/migrations/0018_remove_team_relationships.py index 3d7d82a11..7274be2da 100644 --- a/ansible_ai_connect/users/migrations/0018_remove_team_relationships.py +++ b/ansible_ai_connect/users/migrations/0018_remove_team_relationships.py @@ -22,4 +22,4 @@ class Migration(migrations.Migration): model_name="team", name="users", ), - ] \ No newline at end of file + ] diff --git a/ansible_ai_connect/users/models.py b/ansible_ai_connect/users/models.py index 40189e9a4..6e82aa913 100644 --- a/ansible_ai_connect/users/models.py +++ b/ansible_ai_connect/users/models.py @@ -189,5 +189,3 @@ class Meta: app_label = "users" ordering = ["id"] abstract = False - - diff --git a/ansible_ai_connect/users/pipeline.py b/ansible_ai_connect/users/pipeline.py index a47b69db0..45b6c6f31 100644 --- a/ansible_ai_connect/users/pipeline.py +++ b/ansible_ai_connect/users/pipeline.py @@ -126,7 +126,9 @@ def redhat_organization(backend, user, response, *args, **kwargs): else: logger.error("AUTHZ_DUMMY_RH_ORG_ADMINS has an invalid format.") - user.organization = ExternalOrganization.objects.get_or_create(id=int(payload["organization"]["id"]))[0] + user.organization = ExternalOrganization.objects.get_or_create( + id=int(payload["organization"]["id"]) + )[0] user.save() send_segment_group( f"rhsso-{user.organization.id}", "Red Hat Organization", user.organization.id, user From 075cb55944aab5d5a8a5ce98dbc3911a244da3a6 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Wed, 24 Sep 2025 14:39:05 -0400 Subject: [PATCH 09/12] Revert DAB req back to main --- requirements.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.in b/requirements.in index 55e04550d..c9f83abbc 100644 --- a/requirements.in +++ b/requirements.in @@ -71,4 +71,4 @@ uwsgi==2.0.22 uwsgi-readiness-check==0.2.0 django-allow-cidr==0.6.0 django-csp==3.7 -django-ansible-base[jwt-consumer,resource-registry]==2025.9.22 +django-ansible-base[jwt-consumer,resource-registry]==2025.8.18 From 8cd11697fb1e09e3fb67092968e37b9227a7ba92 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Thu, 25 Sep 2025 09:12:56 -0400 Subject: [PATCH 10/12] Abandon the new organization model because we can do without it --- .../migrations/0006_organization.py | 26 +------------------ ansible_ai_connect/organizations/models.py | 12 --------- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/ansible_ai_connect/organizations/migrations/0006_organization.py b/ansible_ai_connect/organizations/migrations/0006_organization.py index 52bdd67f1..2ecc6b200 100644 --- a/ansible_ai_connect/organizations/migrations/0006_organization.py +++ b/ansible_ai_connect/organizations/migrations/0006_organization.py @@ -1,6 +1,6 @@ # Generated manually to create new Organization model and clear dab_rbac data -from django.db import migrations, models +from django.db import migrations def clear_dab_rbac_data(apps, schema_editor): @@ -34,30 +34,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.CreateModel( - name="Organization", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ( - "name", - models.CharField(help_text="The name of this organization.", max_length=512), - ), - ( - "description", - models.TextField( - blank=True, default="", help_text="The organization description." - ), - ), - ], - options={ - "ordering": ["id"], - }, - ), migrations.RunPython( clear_dab_rbac_data, reverse_clear_dab_rbac_data, diff --git a/ansible_ai_connect/organizations/models.py b/ansible_ai_connect/organizations/models.py index 3a4c6b04a..7d575ec05 100644 --- a/ansible_ai_connect/organizations/models.py +++ b/ansible_ai_connect/organizations/models.py @@ -78,15 +78,3 @@ def __make_organization_request_to_launchdarkly(self, flag: str) -> bool: flag, {"kind": "organization", "key": str(self.id)}, ) - - -class Organization(models.Model): - id = models.BigAutoField(primary_key=True) - name = models.CharField(max_length=512, help_text="The name of this organization.") - description = models.TextField( - blank=True, default="", help_text="The organization description." - ) - - class Meta: - app_label = "organizations" - ordering = ["id"] From 3e1e817da5df4d5795ee99d50696f473e64c7dbc Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Thu, 25 Sep 2025 09:22:29 -0400 Subject: [PATCH 11/12] Revert unintended pages --- ansible_ai_connect/main/tests/test_ssl_manager.py | 2 +- ansible_ai_connect/organizations/migrations/0001_initial.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ansible_ai_connect/main/tests/test_ssl_manager.py b/ansible_ai_connect/main/tests/test_ssl_manager.py index b96a794bc..14bb6936d 100644 --- a/ansible_ai_connect/main/tests/test_ssl_manager.py +++ b/ansible_ai_connect/main/tests/test_ssl_manager.py @@ -876,7 +876,7 @@ def test_corrupted_ca_bundle_file(self): """Test SSL manager with corrupted CA bundle file.""" # Create corrupted CA bundle with tempfile.NamedTemporaryFile(mode="w", suffix=".pem", delete=False) as temp_file: - temp_file.write("CORRUPTED CERTIFICATE DATA\x00\xff\x00") + temp_file.write("CORRUPTED CERTIFICATE DATA\x00\xFF\x00") temp_file_path = temp_file.name try: diff --git a/ansible_ai_connect/organizations/migrations/0001_initial.py b/ansible_ai_connect/organizations/migrations/0001_initial.py index ffd363b81..521ce75a2 100644 --- a/ansible_ai_connect/organizations/migrations/0001_initial.py +++ b/ansible_ai_connect/organizations/migrations/0001_initial.py @@ -1,5 +1,4 @@ # Generated by Django 4.2.3 on 2023-11-29 09:16 -# Modified to show rename of original Organization model to ExternalOrganization from django.db import migrations, models From f6ebce5eb899a257373638b69334fe1f1324401f Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Thu, 25 Sep 2025 11:11:58 -0400 Subject: [PATCH 12/12] Abandon data migration that will not work --- .../migrations/0006_organization.py | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 ansible_ai_connect/organizations/migrations/0006_organization.py diff --git a/ansible_ai_connect/organizations/migrations/0006_organization.py b/ansible_ai_connect/organizations/migrations/0006_organization.py deleted file mode 100644 index 2ecc6b200..000000000 --- a/ansible_ai_connect/organizations/migrations/0006_organization.py +++ /dev/null @@ -1,41 +0,0 @@ -# Generated manually to create new Organization model and clear dab_rbac data - -from django.db import migrations - - -def clear_dab_rbac_data(apps, schema_editor): - """Delete all entries from dab_rbac models""" - db_alias = schema_editor.connection.alias - - # Get all dab_rbac models - from django.apps import apps as django_apps - - dab_rbac_config = django_apps.get_app_config("dab_rbac") - - # Delete all data from dab_rbac models in reverse dependency order - for model in reversed(dab_rbac_config.get_models()): - model.objects.using(db_alias).all().delete() - - -def reverse_clear_dab_rbac_data(apps, schema_editor): - """Reverse operation - no-op since we can't restore deleted data""" - pass - - -class Migration(migrations.Migration): - - dependencies = [ - ("organizations", "0005_rename_organization_to_externalorganization"), - ("dab_rbac", "0004_remote_permissions_additions"), - ] - - run_before = [ - ("dab_rbac", "0005_remote_permissions_data"), - ] - - operations = [ - migrations.RunPython( - clear_dab_rbac_data, - reverse_clear_dab_rbac_data, - ), - ]