diff --git a/common/djangoapps/course_modes/admin.py b/common/djangoapps/course_modes/admin.py index d0a35c1b58..255b2ab706 100644 --- a/common/djangoapps/course_modes/admin.py +++ b/common/djangoapps/course_modes/admin.py @@ -1,3 +1,8 @@ +""" +Django admin page for course modes +""" +from django.conf import settings +from pytz import timezone, UTC from ratelimitbackend import admin from course_modes.models import CourseMode from django import forms @@ -6,6 +11,7 @@ from opaque_keys import InvalidKeyError from xmodule.modulestore.django import modulestore from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locations import SlashSeparatedCourseKey +from util.date_utils import get_time_display class CourseModeForm(forms.ModelForm): @@ -35,13 +41,37 @@ class CourseModeForm(forms.ModelForm): return course_key + def __init__(self, *args, **kwargs): + super(CourseModeForm, self).__init__(*args, **kwargs) + if self.instance.expiration_datetime: + default_tz = timezone(settings.TIME_ZONE) + # 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) + + def clean_expiration_datetime(self): + """changing the tzinfo for a given datetime object""" + # 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) + class CourseModeAdmin(admin.ModelAdmin): + """Admin for course modes""" form = CourseModeForm search_fields = ('course_id',) list_display = ( 'id', 'course_id', 'mode_slug', 'mode_display_name', 'min_price', - 'suggested_prices', 'currency', 'expiration_date', 'expiration_datetime' + 'suggested_prices', 'currency', 'expiration_date', 'expiration_datetime_custom' ) + def expiration_datetime_custom(self, obj): + """adding custom column to show the expiry_datetime""" + if obj.expiration_datetime: + return get_time_display(obj.expiration_datetime, '%B %d, %Y, %H:%M %p') + + expiration_datetime_custom.short_description = "Expiration Datetime" + admin.site.register(CourseMode, CourseModeAdmin) diff --git a/common/djangoapps/course_modes/tests/test_views.py b/common/djangoapps/course_modes/tests/test_views.py index 0aecfaae28..aa53f487ae 100644 --- a/common/djangoapps/course_modes/tests/test_views.py +++ b/common/djangoapps/course_modes/tests/test_views.py @@ -5,11 +5,14 @@ from mock import patch from django.conf import settings from django.test.utils import override_settings from django.core.urlresolvers import reverse +from pytz import timezone +from datetime import datetime from xmodule.modulestore.tests.django_utils import ( ModuleStoreTestCase, mixed_store_config ) +from util.date_utils import get_time_display from util.testing import UrlResetMixin from embargo.test_utils import restrict_course from xmodule.modulestore.tests.factories import CourseFactory @@ -314,3 +317,45 @@ class TrackSelectionEmbargoTest(UrlResetMixin, ModuleStoreTestCase): def test_embargo_allow(self): response = self.client.get(self.url) self.assertEqual(response.status_code, 200) + + +class AdminCourseModePageTest(ModuleStoreTestCase): + """Test the django admin course mode form saving data in db without any conversion + properly converts the tzinfo from default zone to utc + """ + + def test_save_valid_data(self): + user = UserFactory.create(is_staff=True, is_superuser=True) + user.save() + course = CourseFactory.create() + expiration = datetime(2015, 10, 20, 1, 10, 23, tzinfo=timezone(settings.TIME_ZONE)) + + data = { + 'course_id': unicode(course.id), + 'mode_slug': 'professional', + 'mode_display_name': 'professional', + 'min_price': 10, + 'currency': 'usd', + 'expiration_datetime_0': expiration.date(), # due to django admin datetime widget passing as seperate vals + 'expiration_datetime_1': expiration.time(), + + } + + self.client.login(username=user.username, password='test') + + # creating new course mode from django admin page + response = self.client.post(reverse('admin:course_modes_coursemode_add'), data=data) + self.assertRedirects(response, reverse('admin:course_modes_coursemode_changelist')) + + # verifying that datetime is appearing on list page + response = self.client.get(reverse('admin:course_modes_coursemode_changelist')) + self.assertContains(response, get_time_display(expiration, '%B %d, %Y, %H:%M %p')) + + # verifiying the on edit page datetime value appearing without any modifications + resp = self.client.get(reverse('admin:course_modes_coursemode_change', args=(1,))) + self.assertContains(resp, expiration.date()) + self.assertContains(resp, expiration.time()) + + # checking the values in db. comparing values without tzinfo + course_mode = CourseMode.objects.get(pk=1) + self.assertEqual(course_mode.expiration_datetime.replace(tzinfo=None), expiration.replace(tzinfo=None))