expanded range of supported versions of django and added patches for csrf_token

This commit is contained in:
Evgeny Fadeev 2011-03-28 23:03:16 -04:00
parent 8ae8fcdc85
commit 96a9863db2
19 changed files with 543 additions and 71 deletions

View File

@ -6,7 +6,17 @@ basic actions on behalf of the forum application
"""
import os
import smtplib
import sys
import logging
from askbot import patches
from askbot.deployment.assertions import assert_package_compatibility
VERSION = (0, 6, 75)
#necessary for interoperability of django and coffin
assert_package_compatibility()
patches.patch_django()
patches.patch_coffin()#must go after django
def get_install_directory():
"""returns path to directory
@ -15,8 +25,9 @@ def get_install_directory():
"""
return os.path.dirname(__file__)
def get_version():
"""returns version of the askbot app
this version is meaningful for pypi only
"""
return '0.6.74'
return '.'.join([str(subversion) for subversion in VERSION])

View File

@ -0,0 +1,26 @@
"""assertions regarding deployment of askbot
todo: move here stuff from startup_procedures.py
the reason - some assertions need to be run in askbot/__init__
as opposed to startup_procedures.py - which are executed in the
beginning of the models module
"""
from askbot.deployment import package_utils
from askbot.exceptions import DeploymentError
def assert_package_compatibility():
"""raises an exception if any known incompatibilities
are found
"""
(django_major, django_minor, django_micro) = package_utils.get_django_version()
if django_major < 1:
raise DeploymentError('Django version < 1.0 is not supported by askbot')
coffin_version = package_utils.get_coffin_version()
if coffin_version == (0, 3, 0) and django_major == 1 and django_minor > 1:
raise DeploymentError(
'Coffin package version 0.3 is not compatible '
'with the current version of Django, please upgrade '
'coffin to at least 0.3.3'
)

View File

@ -0,0 +1,28 @@
"""utilities that determine versions of packages
that are part of askbot
versions of all packages are normalized to three-tuples
of integers (missing zeroes added)
"""
import coffin
import django
def get_coffin_version():
"""Returns version of Coffin package
as a three integer value tuple
"""
version = coffin.__version__
if len(version) == 2:
micro_version = 0
elif len(version) == 3:
micro_version = version[2]
else:
raise ValueError('unsupported version of coffin %s' % '.'.join(version))
major_version = version[0]
minor_version = version[1]
return (major_version, minor_version, micro_version)
def get_django_version():
"""returns three-tuple for the version
of django"""
return django.VERSION[:3]

View File

@ -45,7 +45,7 @@ from django.utils.html import escape
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
from django.core.mail import send_mail
from askbot.skins.loaders import ENV
from askbot.skins.loaders import render_into_skin
from askbot.deps.openid.consumer.consumer import Consumer, \
SUCCESS, CANCEL, FAILURE, SETUP_NEEDED
@ -554,9 +554,7 @@ def show_signin_view(
data['major_login_providers'] = major_login_providers.values()
data['minor_login_providers'] = minor_login_providers.values()
template = ENV.get_template('authopenid/signin.html')
context = RequestContext(request, data)
return HttpResponse(template.render(context))
return render_into_skin('authopenid/signin.html', data, request)
@login_required
def delete_login_method(request):
@ -813,7 +811,6 @@ def register(request, login_provider_name=None, user_identifier=None):
provider_logo = providers[login_provider_name]
logging.debug('printing authopenid/complete.html output')
template = ENV.get_template('authopenid/complete.html')
data = {
'openid_register_form': register_form,
'email_feeds_form': email_feeds_form,
@ -823,8 +820,7 @@ def register(request, login_provider_name=None, user_identifier=None):
'login_type':'openid',
'gravatar_faq_url':reverse('faq') + '#gravatar',
}
context = RequestContext(request, data)
return HttpResponse(template.render(context))
return render_into_skin('authopenid/complete.html', data, request)
def signin_failure(request, message):
"""
@ -895,7 +891,7 @@ def signup_with_password(request):
# send email
#subject = _("Welcome email subject line")
#message_template = ENV.get_template(
#message_template = get_emplate(
# 'authopenid/confirm_email.txt'
#)
#message_context = Context({
@ -933,9 +929,11 @@ def signup_with_password(request):
'minor_login_providers': minor_login_providers.values(),
'login_form': login_form
}
template = ENV.get_template('authopenid/signup_with_password.html')
context = RequestContext(request, context_data)
return HttpResponse(template.render(context))
return render_into_skin(
'authopenid/signup_with_password.html',
context_data,
request
)
#what if request is not posted?
@login_required
@ -1003,15 +1001,14 @@ def _send_email_key(user):
to user's email address
"""
subject = _("Recover your %(site)s account") % {'site': askbot_settings.APP_SHORT_NAME}
message_template = ENV.get_template('authopenid/email_validation.txt')
import settings
message_context = Context({
'validation_link': askbot_settings.APP_URL + reverse(
'user_account_recover',
kwargs={'key':user.email_key}
)
})
message = message_template.render(message_context)
data = {
'validation_link': askbot_settings.APP_URL + \
reverse(
'user_account_recover',
kwargs={'key':user.email_key}
)
}
message = render_into_skin('authopenid/email_validation.txt', data)
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email])
def send_new_email_key(user,nomessage=False):
@ -1037,14 +1034,16 @@ def send_email_key(request):
"""
if askbot_settings.EMAIL_VALIDATION == True:
if request.user.email_isvalid:
template = ENV.get_template('authopenid/changeemail.html')
data = {
'email': request.user.email,
'action_type': 'key_not_sent',
'change_link': reverse('user_changeemail')
}
context = RequestContext(request, data)
return HttpResponse(template.render(context))
return render_into_skin(
'authopenid/changeemail.html',
data,
request
)
else:
send_new_email_key(request.user)
return validation_email_sent(request)
@ -1107,14 +1106,12 @@ def validation_email_sent(request):
set to True bolean value, basically dead now"""
assert(askbot_settings.EMAIL_VALIDATION == True)
logging.debug('')
template = ENV.get_template('authopenid/changeemail.html')
data = {
'email': request.user.email,
'change_email_url': reverse('user_changeemail'),
'action_type': 'validate'
}
context = RequestContext(request, data)
return HttpResponse(template.render(context))
return render_into_skin('authopenid/changeemail.html', data, request)
def verifyemail(request,id=None,key=None):
"""
@ -1129,10 +1126,12 @@ def verifyemail(request,id=None,key=None):
user.email_isvalid = True
clear_email_validation_message(user)
user.save()
template = ENV.get_template('authopenid/changeemail.html')
data = {'action_type': 'validation_complete'}
context = RequestContext(request, data)
return HttpResponse(template.render(context))
return render_into_skin(
'authopenid/changeemail.html',
data,
request
)
else:
logging.error('hmm, no user found for email validation message - foul play?')
raise Http404

View File

@ -1,6 +1,10 @@
from django.core import exceptions
from django.utils.translation import ugettext as _
class DeploymentError(exceptions.ImproperlyConfigured):
"""raised when there is some error with deployment"""
pass
class LoginRequired(exceptions.PermissionDenied):
"""raised when an operation required a logged
in user"""

View File

@ -52,6 +52,6 @@ class QuestionsPageSizeMiddleware(object):
#500.html needs RequestContext, while handler500 only receives Context
#need to log some more details about the request
logging.critical(utils.http.get_request_info(request))
from askbot.skins.loaders import ENV
template = ENV.get_template('500.jinja.html')
from askbot.skins.loaders import get_template
template = get_template('500.jinja.html', request)
return HttpResponse(template.render(RequestContext(request)))

View File

@ -2010,8 +2010,8 @@ def send_instant_notifications_about_activity_in_post(
if update_activity.activity_type not in acceptable_types:
return
from askbot.skins.loaders import ENV
template = ENV.get_template('instant_notification.html')
from askbot.skins.loaders import get_template
template = get_template('instant_notification.html')
update_type_map = const.RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES
update_type = update_type_map[update_activity.activity_type]

View File

@ -0,0 +1,28 @@
"""module for monkey patching that is
necessary for interoperability of different
versions of various components used in askbot
"""
import django
from askbot.patches import django_patches
from askbot.deployment import package_utils
def patch_django():
"""earlier versions of Django do not have
csrf token and function called import_library
(the latter is needed by coffin)
"""
(major, minor, micro) = package_utils.get_django_version()
if major == 1 and minor < 2:
django_patches.add_import_library_function()
django_patches.add_csrf_protection()
def patch_coffin():
"""coffin before version 0.3.4
does not have csrf_token template tag.
This patch must be applied after the django patches
"""
from askbot.patches import coffin_patches
(major, minor, micro) = package_utils.get_coffin_version()
if major == 0 and minor == 3 and micro < 4:
coffin_patches.add_csrf_token_tag()

View File

@ -0,0 +1,34 @@
"""patches for the coffin module"""
from jinja2 import nodes
from jinja2 import Markup
from jinja2.ext import Extension
class CsrfTokenExtension(Extension):
"""Jinja2-version of the ``csrf_token`` tag.
Adapted from a snippet by Jason Green:
http://www.djangosnippets.org/snippets/1847/
This tag is a bit stricter than the Django tag in that it doesn't
simply ignore any invalid arguments passed in.
"""
tags = set(['csrf_token'])
def parse(self, parser):
lineno = parser.stream.next().lineno
return nodes.Output([
self.call_method('_render', [nodes.Name('csrf_token', 'load')])
]).set_lineno(lineno)
def _render(self, csrf_token):
from django.template.defaulttags import CsrfTokenNode
return Markup(CsrfTokenNode().render({'csrf_token': csrf_token}))
def add_csrf_token_tag():
"""adds csrf token tag to the default library"""
import coffin.template.defaulttags
coffin.template.defaulttags.CsrfTokenExtension = CsrfTokenExtension
csrf_token = CsrfTokenExtension
coffin.template.defaulttags.csrf_token = csrf_token
coffin.template.defaulttags.register.tag(csrf_token)

View File

@ -0,0 +1,327 @@
"""a module for patching django"""
import imp
import os
import sys
from django.utils.safestring import mark_safe
from django.utils.functional import lazy
from django.template import Node
def module_has_submodule(package, module_name):
"""See if 'module' is in 'package'."""
name = ".".join([package.__name__, module_name])
if name in sys.modules:
return True
for finder in sys.meta_path:
if finder.find_module(name):
return True
for entry in package.__path__: # No __path__, then not a package.
try:
# Try the cached finder.
finder = sys.path_importer_cache[entry]
if finder is None:
# Implicit import machinery should be used.
try:
file_, _, _ = imp.find_module(module_name, [entry])
if file_:
file_.close()
return True
except ImportError:
continue
# Else see if the finder knows of a loader.
elif finder.find_module(name):
return True
else:
continue
except KeyError:
# No cached finder, so try and make one.
for hook in sys.path_hooks:
try:
finder = hook(entry)
# XXX Could cache in sys.path_importer_cache
if finder.find_module(name):
return True
else:
# Once a finder is found, stop the search.
break
except ImportError:
# Continue the search for a finder.
continue
else:
# No finder found.
# Try the implicit import machinery if searching a directory.
if os.path.isdir(entry):
try:
file_, _, _ = imp.find_module(module_name, [entry])
if file_:
file_.close()
return True
except ImportError:
pass
# XXX Could insert None or NullImporter
else:
# Exhausted the search, so the module cannot be found.
return False
class CsrfTokenNode(Node):
def render(self, context):
csrf_token = context.get('csrf_token', None)
if csrf_token:
if csrf_token == 'NOTPROVIDED':
return mark_safe(u"")
else:
return mark_safe(u"<div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='%s' /></div>" % csrf_token)
else:
# It's very probable that the token is missing because of
# misconfiguration, so we raise a warning
from django.conf import settings
if settings.DEBUG:
import warnings
warnings.warn("A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.")
return u''
def get_token(request):
"""
Returns the the CSRF token required for a POST form.
A side effect of calling this function is to make the the csrf_protect
decorator and the CsrfViewMiddleware add a CSRF cookie and a 'Vary: Cookie'
header to the outgoing response. For this reason, you may need to use this
function lazily, as is done by the csrf context processor.
"""
request.META["CSRF_COOKIE_USED"] = True
return request.META.get("CSRF_COOKIE", None)
def csrf(request):
"""
Context processor that provides a CSRF token, or the string 'NOTPROVIDED' if
it has not been provided by either a view decorator or the middleware
"""
def _get_val():
token = get_token(request)
if token is None:
# In order to be able to provide debugging info in the
# case of misconfiguration, we use a sentinel value
# instead of returning an empty dict.
return 'NOTPROVIDED'
else:
return token
_get_val = lazy(_get_val, str)
return {'csrf_token': _get_val() }
"""
Cross Site Request Forgery Middleware.
This module provides a middleware that implements protection
against request forgeries from other sites.
"""
import itertools
import re
import random
from django.conf import settings
from django.core.urlresolvers import get_callable
from django.utils.hashcompat import md5_constructor
from django.utils.safestring import mark_safe
_POST_FORM_RE = \
re.compile(r'(<form\W[^>]*\bmethod\s*=\s*(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE)
_HTML_TYPES = ('text/html', 'application/xhtml+xml')
# Use the system (hardware-based) random number generator if it exists.
if hasattr(random, 'SystemRandom'):
randrange = random.SystemRandom().randrange
else:
randrange = random.randrange
_MAX_CSRF_KEY = 18446744073709551616L # 2 << 63
def _get_failure_view():
"""
Returns the view to be used for CSRF rejections
"""
return get_callable(settings.CSRF_FAILURE_VIEW)
def _get_new_csrf_key():
return md5_constructor("%s%s"
% (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest()
def _make_legacy_session_token(session_id):
return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
class CsrfViewMiddleware(object):
"""
Middleware that requires a present and correct csrfmiddlewaretoken
for POST requests that have a CSRF cookie, and sets an outgoing
CSRF cookie.
This middleware should be used in conjunction with the csrf_token template
tag.
"""
def process_view(self, request, callback, callback_args, callback_kwargs):
if getattr(callback, 'csrf_exempt', False):
return None
if getattr(request, 'csrf_processing_done', False):
return None
reject = lambda s: _get_failure_view()(request, reason=s)
def accept():
# Avoid checking the request twice by adding a custom attribute to
# request. This will be relevant when both decorator and middleware
# are used.
request.csrf_processing_done = True
return None
# If the user doesn't have a CSRF cookie, generate one and store it in the
# request, so it's available to the view. We'll store it in a cookie when
# we reach the response.
try:
request.META["CSRF_COOKIE"] = request.COOKIES[settings.CSRF_COOKIE_NAME]
cookie_is_new = False
except KeyError:
# No cookie, so create one. This will be sent with the next
# response.
request.META["CSRF_COOKIE"] = _get_new_csrf_key()
# Set a flag to allow us to fall back and allow the session id in
# place of a CSRF cookie for this request only.
cookie_is_new = True
if request.method == 'POST':
if getattr(request, '_dont_enforce_csrf_checks', False):
# Mechanism to turn off CSRF checks for test suite. It comes after
# the creation of CSRF cookies, so that everything else continues to
# work exactly the same (e.g. cookies are sent etc), but before the
# any branches that call reject()
return accept()
if request.is_ajax():
# .is_ajax() is based on the presence of X-Requested-With. In
# the context of a browser, this can only be sent if using
# XmlHttpRequest. Browsers implement careful policies for
# XmlHttpRequest:
#
# * Normally, only same-domain requests are allowed.
#
# * Some browsers (e.g. Firefox 3.5 and later) relax this
# carefully:
#
# * if it is a 'simple' GET or POST request (which can
# include no custom headers), it is allowed to be cross
# domain. These requests will not be recognized as AJAX.
#
# * if a 'preflight' check with the server confirms that the
# server is expecting and allows the request, cross domain
# requests even with custom headers are allowed. These
# requests will be recognized as AJAX, but can only get
# through when the developer has specifically opted in to
# allowing the cross-domain POST request.
#
# So in all cases, it is safe to allow these requests through.
return accept()
if request.is_secure():
# Strict referer checking for HTTPS
referer = request.META.get('HTTP_REFERER')
if referer is None:
return reject("Referer checking failed - no Referer.")
# The following check ensures that the referer is HTTPS,
# the domains match and the ports match. This might be too strict.
good_referer = 'https://%s/' % request.get_host()
if not referer.startswith(good_referer):
return reject("Referer checking failed - %s does not match %s." %
(referer, good_referer))
# If the user didn't already have a CSRF cookie, then fall back to
# the Django 1.1 method (hash of session ID), so a request is not
# rejected if the form was sent to the user before upgrading to the
# Django 1.2 method (session independent nonce)
if cookie_is_new:
try:
session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
csrf_token = _make_legacy_session_token(session_id)
except KeyError:
# No CSRF cookie and no session cookie. For POST requests,
# we insist on a CSRF cookie, and in this way we can avoid
# all CSRF attacks, including login CSRF.
return reject("No CSRF or session cookie.")
else:
csrf_token = request.META["CSRF_COOKIE"]
# check incoming token
request_csrf_token = request.POST.get('csrfmiddlewaretoken', None)
if request_csrf_token != csrf_token:
if cookie_is_new:
# probably a problem setting the CSRF cookie
return reject("CSRF cookie not set.")
else:
return reject("CSRF token missing or incorrect.")
return accept()
def process_response(self, request, response):
if getattr(response, 'csrf_processing_done', False):
return response
# If CSRF_COOKIE is unset, then CsrfViewMiddleware.process_view was
# never called, probaby because a request middleware returned a response
# (for example, contrib.auth redirecting to a login page).
if request.META.get("CSRF_COOKIE") is None:
return response
if not request.META.get("CSRF_COOKIE_USED", False):
return response
# Set the CSRF cookie even if it's already set, so we renew the expiry timer.
response.set_cookie(settings.CSRF_COOKIE_NAME,
request.META["CSRF_COOKIE"], max_age = 60 * 60 * 24 * 7 * 52,
domain=settings.CSRF_COOKIE_DOMAIN)
# Content varies with the CSRF cookie, so set the Vary header.
from django.utils.cache import patch_vary_headers
patch_vary_headers(response, ('Cookie',))
response.csrf_processing_done = True
return response
from django.utils.decorators import decorator_from_middleware
from functools import wraps
csrf_protect = decorator_from_middleware(CsrfViewMiddleware)
csrf_protect.__name__ = "csrf_protect"
csrf_protect.__doc__ = """
This decorator adds CSRF protection in exactly the same way as
CsrfViewMiddleware, but it can be used on a per view basis. Using both, or
using the decorator multiple times, is harmless and efficient.
"""
def add_import_library_function():
#this definition is copy/pasted from django 1.2 source code
#it is necessary to make Coffin library happy
from django.utils.importlib import import_module
class InvalidTemplateLibrary(Exception):
pass
def import_library(taglib_module):
"""Load a template tag library module.
Verifies that the library contains a 'register' attribute, and
returns that attribute as the representation of the library
"""
app_path, taglib = taglib_module.rsplit('.',1)
app_module = import_module(app_path)
try:
mod = import_module(taglib_module)
except ImportError, e:
# If the ImportError is because the taglib submodule does not exist, that's not
# an error that should be raised. If the submodule exists and raised an ImportError
# on the attempt to load it, that we want to raise.
if not module_has_submodule(app_module, taglib):
return None
else:
raise InvalidTemplateLibrary("ImportError raised loading %s: %s" % (taglib_module, e))
try:
return mod.register
except AttributeError:
raise InvalidTemplateLibrary("Template library %s does not have a variable named 'register'" % taglib_module)
import django.template
django.template.import_library = import_library
def add_csrf_protection():
"""adds csrf_token template tag to django
Must be used if version of django is < 1.2
Also adds csrf function to the context processor
and the csrf_protect decorator for the views
"""
import django.template.defaulttags
def csrf_token(parser, token):
return CsrfTokenNode()
django.template.defaulttags.CsrfTokenNode = CsrfTokenNode
django.template.defaulttags.register.tag(csrf_token)
#add csrf context processor
import django.core.context_processors
django.core.context_processors.csrf = csrf
#add csrf_protect decorator
import django.views.decorators
django.views.decorators.csrf = imp.new_module('csrf')
django.views.decorators.csrf.csrf_protect = csrf_protect

View File

@ -1,5 +1,5 @@
{% load extra_tags %}
{% include_jinja "404.jinja.html" %}
{% include_jinja "404.jinja.html" request %}
{% comment %}
this one has to be a django template because of use of default hander404
{% endcomment %}

View File

@ -1,5 +1,5 @@
{% load extra_tags %}
{% include_jinja "500.jinja.html" %}
{% include_jinja "500.jinja.html" request %}
{% comment %}this template must be django
because of the use of default handler500
{% endcomment %}

View File

@ -3,14 +3,17 @@ from django.template.loaders import filesystem
from django.template import RequestContext
from django.http import HttpResponse
from django.utils import translation
from askbot.conf import settings as askbot_settings
from django.conf import settings as django_settings
from coffin.common import CoffinEnvironment
from jinja2 import loaders as jinja_loaders
from jinja2.exceptions import TemplateNotFound
from jinja2.utils import open_if_exists
from askbot.conf import settings as askbot_settings
from askbot.skins import utils
from coffin import template
template.add_to_builtins('askbot.templatetags.extra_filters_jinja')
#module for skinning askbot
#via ASKBOT_DEFAULT_SKIN configureation variable (not django setting)
@ -103,29 +106,26 @@ class SkinEnvironment(CoffinEnvironment):
return '<link href="%s" rel="stylesheet" type="text/css" />' % url
return ''
ENV = SkinEnvironment(
autoescape=False,
extensions=['jinja2.ext.i18n'],
skin = askbot_settings.ASKBOT_DEFAULT_SKIN
#loader = SkinLoader()
)
ENV.set_language(django_settings.LANGUAGE_CODE)
def load_skins():
skins = dict()
for skin_name in utils.get_available_skins():
skins[skin_name] = SkinEnvironment(skin = skin_name)
skins[skin_name] = SkinEnvironment(
skin = skin_name,
extensions=['jinja2.ext.i18n',]
)
skins[skin_name].set_language(django_settings.LANGUAGE_CODE)
#from askbot.templatetags import extra_filters_jinja as filters
#skins[skin_name].filters['media'] = filters.media
return skins
SKINS = load_skins()
def get_skin(request):
def get_skin(request = None):
"""retreives the skin environment
for a given request (request var is not used at this time)"""
return SKINS[askbot_settings.ASKBOT_DEFAULT_SKIN]
def get_template(template, request):
def get_template(template, request = None):
"""retreives template for the skin
request variable will be used in the future to set
template according to the user preference or admins preference

View File

@ -3,6 +3,8 @@ in the beginning of models/__init__.py
the purpose of this module is to validate deployment of askbot
question: why not run these from askbot/__init__.py?
the main function is run_startup_tests
"""
from django.db import transaction

View File

@ -5,7 +5,7 @@ from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from askbot.utils import functions
from askbot.utils.slug import slugify
from askbot.skins.loaders import ENV
from askbot.skins.loaders import get_template
register = template.Library()
@ -117,10 +117,12 @@ def cnprog_paginator(context):
class IncludeJinja(template.Node):
"""http://www.mellowmorning.com/2010/08/24/"""
def __init__(self, filename):
def __init__(self, filename, request_var):
self.filename = filename
self.request_var = template.Variable(request_var)
def render(self, context):
jinja_template = ENV.get_template(self.filename)
request = self.request_var.resolve(context)
jinja_template = get_template(self.filename, request)
return jinja_template.render(context)
@register.tag
@ -128,11 +130,12 @@ def include_jinja(parser, token):
bits = token.contents.split()
#Check if a filename was given
if len(bits) != 2:
if len(bits) != 3:
error_message = '%r tag requires the name of the ' + \
'template to be included included'
'template and the request variable'
raise template.TemplateSyntaxError(error_message % bits[0])
filename = bits[1]
request_var = bits[2]
#Remove quotes or raise error
if filename[0] in ('"', "'") and filename[-1] == filename[0]:
@ -140,4 +143,4 @@ def include_jinja(parser, token):
else:
raise template.TemplateSyntaxError('file name must be quoted')
return IncludeJinja(filename)
return IncludeJinja(filename, request_var)

View File

@ -1,23 +1,30 @@
from django.test import TestCase, signals
from jinja2.environment import Template as Jinja2Template
from django.test import TestCase
from django.test import signals
from django.template import defaultfilters
from django.core.urlresolvers import reverse
import coffin
import coffin.template
from askbot import models
from askbot.utils.slug import slugify
from askbot.deployment import package_utils
import sys
#note - this code can be run only once
ORIG_JINJA2_RENDERER = Jinja2Template.render
def instrumented_render(template_object, *args, **kwargs):
context = dict(*args, **kwargs)
signals.template_rendered.send(
sender=template_object,
template=template_object,
context=context
)
return ORIG_JINJA2_RENDERER(template_object, *args, **kwargs)
Jinja2Template.render = instrumented_render
def patch_jinja2():
from jinja2 import Template
ORIG_JINJA2_RENDERER = Template.render
def instrumented_render(template_object, *args, **kwargs):
context = dict(*args, **kwargs)
signals.template_rendered.send(
sender=template_object,
template=template_object,
context=context
)
return ORIG_JINJA2_RENDERER(template_object, *args, **kwargs)
Template.render = instrumented_render
(CMAJOR, CMINOR, CMICRO) = package_utils.get_coffin_version()
if CMAJOR == 0 and CMINOR == 3 and CMICRO < 4:
patch_jinja2()
class PageLoadTestCase(TestCase):
def try_url(

0
askbot/version.py Normal file
View File

View File

@ -63,6 +63,7 @@ def questions(request):
List of Questions, Tagged questions, and Unanswered questions.
matching search query or user selection
"""
#before = datetime.datetime.now()
#don't allow to post to this view
if request.method == 'POST':
raise Http404

View File

@ -7,9 +7,9 @@ import sys
#you might want to install django-debug-toolbar as well
install_requires = [
'django==1.1.2',
'django>=1.1.2',
'Jinja2',
'Coffin==0.3.0',
'Coffin>=0.3',
'South>=0.7.1',
'oauth2',
'recaptcha-client',
@ -24,7 +24,9 @@ install_requires = [
'django-kombu==0.9.2',
]
import askbot
#todo: have a dirty version retriever that
#parses it out from askbot/__init__.py but does not
#import it as there are issues
WIN_PLATFORMS = ('win32', 'cygwin',)
if sys.platform not in WIN_PLATFORMS:
@ -32,7 +34,7 @@ if sys.platform not in WIN_PLATFORMS:
setup(
name = "askbot",
version = askbot.get_version(),
version = '0.6.75',#remember to manually set this correctly
description = 'Question and Answer forum, like StackOverflow, written in python and Django',
packages = find_packages(),
author = 'Evgeny.Fadeev',