codeforlife-portal 6.43.1__py2.py3-none-any.whl → 6.43.2__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of codeforlife-portal might be problematic. Click here for more details.
- cfl_common/common/email_messages.py +0 -13
- cfl_common/common/mail.py +1 -0
- {codeforlife_portal-6.43.1.dist-info → codeforlife_portal-6.43.2.dist-info}/METADATA +2 -2
- {codeforlife_portal-6.43.1.dist-info → codeforlife_portal-6.43.2.dist-info}/RECORD +12 -12
- portal/__init__.py +1 -1
- portal/tests/test_independent_student.py +3 -2
- portal/tests/test_views.py +11 -3
- portal/views/registration.py +11 -20
- portal/views/student/edit_account_details.py +8 -6
- {codeforlife_portal-6.43.1.dist-info → codeforlife_portal-6.43.2.dist-info}/LICENSE.md +0 -0
- {codeforlife_portal-6.43.1.dist-info → codeforlife_portal-6.43.2.dist-info}/WHEEL +0 -0
- {codeforlife_portal-6.43.1.dist-info → codeforlife_portal-6.43.2.dist-info}/top_level.txt +0 -0
|
@@ -81,16 +81,3 @@ def inviteTeacherEmail(request, schoolName, token, account_exists):
|
|
|
81
81
|
)
|
|
82
82
|
|
|
83
83
|
return {"subject": f"You've been invited to join Code for Life", "message": message}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def accountDeletionEmail(request):
|
|
87
|
-
return {
|
|
88
|
-
"subject": f"We are sorry to see you go",
|
|
89
|
-
"title": "Your account was successfully deleted",
|
|
90
|
-
"message": (
|
|
91
|
-
f"If you have a moment before you leave us completely, please "
|
|
92
|
-
f"let us know the reason through our super short survey below."
|
|
93
|
-
f"\n\nGive feedback: https://usabi.li/do/d8e0313a31d7/5bef"
|
|
94
|
-
f"\n\nThank you for being part of the Code for Life community!"
|
|
95
|
-
),
|
|
96
|
-
}
|
cfl_common/common/mail.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: codeforlife-portal
|
|
3
|
-
Version: 6.43.
|
|
3
|
+
Version: 6.43.2
|
|
4
4
|
Classifier: Programming Language :: Python
|
|
5
5
|
Classifier: Programming Language :: Python :: 3.8
|
|
6
6
|
Classifier: Framework :: Django
|
|
@@ -24,7 +24,7 @@ Requires-Dist: django-classy-tags ==2.0.0
|
|
|
24
24
|
Requires-Dist: libsass ==0.23.0
|
|
25
25
|
Requires-Dist: phonenumbers ==8.12.12
|
|
26
26
|
Requires-Dist: more-itertools ==8.7.0
|
|
27
|
-
Requires-Dist: cfl-common ==6.43.
|
|
27
|
+
Requires-Dist: cfl-common ==6.43.2
|
|
28
28
|
Requires-Dist: django-ratelimit ==3.0.1
|
|
29
29
|
Requires-Dist: django-preventconcurrentlogins ==0.8.2
|
|
30
30
|
Requires-Dist: django-csp ==3.7
|
|
@@ -5,8 +5,8 @@ cfl_common/common/app_settings.py,sha256=x2ROLY5Xl5LgqjxyTiChZvQorZYUXpFzEkaLsjh
|
|
|
5
5
|
cfl_common/common/apps.py,sha256=49UXZ3bSkFKvIEOL4zM7y1sAhccQJyRtsoOg5XVd_8Y,129
|
|
6
6
|
cfl_common/common/context_processors.py,sha256=X0iuX5qu9kMWa7q8osE9CJ2LgM7pPOYQFGdjm8X3rk0,236
|
|
7
7
|
cfl_common/common/csp_config.py,sha256=sZT6s9zMT5FFIqNODsURT0ifxbDgXpDlki8UxaBq2iE,2940
|
|
8
|
-
cfl_common/common/email_messages.py,sha256=
|
|
9
|
-
cfl_common/common/mail.py,sha256=
|
|
8
|
+
cfl_common/common/email_messages.py,sha256=J57n4krBAnwqacRjIzkO-qhbdlqNWwyJiRd8ozitm-M,3148
|
|
9
|
+
cfl_common/common/mail.py,sha256=11WqmB770MmGJcATa4dOeyGHSYLceV8zZDPx_4kK-zI,6021
|
|
10
10
|
cfl_common/common/models.py,sha256=EunFsc7sOWfWiFf4IQwuy56gu8pu3YpPoOgVtsMhbRM,14958
|
|
11
11
|
cfl_common/common/permissions.py,sha256=gC6RQGZI2QDBbglx-xr_V4Hl2C2nf1V2_uPmEuoEcJo,2416
|
|
12
12
|
cfl_common/common/utils.py,sha256=Nn2Npao9Uqad5Js_IdHwF-ow6wrPNpBLW4AO1LxoEBc,1727
|
|
@@ -106,7 +106,7 @@ example_project/portal_test_settings.py,sha256=frp_XMpd-z1g3VFCRxB2w7AaFW2ivRVKn
|
|
|
106
106
|
example_project/settings.py,sha256=XRZZvASoIl5a9xe3masTq_CUBleuJq9ByHx8f_e2UFc,5613
|
|
107
107
|
example_project/urls.py,sha256=OVeRQ-TCpzHISBRuzqD0yd3ewF7H5U3c-f2p2alfUD0,430
|
|
108
108
|
example_project/wsgi.py,sha256=U1W6WzZxZaIdYZ5tks7w9fqp5WS5qvn2iThsVcskrWw,829
|
|
109
|
-
portal/__init__.py,sha256=
|
|
109
|
+
portal/__init__.py,sha256=hjhQopF2UeY6Ek3KDmWtiEswta3fxltdCEalD4TaXFA,23
|
|
110
110
|
portal/admin.py,sha256=k5Hsiln43DlVPoufnrx5AXWu_RijX8xi_n7wwBuuCJo,5132
|
|
111
111
|
portal/app_settings.py,sha256=DhWLQOwM0zVOXE3O5TNKbMM9K6agfLuCsHOdr1J7xEI,651
|
|
112
112
|
portal/backends.py,sha256=2Dss6_WoQwPuDzJUF1yEaTQTNG4eUrD12ujJQ5cp5Tc,812
|
|
@@ -544,7 +544,7 @@ portal/tests/test_class.py,sha256=V6Fkc6PqdisefKD3xs9PbfE2pKp-9e0gwQVkPUiu6bk,14
|
|
|
544
544
|
portal/tests/test_daily_activities.py,sha256=-siDCMGBD1ijjccHVk7eEmrk4bgTsvbh0B6hDoj2fo0,1803
|
|
545
545
|
portal/tests/test_emails.py,sha256=Y26VjhPOzc2aptHBSmOW9R-do3k1QaRqUc5MiwgsAQk,9156
|
|
546
546
|
portal/tests/test_helper_methods.py,sha256=-SQCDZm2XUtyXGEp0CHIb_SSC9CPD-XOSnpnY8QclHk,890
|
|
547
|
-
portal/tests/test_independent_student.py,sha256=
|
|
547
|
+
portal/tests/test_independent_student.py,sha256=rW3OTFWxeEHm5tSumr1L4MRkUsEgESfhapU6M3bfNhc,26437
|
|
548
548
|
portal/tests/test_invite_teacher.py,sha256=oeOaoJV1IqJSYPlaPFjnhVXdB2mq8otCTLp_lfjuCfk,12224
|
|
549
549
|
portal/tests/test_middleware.py,sha256=b6jfNmiRZ2snqLKsyJUG-RivoX5fmrqLlQkG9MeVnqM,8034
|
|
550
550
|
portal/tests/test_newsletter_footer.py,sha256=MdVUX53mEoDTa4Krq-jg9LFNo-QyghqvTvhHeNXBGnE,838
|
|
@@ -555,7 +555,7 @@ portal/tests/test_school_student.py,sha256=bFZwY4twaFHQLp0cltMq8cLNDZGgCHTZBCZHK
|
|
|
555
555
|
portal/tests/test_security.py,sha256=FGrlRfnzi-Xx2_bn4fTZlYORKm7w_GhGkD3havvplwc,3239
|
|
556
556
|
portal/tests/test_teacher.py,sha256=_VmQCWq07uCFbvq6Vd7GN00mE7vY7WNMeQTk6bHxFPI,36898
|
|
557
557
|
portal/tests/test_teacher_student.py,sha256=NWITbUw1kijqu3c8eRHLHJKaYQMOsOMvl7PAVx5QghI,21567
|
|
558
|
-
portal/tests/test_views.py,sha256=
|
|
558
|
+
portal/tests/test_views.py,sha256=IElQJnp9fhlmqR-54nBycul2uUIjsG9dTRnYy5SxXJ4,39278
|
|
559
559
|
portal/tests/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
560
560
|
portal/tests/migrations/test_migration_make_portaladmin_teacher.py,sha256=ekMRb6cU97oT0k9gCKW7IUB7oPuGmv4uWJCqInQN7x8,2589
|
|
561
561
|
portal/tests/migrations/test_migration_preview_user_remove.py,sha256=K6D-FZT9YFEA8oMxHz9VTglVV6MZOTRYVlvwWwXc2vU,555
|
|
@@ -622,7 +622,7 @@ portal/views/home.py,sha256=J_kb0Kv5Ubk9yQ4r0IAvhPV5o_iezcaqA4Z5bd0-Idc,9869
|
|
|
622
622
|
portal/views/legal.py,sha256=nUunsTHnhMcXBcDlg1GmUal86k9Vhinne4A2FWfq78M,342
|
|
623
623
|
portal/views/organisation.py,sha256=sPDbiM7hdtpF8GKyh_4n4VPl2a-WnAgnF4q9aSvQCVI,3341
|
|
624
624
|
portal/views/play_landing_page.py,sha256=FFmjUFub3ZdlbMqkB8yX3jAImCzqrUqgb8AZcpKywZ4,308
|
|
625
|
-
portal/views/registration.py,sha256=
|
|
625
|
+
portal/views/registration.py,sha256=L9AzIG2nOU946cSOXmUMQRtDo3uxApHX-0ceXopbOCw,10888
|
|
626
626
|
portal/views/teach.py,sha256=nzlyTcgq9ImAjnqrF3esqi212qBLH5Ww1LKE2gSjoRY,210
|
|
627
627
|
portal/views/aimmo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
628
628
|
portal/views/aimmo/dashboard.py,sha256=YMOzonNE87OEP5lThY4BrF0rNyvIYpDInh_sM-n38AM,4046
|
|
@@ -633,7 +633,7 @@ portal/views/login/independent_student.py,sha256=3dFULhwMAlX4VDrJl-Znril6a9M5xKB
|
|
|
633
633
|
portal/views/login/student.py,sha256=dt6cMfWepBJsVCRcADltfYSHVpyeP1WGLKSogMJ22E0,5539
|
|
634
634
|
portal/views/login/teacher.py,sha256=kRugP7TPbZIb_BmYMYxFeugxZy8UbCry_q0_jJDJ_Mw,1975
|
|
635
635
|
portal/views/student/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
636
|
-
portal/views/student/edit_account_details.py,sha256=
|
|
636
|
+
portal/views/student/edit_account_details.py,sha256=Ba-3D_zzKbX5N01NG5qqBS0ud10B8D5SN8hOpLiGa9U,8468
|
|
637
637
|
portal/views/student/play.py,sha256=-v9lBjHF3_PAKRgWcCGGt_bEOpIkmJDJnzgR5JvqrMo,8908
|
|
638
638
|
portal/views/teacher/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
639
639
|
portal/views/teacher/dashboard.py,sha256=nNA7XxylunLjyCpKmq7h_CYITi7wM3YnmjqzUL0A-bI,25236
|
|
@@ -642,8 +642,8 @@ portal/views/two_factor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
|
642
642
|
portal/views/two_factor/core.py,sha256=O_wcBeFqdPYSGNGv-pT_vbs5-Dj1Z-Jfkd6f9-E5yZI,760
|
|
643
643
|
portal/views/two_factor/form.py,sha256=lnHNKI-BMlpncTuW3zUzjPaJJNuEra2I_nOam0eOKFY,257
|
|
644
644
|
portal/views/two_factor/profile.py,sha256=tkl_ludo8arMtd5LKNmohM66vpC_YQiP-0nspTSJiJ4,383
|
|
645
|
-
codeforlife_portal-6.43.
|
|
646
|
-
codeforlife_portal-6.43.
|
|
647
|
-
codeforlife_portal-6.43.
|
|
648
|
-
codeforlife_portal-6.43.
|
|
649
|
-
codeforlife_portal-6.43.
|
|
645
|
+
codeforlife_portal-6.43.2.dist-info/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
|
|
646
|
+
codeforlife_portal-6.43.2.dist-info/METADATA,sha256=kUAWYPqcsp2m4LS4Kh6PwIr_K7GbBPgZA6qvvbO3XQE,1137
|
|
647
|
+
codeforlife_portal-6.43.2.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
|
|
648
|
+
codeforlife_portal-6.43.2.dist-info/top_level.txt,sha256=8e5pdsuIoTqEAMqpelHBjGjLbffcBtgOoggmd2q7nMw,41
|
|
649
|
+
codeforlife_portal-6.43.2.dist-info/RECORD,,
|
portal/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "6.43.
|
|
1
|
+
__version__ = "6.43.2"
|
|
@@ -169,7 +169,8 @@ class TestIndependentStudent(TestCase):
|
|
|
169
169
|
|
|
170
170
|
# Class for Selenium tests. We plan to replace these and turn them into Cypress tests
|
|
171
171
|
class TestIndependentStudentFrontend(BaseTest):
|
|
172
|
-
|
|
172
|
+
@patch("portal.views.registration.send_dotdigital_email")
|
|
173
|
+
def test_delete_indy_account(self, mock_send_dotdigital_email: Mock):
|
|
173
174
|
page = self.go_to_homepage()
|
|
174
175
|
page, _, _, email, password = create_independent_student(page)
|
|
175
176
|
page = page.independent_student_login(email, password)
|
|
@@ -214,7 +215,7 @@ class TestIndependentStudentFrontend(BaseTest):
|
|
|
214
215
|
assert not User.objects.get(id=user_id).is_active
|
|
215
216
|
|
|
216
217
|
# check if email has been sent
|
|
217
|
-
|
|
218
|
+
mock_send_dotdigital_email.assert_called_once_with(campaign_ids["delete_account"], ANY)
|
|
218
219
|
|
|
219
220
|
def test_signup_without_newsletter(self):
|
|
220
221
|
page = self.go_to_homepage()
|
portal/tests/test_views.py
CHANGED
|
@@ -572,7 +572,8 @@ class TestViews(TestCase):
|
|
|
572
572
|
assert response.status_code == 200
|
|
573
573
|
assert response.context_data == EXPECTED_DATA_WITH_KURONO_GAME
|
|
574
574
|
|
|
575
|
-
|
|
575
|
+
@patch("portal.views.registration.send_dotdigital_email")
|
|
576
|
+
def test_delete_account(self, mock_send_dotdigital_email: Mock):
|
|
576
577
|
email, password = signup_teacher_directly()
|
|
577
578
|
u = User.objects.get(email=email)
|
|
578
579
|
usrid = u.id
|
|
@@ -593,7 +594,7 @@ class TestViews(TestCase):
|
|
|
593
594
|
response = c.post(url, {"password": "wrongPassword"})
|
|
594
595
|
|
|
595
596
|
assert response.status_code == 302
|
|
596
|
-
|
|
597
|
+
mock_send_dotdigital_email.assert_not_called()
|
|
597
598
|
|
|
598
599
|
# user has not been anonymised
|
|
599
600
|
u = User.objects.get(email=email)
|
|
@@ -604,6 +605,7 @@ class TestViews(TestCase):
|
|
|
604
605
|
response = c.post(url, {"password": password, "unsubscribe_newsletter": "on"})
|
|
605
606
|
|
|
606
607
|
assert response.status_code == 302
|
|
608
|
+
mock_send_dotdigital_email.assert_called_once()
|
|
607
609
|
assert response.url == reverse("home")
|
|
608
610
|
|
|
609
611
|
# user has been anonymised
|
|
@@ -611,7 +613,10 @@ class TestViews(TestCase):
|
|
|
611
613
|
assert u.first_name == "Deleted"
|
|
612
614
|
assert not u.is_active
|
|
613
615
|
|
|
614
|
-
|
|
616
|
+
assert c.login(username=email, password=password) == False
|
|
617
|
+
|
|
618
|
+
@patch("portal.views.registration.send_dotdigital_email")
|
|
619
|
+
def test_delete_account_admin(self, mock_send_dotdigital_email: Mock):
|
|
615
620
|
"""test the passing of admin role after deletion of an admin account"""
|
|
616
621
|
|
|
617
622
|
email1, password1 = signup_teacher_directly()
|
|
@@ -666,6 +671,7 @@ class TestViews(TestCase):
|
|
|
666
671
|
# delete teacher1 account
|
|
667
672
|
url = reverse("delete_account")
|
|
668
673
|
c.post(url, {"password": password1})
|
|
674
|
+
mock_send_dotdigital_email.assert_called_once()
|
|
669
675
|
|
|
670
676
|
# user has been anonymised
|
|
671
677
|
u = User.objects.get(id=usrid1)
|
|
@@ -706,6 +712,7 @@ class TestViews(TestCase):
|
|
|
706
712
|
# now delete teacher3 account
|
|
707
713
|
url = reverse("delete_account")
|
|
708
714
|
c.post(url, {"password": password3})
|
|
715
|
+
self.assertEqual(mock_send_dotdigital_email.call_count, 2)
|
|
709
716
|
|
|
710
717
|
# 2 teachers left
|
|
711
718
|
teachers = Teacher.objects.filter(school=school).order_by("new_user__last_name", "new_user__first_name")
|
|
@@ -738,6 +745,7 @@ class TestViews(TestCase):
|
|
|
738
745
|
|
|
739
746
|
url = reverse("delete_account")
|
|
740
747
|
c.post(url, {"password": password2})
|
|
748
|
+
self.assertEqual(mock_send_dotdigital_email.call_count, 3)
|
|
741
749
|
|
|
742
750
|
# school should be anonymised
|
|
743
751
|
school = School._base_manager.get(id=school_id)
|
portal/views/registration.py
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
import re
|
|
3
|
-
|
|
4
|
-
from common.email_messages import accountDeletionEmail
|
|
5
|
-
from portal.views.login import has_user_lockout_expired
|
|
6
|
-
|
|
7
|
-
from django.contrib.auth.models import User
|
|
8
3
|
from datetime import datetime
|
|
4
|
+
|
|
9
5
|
from common.helpers.emails import (
|
|
10
|
-
delete_contact,
|
|
11
6
|
NOTIFICATION_EMAIL,
|
|
12
7
|
PASSWORD_RESET_EMAIL,
|
|
8
|
+
delete_contact,
|
|
13
9
|
send_email,
|
|
14
10
|
)
|
|
15
|
-
from common.
|
|
16
|
-
from common.
|
|
17
|
-
|
|
11
|
+
from common.mail import campaign_ids, send_dotdigital_email
|
|
12
|
+
from common.models import DailyActivity, Student, Teacher
|
|
13
|
+
from common.permissions import not_fully_logged_in, not_logged_in
|
|
18
14
|
from django.contrib import messages as messages
|
|
19
15
|
from django.contrib.auth import get_user_model
|
|
20
|
-
from django.contrib.auth.decorators import
|
|
16
|
+
from django.contrib.auth.decorators import login_required, user_passes_test
|
|
21
17
|
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm
|
|
18
|
+
from django.contrib.auth.models import User
|
|
22
19
|
from django.contrib.auth.tokens import default_token_generator
|
|
23
20
|
from django.http import HttpResponseRedirect
|
|
24
21
|
from django.shortcuts import render
|
|
@@ -35,14 +32,15 @@ from django.views.decorators.http import require_POST
|
|
|
35
32
|
from deploy import captcha
|
|
36
33
|
from portal import app_settings
|
|
37
34
|
from portal.forms.registration import (
|
|
38
|
-
TeacherPasswordResetForm,
|
|
39
|
-
TeacherPasswordResetSetPasswordForm,
|
|
40
35
|
StudentPasswordResetForm,
|
|
41
36
|
StudentPasswordResetSetPasswordForm,
|
|
37
|
+
TeacherPasswordResetForm,
|
|
38
|
+
TeacherPasswordResetSetPasswordForm,
|
|
42
39
|
)
|
|
43
40
|
from portal.helpers.captcha import remove_captcha_from_form
|
|
44
41
|
from portal.helpers.ratelimit import clear_ratelimit_cache_for_user
|
|
45
42
|
from portal.views.api import anonymise
|
|
43
|
+
from portal.views.login import has_user_lockout_expired
|
|
46
44
|
|
|
47
45
|
|
|
48
46
|
@user_passes_test(not_logged_in, login_url=reverse_lazy("home"))
|
|
@@ -309,13 +307,6 @@ def delete_account(request):
|
|
|
309
307
|
delete_contact(email)
|
|
310
308
|
|
|
311
309
|
# send confirmation email
|
|
312
|
-
|
|
313
|
-
send_email(
|
|
314
|
-
NOTIFICATION_EMAIL,
|
|
315
|
-
[email],
|
|
316
|
-
message["subject"],
|
|
317
|
-
message["message"],
|
|
318
|
-
message["title"],
|
|
319
|
-
)
|
|
310
|
+
send_dotdigital_email(campaign_ids["delete_account"], [email])
|
|
320
311
|
|
|
321
312
|
return HttpResponseRedirect(reverse_lazy("home"))
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
from common.
|
|
2
|
-
|
|
1
|
+
from common.helpers.emails import (
|
|
2
|
+
NOTIFICATION_EMAIL,
|
|
3
|
+
delete_contact,
|
|
4
|
+
send_email,
|
|
5
|
+
update_indy_email,
|
|
6
|
+
)
|
|
3
7
|
from common.models import Student
|
|
4
8
|
from common.permissions import logged_in_as_student
|
|
5
9
|
from django.contrib import messages as messages
|
|
@@ -7,17 +11,15 @@ from django.contrib.auth import logout
|
|
|
7
11
|
from django.contrib.auth.decorators import login_required, user_passes_test
|
|
8
12
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
9
13
|
from django.http import HttpResponseRedirect
|
|
14
|
+
from django.shortcuts import render
|
|
10
15
|
from django.urls import reverse_lazy
|
|
11
16
|
from django.views.generic.edit import FormView
|
|
12
|
-
from django.shortcuts import render
|
|
13
17
|
|
|
14
|
-
from portal.forms.play import
|
|
18
|
+
from portal.forms.play import IndependentStudentEditAccountForm, StudentEditAccountForm
|
|
15
19
|
from portal.forms.registration import DeleteAccountForm
|
|
16
|
-
|
|
17
20
|
from portal.helpers.password import check_update_password
|
|
18
21
|
from portal.helpers.ratelimit import clear_ratelimit_cache_for_user
|
|
19
22
|
from portal.views.api import anonymise
|
|
20
|
-
from django.contrib import messages as messages
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
def _get_form(self, form_class):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|