Browse Source

#593, #653: use json for form fields extra serialization, localise settings

Rafał Pitoń 8 years ago
parent
commit
6d01abe353

+ 24 - 18
misago/conf/forms.py

@@ -36,13 +36,13 @@ class ValidateChoicesNum(object):
 
 
 def basic_kwargs(setting, extra):
 def basic_kwargs(setting, extra):
     kwargs = {
     kwargs = {
-        'label': setting.name,
+        'label': _(setting.name),
         'initial': setting.value,
         'initial': setting.value,
         'required': extra.get('min_length') or extra.get('min'),
         'required': extra.get('min_length') or extra.get('min'),
     }
     }
 
 
     if setting.description:
     if setting.description:
-        kwargs['help_text'] = setting.description
+        kwargs['help_text'] = _(setting.description)
 
 
     if setting.form_field == 'yesno':
     if setting.form_field == 'yesno':
         # YesNoSwitch is int-base and setting is bool based
         # YesNoSwitch is int-base and setting is bool based
@@ -59,13 +59,18 @@ def basic_kwargs(setting, extra):
     return kwargs
     return kwargs
 
 
 
 
+def localise_choices(extra):
+    return [(v, _(l)) for v, l in extra.get('choices', [])]
+
+
 def create_checkbox(setting, kwargs, extra):
 def create_checkbox(setting, kwargs, extra):
     kwargs['widget'] = forms.CheckboxSelectMultiple()
     kwargs['widget'] = forms.CheckboxSelectMultiple()
-    kwargs['choices'] = extra.get('choices', [])
+    kwargs['choices'] = localise_choices(extra)
 
 
     if extra.get('min') or extra.get('max'):
     if extra.get('min') or extra.get('max'):
-        kwargs['validators'] = [ValidateChoicesNum(extra.pop('min', 0),
-                                                   extra.pop('max', 0))]
+        kwargs['validators'] = [
+            ValidateChoicesNum(extra.pop('min', 0), extra.pop('max', 0))
+        ]
 
 
     if setting.python_type == 'int':
     if setting.python_type == 'int':
         return forms.TypedMultipleChoiceField(coerce='int', **kwargs)
         return forms.TypedMultipleChoiceField(coerce='int', **kwargs)
@@ -79,7 +84,7 @@ def create_choice(setting, kwargs, extra):
     else:
     else:
         kwargs['widget'] = forms.Select()
         kwargs['widget'] = forms.Select()
 
 
-    kwargs['choices'] = extra.get('choices', [])
+    kwargs['choices'] = localise_choices(extra)
 
 
     if setting.python_type == 'int':
     if setting.python_type == 'int':
         return forms.TypedChoiceField(coerce='int', **kwargs)
         return forms.TypedChoiceField(coerce='int', **kwargs)
@@ -122,17 +127,14 @@ FIELD_STYPES = {
 
 
 def setting_field(FormType, setting):
 def setting_field(FormType, setting):
     field_factory = FIELD_STYPES[setting.form_field]
     field_factory = FIELD_STYPES[setting.form_field]
-
     field_extra = setting.field_extra
     field_extra = setting.field_extra
-    form_field = field_factory(setting,
-                               basic_kwargs(setting, field_extra),
-                               field_extra)
 
 
-    if setting.legend:
-        form_field.legend = setting.legend
+    form_field = field_factory(
+        setting, basic_kwargs(setting, field_extra), field_extra)
 
 
-    FormType = type('FormType%s' % setting.pk, (FormType,),
-                    {setting.setting: form_field})
+    FormType = type('FormType%s' % setting.pk, (FormType,), {
+        setting.setting: form_field
+    })
 
 
     return FormType
     return FormType
 
 
@@ -152,8 +154,10 @@ def ChangeSettingsForm(data=None, group=None):
     for setting in group.setting_set.order_by('order'):
     for setting in group.setting_set.order_by('order'):
         if setting.legend and setting.legend != fieldset_legend:
         if setting.legend and setting.legend != fieldset_legend:
             if fieldset_fields:
             if fieldset_fields:
-                fieldsets.append(
-                    {'legend': fieldset_legend, 'form': fieldset_form(data)})
+                fieldsets.append({
+                    'legend': fieldset_legend,
+                    'form': fieldset_form(data)
+                })
             fieldset_legend = setting.legend
             fieldset_legend = setting.legend
             fieldset_form = FormType
             fieldset_form = FormType
             fieldset_fields = False
             fieldset_fields = False
@@ -161,7 +165,9 @@ def ChangeSettingsForm(data=None, group=None):
         fieldset_form = setting_field(fieldset_form, setting)
         fieldset_form = setting_field(fieldset_form, setting)
 
 
     if fieldset_fields:
     if fieldset_fields:
-        fieldsets.append(
-            {'legend': fieldset_legend, 'form': fieldset_form(data)})
+        fieldsets.append({
+            'legend': fieldset_legend,
+            'form': fieldset_form(data)
+        })
 
 
     return fieldsets
     return fieldsets

+ 2 - 1
misago/conf/migrations/0001_initial.py

@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 from __future__ import unicode_literals
 
 
+from django.contrib.postgres.fields import JSONField
 from django.db import migrations, models
 from django.db import migrations, models
 
 
 
 
@@ -25,7 +26,7 @@ class Migration(migrations.Migration):
                 ('is_public', models.BooleanField(default=False)),
                 ('is_public', models.BooleanField(default=False)),
                 ('is_lazy', models.BooleanField(default=False)),
                 ('is_lazy', models.BooleanField(default=False)),
                 ('form_field', models.CharField(default='text', max_length=255)),
                 ('form_field', models.CharField(default='text', max_length=255)),
-                ('pickled_field_extra', models.TextField(null=True, blank=True)),
+                ('field_extra', JSONField()),
             ],
             ],
             options={
             options={
             },
             },

+ 1 - 3
misago/conf/migrationutils.py

@@ -1,4 +1,3 @@
-from misago.core import serializer
 from misago.core.cache import cache as default_cache
 from misago.core.cache import cache as default_cache
 
 
 from .dbsettings import CACHE_KEY
 from .dbsettings import CACHE_KEY
@@ -54,8 +53,7 @@ def migrate_setting(Setting, group, setting_fixture, order, old_value):
         setting.default_value = dehydrate_value(
         setting.default_value = dehydrate_value(
             setting.python_type, setting_fixture.get("default_value"))
             setting.python_type, setting_fixture.get("default_value"))
 
 
-    if field_extra:
-        setting.pickled_field_extra = serializer.dumps(field_extra)
+    setting.field_extra = field_extra or {}
 
 
     setting.save()
     setting.save()
 
 

+ 8 - 35
misago/conf/models.py

@@ -1,8 +1,5 @@
+from django.contrib.postgres.fields import JSONField
 from django.db import models
 from django.db import models
-from django.dispatch import receiver
-
-from misago.core import serializer
-from misago.core.signals import secret_key_changed
 
 
 from . import hydrators
 from . import hydrators
 
 
@@ -56,24 +53,24 @@ class Setting(models.Model):
     is_public = models.BooleanField(default=False)
     is_public = models.BooleanField(default=False)
     is_lazy = models.BooleanField(default=False)
     is_lazy = models.BooleanField(default=False)
     form_field = models.CharField(max_length=255, default='text')
     form_field = models.CharField(max_length=255, default='text')
-    pickled_field_extra = models.TextField(null=True, blank=True)
+    field_extra = JSONField()
 
 
     objects = SettingsManager()
     objects = SettingsManager()
 
 
     @property
     @property
     def value(self):
     def value(self):
         if not self.dry_value and self.default_value:
         if not self.dry_value and self.default_value:
-            return hydrators.hydrate_value(self.python_type,
-                                           self.default_value)
+            return hydrators.hydrate_value(
+                self.python_type, self.default_value)
         else:
         else:
-            return hydrators.hydrate_value(self.python_type,
-                                           self.dry_value)
+            return hydrators.hydrate_value(
+                self.python_type, self.dry_value)
 
 
     @value.setter
     @value.setter
     def value(self, new_value):
     def value(self, new_value):
         if new_value is not None:
         if new_value is not None:
-            self.dry_value = hydrators.dehydrate_value(self.python_type,
-                                                       new_value)
+            self.dry_value = hydrators.dehydrate_value(
+                self.python_type, new_value)
         else:
         else:
             self.dry_value = None
             self.dry_value = None
         return self.value
         return self.value
@@ -81,27 +78,3 @@ class Setting(models.Model):
     @property
     @property
     def has_custom_value(self):
     def has_custom_value(self):
         return self.dry_value and self.dry_value != self.default_value
         return self.dry_value and self.dry_value != self.default_value
-
-    @property
-    def field_extra(self):
-        if self.pickled_field_extra:
-            return serializer.loads(self.pickled_field_extra)
-        else:
-            return {}
-
-    @field_extra.setter
-    def field_extra(self, new_extra):
-        if new_extra:
-            self.pickled_field_extra = serializer.dumps(new_extra)
-
-
-"""
-Signal handlers
-"""
-@receiver(secret_key_changed)
-def update_settings_pickles(sender, **kwargs):
-    for setting in Setting.objects.iterator():
-        if setting.pickled_field_extra:
-            setting.pickled_field_extra = serializer.regenerate_checksum(
-                setting.pickled_field_extra)
-            setting.save(update_fields=['pickled_field_extra'])

+ 9 - 12
misago/conf/views.py

@@ -48,17 +48,14 @@ def group(request, key):
             db_settings.flush_cache()
             db_settings.flush_cache()
 
 
             messages.success(
             messages.success(
-                request, _('Changes in settings have been saved!'))
+                request, _("Changes in settings have been saved!"))
             return redirect('misago:admin:system:settings:group', key=key)
             return redirect('misago:admin:system:settings:group', key=key)
 
 
-    use_single_form_template = (len(fieldsets) == 1 and
-                                not fieldsets[0]['legend'])
-
-    return render(
-        request,
-        'misago/admin/conf/group.html',
-        {
-            'active_group': active_group,
-            'fieldsets': fieldsets,
-            'use_single_form_template': use_single_form_template,
-        })
+    use_single_form_template = (
+        len(fieldsets) == 1 and not fieldsets[0]['legend'])
+
+    return render(request, 'misago/admin/conf/group.html',{
+        'active_group': active_group,
+        'fieldsets': fieldsets,
+        'use_single_form_template': use_single_form_template,
+    })

+ 69 - 69
misago/core/migrations/0002_basic_settings.py

@@ -2,85 +2,85 @@
 from __future__ import unicode_literals
 from __future__ import unicode_literals
 
 
 from django.db import migrations, models
 from django.db import migrations, models
-from django.utils.translation import ugettext as _
 
 
 from misago.conf.migrationutils import migrate_settings_group
 from misago.conf.migrationutils import migrate_settings_group
 
 
 
 
+_ = lambda x: x
+
+
 def create_basic_settings_group(apps, schema_editor):
 def create_basic_settings_group(apps, schema_editor):
-    migrate_settings_group(
-        apps,
-        {
-            'key': 'basic',
-            'name': _("Basic forum settings"),
-            'description': _("Those settings control most basic properties "
-                             "of your forum like its name or description."),
-            'settings': (
-                {
-                    'setting': 'forum_name',
-                    'name': _("Forum name"),
-                    'legend': _("General"),
-                    'value': "Misago",
-                    'field_extra': {
-                        'min_length': 2,
-                        'max_length': 255
-                    },
-                    'is_public': True,
-                },
-                {
-                    'setting': 'forum_index_title',
-                    'name': _("Index title"),
-                    'description': _("You may set custon title on "
-                                     "forum index by typing it here."),
-                    'legend': _("Forum index"),
-                    'field_extra': {
-                        'max_length': 255
-                    },
-                    'is_public': True,
+    migrate_settings_group(apps, {
+        'key': 'basic',
+        'name': _("Basic forum settings"),
+        'description': _("Those settings control most basic properties "
+                         "of your forum like its name or description."),
+        'settings': (
+            {
+                'setting': 'forum_name',
+                'name': _("Forum name"),
+                'legend': _("General"),
+                'value': "Misago",
+                'field_extra': {
+                    'min_length': 2,
+                    'max_length': 255
                 },
                 },
-                {
-                    'setting': 'forum_index_meta_description',
-                    'name': _("Meta Description"),
-                    'description': _("Short description of your forum "
-                                     "for internet crawlers."),
-                    'field_extra': {
-                        'max_length': 255
-                    },
+                'is_public': True,
+            },
+            {
+                'setting': 'forum_index_title',
+                'name': _("Index title"),
+                'description': _("You may set custon title on "
+                                 "forum index by typing it here."),
+                'legend': _("Forum index"),
+                'field_extra': {
+                    'max_length': 255
                 },
                 },
-                {
-                    'setting': 'forum_branding_display',
-                    'name': _("Display branding"),
-                    'description': _("Switch branding in forum's navbar."),
-                    'legend': _("Branding"),
-                    'value': True,
-                    'python_type': 'bool',
-                    'form_field': 'yesno',
-                    'is_public': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'forum_index_meta_description',
+                'name': _("Meta Description"),
+                'description': _("Short description of your forum "
+                                 "for internet crawlers."),
+                'field_extra': {
+                    'max_length': 255
                 },
                 },
-                {
-                    'setting': 'forum_branding_text',
-                    'name': _("Branding text"),
-                    'description': _("Optional text displayed besides "
-                                     "brand image in navbar."),
-                    'value': "Misago",
-                    'field_extra': {
-                        'max_length': 255
-                    },
-                    'is_public': True,
+            },
+            {
+                'setting': 'forum_branding_display',
+                'name': _("Display branding"),
+                'description': _("Switch branding in forum's navbar."),
+                'legend': _("Branding"),
+                'value': True,
+                'python_type': 'bool',
+                'form_field': 'yesno',
+                'is_public': True,
+            },
+            {
+                'setting': 'forum_branding_text',
+                'name': _("Branding text"),
+                'description': _("Optional text displayed besides "
+                                 "brand image in navbar."),
+                'value': "Misago",
+                'field_extra': {
+                    'max_length': 255
                 },
                 },
-                {
-                    'setting': 'email_footer',
-                    'name': _("E-mails footer"),
-                    'description': _("Optional short message included "
-                                     "at the end of e-mails sent by "
-                                     "forum"),
-                    'legend': _("Forum e-mails"),
-                    'field_extra': {
-                        'max_length': 255
-                    },
+                'is_public': True,
+            },
+            {
+                'setting': 'email_footer',
+                'name': _("E-mails footer"),
+                'description': _("Optional short message included "
+                                 "at the end of e-mails sent by "
+                                 "forum"),
+                'legend': _("Forum e-mails"),
+                'field_extra': {
+                    'max_length': 255
                 },
                 },
-            )
-        })
+            },
+        )
+    })
 
 
 
 
 class Migration(migrations.Migration):
 class Migration(migrations.Migration):

+ 2 - 0
misago/core/serializer.py

@@ -26,6 +26,8 @@ def loads(dry):
 
 
 
 
 def dumps(wet):
 def dumps(wet):
+    from misago.core.deprecations import warn
+    warn('misago.core.serializer is being replaced with json')
     base = base64.encodestring(pickle.dumps(wet, pickle.HIGHEST_PROTOCOL)).decode()
     base = base64.encodestring(pickle.dumps(wet, pickle.HIGHEST_PROTOCOL)).decode()
     checksum = _checksum(base)
     checksum = _checksum(base)
     return '%s%s' % (checksum, base)
     return '%s%s' % (checksum, base)

+ 99 - 99
misago/legal/migrations/0001_initial.py

@@ -2,117 +2,117 @@
 from __future__ import unicode_literals
 from __future__ import unicode_literals
 
 
 from django.db import migrations, models
 from django.db import migrations, models
-from django.utils.translation import ugettext as _
 
 
 from misago.conf.migrationutils import migrate_settings_group
 from misago.conf.migrationutils import migrate_settings_group
 
 
 
 
+_ = lambda x: x
+
+
 def create_legal_settings_group(apps, schema_editor):
 def create_legal_settings_group(apps, schema_editor):
-    migrate_settings_group(
-        apps,
-        {
-            'key': 'legal',
-            'name': _("Legal information"),
-            'description': _("Those settings allow you to set forum terms of "
-                             "service and privacy policy"),
-            'settings': (
-                {
-                    'setting': 'terms_of_service_title',
-                    'name': _("Terms title"),
-                    'legend': _("Terms of Service"),
-                    'description': _("Leave this field empty to "
-                                     "use default title."),
-                    'value': "",
-                    'field_extra': {
-                        'max_length': 255,
-                        'required': False,
-                    },
-                    'is_public': True,
+    migrate_settings_group(apps, {
+        'key': 'legal',
+        'name': _("Legal information"),
+        'description': _("Those settings allow you to set forum terms of "
+                         "service and privacy policy"),
+        'settings': (
+            {
+                'setting': 'terms_of_service_title',
+                'name': _("Terms title"),
+                'legend': _("Terms of Service"),
+                'description': _("Leave this field empty to "
+                                 "use default title."),
+                'value': "",
+                'field_extra': {
+                    'max_length': 255,
+                    'required': False,
                 },
                 },
-                {
-                    'setting': 'terms_of_service_link',
-                    'name': _("Terms link"),
-                    'description': _("If terms of service are located "
-                                     "on other page, enter there its link."),
-                    'value': "",
-                    'field_extra': {
-                        'max_length': 255,
-                        'required': False,
-                    },
-                    'is_public': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'terms_of_service_link',
+                'name': _("Terms link"),
+                'description': _("If terms of service are located "
+                                 "on other page, enter there its link."),
+                'value': "",
+                'field_extra': {
+                    'max_length': 255,
+                    'required': False,
                 },
                 },
-                {
-                    'setting': 'terms_of_service',
-                    'name': _("Terms contents"),
-                    'description': _("Your forums can have custom terms of "
-                                     "service page. To create it, write or "
-                                     "paste here its contents. Full Misago "
-                                     "markup is available for formatting."),
-                    'value': "",
-                    'form_field': 'textarea',
-                    'field_extra': {
-                        'max_length': 128000,
-                        'required': False,
-                        'rows': 8,
-                    },
-                    'is_public': True,
-                    'is_lazy': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'terms_of_service',
+                'name': _("Terms contents"),
+                'description': _("Your forums can have custom terms of "
+                                 "service page. To create it, write or "
+                                 "paste here its contents. Full Misago "
+                                 "markup is available for formatting."),
+                'value': "",
+                'form_field': 'textarea',
+                'field_extra': {
+                    'max_length': 128000,
+                    'required': False,
+                    'rows': 8,
                 },
                 },
-                {
-                    'setting': 'privacy_policy_title',
-                    'name': _("Policy title"),
-                    'legend': _("Privacy policy"),
-                    'description': _("Leave this field empty to "
-                                     "use default title."),
-                    'value': "",
-                    'field_extra': {
-                        'max_length': 255,
-                        'required': False,
-                    },
-                    'is_public': True,
+                'is_public': True,
+                'is_lazy': True,
+            },
+            {
+                'setting': 'privacy_policy_title',
+                'name': _("Policy title"),
+                'legend': _("Privacy policy"),
+                'description': _("Leave this field empty to "
+                                 "use default title."),
+                'value': "",
+                'field_extra': {
+                    'max_length': 255,
+                    'required': False,
                 },
                 },
-                {
-                    'setting': 'privacy_policy_link',
-                    'name': _("Policy link"),
-                    'description': _("If privacy policy is located on "
-                                     "other page, enter there its link."),
-                    'value': "",
-                    'field_extra': {
-                        'max_length': 255,
-                        'required': False,
-                    },
-                    'is_public': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'privacy_policy_link',
+                'name': _("Policy link"),
+                'description': _("If privacy policy is located on "
+                                 "other page, enter there its link."),
+                'value': "",
+                'field_extra': {
+                    'max_length': 255,
+                    'required': False,
                 },
                 },
-                {
-                    'setting': 'privacy_policy',
-                    'name': _("Policy contents"),
-                    'description': _("Your forums can have custom privacy "
-                                     "policy page. To create it, write or "
-                                     "paste here its contents. Full Misago "
-                                     "markup is available for formatting."),
-                    'value': "",
-                    'form_field': 'textarea',
-                    'field_extra': {
-                        'max_length': 128000,
-                        'required': False,
-                        'rows': 8,
-                    },
-                    'is_public': True,
-                    'is_lazy': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'privacy_policy',
+                'name': _("Policy contents"),
+                'description': _("Your forums can have custom privacy "
+                                 "policy page. To create it, write or "
+                                 "paste here its contents. Full Misago "
+                                 "markup is available for formatting."),
+                'value': "",
+                'form_field': 'textarea',
+                'field_extra': {
+                    'max_length': 128000,
+                    'required': False,
+                    'rows': 8,
                 },
                 },
-                {
-                    'setting': 'forum_footnote',
-                    'name': _("Footnote"),
-                    'description': _("Short message displayed "
-                                     "in forum footer."),
-                    'legend': _("Forum footer"),
-                    'field_extra': {
-                        'max_length': 300
-                    },
-                    'is_public': True,
+                'is_public': True,
+                'is_lazy': True,
+            },
+            {
+                'setting': 'forum_footnote',
+                'name': _("Footnote"),
+                'description': _("Short message displayed "
+                                 "in forum footer."),
+                'legend': _("Forum footer"),
+                'field_extra': {
+                    'max_length': 300
                 },
                 },
-            )
-        })
+                'is_public': True,
+            },
+        )
+    })
 
 
 
 
 class Migration(migrations.Migration):
 class Migration(migrations.Migration):

+ 5 - 5
misago/templates/misago/admin/conf/group.html

@@ -2,7 +2,7 @@
 {% load i18n misago_forms %}
 {% load i18n misago_forms %}
 
 
 
 
-{% block title %}{{ active_group.name }} | {{ block.super }}{% endblock %}
+{% block title %}{% trans active_group.name %} | {{ block.super }}{% endblock %}
 
 
 
 
 {% block header %}
 {% block header %}
@@ -12,7 +12,7 @@
   </div>
   </div>
   <div class="sub">
   <div class="sub">
     <span class="fa fa-chevron-right"></span>
     <span class="fa fa-chevron-right"></span>
-    {{ active_group.name }}
+    {% trans active_group.name %}
   </div>
   </div>
 {% endblock header%}
 {% endblock header%}
 
 
@@ -23,9 +23,9 @@
     {% csrf_token %}
     {% csrf_token %}
 
 
     <div class="form-header">
     <div class="form-header">
-      <h1>{{ active_group.name }} </h1>
+      <h1>{% trans active_group.name %}</h1>
       {% if active_group.description %}
       {% if active_group.description %}
-      <p>{{ active_group.description }}</p>
+      <p>{% trans active_group.description %}</p>
       {% endif %}
       {% endif %}
     </div>
     </div>
 
 
@@ -41,7 +41,7 @@
         {% for fieldset in fieldsets %}
         {% for fieldset in fieldsets %}
         <fieldset>
         <fieldset>
           {% if fieldset.legend %}
           {% if fieldset.legend %}
-          <legend>{{ fieldset.legend }}</legend>
+          <legend>{% trans fieldset.legend %}</legend>
           {% endif %}
           {% endif %}
 
 
           {% for field in fieldset.form %}
           {% for field in fieldset.form %}

+ 3 - 3
misago/templates/misago/admin/conf/index.html

@@ -25,7 +25,7 @@
         {% for group in settings_groups %}
         {% for group in settings_groups %}
         <li {% if group.key == active_group.key %}class="active"{% endif %}>
         <li {% if group.key == active_group.key %}class="active"{% endif %}>
           <a href="{% url 'misago:admin:system:settings:group' key=group.key %}">
           <a href="{% url 'misago:admin:system:settings:group' key=group.key %}">
-            {{ group.name }}
+            {% trans group.name %}
           </a>
           </a>
         </li>
         </li>
         {% endfor %}
         {% endfor %}
@@ -40,9 +40,9 @@
 
 
           {% for group in settings_groups %}
           {% for group in settings_groups %}
           <a href="{% url 'misago:admin:system:settings:group' key=group.key %}" class="list-group-item">
           <a href="{% url 'misago:admin:system:settings:group' key=group.key %}" class="list-group-item">
-            <h4 class="list-group-item-heading">{{ group.name }}</h4>
+            <h4 class="list-group-item-heading">{% trans group.name %}</h4>
             {% if group.description %}
             {% if group.description %}
-            <p class="list-group-item-text">{{ group.description }}</p>
+            <p class="list-group-item-text">{% trans group.description %}</p>
             {% endif %}
             {% endif %}
           </a>
           </a>
           {% endfor %}
           {% endfor %}

+ 54 - 54
misago/threads/migrations/0002_threads_settings.py

@@ -3,69 +3,69 @@ from __future__ import unicode_literals
 
 
 from django.conf import settings
 from django.conf import settings
 from django.db import migrations, models
 from django.db import migrations, models
-from django.utils.translation import ugettext as _
 
 
 from misago.conf.migrationutils import migrate_settings_group
 from misago.conf.migrationutils import migrate_settings_group
 
 
 
 
+_ = lambda x: x
+
+
 def create_threads_settings_group(apps, schema_editor):
 def create_threads_settings_group(apps, schema_editor):
-    migrate_settings_group(
-        apps,
-        {
-            'key': 'threads',
-            'name': _("Threads"),
-            'description': _("Those settings control threads and posts."),
-            'settings': (
-                {
-                    'setting': 'thread_title_length_min',
-                    'name': _("Minimum length"),
-                    'description': _("Minimum allowed thread title length."),
-                    'legend': _("Thread titles"),
-                    'python_type': 'int',
-                    'value': 5,
-                    'field_extra': {
-                        'min_value': 2,
-                        'max_value': 255,
-                    },
-                    'is_public': True,
+    migrate_settings_group(apps, {
+        'key': 'threads',
+        'name': _("Threads"),
+        'description': _("Those settings control threads and posts."),
+        'settings': (
+            {
+                'setting': 'thread_title_length_min',
+                'name': _("Minimum length"),
+                'description': _("Minimum allowed thread title length."),
+                'legend': _("Thread titles"),
+                'python_type': 'int',
+                'value': 5,
+                'field_extra': {
+                    'min_value': 2,
+                    'max_value': 255,
                 },
                 },
-                {
-                    'setting': 'thread_title_length_max',
-                    'name': _("Maximum length"),
-                    'description': _("Maximum allowed thread length."),
-                    'python_type': 'int',
-                    'value': 90,
-                    'field_extra': {
-                        'min_value': 2,
-                        'max_value': 255,
-                    },
-                    'is_public': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'thread_title_length_max',
+                'name': _("Maximum length"),
+                'description': _("Maximum allowed thread length."),
+                'python_type': 'int',
+                'value': 90,
+                'field_extra': {
+                    'min_value': 2,
+                    'max_value': 255,
                 },
                 },
-                {
-                    'setting': 'post_length_min',
-                    'name': _("Minimum length"),
-                    'description': _("Minimum allowed user post length."),
-                    'legend': _("Posts"),
-                    'python_type': 'int',
-                    'value': 5,
-                    'field_extra': {
-                        'min_value': 1,
-                    },
-                    'is_public': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'post_length_min',
+                'name': _("Minimum length"),
+                'description': _("Minimum allowed user post length."),
+                'legend': _("Posts"),
+                'python_type': 'int',
+                'value': 5,
+                'field_extra': {
+                    'min_value': 1,
                 },
                 },
-                {
-                    'setting': 'post_length_max',
-                    'name': _("Maximum length"),
-                    'description': _("Maximum allowed user post length. Enter zero to disable"),
-                    'python_type': 'int',
-                    'value': 60000,
-                    'field_extra': {
-                        'min_value': 0,
-                    },
-                    'is_public': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'post_length_max',
+                'name': _("Maximum length"),
+                'description': _("Maximum allowed user post length. Enter zero to disable"),
+                'python_type': 'int',
+                'value': 60000,
+                'field_extra': {
+                    'min_value': 0,
                 },
                 },
-            )
-        })
+                'is_public': True,
+            },
+        )
+    })
 
 
 
 
 class Migration(migrations.Migration):
 class Migration(migrations.Migration):

+ 219 - 221
misago/users/migrations/0002_users_settings.py

@@ -3,249 +3,247 @@ from __future__ import unicode_literals
 
 
 from django.conf import settings
 from django.conf import settings
 from django.db import migrations, models
 from django.db import migrations, models
-from django.utils.translation import ugettext as _
 
 
 from misago.conf.migrationutils import migrate_settings_group
 from misago.conf.migrationutils import migrate_settings_group
 
 
 
 
+_ = lambda x: x
+
+
 def create_users_settings_group(apps, schema_editor):
 def create_users_settings_group(apps, schema_editor):
-    migrate_settings_group(
-        apps,
-        {
-            'key': 'users',
-            'name': _("Users"),
-            'description': _("Those settings control user accounts default behaviour and features availability."),
-            'settings': (
-                {
-                    'setting': 'account_activation',
-                    'name': _("New accounts activation"),
-                    'legend': _("New accounts"),
-                    'value': 'none',
-                    'form_field': 'select',
-                    'field_extra': {
-                        'choices': (
-                            ('none', _("No activation required")),
-                            ('user', _("Activation Token sent to User")),
-                            ('admin', _("Activation by Administrator")),
-                            ('closed', _("Don't allow new registrations"))
-                        )
-                    },
-                    'is_public': True,
-                },
-                {
-                    'setting': 'username_length_min',
-                    'name': _("Minimum length"),
-                    'description': _("Minimum allowed username length."),
-                    'legend': _("User names"),
-                    'python_type': 'int',
-                    'value': 3,
-                    'field_extra': {
-                        'min_value': 2,
-                        'max_value': 20,
-                    },
-                    'is_public': True,
+    migrate_settings_group(apps,{
+        'key': 'users',
+        'name': _("Users"),
+        'description': _("Those settings control user accounts default behaviour and features availability."),
+        'settings': (
+            {
+                'setting': 'account_activation',
+                'name': _("New accounts activation"),
+                'legend': _("New accounts"),
+                'value': 'none',
+                'form_field': 'select',
+                'field_extra': {
+                    'choices': (
+                        ('none', _("No activation required")),
+                        ('user', _("Activation Token sent to User")),
+                        ('admin', _("Activation by Administrator")),
+                        ('closed', _("Don't allow new registrations"))
+                    )
                 },
                 },
-                {
-                    'setting': 'username_length_max',
-                    'name': _("Maximum length"),
-                    'description': _("Maximum allowed username length."),
-                    'python_type': 'int',
-                    'value': 14,
-                    'field_extra': {
-                        'min_value': 2,
-                        'max_value': 20,
-                    },
-                    'is_public': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'username_length_min',
+                'name': _("Minimum length"),
+                'description': _("Minimum allowed username length."),
+                'legend': _("User names"),
+                'python_type': 'int',
+                'value': 3,
+                'field_extra': {
+                    'min_value': 2,
+                    'max_value': 20,
                 },
                 },
-                {
-                    'setting': 'password_length_min',
-                    'name': _("Minimum length"),
-                    'description': _("Minimum allowed user password length."),
-                    'legend': _("Passwords"),
-                    'python_type': 'int',
-                    'value': 5,
-                    'field_extra': {
-                        'min_value': 2,
-                        'max_value': 255,
-                    },
-                    'is_public': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'username_length_max',
+                'name': _("Maximum length"),
+                'description': _("Maximum allowed username length."),
+                'python_type': 'int',
+                'value': 14,
+                'field_extra': {
+                    'min_value': 2,
+                    'max_value': 20,
                 },
                 },
-                {
-                    'setting': 'allow_custom_avatars',
-                    'name': _("Allow custom avatars"),
-                    'legend': _("Avatars"),
-                    'description': _("Turning this option off will forbid "
-                                     "forum users from using avatars from "
-                                     "outside forums. Good for forums "
-                                     "adressed at young users."),
-                    'python_type': 'bool',
-                    'value': True,
-                    'form_field': 'yesno',
+                'is_public': True,
+            },
+            {
+                'setting': 'password_length_min',
+                'name': _("Minimum length"),
+                'description': _("Minimum allowed user password length."),
+                'legend': _("Passwords"),
+                'python_type': 'int',
+                'value': 5,
+                'field_extra': {
+                    'min_value': 2,
+                    'max_value': 255,
                 },
                 },
-                {
-                    'setting': 'default_avatar',
-                    'name': _("Default avatar"),
-                    'value': 'gravatar',
-                    'form_field': 'select',
-                    'field_extra': {
-                        'choices': (
-                            ('dynamic', _("Individual")),
-                            ('gravatar', _("Gravatar")),
-                            ('gallery', _("Random avatar from gallery")),
-                        ),
-                    },
+                'is_public': True,
+            },
+            {
+                'setting': 'allow_custom_avatars',
+                'name': _("Allow custom avatars"),
+                'legend': _("Avatars"),
+                'description': _("Turning this option off will forbid "
+                                 "forum users from using avatars from "
+                                 "outside forums. Good for forums "
+                                 "adressed at young users."),
+                'python_type': 'bool',
+                'value': True,
+                'form_field': 'yesno',
+            },
+            {
+                'setting': 'default_avatar',
+                'name': _("Default avatar"),
+                'value': 'gravatar',
+                'form_field': 'select',
+                'field_extra': {
+                    'choices': (
+                        ('dynamic', _("Individual")),
+                        ('gravatar', _("Gravatar")),
+                        ('gallery', _("Random avatar from gallery")),
+                    ),
                 },
                 },
-                {
-                    'setting': 'default_gravatar_fallback',
-                    'name': _("Fallback for default gravatar"),
-                    'description': _("Select which avatar to use when user "
-                                     "has no gravatar associated with his "
-                                     "e-mail address."),
-                    'value': 'dynamic',
-                    'form_field': 'select',
-                    'field_extra': {
-                        'choices': (
-                            ('dynamic', _("Individual")),
-                            ('gallery', _("Random avatar from gallery")),
-                        ),
-                    },
+            },
+            {
+                'setting': 'default_gravatar_fallback',
+                'name': _("Fallback for default gravatar"),
+                'description': _("Select which avatar to use when user "
+                                 "has no gravatar associated with his "
+                                 "e-mail address."),
+                'value': 'dynamic',
+                'form_field': 'select',
+                'field_extra': {
+                    'choices': (
+                        ('dynamic', _("Individual")),
+                        ('gallery', _("Random avatar from gallery")),
+                    ),
                 },
                 },
-                {
-                    'setting': 'avatar_upload_limit',
-                    'name': _("Maximum size of uploaded avatar"),
-                    'description': _("Enter maximum allowed file size "
-                                     "(in KB) for avatar uploads"),
-                    'python_type': 'int',
-                    'value': 1536,
-                    'field_extra': {
-                        'min_value': 0,
-                    },
-                    'is_public': True,
+            },
+            {
+                'setting': 'avatar_upload_limit',
+                'name': _("Maximum size of uploaded avatar"),
+                'description': _("Enter maximum allowed file size "
+                                 "(in KB) for avatar uploads"),
+                'python_type': 'int',
+                'value': 1536,
+                'field_extra': {
+                    'min_value': 0,
                 },
                 },
-                {
-                    'setting': 'signature_length_max',
-                    'name': _("Maximum length"),
-                    'legend': _("Signatures"),
-                    'description': _("Maximum allowed signature length."),
-                    'python_type': 'int',
-                    'value': 256,
-                    'field_extra': {
-                        'min_value': 10,
-                        'max_value': 5000,
-                    },
-                    'is_public': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'signature_length_max',
+                'name': _("Maximum length"),
+                'legend': _("Signatures"),
+                'description': _("Maximum allowed signature length."),
+                'python_type': 'int',
+                'value': 256,
+                'field_extra': {
+                    'min_value': 10,
+                    'max_value': 5000,
                 },
                 },
-                {
-                    'setting': 'subscribe_start',
-                    'name': _("Started threads"),
-                    'legend': _("Default subscriptions settings"),
-                    'value': 'watch_email',
-                    'form_field': 'select',
-                    'field_extra': {
-                        'choices': (
-                            ('no', _("Don't watch")),
-                            ('watch', _("Put on watched threads list")),
-                            ('watch_email', _("Put on watched threads "
-                                              "list and e-mail user when "
-                                              "somebody replies")),
-                        ),
-                    },
+                'is_public': True,
+            },
+            {
+                'setting': 'subscribe_start',
+                'name': _("Started threads"),
+                'legend': _("Default subscriptions settings"),
+                'value': 'watch_email',
+                'form_field': 'select',
+                'field_extra': {
+                    'choices': (
+                        ('no', _("Don't watch")),
+                        ('watch', _("Put on watched threads list")),
+                        ('watch_email', _("Put on watched threads "
+                                          "list and e-mail user when "
+                                          "somebody replies")),
+                    ),
                 },
                 },
-                {
-                    'setting': 'subscribe_reply',
-                    'name': _("Replied threads"),
-                    'value': 'watch_email',
-                    'form_field': 'select',
-                    'field_extra': {
-                        'choices': (
-                            ('no', _("Don't watch")),
-                            ('watch', _("Put on watched threads list")),
-                            ('watch_email', _("Put on watched threads "
-                                              "list and e-mail user when "
-                                              "somebody replies")),
-                        ),
-                    },
+            },
+            {
+                'setting': 'subscribe_reply',
+                'name': _("Replied threads"),
+                'value': 'watch_email',
+                'form_field': 'select',
+                'field_extra': {
+                    'choices': (
+                        ('no', _("Don't watch")),
+                        ('watch', _("Put on watched threads list")),
+                        ('watch_email', _("Put on watched threads "
+                                          "list and e-mail user when "
+                                          "somebody replies")),
+                    ),
                 },
                 },
-            )
-        })
+            },
+        )
+    })
 
 
-    migrate_settings_group(
-        apps,
-        {
-            'key': 'captcha',
-            'name': _("CAPTCHA"),
-            'description': _("Those settings allow you to combat automatic "
-                             "registrations on your forum."),
-            'settings': (
-                {
-                    'setting': 'captcha_type',
-                    'name': _("Select CAPTCHA type"),
-                    'legend': _("CAPTCHA type"),
-                    'value': 'no',
-                    'form_field': 'select',
-                    'field_extra': {
-                        'choices': (
-                            ('no', _("No CAPTCHA")),
-                            ('re', _("reCaptcha")),
-                            ('qa', _("Question and answer")),
-                        ),
-                    },
-                    'is_public': True,
+    migrate_settings_group(apps,{
+        'key': 'captcha',
+        'name': _("CAPTCHA"),
+        'description': _("Those settings allow you to combat automatic "
+                         "registrations on your forum."),
+        'settings': (
+            {
+                'setting': 'captcha_type',
+                'name': _("Select CAPTCHA type"),
+                'legend': _("CAPTCHA type"),
+                'value': 'no',
+                'form_field': 'select',
+                'field_extra': {
+                    'choices': (
+                        ('no', _("No CAPTCHA")),
+                        ('re', _("reCaptcha")),
+                        ('qa', _("Question and answer")),
+                    ),
                 },
                 },
-                {
-                    'setting': 'recaptcha_site_key',
-                    'name': _("Site key"),
-                    'legend': _("reCAPTCHA"),
-                    'value': '',
-                    'field_extra': {
-                        'required': False,
-                        'max_length': 100,
-                    },
-                    'is_public': True,
+                'is_public': True,
+            },
+            {
+                'setting': 'recaptcha_site_key',
+                'name': _("Site key"),
+                'legend': _("reCAPTCHA"),
+                'value': '',
+                'field_extra': {
+                    'required': False,
+                    'max_length': 100,
                 },
                 },
-                {
-                    'setting': 'recaptcha_secret_key',
-                    'name': _("Secret key"),
-                    'value': '',
-                    'field_extra': {
-                        'required': False,
-                        'max_length': 100,
-                    },
+                'is_public': True,
+            },
+            {
+                'setting': 'recaptcha_secret_key',
+                'name': _("Secret key"),
+                'value': '',
+                'field_extra': {
+                    'required': False,
+                    'max_length': 100,
                 },
                 },
-                {
-                    'setting': 'qa_question',
-                    'name': _("Test question"),
-                    'legend': _("Question and answer"),
-                    'value': '',
-                    'field_extra': {
-                        'required': False,
-                        'max_length': 250,
-                    },
+            },
+            {
+                'setting': 'qa_question',
+                'name': _("Test question"),
+                'legend': _("Question and answer"),
+                'value': '',
+                'field_extra': {
+                    'required': False,
+                    'max_length': 250,
                 },
                 },
-                {
-                    'setting': 'qa_help_text',
-                    'name': _("Question help text"),
-                    'value': '',
-                    'field_extra': {
-                        'required': False,
-                        'max_length': 250,
-                    },
+            },
+            {
+                'setting': 'qa_help_text',
+                'name': _("Question help text"),
+                'value': '',
+                'field_extra': {
+                    'required': False,
+                    'max_length': 250,
                 },
                 },
-                {
-                    'setting': 'qa_answers',
-                    'name': _("Valid answers"),
-                    'description': _("Enter each answer in new line. "
-                                     "Answers are case-insensitive."),
-                    'value': '',
-                    'form_field': 'textarea',
-                    'field_extra': {
-                        'rows': 4,
-                        'required': False,
-                        'max_length': 250,
-                    },
+            },
+            {
+                'setting': 'qa_answers',
+                'name': _("Valid answers"),
+                'description': _("Enter each answer in new line. "
+                                 "Answers are case-insensitive."),
+                'value': '',
+                'form_field': 'textarea',
+                'field_extra': {
+                    'rows': 4,
+                    'required': False,
+                    'max_length': 250,
                 },
                 },
-            )
-        })
+            },
+        )
+    })
 
 
 
 
 class Migration(migrations.Migration):
 class Migration(migrations.Migration):