From aca567c28cd5aeff16588bef0e40e4cda7a7b753 Mon Sep 17 00:00:00 2001 From: alipov_d Date: Mon, 13 Nov 2023 20:57:22 +0200 Subject: [PATCH] fix: 500 error message during opening program certificate Error 500 occurs when going to the program certificate page if an organization is connected to the Authoring organizations field with an empty field Certificate logo image. --- .../apps/course_metadata/forms.py | 17 ++++- .../apps/course_metadata/tests/test_forms.py | 72 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 course_discovery/apps/course_metadata/tests/test_forms.py diff --git a/course_discovery/apps/course_metadata/forms.py b/course_discovery/apps/course_metadata/forms.py index 9397b9a6498..6f3d7ec3562 100644 --- a/course_discovery/apps/course_metadata/forms.py +++ b/course_discovery/apps/course_metadata/forms.py @@ -4,7 +4,7 @@ from django.utils.translation import gettext_lazy as _ from course_discovery.apps.course_metadata.choices import ProgramStatus -from course_discovery.apps.course_metadata.models import Course, CourseRun, Pathway, Program +from course_discovery.apps.course_metadata.models import Course, CourseRun, Organization, Pathway, Program from course_discovery.apps.course_metadata.widgets import SortedModelSelect2Multiple @@ -68,6 +68,21 @@ def clean(self): return self.cleaned_data + def clean_authoring_organizations(self): + authoring_organizations = self.cleaned_data.get('authoring_organizations') + orgs_with_empty_certificate_logo_image = [] + + for organization in authoring_organizations: + if not organization.certificate_logo_image: + orgs_with_empty_certificate_logo_image.append(organization.name) + + if orgs_with_empty_certificate_logo_image: + error_message = f'Certificate logo image cannot be empty for organizations: ' \ + f'{", ".join(orgs_with_empty_certificate_logo_image)}.' + raise ValidationError(error_message) + + return authoring_organizations + class CourseRunSelectionForm(forms.ModelForm): class Meta: diff --git a/course_discovery/apps/course_metadata/tests/test_forms.py b/course_discovery/apps/course_metadata/tests/test_forms.py new file mode 100644 index 00000000000..d117d97afa2 --- /dev/null +++ b/course_discovery/apps/course_metadata/tests/test_forms.py @@ -0,0 +1,72 @@ +from django.test import TestCase + +from course_discovery.apps.api.tests.mixins import SiteMixin +from course_discovery.apps.core.tests.factories import USER_PASSWORD, UserFactory +from course_discovery.apps.course_metadata.choices import ProgramStatus +from course_discovery.apps.course_metadata.forms import ProgramAdminForm +from course_discovery.apps.course_metadata.tests import factories + + +class ProgramAdminFormTests(SiteMixin, TestCase): + """ Tests ProgramAdminForm. """ + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.user = UserFactory(is_staff=True, is_superuser=True) + cls.course_runs = factories.CourseRunFactory.create_batch(3) + cls.courses = [course_run.course for course_run in cls.course_runs] + cls.product_source = factories.SourceFactory() + + cls.excluded_course_run = factories.CourseRunFactory(course=cls.courses[0]) + cls.program = factories.ProgramFactory( + courses=cls.courses, + excluded_course_runs=[cls.excluded_course_run], + partner=cls.partner, + ) + cls.org_1 = factories.OrganizationFactory(certificate_logo_image=None) + cls.org_2 = factories.OrganizationFactory(certificate_logo_image=None) + cls.org_3 = factories.OrganizationFactory() + + def setUp(self): + super().setUp() + self.client.login(username=self.user.username, password=USER_PASSWORD) + + def _post_data(self, status=ProgramStatus.Unpublished, marketing_slug='/foo'): + return { + 'title': 'some test title', + 'courses': [self.courses[0].id], + 'type': self.program.type.id, + 'status': status, + 'marketing_slug': marketing_slug, + 'partner': self.program.partner.id, + 'product_source': self.product_source.id, + 'authoring_organizations': [self.org_1.id, self.org_2.id, self.org_3.id], + } + + def test_clean_authoring_organizations_with_empty_certificate_logo_image(self): + """ + Test verifies that the form is invalid if certificate_logo_image + is empty for any of the authoring_organizations. + """ + data = self._post_data() + form = ProgramAdminForm(data=data) + self.assertFalse(form.is_valid()) + expected_error_message = f'Certificate logo image cannot be empty for organizations: ' \ + f'{self.org_1.name}, {self.org_2.name}.' + + self.assertEqual(form.errors['authoring_organizations'][0], expected_error_message) + + def test_clean_authoring_organizations_with_non_empty_certificate_logo_image(self): + """ + Test verifies that the form is valid only if certificate_logo_image + is not empty for all authoring_organizations. + """ + self.org_1.certificate_logo_image = 'logo1.jpg' + self.org_1.save() + self.org_2.certificate_logo_image = 'logo2.jpg' + self.org_2.save() + data = self._post_data() + form = ProgramAdminForm(data=data) + + self.assertTrue(form.is_valid())