From a35044f36f872dbe6f9e476362596ee6d8cee3a0 Mon Sep 17 00:00:00 2001 From: Sumandari Date: Fri, 26 Nov 2021 12:56:43 +0800 Subject: [PATCH 1/3] modified delete convener mechanism --- django_project/certification/forms.py | 2 + .../0007_courseconvener_is_active.py | 18 +++++++ .../certification/models/course_convener.py | 6 +++ .../certifying_organisation/detail.html | 32 ++---------- .../includes/convenor_list.html | 50 +++++++++++++++++++ .../certification/tests/test_models.py | 1 + .../views/certifying_organisation.py | 2 +- 7 files changed, 82 insertions(+), 29 deletions(-) create mode 100644 django_project/certification/migrations/0007_courseconvener_is_active.py create mode 100644 django_project/certification/templates/certifying_organisation/includes/convenor_list.html diff --git a/django_project/certification/forms.py b/django_project/certification/forms.py index 96f3d4fb2..a56c1c7bf 100644 --- a/django_project/certification/forms.py +++ b/django_project/certification/forms.py @@ -156,6 +156,7 @@ class Meta: 'user', 'degree', 'signature', + 'is_active', ) def __init__(self, *args, **kwargs): @@ -171,6 +172,7 @@ def __init__(self, *args, **kwargs): Field('user', css_class='form-control chosen-select'), Field('degree', css_class='form-control'), Field('signature', css_class='form-control'), + Field('is_active', css_class='checkbox-primary'), ) ) self.helper.layout = layout diff --git a/django_project/certification/migrations/0007_courseconvener_is_active.py b/django_project/certification/migrations/0007_courseconvener_is_active.py new file mode 100644 index 000000000..427a58442 --- /dev/null +++ b/django_project/certification/migrations/0007_courseconvener_is_active.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.18 on 2021-11-26 04:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('certification', '0006_auto_20210730_0615'), + ] + + operations = [ + migrations.AddField( + model_name='courseconvener', + name='is_active', + field=models.BooleanField(default=True, help_text='Inactive Convener will not be available in your organisation list.'), + ), + ] diff --git a/django_project/certification/models/course_convener.py b/django_project/certification/models/course_convener.py index 0a7c07eed..6dc2c0750 100644 --- a/django_project/certification/models/course_convener.py +++ b/django_project/certification/models/course_convener.py @@ -52,6 +52,12 @@ class CourseConvener(models.Model): null=True ) + is_active = models.BooleanField( + help_text=_('Inactive Convener will not be available in your ' + 'organisation list.'), + default=True + ) + class Meta: ordering = ['user'] diff --git a/django_project/certification/templates/certifying_organisation/detail.html b/django_project/certification/templates/certifying_organisation/detail.html index a9343cad3..b565bccc0 100644 --- a/django_project/certification/templates/certifying_organisation/detail.html +++ b/django_project/certification/templates/certifying_organisation/detail.html @@ -85,6 +85,9 @@

Certifying Organisation (all)

color: darkblue !important; text-decoration: none !important; } + .btn-disabled, .btn-disabled:hover { + color: #d3d3d3 + } {% if messages %} @@ -536,34 +539,7 @@
No course convener are defined, but you can {% for courseconvener in courseconveners %} - - -
- {% if courseconvener.user.first_name %} - {{ courseconvener.user.first_name }} {{ courseconvener.user.last_name }} - {% else %} - {{ courseconvener.user }} - {% endif %} -
- - - {% if user_can_delete %} - -
- - {% endif %} - + {% include 'certifying_organisation/includes/convenor_list.html' %} {% endfor %} diff --git a/django_project/certification/templates/certifying_organisation/includes/convenor_list.html b/django_project/certification/templates/certifying_organisation/includes/convenor_list.html new file mode 100644 index 000000000..05ce9008f --- /dev/null +++ b/django_project/certification/templates/certifying_organisation/includes/convenor_list.html @@ -0,0 +1,50 @@ + + +
+ {% if courseconvener.is_active %} + {% if courseconvener.user.first_name %} + {{ courseconvener.user.first_name }} {{ courseconvener.user.last_name }} + {% else %} + {{ courseconvener.user }} + {% endif %} + {% elif user_can_delete %} + + {% if courseconvener.user.first_name %} + {{ courseconvener.user.first_name }} {{ courseconvener.user.last_name }} + {% else %} + {{ courseconvener.user }} + {% endif %} + + [inactive] + {% endif %} +
+ + {% if user_can_delete %} + +
+ {% if courseconvener.course_set.exists %} + + + + {% else %} + + + + {% endif %} + + + +
+ + {% endif %} + \ No newline at end of file diff --git a/django_project/certification/tests/test_models.py b/django_project/certification/tests/test_models.py index c7e723990..eedccafd5 100644 --- a/django_project/certification/tests/test_models.py +++ b/django_project/certification/tests/test_models.py @@ -336,6 +336,7 @@ def test_Course_Convener_create(self): self.assertEqual(model.__dict__.get(key), val) self.assertTrue(model.title == 'new Course Convener Title') self.assertTrue(model.degree == 'new Course Convener Degree') + self.assertTrue(model.is_active) # check if PK exists. self.assertTrue(model.pk is not None) diff --git a/django_project/certification/views/certifying_organisation.py b/django_project/certification/views/certifying_organisation.py index 3a8899ebb..0ef42705a 100644 --- a/django_project/certification/views/certifying_organisation.py +++ b/django_project/certification/views/certifying_organisation.py @@ -213,7 +213,7 @@ def get_context_data(self, **kwargs): certifying_organisation=certifying_organisation) context['num_coursetype'] = context['coursetypes'].count() context['courseconveners'] = CourseConvener.objects.filter( - certifying_organisation=certifying_organisation) + certifying_organisation=certifying_organisation).prefetch_related('course_set') context['num_courseconvener'] = context['courseconveners'].count() context['courses'] = Course.objects.filter( certifying_organisation=certifying_organisation).order_by( From d5427d7a5a338a5846ac62453432156236c1699d Mon Sep 17 00:00:00 2001 From: Sumandari Date: Fri, 26 Nov 2021 14:17:38 +0800 Subject: [PATCH 2/3] add unit test --- django_project/certification/forms.py | 2 +- .../tests/views/test_course_view.py | 108 +++++++++++++++++- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/django_project/certification/forms.py b/django_project/certification/forms.py index a56c1c7bf..34371b145 100644 --- a/django_project/certification/forms.py +++ b/django_project/certification/forms.py @@ -331,7 +331,7 @@ def __init__(self, *args, **kwargs): super(CourseForm, self).__init__(*args, **kwargs) self.fields['course_convener'].queryset = \ CourseConvener.objects.filter( - certifying_organisation=self.certifying_organisation) + certifying_organisation=self.certifying_organisation, is_active=True) self.fields['course_convener'].label_from_instance = \ lambda obj: "%s <%s>" % (obj.user.get_full_name(), obj) self.fields['course_type'].queryset = \ diff --git a/django_project/certification/tests/views/test_course_view.py b/django_project/certification/tests/views/test_course_view.py index 3a1a25693..274bab933 100644 --- a/django_project/certification/tests/views/test_course_view.py +++ b/django_project/certification/tests/views/test_course_view.py @@ -7,7 +7,8 @@ ProjectF, UserF, CertifyingOrganisationF, - CourseF + CourseF, + CourseConvenerF ) @@ -162,3 +163,108 @@ def test_delete_with_duplicates(self): 'slug': self.certifying_organisation.slug, }) self.assertRedirects(response, expected_url) + + @override_settings(VALID_DOMAIN=['testserver', ]) + def test_inactive_convener_should_not_be_in_the_course_convener_list(self): + convener = UserF.create(**{ + 'username': 'convener', + 'password': 'password', + 'first_name': 'Pretty', + 'last_name': 'Smart', + 'is_staff': True + }) + convener_inactive = UserF.create(**{ + 'username': 'inactive_convener', + 'password': 'password', + 'first_name': 'Wonder', + 'last_name': 'Woman', + 'is_staff': True + }) + CourseConvenerF.create( + user=convener, + certifying_organisation=self.certifying_organisation + ) + CourseConvenerF.create( + user=convener_inactive, + certifying_organisation=self.certifying_organisation, + is_active=False + ) + self.client.login(username='anita', password='password') + response = self.client.get(reverse('course-create', kwargs={ + 'project_slug': self.project.slug, + 'organisation_slug': self.certifying_organisation.slug, + })) + self.assertContains(response, 'Pretty Smart') + self.assertNotContains(response, 'Wonder Woman') + self.assertNotContains(response, 'inactive_convener') + + @override_settings(VALID_DOMAIN=['testserver', ]) + def test_inactive_convener_should_not_be_in_normal_user_detail_page(self): + convener = UserF.create(**{ + 'username': 'convener', + 'password': 'password', + 'first_name': 'Pretty', + 'last_name': 'Smart', + 'is_staff': True + }) + convener_inactive = UserF.create(**{ + 'username': 'inactive_convener', + 'password': 'password', + 'first_name': 'Wonder', + 'last_name': 'Woman', + 'is_staff': True + }) + CourseConvenerF.create( + user=convener, + certifying_organisation=self.certifying_organisation + ) + CourseConvenerF.create( + user=convener_inactive, + certifying_organisation=self.certifying_organisation, + is_active=False + ) + response = self.client.get( + reverse('certifyingorganisation-detail', kwargs={ + 'project_slug': self.project.slug, + 'slug': self.certifying_organisation.slug, + }) + ) + self.assertContains(response, 'Pretty Smart') + self.assertNotContains(response, 'Wonder Woman') + self.assertNotContains(response, '[inactive]') + + @override_settings(VALID_DOMAIN=['testserver', ]) + def test_inactive_convener_should_be_in_normal_user_detail_page(self): + convener = UserF.create(**{ + 'username': 'convener', + 'password': 'password', + 'first_name': 'Pretty', + 'last_name': 'Smart', + 'is_staff': True + }) + convener_inactive = UserF.create(**{ + 'username': 'inactive_convener', + 'password': 'password', + 'first_name': 'Wonder', + 'last_name': 'Woman', + 'is_staff': True + }) + CourseConvenerF.create( + user=convener, + certifying_organisation=self.certifying_organisation + ) + CourseConvenerF.create( + user=convener_inactive, + certifying_organisation=self.certifying_organisation, + is_active=False + ) + self.client.login(username='anita', password='password') + response = self.client.get( + reverse('certifyingorganisation-detail', kwargs={ + 'project_slug': self.project.slug, + 'slug': self.certifying_organisation.slug, + }) + ) + self.assertContains(response, 'Pretty Smart') + self.assertContains(response, 'Wonder Woman') + self.assertContains(response, '[inactive]') From 745b191a9872ee613255b243c5e0d290f5d76053 Mon Sep 17 00:00:00 2001 From: Sumandari Date: Fri, 26 Nov 2021 14:33:28 +0800 Subject: [PATCH 3/3] fix typo flake8 --- django_project/certification/forms.py | 3 ++- django_project/certification/views/certifying_organisation.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/django_project/certification/forms.py b/django_project/certification/forms.py index 34371b145..6c3249e38 100644 --- a/django_project/certification/forms.py +++ b/django_project/certification/forms.py @@ -331,7 +331,8 @@ def __init__(self, *args, **kwargs): super(CourseForm, self).__init__(*args, **kwargs) self.fields['course_convener'].queryset = \ CourseConvener.objects.filter( - certifying_organisation=self.certifying_organisation, is_active=True) + certifying_organisation=self.certifying_organisation, + is_active=True) self.fields['course_convener'].label_from_instance = \ lambda obj: "%s <%s>" % (obj.user.get_full_name(), obj) self.fields['course_type'].queryset = \ diff --git a/django_project/certification/views/certifying_organisation.py b/django_project/certification/views/certifying_organisation.py index 0ef42705a..be274029f 100644 --- a/django_project/certification/views/certifying_organisation.py +++ b/django_project/certification/views/certifying_organisation.py @@ -213,7 +213,8 @@ def get_context_data(self, **kwargs): certifying_organisation=certifying_organisation) context['num_coursetype'] = context['coursetypes'].count() context['courseconveners'] = CourseConvener.objects.filter( - certifying_organisation=certifying_organisation).prefetch_related('course_set') + certifying_organisation=certifying_organisation + ).prefetch_related('course_set') context['num_courseconvener'] = context['courseconveners'].count() context['courses'] = Course.objects.filter( certifying_organisation=certifying_organisation).order_by(