Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions common/djangoapps/course_modes/admin.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
"""Django admin for course_modes"""


from zoneinfo import ZoneInfo

from django import forms
from django.conf import settings
from django.contrib import admin
from django.http.request import QueryDict
from django.utils.translation import gettext_lazy as _
from opaque_keys.edx.keys import CourseKey
from pytz import UTC, timezone

from common.djangoapps.course_modes.models import CourseMode, CourseModeExpirationConfig
# Technically, we shouldn't be doing this, since verify_student is defined
Expand Down Expand Up @@ -73,15 +74,15 @@ def __init__(self, *args, **kwargs):
# However, the args copy above before the super() call handles this case.
pass

default_tz = timezone(settings.TIME_ZONE)
default_tz = ZoneInfo(settings.TIME_ZONE)

if self.instance._expiration_datetime:
# django admin is using default timezone. To avoid time conversion from db to form
# convert the UTC object to naive and then localize with default timezone.
_expiration_datetime = self.instance._expiration_datetime.replace(
tzinfo=None
)
self.initial["_expiration_datetime"] = default_tz.localize(_expiration_datetime)
self.initial["_expiration_datetime"] = _expiration_datetime.replace(tzinfo=default_tz)
# Load the verification deadline
# Since this is stored on a model in verify student, we need to load it from there.
# We need to munge the timezone a bit to get Django admin to display it without converting
Expand All @@ -90,7 +91,7 @@ def __init__(self, *args, **kwargs):
if self.instance.course_id and self.instance.mode_slug in CourseMode.VERIFIED_MODES:
deadline = verification_models.VerificationDeadline.deadline_for_course(self.instance.course_id)
self.initial["verification_deadline"] = (
default_tz.localize(deadline.replace(tzinfo=None))
deadline.replace(tzinfo=default_tz)
if deadline is not None else None
)

Expand All @@ -107,14 +108,14 @@ def clean__expiration_datetime(self):
# django admin saving the date with default timezone to avoid time conversion from form to db
# changes its tzinfo to UTC
if self.cleaned_data.get("_expiration_datetime"):
return self.cleaned_data.get("_expiration_datetime").replace(tzinfo=UTC)
return self.cleaned_data.get("_expiration_datetime").replace(tzinfo=ZoneInfo("UTC"))

def clean_verification_deadline(self):
"""
Ensure that the verification deadline we save uses the UTC timezone.
"""
if self.cleaned_data.get("verification_deadline"):
return self.cleaned_data.get("verification_deadline").replace(tzinfo=UTC)
return self.cleaned_data.get("verification_deadline").replace(tzinfo=ZoneInfo("UTC"))

def clean(self):
"""
Expand Down
5 changes: 3 additions & 2 deletions common/djangoapps/course_modes/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
import ddt
from django.conf import settings
from django.urls import reverse
from pytz import UTC, timezone
from pytz import timezone
from zoneinfo import ZoneInfo

from common.djangoapps.course_modes.admin import CourseModeForm
from common.djangoapps.course_modes.models import CourseMode
Expand Down Expand Up @@ -84,7 +85,7 @@ class AdminCourseModeFormTest(ModuleStoreTestCase):
Test the course modes Django admin form validation and saving.
"""

UPGRADE_DEADLINE = datetime.now(UTC)
UPGRADE_DEADLINE = datetime.now(ZoneInfo("UTC"))
VERIFICATION_DEADLINE = UPGRADE_DEADLINE + timedelta(days=5)

def setUp(self):
Expand Down
4 changes: 2 additions & 2 deletions common/djangoapps/course_modes/tests/test_signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

from datetime import datetime, timedelta
from unittest.mock import patch
from zoneinfo import ZoneInfo

import ddt
from django.conf import settings
from pytz import UTC

from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.course_modes.signals import _listen_for_course_publish
Expand All @@ -26,7 +26,7 @@ class CourseModeSignalTest(ModuleStoreTestCase):

def setUp(self):
super().setUp()
self.end = datetime.now(tz=UTC).replace(microsecond=0) + timedelta(days=7)
self.end = datetime.now(tz=ZoneInfo("UTC")).replace(microsecond=0) + timedelta(days=7)
self.course = CourseFactory.create(end=self.end)
CourseMode.objects.all().delete()

Expand Down
4 changes: 2 additions & 2 deletions common/djangoapps/course_modes/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
from datetime import datetime, timedelta
from unittest.mock import patch
from urllib.parse import urljoin
from zoneinfo import ZoneInfo

import ddt
import freezegun
import httpretty
import pytz
from django.conf import settings
from django.test import override_settings
from django.urls import reverse
Expand Down Expand Up @@ -50,7 +50,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest
@patch.dict(settings.FEATURES, {'MODE_CREATION_FOR_TESTING': True})
def setUp(self):
super().setUp()
now = datetime.now(pytz.utc)
now = datetime.now(ZoneInfo("UTC"))
day = timedelta(days=1)
tomorrow = now + day
yesterday = now - day
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import uuid
from datetime import datetime, timedelta
from unittest.mock import patch
from zoneinfo import ZoneInfo

from django.conf import settings
from django.urls import reverse
from django.utils.timezone import now
from opaque_keys.edx.locator import CourseKey
from pytz import UTC

from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.course_modes.tests.factories import CourseModeFactory
Expand Down Expand Up @@ -1023,7 +1023,7 @@ def test_already_enrolled_course_ended(self, mock_get_course_runs):
mock_get_course_runs.return_value = self.return_values

# Setup enrollment period to be in the past
utc_now = datetime.now(UTC)
utc_now = datetime.now(ZoneInfo("UTC"))
self.course.start = utc_now - timedelta(days=15)
self.course.end = utc_now - timedelta(days=1)
self.course = self.update_course(self.course, self.user.id)
Expand Down
4 changes: 2 additions & 2 deletions common/djangoapps/entitlements/tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

from datetime import datetime, timedelta
from unittest import mock
from zoneinfo import ZoneInfo

import pytest
import pytz
from django.test import TestCase

from common.djangoapps.entitlements import tasks
Expand All @@ -19,7 +19,7 @@

def make_entitlement(expired=False): # lint-amnesty, pylint: disable=missing-function-docstring
age = CourseEntitlementPolicy.DEFAULT_EXPIRATION_PERIOD_DAYS
past_datetime = datetime.now(tz=pytz.UTC) - timedelta(days=age)
past_datetime = datetime.now(tz=ZoneInfo("UTC")) - timedelta(days=age)
expired_at = past_datetime if expired else None
entitlement = CourseEntitlementFactory.create(created=past_datetime, expired_at=expired_at)
return entitlement
Expand Down
4 changes: 2 additions & 2 deletions common/djangoapps/student/management/commands/assigngroups.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
import random
import sys
from textwrap import dedent
from zoneinfo import ZoneInfo

from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.management.base import BaseCommand
from pytz import UTC

from common.djangoapps.student.models import UserTestGroup

Expand Down Expand Up @@ -75,7 +75,7 @@ def handle(self, *args, **options):
utg = UserTestGroup()
utg.name = group
utg.description = json.dumps({"description": options['description']}, # lint-amnesty, pylint: disable=too-many-function-args
{"time": datetime.datetime.now(UTC).isoformat()})
{"time": datetime.datetime.now(ZoneInfo("UTC")).isoformat()})
group_objects[group] = utg
group_objects[group].save()

Expand Down
22 changes: 14 additions & 8 deletions common/djangoapps/student/models/course_enrollment.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from collections import defaultdict, namedtuple # lint-amnesty, pylint: disable=wrong-import-order
from datetime import date, datetime, timedelta # lint-amnesty, pylint: disable=wrong-import-order
from urllib.parse import urljoin
from zoneinfo import ZoneInfo

from config_models.models import ConfigurationModel
from django.conf import settings
Expand All @@ -29,7 +30,6 @@
COURSE_UNENROLLMENT_COMPLETED,
)
from openedx_filters.learning.filters import CourseEnrollmentStarted, CourseUnenrollmentStarted
from pytz import UTC
from requests.exceptions import HTTPError, RequestException
from simple_history.models import HistoricalRecords

Expand Down Expand Up @@ -152,7 +152,7 @@ def with_certificates(self, username):
"""
return self.filter(course_id__in=self.get_user_course_ids_with_certificates(username))

def in_progress(self, username, time_zone=UTC):
def in_progress(self, username, time_zone=ZoneInfo("UTC")):
"""
Returns a queryset of CourseEnrollment objects for courses that are currently in progress.
"""
Expand All @@ -170,7 +170,7 @@ def completed(self, username):
"""
return self.active().with_certificates(username)

def expired(self, username, time_zone=UTC):
def expired(self, username, time_zone=ZoneInfo("UTC")):
"""
Returns a queryset of CourseEnrollment objects for courses that have expired.
"""
Expand Down Expand Up @@ -1087,7 +1087,7 @@ def refundable(self):
if refund_cutoff_date is None:
log.info("Refund cutoff date is null")
return False
if datetime.now(UTC) > refund_cutoff_date:
if datetime.now(ZoneInfo("UTC")) > refund_cutoff_date:
log.info(f"Refund cutoff date: {refund_cutoff_date} has passed")
return False

Expand Down Expand Up @@ -1133,7 +1133,10 @@ def refund_cutoff_date(self):
self.course_overview.start.replace(tzinfo=None)
)

return refund_window_start_date.replace(tzinfo=UTC) + EnrollmentRefundConfiguration.current().refund_window
return (
refund_window_start_date.replace(tzinfo=ZoneInfo("UTC"))
+ EnrollmentRefundConfiguration.current().refund_window
)

def is_order_voucher_refundable(self):
""" Checks if the coupon batch expiration date has passed to determine whether order voucher is refundable. """
Expand All @@ -1142,8 +1145,11 @@ def is_order_voucher_refundable(self):
if not vouchers:
return False
voucher_end_datetime_str = vouchers[0]['end_datetime']
voucher_expiration_date = datetime.strptime(voucher_end_datetime_str, ECOMMERCE_DATE_FORMAT).replace(tzinfo=UTC)
return datetime.now(UTC) < voucher_expiration_date
voucher_expiration_date = (
datetime.strptime(voucher_end_datetime_str, ECOMMERCE_DATE_FORMAT)
.replace(tzinfo=ZoneInfo("UTC"))
)
return datetime.now(ZoneInfo("UTC")) < voucher_expiration_date

def get_order_attribute_from_ecommerce(self, attribute_name):
"""
Expand Down Expand Up @@ -1265,7 +1271,7 @@ def upgrade_deadline(self):
if self.dynamic_upgrade_deadline is not None:
# When course modes expire they aren't found any more and None would be returned.
# Replicate that behavior here by returning None if the personalized deadline is in the past.
if self.dynamic_upgrade_deadline <= datetime.now(UTC):
if self.dynamic_upgrade_deadline <= datetime.now(ZoneInfo("UTC")):
log.debug('Schedules: Returning None since dynamic upgrade deadline has already passed.')
return None

Expand Down
11 changes: 6 additions & 5 deletions common/djangoapps/student/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from functools import total_ordering
from importlib import import_module
from urllib.parse import urlencode
from zoneinfo import ZoneInfo

import crum
from config_models.models import ConfigurationModel
Expand Down Expand Up @@ -456,7 +457,7 @@ class Meta:
location = models.CharField(blank=True, max_length=255, db_index=True)

# Optional demographic data we started capturing from Fall 2012
this_year = datetime.now(UTC).year
this_year = datetime.now(ZoneInfo("UTC")).year
VALID_YEARS = list(range(this_year, this_year - 120, -1))
year_of_birth = models.IntegerField(blank=True, null=True, db_index=True)
GENDER_CHOICES = (
Expand Down Expand Up @@ -572,7 +573,7 @@ def has_profile_image(self):
def age(self):
""" Convenience method that returns the age given a year_of_birth. """
year_of_birth = self.year_of_birth
year = datetime.now(UTC).year
year = datetime.now(ZoneInfo("UTC")).year
if year_of_birth is not None:
return self._calculate_age(year, year_of_birth)

Expand Down Expand Up @@ -798,7 +799,7 @@ def user_post_save_callback(sender, **kwargs):
'username': user.username,
'name': profile.name,
'age': profile.age or -1,
'yearOfBirth': profile.year_of_birth or datetime.now(UTC).year,
'yearOfBirth': profile.year_of_birth or datetime.now(ZoneInfo("UTC")).year,
'education': profile.level_of_education_display,
'address': profile.mailing_address,
'gender': profile.gender_display,
Expand Down Expand Up @@ -982,7 +983,7 @@ def is_user_locked_out(cls, user):
if not record.lockout_until:
return False

now = datetime.now(UTC)
now = datetime.now(ZoneInfo("UTC"))
until = record.lockout_until
is_locked_out = until and now < until

Expand All @@ -1003,7 +1004,7 @@ def increment_lockout_counter(cls, user):
if record.failure_count >= max_failures_allowed:
# yes, then store when this account is locked out until
lockout_period_secs = settings.MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS
record.lockout_until = datetime.now(UTC) + timedelta(seconds=lockout_period_secs)
record.lockout_until = datetime.now(ZoneInfo("UTC")) + timedelta(seconds=lockout_period_secs)

record.save()

Expand Down
4 changes: 2 additions & 2 deletions common/djangoapps/student/models_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"""
import datetime
import logging
from zoneinfo import ZoneInfo

from pytz import UTC

from common.djangoapps.student.models import CourseAccessRole as _CourseAccessRole
from common.djangoapps.student.models import CourseEnrollment as _CourseEnrollment
Expand Down Expand Up @@ -158,7 +158,7 @@ def confirm_name_change(user, pending_name_change):
if 'old_names' not in meta:
meta['old_names'] = []
meta['old_names'].append(
[user_profile.name, pending_name_change.rationale, datetime.datetime.now(UTC).isoformat()]
[user_profile.name, pending_name_change.rationale, datetime.datetime.now(ZoneInfo("UTC")).isoformat()]
)
user_profile.set_meta(meta)

Expand Down
6 changes: 3 additions & 3 deletions common/djangoapps/student/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

from datetime import datetime
from uuid import uuid4
from zoneinfo import ZoneInfo

import factory
from django.contrib.auth.models import AnonymousUser, Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.test.client import RequestFactory
from factory.django import DjangoModelFactory
from opaque_keys.edx.keys import CourseKey
from pytz import UTC

from common.djangoapps.student.models import (
AccountRecovery,
Expand Down Expand Up @@ -91,8 +91,8 @@ class Meta:
is_staff = False
is_active = True
is_superuser = False
last_login = datetime(2012, 1, 1, tzinfo=UTC)
date_joined = datetime(2011, 1, 1, tzinfo=UTC)
last_login = datetime(2012, 1, 1, tzinfo=ZoneInfo("UTC"))
date_joined = datetime(2011, 1, 1, tzinfo=ZoneInfo("UTC"))

@factory.post_generation
def profile(obj, create, extracted, **kwargs): # pylint: disable=unused-argument, missing-function-docstring
Expand Down
4 changes: 2 additions & 2 deletions common/djangoapps/student/tests/test_admin_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import datetime
import json
from unittest.mock import Mock
from zoneinfo import ZoneInfo

import ddt
import pytest
Expand All @@ -17,7 +18,6 @@
from django.urls import reverse
from django.utils.timezone import now
from edx_toggles.toggles.testutils import override_waffle_switch
from pytz import UTC

from common.djangoapps.student.admin import ( # lint-amnesty, pylint: disable=line-too-long
COURSE_ENROLLMENT_ADMIN_SWITCH,
Expand Down Expand Up @@ -335,7 +335,7 @@ def setUp(self):
super().setUp()
self.client.login(username=self.user.username, password=self.TEST_PASSWORD)
self.user2 = UserFactory.create(username='Zażółć gęślą jaźń')
self.user_lockout_until = datetime.datetime.now(UTC)
self.user_lockout_until = datetime.datetime.now(ZoneInfo("UTC"))
LoginFailures.objects.create(user=self.user, failure_count=10, lockout_until=self.user_lockout_until)
LoginFailures.objects.create(user=self.user2, failure_count=2)

Expand Down
Loading
Loading