import hotshot
import time
import os
import datetime
import functools
import inspect
import logging
from django.conf import settings
from django.core import exceptions as django_exceptions
from django.core.urlresolvers import reverse
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpResponse, HttpResponseForbidden, Http404
from django.http import HttpResponseRedirect
from django.utils import simplejson
from django.utils.translation import ugettext as _
from django.utils.encoding import smart_str
from askbot import exceptions as askbot_exceptions
from askbot.conf import settings as askbot_settings
from askbot.utils import url_utils
from askbot.utils.html import site_url
from askbot import get_version
def auto_now_timestamp(func):
"""decorator that will automatically set
argument named timestamp to the "now" value if timestamp == None
if there is no timestamp argument, then exception is raised
"""
@functools.wraps(func)
def decorated_func(*arg, **kwarg):
timestamp = kwarg.get('timestamp', None)
if timestamp is None:
kwarg['timestamp'] = datetime.datetime.now()
return func(*arg, **kwarg)
return decorated_func
def ajax_login_required(view_func):
@functools.wraps(view_func)
def wrap(request, *args, **kwargs):
if request.user.is_authenticated():
return view_func(request, *args, **kwargs)
else:
json = simplejson.dumps({'login_required':True})
return HttpResponseForbidden(json, mimetype='application/json')
return wrap
def anonymous_forbidden(view_func):
@functools.wraps(view_func)
def wrapper(request, *args, **kwargs):
if request.user.is_anonymous():
raise askbot_exceptions.LoginRequired()
return view_func(request, *args, **kwargs)
return wrapper
def get_only(view_func):
@functools.wraps(view_func)
def wrapper(request, *args, **kwargs):
if request.method != 'GET':
raise django_exceptions.PermissionDenied(
'request method %s is not supported for this function' % \
request.method
)
return view_func(request, *args, **kwargs)
return wrapper
def post_only(view_func):
@functools.wraps(view_func)
def wrapper(request, *args, **kwargs):
if request.method != 'POST':
raise django_exceptions.PermissionDenied(
'request method %s is not supported for this function' % \
request.method
)
return view_func(request, *args, **kwargs)
return wrapper
def ajax_only(view_func):
@functools.wraps(view_func)
def wrapper(request, *args, **kwargs):
if not request.is_ajax():
raise Http404
try:
data = view_func(request, *args, **kwargs)
if data is None:
data = {}
except Exception, e:
#todo: also check field called "message"
if hasattr(e, 'messages'):
if len(e.messages) > 1:
message = u'
' + \
u''.join(
map(lambda v: u'- %s
' % v, e.messages)
) + \
u'
'
else:
message = e.messages[0]
else:
message = unicode(e)
if message == '':
message = _('Oops, apologies - there was some error')
logging.debug(message)
data = {
'message': message,
'success': 0
}
return HttpResponse(simplejson.dumps(data), mimetype='application/json')
if isinstance(data, HttpResponse):#is this used?
data.mimetype = 'application/json'
return data
else:
data['success'] = 1
json = simplejson.dumps(data)
return HttpResponse(json, mimetype='application/json')
return wrapper
def check_authorization_to_post(func_or_message):
message = _('Please login to post')
if not inspect.isfunction(func_or_message):
message = unicode(func_or_message)
def decorator(view_func):
@functools.wraps(view_func)
def wrapper(request, *args, **kwargs):
if request.user.is_anonymous():
#todo: expand for handling ajax responses
if askbot_settings.ALLOW_POSTING_BEFORE_LOGGING_IN == False:
request.user.message_set.create(message = message)
params = 'next=%s' % request.path
return HttpResponseRedirect(url_utils.get_login_url() + '?' + params)
return view_func(request, *args, **kwargs)
return wrapper
if inspect.isfunction(func_or_message):
return decorator(func_or_message)
else:
return decorator
try:
PROFILE_LOG_BASE = settings.PROFILE_LOG_BASE
except:
PROFILE_LOG_BASE = "/tmp"
def profile(log_file):
"""Profile some callable.
This decorator uses the hotshot profiler to profile some callable (like
a view function or method) and dumps the profile data somewhere sensible
for later processing and examination.
It takes one argument, the profile log name. If it's a relative path, it
places it under the PROFILE_LOG_BASE. It also inserts a time stamp into the
file name, such that 'my_view.prof' become 'my_view-20100211T170321.prof',
where the time stamp is in UTC. This makes it easy to run and compare
multiple trials.
http://code.djangoproject.com/wiki/ProfilingDjango
"""
if not os.path.isabs(log_file):
log_file = os.path.join(PROFILE_LOG_BASE, log_file)
def _outer(f):
def _inner(*args, **kwargs):
# Add a timestamp to the profile output when the callable
# is actually called.
(base, ext) = os.path.splitext(log_file)
base = base + "-" + time.strftime("%Y%m%dT%H%M%S", time.gmtime())
final_log_file = base + ext
prof = hotshot.Profile(final_log_file)
try:
ret = prof.runcall(f, *args, **kwargs)
finally:
prof.close()
return ret
return _inner
return _outer
def check_spam(field):
'''Decorator to check if there is spam in the form'''
def decorator(view_func):
@functools.wraps(view_func)
def wrapper(request, *args, **kwargs):
if askbot_settings.USE_AKISMET and askbot_settings.AKISMET_API_KEY == "":
raise ImproperlyConfigured('You have not set AKISMET_API_KEY')
if askbot_settings.USE_AKISMET and request.method == "POST":
comment = smart_str(request.POST[field])
data = {'user_ip': request.META["REMOTE_ADDR"],
'user_agent': request.environ['HTTP_USER_AGENT'],
'comment_author': smart_str(request.user.username),
}
if request.user.is_authenticated():
data.update({'comment_author_email': request.user.email})
from akismet import Akismet
api = Akismet(
askbot_settings.AKISMET_API_KEY,
smart_str(site_url(reverse('questions'))),
"Askbot/%s" % get_version()
)
if api.comment_check(comment, data, build_data=False):
logging.debug(
'Spam detected in %s post at: %s',
request.user.username,
datetime.datetime.now()
)
spam_message = _(
'Spam was detected on your post, sorry '
'for if this is a mistake'
)
if request.is_ajax():
return HttpResponseForbidden(
spam_message,
mimetype="application/json"
)
else:
request.user.message_set.create(message=spam_message)
return HttpResponseRedirect(reverse('index'))
return view_func(request, *args, **kwargs)
return wrapper
return decorator
def admins_only(view_func):
@functools.wraps(view_func)
def decorator(request, *args, **kwargs):
if request.user.is_anonymous():
raise django_exceptions.PermissionDenied()
if not request.user.is_administrator_or_moderator():
raise django_exceptions.PermissionDenied(
_('This function is limited to moderators and administrators')
)
return view_func(request, *args, **kwargs)
return decorator