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

+ 1 - 0
docs/developers/settings.rst

@@ -49,6 +49,7 @@ Each dict in ``settings`` tuple should define following keys:
 * **python_type** - optional string defining type of setting's value. Can be either "string", "int", "bool" or "list". If omitted "string" is used by default.
 * **value** - list, integer or string with default value for this setting.
 * **default_value** - if your setting should always have value, specify there fallabck value used if no user-defined value is available.
+* **is_public** - public settings are included JSON that is passed to Ember.js application. Defaults to ``False``.
 * **is_lazy** - if setting value may too large to be always loaded into memory, you may make setting lazily loaded by defining this key with ``True`` value assigned.
 * **form_field** - What form field should be used to change this setting. Can be either "text", "textarea", "select", "radio", "yesno" or "checkbox". If not defined, "text" is used. "checkbox" should be used exclusively for multiple choices list.
 * **field_extra** - dict that defines extra attributes of form field. For "select", "radio" and "checkbox" fields this dict should contain "choices" key with tuple of tuples that will be used for choices in input. For "string" settings you can define "min_length" and "max_length" extra specifying minmal and maximal lenght of entered text. For integer settings you can specify minimal and maximal range in which value should fall by "min_value" and "max_value". "textarea" field supports extra "rows" setting that controls generated textarea rows attribute. All text-based fields accept "required" setting. "checkbox" field supports "min" and "max" values that control minimum and maximum required choices.

+ 10 - 1
docs/developers/template_tags.rst

@@ -102,8 +102,17 @@ Takes form field as its first argument and renders field complete with label, he
 Takes form field as its only argument and renders it's input.
 
 
+misago_json
+============
+
+``as_json`` filter
+------------------
+
+Turns value into json string.
+
+
 misago_shorthands
-==============
+=================
 
 ``iftrue`` filter
 -----------------

+ 3 - 0
misago/conf/context_processors.py

@@ -1,3 +1,5 @@
+import json
+
 from django.conf import settings as dj_settings
 from misago.conf.dbsettings import db_settings
 
@@ -5,6 +7,7 @@ from misago.conf.dbsettings import db_settings
 def settings(request):
     return {
         'misago_settings': db_settings,
+
         'LOGIN_REDIRECT_URL': dj_settings.LOGIN_REDIRECT_URL,
         'LOGIN_URL': dj_settings.LOGIN_URL,
         'LOGOUT_URL': dj_settings.LOGOUT_URL,

+ 9 - 0
misago/conf/dbsettings.py

@@ -27,14 +27,23 @@ class DBSettings(object):
                 data[setting.setting] = {
                     'value': True if setting.value else None,
                     'is_lazy': setting.is_lazy,
+                    'is_public': setting.is_public,
                 }
             else:
                 data[setting.setting] = {
                     'value': setting.value,
                     'is_lazy': setting.is_lazy,
+                    'is_public': setting.is_public,
                 }
         return data
 
+    def get_public_settings(self):
+        public_settings = {}
+        for name, setting in self._settings.items():
+            if setting['is_public']:
+                public_settings[name] = setting['value']
+        return public_settings
+
     def get_lazy_setting(self, setting):
         from misago.conf.models import Setting
 

+ 3 - 1
misago/conf/defaults.py

@@ -75,9 +75,11 @@ PIPELINE_JS = {
     },
     'misago': {
         'source_filenames': (
-            'misago/js/templates/*.hbs',
             'misago/js/application.js',
             'misago/js/router.js',
+            'misago/js/controllers/*.js',
+            'misago/js/views/*.js',
+            'misago/js/templates/*.hbs',
         ),
         'output_filename': 'misago.js',
     },

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

@@ -22,6 +22,7 @@ class Migration(migrations.Migration):
                 ('dry_value', models.TextField(null=True, blank=True)),
                 ('default_value', models.TextField(null=True, blank=True)),
                 ('python_type', models.CharField(default=b'string', max_length=255)),
+                ('is_public', models.BooleanField(default=False)),
                 ('is_lazy', models.BooleanField(default=False)),
                 ('form_field', models.CharField(default=b'text', max_length=255)),
                 ('pickled_field_extra', models.TextField(null=True, blank=True)),

+ 1 - 0
misago/conf/models.py

@@ -53,6 +53,7 @@ class Setting(models.Model):
     dry_value = models.TextField(null=True, blank=True)
     default_value = models.TextField(null=True, blank=True)
     python_type = models.CharField(max_length=255, default='string')
+    is_public = models.BooleanField(default=False)
     is_lazy = models.BooleanField(default=False)
     form_field = models.CharField(max_length=255, default='text')
     pickled_field_extra = models.TextField(null=True, blank=True)

+ 41 - 0
misago/conf/tests/test_settings.py

@@ -33,7 +33,48 @@ class GatewaySettingsTests(TestCase):
         with self.assertRaises(AttributeError):
             gateway.LoremIpsum
 
+    def test_setting_public(self):
+        """get_public_settings returns public settings"""
+        test_group = {
+            'key': 'test_group',
+            'name': "Test settings",
+            'description': "Those are test settings.",
+            'settings': (
+                {
+                    'setting': 'fish_name',
+                    'name': "Fish's name",
+                    'value': "Public Eric",
+                    'field_extra': {
+                            'min_length': 2,
+                            'max_length': 255
+                        },
+                    'is_public': True
+                },
+                {
+                    'setting': 'private_fish_name',
+                    'name': "Fish's name",
+                    'value': "Private Eric",
+                    'field_extra': {
+                            'min_length': 2,
+                            'max_length': 255
+                        },
+                    'is_public': False
+                },
+            )
+        }
+
+        migrate_settings_group(apps, test_group)
+
+        self.assertEqual(gateway.fish_name, 'Public Eric')
+        self.assertEqual(gateway.private_fish_name, 'Private Eric')
+
+        public_settings = gateway.get_public_settings().keys()
+        self.assertIn('fish_name', public_settings)
+        self.assertNotIn('private_fish_name', public_settings)
+
+
     def test_setting_lazy(self):
+        """lazy settings work"""
         test_group = {
             'key': 'test_group',
             'name': "Test settings",

+ 2 - 0
misago/core/migrations/0002_basic_settings.py

@@ -25,6 +25,7 @@ def create_basic_settings_group(apps, schema_editor):
                         'min_length': 2,
                         'max_length': 255
                     },
+                    'is_public': True,
                 },
                 {
                     'setting': 'forum_index_title',
@@ -35,6 +36,7 @@ def create_basic_settings_group(apps, schema_editor):
                     'field_extra': {
                         'max_length': 255
                     },
+                    'is_public': True,
                 },
                 {
                     'setting': 'forum_index_meta_description',

+ 12 - 0
misago/core/templatetags/misago_json.py

@@ -0,0 +1,12 @@
+import json
+
+from django import template
+from django.utils.safestring import mark_safe
+
+
+register = template.Library()
+
+
+@register.filter
+def as_json(value):
+    return mark_safe(json.dumps(value))

+ 15 - 0
misago/core/tests/test_templatetags.py

@@ -238,3 +238,18 @@ class ShorthandsTests(TestCase):
             'result': 'Ok!',
             'value': False
         })).strip(), 'Ok!')
+
+
+class JSONTests(TestCase):
+    def test_iftrue_for_true(self):
+        """iftrue renders value for true"""
+        tpl_content = """
+{% load misago_json %}
+
+{{ value|as_json }}
+"""
+
+        tpl = Template(tpl_content)
+        self.assertEqual(tpl.render(Context({
+            'value': {'he<llo': 'bo"b!'}
+        })).strip(), '{"he<llo": "bo\\"b!"}')

+ 6 - 0
misago/legal/migrations/0001_initial.py

@@ -27,6 +27,7 @@ def create_legal_settings_group(apps, schema_editor):
                         'max_length': 255,
                         'required': False,
                     },
+                    'is_public': True,
                 },
                 {
                     'setting': 'terms_of_service_link',
@@ -38,6 +39,7 @@ def create_legal_settings_group(apps, schema_editor):
                         'max_length': 255,
                         'required': False,
                     },
+                    'is_public': True,
                 },
                 {
                     'setting': 'terms_of_service',
@@ -53,6 +55,7 @@ def create_legal_settings_group(apps, schema_editor):
                         'required': False,
                         'rows': 8,
                     },
+                    'is_public': True,
                     'is_lazy': True,
                 },
                 {
@@ -66,6 +69,7 @@ def create_legal_settings_group(apps, schema_editor):
                         'max_length': 255,
                         'required': False,
                     },
+                    'is_public': True,
                 },
                 {
                     'setting': 'privacy_policy_link',
@@ -77,6 +81,7 @@ def create_legal_settings_group(apps, schema_editor):
                         'max_length': 255,
                         'required': False,
                     },
+                    'is_public': True,
                 },
                 {
                     'setting': 'privacy_policy',
@@ -92,6 +97,7 @@ def create_legal_settings_group(apps, schema_editor):
                         'required': False,
                         'rows': 8,
                     },
+                    'is_public': True,
                     'is_lazy': True,
                 },
             )

+ 0 - 3
misago/static/misago/js/application.js

@@ -1,6 +1,3 @@
 window.Misago = Ember.Application.create({
   rootElement: '#main'
 });
-
-
-Misago.ApplicationController = Ember.Controller.extend(MisagoPreloadStore.data);

+ 18 - 0
misago/static/misago/js/controllers/application.js

@@ -0,0 +1,18 @@
+Misago.ApplicationController = Ember.Controller.extend({
+  staticUrl: MisagoPreloadStore.get('staticUrl'),
+  mediaUrl: MisagoPreloadStore.get('mediaUrl'),
+  settings: MisagoPreloadStore.get('misago_settings'),
+
+  // footer nav
+  showFooterTermsLink: function() {
+    return this.get('settings.terms_of_service') || this.get('settings.terms_of_service_link');
+  }.property('settings'),
+
+  showFooterPrivacyLink: function() {
+    return this.get('settings.privacy_policy') || this.get('settings.privacy_policy_link');
+  }.property('settings'),
+
+  showFooterNav: function() {
+    return this.get('showFooterTermsLink') || this.get('showFooterPrivacyLink');
+  }.property('showFooterTermsLink', 'showFooterPrivacyLink')
+});

+ 4 - 0
misago/static/misago/js/templates/application.hbs

@@ -1 +1,5 @@
+{{partial "navbar"}}
+
 {{outlet}}
+
+{{partial "footer"}}

+ 31 - 0
misago/static/misago/js/templates/footer.hbs

@@ -0,0 +1,31 @@
+<footer class="site-footer">
+  <div class="container">
+
+    <div class="first-row">
+
+      {{#if showFooterNav}}
+        <ul class="list-inline footer-nav">
+        {{#if showFooterTermsLink}}
+          <li>
+            <a href="{% url 'misago:terms_of_service' %}">{% trans "Terms of service" %}</a>
+          </li>
+        {{/if}}
+        {{#if showFooterPrivacyLink}}
+          <li>
+            <a href="{% url 'misago:privacy_policy' %}">{% trans "Privacy policy" %}</a>
+          </li>
+        {{/if}}
+        </ul>
+      {{/if}}
+
+    </div>
+
+    <div class="misago-branding">
+      <a href="http://misago-project.org">
+        <span class="subscript">powered by</span>
+        <span class="brand-border"><span>m</span></span><span class="subscript">isago</span>
+      </a>
+    </div>
+
+  </div>
+</footer>

+ 10 - 0
misago/static/misago/js/templates/navbar.hbs

@@ -0,0 +1,10 @@
+<nav class="navbar navbar-primary navbar-default navbar-static-top" role="navigation">
+  <div class="container">
+
+    {{#link-to 'misago' class="navbar-brand"}}
+      <img src="{{unbound staticUrl}}misago/img/misago_logo.png" alt="">
+      <span>{{settings.forum_name}}</span>
+    {{/link-to}}
+
+  </div><!-- /.container -->
+</nav>

+ 2 - 0
misago/templates/misago/preload_data.js

@@ -1,2 +1,4 @@
+{% load misago_json%}
+MisagoPreloadStore.set("misago_settings", {{ misago_settings.get_public_settings|as_json }});
 MisagoPreloadStore.set("staticUrl", "{{ STATIC_URL }}");
 MisagoPreloadStore.set("mediaUrl", "{{ MEDIA_URL }}");

+ 2 - 0
misago/threads/migrations/0002_threads_settings.py

@@ -27,6 +27,7 @@ def create_threads_settings_group(apps, schema_editor):
                         'min_value': 2,
                         'max_value': 255,
                     },
+                    'is_public': True,
                 },
                 {
                     'setting': 'thread_title_length_max',
@@ -38,6 +39,7 @@ def create_threads_settings_group(apps, schema_editor):
                         'min_value': 2,
                         'max_value': 255,
                     },
+                    'is_public': True,
                 },
                 {
                     'setting': 'post_length_min',

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

@@ -30,6 +30,7 @@ def create_users_settings_group(apps, schema_editor):
                             ('disabled', _("Don't allow new registrations"))
                         )
                     },
+                    'is_public': True,
                 },
                 {
                     'setting': 'default_timezone',