Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add validation on subsidy uuid #606

Merged
merged 1 commit into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
SubsidyAccessPolicySetLateRedemptionView
)

from .forms import ForcedPolicyRedemptionForm
from .forms import ForcedPolicyRedemptionForm, SubsidyAccessPolicyForm

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -199,6 +199,8 @@ class PerLearnerEnrollmentCreditAccessPolicy(DjangoQLSearchMixin, BaseSubsidyAcc
"""
Admin configuration for PerLearnerEnrollmentCreditAccessPolicy.
"""
form = SubsidyAccessPolicyForm

list_display = BaseSubsidyAccessPolicyMixin.list_display + (
'per_learner_enrollment_limit',
)
Expand Down Expand Up @@ -250,6 +252,8 @@ class PerLearnerSpendCreditAccessPolicy(DjangoQLSearchMixin, BaseSubsidyAccessPo
"""
Admin configuration for PerLearnerSpendCreditAccessPolicy.
"""
form = SubsidyAccessPolicyForm

list_display = BaseSubsidyAccessPolicyMixin.list_display + (
'per_learner_spend_limit_dollars',
)
Expand Down Expand Up @@ -313,6 +317,8 @@ class LearnerContentAssignmentAccessPolicy(DjangoQLSearchMixin, BaseSubsidyAcces
"""
Admin configuration for AssignedLearnerCreditAccessPolicy.
"""
form = SubsidyAccessPolicyForm

search_fields = (
'uuid',
'display_name',
Expand Down
33 changes: 32 additions & 1 deletion enterprise_access/apps/subsidy_access_policy/admin/forms.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
"""
Forms to be used for subsidy_access_policy django admin.
"""
import requests
from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _

from ..models import ForcedPolicyRedemption
from enterprise_access.apps.subsidy_access_policy.utils import get_versioned_subsidy_client

from ..models import ForcedPolicyRedemption, SubsidyAccessPolicy


class LateRedemptionDaysFromNowChoices:
Expand Down Expand Up @@ -92,3 +96,30 @@ class ForcedPolicyRedemptionForm(forms.ModelForm):
class Meta:
model = ForcedPolicyRedemption
fields = '__all__'


class SubsidyAccessPolicyForm(forms.ModelForm):
"""
Admin form for the SubsidyAccessPolicy model.
"""
def clean_subsidy_uuid(self):
"""
Validate that the subsidy exists and is assigned to the same enterprise customer as the budget.
"""
# 1. check if the subsidy_uuid actually exists
# 2. subsidy is assigned to the same enterprise customer as the budget
# if any of these checks fail, raise a ValidationError
client = get_versioned_subsidy_client(version=1)
try:
subsidy = client.retrieve_subsidy(self.cleaned_data["subsidy_uuid"])
except requests.exceptions.HTTPError as exc:
raise ValidationError("Subsidy does not exist") from exc

if str(subsidy["enterprise_customer_uuid"]) != str(self.cleaned_data["enterprise_customer_uuid"]):
raise ValidationError("Subsidy is not assigned to the same enterprise customer as the budget")

return self.cleaned_data["subsidy_uuid"]

class Meta:
model = SubsidyAccessPolicy
fields = '__all__'
77 changes: 77 additions & 0 deletions enterprise_access/apps/subsidy_access_policy/tests/test_forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""
Unittests for forms.
"""
import uuid
from unittest import mock

import requests
from django.test import TestCase

from enterprise_access.apps.subsidy_access_policy.admin.forms import SubsidyAccessPolicyForm
from enterprise_access.apps.subsidy_access_policy.constants import AccessMethods


class TestSubsidyAccessPolicyForm(TestCase):
"""
Tests for SubsidyAccessPolicyForm.
"""
def setUp(self):
super().setUp()
self.enterprise_customer_uuid = uuid.uuid4()
self.subsidy_uuid = uuid.uuid4()
self.catalog_uuid = uuid.uuid4()
self.form_data = {
'enterprise_customer_uuid': self.enterprise_customer_uuid,
'subsidy_uuid': self.subsidy_uuid,
'catalog_uuid': self.catalog_uuid,
'access_method': AccessMethods.DIRECT,
}

@mock.patch('enterprise_access.apps.subsidy_access_policy.admin.forms.get_versioned_subsidy_client')
def test_clean_subsidy_uuid_success(self, mock_get_client):
"""
Test successful validation when subsidy exists and belongs to enterprise customer.
"""
mock_client = mock.MagicMock()
mock_client.retrieve_subsidy.return_value = {
'enterprise_customer_uuid': self.enterprise_customer_uuid
}
mock_get_client.return_value = mock_client

form = SubsidyAccessPolicyForm(data=self.form_data)
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data['subsidy_uuid'], self.subsidy_uuid)

@mock.patch('enterprise_access.apps.subsidy_access_policy.admin.forms.get_versioned_subsidy_client')
def test_clean_subsidy_uuid_not_found(self, mock_get_client):
"""
Verify that a validation error is raised when the subsidy does not exist.
"""
mock_client = mock.MagicMock()
mock_client.retrieve_subsidy.side_effect = requests.exceptions.HTTPError()
mock_get_client.return_value = mock_client

form = SubsidyAccessPolicyForm(data=self.form_data)
self.assertFalse(form.is_valid())
self.assertIn('subsidy_uuid', form.errors)
self.assertEqual(form.errors['subsidy_uuid'], ['Subsidy does not exist'])

@mock.patch('enterprise_access.apps.subsidy_access_policy.admin.forms.get_versioned_subsidy_client')
def test_clean_subsidy_uuid_wrong_enterprise(self, mock_get_client):
"""
Verify that a validation error is raised when the subsidy belongs to a different enterprise customer.
"""
different_enterprise_uuid = uuid.uuid4()
mock_client = mock.MagicMock()
mock_client.retrieve_subsidy.return_value = {
'enterprise_customer_uuid': different_enterprise_uuid
}
mock_get_client.return_value = mock_client

form = SubsidyAccessPolicyForm(data=self.form_data)
self.assertFalse(form.is_valid())
self.assertIn('subsidy_uuid', form.errors)
self.assertEqual(
form.errors['subsidy_uuid'],
['Subsidy is not assigned to the same enterprise customer as the budget']
)
Loading