Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Pootle-2.0.0/local_apps/pootle_misc
diff options
context:
space:
mode:
Diffstat (limited to 'Pootle-2.0.0/local_apps/pootle_misc')
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/__init__.py0
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/baseurl.py48
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/context_processors.py26
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/dbinit.py161
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/middleware/__init__.py0
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/middleware/baseurl.py48
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/middleware/errorpages.py73
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/middleware/siteconfig.py72
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/siteconfig.py51
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/templatetags/__init__.py0
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/templatetags/baseurl.py29
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/templatetags/cleanhtml.py38
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/templatetags/render_pager.py56
-rw-r--r--Pootle-2.0.0/local_apps/pootle_misc/util.py52
14 files changed, 654 insertions, 0 deletions
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/__init__.py b/Pootle-2.0.0/local_apps/pootle_misc/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/__init__.py
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/baseurl.py b/Pootle-2.0.0/local_apps/pootle_misc/baseurl.py
new file mode 100644
index 0000000..fa2e2b2
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/baseurl.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008-2009 Zuza Software Foundation
+#
+# This file is part of Pootle.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+""" utility functions to help deploy Pootle under different url prefixes """
+
+import urllib
+
+from django.conf import settings
+from django.http import HttpResponseRedirect
+
+def l(path):
+ """ filter urls adding base_path prefix if required """
+ if path and path.startswith('/'):
+ base_url = getattr(settings, "SCRIPT_NAME", "")
+ #if not path.startswith(base_url):
+ return base_url + path
+ return path
+
+def abs_l(path):
+ """ filter paths adding full url prefix if required """
+ return settings.BASE_URL + path
+
+def m(path):
+ """ filter urls adding media url prefix if required """
+ return l(settings.MEDIA_URL + path)
+
+def redirect(url, **kwargs):
+ if len(kwargs) > 0:
+ return HttpResponseRedirect(l('%s?%s' % (url, urllib.urlencode(kwargs))))
+ else:
+ return HttpResponseRedirect(l(url))
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/context_processors.py b/Pootle-2.0.0/local_apps/pootle_misc/context_processors.py
new file mode 100644
index 0000000..290a539
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/context_processors.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2009 Zuza Software Foundation
+#
+# This file is part of Pootle.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+from django.conf import settings
+
+def sitesettings(request):
+ """exposes settings to templates"""
+ #FIXME: maybe we should expose relevant settings only?
+ return {'settings': settings }
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/dbinit.py b/Pootle-2.0.0/local_apps/pootle_misc/dbinit.py
new file mode 100644
index 0000000..94b0893
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/dbinit.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008-2009 Zuza Software Foundation
+#
+# This file is part of Pootle.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+import sys
+
+from django.core.management import call_command
+from django.core.exceptions import ObjectDoesNotExist
+from django.contrib.auth.models import User
+
+from pootle.i18n.gettext import ugettext as _
+
+from pootle_app.models import Language, Project
+
+
+def header(exception):
+ text = """
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html>
+ <head>
+ <title>%(title)s</title>
+ <meta content="text/html; charset=utf-8" http-equiv="content-type" />
+ <style type="text/css">
+ body
+ {
+ background-color: #ffffff;
+ color: #000000;
+ font-family: Georgia, serif;
+ margin: 40px auto;
+ width: 740px;
+ }
+ h1
+ {
+ font-size: 185%%;
+ }
+ ul
+ {
+ list-style-type: square;
+ }
+ .error
+ {
+ background-color: inherit;
+ color: #d54e21;
+ font-weight: bold;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>%(title)s</h1>
+ <p class="error">%(msg)s</p>
+ """ % {'title': _('Pootle: Install'),
+ 'msg': _('Error: "%s" while attempting to access the Pootle database, will try to initialize database.', exception)}
+ return text
+
+def syncdb():
+ text = u"""
+ <p>%s</p>
+ """ % _('Creating database tables...')
+ call_command('syncdb', interactive=False)
+ return text
+
+def initdb():
+ text = u"""
+ <p>%s</p>
+ """ % _('Creating default languages, projects and admin user')
+ call_command('initdb')
+ return text
+
+def stats_start():
+ text = u"""
+ <p>%s</p>
+ <ul>
+ """ % _('Calculating translation statistics, this will take a few minutes')
+ return text
+
+def stats_language(language):
+ text = u"""
+ <li>%s</li>
+ """ % _('%(language)s is %(percent)d%% complete',
+ {'language': language.localname(), 'percent': language.translated_percentage()})
+ return text
+
+def stats_project(project):
+ text = u"""
+ <li>%s</li>
+ """ % _('Project %(project)s is %(percent)d%% complete',
+ {'project': project.fullname, 'percent': project.translated_percentage()})
+ return text
+
+def stats_end():
+ text = u"""
+ </ul>
+ <p>%s</p>
+ """ % _('Done calculating statistics for default languages and projects')
+ return text
+
+
+def footer():
+ text = """
+ <p>%(endmsg)s</p>
+ <div><script>setTimeout("location.reload()", 10000)</script></div>
+ </body></html>
+ """ % { 'endmsg': _('Initialized database, you will be redirected to the front page in 10 seconds') }
+ return text
+
+def staggered_install(exception):
+ """Initialize the pootle database without displaying progress
+ reports for each step"""
+
+ # django's syncdb command prints progress repots to stdout, but
+ # mod_wsgi doesn't like stdout, so we reroute to stderr
+ stdout = sys.stdout
+ sys.stdout = sys.stderr
+
+ yield header(exception)
+
+ # try to build the database tables
+ yield syncdb()
+
+ # if this is a fresh install we should add some default languages
+ # and projects and a default admin account to make pootle more
+ # usable out of the box
+ #
+ # if there are no user accounts apart from defaults then assume
+ # it's fresh install
+ if User.objects.hide_defaults().count() == 0:
+ yield initdb()
+
+ # first time to visit the front page all stats for projects and
+ # languages will be calculated which can take forever, since users
+ # don't like webpages that take forever let's precalculate the
+ # stats here
+ yield stats_start()
+ for language in Language.objects.all():
+ yield stats_language(language)
+ for project in Project.objects.all():
+ yield stats_project(project)
+ yield stats_end()
+
+ yield footer()
+
+ # bring back stdout
+ sys.stdout = stdout
+ return
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/middleware/__init__.py b/Pootle-2.0.0/local_apps/pootle_misc/middleware/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/middleware/__init__.py
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/middleware/baseurl.py b/Pootle-2.0.0/local_apps/pootle_misc/middleware/baseurl.py
new file mode 100644
index 0000000..a5c6640
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/middleware/baseurl.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008-2009 Zuza Software Foundation
+#
+# This file is part of Pootle.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+from django.conf import settings
+
+class BaseUrlMiddleware(object):
+ def process_request(self, request):
+ """calculate settings.BASEURL based on HTTP headers"""
+ domain = None
+
+ if 'HTTP_HOST' in request.META:
+ domain = request.META['HTTP_HOST']
+
+ if 'SCRIPT_NAME' in request.META:
+ settings.SCRIPT_NAME = request.META['SCRIPT_NAME']
+ if domain is not None:
+ domain += request.META['SCRIPT_NAME']
+
+ if domain is not None:
+ if request.is_secure():
+ settings.BASE_URL = 'https://' + domain
+ else:
+ settings.BASE_URL = 'http://' + domain
+
+ #FIXME: DIRTY HACK ALERT if this works then something is
+ #wrong with the universe
+ # poison sites cache using detected domain
+ from django.contrib.sites import models as sites_models
+ sites_models.SITE_CACHE[settings.SITE_ID] = sites_models.Site(settings.SITE_ID,
+ request.META['HTTP_HOST'],
+ settings.TITLE)
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/middleware/errorpages.py b/Pootle-2.0.0/local_apps/pootle_misc/middleware/errorpages.py
new file mode 100644
index 0000000..e165e1e
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/middleware/errorpages.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008-2009 Zuza Software Foundation
+#
+# This file is part of Pootle.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+import traceback
+import sys
+
+from django.core.exceptions import PermissionDenied
+from django.http import HttpResponseForbidden, HttpResponseServerError
+from django.http import Http404
+from django.template.loader import render_to_string
+from django.template import RequestContext
+from django.utils.translation import ugettext as _
+from django.conf import settings
+from django.core.mail import mail_admins
+
+from pootle_misc.baseurl import l
+
+class ErrorPagesMiddleware(object):
+ """
+ Friendlier Error Pages
+ """
+ def process_exception(self, request, exception):
+ if isinstance(exception, Http404):
+ pass
+ elif isinstance(exception, PermissionDenied):
+ templatevars = { 'permission_error': unicode(exception.args[0]) }
+ if not request.user.is_authenticated():
+ login_msg = _('You need to <a href="%(login_link)s">login</a> to access this page.' % {
+ 'login_link': l("/accounts/login/") })
+ templatevars["login_message"] = login_msg
+ return HttpResponseForbidden(render_to_string('403.html', templatevars,
+ RequestContext(request)))
+ else:
+ #FIXME: implement better 500
+ tb = traceback.format_exc()
+ print >> sys.stderr, tb
+ if not settings.DEBUG:
+ try:
+ templatevars = {'exception': unicode(exception.args[0])}
+ if hasattr(exception, 'filename'):
+ templatevars['fserror'] = _('Error accessing %(filename)s, Filesystem sent error: %(errormsg)s',
+ {'filename': exception.filename, 'errormsg': exception.strerror})
+
+ # send email to admins with details about exception
+ subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path)
+ try:
+ request_repr = repr(request)
+ except:
+ request_repr = "Request repr() unavailable"
+ message = "%s\n\n%s\n\n%s" % (unicode(exception.args[0]), tb, request_repr)
+ mail_admins(subject, message, fail_silently=True)
+ return HttpResponseServerError(render_to_string('500.html', templatevars,
+ RequestContext(request)))
+ except:
+ # let's not confuse things by throwing an exception here
+ pass
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/middleware/siteconfig.py b/Pootle-2.0.0/local_apps/pootle_misc/middleware/siteconfig.py
new file mode 100644
index 0000000..7db632b
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/middleware/siteconfig.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008-2009 Zuza Software Foundation
+#
+# This file is part of Pootle.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+from django.http import HttpResponse
+from pootle_misc import siteconfig
+from pootle_misc import dbinit
+
+"""some unused http status code to mark the need to auto install"""
+
+INSTALL_STATUS_CODE = 613
+class SiteConfigMiddleware(object):
+ """
+ This middleware does two things, it reload djblet siteconfigs on
+ every request to ensure they're uptodate. but also works as an
+ early detection system for database errors.
+
+ It might seem strange that the middleware does these two unrelated
+ tasks, but since the only way to test the database is to run a
+ query, it would be too wasteful to add another query per request
+ when siteconfig already requires one.
+
+ """
+ def process_request(self, request):
+ """load site config, return a dummy response if database seems uninitialized"""
+ #FIXME: can't we find a more efficient method?
+ try:
+ siteconfig.load_site_config()
+ except Exception, e:
+ #HACKISH: since exceptions thrown by different databases
+ # do not share the same class heirarchy (DBAPI2 sucks) we
+ # have to check the class name instead (since python uses
+ # duck typing I will call this
+ # poking-the-duck-until-it-quacks-like-a-duck-test
+
+ if e.__class__.__name__ in ['OperationalError', 'ProgrammingError']:
+ # we can't build the database here cause caching
+ # middleware won't allow progressive loading of
+ # response so instead return an empty response marked
+ # with special status code INSTALL_STATUS_CODE
+
+ response = HttpResponse()
+ response.status_code = INSTALL_STATUS_CODE
+ response.exception = e
+ return response
+
+ def process_response(self, request, response):
+ """ this should be the last response processor to run, detect
+ dummy response with INSTALL_STATUS_CODE status code and start
+ db install process"""
+
+ if response.status_code == INSTALL_STATUS_CODE:
+ return HttpResponse(dbinit.staggered_install(response.exception))
+ else:
+ return response
+
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/siteconfig.py b/Pootle-2.0.0/local_apps/pootle_misc/siteconfig.py
new file mode 100644
index 0000000..3d4f9ea
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/siteconfig.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2004-2009 Zuza Software Foundation
+#
+# This file is part of Pootle.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+# NOTE: Import this file in your urls.py or some place before
+# any code relying on settings is imported.
+
+from django.contrib.sites.models import Site
+
+from djblets.siteconfig.models import SiteConfiguration
+from djblets.siteconfig.django_settings import apply_django_settings, generate_defaults
+
+settings_map = {
+ # siteconfig key settings.py key
+ 'DESCRIPTION': 'DESCRIPTION',
+ 'TITLE' : 'TITLE',
+}
+
+defaults = generate_defaults(settings_map)
+
+def load_site_config():
+ """Sets up the SiteConfiguration, provides defaults and syncs settings."""
+ try:
+ siteconfig = SiteConfiguration.objects.get_current()
+ except SiteConfiguration.DoesNotExist:
+ # Either warn or just create the thing. Depends on your app
+ siteconfig = SiteConfiguration(site=Site.objects.get_current(),
+ version="1.0")
+ siteconfig.save()
+
+ # Code will go here for settings work in later examples.
+ if not siteconfig.get_defaults():
+ siteconfig.add_defaults(defaults)
+ apply_django_settings(siteconfig, settings_map)
+ return siteconfig
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/templatetags/__init__.py b/Pootle-2.0.0/local_apps/pootle_misc/templatetags/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/templatetags/__init__.py
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/templatetags/baseurl.py b/Pootle-2.0.0/local_apps/pootle_misc/templatetags/baseurl.py
new file mode 100644
index 0000000..877fb72
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/templatetags/baseurl.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008-2009 Zuza Software Foundation
+#
+# This file is part of Pootle.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+from django import template
+from django.template.defaultfilters import stringfilter
+
+from pootle_misc.baseurl import l, m, abs_l
+
+register = template.Library()
+register.filter('l', stringfilter(l))
+register.filter('m', stringfilter(m))
+register.filter('abs_l', stringfilter(abs_l))
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/templatetags/cleanhtml.py b/Pootle-2.0.0/local_apps/pootle_misc/templatetags/cleanhtml.py
new file mode 100644
index 0000000..40d9e60
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/templatetags/cleanhtml.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008-2009 Zuza Software Foundation
+#
+# This file is part of Pootle.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+
+from django import template
+from django.template.defaultfilters import stringfilter
+from django.utils.safestring import mark_safe
+
+try:
+ from lxml.html.clean import clean_html
+except ImportError:
+ clean_html = lambda text: text
+
+def clean_wrapper(text):
+ """wrapper around lxml's html cleaner that returns SafeStrings for
+ immediate rendering in templates"""
+ return mark_safe(clean_html(text))
+
+register = template.Library()
+register.filter('clean', stringfilter(clean_wrapper))
+
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/templatetags/render_pager.py b/Pootle-2.0.0/local_apps/pootle_misc/templatetags/render_pager.py
new file mode 100644
index 0000000..86961b6
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/templatetags/render_pager.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008-2009 Zuza Software Foundation
+#
+# This file is part of Pootle.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+from django.utils.translation import ugettext as _
+from django import template
+from django.utils.safestring import mark_safe
+
+def render_pager(pager):
+ """Render a pager block with next and previous links"""
+ if not pager.has_other_pages():
+ return ""
+
+ result = '<ul class="pager">'
+ if pager.has_previous():
+ result += '<li><a href="?page=1" class="nth-link">%s</a></li>' % _('First')
+ result += '<li><a href="?page=%d" class="prevnext-link">%s</a></li>' % (pager.previous_page_number(), _('Previous'))
+
+ start = max(1, pager.number - 4)
+ end = min(pager.paginator.num_pages, pager.number + 4)
+ if start > 1:
+ result += '<li>...</li>'
+ for i in range(start, end+1):
+ if i == pager.number:
+ result += '<li><span class="current-link">%s</span></li>' % i
+ else:
+ result += '<li><a href="?page=%d" class="number-link">%d</a></li>' % (i, i)
+ if end < pager.paginator.num_pages:
+ result += '<li>...</li>'
+
+ if pager.has_next():
+ result += '<li><a href="?page=%d" class="prevnext-link">%s</a></li>' % (pager.next_page_number(), _('Next'))
+ result += '<li><a href="?page=%d" class="nth-link">%s</a></li>' % (pager.paginator.num_pages, _('Last'))
+
+ result += '</ul>'
+ return mark_safe(result)
+
+register = template.Library()
+register.filter('render_pager', render_pager)
+
diff --git a/Pootle-2.0.0/local_apps/pootle_misc/util.py b/Pootle-2.0.0/local_apps/pootle_misc/util.py
new file mode 100644
index 0000000..11b5c44
--- /dev/null
+++ b/Pootle-2.0.0/local_apps/pootle_misc/util.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2004-2009 Zuza Software Foundation
+#
+# This file is part of Pootle.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+from django.core.cache import cache
+from django.conf import settings
+import logging
+
+def getfromcache(function, timeout=settings.OBJECT_CACHE_TIMEOUT):
+ def _getfromcache(instance, *args, **kwargs):
+ key = instance.pootle_path + ":" + function.__name__
+ result = cache.get(key)
+ if result is None:
+ logging.debug("cache miss for %s", key)
+ result = function(instance, *args, **kwargs)
+ cache.set(key, result, timeout)
+ return result
+ return _getfromcache
+
+def deletefromcache(sender, functions, **kwargs):
+ path = sender.pootle_path
+ path_parts = path.split("/")
+
+ # clean project cache
+ if len(path_parts):
+ key = "/projects/%s/" % path_parts[2]
+ for func in functions:
+ cache.delete(key + ":"+func)
+
+ # clean store and directory cache
+ while path_parts:
+ for func in functions:
+ cache.delete(path + ":"+func)
+ path_parts = path_parts[:-1]
+ path = "/".join(path_parts) + "/"
+