mirror of
https://github.com/pretix/pretix.git
synced 2026-05-07 15:34:02 +00:00
Bump Django to 4.1.* (#2989)
This commit is contained in:
@@ -37,8 +37,8 @@ import tempfile
|
||||
from collections import OrderedDict, namedtuple
|
||||
from decimal import Decimal
|
||||
from typing import Optional, Tuple
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import pytz
|
||||
from defusedcsv import csv
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
@@ -68,7 +68,7 @@ class BaseExporter:
|
||||
self.events = event
|
||||
self.event = None
|
||||
e = self.events.first()
|
||||
self.timezone = e.timezone if e else pytz.timezone(settings.TIME_ZONE)
|
||||
self.timezone = e.timezone if e else ZoneInfo(settings.TIME_ZONE)
|
||||
else:
|
||||
self.events = Event.objects.filter(pk=event.pk)
|
||||
self.timezone = event.timezone
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
|
||||
from collections import OrderedDict
|
||||
from decimal import Decimal
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import pytz
|
||||
from django import forms
|
||||
from django.db.models import (
|
||||
Case, CharField, Count, DateTimeField, F, IntegerField, Max, Min, OuterRef,
|
||||
@@ -326,7 +326,7 @@ class OrderListExporter(MultiSheetListExporter):
|
||||
|
||||
yield self.ProgressSetTotal(total=qs.count())
|
||||
for order in qs.order_by('datetime').iterator():
|
||||
tz = pytz.timezone(self.event_object_cache[order.event_id].settings.timezone)
|
||||
tz = ZoneInfo(self.event_object_cache[order.event_id].settings.timezone)
|
||||
|
||||
row = [
|
||||
self.event_object_cache[order.event_id].slug,
|
||||
@@ -459,7 +459,7 @@ class OrderListExporter(MultiSheetListExporter):
|
||||
yield self.ProgressSetTotal(total=qs.count())
|
||||
for op in qs.order_by('order__datetime').iterator():
|
||||
order = op.order
|
||||
tz = pytz.timezone(order.event.settings.timezone)
|
||||
tz = ZoneInfo(order.event.settings.timezone)
|
||||
row = [
|
||||
self.event_object_cache[order.event_id].slug,
|
||||
order.code,
|
||||
@@ -631,7 +631,7 @@ class OrderListExporter(MultiSheetListExporter):
|
||||
|
||||
for op in ops:
|
||||
order = op.order
|
||||
tz = pytz.timezone(self.event_object_cache[order.event_id].settings.timezone)
|
||||
tz = ZoneInfo(self.event_object_cache[order.event_id].settings.timezone)
|
||||
row = [
|
||||
self.event_object_cache[order.event_id].slug,
|
||||
order.code,
|
||||
@@ -1024,7 +1024,7 @@ class PaymentListExporter(ListExporter):
|
||||
|
||||
yield self.ProgressSetTotal(total=len(objs))
|
||||
for obj in objs:
|
||||
tz = pytz.timezone(obj.order.event.settings.timezone)
|
||||
tz = ZoneInfo(obj.order.event.settings.timezone)
|
||||
if isinstance(obj, OrderPayment) and obj.payment_date:
|
||||
d2 = obj.payment_date.astimezone(tz).date().strftime('%Y-%m-%d')
|
||||
elif isinstance(obj, OrderRefund) and obj.execution_date:
|
||||
@@ -1203,7 +1203,7 @@ class GiftcardRedemptionListExporter(ListExporter):
|
||||
yield headers
|
||||
|
||||
for obj in objs:
|
||||
tz = pytz.timezone(obj.order.event.settings.timezone)
|
||||
tz = ZoneInfo(obj.order.event.settings.timezone)
|
||||
gc = GiftCard.objects.get(pk=obj.info_data.get('gift_card'))
|
||||
row = [
|
||||
obj.order.event.slug,
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from collections import OrderedDict
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import pytz
|
||||
from django import forms
|
||||
from django.db.models import F, Q
|
||||
from django.dispatch import receiver
|
||||
@@ -137,7 +137,7 @@ class WaitingListExporter(ListExporter):
|
||||
|
||||
# which event should be used to output dates in columns "Start date" and "End date"
|
||||
event_for_date_columns = entry.subevent if entry.subevent else entry.event
|
||||
tz = pytz.timezone(entry.event.settings.timezone)
|
||||
tz = ZoneInfo(entry.event.settings.timezone)
|
||||
datetime_format = '%Y-%m-%d %H:%M:%S'
|
||||
|
||||
row = [
|
||||
|
||||
@@ -167,6 +167,7 @@ class SettingsForm(i18nfield.forms.I18nFormMixin, HierarkeyForm):
|
||||
|
||||
class PrefixForm(forms.Form):
|
||||
prefix = forms.CharField(widget=forms.HiddenInput)
|
||||
template_name = 'django/forms/formsets/table.html'
|
||||
|
||||
|
||||
class SafeSessionWizardView(SessionWizardView):
|
||||
|
||||
@@ -38,10 +38,10 @@ import logging
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
from io import BytesIO
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import dateutil.parser
|
||||
import pycountry
|
||||
import pytz
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
@@ -733,7 +733,7 @@ class BaseQuestionsForm(forms.Form):
|
||||
initial = answers[0]
|
||||
else:
|
||||
initial = None
|
||||
tz = pytz.timezone(event.settings.timezone)
|
||||
tz = ZoneInfo(event.settings.timezone)
|
||||
help_text = rich_text(q.help_text)
|
||||
label = escape(q.question) # django-bootstrap3 calls mark_safe
|
||||
required = q.required and not self.all_optional
|
||||
|
||||
63
src/pretix/base/forms/renderers.py
Normal file
63
src/pretix/base/forms/renderers.py
Normal file
@@ -0,0 +1,63 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from bootstrap3.renderers import (
|
||||
FieldRenderer as BaseFieldRenderer,
|
||||
InlineFieldRenderer as BaseInlineFieldRenderer,
|
||||
)
|
||||
from django.forms import (
|
||||
CheckboxInput, CheckboxSelectMultiple, ClearableFileInput, RadioSelect,
|
||||
SelectDateWidget,
|
||||
)
|
||||
|
||||
|
||||
class FieldRenderer(BaseFieldRenderer):
|
||||
# Local application of https://github.com/zostera/django-bootstrap3/pull/859
|
||||
|
||||
def post_widget_render(self, html):
|
||||
if isinstance(self.widget, CheckboxSelectMultiple):
|
||||
html = self.list_to_class(html, "checkbox")
|
||||
elif isinstance(self.widget, RadioSelect):
|
||||
html = self.list_to_class(html, "radio")
|
||||
elif isinstance(self.widget, SelectDateWidget):
|
||||
html = self.fix_date_select_input(html)
|
||||
elif isinstance(self.widget, ClearableFileInput):
|
||||
html = self.fix_clearable_file_input(html)
|
||||
elif isinstance(self.widget, CheckboxInput):
|
||||
html = self.put_inside_label(html)
|
||||
return html
|
||||
|
||||
|
||||
class InlineFieldRenderer(BaseInlineFieldRenderer):
|
||||
# Local application of https://github.com/zostera/django-bootstrap3/pull/859
|
||||
|
||||
def post_widget_render(self, html):
|
||||
if isinstance(self.widget, CheckboxSelectMultiple):
|
||||
html = self.list_to_class(html, "checkbox")
|
||||
elif isinstance(self.widget, RadioSelect):
|
||||
html = self.list_to_class(html, "radio")
|
||||
elif isinstance(self.widget, SelectDateWidget):
|
||||
html = self.fix_date_select_input(html)
|
||||
elif isinstance(self.widget, ClearableFileInput):
|
||||
html = self.fix_clearable_file_input(html)
|
||||
elif isinstance(self.widget, CheckboxInput):
|
||||
html = self.put_inside_label(html)
|
||||
return html
|
||||
@@ -22,7 +22,7 @@
|
||||
import json
|
||||
import sys
|
||||
|
||||
import pytz
|
||||
import pytz_deprecation_shim
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils.timezone import override
|
||||
from django_scopes import scope
|
||||
@@ -60,7 +60,7 @@ class Command(BaseCommand):
|
||||
sys.exit(1)
|
||||
|
||||
locale = options.get("locale", None)
|
||||
timezone = pytz.timezone(options['timezone']) if options.get('timezone') else None
|
||||
timezone = pytz_deprecation_shim.timezone(options['timezone']) if options.get('timezone') else None
|
||||
|
||||
with scope(organizer=o):
|
||||
if options['event_slug']:
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#
|
||||
from collections import OrderedDict
|
||||
from urllib.parse import urlsplit
|
||||
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
||||
|
||||
import pytz
|
||||
from django.conf import settings
|
||||
from django.http import Http404, HttpRequest, HttpResponse
|
||||
from django.middleware.common import CommonMiddleware
|
||||
@@ -98,9 +98,9 @@ class LocaleMiddleware(MiddlewareMixin):
|
||||
tzname = request.user.timezone
|
||||
if tzname:
|
||||
try:
|
||||
timezone.activate(pytz.timezone(tzname))
|
||||
timezone.activate(ZoneInfo(tzname))
|
||||
request.timezone = tzname
|
||||
except pytz.UnknownTimeZoneError:
|
||||
except ZoneInfoNotFoundError:
|
||||
pass
|
||||
else:
|
||||
timezone.deactivate()
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
# Generated by Django 1.10.4 on 2017-02-03 14:21
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import django.core.validators
|
||||
import django.db.migrations.operations.special
|
||||
import django.db.models.deletion
|
||||
@@ -26,7 +28,7 @@ def forwards42(apps, schema_editor):
|
||||
for s in EventSetting.objects.filter(key='timezone').values('object_id', 'value')
|
||||
}
|
||||
for order in Order.objects.all():
|
||||
tz = pytz.timezone(etz.get(order.event_id, 'UTC'))
|
||||
tz = ZoneInfo(etz.get(order.event_id, 'UTC'))
|
||||
order.expires = order.expires.astimezone(tz).replace(hour=23, minute=59, second=59)
|
||||
order.save()
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# Generated by Django 1.10.2 on 2016-10-19 17:57
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import pytz
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from django.db import migrations
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
def forwards(apps, schema_editor):
|
||||
@@ -15,7 +15,7 @@ def forwards(apps, schema_editor):
|
||||
for s in EventSetting.objects.filter(key='timezone').values('object_id', 'value')
|
||||
}
|
||||
for order in Order.objects.all():
|
||||
tz = pytz.timezone(etz.get(order.event_id, 'UTC'))
|
||||
tz = ZoneInfo(etz.get(order.event_id, 'UTC'))
|
||||
order.expires = order.expires.astimezone(tz).replace(hour=23, minute=59, second=59)
|
||||
order.save()
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# Generated by Django 3.2.4 on 2021-09-30 10:25
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from django.db import migrations, models
|
||||
from pytz import UTC
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
@@ -15,7 +14,7 @@ class Migration(migrations.Migration):
|
||||
migrations.AddField(
|
||||
model_name='invoice',
|
||||
name='sent_to_customer',
|
||||
field=models.DateTimeField(blank=True, null=True, default=UTC.localize(datetime(1970, 1, 1, 0, 0, 0, 0))),
|
||||
field=models.DateTimeField(blank=True, null=True, default=datetime(1970, 1, 1, 0, 0, 0, 0, tzinfo=timezone.utc)),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
|
||||
@@ -121,14 +121,23 @@ class Customer(LoggedModel):
|
||||
if self.email:
|
||||
self.email = self.email.lower()
|
||||
if 'update_fields' in kwargs and 'last_modified' not in kwargs['update_fields']:
|
||||
kwargs['update_fields'] = list(kwargs['update_fields']) + ['last_modified']
|
||||
kwargs['update_fields'] = {'last_modified'}.union(kwargs['update_fields'])
|
||||
if not self.identifier:
|
||||
self.assign_identifier()
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'identifier'}.union(kwargs['update_fields'])
|
||||
if self.name_parts:
|
||||
self.name_cached = self.name
|
||||
name = self.name
|
||||
if self.name_cached != name:
|
||||
self.name_cached = name
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'name_cached'}.union(kwargs['update_fields'])
|
||||
else:
|
||||
self.name_cached = ""
|
||||
self.name_parts = {}
|
||||
if self.name_cached != "" or self.name_parts != {}:
|
||||
self.name_cached = ""
|
||||
self.name_parts = {}
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'name_cached', 'name_parts'}.union(kwargs['update_fields'])
|
||||
super().save(**kwargs)
|
||||
|
||||
def anonymize(self):
|
||||
|
||||
@@ -98,6 +98,8 @@ class Gate(LoggedModel):
|
||||
if not Gate.objects.filter(organizer=self.organizer, identifier=code).exists():
|
||||
self.identifier = code
|
||||
break
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'identifier'}.union(kwargs['update_fields'])
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
|
||||
@@ -173,6 +175,8 @@ class Device(LoggedModel):
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.device_id:
|
||||
self.device_id = (self.organizer.devices.aggregate(m=Max('device_id'))['m'] or 0) + 1
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'device_id'}.union(kwargs['update_fields'])
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def permission_set(self) -> set:
|
||||
|
||||
@@ -40,8 +40,9 @@ from collections import Counter, OrderedDict, defaultdict
|
||||
from datetime import datetime, time, timedelta
|
||||
from operator import attrgetter
|
||||
from urllib.parse import urljoin
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import pytz
|
||||
import pytz_deprecation_shim
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.files.storage import default_storage
|
||||
@@ -214,7 +215,7 @@ class EventMixin:
|
||||
|
||||
@property
|
||||
def timezone(self):
|
||||
return pytz.timezone(self.settings.timezone)
|
||||
return pytz_deprecation_shim.timezone(self.settings.timezone)
|
||||
|
||||
@property
|
||||
def effective_presale_end(self):
|
||||
@@ -773,7 +774,7 @@ class Event(EventMixin, LoggedModel):
|
||||
"""
|
||||
The last datetime of payments for this event.
|
||||
"""
|
||||
tz = pytz.timezone(self.settings.timezone)
|
||||
tz = ZoneInfo(self.settings.timezone)
|
||||
return make_aware(datetime.combine(
|
||||
self.settings.get('payment_term_last', as_type=RelativeDateWrapper).datetime(self).date(),
|
||||
time(hour=23, minute=59, second=59)
|
||||
|
||||
@@ -19,10 +19,11 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import zoneinfo
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytz
|
||||
from dateutil.rrule import rrulestr
|
||||
from dateutil.tz import datetime_exists
|
||||
from django.conf import settings
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.db import models
|
||||
@@ -108,12 +109,9 @@ class AbstractScheduledExport(LoggedModel):
|
||||
self.schedule_next_run = None
|
||||
return
|
||||
|
||||
try:
|
||||
self.schedule_next_run = make_aware(datetime.combine(new_d.date(), self.schedule_rrule_time), tz)
|
||||
except pytz.exceptions.AmbiguousTimeError:
|
||||
self.schedule_next_run = make_aware(datetime.combine(new_d.date(), self.schedule_rrule_time), tz, is_dst=False)
|
||||
except pytz.exceptions.NonExistentTimeError:
|
||||
self.schedule_next_run = make_aware(datetime.combine(new_d.date(), self.schedule_rrule_time) + timedelta(hours=1), tz)
|
||||
self.schedule_next_run = make_aware(datetime.combine(new_d.date(), self.schedule_rrule_time), tz)
|
||||
if not datetime_exists(self.schedule_next_run):
|
||||
self.schedule_next_run += timedelta(hours=1)
|
||||
|
||||
|
||||
class ScheduledEventExport(AbstractScheduledExport):
|
||||
@@ -136,4 +134,4 @@ class ScheduledOrganizerExport(AbstractScheduledExport):
|
||||
|
||||
@property
|
||||
def tz(self):
|
||||
return pytz.timezone(self.timezone)
|
||||
return zoneinfo.ZoneInfo(self.timezone)
|
||||
|
||||
@@ -251,14 +251,20 @@ class Invoice(models.Model):
|
||||
raise ValueError('Every invoice needs to be connected to an order')
|
||||
if not self.event:
|
||||
self.event = self.order.event
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'event'}.union(kwargs['update_fields'])
|
||||
if not self.organizer:
|
||||
self.organizer = self.order.event.organizer
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'organizer'}.union(kwargs['update_fields'])
|
||||
if not self.prefix:
|
||||
self.prefix = self.event.settings.invoice_numbers_prefix or (self.event.slug.upper() + '-')
|
||||
if self.is_cancellation:
|
||||
self.prefix = self.event.settings.invoice_numbers_prefix_cancellations or self.prefix
|
||||
if '%' in self.prefix:
|
||||
self.prefix = self.date.strftime(self.prefix)
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'prefix'}.union(kwargs['update_fields'])
|
||||
|
||||
if not self.invoice_no:
|
||||
if self.order.testmode:
|
||||
@@ -276,8 +282,13 @@ class Invoice(models.Model):
|
||||
# Suppress duplicate key errors and try again
|
||||
if i == 9:
|
||||
raise
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'invoice_no'}.union(kwargs['update_fields'])
|
||||
|
||||
self.full_invoice_no = self.prefix + self.invoice_no
|
||||
if self.full_invoice_no != self.prefix + self.invoice_no:
|
||||
self.full_invoice_no = self.prefix + self.invoice_no
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'full_invoice_no'}.union(kwargs['update_fields'])
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
|
||||
@@ -40,9 +40,10 @@ from collections import Counter, OrderedDict
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from decimal import Decimal, DecimalException
|
||||
from typing import Optional, Tuple
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import dateutil.parser
|
||||
import pytz
|
||||
from dateutil.tz import datetime_exists
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import (
|
||||
@@ -927,22 +928,22 @@ class Item(LoggedModel):
|
||||
)
|
||||
if self.validity_dynamic_duration_days:
|
||||
replace_date += timedelta(days=self.validity_dynamic_duration_days)
|
||||
valid_until = tz.localize(valid_until.replace(
|
||||
valid_until = valid_until.replace(
|
||||
year=replace_date.year,
|
||||
month=replace_date.month,
|
||||
day=replace_date.day,
|
||||
hour=23, minute=59, second=59, microsecond=0,
|
||||
tzinfo=None,
|
||||
))
|
||||
tzinfo=tz,
|
||||
)
|
||||
elif self.validity_dynamic_duration_days:
|
||||
replace_date = valid_until.date() + timedelta(days=self.validity_dynamic_duration_days - 1)
|
||||
valid_until = tz.localize(valid_until.replace(
|
||||
valid_until = valid_until.replace(
|
||||
year=replace_date.year,
|
||||
month=replace_date.month,
|
||||
day=replace_date.day,
|
||||
hour=23, minute=59, second=59, microsecond=0,
|
||||
tzinfo=None
|
||||
))
|
||||
tzinfo=tz
|
||||
)
|
||||
|
||||
if self.validity_dynamic_duration_hours:
|
||||
valid_until += timedelta(hours=self.validity_dynamic_duration_hours)
|
||||
@@ -950,6 +951,9 @@ class Item(LoggedModel):
|
||||
if self.validity_dynamic_duration_minutes:
|
||||
valid_until += timedelta(minutes=self.validity_dynamic_duration_minutes)
|
||||
|
||||
if not datetime_exists(valid_until):
|
||||
valid_until += timedelta(hours=1)
|
||||
|
||||
return requested_start, valid_until
|
||||
|
||||
else:
|
||||
@@ -1589,6 +1593,8 @@ class Question(LoggedModel):
|
||||
if not Question.objects.filter(event=self.event, identifier=code).exists():
|
||||
self.identifier = code
|
||||
break
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'identifier'}.union(kwargs['update_fields'])
|
||||
super().save(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
@@ -1678,7 +1684,7 @@ class Question(LoggedModel):
|
||||
try:
|
||||
dt = dateutil.parser.parse(answer)
|
||||
if is_naive(dt):
|
||||
dt = make_aware(dt, pytz.timezone(self.event.settings.timezone))
|
||||
dt = make_aware(dt, ZoneInfo(self.event.settings.timezone))
|
||||
except:
|
||||
raise ValidationError(_('Invalid datetime input.'))
|
||||
else:
|
||||
@@ -1736,6 +1742,8 @@ class QuestionOption(models.Model):
|
||||
if not QuestionOption.objects.filter(question__event=self.question.event, identifier=code).exists():
|
||||
self.identifier = code
|
||||
break
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'identifier'}.union(kwargs['update_fields'])
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -42,10 +42,10 @@ from collections import Counter
|
||||
from datetime import datetime, time, timedelta
|
||||
from decimal import Decimal
|
||||
from typing import Any, Dict, List, Union
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import dateutil
|
||||
import pycountry
|
||||
import pytz
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models, transaction
|
||||
@@ -461,14 +461,20 @@ class Order(LockModel, LoggedModel):
|
||||
return '{event}-{code}'.format(event=self.event.slug.upper(), code=self.code)
|
||||
|
||||
def save(self, **kwargs):
|
||||
if 'update_fields' in kwargs and 'last_modified' not in kwargs['update_fields']:
|
||||
kwargs['update_fields'] = list(kwargs['update_fields']) + ['last_modified']
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'last_modified'}.union(kwargs['update_fields'])
|
||||
if not self.code:
|
||||
self.assign_code()
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'code'}.union(kwargs['update_fields'])
|
||||
if not self.datetime:
|
||||
self.datetime = now()
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'datetime'}.union(kwargs['update_fields'])
|
||||
if not self.expires:
|
||||
self.set_expires()
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'expires'}.union(kwargs['update_fields'])
|
||||
|
||||
is_new = not self.pk
|
||||
update_fields = kwargs.get('update_fields', [])
|
||||
@@ -496,7 +502,7 @@ class Order(LockModel, LoggedModel):
|
||||
|
||||
def set_expires(self, now_dt=None, subevents=None):
|
||||
now_dt = now_dt or now()
|
||||
tz = pytz.timezone(self.event.settings.timezone)
|
||||
tz = ZoneInfo(self.event.settings.timezone)
|
||||
mode = self.event.settings.get('payment_term_mode')
|
||||
if mode == 'days':
|
||||
exp_by_date = now_dt.astimezone(tz) + timedelta(days=self.event.settings.get('payment_term_days', as_type=int))
|
||||
@@ -870,7 +876,7 @@ class Order(LockModel, LoggedModel):
|
||||
|
||||
@property
|
||||
def payment_term_last(self):
|
||||
tz = pytz.timezone(self.event.settings.timezone)
|
||||
tz = ZoneInfo(self.event.settings.timezone)
|
||||
term_last = self.event.settings.get('payment_term_last', as_type=RelativeDateWrapper)
|
||||
if term_last:
|
||||
if self.event.has_subevents:
|
||||
@@ -1230,7 +1236,7 @@ class QuestionAnswer(models.Model):
|
||||
try:
|
||||
d = dateutil.parser.parse(self.answer)
|
||||
if self.orderposition:
|
||||
tz = pytz.timezone(self.orderposition.order.event.settings.timezone)
|
||||
tz = ZoneInfo(self.orderposition.order.event.settings.timezone)
|
||||
d = d.astimezone(tz)
|
||||
return date_format(d, "SHORT_DATETIME_FORMAT")
|
||||
except ValueError:
|
||||
@@ -1442,12 +1448,20 @@ class AbstractPosition(models.Model):
|
||||
else self.variation.quotas.filter(subevent=self.subevent))
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
update_fields = kwargs.get('update_fields', [])
|
||||
update_fields = kwargs.get('update_fields', set())
|
||||
if 'attendee_name_parts' in update_fields:
|
||||
update_fields.append('attendee_name_cached')
|
||||
self.attendee_name_cached = self.attendee_name
|
||||
kwargs['update_fields'] = {'attendee_name_cached'}.union(kwargs['update_fields'])
|
||||
|
||||
name = self.attendee_name
|
||||
if name != self.attendee_name_cached:
|
||||
self.attendee_name_cached = name
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'attendee_name_cached'}.union(kwargs['update_fields'])
|
||||
|
||||
if self.attendee_name_parts is None:
|
||||
self.attendee_name_parts = {}
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'attendee_name_parts'}.union(kwargs['update_fields'])
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
@@ -1827,6 +1841,8 @@ class OrderPayment(models.Model):
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.local_id:
|
||||
self.local_id = (self.order.payments.aggregate(m=Max('local_id'))['m'] or 0) + 1
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'local_id'}.union(kwargs['update_fields'])
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def create_external_refund(self, amount=None, execution_date=None, info='{}'):
|
||||
@@ -2025,6 +2041,8 @@ class OrderRefund(models.Model):
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.local_id:
|
||||
self.local_id = (self.order.refunds.aggregate(m=Max('local_id'))['m'] or 0) + 1
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'local_id'}.union(kwargs['update_fields'])
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
@@ -2443,14 +2461,20 @@ class OrderPosition(AbstractPosition):
|
||||
assign_ticket_secret(
|
||||
event=self.order.event, position=self, force_invalidate=True, save=False
|
||||
)
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'secret'}.union(kwargs['update_fields'])
|
||||
|
||||
if not self.blocked:
|
||||
if not self.blocked and self.blocked is not None:
|
||||
self.blocked = None
|
||||
elif not isinstance(self.blocked, list) or any(not isinstance(b, str) for b in self.blocked):
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'blocked'}.union(kwargs['update_fields'])
|
||||
elif self.blocked and (not isinstance(self.blocked, list) or any(not isinstance(b, str) for b in self.blocked)):
|
||||
raise TypeError("blocked needs to be a list of strings")
|
||||
|
||||
if not self.pseudonymization_id:
|
||||
self.assign_pseudonymization_id()
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'pseudonymization_id'}.union(kwargs['update_fields'])
|
||||
|
||||
if not self.get_deferred_fields():
|
||||
if Transaction.key(self) != self.__initial_transaction_key or self.canceled != self.__initial_canceled or not self.pk:
|
||||
@@ -2936,10 +2960,17 @@ class InvoiceAddress(models.Model):
|
||||
self.order.touch()
|
||||
|
||||
if self.name_parts:
|
||||
self.name_cached = self.name
|
||||
name = self.name
|
||||
if self.name_cached != name:
|
||||
self.name_cached = self.name
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'name_cached'}.union(kwargs['update_fields'])
|
||||
else:
|
||||
self.name_cached = ""
|
||||
self.name_parts = {}
|
||||
if self.name_cached != "" or self.name_parts != {}:
|
||||
self.name_cached = ""
|
||||
self.name_parts = {}
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'name_cached', 'name_parts'}.union(kwargs['update_fields'])
|
||||
super().save(**kwargs)
|
||||
|
||||
def describe(self):
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
import string
|
||||
from datetime import date, datetime, time
|
||||
|
||||
import pytz
|
||||
import pytz_deprecation_shim
|
||||
from django.conf import settings
|
||||
from django.core.mail import get_connection
|
||||
from django.core.validators import MinLengthValidator, RegexValidator
|
||||
@@ -102,6 +102,7 @@ class Organizer(LoggedModel):
|
||||
is_new = not self.pk
|
||||
obj = super().save(*args, **kwargs)
|
||||
if is_new:
|
||||
kwargs.pop('update_fields', None) # does not make sense here
|
||||
self.set_defaults()
|
||||
else:
|
||||
self.get_cache().clear()
|
||||
@@ -140,7 +141,7 @@ class Organizer(LoggedModel):
|
||||
|
||||
@property
|
||||
def timezone(self):
|
||||
return pytz.timezone(self.settings.timezone)
|
||||
return pytz_deprecation_shim.timezone(self.settings.timezone)
|
||||
|
||||
@cached_property
|
||||
def all_logentries_link(self):
|
||||
|
||||
@@ -502,7 +502,10 @@ class Voucher(LoggedModel):
|
||||
return seat
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.code = self.code.upper()
|
||||
if self.code != self.code.upper():
|
||||
self.code = self.code.upper()
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'code'}.union(kwargs['update_fields'])
|
||||
super().save(*args, **kwargs)
|
||||
self.event.cache.set('vouchers_exist', True)
|
||||
|
||||
|
||||
@@ -126,12 +126,19 @@ class WaitingListEntry(LoggedModel):
|
||||
raise ValidationError('Invalid input')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
update_fields = kwargs.get('update_fields', [])
|
||||
update_fields = kwargs.get('update_fields', set())
|
||||
if 'name_parts' in update_fields:
|
||||
update_fields.append('name_cached')
|
||||
self.name_cached = self.name
|
||||
kwargs['update_fields'] = {'name_cached'}.union(kwargs['update_fields'])
|
||||
name = self.name
|
||||
if name != self.name_cached:
|
||||
self.name_cached = name
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'name_cached'}.union(kwargs['update_fields'])
|
||||
|
||||
if self.name_parts is None:
|
||||
self.name_parts = {}
|
||||
if 'update_fields' in kwargs:
|
||||
kwargs['update_fields'] = {'name_parts'}.union(kwargs['update_fields'])
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
|
||||
@@ -210,7 +210,7 @@ class SubeventColumn(ImportColumn):
|
||||
for format in input_formats:
|
||||
try:
|
||||
d = datetime.datetime.strptime(value, format)
|
||||
d = self.event.timezone.localize(d)
|
||||
d = d.replace(tzinfo=self.event.timezone)
|
||||
try:
|
||||
se = self.event.subevents.get(
|
||||
active=True,
|
||||
@@ -660,7 +660,7 @@ class ValidFrom(ImportColumn):
|
||||
for format in input_formats:
|
||||
try:
|
||||
d = datetime.datetime.strptime(value, format)
|
||||
d = self.event.timezone.localize(d)
|
||||
d = d.replace(tzinfo=self.event.timezone)
|
||||
return d
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
@@ -683,7 +683,7 @@ class ValidUntil(ImportColumn):
|
||||
for format in input_formats:
|
||||
try:
|
||||
d = datetime.datetime.strptime(value, format)
|
||||
d = self.event.timezone.localize(d)
|
||||
d = d.replace(tzinfo=self.event.timezone)
|
||||
return d
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
@@ -39,8 +39,8 @@ import logging
|
||||
from collections import OrderedDict
|
||||
from decimal import ROUND_HALF_UP, Decimal
|
||||
from typing import Any, Dict, Union
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import pytz
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
@@ -518,7 +518,7 @@ class BasePaymentProvider:
|
||||
|
||||
def _is_still_available(self, now_dt=None, cart_id=None, order=None):
|
||||
now_dt = now_dt or now()
|
||||
tz = pytz.timezone(self.event.settings.timezone)
|
||||
tz = ZoneInfo(self.event.settings.timezone)
|
||||
|
||||
availability_date = self.settings.get('_availability_date', as_type=RelativeDateWrapper)
|
||||
if availability_date:
|
||||
|
||||
@@ -61,7 +61,6 @@ from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _, pgettext
|
||||
from i18nfield.strings import LazyI18nString
|
||||
from pypdf import PdfReader
|
||||
from pytz import timezone
|
||||
from reportlab.graphics import renderPDF
|
||||
from reportlab.graphics.barcode.qr import QrCodeWidget
|
||||
from reportlab.graphics.shapes import Drawing
|
||||
@@ -237,7 +236,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Event begin date and time"),
|
||||
"editor_sample": _("2017-05-31 20:00"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
ev.date_from.astimezone(timezone(ev.settings.timezone)),
|
||||
ev.date_from.astimezone(ev.timezone),
|
||||
"SHORT_DATETIME_FORMAT"
|
||||
) if ev.date_from else ""
|
||||
}),
|
||||
@@ -245,7 +244,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Event begin date"),
|
||||
"editor_sample": _("2017-05-31"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
ev.date_from.astimezone(timezone(ev.settings.timezone)),
|
||||
ev.date_from.astimezone(ev.timezone),
|
||||
"SHORT_DATE_FORMAT"
|
||||
) if ev.date_from else ""
|
||||
}),
|
||||
@@ -263,7 +262,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Event end date and time"),
|
||||
"editor_sample": _("2017-05-31 22:00"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
ev.date_to.astimezone(timezone(ev.settings.timezone)),
|
||||
ev.date_to.astimezone(ev.timezone),
|
||||
"SHORT_DATETIME_FORMAT"
|
||||
) if ev.date_to else ""
|
||||
}),
|
||||
@@ -271,7 +270,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Event end date"),
|
||||
"editor_sample": _("2017-05-31"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
ev.date_to.astimezone(timezone(ev.settings.timezone)),
|
||||
ev.date_to.astimezone(ev.timezone),
|
||||
"SHORT_DATE_FORMAT"
|
||||
) if ev.date_to else ""
|
||||
}),
|
||||
@@ -279,7 +278,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Event end time"),
|
||||
"editor_sample": _("22:00"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
ev.date_to.astimezone(timezone(ev.settings.timezone)),
|
||||
ev.date_to.astimezone(ev.timezone),
|
||||
"TIME_FORMAT"
|
||||
) if ev.date_to else ""
|
||||
}),
|
||||
@@ -292,7 +291,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Event admission date and time"),
|
||||
"editor_sample": _("2017-05-31 19:00"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
ev.date_admission.astimezone(timezone(ev.settings.timezone)),
|
||||
ev.date_admission.astimezone(ev.timezone),
|
||||
"SHORT_DATETIME_FORMAT"
|
||||
) if ev.date_admission else ""
|
||||
}),
|
||||
@@ -300,7 +299,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Event admission time"),
|
||||
"editor_sample": _("19:00"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
ev.date_admission.astimezone(timezone(ev.settings.timezone)),
|
||||
ev.date_admission.astimezone(ev.timezone),
|
||||
"TIME_FORMAT"
|
||||
) if ev.date_admission else ""
|
||||
}),
|
||||
@@ -385,7 +384,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Printing date"),
|
||||
"editor_sample": _("2017-05-31"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
now().astimezone(timezone(ev.settings.timezone)),
|
||||
now().astimezone(ev.timezone),
|
||||
"SHORT_DATE_FORMAT"
|
||||
)
|
||||
}),
|
||||
@@ -393,7 +392,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Printing date and time"),
|
||||
"editor_sample": _("2017-05-31 19:00"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
now().astimezone(timezone(ev.settings.timezone)),
|
||||
now().astimezone(ev.timezone),
|
||||
"SHORT_DATETIME_FORMAT"
|
||||
)
|
||||
}),
|
||||
@@ -401,7 +400,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Printing time"),
|
||||
"editor_sample": _("19:00"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
now().astimezone(timezone(ev.settings.timezone)),
|
||||
now().astimezone(ev.timezone),
|
||||
"TIME_FORMAT"
|
||||
)
|
||||
}),
|
||||
@@ -409,7 +408,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Validity start date"),
|
||||
"editor_sample": _("2017-05-31"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
op.valid_from.astimezone(timezone(ev.settings.timezone)),
|
||||
op.valid_from.astimezone(ev.timezone),
|
||||
"SHORT_DATE_FORMAT"
|
||||
) if op.valid_from else ""
|
||||
}),
|
||||
@@ -417,7 +416,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Validity start date and time"),
|
||||
"editor_sample": _("2017-05-31 19:00"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
op.valid_from.astimezone(timezone(ev.settings.timezone)),
|
||||
op.valid_from.astimezone(ev.timezone),
|
||||
"SHORT_DATETIME_FORMAT"
|
||||
) if op.valid_from else ""
|
||||
}),
|
||||
@@ -425,7 +424,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Validity start time"),
|
||||
"editor_sample": _("19:00"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
op.valid_from.astimezone(timezone(ev.settings.timezone)),
|
||||
op.valid_from.astimezone(ev.timezone),
|
||||
"TIME_FORMAT"
|
||||
) if op.valid_from else ""
|
||||
}),
|
||||
@@ -433,7 +432,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Validity end date"),
|
||||
"editor_sample": _("2017-05-31"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
op.valid_until.astimezone(timezone(ev.settings.timezone)),
|
||||
op.valid_until.astimezone(ev.timezone),
|
||||
"SHORT_DATE_FORMAT"
|
||||
) if op.valid_until else ""
|
||||
}),
|
||||
@@ -441,7 +440,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Validity end date and time"),
|
||||
"editor_sample": _("2017-05-31 19:00"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
op.valid_until.astimezone(timezone(ev.settings.timezone)),
|
||||
op.valid_until.astimezone(ev.timezone),
|
||||
"SHORT_DATETIME_FORMAT"
|
||||
) if op.valid_until else ""
|
||||
}),
|
||||
@@ -449,7 +448,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"label": _("Validity end time"),
|
||||
"editor_sample": _("19:00"),
|
||||
"evaluate": lambda op, order, ev: date_format(
|
||||
op.valid_until.astimezone(timezone(ev.settings.timezone)),
|
||||
op.valid_until.astimezone(ev.timezone),
|
||||
"TIME_FORMAT"
|
||||
) if op.valid_until else ""
|
||||
}),
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
import datetime
|
||||
from collections import namedtuple
|
||||
from typing import Union
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import pytz
|
||||
from dateutil import parser
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
@@ -67,7 +67,7 @@ class RelativeDateWrapper:
|
||||
if self.data.minutes_before is not None:
|
||||
raise ValueError('A minute-based relative datetime can not be used as a date')
|
||||
|
||||
tz = pytz.timezone(event.settings.timezone)
|
||||
tz = ZoneInfo(event.settings.timezone)
|
||||
if isinstance(event, SubEvent):
|
||||
base_date = (
|
||||
getattr(event, self.data.base_date_name)
|
||||
@@ -86,7 +86,7 @@ class RelativeDateWrapper:
|
||||
if isinstance(self.data, (datetime.datetime, datetime.date)):
|
||||
return self.data
|
||||
else:
|
||||
tz = pytz.timezone(event.settings.timezone)
|
||||
tz = ZoneInfo(event.settings.timezone)
|
||||
if isinstance(event, SubEvent):
|
||||
base_date = (
|
||||
getattr(event, self.data.base_date_name)
|
||||
@@ -99,8 +99,7 @@ class RelativeDateWrapper:
|
||||
if self.data.minutes_before is not None:
|
||||
return base_date.astimezone(tz) - datetime.timedelta(minutes=self.data.minutes_before)
|
||||
else:
|
||||
oldoffset = base_date.astimezone(tz).utcoffset()
|
||||
new_date = base_date.astimezone(tz) - datetime.timedelta(days=self.data.days_before)
|
||||
new_date = (base_date.astimezone(tz) - datetime.timedelta(days=self.data.days_before)).astimezone(tz)
|
||||
if self.data.time:
|
||||
new_date = new_date.replace(
|
||||
hour=self.data.time.hour,
|
||||
@@ -108,8 +107,6 @@ class RelativeDateWrapper:
|
||||
second=self.data.time.second
|
||||
)
|
||||
new_date = new_date.astimezone(tz)
|
||||
new_offset = new_date.utcoffset()
|
||||
new_date += oldoffset - new_offset
|
||||
return new_date
|
||||
|
||||
def to_string(self) -> str:
|
||||
|
||||
@@ -32,12 +32,12 @@
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from functools import partial, reduce
|
||||
|
||||
import dateutil
|
||||
import dateutil.parser
|
||||
import pytz
|
||||
from dateutil.tz import datetime_exists
|
||||
from django.core.files import File
|
||||
from django.db import IntegrityError, transaction
|
||||
from django.db.models import (
|
||||
@@ -439,7 +439,7 @@ class SQLLogic:
|
||||
|
||||
if operator == 'buildTime':
|
||||
if values[0] == "custom":
|
||||
return Value(dateutil.parser.parse(values[1]).astimezone(pytz.UTC))
|
||||
return Value(dateutil.parser.parse(values[1]).astimezone(timezone.utc))
|
||||
elif values[0] == "customtime":
|
||||
parsed = dateutil.parser.parse(values[1])
|
||||
return Value(now().astimezone(self.list.event.timezone).replace(
|
||||
@@ -447,7 +447,7 @@ class SQLLogic:
|
||||
minute=parsed.minute,
|
||||
second=parsed.second,
|
||||
microsecond=parsed.microsecond,
|
||||
).astimezone(pytz.UTC))
|
||||
).astimezone(timezone.utc))
|
||||
elif values[0] == 'date_from':
|
||||
return Coalesce(
|
||||
F('subevent__date_from'),
|
||||
@@ -475,7 +475,7 @@ class SQLLogic:
|
||||
return int(values[1])
|
||||
elif operator == 'var':
|
||||
if values[0] == 'now':
|
||||
return Value(now().astimezone(pytz.UTC))
|
||||
return Value(now().astimezone(timezone.utc))
|
||||
elif values[0] == 'now_isoweekday':
|
||||
return Value(now().astimezone(self.list.event.timezone).isoweekday())
|
||||
elif values[0] == 'product':
|
||||
@@ -926,14 +926,11 @@ def process_exit_all(sender, **kwargs):
|
||||
if cl.event.settings.get(f'autocheckin_dst_hack_{cl.pk}'): # move time back if yesterday was DST switch
|
||||
d -= timedelta(hours=1)
|
||||
cl.event.settings.delete(f'autocheckin_dst_hack_{cl.pk}')
|
||||
try:
|
||||
cl.exit_all_at = make_aware(datetime.combine(d.date() + timedelta(days=1), d.time()), cl.event.timezone)
|
||||
except pytz.exceptions.AmbiguousTimeError:
|
||||
cl.exit_all_at = make_aware(datetime.combine(d.date() + timedelta(days=1), d.time()), cl.event.timezone,
|
||||
is_dst=False)
|
||||
except pytz.exceptions.NonExistentTimeError:
|
||||
|
||||
cl.exit_all_at = make_aware(datetime.combine(d.date() + timedelta(days=1), d.time().replace(fold=1)), cl.event.timezone)
|
||||
if not datetime_exists(cl.exit_all_at):
|
||||
cl.event.settings.set(f'autocheckin_dst_hack_{cl.pk}', True)
|
||||
d += timedelta(hours=1)
|
||||
cl.exit_all_at = make_aware(datetime.combine(d.date() + timedelta(days=1), d.time()), cl.event.timezone)
|
||||
cl.exit_all_at = make_aware(datetime.combine(d.date() + timedelta(days=1), d.time().replace(fold=1)), cl.event.timezone)
|
||||
# AmbiguousTimeError shouldn't be possible since d.time() includes fold=0
|
||||
cl.save(update_fields=['exit_all_at'])
|
||||
|
||||
@@ -45,8 +45,8 @@ from email.mime.image import MIMEImage
|
||||
from email.utils import formataddr
|
||||
from typing import Any, Dict, List, Sequence, Union
|
||||
from urllib.parse import urljoin, urlparse
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import pytz
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from celery import chain
|
||||
@@ -226,11 +226,11 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
|
||||
if event:
|
||||
timezone = event.timezone
|
||||
elif user:
|
||||
timezone = pytz.timezone(user.timezone)
|
||||
timezone = ZoneInfo(user.timezone)
|
||||
elif organizer:
|
||||
timezone = organizer.timezone
|
||||
else:
|
||||
timezone = pytz.timezone(settings.TIME_ZONE)
|
||||
timezone = ZoneInfo(settings.TIME_ZONE)
|
||||
|
||||
if settings_holder:
|
||||
if settings_holder.settings.mail_bcc:
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{# this is the version from django 3.x, prior to https://github.com/django/django/commit/5942ab5eb165ee2e759174e297148a40dd855920 so that django-bootstrap3 can keep doing its magic #}
|
||||
{% with id=widget.attrs.id %}<ul{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>{% for group, options, index in widget.optgroups %}{% if group %}
|
||||
<li>{{ group }}<ul{% if id %} id="{{ id }}_{{ index }}"{% endif %}>{% endif %}{% for option in options %}
|
||||
<li>{% include option.template_name with widget=option %}</li>{% endfor %}{% if group %}
|
||||
</ul></li>{% endif %}{% endfor %}
|
||||
</ul>{% endwith %}
|
||||
@@ -20,11 +20,10 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import calendar
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from datetime import date, datetime, time, timedelta, timezone
|
||||
from itertools import groupby
|
||||
from typing import Optional, Tuple
|
||||
|
||||
import pytz
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.formats import date_format
|
||||
@@ -392,7 +391,7 @@ class SerializerDateFrameField(serializers.CharField):
|
||||
if data is None:
|
||||
return None
|
||||
try:
|
||||
resolve_timeframe_to_dates_inclusive(now(), data, pytz.UTC)
|
||||
resolve_timeframe_to_dates_inclusive(now(), data, timezone.utc)
|
||||
except:
|
||||
raise ValidationError("Invalid date frame")
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#
|
||||
import logging
|
||||
from importlib import import_module
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import celery.exceptions
|
||||
import pytz
|
||||
from celery import states
|
||||
from celery.result import AsyncResult
|
||||
from django.conf import settings
|
||||
@@ -252,7 +252,7 @@ class AsyncFormView(AsyncMixin, FormView):
|
||||
task_self = self
|
||||
view_instance._task_self = task_self
|
||||
|
||||
with translation.override(locale), timezone.override(pytz.timezone(tz)):
|
||||
with translation.override(locale), timezone.override(ZoneInfo(tz)):
|
||||
form_class = view_instance.get_form_class()
|
||||
if form_kwargs.get('instance'):
|
||||
form_kwargs['instance'] = cls.model.objects.get(pk=form_kwargs['instance'])
|
||||
@@ -302,7 +302,7 @@ class AsyncFormView(AsyncMixin, FormView):
|
||||
'url_args': self.args,
|
||||
'url_kwargs': self.kwargs,
|
||||
'locale': get_language(),
|
||||
'tz': get_current_timezone().zone,
|
||||
'tz': str(get_current_timezone()),
|
||||
}
|
||||
if hasattr(self.request, 'organizer'):
|
||||
kwargs['organizer'] = self.request.organizer.pk
|
||||
@@ -377,7 +377,7 @@ class AsyncPostView(AsyncMixin, View):
|
||||
task_self = self
|
||||
view_instance._task_self = task_self
|
||||
|
||||
with translation.override(locale), timezone.override(pytz.timezone(tz)):
|
||||
with translation.override(locale), timezone.override(ZoneInfo(tz)):
|
||||
return view_instance.async_post(view_instance.request, *url_args, **url_kwargs)
|
||||
|
||||
cls.async_execute = app.task(
|
||||
@@ -405,7 +405,7 @@ class AsyncPostView(AsyncMixin, View):
|
||||
'locale': get_language(),
|
||||
'url_args': args,
|
||||
'url_kwargs': kwargs,
|
||||
'tz': get_current_timezone().zone,
|
||||
'tz': str(get_current_timezone()),
|
||||
}
|
||||
if hasattr(self.request, 'organizer'):
|
||||
kwargs['organizer'] = self.request.organizer.pk
|
||||
|
||||
Reference in New Issue
Block a user