Merge pull request from jennifer-richards/django32

chore: Upgrade to Django 3.2
This commit is contained in:
Jennifer Richards 2023-05-16 12:54:14 -03:00 committed by GitHub
commit 0d5ecea42e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 231 additions and 149 deletions

View file

@ -11,9 +11,10 @@ from django.core.serializers.json import Serializer
from django.http import HttpResponse
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
from django_stubs_ext import QuerySetAny
import debug # pyflakes:ignore
@ -145,7 +146,7 @@ class AdminJsonSerializer(Serializer):
field_value = None
else:
field_value = field
if isinstance(field_value, QuerySet) or isinstance(field_value, list):
if isinstance(field_value, QuerySetAny) or isinstance(field_value, list):
self._current[name] = dict([ (rel.pk, self.expand_related(rel, name)) for rel in field_value ])
else:
if hasattr(field_value, "_meta"):

View file

@ -1,7 +1,7 @@
# Copyright The IETF Trust 2017, All Rights Reserved
from django.conf import settings
from django.conf.urls import include
from django.urls import include
from django.views.generic import TemplateView
from ietf import api

View file

@ -22,6 +22,7 @@ from ietf.community.utils import docs_tracked_by_community_list, docs_matching_c
from ietf.community.utils import states_of_significant_change, reset_name_contains_index_for_rule
from ietf.doc.models import DocEvent, Document
from ietf.doc.utils_search import prepare_document_table
from ietf.utils.http import is_ajax
from ietf.utils.response import permission_denied
def view_list(request, username=None):
@ -142,7 +143,7 @@ def track_document(request, name, username=None, acronym=None):
if not doc in clist.added_docs.all():
clist.added_docs.add(doc)
if request.is_ajax():
if is_ajax(request):
return HttpResponse(json.dumps({ 'success': True }), content_type='application/json')
else:
return HttpResponseRedirect(clist.get_absolute_url())
@ -162,7 +163,7 @@ def untrack_document(request, name, username=None, acronym=None):
if clist.pk is not None:
clist.added_docs.remove(doc)
if request.is_ajax():
if is_ajax(request):
return HttpResponse(json.dumps({ 'success': True }), content_type='application/json')
else:
return HttpResponseRedirect(clist.get_absolute_url())

View file

@ -1779,7 +1779,7 @@ class DocTestCase(TestCase):
self.client.login(username='ad', password='ad+password')
r = self.client.post(urlreverse('ietf.doc.views_status_change.change_state',kwargs=dict(name=doc.name)),dict(new_state=iesgeval_pk))
self.assertEqual(r.status_code, 302)
r = self.client.get(r._headers["location"][1])
r = self.client.get(r.headers["location"])
self.assertContains(r, ">IESG Evaluation<")
self.assertEqual(len(outbox), 2)
self.assertIn('iesg-secretary',outbox[0]['To'])

View file

@ -33,9 +33,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from django.conf.urls import include
from django.views.generic import RedirectView
from django.conf import settings
from django.urls import include
from django.views.generic import RedirectView
from ietf.doc import views_search, views_draft, views_ballot, views_status_change, views_doc, views_downref, views_stats, views_help, views_bofreq
from ietf.utils.urls import url

View file

@ -11,7 +11,7 @@ import requests
import email.utils
from django.utils import timezone
from django.utils.http import is_safe_url
from django.utils.http import url_has_allowed_host_and_scheme
from simple_history.utils import update_change_reason
@ -53,6 +53,7 @@ from ietf.utils.textupload import get_cleaned_text_file_content
from ietf.utils.mail import send_mail_message
from ietf.mailtrigger.utils import gather_address_lists
from ietf.utils.fields import MultiEmailField
from ietf.utils.http import is_ajax
from ietf.utils.response import permission_denied
from ietf.utils.timezone import date_today, DEADLINE_TZINFO
@ -1087,11 +1088,16 @@ def review_wishes_remove(request, name):
def _generate_ajax_or_redirect_response(request, doc):
redirect_url = request.GET.get('next')
url_is_safe = is_safe_url(url=redirect_url, allowed_hosts=request.get_host(),
require_https=request.is_secure())
if request.is_ajax():
return HttpResponse(json.dumps({'success': True}), content_type='application/json')
redirect_url = request.GET.get("next")
url_is_safe = url_has_allowed_host_and_scheme(
url=redirect_url,
allowed_hosts=request.get_host(),
require_https=request.is_secure(),
)
if is_ajax(request):
return HttpResponse(
json.dumps({"success": True}), content_type="application/json"
)
elif url_is_safe:
return HttpResponseRedirect(redirect_url)
else:

View file

@ -25,7 +25,6 @@ from ietf.utils.timezone import date_today
epochday = datetime.datetime.utcfromtimestamp(0).date().toordinal()
column_chart_conf = settings.CHART_TYPE_COLUMN_OPTIONS
def dt(s):
"Convert the date string returned by sqlite's date() to a datetime.date"

View file

@ -16,7 +16,7 @@ from django.http import Http404
from django.shortcuts import render
from django.utils.encoding import force_str
from django.utils.html import escape
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
from ietf.group.models import (Group, GroupFeatures, GroupHistory, GroupEvent, GroupURL, GroupMilestone,
GroupMilestoneHistory, GroupStateTransitions, Role, RoleHistory, ChangeStateGroupEvent,

View file

@ -1,7 +1,7 @@
# Copyright The IETF Trust 2013-2020, All Rights Reserved
from django.conf import settings
from django.conf.urls import include
from django.urls import include
from django.views.generic import RedirectView
from ietf.community import views as community_views

View file

@ -11,14 +11,14 @@ from django.core.exceptions import ValidationError
from django.db import models
from django.contrib.auth.models import User
from django_password_strength.widgets import PasswordStrengthInput, PasswordConfirmationInput
import debug # pyflakes:ignore
from ietf.person.models import Person, Email
from ietf.mailinglists.models import Allowlisted
from ietf.utils.text import isascii
from .widgets import PasswordStrengthInput, PasswordConfirmationInput
class RegistrationForm(forms.Form):
email = forms.EmailField(label="Your email (lowercase)")

View file

@ -8,6 +8,7 @@ import oidc_provider.lib.claims
from functools import wraps, WRAPPER_ASSIGNMENTS
from urllib.parse import quote as urlquote
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
@ -15,7 +16,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.http import urlquote
import debug # pyflakes:ignore

114
ietf/ietfauth/widgets.py Normal file
View file

@ -0,0 +1,114 @@
from django.forms import PasswordInput
from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _
# The PasswordStrengthInput and PasswordConfirmationInput widgets come from the
# django-password-strength project, https://pypi.org/project/django-password-strength/
#
# Original license:
#
# Copyright &copy; 2015 A.J. May and individual contributors. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
# following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
# products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
class PasswordStrengthInput(PasswordInput):
"""
Form widget to show the user how strong his/her password is.
"""
def render(self, name, value, attrs=None, renderer=None):
strength_markup = """
<div style="margin-top: 10px;">
<div class="progress" style="margin-bottom: 10px;">
<div class="progress-bar progress-bar-warning password_strength_bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="5" style="width: 0%%"></div>
</div>
<p class="text-muted password_strength_info hidden">
<span class="label label-danger">
%s
</span>
<span style="margin-left:5px;">
%s
</span>
</p>
</div>
""" % (
_("Warning"),
_(
'This password would take <em class="password_strength_time"></em> to crack.'
),
)
try:
self.attrs["class"] = "%s password_strength".strip() % self.attrs["class"]
except KeyError:
self.attrs["class"] = "password_strength"
return mark_safe(
super(PasswordInput, self).render(name, value, attrs, renderer)
+ strength_markup
)
class Media:
js = (
"ietf/js/zxcvbn.js",
"ietf/js/password_strength.js",
)
class PasswordConfirmationInput(PasswordInput):
"""
Form widget to confirm the users password by letting him/her type it again.
"""
def __init__(self, confirm_with=None, attrs=None, render_value=False):
super(PasswordConfirmationInput, self).__init__(attrs, render_value)
self.confirm_with = confirm_with
def render(self, name, value, attrs=None, renderer=None):
if self.confirm_with:
self.attrs["data-confirm-with"] = "id_%s" % self.confirm_with
confirmation_markup = """
<div style="margin-top: 10px;" class="hidden password_strength_info">
<p class="text-muted">
<span class="label label-danger">
%s
</span>
<span style="margin-left:5px;">%s</span>
</p>
</div>
""" % (
_("Warning"),
_("Your passwords don't match."),
)
try:
self.attrs["class"] = (
"%s password_confirmation".strip() % self.attrs["class"]
)
except KeyError:
self.attrs["class"] = "password_confirmation"
return mark_safe(
super(PasswordInput, self).render(name, value, attrs, renderer)
+ confirmation_markup
)

View file

@ -13,11 +13,11 @@ from email.utils import parseaddr
from django import forms
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db.models.query import QuerySet
from django.forms.utils import ErrorList
from django.db.models import Q
#from django.forms.widgets import RadioFieldRenderer
from django.core.validators import validate_email
from django_stubs_ext import QuerySetAny
import debug # pyflakes:ignore
@ -203,7 +203,7 @@ class SearchLiaisonForm(forms.Form):
class CustomModelMultipleChoiceField(forms.ModelMultipleChoiceField):
'''If value is a QuerySet, return it as is (for use in widget.render)'''
def prepare_value(self, value):
if isinstance(value, QuerySet):
if isinstance(value, QuerySetAny):
return value
if (hasattr(value, '__iter__') and
not isinstance(value, str) and

View file

@ -3,11 +3,12 @@
from django.urls import reverse as urlreverse
from django.db.models.query import QuerySet
from django.forms.widgets import Widget
from django.utils.safestring import mark_safe
from django.utils.html import conditional_escape
from django_stubs_ext import QuerySetAny
class ButtonWidget(Widget):
def __init__(self, *args, **kwargs):
@ -34,7 +35,7 @@ class ShowAttachmentsWidget(Widget):
html = '<div id="id_%s">' % name
html += '<span class="d-none showAttachmentsEmpty form-control widget">No files attached</span>'
html += '<div class="attachedFiles form-control widget">'
if value and isinstance(value, QuerySet):
if value and isinstance(value, QuerySetAny):
for attachment in value:
html += '<a class="initialAttach" href="%s">%s</a>&nbsp' % (conditional_escape(attachment.document.get_href()), conditional_escape(attachment.document.title))
html += '<a class="btn btn-primary btn-sm" href="{}">Edit</a>&nbsp'.format(urlreverse("ietf.liaisons.views.liaison_edit_attachment", kwargs={'object_id':attachment.statement.pk,'doc_id':attachment.document.pk}))
@ -43,4 +44,4 @@ class ShowAttachmentsWidget(Widget):
else:
html += 'No files attached'
html += '</div></div>'
return mark_safe(html)
return mark_safe(html)

View file

@ -1493,7 +1493,7 @@ class EditTimeslotsTests(IetfSeleniumTestCase):
"""Test the timeslot editor"""
def setUp(self):
super().setUp()
self.meeting: Meeting = MeetingFactory(
self.meeting: Meeting = MeetingFactory( # type: ignore[annotation-unchecked]
type_id='ietf',
number=120,
date=date_today() + datetime.timedelta(days=10),
@ -1570,13 +1570,13 @@ class EditTimeslotsTests(IetfSeleniumTestCase):
delete_time = delete_time_local.astimezone(datetime.timezone.utc)
duration = datetime.timedelta(minutes=60)
delete: [TimeSlot] = TimeSlotFactory.create_batch(
delete: [TimeSlot] = TimeSlotFactory.create_batch( # type: ignore[annotation-unchecked]
2,
meeting=self.meeting,
time=delete_time_local,
duration=duration,
)
keep: [TimeSlot] = [
keep: [TimeSlot] = [ # type: ignore[annotation-unchecked]
TimeSlotFactory(
meeting=self.meeting,
time=keep_time,
@ -1613,14 +1613,14 @@ class EditTimeslotsTests(IetfSeleniumTestCase):
hours = [10, 12]
other_days = [self.meeting.get_meeting_date(d) for d in range(1, 3)]
delete: [TimeSlot] = [
delete: [TimeSlot] = [ # type: ignore[annotation-unchecked]
TimeSlotFactory(
meeting=self.meeting,
time=datetime_from_date(delete_day, self.meeting.tz()).replace(hour=hour),
) for hour in hours
]
keep: [TimeSlot] = [
keep: [TimeSlot] = [ # type: ignore[annotation-unchecked]
TimeSlotFactory(
meeting=self.meeting,
time=datetime_from_date(day, self.meeting.tz()).replace(hour=hour),

View file

@ -556,7 +556,7 @@ class MeetingTests(BaseMeetingTestCase):
self.assertContains(r, "1. More work items underway")
cont_disp = r._headers.get('content-disposition', ('Content-Disposition', ''))[1]
cont_disp = r.headers.get('content-disposition', ('Content-Disposition', ''))[1]
cont_disp = re.split('; ?', cont_disp)
cont_disp_settings = dict( e.split('=', 1) for e in cont_disp if '=' in e )
filename = cont_disp_settings.get('filename', '').strip('"')
@ -2357,7 +2357,7 @@ class EditTimeslotsTests(TestCase):
def test_invalid_edit_timeslot(self):
meeting = self.create_bare_meeting()
ts: TimeSlot = TimeSlotFactory(meeting=meeting, name='slot') # n.b., colon indicates type hinting
ts: TimeSlot = TimeSlotFactory(meeting=meeting, name='slot') # type: ignore[annotation-unchecked]
self.login()
r = self.client.post(
self.edit_timeslot_url(ts),

View file

@ -1,8 +1,8 @@
# Copyright The IETF Trust 2007-2020, All Rights Reserved
from django.conf.urls import include
from django.views.generic import RedirectView
from django.conf import settings
from django.urls import include
from django.views.generic import RedirectView
from ietf.meeting import views, views_proceedings
from ietf.utils.urls import url

View file

@ -67,7 +67,7 @@ class Command(BaseCommand):
pprint(connection.queries)
raise
objects = [] # type: List[object]
objects: List[object] = [] # type: ignore[annotation-unchecked]
model_objects = {}
import ietf.name.models

View file

@ -3,10 +3,11 @@
import functools
from urllib.parse import quote as urlquote
from django.urls import reverse
from django.http import HttpResponseRedirect
from django.utils.http import urlquote
def nomcom_private_key_required(view_func):

View file

@ -1,13 +1,13 @@
from django.conf.urls import url, include
from django.urls import re_path, include
from django.views.generic import TemplateView
urlpatterns = [
url(r'^$', TemplateView.as_view(template_name='main.html')),
url(r'^announcement/', include('ietf.secr.announcement.urls')),
url(r'^areas/', include('ietf.secr.areas.urls')),
url(r'^console/', include('ietf.secr.console.urls')),
url(r'^meetings/', include('ietf.secr.meetings.urls')),
url(r'^rolodex/', include('ietf.secr.rolodex.urls')),
url(r'^sreq/', include('ietf.secr.sreq.urls')),
url(r'^telechat/', include('ietf.secr.telechat.urls')),
re_path(r'^$', TemplateView.as_view(template_name='main.html')),
re_path(r'^announcement/', include('ietf.secr.announcement.urls')),
re_path(r'^areas/', include('ietf.secr.areas.urls')),
re_path(r'^console/', include('ietf.secr.console.urls')),
re_path(r'^meetings/', include('ietf.secr.meetings.urls')),
re_path(r'^rolodex/', include('ietf.secr.rolodex.urls')),
re_path(r'^sreq/', include('ietf.secr.sreq.urls')),
re_path(r'^telechat/', include('ietf.secr.telechat.urls')),
]

View file

@ -1,12 +1,12 @@
# Copyright The IETF Trust 2013-2020, All Rights Reserved
from functools import wraps
from urllib.parse import quote as urlquote
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.utils.http import urlquote
from ietf.ietfauth.utils import has_role
from ietf.doc.models import Document

View file

@ -102,6 +102,11 @@ USE_I18N = False
USE_TZ = True
# Default primary key field type to use for models that dont have a field with primary_key=True.
# In the future (relative to 4.2), the default will become 'django.db.models.BigAutoField.'
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
if SERVER_MODE == 'production':
MEDIA_ROOT = '/a/www/www6s/lib/dt/media/'
MEDIA_URL = 'https://www.ietf.org/lib/dt/media/'
@ -428,7 +433,6 @@ INSTALLED_APPS = [
'django_celery_beat',
'corsheaders',
'django_markup',
'django_password_strength',
'oidc_provider',
'simple_history',
'tastypie',
@ -1119,7 +1123,6 @@ CHECKS_LIBRARY_PATCHES_TO_APPLY = [
'patch/change-oidc-provider-field-sizes-228.patch',
'patch/fix-oidc-access-token-post.patch',
'patch/fix-jwkest-jwt-logging.patch',
'patch/fix-django-password-strength-kwargs.patch',
'patch/django-cookie-delete-with-all-settings.patch',
'patch/tastypie-django22-fielderror-response.patch',
]

View file

@ -1204,15 +1204,15 @@ class SubmitTests(BaseSubmitTestCase):
Unlike some other tests in this module, does not confirm draft if this would be required.
"""
orig_draft = DocumentFactory(
orig_draft: Document = DocumentFactory( # type: ignore[annotation-unchecked]
type_id='draft',
group=GroupFactory(type_id=group_type) if group_type else None,
stream_id=stream_type,
) # type: Document
)
name = orig_draft.name
group = orig_draft.group
new_rev = '%02d' % (int(orig_draft.rev) + 1)
author = PersonFactory() # type: Person
author: Person = PersonFactory() # type: ignore[annotation-unchecked]
DocumentAuthor.objects.create(person=author, document=orig_draft)
orig_draft.docextresource_set.create(name_id='faq', value='https://faq.example.com/')
orig_draft.docextresource_set.create(name_id='wiki', value='https://wiki.example.com', display_name='Test Wiki')
@ -1982,7 +1982,7 @@ class SubmitTests(BaseSubmitTestCase):
group = GroupFactory()
# someone to be notified of resource suggestion when permission not granted
RoleFactory(group=group, person=PersonFactory(), name_id='chair')
submission = SubmissionFactory(state_id='grp-appr', group=group) # type: Submission
submission: Submission = SubmissionFactory(state_id='grp-appr', group=group) # type: ignore[annotation-unchecked]
SubmissionExtResourceFactory(submission=submission)
# use secretary user to ensure we have permission to approve
@ -2000,7 +2000,7 @@ class SubmitTests(BaseSubmitTestCase):
group = GroupFactory()
# someone to be notified of resource suggestion when permission not granted
RoleFactory(group=group, person=PersonFactory(), name_id='chair')
submission = SubmissionFactory(state_id=state, group=group) # type: Submission
submission: Submission = SubmissionFactory(state_id=state, group=group) # type: ignore[annotation-unchecked]
SubmissionExtResourceFactory(submission=submission)
url = urlreverse(
@ -2052,7 +2052,7 @@ class SubmitTests(BaseSubmitTestCase):
def test_forcepost_with_extresources(self):
# state needs to be one that has 'posted' as a next state
submission = SubmissionFactory(state_id='grp-appr') # type: Submission
submission: Submission = SubmissionFactory(state_id='grp-appr') # type: ignore[annotation-unchecked]
SubmissionExtResourceFactory(submission=submission)
url = urlreverse(

View file

@ -10,11 +10,11 @@ import re
import requests
from email.utils import parsedate_to_datetime
from urllib.parse import quote as urlquote
from django.conf import settings
from django.utils import timezone
from django.utils.encoding import smart_bytes, force_str
from django.utils.http import urlquote
import debug # pyflakes:ignore

View file

@ -64,7 +64,7 @@
</a>
</td>
<td>
{% ifequal ref.source.get_state.slug 'rfc' %}
{% if ref.source.get_state.slug == 'rfc' %}
{% with ref.source.std_level as lvl %}
{% if lvl %}{{ lvl }}{% endif %}
{% endwith %}
@ -72,7 +72,7 @@
{% with ref.source.intended_std_level as lvl %}
{% if lvl %}{{ lvl }}{% endif %}
{% endwith %}
{% endifequal %}
{% endif %}
</td>
<td>{{ ref.relationship.name }}</td>
<td>{{ ref.is_downref|default:'' }}</td>

View file

@ -51,7 +51,7 @@
</a>
</td>
<td>
{% ifequal ref.target.document.get_state.slug 'rfc' %}
{% if ref.target.document.get_state.slug == 'rfc' %}
{% with ref.target.document.std_level as lvl %}
{% if lvl %}{{ lvl }}{% endif %}
{% endwith %}
@ -59,7 +59,7 @@
{% with ref.target.document.intended_std_level as lvl %}
{% if lvl %}{{ lvl }}{% endif %}
{% endwith %}
{% endifequal %}
{% endif %}
</td>
<td>{{ ref.relationship.name }}</td>
<td>{{ ref.is_downref|default:'' }}</td>

View file

@ -6,8 +6,7 @@
{% block title %}Change password{% endblock %}
{% block js %}
{{ block.super }}
<script src="{% static 'ietf/js/zxcvbn.js' %}"></script>
<script src="{% static 'ietf/js/password_strength.js' %}"></script>
{{ form.media.js }}
{% endblock %}
{% block content %}
{% origin %}

View file

@ -6,8 +6,7 @@
{% block title %}Complete account creation{% endblock %}
{% block js %}
{{ block.super }}
<script src="{% static 'ietf/js/zxcvbn.js' %}"></script>
<script src="{% static 'ietf/js/password_strength.js' %}"></script>
{{ form.media.js }}
{% endblock %}
{% block content %}
{% origin %}

View file

@ -1,15 +1,14 @@
# Copyright The IETF Trust 2007-2022, All Rights Reserved
from django.conf import settings
from django.conf.urls import include
from django.conf.urls.static import static as static_url
from django.contrib import admin
from django.contrib.sitemaps import views as sitemap_views
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.urls import include, path
from django.views import static as static_view
from django.views.generic import TemplateView
from django.views.defaults import server_error
from django.urls import path
import debug # pyflakes:ignore

10
ietf/utils/http.py Normal file
View file

@ -0,0 +1,10 @@
# Copyright The IETF Trust 2023, All Rights Reserved
# -*- coding: utf-8 -*-
def is_ajax(request):
"""Checks whether a request was an AJAX call
See https://docs.djangoproject.com/en/3.1/releases/3.1/#id2 - this implements the
exact reproduction of the deprecated method suggested there.
"""
return request.headers.get("x-requested-with") == "XMLHttpRequest"

View file

@ -6,9 +6,9 @@ import debug # pyflakes:ignore
from inspect import isclass
from django.conf.urls import url as django_url
from django.views.generic import View
from django.urls import re_path
from django.utils.encoding import force_str
from django.views.generic import View
def url(regex, view, kwargs=None, name=None):
if callable(view) and hasattr(view, '__name__'):
@ -42,5 +42,5 @@ def url(regex, view, kwargs=None, name=None):
#debug.show('branch')
#debug.show('name')
pass
return django_url(regex, view, kwargs=kwargs, name=name)
return re_path(regex, view, kwargs=kwargs, name=name)

View file

@ -11,10 +11,11 @@ from urllib.parse import urlparse, urlsplit, urlunsplit
from django.apps import apps
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.validators import RegexValidator, URLValidator, EmailValidator, _lazy_re_compile, BaseValidator
from django.core.validators import RegexValidator, URLValidator, EmailValidator, BaseValidator
from django.template.defaultfilters import filesizeformat
from django.utils.deconstruct import deconstructible
from django.utils.ipv6 import is_valid_ipv6_address
from django.utils.regex_helper import _lazy_re_compile # type: ignore
from django.utils.translation import gettext_lazy as _
import debug # pyflakes:ignore

View file

@ -1,7 +1,5 @@
[mypy]
#mypy_path = ./stubs/
ignore_missing_imports = True
plugins =
@ -9,12 +7,3 @@ plugins =
[mypy.plugins.django-stubs]
django_settings_module = ietf.settings
[mypy-ietf.group.migrations.0004_add_group_feature_fields]
ignore_errors = True
[mypy-ietf.group.migrations.0002_groupfeatures_historicalgroupfeatures]
ignore_errors = True
[mypy-ietf.doc.migrations.0001_initial]
ignore_errors = True

View file

@ -281,7 +281,7 @@ diff -ur oidc_provider.orig/migrations/0021_refresh_token_not_unique.py oidc_pro
diff -ur oidc_provider.orig/models.py oidc_provider/models.py
--- oidc_provider.orig/models.py 2018-09-14 21:34:52.000000000 +0200
+++ oidc_provider/models.py 2020-06-07 13:34:26.830716635 +0200
@@ -67,8 +67,8 @@
@@ -66,8 +66,8 @@
verbose_name=_(u'Client Type'),
help_text=_(u'<b>Confidential</b> clients are capable of maintaining the confidentiality'
u' of their credentials. <b>Public</b> clients are incapable.'))
@ -292,7 +292,7 @@ diff -ur oidc_provider.orig/models.py oidc_provider/models.py
response_types = models.ManyToManyField(ResponseType)
jwt_alg = models.CharField(
max_length=10,
@@ -78,15 +78,15 @@
@@ -77,15 +77,15 @@
help_text=_(u'Algorithm used to encode ID Tokens.'))
date_created = models.DateField(auto_now_add=True, verbose_name=_(u'Date Created'))
website_url = models.CharField(
@ -311,7 +311,7 @@ diff -ur oidc_provider.orig/models.py oidc_provider/models.py
logo = models.FileField(
blank=True, default='', upload_to='oidc_provider/clients', verbose_name=_(u'Logo Image'))
reuse_consent = models.BooleanField(
@@ -186,12 +186,12 @@
@@ -185,12 +185,12 @@
user = models.ForeignKey(
settings.AUTH_USER_MODEL, verbose_name=_(u'User'), on_delete=models.CASCADE)
@ -328,7 +328,7 @@ diff -ur oidc_provider.orig/models.py oidc_provider/models.py
class Meta:
verbose_name = _(u'Authorization Code')
@@ -205,8 +205,8 @@
@@ -204,8 +204,8 @@
user = models.ForeignKey(
settings.AUTH_USER_MODEL, null=True, verbose_name=_(u'User'), on_delete=models.CASCADE)

View file

@ -1,6 +1,6 @@
--- 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
@@ -95,6 +95,8 @@
@@ -108,6 +108,8 @@
response.delete_cookie(
self.cookie_name,
domain=settings.SESSION_COOKIE_DOMAIN,
@ -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 @@
@@ -243,12 +243,18 @@
value = signing.get_cookie_signer(salt=key + salt).sign(value)
return self.set_cookie(key, value, **kwargs)
@ -43,7 +43,7 @@
--- 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
@@ -42,6 +42,8 @@
@@ -40,6 +40,8 @@
settings.SESSION_COOKIE_NAME,
path=settings.SESSION_COOKIE_PATH,
domain=settings.SESSION_COOKIE_DOMAIN,

View file

@ -1,36 +0,0 @@
--- django_password_strength/widgets.py.orig 2020-06-24 16:07:28.479533134 +0200
+++ django_password_strength/widgets.py 2020-06-24 16:08:09.540714290 +0200
@@ -8,7 +8,7 @@
Form widget to show the user how strong his/her password is.
"""
- def render(self, name, value, attrs=None):
+ def render(self, name, value, **kwargs):
strength_markup = """
<div style="margin-top: 10px;">
<div class="progress" style="margin-bottom: 10px;">
@@ -30,7 +30,7 @@
except KeyError:
self.attrs['class'] = 'password_strength'
- return mark_safe( super(PasswordInput, self).render(name, value, attrs) + strength_markup )
+ return mark_safe( super(PasswordInput, self).render(name, value, **kwargs) + strength_markup )
class Media:
js = (
@@ -48,7 +48,7 @@
super(PasswordConfirmationInput, self).__init__(attrs, render_value)
self.confirm_with=confirm_with
- def render(self, name, value, attrs=None):
+ def render(self, name, value, **kwargs):
if self.confirm_with:
self.attrs['data-confirm-with'] = 'id_%s' % self.confirm_with
@@ -68,4 +68,4 @@
except KeyError:
self.attrs['class'] = 'password_confirmation'
- return mark_safe( super(PasswordInput, self).render(name, value, attrs) + confirmation_markup )
+ return mark_safe( super(PasswordInput, self).render(name, value, **kwargs) + confirmation_markup )

View file

@ -11,12 +11,10 @@ diff -ur oidc_provider.orig/lib/utils/common.py oidc_provider/lib/utils/common.p
--- oidc_provider.orig/lib/utils/oauth2.py 2020-05-22 15:09:21.009044320 +0200
+++ oidc_provider/lib/utils/oauth2.py 2020-06-05 17:05:23.271285858 +0200
@@ -21,10 +21,14 @@
"""
@@ -22,9 +22,13 @@
auth_header = request.META.get('HTTP_AUTHORIZATION', '')
- if re.compile('^[Bb]earer\s{1}.+$').match(auth_header):
+ if re.compile(r'^[Bb]earer\s{1}.+$').match(auth_header):
if re.compile(r'^[Bb]earer\s{1}.+$').match(auth_header):
access_token = auth_header.split()[1]
- else:
+ elif request.method == 'GET':
@ -27,13 +25,4 @@ diff -ur oidc_provider.orig/lib/utils/common.py oidc_provider/lib/utils/common.p
+ access_token = ''
return access_token
@@ -39,7 +43,7 @@
"""
auth_header = request.META.get('HTTP_AUTHORIZATION', '')
- if re.compile('^Basic\s{1}.+$').match(auth_header):
+ if re.compile(r'^Basic\s{1}.+$').match(auth_header):
b64_user_pass = auth_header.split()[1]
try:
user_pass = b64decode(b64_user_pass).decode('utf-8').split(':')

View file

@ -1,15 +1,15 @@
--- tastypie/resources.py.orig 2020-08-24 13:14:25.463166100 +0200
+++ tastypie/resources.py 2020-08-24 13:15:55.133759224 +0200
@@ -15,7 +15,7 @@
@@ -12,7 +12,7 @@
ObjectDoesNotExist, MultipleObjectsReturned, ValidationError, FieldDoesNotExist
)
from django.core.signals import got_request_exception
-from django.core.exceptions import ImproperlyConfigured
+from django.core.exceptions import ImproperlyConfigured, FieldError
from django.db.models.fields.related import ForeignKey
try:
from django.contrib.gis.db.models.fields import GeometryField
@@ -2207,6 +2207,8 @@
from django.urls.conf import re_path
from tastypie.utils.timezone import make_naive_utc
@@ -2198,6 +2198,8 @@
return self.authorized_read_list(objects, bundle)
except ValueError:
raise BadRequest("Invalid resource lookup data provided (mismatched type).")
@ -20,7 +20,7 @@
"""
--- tastypie/paginator.py.orig 2020-08-25 15:24:46.391588425 +0200
+++ tastypie/paginator.py 2020-08-25 15:24:53.591797122 +0200
@@ -128,6 +128,8 @@
@@ -124,6 +124,8 @@
except (AttributeError, TypeError):
# If it's not a QuerySet (or it's ilk), fallback to ``len``.
return len(self.objects)

View file

@ -5,11 +5,13 @@ argon2-cffi>=21.3.0 # For the Argon2 password hasher option
beautifulsoup4>=4.11.1 # Only used in tests
bibtexparser>=1.2.0 # Only used in tests
bleach>=6
types-bleach>=6
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
types-decorator>=5.1.1
defusedxml>=0.7.1 # for TastyPie when using xml; not a declared dependency
Django<3.2
Django<4
django-analytical>=3.1.0
django-bootstrap5>=21.3
django-celery-beat>=2.3.0
@ -17,17 +19,17 @@ django-csp>=3.7
django-cors-headers>=3.11.0
django-debug-toolbar>=3.2.4
django-markup>=1.5 # Limited use - need to reconcile against direct use of markdown
django-oidc-provider>=0.7,<0.8 # 0.8 dropped Django 2 support
django-password-strength>=1.2.1
django-oidc-provider>=0.8 # 0.8 dropped Django 2 support
django-referrer-policy>=1.0
django-simple-history>=3.0.0
django-stubs==1.8.0 # The django-stubs version used determines the the mypy version indicated below
django-tastypie==0.14.3 # Version must be locked in sync with version of Django
django-stubs>=4.2.0 # The django-stubs version used determines the the mypy version indicated below
django-tastypie>=0.14.5 # Version must be locked in sync with version of Django
django-vite>=2.0.2
django-webtest>=1.9.10 # Only used in tests
django-widget-tweaks>=1.4.12
djlint>=1.0.0 # To auto-indent templates via "djlint --profile django --reformat"
docutils>=0.18.1 # Used only by dbtemplates for RestructuredText
types-docutils>=0.18.1
factory-boy>=3.2.1
github3.py>=3.2.0
gunicorn>=20.1.0
@ -40,21 +42,25 @@ jwcrypto>=1.2 # for signed notifications - this is aspirational, and is not r
logging_tree>=1.9 # Used only by the showloggers management command
lxml>=4.8.0,<5
markdown>=3.3.6
types-markdown>=3.3.6
mock>=4.0.3 # Used only by tests, of course
mypy==0.812 # Version requirements determined by django-stubs.
types-mock>=4.0.3
mypy<1.3 # Version requirements determined by django-stubs.
oic>=1.3 # Used only by tests
Pillow>=9.1.0
psycopg2<2.9
psycopg2>=2.9.6
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
pyquery>=1.4.3
python-dateutil>=2.8.2
types-python-dateutil>=2.8.2
python-magic==0.4.18 # Versions beyond the yanked .19 and .20 introduce form failures
python-memcached>=1.59 # for django.core.cache.backends.memcached
python-mimeparse>=1.6 # from TastyPie
pytz==2022.2.1 # Pinned as changes need to be vetted for their effect on Meeting fields
requests>=2.27.1
types-requests>=2.27.1
requests-mock>=1.9.3
rfc2html>=2.0.3
scout-apm>=2.24.2