byteflow

changeset 968:99f39a118795

WARNING! All applications, which are not necessary (or at least making big sense to be enabled by default) moved to ADDITIONAL_APPS settings.

This is first step on introducing plugin-like applications. It is
backward compatibility breaking changeset and you should be careful
updating your blog.

Previous we've used [APP]_ENABLE settings, they are removed now (there is some
[something]_ENABLE settings, they have nothing common with enabling
applications). Now if you want to enable or disable something, you should add,
remove or comment application name in ADDITIONAL_APPS setting.

Some convenient defaults (list of all additional applications with some of them
commented out) are provided in local_settings.py.template.

There is also small object (lib.appcheck, available by "appcheck" name in
RequestContext) to simplify checking is application enabled or not.
author Alexander Solovyov <piranha@piranha.org.ua>
date Thu Oct 16 23:34:22 2008 +0300 (16 months ago)
parents 3552cd0d34cd
children 9e96b58e0179
files apps/blog/models.py apps/blog/tests.py apps/context_processors.py apps/lib/__init__.py apps/livejournal/admin.py settings.py settings_local.py.template templates/blog/post_detail.html urls.py
line diff
     1.1 --- a/apps/blog/models.py
     1.2 +++ b/apps/blog/models.py
     1.3 @@ -7,6 +7,7 @@ from django.utils.translation import uge
     1.4  from django.utils.html import strip_tags
     1.5  from django.contrib.contenttypes import generic
     1.6  
     1.7 +from lib import appcheck
     1.8  from lib.helpers import reverse
     1.9  from render import render, RENDER_METHODS
    1.10  from blog.managers import PostManager, PublicPostManager, FeaturedPostManager
    1.11 @@ -99,19 +100,20 @@ def pingback_blog_handler(year, month, d
    1.12      return Post.objects.filter(date__range=r).get(slug=slug)
    1.13  
    1.14  ping_details = {'post_detail': pingback_blog_handler}
    1.15 -
    1.16  xmlrpc.dispatcher.register_function(create_ping_func(**ping_details), 'pingback.ping')
    1.17  
    1.18 -if settings.ENABLE_PINGBACK:
    1.19 -    ping_links = ping_external_links(content_attr='html', url_attr='get_absolute_url',
    1.20 -                                     filtr=lambda x: not x.is_draft)
    1.21 +
    1.22 +ping_links = ping_external_links(content_attr='html', url_attr='get_absolute_url',
    1.23 +                                 filtr=lambda x: not x.is_draft)
    1.24 +ping_dirs = ping_directories(content_attr='html', url_attr='get_absolute_url',
    1.25 +                             filtr=lambda x: not x.is_draft)
    1.26 +
    1.27 +if appcheck.pingback:
    1.28      models.signals.post_save.connect(ping_links, sender=Post)
    1.29 -if settings.ENABLE_DIRECTORY_PING:
    1.30 -    ping_dirs = ping_directories(content_attr='html', url_attr='get_absolute_url',
    1.31 -                                 filtr=lambda x: not x.is_draft)
    1.32      models.signals.post_save.connect(ping_dirs, sender=Post)
    1.33  
    1.34 -if 'watchlist' in settings.INSTALLED_APPS:
    1.35 +
    1.36 +if appcheck.watchlist:
    1.37      from watchlist.models import Subscription
    1.38      def subscribe_author(instance, created, **kwargs):
    1.39          if not created:
     2.1 --- a/apps/blog/tests.py
     2.2 +++ b/apps/blog/tests.py
     2.3 @@ -9,6 +9,8 @@ from django.conf import settings
     2.4  from blog.models import Post
     2.5  from discussion.models import CommentNode
     2.6  from lib.helpers import reverse
     2.7 +from lib import appcheck
     2.8 +
     2.9  
    2.10  class PostTestCase(test.TestCase):
    2.11  
    2.12 @@ -61,8 +63,13 @@ class PostTestCase(test.TestCase):
    2.13          response = self.client.post(self.p1.get_absolute_url(),
    2.14                                      {'body': 'completely useless', 'name': 'somethingright',
    2.15                                       'email': 'right@something.com', 'subscribe': True})
    2.16 -        # Expect a registrations and notification email to be sent
    2.17 -        self.assertEquals(len(mail.outbox), 3)
    2.18 +        if not appcheck.watchlist:
    2.19 +            # Expect a registrations and notification email to be sent
    2.20 +            mailcount = 3
    2.21 +        else:
    2.22 +            # Additionally two notification for comment author
    2.23 +            mailcount = 5
    2.24 +        self.assertEquals(len(mail.outbox), mailcount)
    2.25  
    2.26      def testDeleteComments(self):
    2.27          c = CommentNode(approved=False, body="just test", user=self.user, object=self.p1)
     3.1 --- a/apps/context_processors.py
     3.2 +++ b/apps/context_processors.py
     3.3 @@ -4,11 +4,14 @@ from django.conf import settings
     3.4  from django.contrib.sites.models import Site
     3.5  from blog.models import Post
     3.6  
     3.7 +from lib import appcheck
     3.8 +
     3.9  def settings_vars(request):
    3.10      return {
    3.11          'STATIC_URL': settings.STATIC_URL,
    3.12          'THEME_STATIC_URL': settings.THEME_STATIC_URL,
    3.13          'settings': settings,
    3.14 +        'appcheck': appcheck,
    3.15          }
    3.16  
    3.17  def featured_posts(request):
     4.1 --- a/apps/lib/__init__.py
     4.2 +++ b/apps/lib/__init__.py
     4.3 @@ -0,0 +1,8 @@
     4.4 +from django.conf import settings
     4.5 +
     4.6 +
     4.7 +class ApplicationChecker(object):
     4.8 +    "Checks if application is enabled"
     4.9 +    def __getattr__(self, attr):
    4.10 +        return attr in settings.INSTALLED_APPS
    4.11 +appcheck = ApplicationChecker()
     5.1 --- a/apps/livejournal/admin.py
     5.2 +++ b/apps/livejournal/admin.py
     5.3 @@ -4,7 +4,8 @@ from django.conf import settings
     5.4  
     5.5  from livejournal.models import LiveJournalPost
     5.6  from livejournal.utils import lj_crosspost, lj_delete
     5.7 -
     5.8 +from blog.models import Post
     5.9 +from blog.admin import PostAdmin
    5.10  
    5.11  class LiveJournalPostAdmin(admin.ModelAdmin):
    5.12      list_display = ('post', 'need_crosspost')
    5.13 @@ -12,15 +13,14 @@ class LiveJournalPostAdmin(admin.ModelAd
    5.14  admin.site.register(LiveJournalPost, LiveJournalPostAdmin)
    5.15  
    5.16  
    5.17 -if settings.ENABLE_LJ_CROSSPOST:
    5.18 -    from blog.models import Post
    5.19 -    from blog.admin import PostAdmin
    5.20 -    class LiveJournalPostInlineAdmin(admin.TabularInline):
    5.21 -        model = LiveJournalPost
    5.22 -        max_num = 1
    5.23 -    PostAdmin.list_display += ('lj_object', )
    5.24 -    pa = admin.site._registry[Post]
    5.25 -    pa.inline_instances.append(
    5.26 -        LiveJournalPostInlineAdmin(pa.model, pa.admin_site))
    5.27 -    models.signals.pre_save.connect(lj_crosspost, sender=LiveJournalPost)
    5.28 -    models.signals.pre_delete.connect(lj_delete, sender=LiveJournalPost)
    5.29 +class LiveJournalPostInlineAdmin(admin.TabularInline):
    5.30 +    model = LiveJournalPost
    5.31 +    max_num = 1
    5.32 +
    5.33 +PostAdmin.list_display += ('lj_object', )
    5.34 +
    5.35 +pa = admin.site._registry[Post]
    5.36 +pa.inline_instances.append(LiveJournalPostInlineAdmin(pa.model, pa.admin_site))
    5.37 +
    5.38 +models.signals.pre_save.connect(lj_crosspost, sender=LiveJournalPost)
    5.39 +models.signals.pre_delete.connect(lj_delete, sender=LiveJournalPost)
     6.1 --- a/settings.py
     6.2 +++ b/settings.py
     6.3 @@ -124,6 +124,8 @@ TEMPLATE_DIRS = (
     6.4      os.path.join(PROJECT_ROOT, 'templates'),
     6.5  )
     6.6  
     6.7 +# Here are included application necessary for work
     6.8 +# All other should go to the ADDITIONAL_APPS
     6.9  INSTALLED_APPS = (
    6.10      'django.contrib.auth',
    6.11      'django.contrib.contenttypes',
    6.12 @@ -136,23 +138,14 @@ INSTALLED_APPS = (
    6.13      'lib',
    6.14      'pytils',
    6.15      'accounts',
    6.16 +    'blog',
    6.17      'discussion',
    6.18 -    'blog',
    6.19 -    'pingback',
    6.20 -    'openidconsumer',
    6.21      'tagging',
    6.22      'typogrify',
    6.23 -    'livejournal',
    6.24      'render',
    6.25 -    'robots',
    6.26 -    'textblocks',
    6.27 -    'blogroll',
    6.28 +    'postimage',
    6.29 +    'openidconsumer',
    6.30      'openidserver',
    6.31 -    'recaptcha',
    6.32 -    'debug',
    6.33 -    'sape',
    6.34 -    'watchlist',
    6.35 -    'postimage',
    6.36  )
    6.37  
    6.38  APPEND_SLASH = False
    6.39 @@ -177,14 +170,11 @@ OPENID_WITH_AUTH = True
    6.40  OPENID_REDIRECT_NEXT = '/'
    6.41  
    6.42  # Pingback
    6.43 -ENABLE_PINGBACK = True
    6.44  PINGBACK_SERVER = {
    6.45      'post_detail': 'pingback.getters.post_get',
    6.46      }
    6.47  PINGBACK_RESPONSE_LENGTH = 200
    6.48  
    6.49 -# Blogs directory ping
    6.50 -ENABLE_DIRECTORY_PING = False
    6.51  # TODO: move this list to DB
    6.52  DIRECTORY_URLS = (
    6.53      'http://ping.blogs.yandex.ru/RPC2',
    6.54 @@ -239,14 +229,10 @@ except ImportError:
    6.55      sys.stderr.write('Unable to read settings_local.py\n')
    6.56      sys.exit(1)
    6.57  
    6.58 -if ENABLE_IMPORT:
    6.59 -    INSTALLED_APPS += ('wpimport', )
    6.60 -
    6.61 -#if ENABLE_SAPE:
    6.62 -    #INSTALLED_APPS += ('sape', )
    6.63 -
    6.64 -if 'ADDITIONAL_APPS' in locals():
    6.65 -    INSTALLED_APPS = INSTALLED_APPS + locals()['ADDITIONAL_APPS']
    6.66 +try:
    6.67 +    INSTALLED_APPS += ADDITIONAL_APPS
    6.68 +except NameError:
    6.69 +    pass
    6.70  
    6.71  LOCALE_PATHS = (os.path.join(PROJECT_ROOT, 'locale'), )
    6.72  THEME_STATIC_URL = os.path.join(STATIC_URL, THEME + '/')
     7.1 --- a/settings_local.py.template
     7.2 +++ b/settings_local.py.template
     7.3 @@ -37,8 +37,6 @@ CAPTCHA='simple'
     7.4  RECAPTCHA_PUBLIC_KEY = ''
     7.5  RECAPTCHA_PRIVATE_KEY =''
     7.6  
     7.7 -ENABLE_SAPE = False # Set this to true to enable Sape.ru client
     7.8 -ENABLE_IMPORT = False # Set this to true to enable WordPress importer
     7.9  GA_ACC = '' # Google Analytics account
    7.10  LI_ACC = False # Set True if you want liveinternet.ru counter
    7.11  GRAVATAR_ENABLE = False # Enable gravatars?
    7.12 @@ -62,10 +60,22 @@ FEEDBURNER = {}
    7.13  ORM_DEBUG = False
    7.14  
    7.15  # Livejournal crossposting
    7.16 -ENABLE_LJ_CROSSPOST = False
    7.17  LJ_USERNAME = ''
    7.18  LJ_PASSWORD = ''
    7.19  
    7.20 +ADDITIONAL_APPS = (
    7.21 +    'recaptcha',
    7.22 +    'pingback',
    7.23 +    'watchlist',   # comments subscription
    7.24 +    'blogroll',
    7.25 +    'robots',
    7.26 +#    'debug',       # debug sql query
    7.27 +#    'livejournal', # livejournal crossposting
    7.28 +#    'textblocks',
    7.29 +#    'wpimport',
    7.30 +#    'sape',        # sape.ru
    7.31 +    )
    7.32 +
    7.33  # DEBUG must be False in production mode
    7.34  # Please read http://byteflow.su/wiki/DEBUG
    7.35  DEBUG = False
     8.1 --- a/templates/blog/post_detail.html
     8.2 +++ b/templates/blog/post_detail.html
     8.3 @@ -18,7 +18,7 @@
     8.4  {% theme_js "ajaxforms" %}
     8.5  {% ifequal settings.CAPTCHA "recaptcha" %}<script type="text/javascript" src="http://api.recaptcha.net/js/recaptcha_ajax.js"></script>{% endifequal %}
     8.6  <link rel="alternate" type="application/rss+xml" title="{{ settings.BLOG_NAME }}: comments on {{ object.name }} feed" href="{% url feed feedurl %}" />
     8.7 -<link rel="pingback" href="http://{{ site.domain }}{% url xmlrpc %}" />
     8.8 +{% if appcheck.pingback %}<link rel="pingback" href="http://{{ site.domain }}{% url xmlrpc %}" />{% endif %}
     8.9  {% endblock %}
    8.10  
    8.11  {% block content %}
     9.1 --- a/urls.py
     9.2 +++ b/urls.py
     9.3 @@ -13,13 +13,13 @@ from blog.sitemaps import BlogSitemap, I
     9.4  from tagging.models import Tag
     9.5  import watchlist.mail
     9.6  import patches
     9.7 +from lib import appcheck
     9.8  
     9.9  def error500(request, template_name='500.html'):
    9.10      try:
    9.11          output = render_to_string(template_name, {}, RequestContext(request))
    9.12      except:
    9.13          output = "Critical error. Administrator was notified."
    9.14 -    #render_to_string(template_name, {}, Context())
    9.15      return HttpResponseServerError(output)
    9.16  
    9.17  handler500 = 'urls.error500'
    9.18 @@ -65,25 +65,16 @@ if settings.SET_URL_ROOT_HANDLER:
    9.19  if settings.DEBUG:
    9.20      urlpatterns += patterns(
    9.21          '',
    9.22 -        url(r'^media/(.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
    9.23 -        url(r'^static/(.*)$', 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),
    9.24 -        url(r'^admin-media/(.*)$', 'django.views.static.serve', {'document_root': join(dirname(admin.__file__), 'media')}),
    9.25 +        url(r'^media/(.*)$', 'django.views.static.serve',
    9.26 +            {'document_root': settings.MEDIA_ROOT}),
    9.27 +        url(r'^static/(.*)$', 'django.views.static.serve',
    9.28 +            {'document_root': settings.STATIC_ROOT}),
    9.29 +        url(r'^admin-media/(.*)$', 'django.views.static.serve',
    9.30 +            {'document_root': join(dirname(admin.__file__), 'media')}),
    9.31          )
    9.32  
    9.33 -if 'wpimport' in settings.INSTALLED_APPS:
    9.34 -    urlpatterns += patterns(
    9.35 -        '',
    9.36 -        url(r'^wpimport/', include('wpimport.urls')),
    9.37 -        )
    9.38 +if appcheck.wpimport:
    9.39 +    urlpatterns += patterns('', url(r'^wpimport/', include('wpimport.urls')),)
    9.40  
    9.41 -if 'wbimport' in settings.INSTALLED_APPS:
    9.42 -    urlpatterns += patterns(
    9.43 -        '',
    9.44 -        url(r'^wbimport/', include('wbimport.urls')),
    9.45 -        )
    9.46 -
    9.47 -if 'debug' in settings.INSTALLED_APPS:
    9.48 -    urlpatterns += patterns(
    9.49 -        '',
    9.50 -        url('', include('debug.urls')),
    9.51 -        )
    9.52 +if appcheck.debug:
    9.53 +    urlpatterns += patterns('', url('', include('debug.urls')),)
Repositories maintained by Alexander Solovyov