From e1b783ead98ba0c557237c7cd23af59d71306f4b Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Mon, 8 May 2023 15:03:10 -0300 Subject: [PATCH 01/21] chore: Update requirements.txt for Django 3.0 --- requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index d3989d3f2..b46adf3dd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # -*- conf-mode -*- -setuptools>=51.1.0 # Require this first, to prevent later errors +setuptools>=51.1.0,<67.5.0 # Require this first, to prevent later errors # argon2-cffi>=21.3.0 # For the Argon2 password hasher option beautifulsoup4>=4.11.1 # Only used in tests @@ -9,7 +9,7 @@ celery>=5.2.6 coverage>=4.5.4,<5.0 # Coverage 5.x moves from a json database to SQLite. Moving to 5.x will require substantial rewrites in ietf.utils.test_runner and ietf.release.views decorator>=5.1.1 defusedxml>=0.7.1 # for TastyPie when using xml; not a declared dependency -Django>=2.2.28,<3.0 +Django<3.1 django-analytical>=3.1.0 django-bootstrap5>=21.3 django-celery-beat>=2.3.0 @@ -46,7 +46,7 @@ mypy>=0.782,<0.790 # Version requirements determined by django-stubs. mysqlclient>=2.1.0 oic>=1.3 # Used only by tests Pillow>=9.1.0 -psycopg2<2.9 +psycopg2>=2.9 pyang>=2.5.3 pyflakes>=2.4.0 pyopenssl>=22.0.0 # Used by urllib3.contrib, which is used by PyQuery but not marked as a dependency From 9fda268853b013e80ca7b5baf532377e095f1653 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Mon, 8 May 2023 15:19:33 -0300 Subject: [PATCH 02/21] fix: Replace `available_attrs` helper (dropped by Django 3.0) --- ietf/ietfauth/utils.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ietf/ietfauth/utils.py b/ietf/ietfauth/utils.py index 029342e7f..702b0199d 100644 --- a/ietf/ietfauth/utils.py +++ b/ietf/ietfauth/utils.py @@ -7,7 +7,7 @@ import oidc_provider.lib.claims -from functools import wraps +from functools import wraps, WRAPPER_ASSIGNMENTS from django.conf import settings from django.contrib.auth import REDIRECT_FIELD_NAME @@ -15,7 +15,6 @@ from django.core.exceptions import PermissionDenied from django.db.models import Q from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 -from django.utils.decorators import available_attrs from django.utils.http import urlquote import debug # pyflakes:ignore @@ -113,7 +112,7 @@ def passes_test_decorator(test_func, message): error. The test function should be on the form fn(user) -> true/false.""" def decorate(view_func): - @wraps(view_func, assigned=available_attrs(view_func)) + @wraps(view_func, assigned=WRAPPER_ASSIGNMENTS) def inner(request, *args, **kwargs): if not request.user.is_authenticated: return HttpResponseRedirect('%s?%s=%s' % (settings.LOGIN_URL, REDIRECT_FIELD_NAME, urlquote(request.get_full_path()))) From 6d4d09542f6d5dcc627f9af849ff932f7f29624e Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Mon, 8 May 2023 22:55:15 -0300 Subject: [PATCH 03/21] fix: Replace obsolete `curry()` with `functools.partialmethod()` --- ietf/meeting/views.py | 10 +++++----- ietf/secr/telechat/views.py | 7 ++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 28beaa113..87b48a7a2 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -17,6 +17,7 @@ import tempfile from calendar import timegm from collections import OrderedDict, Counter, deque, defaultdict, namedtuple +from functools import partialmethod from urllib.parse import parse_qs, unquote, urlencode, urlsplit, urlunsplit from tempfile import mkstemp from wsgiref.handlers import format_date_time @@ -38,7 +39,6 @@ from django.template import TemplateDoesNotExist from django.template.loader import render_to_string from django.utils import timezone from django.utils.encoding import force_str -from django.utils.functional import curry from django.utils.text import slugify from django.views.decorators.cache import cache_page from django.views.decorators.csrf import ensure_csrf_cookie, csrf_exempt @@ -3210,8 +3210,8 @@ def interim_request(request): if meeting_type in ('single', 'multi-day'): meeting = form.save(date=get_earliest_session_date(formset)) - # need to use curry here to pass custom variable to form init - SessionFormset.form.__init__ = curry( + # need to use partialmethod here to pass custom variable to form init + SessionFormset.form.__init__ = partialmethod( InterimSessionModelForm.__init__, user=request.user, group=group, @@ -3233,7 +3233,7 @@ def interim_request(request): # subsequently dealt with individually elif meeting_type == 'series': series = [] - SessionFormset.form.__init__ = curry( + SessionFormset.form.__init__ = partialmethod( InterimSessionModelForm.__init__, user=request.user, group=group, @@ -3453,7 +3453,7 @@ def interim_request_edit(request, number): group = Group.objects.get(pk=form.data['group']) is_approved = is_interim_meeting_approved(meeting) - SessionFormset.form.__init__ = curry( + SessionFormset.form.__init__ = partialmethod( InterimSessionModelForm.__init__, user=request.user, group=group, diff --git a/ietf/secr/telechat/views.py b/ietf/secr/telechat/views.py index 4dd4fba4e..f13a082f2 100644 --- a/ietf/secr/telechat/views.py +++ b/ietf/secr/telechat/views.py @@ -4,10 +4,11 @@ import datetime +from functools import partialmethod + from django.contrib import messages from django.forms.formsets import formset_factory from django.shortcuts import render, get_object_or_404, redirect -from django.utils.functional import curry import debug # pyflakes:ignore @@ -215,7 +216,7 @@ def doc_detail(request, date, name): initial_state = {'state':doc.get_state(state_type).pk, 'substate':tag} - # need to use curry here to pass custom variable to form init + # need to use partialmethod here to pass custom variable to form init if doc.active_ballot(): ballot_type = doc.active_ballot().ballot_type elif doc.type.slug == 'draft': @@ -223,7 +224,7 @@ def doc_detail(request, date, name): else: ballot_type = BallotType.objects.get(doc_type=doc.type) BallotFormset = formset_factory(BallotForm, extra=0) - BallotFormset.form.__init__ = curry(BallotForm.__init__, ballot_type=ballot_type) + BallotFormset.form.__init__ = partialmethod(BallotForm.__init__, ballot_type=ballot_type) agenda = agenda_data(date=date) header = get_section_header(doc, agenda) From 9fde845719c6f68732f949a3fba6a6600ccebbd9 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Tue, 9 May 2023 11:05:43 -0300 Subject: [PATCH 04/21] chore: Revert psycopg2 dependency Try again with Django 3.2 --- requirements.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index b46adf3dd..05d7e9d16 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,7 +16,6 @@ django-celery-beat>=2.3.0 django-csp>=3.7 django-cors-headers>=3.11.0 django-debug-toolbar>=3.2.4 -django-form-utils>=1.0.3 # Only one use, in the liaisons app. Last release was in 2015. django-markup>=1.5 # Limited use - need to reconcile against direct use of markdown django-oidc-provider>=0.7 django-password-strength>=1.2.1 @@ -46,7 +45,7 @@ mypy>=0.782,<0.790 # Version requirements determined by django-stubs. mysqlclient>=2.1.0 oic>=1.3 # Used only by tests Pillow>=9.1.0 -psycopg2>=2.9 +psycopg2<2.9 pyang>=2.5.3 pyflakes>=2.4.0 pyopenssl>=22.0.0 # Used by urllib3.contrib, which is used by PyQuery but not marked as a dependency From 2cf2a3dee69bbc15dcfac30c8bbaaf7929418389 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Tue, 9 May 2023 11:09:41 -0300 Subject: [PATCH 05/21] chore: Remove django-cookie-delete-with-all-settings.patch Patch no longer applies. Needed until Django 4.2.1, so bring it back if we deploy something earlier than that to production. --- ietf/settings.py | 4 +- ...ango-cookie-delete-with-all-settings.patch | 46 ------------------- 2 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 patch/django-cookie-delete-with-all-settings.patch diff --git a/ietf/settings.py b/ietf/settings.py index 00e7f292f..cbbc6d418 100644 --- a/ietf/settings.py +++ b/ietf/settings.py @@ -76,7 +76,7 @@ MANAGERS = ADMINS DATABASES = { 'default': { 'NAME': 'datatracker', - 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'ENGINE': 'django.db.backends.postgresql', 'USER': 'ietf', #'PASSWORD': 'somepassword', }, @@ -430,7 +430,6 @@ INSTALLED_APPS = [ 'corsheaders', 'django_markup', 'django_password_strength', - 'form_utils', 'oidc_provider', 'simple_history', 'tastypie', @@ -1123,7 +1122,6 @@ CHECKS_LIBRARY_PATCHES_TO_APPLY = [ 'patch/fix-jwkest-jwt-logging.patch', 'patch/fix-django-password-strength-kwargs.patch', 'patch/add-django-http-cookie-value-none.patch', - 'patch/django-cookie-delete-with-all-settings.patch', 'patch/tastypie-django22-fielderror-response.patch', ] if DEBUG: diff --git a/patch/django-cookie-delete-with-all-settings.patch b/patch/django-cookie-delete-with-all-settings.patch deleted file mode 100644 index 830f031d7..000000000 --- a/patch/django-cookie-delete-with-all-settings.patch +++ /dev/null @@ -1,46 +0,0 @@ ---- django/contrib/messages/storage/cookie.py.orig 2020-08-13 11:10:36.719177122 +0200 -+++ django/contrib/messages/storage/cookie.py 2020-08-13 11:45:23.503463150 +0200 -@@ -92,6 +92,8 @@ - response.delete_cookie( - self.cookie_name, - domain=settings.SESSION_COOKIE_DOMAIN, -+ secure=settings.SESSION_COOKIE_SECURE or None, -+ httponly=settings.SESSION_COOKIE_HTTPONLY or None, - samesite=settings.SESSION_COOKIE_SAMESITE, - ) - ---- django/http/response.py.orig 2020-08-13 11:16:04.060627793 +0200 -+++ django/http/response.py 2020-08-13 11:54:03.482476973 +0200 -@@ -210,12 +210,18 @@ - value = signing.get_cookie_signer(salt=key + salt).sign(value) - return self.set_cookie(key, value, **kwargs) - -- def delete_cookie(self, key, path='/', domain=None, samesite=None): -+ def delete_cookie(self, key, path='/', domain=None, secure=False, httponly=False, samesite=None): - # Most browsers ignore the Set-Cookie header if the cookie name starts - # with __Host- or __Secure- and the cookie doesn't use the secure flag. -- secure = key.startswith(('__Secure-', '__Host-')) -+ if key in self.cookies: -+ domain = self.cookies[key].get('domain', domain) -+ secure = self.cookies[key].get('secure', secure) -+ httponly = self.cookies[key].get('httponly', httponly) -+ samesite = self.cookies[key].get('samesite', samesite) -+ else: -+ secure = secure or key.startswith(('__Secure-', '__Host-')) - self.set_cookie( -- key, max_age=0, path=path, domain=domain, secure=secure, -+ key, max_age=0, path=path, domain=domain, secure=secure, httponly=httponly, - expires='Thu, 01 Jan 1970 00:00:00 GMT', samesite=samesite, - ) - ---- django/contrib/sessions/middleware.py.orig 2020-08-13 12:12:12.401898114 +0200 -+++ django/contrib/sessions/middleware.py 2020-08-13 12:14:52.690520659 +0200 -@@ -39,6 +39,8 @@ - settings.SESSION_COOKIE_NAME, - path=settings.SESSION_COOKIE_PATH, - domain=settings.SESSION_COOKIE_DOMAIN, -+ secure=settings.SESSION_COOKIE_SECURE or None, -+ httponly=settings.SESSION_COOKIE_HTTPONLY or None, - samesite=settings.SESSION_COOKIE_SAMESITE, - ) - else: From 07e26dd52e08ff6dfcfc0a8d39d729f8e576b631 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Tue, 9 May 2023 15:21:50 -0300 Subject: [PATCH 06/21] refactor: Replace deprecated force_text with force_str --- ietf/api/serializer.py | 2 +- ietf/doc/mails.py | 10 +++++----- ietf/doc/models.py | 6 +++--- ietf/doc/templatetags/ietf_filters.py | 5 ++--- ietf/doc/utils_charter.py | 4 ++-- ietf/doc/views_charter.py | 4 ++-- ietf/doc/views_status_change.py | 4 ++-- ietf/group/admin.py | 4 ++-- ietf/ipr/feeds.py | 4 ++-- ietf/ipr/mail.py | 4 ++-- ietf/liaisons/forms.py | 2 +- ietf/nomcom/templatetags/nomcom_tags.py | 4 ++-- ietf/nomcom/views.py | 4 ++-- ietf/person/factories.py | 4 ++-- ietf/submit/mail.py | 4 ++-- ietf/submit/tests.py | 8 ++++---- ietf/sync/rfceditor.py | 4 ++-- ietf/utils/accesstoken.py | 4 ++-- ietf/utils/admin.py | 4 ++-- ietf/utils/mail.py | 10 +++++----- ietf/utils/management/commands/loadrelated.py | 4 ++-- ietf/utils/management/commands/mergedata.py | 4 ++-- 22 files changed, 51 insertions(+), 52 deletions(-) diff --git a/ietf/api/serializer.py b/ietf/api/serializer.py index 9d6cf1ebb..8340fa8be 100644 --- a/ietf/api/serializer.py +++ b/ietf/api/serializer.py @@ -221,7 +221,7 @@ class JsonExportMixin(object): # obj = None # # if obj is None: -# raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_text(self.model._meta.verbose_name), 'key': escape(object_id)}) +# raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_str(self.model._meta.verbose_name), 'key': escape(object_id)}) # # content_type = 'application/json' # return HttpResponse(serialize([ obj ], sort_keys=True, indent=3)[2:-2], content_type=content_type) diff --git a/ietf/doc/mails.py b/ietf/doc/mails.py index ddb2843cc..8f5d0eb67 100644 --- a/ietf/doc/mails.py +++ b/ietf/doc/mails.py @@ -11,7 +11,7 @@ from django.utils.html import strip_tags from django.conf import settings from django.urls import reverse as urlreverse from django.utils import timezone -from django.utils.encoding import force_text +from django.utils.encoding import force_str import debug # pyflakes:ignore from ietf.doc.templatetags.mail_filters import std_level_prompt @@ -175,7 +175,7 @@ def generate_ballot_writeup(request, doc): e.doc = doc e.rev = doc.rev e.desc = "Ballot writeup was generated" - e.text = force_text(render_to_string("doc/mail/ballot_writeup.txt", {'iana': iana, 'doc': doc })) + e.text = force_str(render_to_string("doc/mail/ballot_writeup.txt", {'iana': iana, 'doc': doc })) # caller is responsible for saving, if necessary return e @@ -187,7 +187,7 @@ def generate_ballot_rfceditornote(request, doc): e.doc = doc e.rev = doc.rev e.desc = "RFC Editor Note for ballot was generated" - e.text = force_text(render_to_string("doc/mail/ballot_rfceditornote.txt")) + e.text = force_str(render_to_string("doc/mail/ballot_rfceditornote.txt")) e.save() return e @@ -232,7 +232,7 @@ def generate_last_call_announcement(request, doc): e.doc = doc e.rev = doc.rev e.desc = "Last call announcement was generated" - e.text = force_text(mail) + e.text = force_str(mail) # caller is responsible for saving, if necessary return e @@ -252,7 +252,7 @@ def generate_approval_mail(request, doc): e.doc = doc e.rev = doc.rev e.desc = "Ballot approval text was generated" - e.text = force_text(mail) + e.text = force_str(mail) # caller is responsible for saving, if necessary return e diff --git a/ietf/doc/models.py b/ietf/doc/models.py index ee56c0dc3..2181490c0 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -23,7 +23,7 @@ from django.urls import reverse as urlreverse from django.contrib.contenttypes.models import ContentType from django.conf import settings from django.utils import timezone -from django.utils.encoding import force_text +from django.utils.encoding import force_str from django.utils.html import mark_safe # type:ignore from django.contrib.staticfiles import finders @@ -1131,7 +1131,7 @@ class DocHistory(DocumentInfo): name = models.CharField(max_length=255) def __str__(self): - return force_text(self.doc.name) + return force_str(self.doc.name) def get_related_session(self): return self.doc.get_related_session() @@ -1193,7 +1193,7 @@ class DocAlias(models.Model): return self.docs.first() def __str__(self): - return u"%s-->%s" % (self.name, ','.join([force_text(d.name) for d in self.docs.all() if isinstance(d, Document) ])) + return u"%s-->%s" % (self.name, ','.join([force_str(d.name) for d in self.docs.all() if isinstance(d, Document) ])) document_link = admin_link("document") class Meta: verbose_name = "document alias" diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py index 332e5ca15..1c5836328 100644 --- a/ietf/doc/templatetags/ietf_filters.py +++ b/ietf/doc/templatetags/ietf_filters.py @@ -13,8 +13,7 @@ from django.utils.html import escape from django.template.defaultfilters import truncatewords_html, linebreaksbr, stringfilter, striptags from django.utils.safestring import mark_safe, SafeData from django.utils.html import strip_tags -from django.utils.encoding import force_text -from django.utils.encoding import force_str # pyflakes:ignore force_str is used in the doctests +from django.utils.encoding import force_str from django.urls import reverse as urlreverse from django.core.cache import cache from django.core.exceptions import ValidationError @@ -132,7 +131,7 @@ register.filter('fill', fill) @register.filter def prettystdname(string, space=" "): from ietf.doc.utils import prettify_std_name - return prettify_std_name(force_text(string or ""), space) + return prettify_std_name(force_str(string or ""), space) @register.filter def rfceditor_info_url(rfcnum : str): diff --git a/ietf/doc/utils_charter.py b/ietf/doc/utils_charter.py index d14684d42..84dc70c8c 100644 --- a/ietf/doc/utils_charter.py +++ b/ietf/doc/utils_charter.py @@ -12,7 +12,7 @@ from django.conf import settings from django.urls import reverse as urlreverse from django.template.loader import render_to_string from django.utils import timezone -from django.utils.encoding import smart_text, force_text +from django.utils.encoding import smart_text, force_str import debug # pyflakes:ignore @@ -153,7 +153,7 @@ def generate_ballot_writeup(request, doc): e.doc = doc e.rev = doc.rev, e.desc = "Ballot writeup was generated" - e.text = force_text(render_to_string("doc/charter/ballot_writeup.txt")) + e.text = force_str(render_to_string("doc/charter/ballot_writeup.txt")) # caller is responsible for saving, if necessary return e diff --git a/ietf/doc/views_charter.py b/ietf/doc/views_charter.py index c49710895..d3173291d 100644 --- a/ietf/doc/views_charter.py +++ b/ietf/doc/views_charter.py @@ -17,7 +17,7 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required from django.utils import timezone -from django.utils.encoding import force_text +from django.utils.encoding import force_str from django.utils.html import escape import debug # pyflakes:ignore @@ -821,7 +821,7 @@ def charter_with_milestones_txt(request, name, rev): try: with io.open(os.path.join(settings.CHARTER_PATH, filename), 'r') as f: - charter_text = force_text(f.read(), errors='ignore') + charter_text = force_str(f.read(), errors='ignore') except IOError: charter_text = "Error reading charter text %s" % filename diff --git a/ietf/doc/views_status_change.py b/ietf/doc/views_status_change.py index 99f82d435..9a878bc54 100644 --- a/ietf/doc/views_status_change.py +++ b/ietf/doc/views_status_change.py @@ -15,7 +15,7 @@ from django.http import Http404, HttpResponseRedirect from django.urls import reverse from django.template.loader import render_to_string from django.conf import settings -from django.utils.encoding import force_text +from django.utils.encoding import force_str from django.utils.html import escape import debug # pyflakes:ignore @@ -665,7 +665,7 @@ def generate_last_call_text(request, doc): e.doc = doc e.rev = doc.rev e.desc = 'Last call announcement was generated' - e.text = force_text(new_text) + e.text = force_str(new_text) e.save() return e diff --git a/ietf/group/admin.py b/ietf/group/admin.py index 0773a4ce2..d6cbf5f1b 100644 --- a/ietf/group/admin.py +++ b/ietf/group/admin.py @@ -14,7 +14,7 @@ from django.contrib.admin.utils import unquote from django.core.management import load_command_class from django.http import Http404 from django.shortcuts import render -from django.utils.encoding import force_text +from django.utils.encoding import force_str from django.utils.html import escape from django.utils.translation import ugettext as _ @@ -152,7 +152,7 @@ class GroupAdmin(admin.ModelAdmin): permission_denied(request, "You don't have edit permissions for this change.") if obj is None: - raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_text(opts.verbose_name), 'key': escape(object_id)}) + raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_str(opts.verbose_name), 'key': escape(object_id)}) return self.send_reminder(request, sdo=obj) diff --git a/ietf/ipr/feeds.py b/ietf/ipr/feeds.py index b5f4c4e6a..4979c649b 100644 --- a/ietf/ipr/feeds.py +++ b/ietf/ipr/feeds.py @@ -6,7 +6,7 @@ from django.contrib.syndication.views import Feed from django.utils.feedgenerator import Atom1Feed from django.urls import reverse_lazy from django.utils.safestring import mark_safe -from django.utils.encoding import force_text +from django.utils.encoding import force_str from ietf.ipr.models import IprDisclosureBase @@ -25,7 +25,7 @@ class LatestIprDisclosuresFeed(Feed): return mark_safe(item.title) def item_description(self, item): - return force_text(item.title) + return force_str(item.title) def item_pubdate(self, item): return item.time diff --git a/ietf/ipr/mail.py b/ietf/ipr/mail.py index f1d8039db..842426d82 100644 --- a/ietf/ipr/mail.py +++ b/ietf/ipr/mail.py @@ -12,7 +12,7 @@ from email import message_from_bytes from email.utils import parsedate_tz from django.template.loader import render_to_string -from django.utils.encoding import force_text, force_bytes +from django.utils.encoding import force_str, force_bytes import debug # pyflakes:ignore @@ -102,7 +102,7 @@ def get_reply_to(): address with "plus addressing" using a random string. Guaranteed to be unique""" local,domain = get_base_ipr_request_address().split('@') while True: - rand = force_text(base64.urlsafe_b64encode(os.urandom(12))) + rand = force_str(base64.urlsafe_b64encode(os.urandom(12))) address = "{}+{}@{}".format(local,rand,domain) q = Message.objects.filter(reply_to=address) if not q: diff --git a/ietf/liaisons/forms.py b/ietf/liaisons/forms.py index fa1f550d0..3dfe6e406 100644 --- a/ietf/liaisons/forms.py +++ b/ietf/liaisons/forms.py @@ -132,7 +132,7 @@ class AddCommentForm(forms.Form): # def render(self): # output = [] # for widget in self: -# output.append(format_html(force_text(widget))) +# output.append(format_html(force_str(widget))) # return mark_safe('\n'.join(output)) diff --git a/ietf/nomcom/templatetags/nomcom_tags.py b/ietf/nomcom/templatetags/nomcom_tags.py index 05a2c2e8b..c751383fb 100644 --- a/ietf/nomcom/templatetags/nomcom_tags.py +++ b/ietf/nomcom/templatetags/nomcom_tags.py @@ -6,7 +6,7 @@ import re from django import template from django.conf import settings from django.template.defaultfilters import linebreaksbr, force_escape -from django.utils.encoding import force_text, DjangoUnicodeDecodeError +from django.utils.encoding import force_str, DjangoUnicodeDecodeError from django.utils.safestring import mark_safe import debug # pyflakes:ignore @@ -68,7 +68,7 @@ def decrypt(string, request, year, plain=False): code, out, error = pipe(command % (settings.OPENSSL_COMMAND, encrypted_file.name), key) try: - out = force_text(out) + out = force_str(out) except DjangoUnicodeDecodeError: pass if code != 0: diff --git a/ietf/nomcom/views.py b/ietf/nomcom/views.py index d862b3a40..51c165bce 100644 --- a/ietf/nomcom/views.py +++ b/ietf/nomcom/views.py @@ -18,7 +18,7 @@ from django.http import Http404, HttpResponseRedirect, HttpResponse from django.shortcuts import render, get_object_or_404, redirect from django.template.loader import render_to_string from django.urls import reverse -from django.utils.encoding import force_bytes, force_text +from django.utils.encoding import force_bytes, force_str from ietf.dbtemplate.models import DBTemplate @@ -684,7 +684,7 @@ def private_questionnaire(request, year): if form.is_valid(): form.save() messages.success(request, 'The questionnaire response has been registered.') - questionnaire_response = force_text(form.cleaned_data['comment_text']) + questionnaire_response = force_str(form.cleaned_data['comment_text']) form = QuestionnaireForm(nomcom=nomcom, user=request.user) else: form = QuestionnaireForm(nomcom=nomcom, user=request.user) diff --git a/ietf/person/factories.py b/ietf/person/factories.py index 8e80932c9..4761a3f4e 100644 --- a/ietf/person/factories.py +++ b/ietf/person/factories.py @@ -16,7 +16,7 @@ from unicodedata import normalize from django.conf import settings from django.contrib.auth.models import User from django.utils.text import slugify -from django.utils.encoding import force_text +from django.utils.encoding import force_str import debug # pyflakes:ignore @@ -68,7 +68,7 @@ class PersonFactory(factory.django.DjangoModelFactory): # Some i18n names, e.g., "शिला के.सी." have a dot at the end that is also part of the ASCII, e.g., "Shilaa Kesii." # That trailing dot breaks extract_authors(). Avoid this issue by stripping the dot from the ASCII. # Some others have a trailing semicolon (e.g., "உயிரோவியம் தங்கராஐ;") - strip those, too. - ascii = factory.LazyAttribute(lambda p: force_text(unidecode_name(p.name)).rstrip(".;")) + ascii = factory.LazyAttribute(lambda p: force_str(unidecode_name(p.name)).rstrip(".;")) class Params: with_bio = factory.Trait(biography = "\n\n".join(fake.paragraphs())) # type: ignore diff --git a/ietf/submit/mail.py b/ietf/submit/mail.py index 93f97026c..1953ad81c 100644 --- a/ietf/submit/mail.py +++ b/ietf/submit/mail.py @@ -13,7 +13,7 @@ from django.urls import reverse as urlreverse from django.core.exceptions import ValidationError from django.contrib.sites.models import Site from django.template.loader import render_to_string -from django.utils.encoding import force_text, force_str +from django.utils.encoding import force_str import debug # pyflakes:ignore @@ -202,7 +202,7 @@ def get_reply_to(): address with "plus addressing" using a random string. Guaranteed to be unique""" local,domain = get_base_submission_message_address().split('@') while True: - rand = force_text(base64.urlsafe_b64encode(os.urandom(12))) + rand = force_str(base64.urlsafe_b64encode(os.urandom(12))) address = "{}+{}@{}".format(local,rand,domain) q = Message.objects.filter(reply_to=address) if not q: diff --git a/ietf/submit/tests.py b/ietf/submit/tests.py index 50a58494d..0a40b0016 100644 --- a/ietf/submit/tests.py +++ b/ietf/submit/tests.py @@ -23,7 +23,7 @@ from django.test import override_settings from django.test.client import RequestFactory from django.urls import reverse as urlreverse from django.utils import timezone -from django.utils.encoding import force_str, force_text +from django.utils.encoding import force_str import debug # pyflakes:ignore from ietf.submit.utils import (expirable_submissions, expire_submission, find_submission_filenames, @@ -701,10 +701,10 @@ class SubmitTests(BaseSubmitTestCase): self.assertTrue("New Version Notification" in outbox[-2]["Subject"]) self.assertTrue(name in get_payload_text(outbox[-2])) interesting_address = {'ietf':'mars', 'irtf':'irtf-chair', 'iab':'iab-chair', 'ise':'rfc-ise'}[draft.stream_id] - self.assertTrue(interesting_address in force_text(outbox[-2].as_string())) + self.assertTrue(interesting_address in force_str(outbox[-2].as_string())) if draft.stream_id == 'ietf': - self.assertTrue(draft.ad.role_email("ad").address in force_text(outbox[-2].as_string())) - self.assertTrue(ballot_position.balloter.role_email("ad").address in force_text(outbox[-2].as_string())) + self.assertTrue(draft.ad.role_email("ad").address in force_str(outbox[-2].as_string())) + self.assertTrue(ballot_position.balloter.role_email("ad").address in force_str(outbox[-2].as_string())) self.assertTrue("New Version Notification" in outbox[-1]["Subject"]) self.assertTrue(name in get_payload_text(outbox[-1])) r = self.client.get(urlreverse('ietf.doc.views_search.recent_drafts')) diff --git a/ietf/sync/rfceditor.py b/ietf/sync/rfceditor.py index 59356dd48..784e7a2f0 100644 --- a/ietf/sync/rfceditor.py +++ b/ietf/sync/rfceditor.py @@ -12,7 +12,7 @@ from xml.dom import pulldom, Node from django.conf import settings from django.utils import timezone -from django.utils.encoding import smart_bytes, force_str, force_text +from django.utils.encoding import smart_bytes, force_str import debug # pyflakes:ignore @@ -583,7 +583,7 @@ def post_approved_draft(url, name): if r.status_code != 200: raise RuntimeError("Status code is not 200 OK (it's %s)." % r.status_code) - if force_text(r.text) != "OK": + if force_str(r.text) != "OK": raise RuntimeError('Response is not "OK" (it\'s "%s").' % r.text) except Exception as e: diff --git a/ietf/utils/accesstoken.py b/ietf/utils/accesstoken.py index b2a93f77d..243d3f24d 100644 --- a/ietf/utils/accesstoken.py +++ b/ietf/utils/accesstoken.py @@ -5,7 +5,7 @@ import time, random, hashlib from django.conf import settings -from django.utils.encoding import force_bytes, force_text +from django.utils.encoding import force_bytes, force_str def generate_random_key(max_length=32): @@ -18,4 +18,4 @@ def generate_access_token(key, max_length=32): # we hash it with the private key to make sure only we can # generate and use the final token - so storing the key in the # database is safe - return force_text(hashlib.sha256(force_bytes(settings.SECRET_KEY) + force_bytes(key)).hexdigest()[:max_length]) + return force_str(hashlib.sha256(force_bytes(settings.SECRET_KEY) + force_bytes(key)).hexdigest()[:max_length]) diff --git a/ietf/utils/admin.py b/ietf/utils/admin.py index 3e562c2bc..fa1ebb708 100644 --- a/ietf/utils/admin.py +++ b/ietf/utils/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin -from django.utils.encoding import force_text +from django.utils.encoding import force_str from ietf.utils.models import VersionInfo @@ -14,7 +14,7 @@ def name(obj): if callable(obj.name): name = obj.name() else: - name = force_text(obj.name) + name = force_str(obj.name) if name: return name return str(obj) diff --git a/ietf/utils/mail.py b/ietf/utils/mail.py index b2b9f0b9d..e747c7477 100644 --- a/ietf/utils/mail.py +++ b/ietf/utils/mail.py @@ -27,7 +27,7 @@ from django.core.validators import validate_email from django.template.loader import render_to_string from django.template import Context,RequestContext from django.utils import timezone -from django.utils.encoding import force_text, force_str, force_bytes +from django.utils.encoding import force_str, force_bytes import debug # pyflakes:ignore @@ -137,7 +137,7 @@ def send_smtp(msg, bcc=None): server.quit() except smtplib.SMTPServerDisconnected: pass - subj = force_text(msg.get('Subject', '[no subject]')) + subj = force_str(msg.get('Subject', '[no subject]')) tau = time.time() - mark log("sent email (%.3fs) from '%s' to %s id %s subject '%s'" % (tau, frm, to, msg.get('Message-ID', ''), subj)) @@ -166,7 +166,7 @@ def copy_email(msg, to, toUser=False, originalBcc=None): # Overwrite the From: header, so that the copy from a development or # test server doesn't look like spam. new['From'] = settings.DEFAULT_FROM_EMAIL - new['Subject'] = '[Django %s] %s' % (settings.SERVER_MODE, force_text(msg.get('Subject', '[no subject]'))) + new['Subject'] = '[Django %s] %s' % (settings.SERVER_MODE, force_str(msg.get('Subject', '[no subject]'))) new['To'] = to send_smtp(new) @@ -325,7 +325,7 @@ def show_that_mail_was_sent(request,leadline,msg,bcc): from ietf.ietfauth.utils import has_role if has_role(request.user,['Area Director','Secretariat','IANA','RFC Editor','ISE','IAD','IRTF Chair','WG Chair','RG Chair','WG Secretary','RG Secretary']): info = "%s at %s %s\n" % (leadline,timezone.now().strftime("%Y-%m-%d %H:%M:%S"),settings.TIME_ZONE) - info += "Subject: %s\n" % force_text(msg.get('Subject','[no subject]')) + info += "Subject: %s\n" % force_str(msg.get('Subject','[no subject]')) info += "To: %s\n" % msg.get('To','[no to]') if msg.get('Cc'): info += "Cc: %s\n" % msg.get('Cc') @@ -336,7 +336,7 @@ def show_that_mail_was_sent(request,leadline,msg,bcc): def save_as_message(request, msg, bcc): by = ((request and request.user and not request.user.is_anonymous and request.user.person) or ietf.person.models.Person.objects.get(name="(System)")) - headers, body = force_text(str(msg)).split('\n\n', 1) + headers, body = force_str(str(msg)).split('\n\n', 1) kwargs = {'by': by, 'body': body, 'content_type': msg.get_content_type(), 'bcc': bcc or '' } for (arg, field) in [ ('cc', 'Cc'), diff --git a/ietf/utils/management/commands/loadrelated.py b/ietf/utils/management/commands/loadrelated.py index e3d84990c..da9d00d5d 100644 --- a/ietf/utils/management/commands/loadrelated.py +++ b/ietf/utils/management/commands/loadrelated.py @@ -18,7 +18,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.core import serializers from django.db import DEFAULT_DB_ALIAS, DatabaseError, IntegrityError, connections from django.db.models.signals import post_save -from django.utils.encoding import force_text +from django.utils.encoding import force_str import django.core.management.commands.loaddata as loaddata import debug # pyflakes:ignore @@ -91,7 +91,7 @@ class Command(loaddata.Command): obj.save(using=self.using) self.loaded_object_count += 1 except (DatabaseError, IntegrityError, ObjectDoesNotExist, AttributeError) as e: - error_msg = force_text(e) + error_msg = force_str(e) if "Duplicate entry" in error_msg: pass else: diff --git a/ietf/utils/management/commands/mergedata.py b/ietf/utils/management/commands/mergedata.py index 861973482..e73014c78 100644 --- a/ietf/utils/management/commands/mergedata.py +++ b/ietf/utils/management/commands/mergedata.py @@ -15,7 +15,7 @@ from django.core.management.base import CommandError from django.core.management.commands.loaddata import Command as LoadCommand, humanize from django.db import DatabaseError, IntegrityError, router, transaction from django.db.models import ManyToManyField -from django.utils.encoding import force_text +from django.utils.encoding import force_str from ietf.utils.models import ForeignKey @@ -234,7 +234,7 @@ class Command(LoadCommand): 'object_name': obj.object._meta.object_name, 'pk': obj.object.pk, 'data': obj_to_dict(obj.object), - 'error_msg': force_text(e) + 'error_msg': force_str(e) },) raise if objects and show_progress: From da168395fcb4bb75d7944093a9ef5b8bbd8af34a Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Tue, 9 May 2023 15:23:33 -0300 Subject: [PATCH 07/21] refactor: Replace deprecated smart_text with smart_str --- ietf/api/serializer.py | 12 ++++++------ ietf/doc/utils_charter.py | 4 ++-- ietf/meeting/utils.py | 4 ++-- ietf/utils/test_data.py | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ietf/api/serializer.py b/ietf/api/serializer.py index 8340fa8be..e4253bfb6 100644 --- a/ietf/api/serializer.py +++ b/ietf/api/serializer.py @@ -9,7 +9,7 @@ from django.core.cache import cache from django.core.exceptions import ObjectDoesNotExist, FieldError from django.core.serializers.json import Serializer from django.http import HttpResponse -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from django.db.models import Field from django.db.models.query import QuerySet from django.db.models.signals import post_save, post_delete, m2m_changed @@ -121,7 +121,7 @@ class AdminJsonSerializer(Serializer): for name in expansions: try: field = getattr(obj, name) - #self._current["_"+name] = smart_text(field) + #self._current["_"+name] = smart_str(field) if not isinstance(field, Field): options = self.options.copy() options["expand"] = [ v[len(name)+2:] for v in options["expand"] if v.startswith(name+"__") ] @@ -188,10 +188,10 @@ class AdminJsonSerializer(Serializer): related = related.natural_key() elif field.remote_field.field_name == related._meta.pk.name: # Related to remote object via primary key - related = smart_text(related._get_pk_val(), strings_only=True) + related = smart_str(related._get_pk_val(), strings_only=True) else: # Related to remote object via other field - related = smart_text(getattr(related, field.remote_field.field_name), strings_only=True) + related = smart_str(getattr(related, field.remote_field.field_name), strings_only=True) self._current[field.name] = related def handle_m2m_field(self, obj, field): @@ -201,7 +201,7 @@ class AdminJsonSerializer(Serializer): elif self.use_natural_keys and hasattr(field.remote_field.to, 'natural_key'): m2m_value = lambda value: value.natural_key() else: - m2m_value = lambda value: smart_text(value._get_pk_val(), strings_only=True) + m2m_value = lambda value: smart_str(value._get_pk_val(), strings_only=True) self._current[field.name] = [m2m_value(related) for related in getattr(obj, field.name).iterator()] @@ -264,6 +264,6 @@ class JsonExportMixin(object): qd = dict( ( k, json.loads(v)[0] ) for k,v in items ) except (FieldError, ValueError) as e: return HttpResponse(json.dumps({"error": str(e)}, sort_keys=True, indent=3), content_type=content_type) - text = json.dumps({smart_text(self.model._meta): qd}, sort_keys=True, indent=3) + text = json.dumps({smart_str(self.model._meta): qd}, sort_keys=True, indent=3) return HttpResponse(text, content_type=content_type) diff --git a/ietf/doc/utils_charter.py b/ietf/doc/utils_charter.py index 84dc70c8c..2e85b3cc1 100644 --- a/ietf/doc/utils_charter.py +++ b/ietf/doc/utils_charter.py @@ -12,7 +12,7 @@ from django.conf import settings from django.urls import reverse as urlreverse from django.template.loader import render_to_string from django.utils import timezone -from django.utils.encoding import smart_text, force_str +from django.utils.encoding import smart_str, force_str import debug # pyflakes:ignore @@ -197,7 +197,7 @@ def derive_new_work_text(review_text,group): 'Reply_to':''}) if not addrs.cc: del m['Cc'] - return smart_text(m.as_string()) + return smart_str(m.as_string()) def default_review_text(group, charter, by): now = timezone.now() diff --git a/ietf/meeting/utils.py b/ietf/meeting/utils.py index 1f4896c88..a99f29463 100644 --- a/ietf/meeting/utils.py +++ b/ietf/meeting/utils.py @@ -15,7 +15,7 @@ from django.conf import settings from django.contrib import messages from django.template.loader import render_to_string from django.utils import timezone -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str import debug # pyflakes:ignore @@ -699,7 +699,7 @@ def handle_upload_file(file, filename, meeting, subdir, request=None, encoding=N ) else: try: - text = smart_text(text) + text = smart_str(text) except UnicodeDecodeError as e: return "Failure trying to save '%s'. Hint: Try to upload as UTF-8: %s..." % (filename, str(e)[:120]) # Whole file sanitization; add back what's missing from a complete diff --git a/ietf/utils/test_data.py b/ietf/utils/test_data.py index 3e3324211..1e7097625 100644 --- a/ietf/utils/test_data.py +++ b/ietf/utils/test_data.py @@ -7,7 +7,7 @@ import datetime from django.conf import settings from django.contrib.auth.models import User from django.utils import timezone -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str import debug # pyflakes:ignore @@ -38,7 +38,7 @@ def create_person(group, role_name, name=None, username=None, email_address=None user = User.objects.create(username=username,is_staff=is_staff,is_superuser=is_superuser) user.set_password(password) user.save() - person = Person.objects.create(name=name, ascii=unidecode_name(smart_text(name)), user=user) + person = Person.objects.create(name=name, ascii=unidecode_name(smart_str(name)), user=user) email = Email.objects.create(address=email_address, person=person, origin=user.username) Role.objects.create(group=group, name_id=role_name, person=person, email=email) return person From 31fd43184cb9b3db59ac979fcdf5e8226f27d263 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Tue, 9 May 2023 15:39:12 -0300 Subject: [PATCH 08/21] chore: Tweak add-django-http-cookie-value-none.patch for Django 3.0 --- patch/add-django-http-cookie-value-none.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patch/add-django-http-cookie-value-none.patch b/patch/add-django-http-cookie-value-none.patch index ab75235f2..54d0f74d9 100644 --- a/patch/add-django-http-cookie-value-none.patch +++ b/patch/add-django-http-cookie-value-none.patch @@ -1,6 +1,6 @@ --- django/http/response.py.orig 2020-07-08 14:34:42.776562458 +0200 +++ django/http/response.py 2020-07-08 14:35:56.454687322 +0200 -@@ -197,8 +197,8 @@ +@@ -196,8 +196,8 @@ if httponly: self.cookies[key]['httponly'] = True if samesite: From ed571ae50b16d3e6cb6f109058ad0a46e2eaf790 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 12:40:37 -0300 Subject: [PATCH 09/21] chore: Rename DB engine to drop the deprecated "_psycopg2" suffix --- dev/deploy-to-container/settings_local.py | 2 +- dev/diff/settings_local.py | 2 +- dev/tests/settings_local.py | 2 +- docker/configs/settings_postgresqldb.py | 2 +- ietf/settings_postgrestest.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dev/deploy-to-container/settings_local.py b/dev/deploy-to-container/settings_local.py index d9bf00f22..60981ba56 100644 --- a/dev/deploy-to-container/settings_local.py +++ b/dev/deploy-to-container/settings_local.py @@ -10,7 +10,7 @@ DATABASES = { 'HOST': '__DBHOST__', 'PORT': 5432, 'NAME': 'datatracker', - 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'ENGINE': 'django.db.backends.postgresql', 'USER': 'django', 'PASSWORD': 'RkTkDPFnKpko', }, diff --git a/dev/diff/settings_local.py b/dev/diff/settings_local.py index cd3923d50..593ccadd7 100644 --- a/dev/diff/settings_local.py +++ b/dev/diff/settings_local.py @@ -10,7 +10,7 @@ DATABASES = { 'HOST': '__DBHOST__', 'PORT': 5432, 'NAME': 'datatracker', - 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'ENGINE': 'django.db.backends.postgresql', 'USER': 'django', 'PASSWORD': 'RkTkDPFnKpko', }, diff --git a/dev/tests/settings_local.py b/dev/tests/settings_local.py index fdc60a849..0cd761c0a 100644 --- a/dev/tests/settings_local.py +++ b/dev/tests/settings_local.py @@ -10,7 +10,7 @@ DATABASES = { 'HOST': 'db', 'PORT': 5432, 'NAME': 'datatracker', - 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'ENGINE': 'django.db.backends.postgresql', 'USER': 'django', 'PASSWORD': 'RkTkDPFnKpko', }, diff --git a/docker/configs/settings_postgresqldb.py b/docker/configs/settings_postgresqldb.py index fe0c827ff..05d19b9a8 100644 --- a/docker/configs/settings_postgresqldb.py +++ b/docker/configs/settings_postgresqldb.py @@ -3,7 +3,7 @@ DATABASES = { 'HOST': 'db', 'PORT': 5432, 'NAME': 'datatracker', - 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'ENGINE': 'django.db.backends.postgresql', 'USER': 'django', 'PASSWORD': 'RkTkDPFnKpko', }, diff --git a/ietf/settings_postgrestest.py b/ietf/settings_postgrestest.py index 450fd9180..13bbc9239 100755 --- a/ietf/settings_postgrestest.py +++ b/ietf/settings_postgrestest.py @@ -39,7 +39,7 @@ DATABASES = { 'HOST': 'db', 'PORT': '5432', 'NAME': 'test.db', - 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'ENGINE': 'django.db.backends.postgresql', 'USER': 'django', 'PASSWORD': 'RkTkDPFnKpko', }, From 69eb6340fd568b59d937a9bc50c386288ae8af91 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 15:41:36 -0300 Subject: [PATCH 10/21] test: Do not misuse django.conf.settings for HTML validation params --- ietf/utils/test_runner.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/ietf/utils/test_runner.py b/ietf/utils/test_runner.py index 7453b40a4..281b22724 100644 --- a/ietf/utils/test_runner.py +++ b/ietf/utils/test_runner.py @@ -95,7 +95,7 @@ old_create = None template_coverage_collection = None code_coverage_collection = None url_coverage_collection = None - +validation_settings = {"validate_html": None, "validate_html_harder": None, "show_logging": False} def start_vnu_server(port=8888): "Start a vnu validation server on the indicated port" @@ -282,7 +282,7 @@ class ValidatingTemplates(DjangoTemplates): def __init__(self, params): super().__init__(params) - if not settings.validate_html: + if not validation_settings["validate_html"]: return self.validation_cache = set() self.cwd = str(pathlib.Path.cwd()) @@ -298,7 +298,7 @@ class ValidatingTemplate(Template): def render(self, context=None, request=None): content = super().render(context, request) - if not settings.validate_html: + if not validation_settings["validate_html"]: return content if not self.origin.name.endswith("html"): @@ -310,7 +310,7 @@ class ValidatingTemplate(Template): return content fingerprint = hash(content) + sys.maxsize + 1 # make hash positive - if not settings.validate_html_harder and fingerprint in self.backend.validation_cache: + if not validation_settings["validate_html_harder"] and fingerprint in self.backend.validation_cache: # already validated this HTML fragment, skip it # as an optimization, make page a bit smaller by not returning HTML for the menus # FIXME: figure out why this still includes base/menu.html @@ -326,7 +326,7 @@ class ValidatingTemplate(Template): # don't validate each template by itself, causes too much overhead # instead, save a batch of them and then validate them all in one go # this delays error detection a bit, but is MUCH faster - settings.validate_html.batches[kind].append( + validation_settings["validate_html"].batches[kind].append( (self.origin.name, content, fingerprint) ) return content @@ -726,9 +726,10 @@ class IetfTestRunner(DiscoverRunner): self.html_report = html_report self.permit_mixed_migrations = permit_mixed_migrations self.show_logging = show_logging - settings.validate_html = self if validate_html else None - settings.validate_html_harder = self if validate_html and validate_html_harder else None - settings.show_logging = show_logging + global validation_settings + validation_settings["validate_html"] = self if validate_html else None + validation_settings["validate_html_harder"] = self if validate_html and validate_html_harder else None + validation_settings["show_logging"] = show_logging # self.root_dir = os.path.dirname(settings.BASE_DIR) self.coverage_file = os.path.join(self.root_dir, settings.TEST_COVERAGE_MAIN_FILE) @@ -843,7 +844,7 @@ class IetfTestRunner(DiscoverRunner): s[1] = tuple(s[1]) # random.setstate() won't accept a list in lieu of a tuple factory.random.set_random_state(s) - if not settings.validate_html: + if not validation_settings["validate_html"]: print(" Not validating any generated HTML; " "please do so at least once before committing changes") else: @@ -912,7 +913,7 @@ class IetfTestRunner(DiscoverRunner): self.config_file[kind].flush() pathlib.Path(self.config_file[kind].name).chmod(0o644) - if not settings.validate_html_harder: + if not validation_settings["validate_html_harder"]: print("") self.vnu = None else: @@ -941,7 +942,7 @@ class IetfTestRunner(DiscoverRunner): with open(self.coverage_file, "w") as file: json.dump(self.coverage_master, file, indent=2, sort_keys=True) - if settings.validate_html: + if validation_settings["validate_html"]: for kind in self.batches: if len(self.batches[kind]): print(f" WARNING: not all templates of kind '{kind}' were validated") @@ -1007,7 +1008,7 @@ class IetfTestRunner(DiscoverRunner): + "\n" ) - if settings.validate_html_harder and kind != "frag": + if validation_settings["validate_html_harder"] and kind != "frag": files = [ os.path.join(d, f) for d, dirs, files in os.walk(tmppath) @@ -1084,7 +1085,7 @@ class IetfTestRunner(DiscoverRunner): self.test_apps, self.test_paths = self.get_test_paths(test_labels) - if settings.validate_html: + if validation_settings["validate_html"]: extra_tests += [ TemplateValidationTests( test_runner=self, From 57026bbb5f69b7e4cd81daa93d17061e031b533d Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 15:55:25 -0300 Subject: [PATCH 11/21] Revert "chore: Remove django-cookie-delete-with-all-settings.patch" This reverts commit 2cf2a3dee69bbc15dcfac30c8bbaaf7929418389. --- ietf/settings.py | 4 +- ...ango-cookie-delete-with-all-settings.patch | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 patch/django-cookie-delete-with-all-settings.patch diff --git a/ietf/settings.py b/ietf/settings.py index cbbc6d418..00e7f292f 100644 --- a/ietf/settings.py +++ b/ietf/settings.py @@ -76,7 +76,7 @@ MANAGERS = ADMINS DATABASES = { 'default': { 'NAME': 'datatracker', - 'ENGINE': 'django.db.backends.postgresql', + 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'USER': 'ietf', #'PASSWORD': 'somepassword', }, @@ -430,6 +430,7 @@ INSTALLED_APPS = [ 'corsheaders', 'django_markup', 'django_password_strength', + 'form_utils', 'oidc_provider', 'simple_history', 'tastypie', @@ -1122,6 +1123,7 @@ CHECKS_LIBRARY_PATCHES_TO_APPLY = [ 'patch/fix-jwkest-jwt-logging.patch', 'patch/fix-django-password-strength-kwargs.patch', 'patch/add-django-http-cookie-value-none.patch', + 'patch/django-cookie-delete-with-all-settings.patch', 'patch/tastypie-django22-fielderror-response.patch', ] if DEBUG: diff --git a/patch/django-cookie-delete-with-all-settings.patch b/patch/django-cookie-delete-with-all-settings.patch new file mode 100644 index 000000000..830f031d7 --- /dev/null +++ b/patch/django-cookie-delete-with-all-settings.patch @@ -0,0 +1,46 @@ +--- django/contrib/messages/storage/cookie.py.orig 2020-08-13 11:10:36.719177122 +0200 ++++ django/contrib/messages/storage/cookie.py 2020-08-13 11:45:23.503463150 +0200 +@@ -92,6 +92,8 @@ + response.delete_cookie( + self.cookie_name, + domain=settings.SESSION_COOKIE_DOMAIN, ++ secure=settings.SESSION_COOKIE_SECURE or None, ++ httponly=settings.SESSION_COOKIE_HTTPONLY or None, + samesite=settings.SESSION_COOKIE_SAMESITE, + ) + +--- django/http/response.py.orig 2020-08-13 11:16:04.060627793 +0200 ++++ django/http/response.py 2020-08-13 11:54:03.482476973 +0200 +@@ -210,12 +210,18 @@ + value = signing.get_cookie_signer(salt=key + salt).sign(value) + return self.set_cookie(key, value, **kwargs) + +- def delete_cookie(self, key, path='/', domain=None, samesite=None): ++ def delete_cookie(self, key, path='/', domain=None, secure=False, httponly=False, samesite=None): + # Most browsers ignore the Set-Cookie header if the cookie name starts + # with __Host- or __Secure- and the cookie doesn't use the secure flag. +- secure = key.startswith(('__Secure-', '__Host-')) ++ if key in self.cookies: ++ domain = self.cookies[key].get('domain', domain) ++ secure = self.cookies[key].get('secure', secure) ++ httponly = self.cookies[key].get('httponly', httponly) ++ samesite = self.cookies[key].get('samesite', samesite) ++ else: ++ secure = secure or key.startswith(('__Secure-', '__Host-')) + self.set_cookie( +- key, max_age=0, path=path, domain=domain, secure=secure, ++ key, max_age=0, path=path, domain=domain, secure=secure, httponly=httponly, + expires='Thu, 01 Jan 1970 00:00:00 GMT', samesite=samesite, + ) + +--- django/contrib/sessions/middleware.py.orig 2020-08-13 12:12:12.401898114 +0200 ++++ django/contrib/sessions/middleware.py 2020-08-13 12:14:52.690520659 +0200 +@@ -39,6 +39,8 @@ + settings.SESSION_COOKIE_NAME, + path=settings.SESSION_COOKIE_PATH, + domain=settings.SESSION_COOKIE_DOMAIN, ++ secure=settings.SESSION_COOKIE_SECURE or None, ++ httponly=settings.SESSION_COOKIE_HTTPONLY or None, + samesite=settings.SESSION_COOKIE_SAMESITE, + ) + else: From 21ac8c067d5ad9587ef4fe88e6e611bf05cd5808 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 16:50:11 -0300 Subject: [PATCH 12/21] chore: Fix cookie-delete patch to work with Django 3.0 --- ...ango-cookie-delete-with-all-settings.patch | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/patch/django-cookie-delete-with-all-settings.patch b/patch/django-cookie-delete-with-all-settings.patch index 830f031d7..eb9d0a6c6 100644 --- a/patch/django-cookie-delete-with-all-settings.patch +++ b/patch/django-cookie-delete-with-all-settings.patch @@ -11,7 +11,7 @@ --- django/http/response.py.orig 2020-08-13 11:16:04.060627793 +0200 +++ django/http/response.py 2020-08-13 11:54:03.482476973 +0200 -@@ -210,12 +210,18 @@ +@@ -209,12 +209,18 @@ value = signing.get_cookie_signer(salt=key + salt).sign(value) return self.set_cookie(key, value, **kwargs) @@ -35,12 +35,12 @@ --- django/contrib/sessions/middleware.py.orig 2020-08-13 12:12:12.401898114 +0200 +++ django/contrib/sessions/middleware.py 2020-08-13 12:14:52.690520659 +0200 -@@ -39,6 +39,8 @@ - settings.SESSION_COOKIE_NAME, - path=settings.SESSION_COOKIE_PATH, - domain=settings.SESSION_COOKIE_DOMAIN, -+ secure=settings.SESSION_COOKIE_SECURE or None, -+ httponly=settings.SESSION_COOKIE_HTTPONLY or None, - samesite=settings.SESSION_COOKIE_SAMESITE, - ) - else: +@@ -38,6 +38,8 @@ + settings.SESSION_COOKIE_NAME, + path=settings.SESSION_COOKIE_PATH, + domain=settings.SESSION_COOKIE_DOMAIN, ++ secure=settings.SESSION_COOKIE_SECURE or None, ++ httponly=settings.SESSION_COOKIE_HTTPONLY or None, + samesite=settings.SESSION_COOKIE_SAMESITE, + ) + patch_vary_headers(response, ('Cookie',)) From a75dbd4f40d9fdf27292a8ee06e4cff1ccd00e68 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 16:50:42 -0300 Subject: [PATCH 13/21] chore: Remove accidentally reverted removal of form_utils app --- ietf/settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ietf/settings.py b/ietf/settings.py index 00e7f292f..207619f7e 100644 --- a/ietf/settings.py +++ b/ietf/settings.py @@ -430,7 +430,6 @@ INSTALLED_APPS = [ 'corsheaders', 'django_markup', 'django_password_strength', - 'form_utils', 'oidc_provider', 'simple_history', 'tastypie', From 85d0934ba0b57934414c263d1ee6c4afc7c01a98 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 17:03:31 -0300 Subject: [PATCH 14/21] refactor: Refactor LiaisonForm without BetterModelForm --- ietf/liaisons/forms.py | 10 +------ ietf/templates/liaisons/edit.html | 45 +++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/ietf/liaisons/forms.py b/ietf/liaisons/forms.py index 3dfe6e406..01aa935dc 100644 --- a/ietf/liaisons/forms.py +++ b/ietf/liaisons/forms.py @@ -9,7 +9,6 @@ import operator from typing import Union # pyflakes:ignore from email.utils import parseaddr -from form_utils.forms import BetterModelForm from django import forms from django.conf import settings @@ -213,7 +212,7 @@ class CustomModelMultipleChoiceField(forms.ModelMultipleChoiceField): return super(CustomModelMultipleChoiceField, self).prepare_value(value) -class LiaisonModelForm(BetterModelForm): +class LiaisonModelForm(forms.ModelForm): '''Specify fields which require a custom widget or that are not part of the model. ''' from_groups = forms.ModelMultipleChoiceField(queryset=Group.objects.all(),label='Groups',required=False) @@ -238,13 +237,6 @@ class LiaisonModelForm(BetterModelForm): class Meta: model = LiaisonStatement exclude = ('attachments','state','from_name','to_name') - fieldsets = [('From', {'fields': ['from_groups','from_contact', 'response_contacts'], 'legend': ''}), - ('To', {'fields': ['to_groups','to_contacts'], 'legend': ''}), - ('Other email addresses', {'fields': ['technical_contacts','action_holder_contacts','cc_contacts'], 'legend': ''}), - ('Purpose', {'fields':['purpose', 'deadline'], 'legend': ''}), - ('Reference', {'fields': ['other_identifiers','related_to'], 'legend': ''}), - ('Liaison Statement', {'fields': ['title', 'submitted_date', 'body', 'attachments'], 'legend': ''}), - ('Add attachment', {'fields': ['attach_title', 'attach_file', 'attach_button'], 'legend': ''})] def __init__(self, user, *args, **kwargs): super(LiaisonModelForm, self).__init__(*args, **kwargs) diff --git a/ietf/templates/liaisons/edit.html b/ietf/templates/liaisons/edit.html index 2c7b4b65b..30cc4b00e 100644 --- a/ietf/templates/liaisons/edit.html +++ b/ietf/templates/liaisons/edit.html @@ -47,21 +47,38 @@ method="post" enctype="multipart/form-data" data-edit-form="{{ form.edit }}" - data-ajax-info-url="{% url "ietf.liaisons.views.ajax_get_liaison_info" %}"> + data-ajax-info-url="{% url 'ietf.liaisons.views.ajax_get_liaison_info' %}"> {% csrf_token %} - {% for fieldset in form.fieldsets %} -

{{ fieldset.name }}

- {% for field in fieldset %} - {% if field.id_for_label != "id_attachments" %} - {% bootstrap_field field layout="horizontal" %} - {% else %} -
-

{{ field.label }}

-
{{ field }}
-
- {% endif %} - {% endfor %} - {% endfor %} +

From

+ {% bootstrap_field form.from_groups layout="horizontal" %} + {% bootstrap_field form.from_contact layout="horizontal" %} + {% bootstrap_field form.response_contacts layout="horizontal" %} +

To

+ {% bootstrap_field form.to_groups layout="horizontal" %} + {% bootstrap_field form.to_contacts layout="horizontal" %} +

Other email addresses

+ {% bootstrap_field form.technical_contacts layout="horizontal" %} + {% bootstrap_field form.action_holder_contacts layout="horizontal" %} + {% bootstrap_field form.cc_contacts layout="horizontal" %} +

Purpose

+ {% bootstrap_field form.purpose layout="horizontal" %} + {% bootstrap_field form.deadline layout="horizontal" %} +

Reference

+ {% bootstrap_field form.other_identifiers layout="horizontal" %} + {% bootstrap_field form.related_to layout="horizontal" %} +

Liaison Statement

+ {% bootstrap_field form.title layout="horizontal" %} + {% bootstrap_field form.submitted_date layout="horizontal" %} + {% bootstrap_field form.body layout="horizontal" %} +
+

{{ form.attachments.label }}

+
{{ form.attachments }}
+
+

Add attachment

+ {% bootstrap_field form.attach_title layout="horizontal" %} + {% bootstrap_field form.attach_file layout="horizontal" %} + {% bootstrap_field form.attach_button layout="horizontal" %} + Cancel From 163479bc06aafefdd69ba63b16cfd0b21dcabe9f Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 17:12:34 -0300 Subject: [PATCH 15/21] refactor: Replace obsolete `staticfiles` template lib with `static` --- ietf/secr/templates/announcement/confirm.html | 2 +- ietf/secr/templates/areas/list.html | 2 +- ietf/secr/templates/areas/people.html | 2 +- ietf/secr/templates/areas/view.html | 2 +- ietf/secr/templates/base_secr.html | 2 +- ietf/secr/templates/base_secr_bootstrap.html | 2 +- ietf/secr/templates/base_site.html | 2 +- ietf/secr/templates/base_site_bootstrap.html | 2 +- ietf/secr/templates/confirm_cancel.html | 2 +- ietf/secr/templates/confirm_delete.html | 2 +- ietf/secr/templates/meetings/add.html | 2 +- ietf/secr/templates/meetings/base_rooms_times.html | 2 +- ietf/secr/templates/meetings/blue_sheet.html | 2 +- ietf/secr/templates/meetings/edit_meeting.html | 2 +- ietf/secr/templates/meetings/main.html | 2 +- ietf/secr/templates/meetings/notifications.html | 2 +- ietf/secr/templates/meetings/regular_session_edit.html | 2 +- ietf/secr/templates/meetings/view.html | 2 +- ietf/secr/templates/rolodex/add.html | 2 +- ietf/secr/templates/rolodex/edit.html | 2 +- ietf/secr/templates/rolodex/search.html | 2 +- ietf/secr/templates/sreq/confirm.html | 2 +- ietf/secr/templates/sreq/edit.html | 2 +- ietf/secr/templates/sreq/locked.html | 2 +- ietf/secr/templates/sreq/main.html | 2 +- ietf/secr/templates/sreq/new.html | 2 +- ietf/secr/templates/sreq/tool_status.html | 2 +- ietf/secr/templates/sreq/view.html | 2 +- ietf/secr/templates/telechat/base_telechat.html | 2 +- .../meeting/edit_meeting_timeslots_and_misc_sessions.html | 2 +- ietf/templates/meeting/new_meeting_schedule.html | 2 +- ietf/templates/meeting/previously_approved_slides.html | 2 +- 32 files changed, 32 insertions(+), 32 deletions(-) diff --git a/ietf/secr/templates/announcement/confirm.html b/ietf/secr/templates/announcement/confirm.html index 7ad745a09..ddf2a6de6 100644 --- a/ietf/secr/templates/announcement/confirm.html +++ b/ietf/secr/templates/announcement/confirm.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Announcement{% endblock %} diff --git a/ietf/secr/templates/areas/list.html b/ietf/secr/templates/areas/list.html index a0ed1ae4a..0d9946efc 100644 --- a/ietf/secr/templates/areas/list.html +++ b/ietf/secr/templates/areas/list.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Areas{% endblock %} {% block extrahead %}{{ block.super }} diff --git a/ietf/secr/templates/areas/people.html b/ietf/secr/templates/areas/people.html index e84dc1a79..168089f52 100644 --- a/ietf/secr/templates/areas/people.html +++ b/ietf/secr/templates/areas/people.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Areas - People{% endblock %} {% block extrahead %}{{ block.super }} diff --git a/ietf/secr/templates/areas/view.html b/ietf/secr/templates/areas/view.html index e3ecac70a..2bcb9619c 100644 --- a/ietf/secr/templates/areas/view.html +++ b/ietf/secr/templates/areas/view.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Areas - View{% endblock %} {% block extrahead %}{{ block.super }} diff --git a/ietf/secr/templates/base_secr.html b/ietf/secr/templates/base_secr.html index 47b893f04..18d77e47b 100644 --- a/ietf/secr/templates/base_secr.html +++ b/ietf/secr/templates/base_secr.html @@ -1,5 +1,5 @@ -{% load staticfiles %} +{% load static %} diff --git a/ietf/secr/templates/base_secr_bootstrap.html b/ietf/secr/templates/base_secr_bootstrap.html index 2eee566a1..a32634684 100644 --- a/ietf/secr/templates/base_secr_bootstrap.html +++ b/ietf/secr/templates/base_secr_bootstrap.html @@ -1,5 +1,5 @@ -{% load staticfiles %} +{% load static %} diff --git a/ietf/secr/templates/base_site.html b/ietf/secr/templates/base_site.html index d369a40ec..5e3ddc62d 100644 --- a/ietf/secr/templates/base_site.html +++ b/ietf/secr/templates/base_site.html @@ -1,7 +1,7 @@ {% extends "base_secr.html" %} {% load i18n %} {% load ietf_filters %} -{% load staticfiles %} +{% load static %} {% block title %}{{ title }}{% if user|has_role:"Secretariat" %} Secretariat Dashboard {% else %} IETF Dashboard {% endif %}{% endblock %} diff --git a/ietf/secr/templates/base_site_bootstrap.html b/ietf/secr/templates/base_site_bootstrap.html index c1c2fdac6..1653b26b8 100644 --- a/ietf/secr/templates/base_site_bootstrap.html +++ b/ietf/secr/templates/base_site_bootstrap.html @@ -1,7 +1,7 @@ {% extends "base_secr_bootstrap.html" %} {% load i18n %} {% load ietf_filters %} -{% load staticfiles %} +{% load static %} {% block title %}{{ title }}{% if user|has_role:"Secretariat" %} Secretariat Dashboard {% else %} WG Chair Dashboard {% endif %}{% endblock %} diff --git a/ietf/secr/templates/confirm_cancel.html b/ietf/secr/templates/confirm_cancel.html index 6bae631a7..541c82863 100644 --- a/ietf/secr/templates/confirm_cancel.html +++ b/ietf/secr/templates/confirm_cancel.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Confirm Cancel{% endblock %} diff --git a/ietf/secr/templates/confirm_delete.html b/ietf/secr/templates/confirm_delete.html index ccfc7b1c2..3f8fd19c8 100644 --- a/ietf/secr/templates/confirm_delete.html +++ b/ietf/secr/templates/confirm_delete.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Confirm Delete{% endblock %} diff --git a/ietf/secr/templates/meetings/add.html b/ietf/secr/templates/meetings/add.html index 5a7825526..b2cc2617d 100644 --- a/ietf/secr/templates/meetings/add.html +++ b/ietf/secr/templates/meetings/add.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Meetings - Add{% endblock %} diff --git a/ietf/secr/templates/meetings/base_rooms_times.html b/ietf/secr/templates/meetings/base_rooms_times.html index f856b1f62..263418fab 100644 --- a/ietf/secr/templates/meetings/base_rooms_times.html +++ b/ietf/secr/templates/meetings/base_rooms_times.html @@ -1,5 +1,5 @@ {% extends "base_site_bootstrap.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Meetings{% endblock %} diff --git a/ietf/secr/templates/meetings/blue_sheet.html b/ietf/secr/templates/meetings/blue_sheet.html index d67efd9f6..9bda80f2e 100644 --- a/ietf/secr/templates/meetings/blue_sheet.html +++ b/ietf/secr/templates/meetings/blue_sheet.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Meetings - Blue Sheet{% endblock %} diff --git a/ietf/secr/templates/meetings/edit_meeting.html b/ietf/secr/templates/meetings/edit_meeting.html index 773536e65..474373dbe 100644 --- a/ietf/secr/templates/meetings/edit_meeting.html +++ b/ietf/secr/templates/meetings/edit_meeting.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Meetings - Edit{% endblock %} diff --git a/ietf/secr/templates/meetings/main.html b/ietf/secr/templates/meetings/main.html index 90c380289..ff110dd97 100755 --- a/ietf/secr/templates/meetings/main.html +++ b/ietf/secr/templates/meetings/main.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Meetings{% endblock %} diff --git a/ietf/secr/templates/meetings/notifications.html b/ietf/secr/templates/meetings/notifications.html index bf7099577..dbe66ff28 100644 --- a/ietf/secr/templates/meetings/notifications.html +++ b/ietf/secr/templates/meetings/notifications.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Meetings{% endblock %} diff --git a/ietf/secr/templates/meetings/regular_session_edit.html b/ietf/secr/templates/meetings/regular_session_edit.html index fbfba4f96..9993858be 100644 --- a/ietf/secr/templates/meetings/regular_session_edit.html +++ b/ietf/secr/templates/meetings/regular_session_edit.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles tz %} +{% load static tz %} {% block title %}Meetings{% endblock %} diff --git a/ietf/secr/templates/meetings/view.html b/ietf/secr/templates/meetings/view.html index d552d38dc..d54346dae 100644 --- a/ietf/secr/templates/meetings/view.html +++ b/ietf/secr/templates/meetings/view.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Meetings{% endblock %} diff --git a/ietf/secr/templates/rolodex/add.html b/ietf/secr/templates/rolodex/add.html index 272b844fa..5adb738f2 100644 --- a/ietf/secr/templates/rolodex/add.html +++ b/ietf/secr/templates/rolodex/add.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Rolodex - Add{% endblock %} diff --git a/ietf/secr/templates/rolodex/edit.html b/ietf/secr/templates/rolodex/edit.html index 28a125f10..ed4c0f97e 100644 --- a/ietf/secr/templates/rolodex/edit.html +++ b/ietf/secr/templates/rolodex/edit.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Rolodex - Edit{% endblock %} diff --git a/ietf/secr/templates/rolodex/search.html b/ietf/secr/templates/rolodex/search.html index 8994cfabd..065b0463f 100644 --- a/ietf/secr/templates/rolodex/search.html +++ b/ietf/secr/templates/rolodex/search.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Rolodex - Search{% endblock %} diff --git a/ietf/secr/templates/sreq/confirm.html b/ietf/secr/templates/sreq/confirm.html index 4215c89c3..025375af3 100755 --- a/ietf/secr/templates/sreq/confirm.html +++ b/ietf/secr/templates/sreq/confirm.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Sessions - Confirm{% endblock %} diff --git a/ietf/secr/templates/sreq/edit.html b/ietf/secr/templates/sreq/edit.html index b0bfbc1e0..f6e62104b 100755 --- a/ietf/secr/templates/sreq/edit.html +++ b/ietf/secr/templates/sreq/edit.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Sessions - Edit{% endblock %} {% block extrahead %}{{ block.super }} diff --git a/ietf/secr/templates/sreq/locked.html b/ietf/secr/templates/sreq/locked.html index 5f619f37c..c27cf578e 100755 --- a/ietf/secr/templates/sreq/locked.html +++ b/ietf/secr/templates/sreq/locked.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Sessions{% endblock %} diff --git a/ietf/secr/templates/sreq/main.html b/ietf/secr/templates/sreq/main.html index bdb33bb77..a6695cd4f 100755 --- a/ietf/secr/templates/sreq/main.html +++ b/ietf/secr/templates/sreq/main.html @@ -1,6 +1,6 @@ {% extends "base_site.html" %} {% load ietf_filters %} -{% load staticfiles %} +{% load static %} {% block title %}Sessions{% endblock %} diff --git a/ietf/secr/templates/sreq/new.html b/ietf/secr/templates/sreq/new.html index 2c6afb557..3f46e6f89 100755 --- a/ietf/secr/templates/sreq/new.html +++ b/ietf/secr/templates/sreq/new.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Sessions- New{% endblock %} diff --git a/ietf/secr/templates/sreq/tool_status.html b/ietf/secr/templates/sreq/tool_status.html index cf5131c22..b91e73a12 100755 --- a/ietf/secr/templates/sreq/tool_status.html +++ b/ietf/secr/templates/sreq/tool_status.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Sessions{% endblock %} diff --git a/ietf/secr/templates/sreq/view.html b/ietf/secr/templates/sreq/view.html index c7ae2d27b..9a0a3b01c 100644 --- a/ietf/secr/templates/sreq/view.html +++ b/ietf/secr/templates/sreq/view.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Sessions - View{% endblock %} diff --git a/ietf/secr/templates/telechat/base_telechat.html b/ietf/secr/templates/telechat/base_telechat.html index 73d42ea71..1c8feaff6 100644 --- a/ietf/secr/templates/telechat/base_telechat.html +++ b/ietf/secr/templates/telechat/base_telechat.html @@ -1,5 +1,5 @@ {% extends "base_site.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Telechat{% endblock %} diff --git a/ietf/templates/meeting/edit_meeting_timeslots_and_misc_sessions.html b/ietf/templates/meeting/edit_meeting_timeslots_and_misc_sessions.html index 214845035..5e51ab5a8 100644 --- a/ietf/templates/meeting/edit_meeting_timeslots_and_misc_sessions.html +++ b/ietf/templates/meeting/edit_meeting_timeslots_and_misc_sessions.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {# Copyright The IETF Trust 2015-2020, All Rights Reserved #} {% load origin %} -{% load staticfiles %} +{% load static %} {% load ietf_filters %} {% load django_bootstrap5 %} {% block title %}{{ schedule.name }}: IETF {{ meeting.number }} meeting agenda{% endblock %} diff --git a/ietf/templates/meeting/new_meeting_schedule.html b/ietf/templates/meeting/new_meeting_schedule.html index c93d72b2a..d1b5263c5 100644 --- a/ietf/templates/meeting/new_meeting_schedule.html +++ b/ietf/templates/meeting/new_meeting_schedule.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {# Copyright The IETF Trust 2015-2020, All Rights Reserved #} {% load origin %} -{% load staticfiles %} +{% load static %} {% load ietf_filters %} {% load django_bootstrap5 %} {% block content %} diff --git a/ietf/templates/meeting/previously_approved_slides.html b/ietf/templates/meeting/previously_approved_slides.html index 060be438e..25a4c9786 100644 --- a/ietf/templates/meeting/previously_approved_slides.html +++ b/ietf/templates/meeting/previously_approved_slides.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {# Copyright The IETF Trust 2020, All Rights Reserved #} -{% load origin staticfiles django_bootstrap5 %} +{% load origin static django_bootstrap5 %} {% block title %} Approved Slides for {{ submission.session.meeting }} : {{ submission.session.group.acronym }} {% endblock %} From 4f443cc44538da4fbee1243d0558569c8f36806e Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 17:16:20 -0300 Subject: [PATCH 16/21] refactor: Explicitly allow name=None for a couple of views --- ietf/doc/views_status_change.py | 2 +- ietf/meeting/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ietf/doc/views_status_change.py b/ietf/doc/views_status_change.py index 9a878bc54..ec914eebe 100644 --- a/ietf/doc/views_status_change.py +++ b/ietf/doc/views_status_change.py @@ -531,7 +531,7 @@ def rfc_status_changes(request): ) @role_required("Area Director","Secretariat") -def start_rfc_status_change(request,name): +def start_rfc_status_change(request, name=None): """Start the RFC status change review process, setting the initial shepherding AD, and possibly putting the review on a telechat.""" if name: diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 87b48a7a2..873bdad75 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -2730,7 +2730,7 @@ def upload_session_agenda(request, session_id, num): }) -def upload_session_slides(request, session_id, num, name): +def upload_session_slides(request, session_id, num, name=None): # num is redundant, but we're dragging it along an artifact of where we are in the current URL structure session = get_object_or_404(Session,pk=session_id) if not session.can_manage_materials(request.user): From 1015cf83f83f3c6e7df542290f814131c6ae1812 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 18:47:36 -0300 Subject: [PATCH 17/21] fix: Finish refactoring LiaisonModelForm subclasses without BetterModelForm --- ietf/liaisons/forms.py | 8 -------- ietf/templates/liaisons/edit.html | 7 ++++++- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/ietf/liaisons/forms.py b/ietf/liaisons/forms.py index 01aa935dc..2c2811375 100644 --- a/ietf/liaisons/forms.py +++ b/ietf/liaisons/forms.py @@ -468,14 +468,6 @@ class OutgoingLiaisonForm(LiaisonModelForm): class Meta: model = LiaisonStatement exclude = ('attachments','state','from_name','to_name','action_holder_contacts') - # add approved field, no action_holder_contacts - fieldsets = [('From', {'fields': ['from_groups','from_contact','response_contacts','approved'], 'legend': ''}), - ('To', {'fields': ['to_groups','to_contacts'], 'legend': ''}), - ('Other email addresses', {'fields': ['technical_contacts','cc_contacts'], 'legend': ''}), - ('Purpose', {'fields':['purpose', 'deadline'], 'legend': ''}), - ('Reference', {'fields': ['other_identifiers','related_to'], 'legend': ''}), - ('Liaison Statement', {'fields': ['title', 'submitted_date', 'body', 'attachments'], 'legend': ''}), - ('Add attachment', {'fields': ['attach_title', 'attach_file', 'attach_button'], 'legend': ''})] def is_approved(self): return self.cleaned_data['approved'] diff --git a/ietf/templates/liaisons/edit.html b/ietf/templates/liaisons/edit.html index 30cc4b00e..c8023e50c 100644 --- a/ietf/templates/liaisons/edit.html +++ b/ietf/templates/liaisons/edit.html @@ -53,12 +53,17 @@ {% bootstrap_field form.from_groups layout="horizontal" %} {% bootstrap_field form.from_contact layout="horizontal" %} {% bootstrap_field form.response_contacts layout="horizontal" %} + {% if form.approved %} + {% bootstrap_field form.approved layout="horizontal" %} + {% endif %}

To

{% bootstrap_field form.to_groups layout="horizontal" %} {% bootstrap_field form.to_contacts layout="horizontal" %}

Other email addresses

{% bootstrap_field form.technical_contacts layout="horizontal" %} - {% bootstrap_field form.action_holder_contacts layout="horizontal" %} + {% if form.action_holder_contacts %} + {% bootstrap_field form.action_holder_contacts layout="horizontal" %} + {% endif %} {% bootstrap_field form.cc_contacts layout="horizontal" %}

Purpose

{% bootstrap_field form.purpose layout="horizontal" %} From e6259a521874b68a3b4c33d0a1b80aa0933b7c9f Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 18:52:52 -0300 Subject: [PATCH 18/21] chore: Remove filter on staticfiles DeprecationWarning --- ietf/settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ietf/settings.py b/ietf/settings.py index 207619f7e..5af6c7530 100644 --- a/ietf/settings.py +++ b/ietf/settings.py @@ -16,7 +16,6 @@ warnings.simplefilter("always", DeprecationWarning) warnings.filterwarnings("ignore", message="'urllib3\[secure\]' extra is deprecated") warnings.filterwarnings("ignore", message="The logout\(\) view is superseded by") warnings.filterwarnings("ignore", message="Report.file_reporters will no longer be available in Coverage.py 4.2", module="coverage.report") -warnings.filterwarnings("ignore", message="{% load staticfiles %} is deprecated") warnings.filterwarnings("ignore", message="Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated", module="bleach") warnings.filterwarnings("ignore", message="HTTPResponse.getheader\(\) is deprecated", module='selenium.webdriver') try: From 406ba7bf0bb8778b569c84dad04277b2d740cb26 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 19:18:30 -0300 Subject: [PATCH 19/21] style: Apply Black style to active_group_types() view --- ietf/group/views.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/ietf/group/views.py b/ietf/group/views.py index 4d83a6b4c..1749912ea 100644 --- a/ietf/group/views.py +++ b/ietf/group/views.py @@ -300,8 +300,26 @@ def active_groups(request, group_type=None): raise Http404 def active_group_types(request): - grouptypes = GroupTypeName.objects.filter(slug__in=['wg','rg','ag','rag','team','dir','review','area','program','iabasg','adm']).filter(group__state='active').annotate(group_count=Count('group')) - return render(request, 'group/active_groups.html', {'grouptypes':grouptypes}) + grouptypes = ( + GroupTypeName.objects.filter( + slug__in=[ + "wg", + "rg", + "ag", + "rag", + "team", + "dir", + "review", + "area", + "program", + "iabasg", + "adm", + ] + ) + .filter(group__state="active") + .annotate(group_count=Count("group")) + ) + return render(request, "group/active_groups.html", {"grouptypes": grouptypes}) def active_dirs(request): dirs = Group.objects.filter(type__in=['dir', 'review'], state="active").order_by("name") From eee145ee6728cc15f5b75711c4b435a1e1d58452 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 19:19:39 -0300 Subject: [PATCH 20/21] fix: Explicitly order GroupTypeNames in active_group_types Relying on Meta.ordering to order querysets involving GROUP BY queries is deprecated and will be dropped in Django 3.1. --- ietf/group/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ietf/group/views.py b/ietf/group/views.py index 1749912ea..95bf4c5e9 100644 --- a/ietf/group/views.py +++ b/ietf/group/views.py @@ -317,6 +317,7 @@ def active_group_types(request): ] ) .filter(group__state="active") + .order_by('order', 'name') # default ordering ignored for "GROUP BY" queries, make it explicit .annotate(group_count=Count("group")) ) return render(request, "group/active_groups.html", {"grouptypes": grouptypes}) From 0d070597b482cafa8db814e9c8e74bf5f2a11c34 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 10 May 2023 19:21:47 -0300 Subject: [PATCH 21/21] style: Double backslashes in strings Not sure why, but if I change the DeprecationWarning filter to "error", I get a SyntaxError from the \[ because it is an invalid escape sequence. Not sure why that change triggers it, but "\[" and "\\[" are the same, so this is a no-op. --- ietf/settings.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ietf/settings.py b/ietf/settings.py index 5af6c7530..c08918c7e 100644 --- a/ietf/settings.py +++ b/ietf/settings.py @@ -13,11 +13,11 @@ import warnings from typing import Any, Dict, List, Tuple # pyflakes:ignore warnings.simplefilter("always", DeprecationWarning) -warnings.filterwarnings("ignore", message="'urllib3\[secure\]' extra is deprecated") -warnings.filterwarnings("ignore", message="The logout\(\) view is superseded by") +warnings.filterwarnings("ignore", message="'urllib3\\[secure\\]' extra is deprecated") +warnings.filterwarnings("ignore", message="The logout\\(\\) view is superseded by") warnings.filterwarnings("ignore", message="Report.file_reporters will no longer be available in Coverage.py 4.2", module="coverage.report") warnings.filterwarnings("ignore", message="Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated", module="bleach") -warnings.filterwarnings("ignore", message="HTTPResponse.getheader\(\) is deprecated", module='selenium.webdriver') +warnings.filterwarnings("ignore", message="HTTPResponse.getheader\\(\\) is deprecated", module='selenium.webdriver') try: import syslog syslog.openlog(str("datatracker"), syslog.LOG_PID, syslog.LOG_USER)