Просмотр исходного кода

Close #505: removed explicit timezone settings

Rafał Pitoń 10 лет назад
Родитель
Сommit
e1e117e34f

+ 0 - 1
misago/conf/defaults.py

@@ -128,7 +128,6 @@ MIDDLEWARE_CLASSES = (
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
     'misago.users.middleware.UserMiddleware',
-    'misago.users.middleware.TimezoneMiddleware',
     'misago.users.middleware.PreloadUserMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',

+ 1 - 3
misago/conf/forms.py

@@ -1,5 +1,5 @@
 from django.utils.translation import ugettext as _, ungettext
-from misago.core import forms, timezones
+from misago.core import forms
 
 
 __ALL__ = ['ChangeSettingsForm']
@@ -78,8 +78,6 @@ def create_choice(setting, kwargs, extra):
         kwargs['widget'] = forms.Select()
 
     kwargs['choices'] = extra.get('choices', [])
-    if kwargs['choices'] == '#TZ#':
-        kwargs['choices'] = timezones.choices()
 
     if setting.python_type == 'int':
         return forms.TypedChoiceField(coerce='int', **kwargs)

+ 5 - 8
misago/conf/migrationutils.py

@@ -33,14 +33,11 @@ def migrate_setting(Setting, group, setting_fixture, order, old_value):
     if (setting_fixture.get('field_extra') and
             setting_fixture.get('field_extra').get('choices')):
         untranslated_choices = setting_fixture['field_extra']['choices']
-        if untranslated_choices == '#TZ#':
-            setting_fixture['field_extra']['choices'] = '#TZ#'
-        else:
-            translated_choices = []
-            for val, name in untranslated_choices:
-                translated_choices.append((val, name))
-            setting_fixture['field_extra']['choices'] = tuple(
-                translated_choices)
+        translated_choices = []
+        for val, name in untranslated_choices:
+            translated_choices.append((val, name))
+        setting_fixture['field_extra']['choices'] = tuple(
+            translated_choices)
 
     if old_value is None:
         value = setting_fixture.pop('value', None)

+ 54 - 0
misago/core/forms.py

@@ -1,7 +1,11 @@
+from datetime import datetime, timedelta
+
 from mptt.forms import *  # noqa
 
 from django.forms import *  # noqa
 from django.forms import Form as BaseForm, ModelForm as BaseModelForm
+from django.utils import timezone
+from django.utils.encoding import force_text
 from django.utils.translation import ugettext_lazy as _
 
 
@@ -33,6 +37,56 @@ def YesNoSwitch(**kwargs):
         **kwargs)
 
 
+class IsoDateTimeField(DateTimeField):
+    input_formats = ['iso8601']
+    iso8601_formats = ("%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%S.%f")
+
+    def prepare_value(self, value):
+        try:
+            return value.isoformat()
+        except AttributeError:
+            return value
+
+    def strptime(self, value):
+        for format in self.iso8601_formats:
+            try:
+                return datetime.strptime(value, format)
+            except ValueError:
+                pass
+        else:
+            raise ValueError()
+
+    def to_python(self, value):
+        """
+        Validates that the input can be converted to a datetime. Returns a
+        Python datetime.datetime object.
+        """
+        if value in self.empty_values:
+            return None
+
+        try:
+            unicode_value = force_text(value, strings_only=True)
+            date = unicode_value[:-6]
+            offset = unicode_value[-6:]
+
+            local_date = self.strptime(value)
+
+            if offset and offset[0] in ('-', '+'):
+                tz_offset = timedelta(hours=int(offset[1:3]),
+                                      minutes=int(offset[4:6]))
+                tz_offset = tz_offset.seconds // 60
+                if offset[0] == '-':
+                    tz_offset *= -1
+            else:
+                tz_offset = 0
+
+            tz_correction = timezone.get_fixed_timezone(tz_offset)
+            return timezone.make_aware(local_date, tz_correction)
+        except (IndexError, TypeError, ValueError) as e:
+            raise ValidationError(
+                self.error_messages['invalid'], code='invalid')
+
+
 """
 Forms
 """

+ 0 - 93
misago/core/timezones.py

@@ -1,93 +0,0 @@
-# flake8: noqa
-import datetime
-
-import pytz
-
-from django.utils.translation import ugettext_lazy as _
-
-
-TIMEZONES = (
-    ('Pacific/Apia', _('(UTC-13:00) Samoa'), _('(UTC-14:00) Samoa')),
-    ('Pacific/Midway', _('(UTC-11:00) Midway Islands, American Samoa')),
-    ('Pacific/Honolulu', _('(UTC-10:00) Cook Islands, Hawaii, Society Islands')),
-    ('America/Adak', _('(UTC-10:00) Aleutian Islands'), _('(UTC-09:00) Aleutian Islands')),
-    ('Pacific/Marquesas', _('(UTC-09:30) Marquesas Islands')),
-    ('Pacific/Gambier', _('(UTC-09:00) Gambier Islands')),
-    ('America/Anchorage', _('(UTC-09:00) Alaska Standard Time'), _('(UTC-08:00) Alaska Daylight Time')),
-    ('Pacific/Pitcairn', _('(UTC-08:00) Pitcairn Islands')),
-    ('America/Los_Angeles', _('(UTC-08:00) Pacific Time (Canada and US)'), _('(UTC-07:00) Pacific Time (Canada and US)')),
-    ('America/Santa_Isabel', _('(UTC-08:00) Baja California'), _('(UTC-07:00) Baja California')),
-    ('America/Phoenix', _('(UTC-07:00) Mountain Standard Time (No DST)')),
-    ('America/Hermosillo', _('(UTC-07:00) Sonora')),
-    ('America/Denver', _('(UTC-07:00) Mountain Standard Time'), _('(UTC-06:00) Mountain Summer Time')),
-    ('America/Chihuahua', _('(UTC-07:00) Baja California Sur, Chihuahua, Nayarit, Sinaloa'), _('(UTC-06:00) Baja California Sur, Chihuahua, Nayarit, Sinaloa')),
-    ('America/Costa_Rica', _('(UTC-06:00) Costa Rica, El Salvador, Galapagos, Guatemala, Managua')),
-    ('America/Chicago', _('(UTC-06:00) Central Standard Time'), _('(UTC-05:00) Central Daylight Time')),
-    ('America/Mexico_City', _('(UTC-06:00) Mexican Central Zone'), _('(UTC-05:00) Mexican Central Zone')),
-    ('America/Panama', _('(UTC-05:00) Bogota, Cayman, Guayaquil, Jamaica, Lima, Panama')),
-    ('America/New_York', _('(UTC-05:00) Eastern Standard Time'), _('(UTC-04:00) Eastern Daylight Time')),
-    ('America/Caracas', _('(UTC-04:30) Caracas')),
-    ('America/Puerto_Rico', _('(UTC-04:00) Barbados, Dominica, Puerto Rico, Santo Domingo')),
-    ('America/Santiago', _('(UTC-04:00) Bermuda, Campo Grande, Goose Bay, Santiago, Thule'), _('(UTC-03:00) Bermuda, Campo Grande, Goose Bay, Santiago, Thule')),
-    ('America/St_Johns', _('(UTC-03:30) Newfoundland Time')),
-    ('America/Argentina/La_Rioja', _('(UTC-03:00) San Juan, San Luis, Santa Cruz')),
-    ('America/Sao_Paulo', _('(UTC-03:00) Buenos Aires, Godthab, Sao Paulo, Montevideo'), _('(UTC-02:00) Buenos Aires, Godthab, Sao Paulo, Montevideo')),
-    ('America/Noronha', _('(UTC-02:00) Atlantic islands')),
-    ('Atlantic/Cape_Verde', _('(UTC-01:00) Cape Verde Time')),
-    ('Atlantic/Azores', _('(UTC-01:00) Azores, Scoresbysund'), _('(UTC) Azores, Scoresbysund')),
-    ('utc', _('(UTC) Coordinated Universal Time')),
-    ('Africa/Dakar', _('(UTC) Dakar, Rabat')),
-    ('Europe/Lisbon', _('(UTC) Western European Time'), _('(UTC+01:00) Western European Summer Time')),
-    ('Africa/Algiers', _('(UTC+01:00) West Africa Time')),
-    ('Europe/Zurich', _('(UTC+01:00) Central European Time'), _('(UTC+02:00) Central European Summer Time')),
-    ('Africa/Cairo', _('(UTC+02:00) Central Africa Time')),
-    ('Europe/Athens', _('(UTC+02:00) Eastern European Time'), _('(UTC+03:00) Eastern European Summer Time')),
-    ('Asia/Qatar', _('(UTC+03:00) East Africa Time')),
-    ('Europe/Minsk', _('(UTC+03:00) Further-eastern European Time')),
-    ('Asia/Tehran', _('(UTC+03:30) Iran Time'), _('(UTC+04:30) Iran Time')),
-    ('Europe/Moscow', _('(UTC+04:00) Moscow Standard Time, Georgia Standard Time')),
-    ('Asia/Dubai', _('(UTC+04:00) United Arab Emirates Standard Time')),
-    ('Asia/Baku', _('(UTC+05:00) Baku, Yerevan'), _('(UTC+06:00) Baku, Yerevan')),
-    ('Asia/Kabul', _('(UTC+04:30) Afghanistan Standard Time')),
-    ('Asia/Karachi', _('(UTC+05:00) Ashgabat, Dushanbe, Karachi, Maldives, Tashkent')),
-    ('Asia/Kolkata', _('(UTC+05:30) Colombo, Kolkata')),
-    ('Asia/Kathmandu', _('(UTC+05:45) Kathmandu')),
-    ('Asia/Almaty', _('(UTC+06:00) Astana, Bishkek, Dhaka, Thimphu, Yekaterinburg')),
-    ('Asia/Rangoon', _('(UTC+06:30) Yangon, Cocos Islands')),
-    ('Asia/Bangkok', _('(UTC+07:00) Bangkok, Ho Chi Minh, Jakarta, Novosibirsk')),
-    ('Asia/Taipei', _('(UTC+08:00) Beijing, Hong Kong, Kuala Lumpur, Singapore, Taipei')),
-    ('Australia/Perth', _('(UTC+08:00) Australian Western Standard Time')),
-    ('Australia/Eucla', _('(UTC+08:45) Eucla Area')),
-    ('Asia/Tokyo', _('(UTC+09:00) Tokyo, Seoul, Irkutsk, Pyongyang')),
-    ('Australia/Darwin', _('(UTC+09:30) Australian Central Standard Time')),
-    ('Australia/Adelaide', _('(UTC+09:30) Australian Central Standard Time')),
-    ('Australia/Melbourne', _('(UTC+10:00) Australian Eastern Standard Time'), _('(UTC+11:00) Australian Eastern Summer Time')),
-    ('Australia/Lord_Howe', _('(UTC+10:30) Lord Howe Island'), _('(UTC+11:00) Lord Howe Island')),
-    ('Pacific/Guadalcanal', _('(UTC+11:00) Guadalcanal, Honiara, Noumea, Vladivostok')),
-    ('Pacific/Norfolk', _('(UTC+11:30) Norfolk Island')),
-    ('Pacific/Wake', _('(UTC+12:00) Kamchatka, Marshall Islands')),
-    ('Pacific/Auckland', _('(UTC+12:00) Auckland, Fiji'), _('(UTC+13:00) Auckland, Fiji')),
-    ('Pacific/Chatham', _('(UTC+12:45) Chatham Islands'), _('(UTC+13:45) Chatham Islands')),
-    ('Pacific/Enderbury', _('(UTC+13:00) Phoenix Islands')),
-    ('Pacific/Kiritimati', _('(UTC+14:00) Nuku\'alofa')),
-)
-
-
-def choices():
-    """
-    Generate user-friendly timezone list for selects
-    """
-    utc_now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
-
-    ready_list = []
-    for tz in TIMEZONES:
-        if len(tz) == 3:
-            tzinfo = pytz.timezone(tz[0])
-            if utc_now.astimezone(tzinfo).dst().seconds > 0:
-                ready_list.append((tz[0], tz[2]))
-            else:
-                ready_list.append((tz[0], tz[1]))
-        else:
-            ready_list.append(tz)
-
-    return tuple(ready_list)

+ 2 - 2
misago/faker/management/commands/createfakebans.py

@@ -98,8 +98,8 @@ class Command(BaseCommand):
         created_count = 0
         show_progress(self, created_count, fake_bans_to_create)
         for i in xrange(fake_bans_to_create):
-            ban = Ban(test=random.randint(BAN_USERNAME, BAN_IP))
-            ban.banned_value = create_fake_test(fake, ban.test)
+            ban = Ban(check_type=random.randint(BAN_USERNAME, BAN_IP))
+            ban.banned_value = create_fake_test(fake, ban.check_type)
 
             if random.randint(0, 10) == 0:
                 ban.user_message = fake.sentence()

+ 8 - 0
misago/project_template/project_name/settings.py

@@ -57,6 +57,14 @@ CACHES = {
 
 LANGUAGE_CODE = 'en-us'
 
+# Fallback Timezone
+# Used to format dates on server, that are then
+# presented to clients with disabled JS
+# Consult http://en.wikipedia.org/wiki/List_of_tz_database_time_zones TZ column
+# for valid values
+
+TIME_ZONE = 'UTC'
+
 
 # Path used to access static files (CSS, JavaScript, Images)
 # https://docs.djangoproject.com/en/{{ docs_version }}/howto/static-files/

+ 16 - 20
misago/static/misago/admin/js/misago-datetimepicker.js

@@ -3,10 +3,6 @@ $(function() {
 
   function enchanceDateTimeField($control) {
 
-    var formats = $control.data('input-format').split(" ");
-    var date_format = formats[0];
-    var time_format = formats[1].replace(":%S", "");
-
     var $input = $control.find('input');
 
     $input.attr('type', 'hidden');
@@ -21,25 +17,20 @@ $(function() {
     $container.append($date);
     $container.append($time);
 
-    date_format = date_format.replace('%d', 'DD');
-    date_format = date_format.replace('%m', 'MM');
-    date_format = date_format.replace('%y', 'YY');
-    date_format = date_format.replace('%Y', 'YYYY');
+    if ($.trim($input.val()).length > 0) {
+      var parsed = moment($input.val());
+      if (parsed.isValid()) {
+        $date.val(parsed.format('MM-DD-YYYY'));
+        $time.val(parsed.format('HH:mm'));
+      }
+    }
 
     $date.datetimepicker({
-      format: date_format,
+      format: 'MM-DD-YYYY',
       pickDate: true,
       pickTime: false
     });
 
-    var values = $input.val().split(" ");
-    if (values.length == 2) {
-      $date.val(values[0]);
-
-      var time = values[1].split(":");
-      $time.val(time[0] + ":" + time[1]);
-    }
-
     $time.datetimepicker({
       format: 'HH:mm',
       pickDate: false,
@@ -48,7 +39,12 @@ $(function() {
     });
 
     function update_value() {
-      $input.val($date.val() + " " + $time.val());
+      var input = moment($date.val() + " " + $time.val(), 'MM-DD-YYYY HH:mm');
+      if (input.isValid()) {
+        $input.val(input.format());
+      } else {
+        $input.val('');
+      }
     }
 
     $date.change(update_value);
@@ -60,6 +56,6 @@ $(function() {
     if ($(this).data('input-format')) {
       enchanceDateTimeField($(this));
     }
-  })
+  });
 
-})
+});

+ 21 - 27
misago/static/misago/admin/js/misago-timestamps.js

@@ -3,40 +3,34 @@ $(function() {
   var moment_now = moment();
   var time_format = moment_now.lang()._longDateFormat.LT;
 
-  var moments = {};
-
-  // Initialize moment.js for dates
-  $('.dynamic').each(function() {
-    var timestamp = $(this).data('timestamp');
-    var rel_moment = moment(timestamp);
+  function set_titles() {
+    $('.moment').each(function() {
+      var obj = moment($(this).data('iso'));
+      $(this).attr('title', obj.format('LLLL'));
+    });
+  }
+  set_titles();
 
-    if (moment_now.diff(rel_moment, 'days') <= 7) {
-      moments[timestamp] = {
-        rel_moment: rel_moment,
-        original: $(this).text()
-      }
-    }
-  });
+  function update_timestamps() {
+    var now = moment();
 
-  // Update function
-  function update_times() {
-    $('.time-ago').each(function() {
-      var timestamp = $(this).data('timestamp');
-      if (moments[timestamp] != undefined) {
-        if (moment_now.diff(moments[timestamp].rel_moment, 'hours') <= 6 && moment_now.diff(moments[timestamp].rel_moment, 'hours') >= -6) {
-          $(this).text(moments[timestamp].rel_moment.fromNow());
-        } else if (moment_now.diff(moments[timestamp].rel_moment, 'days') < 1 && moment_now.diff(moments[timestamp].rel_moment, 'days') > -1) {
-          $(this).text(moments[timestamp].rel_moment.calendar());
-        } else if (moment_now.diff(moments[timestamp].rel_moment, 'days') < 7 && moment_now.diff(moments[timestamp].rel_moment, 'days') > -7) {
-          $(this).text(moments[timestamp].rel_moment.format("dddd, " + time_format));
+    $('.moment').each(function() {
+      var obj = moment($(this).data('iso'));
+      var diff = Math.abs(obj.diff(now, 'seconds'));
+      if (diff < 18000) {
+        $(this).text(obj.from(now));
+      } else {
+        diff = Math.abs(obj.diff(now, 'days'));
+        if (diff < 5) {
+          $(this).text(obj.calendar(now));
         } else {
-          $(this).text(moments[timestamp].original);
+          $(this).text(obj.format($(this).data('format')));
         }
       }
     });
   }
 
   // Run updates
-  update_times();
-  window.setInterval(update_times, 5000);
+  update_timestamps();
+  window.setInterval(update_timestamps, 5000);
 });

+ 3 - 12
misago/templates/misago/admin/bans/list.html

@@ -31,20 +31,11 @@
 <td>
   {{ item.test_name }}
 </td>
-<td>
+<td{% if item.is_expired %} class="text-muted"{% endif %}>
   {% if item.expires_on %}
-    {% if item.is_expired %}
-      <span class="text-muted tooltip-top" title="{% trans "This ban has expired." %}">
-        {{ item.expires_on|date }}
-        <span class="fa fa-exclamation text-danger"></span>
-      </span>
-    {% else %}
-      <span class="tooltip-top" title="{{ item.expires_on|date:"DATETIME_FORMAT" }}">
-        {{ item.formatted_expiration_date }}
-      </span>
-    {% endif %}
+    <abbr class="moment" data-iso="{{ item.expires_on.isoformat }}" data-format="lll"></abbr>
   {% else %}
-  <em>{% trans "Never" %}</em>
+    <em>{% trans "Never" %}</em>
   {% endif %}
 </td>
 {% for action in extra_actions %}

+ 0 - 1
misago/templates/misago/admin/base.html

@@ -15,7 +15,6 @@
       <span class="brand-border"><span>m</span></span>isago
     </a>
   </div>
-  <div class="small text-muted text-center">{% now "jS F Y H:i" %}</div>
 </footer>
 
 {% include "misago/admin/logout.html" %}

+ 1 - 3
misago/templates/misago/admin/users/list.html

@@ -62,9 +62,7 @@
   {{ item.rank }}
 </td>
 <td>
-  <abbr class="tooltip-top dynamic time-ago" title="{{ item.joined_on }}" data-timestamp="{{ item.joined_on|date:"c" }}">
-    {{ item.joined_on|date }}
-  </abbr>
+  <abbr class="moment" data-iso="{{ item.joined_on.isoformat }}" data-format="LL"></abbr>
 </td>
 <td>
   {{ item.posts }}

+ 1 - 4
misago/users/bans.py

@@ -11,7 +11,7 @@ from django.utils import timezone
 from django.utils.dateparse import parse_datetime
 
 from misago.core import cachebuster
-from misago.users.models import BAN_IP, Ban, BanCache, format_expiration_date
+from misago.users.models import BAN_IP, Ban, BanCache
 
 
 BAN_CACHE_SESSION_KEY = 'misago_ip_check'
@@ -143,11 +143,8 @@ def _get_session_bancache(request):
 def _hydrate_session_cache(ban_cache):
     hydrated = ban_cache.copy()
 
-    hydrated['formatted_expiration_date'] = None
     if hydrated.get('expires_on'):
         hydrated['expires_on'] = parse_datetime(hydrated['expires_on'])
-        hydrated['formatted_expiration_date'] = format_expiration_date(
-            hydrated['expires_on'])
 
     return hydrated
 

+ 8 - 15
misago/users/forms/admin.py

@@ -2,7 +2,7 @@ from django.contrib.auth import get_user_model
 from django.utils.translation import ugettext_lazy as _, ungettext
 
 from misago.conf import settings
-from misago.core import forms, threadstore, timezones
+from misago.core import forms, threadstore
 from misago.core.validators import validate_sluggable
 from misago.acl.models import Role
 
@@ -135,7 +135,6 @@ class EditUserForm(UserBaseForm):
             'avatar_lock_staff_message',
             'signature',
             'is_signature_locked',
-            'timezone',
             'is_hiding_presence',
             'limits_private_thread_invites_to',
             'signature_lock_user_message',
@@ -178,10 +177,6 @@ def UserFormFactory(FormType, instance):
         initial=instance.roles.all() if instance.pk else None,
         widget=forms.CheckboxSelectMultiple)
 
-    if instance.pk:
-        extra_fields['timezone'] = forms.ChoiceField(
-            label=_("Timezone"), choices=timezones.choices())
-
     return type('UserFormFinal', (FormType,), extra_fields)
 
 
@@ -366,9 +361,8 @@ class BanUsersForm(forms.Form):
         error_messages={
             'max_length': _("Message can't be longer than 1000 characters.")
         })
-    expires_on = forms.DateTimeField(
-        label=_("Expires on"),
-        required=False, localize=True,
+    expires_on = forms.IsoDateTimeField(
+        label=_("Expires on"), required=False,
         help_text=_('Leave this field empty for set bans to never expire.'))
 
 
@@ -401,9 +395,8 @@ class BanForm(forms.ModelForm):
         error_messages={
             'max_length': _("Message can't be longer than 1000 characters.")
         })
-    expires_on = forms.DateTimeField(
-        label=_("Expires on"),
-        required=False, localize=True,
+    expires_on = forms.IsoDateTimeField(
+        label=_("Expires on"), required=False,
         help_text=_('Leave this field empty for this ban to never expire.'))
 
     class Meta:
@@ -445,9 +438,9 @@ class SearchBansForm(forms.Form):
     state = forms.ChoiceField(
         label=_("State"), required=False,
         choices=(
-            ('', _('Is used in checks')),
-            ('used', _('Yes')),
-            ('unused', _('No')),
+            ('', _('Any')),
+            ('used', _('Active')),
+            ('unused', _('Expired')),
         ))
 
     def filter_queryset(self, search_criteria, queryset):

+ 2 - 14
misago/users/forms/usercp.py

@@ -2,7 +2,7 @@ from django.contrib.auth import get_user_model
 from django.utils.translation import ugettext_lazy as _, ungettext
 
 from misago.conf import settings
-from misago.core import forms, timezones
+from misago.core import forms
 
 from misago.users.models import (AUTO_SUBSCRIBE_CHOICES,
                                  PRIVATE_THREAD_INVITES_LIMITS_CHOICES)
@@ -10,11 +10,6 @@ from misago.users.validators import validate_email, validate_password
 
 
 class ChangeForumOptionsBaseForm(forms.ModelForm):
-    timezone = forms.ChoiceField(
-        label=_("Your current timezone"), choices=[],
-        help_text=_("If dates and hours displayed by forums are inaccurate, "
-                    "you can fix it by adjusting timezone setting."))
-
     is_hiding_presence = forms.YesNoSwitch(
         label=_("Hide my presence"),
         help_text=_("If you hide your presence, only members with permission "
@@ -35,7 +30,6 @@ class ChangeForumOptionsBaseForm(forms.ModelForm):
     class Meta:
         model = get_user_model()
         fields = [
-            'timezone',
             'is_hiding_presence',
             'limits_private_thread_invites_to',
             'subscribe_to_started_threads',
@@ -44,14 +38,8 @@ class ChangeForumOptionsBaseForm(forms.ModelForm):
 
 
 def ChangeForumOptionsForm(*args, **kwargs):
-    timezone = forms.ChoiceField(
-        label=_("Your current timezone"), choices=timezones.choices(),
-        help_text=_("If dates and hours displayed by forums are inaccurate, "
-                    "you can fix it by adjusting timezone setting."))
-
     FinalFormType = type('FinalChangeForumOptionsForm',
-                         (ChangeForumOptionsBaseForm,),
-                         {'timezone': timezone})
+                         (ChangeForumOptionsBaseForm,))
     return FinalFormType(*args, **kwargs)
 
 

+ 0 - 16
misago/users/middleware.py

@@ -3,7 +3,6 @@ import pytz
 from django.contrib.auth import logout
 from django.contrib.auth.models import AnonymousUser as DjAnonymousUser
 from django.core.urlresolvers import resolve
-from django.utils import timezone
 
 from misago.conf import settings
 
@@ -38,21 +37,6 @@ class UserMiddleware(object):
                 logout(request)
 
 
-class TimezoneMiddleware(object):
-    def process_request(self, request):
-        if request.user.is_authenticated():
-            timezone.activate(pytz.timezone(request.user.timezone))
-        else:
-            timezone.activate(pytz.timezone(settings.default_timezone))
-
-        current_tz = timezone.get_current_timezone()
-
-        utc_offset = current_tz.normalize(timezone.now()).utcoffset()
-        utc_offset_seconds = int(utc_offset.total_seconds())
-
-        request.preloaded_ember_data['utcOffset'] = utc_offset_seconds
-
-
 class PreloadUserMiddleware(object):
     def process_request(self, request):
         request.preloaded_ember_data.update({

+ 0 - 1
misago/users/migrations/0001_initial.py

@@ -31,7 +31,6 @@ class Migration(migrations.Migration):
                 ('joined_from_ip', models.GenericIPAddressField()),
                 ('last_ip', models.GenericIPAddressField(null=True, blank=True)),
                 ('is_hiding_presence', models.BooleanField(default=False)),
-                ('timezone', models.CharField(max_length=255, default='utc')),
                 ('title', models.CharField(max_length=255, null=True, blank=True)),
                 ('requires_activation', models.PositiveIntegerField(default=0)),
                 ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into admin sites.', verbose_name='staff status')),

+ 0 - 12
misago/users/migrations/0002_users_settings.py

@@ -33,18 +33,6 @@ def create_users_settings_group(apps, schema_editor):
                     'is_public': True,
                 },
                 {
-                    'setting': 'default_timezone',
-                    'name': _("Default timezone"),
-                    'description': _("Default timezone for newly "
-                                     "registered accouts as well as "
-                                     "unsigned users."),
-                    'value': 'utc',
-                    'form_field': 'select',
-                    'field_extra': {
-                        'choices': '#TZ#',
-                    },
-                },
-                {
                     'setting': 'username_length_min',
                     'name': _("Minimum length"),
                     'description': _("Minimum allowed username length."),

+ 2 - 30
misago/users/models/ban.py

@@ -3,7 +3,7 @@ import re
 from django.conf import settings
 from django.db import models
 from django.utils import timezone
-from django.utils.translation import ugettext_lazy as _, ungettext, pgettext
+from django.utils.translation import ugettext_lazy as _
 
 from misago.core import cachebuster
 from misago.core.utils import date_format
@@ -11,7 +11,7 @@ from misago.core.utils import date_format
 
 __all__ = [
     'BAN_USERNAME', 'BAN_EMAIL', 'BAN_IP', 'BANS_CHOICES',
-    'Ban', 'BanCache', 'format_expiration_date'
+    'Ban', 'BanCache'
 ]
 
 
@@ -30,26 +30,6 @@ BANS_CHOICES = (
 )
 
 
-def format_expiration_date(expiration_date):
-    if not expiration_date:
-        return _("Never")
-
-    now = timezone.now()
-    diff = (expiration_date - now).total_seconds()
-
-    if diff and diff < (3600 * 24):
-        format = pgettext("ban expiration hour minute",
-                          "h:i a")
-    elif now.year == expiration_date.year:
-        format = pgettext("ban expiration hour minute day month",
-                          "jS F, h:i a")
-    else:
-        format = pgettext("ban expiration hour minute day month year",
-                          "jS F Y, h:i a")
-
-    return date_format(expiration_date, format)
-
-
 class BansManager(models.Manager):
     def get_ip_ban(self, ip):
         return self.get_ban(ip=ip)
@@ -129,10 +109,6 @@ class Ban(models.Model):
         else:
             return False
 
-    @property
-    def formatted_expiration_date(self):
-        return format_expiration_date(self.expires_on)
-
     def check_value(self, value):
         if '*' in self.banned_value:
             regex = re.escape(self.banned_value).replace('\*', '(.*?)')
@@ -155,10 +131,6 @@ class BanCache(models.Model):
     expires_on = models.DateTimeField(null=True, blank=True)
 
     @property
-    def formatted_expiration_date(self):
-        return format_expiration_date(self.expires_on)
-
-    @property
     def is_banned(self):
         return bool(self.ban)
 

+ 0 - 5
misago/users/models/user.py

@@ -89,9 +89,6 @@ class UserManager(BaseUserManager):
             if not 'joined_from_ip' in extra_fields:
                 extra_fields['joined_from_ip'] = '127.0.0.1'
 
-            if not 'timezone' in extra_fields:
-                extra_fields['timezone'] = settings.default_timezone
-
             WATCH_DICT = {
                 'no': AUTO_SUBSCRIBE_NONE,
                 'watch': AUTO_SUBSCRIBE_WATCH,
@@ -185,8 +182,6 @@ class User(AbstractBaseUser, PermissionsMixin):
     last_ip = models.GenericIPAddressField(null=True, blank=True)
     is_hiding_presence = models.BooleanField(default=False)
 
-    timezone = models.CharField(max_length=255, default='utc')
-
     rank = models.ForeignKey(
         'Rank', null=True, blank=True, on_delete=models.PROTECT)
     title = models.CharField(max_length=255, null=True, blank=True)

+ 0 - 3
misago/users/online/utils.py

@@ -37,9 +37,6 @@ def get_user_state(user, acl):
         user_state['is_banned'] = True
         user_state['banned_until'] = user_ban.expires_on
 
-        ban_expiration_date = user_ban.formatted_expiration_date
-        user_state['formatted_ban_expiration_date'] = ban_expiration_date
-
     try:
         if not user.is_hiding_presence or acl['can_see_hidden_users']:
             online_tracker = user.online_tracker

+ 10 - 6
misago/users/tests/test_banadmin_views.py

@@ -1,4 +1,4 @@
-from datetime import date
+from datetime import date, datetime, timedelta
 
 from django.core.urlresolvers import reverse
 
@@ -27,16 +27,19 @@ class BanAdminViewsTests(AdminTestCase):
 
     def test_mass_delete(self):
         """adminview deletes multiple bans"""
+        test_date = datetime.now() + timedelta(days=180)
+
         for i in xrange(10):
             response = self.client.post(
                 reverse('misago:admin:users:bans:new'),
                 data={
                     'check_type': '1',
-                    'banned_value': 'test@test.com',
+                    'banned_value': '%stest@test.com' % i,
                     'user_message': 'Lorem ipsum dolor met',
                     'staff_message': 'Sit amet elit',
-                    'expires_on': '%s-12-24' % unicode(date.today().year + 1),
+                    'expires_on': test_date.isoformat(),
                 })
+            self.assertEqual(response.status_code, 302)
 
         self.assertEqual(Ban.objects.count(), 10)
 
@@ -56,6 +59,8 @@ class BanAdminViewsTests(AdminTestCase):
             reverse('misago:admin:users:bans:new'))
         self.assertEqual(response.status_code, 200)
 
+        test_date = datetime.now() + timedelta(days=180)
+
         response = self.client.post(
             reverse('misago:admin:users:bans:new'),
             data={
@@ -63,7 +68,7 @@ class BanAdminViewsTests(AdminTestCase):
                 'banned_value': 'test@test.com',
                 'user_message': 'Lorem ipsum dolor met',
                 'staff_message': 'Sit amet elit',
-                'expires_on': '%s-12-24' % unicode(date.today().year + 1),
+                'expires_on': test_date.isoformat(),
             })
         self.assertEqual(response.status_code, 302)
 
@@ -90,7 +95,7 @@ class BanAdminViewsTests(AdminTestCase):
                 'banned_value': 'test@test.com',
                 'user_message': 'Lorem ipsum dolor met',
                 'staff_message': 'Sit amet elit',
-                'expires_on': '%s-12-24' % unicode(date.today().year + 1),
+                'expires_on': '',
             })
         self.assertEqual(response.status_code, 302)
 
@@ -98,7 +103,6 @@ class BanAdminViewsTests(AdminTestCase):
         response = self.client.get(response['location'])
         self.assertEqual(response.status_code, 200)
         self.assertIn('test@test.com', response.content)
-        #raise Exception('FIX WARNING!')
 
     def test_delete_view(self):
         """delete ban view has no showstoppers"""

+ 0 - 47
misago/users/tests/test_timezone_middleware.py

@@ -1,47 +0,0 @@
-from django.test import TestCase
-from django.utils import timezone
-
-from misago.conf import settings
-
-from misago.users.middleware import TimezoneMiddleware
-
-
-class MockRequest(object):
-    def __init__(self, user):
-        self.user = user
-
-
-class MockAuthenticated(object):
-    timezone = 'Europe/Warsaw'
-
-    def is_authenticated(self):
-        return True
-
-
-class MockGuest(object):
-    def is_authenticated(self):
-        return False
-
-
-class TimezoneMiddlewareTests(TestCase):
-    def setUp(self):
-        timezone.activate('Europe/Paris')
-
-    def tearDown(self):
-        timezone.deactivate()
-
-    def test_middleware_sets_timezone_for_guest(self):
-        """Middleware sets ip from remote_addr header"""
-        request = MockRequest(MockGuest())
-        TimezoneMiddleware().process_request(request)
-
-        self.assertEqual(timezone.get_current_timezone_name().lower(),
-                         settings.default_timezone)
-
-    def test_middleware_sets_timezone_for_authenticated(self):
-        """Middleware sets ip from forwarded_for header"""
-        request = MockRequest(MockAuthenticated())
-        TimezoneMiddleware().process_request(request)
-
-        self.assertEqual(timezone.get_current_timezone_name(),
-                         MockAuthenticated.timezone)