New fnpdjango app with lots of common utils.
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Tue, 9 Oct 2012 10:10:51 +0000 (12:10 +0200)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Wed, 10 Oct 2012 11:23:10 +0000 (13:23 +0200)
68 files changed:
contact/__init__.py
contact/utils.py [deleted file]
contact/views.py
events/__init__.py
events/admin.py
events/models.py
events/search_indexes.py
events/templates/events/event_list.html
fnpdjango/__init__.py [new file with mode: 0644]
fnpdjango/middleware.py [new file with mode: 0644]
fnpdjango/models.py [new file with mode: 0644]
fnpdjango/templates/fnpdjango/prevnext/next.html [new file with mode: 0755]
fnpdjango/templates/fnpdjango/prevnext/previous.html [new file with mode: 0755]
fnpdjango/templates/fnpdjango/prevnext/prevnext.html [new file with mode: 0755]
fnpdjango/templates/fnpdjango/share.html [new file with mode: 0755]
fnpdjango/templatetags/__init__.py [new file with mode: 0755]
fnpdjango/templatetags/fnp_common.py [new file with mode: 0755]
fnpdjango/templatetags/fnp_markup.py [new file with mode: 0755]
fnpdjango/templatetags/fnp_prevnext.py [new file with mode: 0755]
fnpdjango/templatetags/fnp_share.py [new file with mode: 0755]
fnpdjango/utils/__init__.py [new file with mode: 0644]
fnpdjango/utils/app.py [new file with mode: 0755]
fnpdjango/utils/models/__init__.py [new file with mode: 0644]
fnpdjango/utils/models/translation.py [new file with mode: 0644]
fnpdjango/utils/settings.py [new file with mode: 0644]
fnpdjango/utils/text/__init__.py [new file with mode: 0644]
fnpdjango/utils/text/slughifi.py [new file with mode: 0644]
fnpdjango/utils/text/textilepl.py [new file with mode: 0644]
fnpdjango/utils/urls.py [new file with mode: 0644]
fnpdjango/utils/views.py [new file with mode: 0644]
migdal/__init__.py
migdal/admin.py
migdal/api.py
migdal/feeds.py
migdal/forms.py
migdal/helpers.py
migdal/middleware.py [deleted file]
migdal/models.py
migdal/readme.md [new file with mode: 0644]
migdal/search_indexes.py
migdal/templates/comments/migdal/entry/list.html
migdal/templates/comments/migdal/entry/preview.html
migdal/templates/migdal/entry/entry_detail.html
migdal/templates/migdal/entry/entry_list.html
migdal/templates/migdal/entry/entry_short.html
migdal/templates/migdal/last_comments.html
migdal/urls.py
prawokultury/helpers.py [deleted file]
prawokultury/model_helpers.py [deleted file]
prawokultury/settings.d/30-apps.conf
prawokultury/settings.d/35-search.conf
prawokultury/settings.d/40-middleware.conf
prawokultury/settings.d/50-contrib.conf
prawokultury/settings.d/60-custom.conf
prawokultury/static/css/search.css
prawokultury/static/css/search.scss
prawokultury/templates/base.html
prawokultury/templates/prevnext/next.html [deleted file]
prawokultury/templates/prevnext/previous.html [deleted file]
prawokultury/templates/prevnext/prevnext.html [deleted file]
prawokultury/templates/share.html [deleted file]
prawokultury/templatetags/__init__.py [deleted file]
prawokultury/templatetags/common_tags.py [deleted file]
prawokultury/templatetags/markup_tags.py [deleted file]
prawokultury/templatetags/prevnext.py [deleted file]
prawokultury/templatetags/share.py [deleted file]
prawokultury/urls.py
realip_middleware.py [deleted file]

index 5e8bf90..0f043ed 100644 (file)
@@ -42,7 +42,7 @@ some_template.html:
 
 """
 
-from prawokultury.helpers import AppSettings
+from fnpdjango.utils.app import AppSettings
 
 
 class Settings(AppSettings):
diff --git a/contact/utils.py b/contact/utils.py
deleted file mode 100755 (executable)
index e69de29..0000000
index 5d4a62a..e4dfeef 100644 (file)
@@ -2,7 +2,7 @@ from django.contrib.auth.decorators import permission_required
 from django.http import Http404, HttpResponse
 from django.shortcuts import get_object_or_404, redirect, render
 from django.utils.translation import ugettext_lazy as _
-from prawokultury.helpers import serve_file
+from fnpdjango.utils.views import serve_file
 from .forms import contact_forms
 from .models import Attachment
 
index 9de4ba2..300aa93 100644 (file)
@@ -1,4 +1,4 @@
-from prawokultury.helpers import AppSettings
+from fnpdjango.utils.app import AppSettings
 
 
 class Settings(AppSettings):
index 794fa52..b584b6f 100644 (file)
@@ -4,8 +4,8 @@
 #
 from django.conf import settings
 from django.contrib import admin
+from fnpdjango.utils.models.translation import translated_fields
 from events.models import Event
-from migdal.helpers import translated_fields
 
 
 class EventAdmin(admin.ModelAdmin):
index e20ae53..aa36591 100644 (file)
@@ -6,7 +6,7 @@ from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.db import models
 from django.utils.translation import ugettext_lazy as _, ugettext
-from migdal.helpers import add_translatable
+from fnpdjango.utils.models.translation import add_translatable
 
 
 class Event(models.Model):
index 9977957..2fe31cb 100644 (file)
@@ -2,7 +2,7 @@ from django.conf import settings
 import datetime
 from haystack import indexes
 from events.models import Event
-from migdal.helpers import add_translatable_index
+from fnpdjango.utils.models.translation import add_translatable_index
 
 
 class EventIndex(indexes.RealTimeSearchIndex, indexes.Indexable):
index 66c5184..b6dd773 100755 (executable)
@@ -1,6 +1,6 @@
 {% extends "base.html" %}
 {% load url from future %}
-{% load i18n pagination_tags prevnext %}
+{% load i18n pagination_tags fnp_prevnext %}
 {% load events_tags %}
 
 {% block "body" %}
diff --git a/fnpdjango/__init__.py b/fnpdjango/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/fnpdjango/middleware.py b/fnpdjango/middleware.py
new file mode 100644 (file)
index 0000000..21de872
--- /dev/null
@@ -0,0 +1,31 @@
+from django.utils import translation
+from django.conf import settings
+from django.http import Http404
+
+
+class SetRemoteAddrFromXRealIP(object):
+    """Sets REMOTE_ADDR from the X-Real-IP header, as set by Nginx."""
+    def process_request(self, request):
+        try:
+            request.META['REMOTE_ADDR'] = request.META['HTTP_X_REAL_IP']
+        except KeyError:
+            return None
+
+
+class URLLocaleMiddleware(object):
+    """Decides which translation to use, based on path only."""
+
+    def process_request(self, request):
+        language = translation.get_language_from_path(request.path_info)
+        if language == settings.LANGUAGE_CODE:
+            raise Http404
+        if language:
+            translation.activate(language)
+        request.LANGUAGE_CODE = translation.get_language()
+
+    def process_response(self, request, response):
+        language = translation.get_language()
+        translation.deactivate()
+        if 'Content-Language' not in response:
+            response['Content-Language'] = language
+        return response
diff --git a/fnpdjango/models.py b/fnpdjango/models.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/fnpdjango/templates/fnpdjango/prevnext/next.html b/fnpdjango/templates/fnpdjango/prevnext/next.html
new file mode 100755 (executable)
index 0000000..928011f
--- /dev/null
@@ -0,0 +1,16 @@
+{% if number or url %}
+    {% load i18n %}
+    <a class="next_page" 
+        {% if number %}
+            href="?page={{ number }}"
+        {% else %}
+            href="{{ url }}"
+        {% endif %}
+    >
+        {% if title %}
+            {{ title }}
+        {% else %}
+            {% trans "next" %}
+        {% endif %}
+    </a>
+{% endif %}
\ No newline at end of file
diff --git a/fnpdjango/templates/fnpdjango/prevnext/previous.html b/fnpdjango/templates/fnpdjango/prevnext/previous.html
new file mode 100755 (executable)
index 0000000..88a656b
--- /dev/null
@@ -0,0 +1,16 @@
+{% if number or url %}
+    {% load i18n %}
+    <a class="previous_page" 
+        {% if number %}
+            href="?page={{ number }}"
+        {% else %}
+            href="{{ url }}"
+        {% endif %}
+    >
+        {% if title %}
+            {{ title }}
+        {% else %}
+            {% trans "previous" %}
+        {% endif %}
+    </a>
+{% endif %}
\ No newline at end of file
diff --git a/fnpdjango/templates/fnpdjango/prevnext/prevnext.html b/fnpdjango/templates/fnpdjango/prevnext/prevnext.html
new file mode 100755 (executable)
index 0000000..fd3f9b3
--- /dev/null
@@ -0,0 +1,5 @@
+{% load fnp_prevnext %}
+<p class="prevnext">
+{% next_page %}
+{% previous_page %}
+</p>
\ No newline at end of file
diff --git a/fnpdjango/templates/fnpdjango/share.html b/fnpdjango/templates/fnpdjango/share.html
new file mode 100755 (executable)
index 0000000..c42e81b
--- /dev/null
@@ -0,0 +1,35 @@
+{% load i18n fnp_common static %}
+{% with encoded_url=url|build_absolute_uri:request|urlencode encoded_desc=description|urlencode %}
+<a rel="nofollow" target="_blank" class="facebook"
+    href="https://www.facebook.com/sharer.php?u={{ encoded_url }}"
+    title="{% trans 'Share on Facebook' %}">
+    <img src="{% static "img/social/"|add:iconset|add:"facebook.png" %}"
+        alt="{% trans 'Share on Facebook' %}"></a>
+<a rel="nofollow" target="_blank" class="google"
+    href="https://plus.google.com/share?url={{ encoded_url }}"
+    title="{% trans 'Share on Google+' %}">
+    <img src="{% static "img/social/"|add:iconset|add:"google.png" %}"
+        alt="{% trans 'Share on Google+' %}"></a>
+<a rel="nofollow" target="_blank" class="twitter"
+    href="https://twitter.com/intent/tweet?url={{ encoded_url }}&amp;text={{ encoded_desc }}"
+    title="{% trans 'Share on Twitter' %}">
+    <img src="{% static "img/social/"|add:iconset|add:"twitter.png" %}"
+        alt="{% trans 'Share on Twitter' %}"></a>
+<a rel="nofollow" target="_blank" class="nk"
+    href="http://nk.pl/#sledzik?shout={{ encoded_desc }}%20{{ encoded_url }}"
+    title="{% trans 'Share on NK.pl' %}">
+    <img src="{% static "img/social/"|add:iconset|add:"nk.png" %}"
+        alt="{% trans 'Share on NK.pl' %}"></a>
+{% comment %}
+<a rel="nofollow" target="_blank" class="diaspora"
+    href="http://sharetodiaspora.github.com/?title={{ encoded_desc }}&amp;url={{ encoded_url }}"
+    title="{% trans 'Share on Diaspora' %}">
+    <img src="{% static "img/social/"|add:iconset|add:"diaspora.png" %}"
+        alt="{% trans 'Share on Diaspora' %}"></a>
+<a rel="nofollow" target="_blank" class="blip"
+    href="http://blip.pl/dashboard?body={{ encoded_desc }}%20{{ encoded_url }}"
+    title="{% trans 'Share on Blip.pl' %}">
+    <img src="{% static "img/social/"|add:iconset|add:"blip.png" %}"
+        alt="{% trans 'Share on Blip.pl' %}"></a>
+{% endcomment %}
+{% endwith %}
\ No newline at end of file
diff --git a/fnpdjango/templatetags/__init__.py b/fnpdjango/templatetags/__init__.py
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/fnpdjango/templatetags/fnp_common.py b/fnpdjango/templatetags/fnp_common.py
new file mode 100755 (executable)
index 0000000..ccaf03b
--- /dev/null
@@ -0,0 +1,7 @@
+from django import template
+register = template.Library()
+
+
+@register.filter
+def build_absolute_uri(uri, request):
+    return request.build_absolute_uri(uri)
diff --git a/fnpdjango/templatetags/fnp_markup.py b/fnpdjango/templatetags/fnp_markup.py
new file mode 100755 (executable)
index 0000000..050486a
--- /dev/null
@@ -0,0 +1,14 @@
+from django import template
+from django.utils.safestring import mark_safe
+from ..utils.text import textilepl
+
+register = template.Library()
+
+
+@register.filter
+def textile_pl(node):
+    return mark_safe(textile.textile_pl(node))
+
+@register.filter
+def textile_restricted_pl(node):
+    return mark_safe(textile.textile_restricted_pl(node))
diff --git a/fnpdjango/templatetags/fnp_prevnext.py b/fnpdjango/templatetags/fnp_prevnext.py
new file mode 100755 (executable)
index 0000000..4cfbb08
--- /dev/null
@@ -0,0 +1,27 @@
+from django.template import Library
+
+register = Library()
+
+
+@register.inclusion_tag('fnpdjango/prevnext/previous.html', takes_context=True)
+def previous_page(context, fallback=None, fallback_title=None):
+    current = context['page_obj'].number
+    if current > 1:
+        return {'number': current - 1, 'title': None, 'url': None}
+    else:
+        return {'number': None, 'title': fallback_title, 'url': fallback}
+
+
+@register.inclusion_tag('fnpdjango/prevnext/next.html', takes_context=True)
+def next_page(context, fallback=None, fallback_title=None):
+    current = context['page_obj'].number
+    page_range = context['paginator'].page_range
+    if current < page_range[-1]:
+        return {'number': current + 1, 'title': None, 'url': None}
+    else:
+        return {'number': None, 'title': fallback_title, 'url': fallback}
+
+
+@register.inclusion_tag('fnpdjango/prevnext/prevnext.html', takes_context=True)
+def prevnext(context):
+    return context
diff --git a/fnpdjango/templatetags/fnp_share.py b/fnpdjango/templatetags/fnp_share.py
new file mode 100755 (executable)
index 0000000..3af9447
--- /dev/null
@@ -0,0 +1,13 @@
+from django.template import Library
+
+register = Library()
+
+
+@register.inclusion_tag('fnpdjango/share.html', takes_context=True)
+def share(context, url, description, iconset=""):
+    return {
+        'url': url,
+        'description': description,
+        'iconset': iconset,
+        'request': context['request'],
+    }
diff --git a/fnpdjango/utils/__init__.py b/fnpdjango/utils/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/fnpdjango/utils/app.py b/fnpdjango/utils/app.py
new file mode 100755 (executable)
index 0000000..795e01d
--- /dev/null
@@ -0,0 +1,30 @@
+"""
+Basic utilities for applications.
+"""
+
+
+from django.conf import settings
+
+
+class AppSettings(object):
+    """Allows specyfying custom settings for an app, with default values.
+
+    Just subclass, set some properties and instantiate with a prefix.
+    Getting a SETTING from an instance will check for prefix_SETTING
+    in project settings if set, else take the default. The value will be
+    then filtered through _more_SETTING method, if there is one.
+
+    """
+    def __init__(self, prefix):
+        self._prefix = prefix
+
+    def __getattribute__(self, name):
+        if name.startswith('_'):
+            return object.__getattribute__(self, name)
+        value = getattr(settings,
+                         "%s_%s" % (self._prefix, name),
+                         object.__getattribute__(self, name))
+        more = "_more_%s" % name
+        if hasattr(self, more):
+            value = getattr(self, more)(value)
+        return value
diff --git a/fnpdjango/utils/models/__init__.py b/fnpdjango/utils/models/__init__.py
new file mode 100644 (file)
index 0000000..6c6e620
--- /dev/null
@@ -0,0 +1,25 @@
+"""
+Utilities for Django models.
+"""
+
+from django.utils.translation import string_concat
+
+
+def filtered_model(name, model, field, value, verbose_extra=None):
+    """Creates a proxy model filtering objects by a field."""
+    verbose_extra = verbose_extra or value
+    class  Meta:
+        proxy = True
+        app_label = model._meta.app_label
+        verbose_name = string_concat(model._meta.verbose_name,
+            ': ', verbose_extra)
+        verbose_name_plural = string_concat(model._meta.verbose_name_plural,
+            ': ', verbose_extra)
+
+    def save(self, *args, **kwargs):
+        if not getattr(self, field):
+            setattr(self, field, value)
+        return model.save(self, *args, **kwargs)
+
+    attrs = {'__module__': '', 'Meta': Meta, 'save': save}
+    return type(name, (model,), attrs)
diff --git a/fnpdjango/utils/models/translation.py b/fnpdjango/utils/models/translation.py
new file mode 100644 (file)
index 0000000..dd1d515
--- /dev/null
@@ -0,0 +1,57 @@
+"""
+Utilities for creating multilingual fields in your apps.
+"""
+
+from copy import copy
+from django.conf import settings
+from django.utils.translation import get_language, string_concat
+
+
+def field_getter(name):
+    @property
+    def getter(self):
+        val = getattr(self, "%s_%s" % (name, get_language()), None)
+        if not val:
+            val = getattr(self, "%s_%s" % (name, settings.LANGUAGE_CODE))
+        return val
+    return getter
+
+
+def add_translatable(model, fields, languages=None):
+    """Adds some translatable fields to a model, and a getter."""
+    if languages is None:
+        languages = settings.LANGUAGES
+    for name, field in fields.items():
+        for lang_code, lang_name in languages:
+            new_field = copy(field)
+            if field.verbose_name:
+                new_field.verbose_name = string_concat(field.verbose_name, ' [%s]' % lang_code)
+            new_field.contribute_to_class(model, "%s_%s" % (name, lang_code))
+        setattr(model, name, field_getter(name))
+        # add setter?
+
+
+def add_translatable_index(index_class, fields, languages=None):
+    """Adds some translatable fields to a search index."""
+    if languages is None:
+        languages = settings.LANGUAGES
+    for name, field in fields.items():
+        for lang_code, lang_name in languages:
+            new_field = copy(field)
+            fname = "%s_%s" % (name, lang_code)
+            new_field.index_fieldname = new_field.index_fieldname \
+                and "%s_%s" % (new_field.index_fieldname, lang_code) \
+                or fname
+            new_field.model_attr = new_field.model_attr \
+                and "%s_%s" % (new_field.model_attr, lang_code) \
+                or fname
+            setattr(index_class, fname, new_field)
+            index_class.fields[fname] = new_field
+
+
+def translated_fields(field_names, languages=settings.LANGUAGES):
+    """Generate a tuple of field names in translated versions."""
+    return tuple("%s_%s" % (field_name, lang_code)
+                for field_name in field_names
+                for lang_code, lang_name in languages
+                )
diff --git a/fnpdjango/utils/settings.py b/fnpdjango/utils/settings.py
new file mode 100644 (file)
index 0000000..39b0a25
--- /dev/null
@@ -0,0 +1,24 @@
+"""
+Utilities for global settings.
+"""
+
+
+class LazyUGettextLazy(object):
+    """You can use it to internationalize strings in settings.
+
+    Just import this class as gettext.
+    """
+    _ = lambda s: s
+    real = False
+
+    def __init__(self, text):
+        self.text = text
+
+    def __unicode__(self):
+        if not self.real:
+            from django.utils.translation import ugettext_lazy
+            LazyUGettextLazy._ = staticmethod(ugettext_lazy)
+            LazyUGettextLazy.real = True
+        return unicode(self._(self.text))
+
+
diff --git a/fnpdjango/utils/text/__init__.py b/fnpdjango/utils/text/__init__.py
new file mode 100644 (file)
index 0000000..e9aecbb
--- /dev/null
@@ -0,0 +1,3 @@
+"""
+Text utilities.
+"""
\ No newline at end of file
diff --git a/fnpdjango/utils/text/slughifi.py b/fnpdjango/utils/text/slughifi.py
new file mode 100644 (file)
index 0000000..fe5c9e3
--- /dev/null
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+import re
+from types import UnicodeType
+
+from django.template.defaultfilters import slugify
+
+# default unicode character mapping ( you may not see some chars, leave as is )
+char_map = {u'À': 'A', u'Á': 'A', u'Â': 'A', u'Ã': 'A', u'Ä': 'Ae', u'Å': 'A', u'Æ': 'A', u'Ā': 'A', u'Ą': 'A', u'Ă': 'A', u'Ç': 'C', u'Ć': 'C', u'Č': 'C', u'Ĉ': 'C', u'Ċ': 'C', u'Ď': 'D', u'Đ': 'D', u'È': 'E', u'É': 'E', u'Ê': 'E', u'Ë': 'E', u'Ē': 'E', u'Ę': 'E', u'Ě': 'E', u'Ĕ': 'E', u'Ė': 'E', u'Ĝ': 'G', u'Ğ': 'G', u'Ġ': 'G', u'Ģ': 'G', u'Ĥ': 'H', u'Ħ': 'H', u'Ì': 'I', u'Í': 'I', u'Î': 'I', u'Ï': 'I', u'Ī': 'I', u'Ĩ': 'I', u'Ĭ': 'I', u'Į': 'I', u'İ': 'I', u'IJ': 'IJ', u'Ĵ': 'J', u'Ķ': 'K', u'Ľ': 'K', u'Ĺ': 'K', u'Ļ': 'K', u'Ŀ': 'K', u'Ł': 'L', u'Ñ': 'N', u'Ń': 'N', u'Ň': 'N', u'Ņ': 'N', u'Ŋ': 'N', u'Ò': 'O', u'Ó': 'O', u'Ô': 'O', u'Õ': 'O', u'Ö': 'Oe', u'Ø': 'O', u'Ō': 'O', u'Ő': 'O', u'Ŏ': 'O', u'Œ': 'OE', u'Ŕ': 'R', u'Ř': 'R', u'Ŗ': 'R', u'Ś': 'S', u'Ş': 'S', u'Ŝ': 'S', u'Ș': 'S', u'Š': 'S', u'Ť': 'T', u'Ţ': 'T', u'Ŧ': 'T', u'Ț': 'T', u'Ù': 'U', u'Ú': 'U', u'Û': 'U', u'Ü': 'Ue', u'Ū': 'U', u'Ů': 'U', u'Ű': 'U', u'Ŭ': 'U', u'Ũ': 'U', u'Ų': 'U', u'Ŵ': 'W', u'Ŷ': 'Y', u'Ÿ': 'Y', u'Ý': 'Y', u'Ź': 'Z', u'Ż': 'Z', u'Ž': 'Z', u'à': 'a', u'á': 'a', u'â': 'a', u'ã': 'a', u'ä': 'ae', u'ā': 'a', u'ą': 'a', u'ă': 'a', u'å': 'a', u'æ': 'ae', u'ç': 'c', u'ć': 'c', u'č': 'c', u'ĉ': 'c', u'ċ': 'c', u'ď': 'd', u'đ': 'd', u'è': 'e', u'é': 'e', u'ê': 'e', u'ë': 'e', u'ē': 'e', u'ę': 'e', u'ě': 'e', u'ĕ': 'e', u'ė': 'e', u'ƒ': 'f', u'ĝ': 'g', u'ğ': 'g', u'ġ': 'g', u'ģ': 'g', u'ĥ': 'h', u'ħ': 'h', u'ì': 'i', u'í': 'i', u'î': 'i', u'ï': 'i', u'ī': 'i', u'ĩ': 'i', u'ĭ': 'i', u'į': 'i', u'ı': 'i', u'ij': 'ij', u'ĵ': 'j', u'ķ': 'k', u'ĸ': 'k', u'ł': 'l', u'ľ': 'l', u'ĺ': 'l', u'ļ': 'l', u'ŀ': 'l', u'ñ': 'n', u'ń': 'n', u'ň': 'n', u'ņ': 'n', u'ʼn': 'n', u'ŋ': 'n', u'ò': 'o', u'ó': 'o', u'ô': 'o', u'õ': 'o', u'ö': 'oe', u'ø': 'o', u'ō': 'o', u'ő': 'o', u'ŏ': 'o', u'œ': 'oe', u'ŕ': 'r', u'ř': 'r', u'ŗ': 'r', u'ś': 's', u'š': 's', u'ť': 't', u'ù': 'u', u'ú': 'u', u'û': 'u', u'ü': 'ue', u'ū': 'u', u'ů': 'u', u'ű': 'u', u'ŭ': 'u', u'ũ': 'u', u'ų': 'u', u'ŵ': 'w', u'ÿ': 'y', u'ý': 'y', u'ŷ': 'y', u'ż': 'z', u'ź': 'z', u'ž': 'z', u'ß': 'ss', u'ſ': 'ss', u'Α': 'A', u'Ά': 'A', u'Ἀ': 'A', u'Ἁ': 'A', u'Ἂ': 'A', u'Ἃ': 'A', u'Ἄ': 'A', u'Ἅ': 'A', u'Ἆ': 'A', u'Ἇ': 'A', u'ᾈ': 'A', u'ᾉ': 'A', u'ᾊ': 'A', u'ᾋ': 'A', u'ᾌ': 'A', u'ᾍ': 'A', u'ᾎ': 'A', u'ᾏ': 'A', u'Ᾰ': 'A', u'Ᾱ': 'A', u'Ὰ': 'A', u'Ά': 'A', u'ᾼ': 'A', u'Β': 'B', u'Γ': 'G', u'Δ': 'D', u'Ε': 'E', u'Έ': 'E', u'Ἐ': 'E', u'Ἑ': 'E', u'Ἒ': 'E', u'Ἓ': 'E', u'Ἔ': 'E', u'Ἕ': 'E', u'Έ': 'E', u'Ὲ': 'E', u'Ζ': 'Z', u'Η': 'I', u'Ή': 'I', u'Ἠ': 'I', u'Ἡ': 'I', u'Ἢ': 'I', u'Ἣ': 'I', u'Ἤ': 'I', u'Ἥ': 'I', u'Ἦ': 'I', u'Ἧ': 'I', u'ᾘ': 'I', u'ᾙ': 'I', u'ᾚ': 'I', u'ᾛ': 'I', u'ᾜ': 'I', u'ᾝ': 'I', u'ᾞ': 'I', u'ᾟ': 'I', u'Ὴ': 'I', u'Ή': 'I', u'ῌ': 'I', u'Θ': 'TH', u'Ι': 'I', u'Ί': 'I', u'Ϊ': 'I', u'Ἰ': 'I', u'Ἱ': 'I', u'Ἲ': 'I', u'Ἳ': 'I', u'Ἴ': 'I', u'Ἵ': 'I', u'Ἶ': 'I', u'Ἷ': 'I', u'Ῐ': 'I', u'Ῑ': 'I', u'Ὶ': 'I', u'Ί': 'I', u'Κ': 'K', u'Λ': 'L', u'Μ': 'M', u'Ν': 'N', u'Ξ': 'KS', u'Ο': 'O', u'Ό': 'O', u'Ὀ': 'O', u'Ὁ': 'O', u'Ὂ': 'O', u'Ὃ': 'O', u'Ὄ': 'O', u'Ὅ': 'O', u'Ὸ': 'O', u'Ό': 'O', u'Π': 'P', u'Ρ': 'R', u'Ῥ': 'R', u'Σ': 'S', u'Τ': 'T', u'Υ': 'Y', u'Ύ': 'Y', u'Ϋ': 'Y', u'Ὑ': 'Y', u'Ὓ': 'Y', u'Ὕ': 'Y', u'Ὗ': 'Y', u'Ῠ': 'Y', u'Ῡ': 'Y', u'Ὺ': 'Y', u'Ύ': 'Y', u'Φ': 'F', u'Χ': 'X', u'Ψ': 'PS', u'Ω': 'O', u'Ώ': 'O', u'Ὠ': 'O', u'Ὡ': 'O', u'Ὢ': 'O', u'Ὣ': 'O', u'Ὤ': 'O', u'Ὥ': 'O', u'Ὦ': 'O', u'Ὧ': 'O', u'ᾨ': 'O', u'ᾩ': 'O', u'ᾪ': 'O', u'ᾫ': 'O', u'ᾬ': 'O', u'ᾭ': 'O', u'ᾮ': 'O', u'ᾯ': 'O', u'Ὼ': 'O', u'Ώ': 'O', u'ῼ': 'O', u'α': 'a', u'ά': 'a', u'ἀ': 'a', u'ἁ': 'a', u'ἂ': 'a', u'ἃ': 'a', u'ἄ': 'a', u'ἅ': 'a', u'ἆ': 'a', u'ἇ': 'a', u'ᾀ': 'a', u'ᾁ': 'a', u'ᾂ': 'a', u'ᾃ': 'a', u'ᾄ': 'a', u'ᾅ': 'a', u'ᾆ': 'a', u'ᾇ': 'a', u'ὰ': 'a', u'ά': 'a', u'ᾰ': 'a', u'ᾱ': 'a', u'ᾲ': 'a', u'ᾳ': 'a', u'ᾴ': 'a', u'ᾶ': 'a', u'ᾷ': 'a', u'β': 'b', u'γ': 'g', u'δ': 'd', u'ε': 'e', u'έ': 'e', u'ἐ': 'e', u'ἑ': 'e', u'ἒ': 'e', u'ἓ': 'e', u'ἔ': 'e', u'ἕ': 'e', u'ὲ': 'e', u'έ': 'e', u'ζ': 'z', u'η': 'i', u'ή': 'i', u'ἠ': 'i', u'ἡ': 'i', u'ἢ': 'i', u'ἣ': 'i', u'ἤ': 'i', u'ἥ': 'i', u'ἦ': 'i', u'ἧ': 'i', u'ᾐ': 'i', u'ᾑ': 'i', u'ᾒ': 'i', u'ᾓ': 'i', u'ᾔ': 'i', u'ᾕ': 'i', u'ᾖ': 'i', u'ᾗ': 'i', u'ὴ': 'i', u'ή': 'i', u'ῂ': 'i', u'ῃ': 'i', u'ῄ': 'i', u'ῆ': 'i', u'ῇ': 'i', u'θ': 'th', u'ι': 'i', u'ί': 'i', u'ϊ': 'i', u'ΐ': 'i', u'ἰ': 'i', u'ἱ': 'i', u'ἲ': 'i', u'ἳ': 'i', u'ἴ': 'i', u'ἵ': 'i', u'ἶ': 'i', u'ἷ': 'i', u'ὶ': 'i', u'ί': 'i', u'ῐ': 'i', u'ῑ': 'i', u'ῒ': 'i', u'ΐ': 'i', u'ῖ': 'i', u'ῗ': 'i', u'κ': 'k', u'λ': 'l', u'μ': 'm', u'ν': 'n', u'ξ': 'ks', u'ο': 'o', u'ό': 'o', u'ὀ': 'o', u'ὁ': 'o', u'ὂ': 'o', u'ὃ': 'o', u'ὄ': 'o', u'ὅ': 'o', u'ὸ': 'o', u'ό': 'o', u'π': 'p', u'ρ': 'r', u'ῤ': 'r', u'ῥ': 'r', u'σ': 's', u'ς': 's', u'τ': 't', u'υ': 'y', u'ύ': 'y', u'ϋ': 'y', u'ΰ': 'y', u'ὐ': 'y', u'ὑ': 'y', u'ὒ': 'y', u'ὓ': 'y', u'ὔ': 'y', u'ὕ': 'y', u'ὖ': 'y', u'ὗ': 'y', u'ὺ': 'y', u'ύ': 'y', u'ῠ': 'y', u'ῡ': 'y', u'ῢ': 'y', u'ΰ': 'y', u'ῦ': 'y', u'ῧ': 'y', u'φ': 'f', u'χ': 'x', u'ψ': 'ps', u'ω': 'o', u'ώ': 'o', u'ὠ': 'o', u'ὡ': 'o', u'ὢ': 'o', u'ὣ': 'o', u'ὤ': 'o', u'ὥ': 'o', u'ὦ': 'o', u'ὧ': 'o', u'ᾠ': 'o', u'ᾡ': 'o', u'ᾢ': 'o', u'ᾣ': 'o', u'ᾤ': 'o', u'ᾥ': 'o', u'ᾦ': 'o', u'ᾧ': 'o', u'ὼ': 'o', u'ώ': 'o', u'ῲ': 'o', u'ῳ': 'o', u'ῴ': 'o', u'ῶ': 'o', u'ῷ': 'o', u'¨': '', u'΅': '', u'᾿': '', u'῾': '', u'῍': '', u'῝': '', u'῎': '', u'῞': '', u'῏': '', u'῟': '', u'῀': '', u'῁': '', u'΄': '', u'΅': '', u'`': '', u'῭': '', u'ͺ': '', u'᾽': '', u'А': 'A', u'Б': 'B', u'В': 'V', u'Г': 'G', u'Д': 'D', u'Е': 'E', u'Ё': 'E', u'Ж': 'ZH', u'З': 'Z', u'И': 'I', u'Й': 'I', u'К': 'K', u'Л': 'L', u'М': 'M', u'Н': 'N', u'О': 'O', u'П': 'P', u'Р': 'R', u'С': 'S', u'Т': 'T', u'У': 'U', u'Ф': 'F', u'Х': 'KH', u'Ц': 'TS', u'Ч': 'CH', u'Ш': 'SH', u'Щ': 'SHCH', u'Ы': 'Y', u'Э': 'E', u'Ю': 'YU', u'Я': 'YA', u'а': 'A', u'б': 'B', u'в': 'V', u'г': 'G', u'д': 'D', u'е': 'E', u'ё': 'E', u'ж': 'ZH', u'з': 'Z', u'и': 'I', u'й': 'I', u'к': 'K', u'л': 'L', u'м': 'M', u'н': 'N', u'о': 'O', u'п': 'P', u'р': 'R', u'с': 'S', u'т': 'T', u'у': 'U', u'ф': 'F', u'х': 'KH', u'ц': 'TS', u'ч': 'CH', u'ш': 'SH', u'щ': 'SHCH', u'ы': 'Y', u'э': 'E', u'ю': 'YU', u'я': 'YA', u'Ъ': '', u'ъ': '', u'Ь': '', u'ь': '', u'ð': 'd', u'Ð': 'D', u'þ': 'th', u'Þ': 'TH',
+            u'ა': 'a', u'ბ': 'b', u'გ': 'g', u'დ': 'd', u'ე': 'e', u'ვ': 'v', u'ზ': 'z', u'თ': 't', u'ი': 'i', u'კ': 'k', u'ლ': 'l', u'მ': 'm', u'ნ': 'n', u'ო': 'o', u'პ': 'p', u'ჟ': 'zh', u'რ': 'r', u'ს': 's', u'ტ': 't', u'უ': 'u', u'ფ': 'p', u'ქ': 'k', u'ღ': 'gh', u'ყ': 'q', u'შ': 'sh', u'ჩ': 'ch', u'ც': 'ts', u'ძ': 'dz', u'წ': 'ts', u'ჭ': 'ch', u'ხ': 'kh', u'ჯ': 'j', u'ჰ': 'h' }
+
+def replace_char(m):
+    char = m.group()
+    if char_map.has_key(char):
+        return char_map[char]
+    else:
+        return char
+
+def slughifi(value, do_slugify=True, overwrite_char_map={}):
+    """
+        High Fidelity slugify - slughifi.py, v 0.1
+
+        Examples :
+
+        >>> text = 'C\'est déjà l\'été.'
+
+        >>> slughifi(text)
+        'cest-deja-lete'
+
+        >>> slughifi(text, overwrite_char_map={u'\'': '-',})
+        'c-est-deja-l-ete'
+
+        >>> slughifi(text, do_slugify=False)
+        "C'est deja l'ete."
+
+        # Normal slugify removes accented characters
+        >>> slugify(text)
+        'cest-dj-lt'
+
+    """
+
+    # unicodification
+    if type(value) != UnicodeType:
+        value = unicode(value, 'utf-8', 'ignore')
+
+    # overwrite chararcter mapping
+    char_map.update(overwrite_char_map)
+
+    # try to replace chars
+    value = re.sub('[^a-zA-Z0-9\\s\\-]{1}', replace_char, value)
+
+    # apply django default slugify
+    if do_slugify:
+        value = slugify(value)
+
+    return value.encode('ascii', 'ignore')
+
diff --git a/fnpdjango/utils/text/textilepl.py b/fnpdjango/utils/text/textilepl.py
new file mode 100644 (file)
index 0000000..2efde25
--- /dev/null
@@ -0,0 +1,22 @@
+from textile import Textile
+
+
+class TextilePL(Textile):
+    """Polish version of Textile.
+
+    Changes opening quote to Polish lower-double.
+    """
+    glyph_defaults = [(name, repl) 
+        for (name, repl) in Textile.glyph_defaults
+        if name != 'txt_quote_double_open']
+    glyph_defaults.append(('txt_quote_double_open', '&#8222;'))
+
+
+def textile_pl(text):
+    return TextilePL().textile(text)
+
+
+def textile_restricted_pl(text):
+    return TextilePL(restricted=True, lite=True,
+                   noimage=True, auto_link=False).textile(
+                        text, rel='nofollow')
diff --git a/fnpdjango/utils/urls.py b/fnpdjango/utils/urls.py
new file mode 100644 (file)
index 0000000..bf9747d
--- /dev/null
@@ -0,0 +1,40 @@
+"""
+Utilities for urlconfs.
+"""
+
+import re
+from django.conf import settings
+from django.conf.urls import patterns
+from django.core.urlresolvers import LocaleRegexURLResolver
+from django.utils.translation import get_language, string_concat
+
+
+class MyLocaleRegexURLResolver(LocaleRegexURLResolver):
+    """
+    A URL resolver that always matches the active language code as URL prefix.
+
+    Rather than taking a regex argument, we just override the ``regex``
+    function to always return the active language-code as regex.
+    """
+    @property
+    def regex(self):
+        language_code = get_language()
+        if language_code == settings.LANGUAGE_CODE:
+            return re.compile('')
+        if language_code not in self._regex_dict:
+            regex_compiled = re.compile('^%s/' % language_code, re.UNICODE)
+            self._regex_dict[language_code] = regex_compiled
+        return self._regex_dict[language_code]
+
+
+def i18n_patterns(prefix, *args):
+    """
+    Adds the language code prefix to every URL pattern within this
+    function. This may only be used in the root URLconf, not in an included
+    URLconf.
+
+    """
+    pattern_list = patterns(prefix, *args)
+    if not settings.USE_I18N:
+        return pattern_list
+    return pattern_list + [MyLocaleRegexURLResolver(pattern_list)]
diff --git a/fnpdjango/utils/views.py b/fnpdjango/utils/views.py
new file mode 100644 (file)
index 0000000..caf8a43
--- /dev/null
@@ -0,0 +1,17 @@
+"""
+View-specific utilities.
+"""
+
+from django.conf import settings
+from django.http import HttpResponse, HttpResponseRedirect
+
+
+def serve_file(url):
+    """Serves an URL either though Nginx's X-accel, or by redirection.""" 
+    if settings.X_ACCEL_REDIRECT:
+        response = HttpResponse()
+        response['Content-Type'] = ""
+        response['X-Accel-Redirect'] = url
+        return response
+    else:
+        return HttpResponseRedirect(url)
index 0a04b06..4d3a144 100644 (file)
@@ -5,7 +5,7 @@ Migdal (מִגְדָּל) is a multilingual blog Django app.
 Author: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
 """
 from django.conf import settings
-from prawokultury.helpers import AppSettings
+from fnpdjango.utils.app import AppSettings
 from django.utils.translation import ugettext_lazy as _
 from migdal.helpers import EntryType
 
@@ -50,6 +50,3 @@ class Settings(AppSettings):
                         if lang not in self.OBLIGATORY_LANGUAGES)
 
 app_settings = Settings('MIGDAL')
-
-
-
index 4043921..5c01f74 100644 (file)
@@ -7,8 +7,8 @@ from django.contrib import admin
 from django.utils.translation import ugettext_lazy as _
 from migdal.models import Entry, Attachment
 from migdal import app_settings
-from migdal.helpers import translated_fields
-from prawokultury.model_helpers import filtered_model
+from fnpdjango.utils.models import filtered_model
+from fnpdjango.utils.models.translation import translated_fields
 
 
 class AttachmentInline(admin.TabularInline):
index 6f81a4d..d4f031e 100644 (file)
@@ -4,7 +4,7 @@
 #
 from itertools import chain
 from migdal.models import Entry
-from migdal.settings import TYPES
+from migdal import app_settings
 from django.utils.translation import get_language
 
 
@@ -15,7 +15,8 @@ def entry_list(entry_type=None, category=None, promobox=False):
     if entry_type:
         object_list = object_list.filter(type=entry_type.db)
     else:
-        object_list = object_list.filter(type__in=[t.db for t in TYPES if t.on_main])
+        object_list = object_list.filter(
+            type__in=[t.db for t in app_settings.TYPES if t.on_main])
     if category:
         object_list = object_list.filter(categories=category)
 
index 53145c5..33e9e0b 100644 (file)
@@ -8,7 +8,7 @@ from django.shortcuts import get_object_or_404
 from django.utils.translation import ugettext as _, string_concat
 from migdal import api
 from migdal.models import Category
-from migdal.settings import TYPES_DICT
+from migdal import app_settings
 
 
 class EntriesFeed(Feed):
@@ -19,7 +19,7 @@ class EntriesFeed(Feed):
         else:
             category = None
         if type_db:
-            entry_type = TYPES_DICT[type_db]
+            entry_type = app_settings.TYPES_DICT[type_db]
         else:
             entry_type = None
         return {'entry_type': entry_type, 'category': category}
index 9c87bd1..e7d6394 100644 (file)
@@ -5,8 +5,8 @@
 from django import forms
 from django.utils.translation import ugettext_lazy as _, get_language
 from migdal.models import Entry
-from migdal.settings import TYPE_SUBMIT
-from slughifi import slughifi
+from migdal import app_settings
+from fnpdjango.utils.text import slughifi
 from django.core.mail import mail_managers
 from django import template
 
@@ -32,7 +32,7 @@ def get_submit_form(*args, **kwargs):
 
         def clean(self):
             data = super(SubmitForm, self).clean()
-            data['type'] = TYPE_SUBMIT
+            data['type'] = app_settings.TYPE_SUBMIT
             orig_slug = slughifi(data.get('title_%s' % lang, ''))
             slug = orig_slug
             number = 2
index 4e1a16e..8c06c16 100644 (file)
@@ -2,15 +2,6 @@
 # This file is part of PrawoKultury, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
-from collections import namedtuple
-from copy import copy
-import re
-from django.conf import settings
-from django.conf.urls import patterns
-from django.core.urlresolvers import LocaleRegexURLResolver
-from django.utils.translation import get_language, string_concat
-
-
 class EntryType(object):
     def __init__(self, db, slug, commentable=False, on_main=False,
             promotable=False, categorized=False):
@@ -23,83 +14,3 @@ class EntryType(object):
 
     def __unicode__(self):
         return unicode(self.slug)
-
-
-def field_getter(name):
-    @property
-    def getter(self):
-        val = getattr(self, "%s_%s" % (name, get_language()), None)
-        if not val:
-            val = getattr(self, "%s_%s" % (name, settings.LANGUAGE_CODE))
-        return val
-    return getter
-
-
-def add_translatable(model, fields, languages=None):
-    """Adds some translatable fields to a model, and a getter."""
-    if languages is None:
-        languages = settings.LANGUAGES
-    for name, field in fields.items():
-        for lang_code, lang_name in languages:
-            new_field = copy(field)
-            if field.verbose_name:
-                new_field.verbose_name = string_concat(field.verbose_name, ' [%s]' % lang_code)
-            new_field.contribute_to_class(model, "%s_%s" % (name, lang_code))
-        setattr(model, name, field_getter(name))
-        # add setter?
-
-
-class MyLocaleRegexURLResolver(LocaleRegexURLResolver):
-    """
-    A URL resolver that always matches the active language code as URL prefix.
-
-    Rather than taking a regex argument, we just override the ``regex``
-    function to always return the active language-code as regex.
-    """
-    @property
-    def regex(self):
-        language_code = get_language()
-        if language_code == settings.LANGUAGE_CODE:
-            return re.compile('')
-        if language_code not in self._regex_dict:
-            regex_compiled = re.compile('^%s/' % language_code, re.UNICODE)
-            self._regex_dict[language_code] = regex_compiled
-        return self._regex_dict[language_code]
-
-
-def i18n_patterns(prefix, *args):
-    """
-    Adds the language code prefix to every URL pattern within this
-    function. This may only be used in the root URLconf, not in an included
-    URLconf.
-
-    """
-    pattern_list = patterns(prefix, *args)
-    if not settings.USE_I18N:
-        return pattern_list
-    return pattern_list + [MyLocaleRegexURLResolver(pattern_list)]
-
-
-def add_translatable_index(index_class, fields, languages=None):
-    """Adds some translatable fields to a search index, and a getter."""
-    if languages is None:
-        languages = settings.LANGUAGES
-    for name, field in fields.items():
-        for lang_code, lang_name in languages:
-            new_field = copy(field)
-            fname = "%s_%s" % (name, lang_code)
-            new_field.index_fieldname = new_field.index_fieldname \
-                and "%s_%s" % (new_field.index_fieldname, lang_code) \
-                or fname
-            new_field.model_attr = new_field.model_attr \
-                and "%s_%s" % (new_field.model_attr, lang_code) \
-                or fname
-            setattr(index_class, fname, new_field)
-            index_class.fields[fname] = new_field
-
-
-def translated_fields(field_names, languages=settings.LANGUAGES):
-    return tuple("%s_%s" % (field_name, lang_code)
-                for field_name in field_names
-                for lang_code, lang_name in languages
-                )
diff --git a/migdal/middleware.py b/migdal/middleware.py
deleted file mode 100644 (file)
index 7153562..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- coding: utf-8 -*-
-# This file is part of PrawoKultury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.utils import translation
-from django.conf import settings
-from django.http import Http404
-
-
-class URLLocaleMiddleware(object):
-    """Decides which translation to use, based on path only."""
-
-    def process_request(self, request):
-        language = translation.get_language_from_path(request.path_info)
-        if language == settings.LANGUAGE_CODE:
-            raise Http404
-        if language:
-            translation.activate(language)
-        request.LANGUAGE_CODE = translation.get_language()
-
-    def process_response(self, request, response):
-        language = translation.get_language()
-        translation.deactivate()
-        if 'Content-Language' not in response:
-            response['Content-Language'] = language
-        return response
index 028350c..54091e4 100644 (file)
@@ -13,7 +13,7 @@ from django.utils.translation import get_language, ugettext_lazy as _, ugettext
 from django_comments_xtd.models import XtdComment
 from markupfield.fields import MarkupField
 from migdal import app_settings
-from migdal.helpers import add_translatable
+from fnpdjango.utils.models.translation import add_translatable
 from migdal.fields import SlugNullField
 
 class Category(models.Model):
diff --git a/migdal/readme.md b/migdal/readme.md
new file mode 100644 (file)
index 0000000..c125966
--- /dev/null
@@ -0,0 +1 @@
+Why not LocaleMiddleware? (consistent lang, url to lang)
index 4257483..27169f3 100644 (file)
@@ -1,8 +1,8 @@
-from django.conf import settings
 import datetime
+from django.conf import settings
 from haystack import indexes
+from fnpdjango.utils.models.translation import add_translatable_index
 from migdal.models import Entry
-from migdal.helpers import add_translatable_index
 
 
 class EntryIndex(indexes.RealTimeSearchIndex, indexes.Indexable):
index 9f7241b..59510ee 100755 (executable)
@@ -1,6 +1,6 @@
 {% load i18n %}
 {% load gravatar %}
-{% load markup_tags %}
+{% load fnp_markup %}
 <a name="comment"></a>
 <h2 class="section">{% trans "Comments" %}</h2>
 <div class="comments">
index 6d2b5ff..ae3eb92 100755 (executable)
@@ -1,6 +1,6 @@
 {% extends "base.html" %}
 {% load comments gravatar i18n %}
-{% load migdal_tags markup_tags %}
+{% load migdal_tags fnp_markup %}
 
 
 {% block "main_menu" %}
index 5827d08..92bf2dd 100755 (executable)
@@ -1,6 +1,6 @@
 {% extends "base.html" %}
 {% load comments i18n %}
-{% load common_tags migdal_tags share %}
+{% load fnp_common migdal_tags fnp_share %}
 
 
 {% block "titleextra" %}{{ entry.title }} :: {% endblock %}
index eede699..bd9bbf6 100755 (executable)
@@ -1,7 +1,7 @@
 {% extends "base.html" %}
 {% load url from future %}
 {% load i18n %}
-{% load pagination_tags prevnext %}
+{% load pagination_tags fnp_prevnext %}
 {% load migdal_tags %}
 
 
index 31dbf9e..7a5eb25 100755 (executable)
@@ -1,6 +1,6 @@
 {% load i18n %}
 {% load comments %}
-{% load migdal_tags share %}
+{% load migdal_tags fnp_share %}
 
 
 <div class="entry entry-short entry-{{ object.type }}">
index f26cfea..8deba13 100755 (executable)
@@ -1,5 +1,5 @@
 {% load gravatar %}
-{% load markup_tags %}
+{% load fnp_markup %}
 <ul id="latest-comments">
   {% for comment in object_list %}
     <li>
index 3a58123..310a648 100644 (file)
@@ -7,7 +7,7 @@ from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import string_concat
 from migdal import feeds, app_settings
 from migdal.views import SearchPublishedView
-from migdal.helpers import i18n_patterns
+from fnpdjango.utils.urls import i18n_patterns
 
 pats = []
 for t in app_settings.TYPES:
diff --git a/prawokultury/helpers.py b/prawokultury/helpers.py
deleted file mode 100644 (file)
index 9b943de..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-# -*- coding: utf-8 -*-
-# This file is part of PrawoKultury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.conf import settings
-from django.http import HttpResponse, HttpResponseRedirect
-from textile import Textile
-
-
-class TextilePL(Textile):
-    glyph_defaults = [(name, repl) 
-        for (name, repl) in Textile.glyph_defaults
-        if name != 'txt_quote_double_open']
-    glyph_defaults.append(('txt_quote_double_open', '&#8222;'))
-
-
-def textile_pl(text):
-    return TextilePL().textile(text)
-
-
-def textile_restricted_pl(text):
-    return TextilePL(restricted=True, lite=True,
-                   noimage=True, auto_link=False).textile(
-                        text, rel='nofollow')
-
-
-class LazyUGettextLazy(object):
-    """You can use it to internationalize strings in settings.
-
-    Just import this class as gettext.
-    """
-    _ = lambda s: s
-    real = False
-
-    def __init__(self, text):
-        self.text = text
-
-    def __unicode__(self):
-        if not self.real:
-            from django.utils.translation import ugettext_lazy
-            LazyUGettextLazy._ = staticmethod(ugettext_lazy)
-            LazyUGettextLazy.real = True
-        return unicode(self._(self.text))
-
-
-class AppSettings(object):
-    """Allows specyfying custom settings for an app, with default values.
-
-    Just subclass, set some properties and instantiate with a prefix.
-    Getting a SETTING from an instance will check for prefix_SETTING
-    in project settings if set, else take the default. The value will be
-    then filtered through _more_SETTING method, if there is one.
-
-    """
-    def __init__(self, prefix):
-        self._prefix = prefix
-
-    def __getattribute__(self, name):
-        if name.startswith('_'):
-            return object.__getattribute__(self, name)
-        value = getattr(settings,
-                         "%s_%s" % (self._prefix, name),
-                         object.__getattribute__(self, name))
-        more = "_more_%s" % name
-        if hasattr(self, more):
-            value = getattr(self, more)(value)
-        return value
-
-
-def serve_file(url):
-    if settings.X_ACCEL_REDIRECT:
-        response = HttpResponse()
-        response['Content-Type'] = ""
-        response['X-Accel-Redirect'] = url
-        return response
-    else:
-        return HttpResponseRedirect(url)
diff --git a/prawokultury/model_helpers.py b/prawokultury/model_helpers.py
deleted file mode 100755 (executable)
index 4a734b6..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-from django.utils.translation import string_concat
-
-def filtered_model(name, model, field, value, verbose_extra=None):
-    """Creates a proxy model filtering objects by a field."""
-    verbose_extra = verbose_extra or value
-    class  Meta:
-        proxy = True
-        app_label = model._meta.app_label
-        verbose_name = string_concat(model._meta.verbose_name,
-            ': ', verbose_extra)
-        verbose_name_plural = string_concat(model._meta.verbose_name_plural,
-            ': ', verbose_extra)
-
-    def save(self, *args, **kwargs):
-        if not getattr(self, field):
-            setattr(self, field, value)
-        return model.save(self, *args, **kwargs)
-
-    attrs = {'__module__': '', 'Meta': Meta, 'save': save}
-    return type(name, (model,), attrs)
index 60b1f96..f466de7 100755 (executable)
@@ -1,13 +1,15 @@
 INSTALLED_APPS = (
     'prawokultury',
+    'fnpdjango',
+
     #'events',
     'migdal',
     'contact',
 
     'gravatar',
     'south',
-    #'django.contrib.comments',
-    #'django_comments_xtd',
+    'django.contrib.comments',
+    'django_comments_xtd',
     'pipeline',
     'haystack',
     'pagination',
index 62b5799..15667a3 100644 (file)
@@ -5,5 +5,4 @@ HAYSTACK_CONNECTIONS = {
     },
 }
 
-from django.conf import settings
-HAYSTACK_DOCUMENT_FIELD = "body_%s" % settings.LANGUAGE_CODE
+HAYSTACK_DOCUMENT_FIELD = "body_%s" % LANGUAGE_CODE
index cde9886..530e34a 100755 (executable)
@@ -1,7 +1,7 @@
 MIDDLEWARE_CLASSES = (
     'django.contrib.sessions.middleware.SessionMiddleware',
     #'django.middleware.locale.LocaleMiddleware',
-    'migdal.middleware.URLLocaleMiddleware',
+    'fnpdjango.middleware.URLLocaleMiddleware',
 
     'django.middleware.common.CommonMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
@@ -19,5 +19,5 @@ MIDDLEWARE_CLASSES += (
     # Uncomment the next line for simple clickjacking protection:
     # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'pagination.middleware.PaginationMiddleware',
-    'realip_middleware.SetRemoteAddrFromXRealIP',
+    'fnpdjango.middleware.SetRemoteAddrFromXRealIP',
 )
index 27a516c..55c9811 100755 (executable)
@@ -1,4 +1,4 @@
-from prawokultury.helpers import textile_pl
+from fnpdjango.utils.text.textilepl import textile_pl
 
 COMMENTS_APP = "django_comments_xtd"
 COMMENTS_XTD_CONFIRM_EMAIL = False
index 6b26db5..9fec2d5 100755 (executable)
@@ -1,4 +1,4 @@
-from prawokultury.helpers import LazyUGettextLazy as gettext
+from fnpdjango.utils.settings import LazyUGettextLazy as gettext
 from migdal.helpers import EntryType
 
 MIGDAL_TYPES = (
index 6bc635c..77451ce 100644 (file)
@@ -1,5 +1,5 @@
 #search-form {
-  margin-top: .4em; }
+  margin: .4em 0 0 0; }
   #search-form input {
     font-size: 1.1em;
     width: 16.1em;
index 9b9bbe1..f018c15 100644 (file)
@@ -1,5 +1,5 @@
 #search-form {
-    margin-top: .4em;
+    margin: .4em 0 0 0;
 
     input {
         font-size: 1.1em;
index 57ea892..6473962 100755 (executable)
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 {% load url from future %}
 {% load i18n static %}
-{% load common_tags migdal_tags share %}
+{% load fnp_common migdal_tags fnp_share %}
 {% load compressed %}
 <html prefix="og: http://ogp.me/ns#">
     <head>
@@ -27,6 +27,7 @@
         </div>
         <div class="bar-right">
             <div class="social">
+                <a href="{% url 'contact_form' 'register' %}">register!</a>
                 {% url 'migdal_main' as main_url %}
                 {% share main_url "CopyCamp" "big" %}
             </div>
diff --git a/prawokultury/templates/prevnext/next.html b/prawokultury/templates/prevnext/next.html
deleted file mode 100755 (executable)
index 928011f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-{% if number or url %}
-    {% load i18n %}
-    <a class="next_page" 
-        {% if number %}
-            href="?page={{ number }}"
-        {% else %}
-            href="{{ url }}"
-        {% endif %}
-    >
-        {% if title %}
-            {{ title }}
-        {% else %}
-            {% trans "next" %}
-        {% endif %}
-    </a>
-{% endif %}
\ No newline at end of file
diff --git a/prawokultury/templates/prevnext/previous.html b/prawokultury/templates/prevnext/previous.html
deleted file mode 100755 (executable)
index 88a656b..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-{% if number or url %}
-    {% load i18n %}
-    <a class="previous_page" 
-        {% if number %}
-            href="?page={{ number }}"
-        {% else %}
-            href="{{ url }}"
-        {% endif %}
-    >
-        {% if title %}
-            {{ title }}
-        {% else %}
-            {% trans "previous" %}
-        {% endif %}
-    </a>
-{% endif %}
\ No newline at end of file
diff --git a/prawokultury/templates/prevnext/prevnext.html b/prawokultury/templates/prevnext/prevnext.html
deleted file mode 100755 (executable)
index 8a5cd04..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-{% load prevnext %}
-<p class="prevnext">
-{% next_page %}
-{% previous_page %}
-</p>
\ No newline at end of file
diff --git a/prawokultury/templates/share.html b/prawokultury/templates/share.html
deleted file mode 100755 (executable)
index 71b2c0e..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-{% load i18n common_tags static %}
-{% with encoded_url=url|build_absolute_uri:request|urlencode encoded_desc=description|urlencode %}
-<a rel="nofollow" target="_blank" class="facebook"
-    href="https://www.facebook.com/sharer.php?u={{ encoded_url }}"
-    title="{% trans 'Share on Facebook' %}">
-    <img src="{% static "img/social/"|add:iconset|add:"facebook.png" %}"
-        alt="{% trans 'Share on Facebook' %}"></a>
-<a rel="nofollow" target="_blank" class="google"
-    href="https://plus.google.com/share?url={{ encoded_url }}"
-    title="{% trans 'Share on Google+' %}">
-    <img src="{% static "img/social/"|add:iconset|add:"google.png" %}"
-        alt="{% trans 'Share on Google+' %}"></a>
-<a rel="nofollow" target="_blank" class="twitter"
-    href="https://twitter.com/intent/tweet?url={{ encoded_url }}&amp;text={{ encoded_desc }}"
-    title="{% trans 'Share on Twitter' %}">
-    <img src="{% static "img/social/"|add:iconset|add:"twitter.png" %}"
-        alt="{% trans 'Share on Twitter' %}"></a>
-<a rel="nofollow" target="_blank" class="nk"
-    href="http://nk.pl/#sledzik?shout={{ encoded_desc }}%20{{ encoded_url }}"
-    title="{% trans 'Share on NK.pl' %}">
-    <img src="{% static "img/social/"|add:iconset|add:"nk.png" %}"
-        alt="{% trans 'Share on NK.pl' %}"></a>
-{% comment %}
-<a rel="nofollow" target="_blank" class="diaspora"
-    href="http://sharetodiaspora.github.com/?title={{ encoded_desc }}&amp;url={{ encoded_url }}"
-    title="{% trans 'Share on Diaspora' %}">
-    <img src="{% static "img/social/"|add:iconset|add:"diaspora.png" %}"
-        alt="{% trans 'Share on Diaspora' %}"></a>
-<a rel="nofollow" target="_blank" class="blip"
-    href="http://blip.pl/dashboard?body={{ encoded_desc }}%20{{ encoded_url }}"
-    title="{% trans 'Share on Blip.pl' %}">
-    <img src="{% static "img/social/"|add:iconset|add:"blip.png" %}"
-        alt="{% trans 'Share on Blip.pl' %}"></a>
-{% endcomment %}
-{% endwith %}
\ No newline at end of file
diff --git a/prawokultury/templatetags/__init__.py b/prawokultury/templatetags/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/prawokultury/templatetags/common_tags.py b/prawokultury/templatetags/common_tags.py
deleted file mode 100755 (executable)
index ccaf03b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-from django import template
-register = template.Library()
-
-
-@register.filter
-def build_absolute_uri(uri, request):
-    return request.build_absolute_uri(uri)
diff --git a/prawokultury/templatetags/markup_tags.py b/prawokultury/templatetags/markup_tags.py
deleted file mode 100644 (file)
index 9f1117e..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- coding: utf-8 -*-
-# This file is part of PrawoKultury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django import template
-from django.utils.safestring import mark_safe
-from prawokultury import helpers
-
-register = template.Library()
-
-
-@register.filter
-def textile_pl(node):
-    return mark_safe(helpers.textile_pl(node))
-
-@register.filter
-def textile_restricted_pl(node):
-    return mark_safe(helpers.textile_restricted_pl(node))
diff --git a/prawokultury/templatetags/prevnext.py b/prawokultury/templatetags/prevnext.py
deleted file mode 100755 (executable)
index ec067e7..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-from django.template import Library
-
-register = Library()
-
-
-@register.inclusion_tag('prevnext/previous.html', takes_context=True)
-def previous_page(context, fallback=None, fallback_title=None):
-    current = context['page_obj'].number
-    if current > 1:
-        return {'number': current - 1, 'title': None, 'url': None}
-    else:
-        return {'number': None, 'title': fallback_title, 'url': fallback}
-
-
-@register.inclusion_tag('prevnext/next.html', takes_context=True)
-def next_page(context, fallback=None, fallback_title=None):
-    current = context['page_obj'].number
-    page_range = context['paginator'].page_range
-    if current < page_range[-1]:
-        return {'number': current + 1, 'title': None, 'url': None}
-    else:
-        return {'number': None, 'title': fallback_title, 'url': fallback}
-
-
-@register.inclusion_tag('prevnext/prevnext.html', takes_context=True)
-def prevnext(context):
-    return context
diff --git a/prawokultury/templatetags/share.py b/prawokultury/templatetags/share.py
deleted file mode 100755 (executable)
index ba9a69b..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-from django.template import Library
-
-register = Library()
-
-
-@register.inclusion_tag('share.html', takes_context=True)
-def share(context, url, description, iconset=""):
-    return {
-        'url': url,
-        'description': description,
-        'iconset': iconset,
-        'request': context['request'],
-    }
index 7ba9209..049edac 100644 (file)
@@ -6,10 +6,10 @@ from django.conf import settings
 from django.conf.urls import patterns, include, url
 from django.contrib import admin
 from django.contrib.staticfiles.urls import staticfiles_urlpatterns
-from migdal.helpers import i18n_patterns
-from migdal.urls import urlpatterns as migdal_urlpatterns
 from django.utils.translation import ugettext_lazy as _, string_concat
+from fnpdjango.utils.urls import i18n_patterns
 from events.urls import urlpatterns as events_urlpatterns
+from migdal.urls import urlpatterns as migdal_urlpatterns
 
 admin.autodiscover()
 
diff --git a/realip_middleware.py b/realip_middleware.py
deleted file mode 100755 (executable)
index 9f97b7f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-class SetRemoteAddrFromXRealIP(object):
-    """Sets REMOTE_ADDR from the X-Real-IP header, as set by Nginx."""
-    def process_request(self, request):
-        try:
-            request.META['REMOTE_ADDR'] = request.META['HTTP_X_REAL_IP']
-        except KeyError:
-            return None