summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST.in1
-rw-r--r--askbot/conf/__init__.py1
-rw-r--r--askbot/conf/external_keys.py49
-rw-r--r--askbot/conf/spam_and_moderation.py32
-rw-r--r--askbot/const/__init__.py63
-rw-r--r--askbot/context.py4
-rw-r--r--askbot/doc/source/changelog.rst1
-rw-r--r--askbot/locale/en/LC_MESSAGES/django.po2
-rw-r--r--askbot/skins/default/media/jquery-openid/jquery.openid.js15
-rw-r--r--askbot/skins/default/templates/authopenid/providers_javascript.html7
-rw-r--r--askbot/skins/default/templates/blocks/bottom_scripts.html2
-rw-r--r--askbot/skins/default/templates/macros.html4
-rw-r--r--askbot/startup_procedures.py1
-rw-r--r--askbot/utils/decorators.py68
-rw-r--r--askbot/utils/functions.py24
-rw-r--r--askbot/views/writers.py22
-rw-r--r--askbot_requirements.txt1
-rw-r--r--setup.py1
18 files changed, 223 insertions, 75 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index 484f6b67..7d503fb7 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,6 +4,7 @@ include LICENSE
include AUTHORS
include COPYING
include README.rst
+include askbot_requirements.txt
recursive-include askbot *
recursive-exclude askbot *.pyc
recursive-exclude .git
diff --git a/askbot/conf/__init__.py b/askbot/conf/__init__.py
index d51be698..1d2d7240 100644
--- a/askbot/conf/__init__.py
+++ b/askbot/conf/__init__.py
@@ -13,6 +13,7 @@ import askbot.conf.skin_general_settings
import askbot.conf.sidebar_main
import askbot.conf.sidebar_question
import askbot.conf.sidebar_profile
+import askbot.conf.spam_and_moderation
import askbot.conf.user_settings
import askbot.conf.markup
import askbot.conf.social_sharing
diff --git a/askbot/conf/external_keys.py b/askbot/conf/external_keys.py
index 15ad2903..8912b0ff 100644
--- a/askbot/conf/external_keys.py
+++ b/askbot/conf/external_keys.py
@@ -1,6 +1,5 @@
-"""
-External service key settings
-"""
+"""External service key settings"""
+from askbot import const
from askbot.conf.settings_wrapper import settings
from askbot.deps import livesettings
from django.utils.translation import ugettext as _
@@ -8,7 +7,8 @@ from django.conf import settings as django_settings
EXTERNAL_KEYS = livesettings.ConfigurationGroup(
'EXTERNAL_KEYS',
- _('Keys to connect the site with external services like Facebook, etc.')
+ _('Keys to connect the site with external '
+ 'services like Facebook, etc.')
)
settings.register(
@@ -19,11 +19,12 @@ settings.register(
help_text=_(
'This key helps google index your site '
'please obtain is at '
- '<a href="%(google_webmasters_tools_url)s">'
+ '<a href="%(url)s?hl=%(lang)s">'
'google webmasters tools site</a>'
- ) % {'google_webmasters_tools_url':
- 'https://www.google.com/webmasters/tools/home?hl=' \
- + django_settings.LANGUAGE_CODE}
+ ) % {
+ 'url': const.DEPENDENCY_URLS['google-webmaster-tools'],
+ 'lang': django_settings.LANGUAGE_CODE,
+ }
)
)
@@ -33,12 +34,12 @@ settings.register(
'GOOGLE_ANALYTICS_KEY',
description=_('Google Analytics key'),
help_text=_(
- 'Obtain is at <a href="%(ga_site)s">'
- 'Google Analytics</a> site, if you '
- 'wish to use Google Analytics to monitor '
- 'your site'
- ) % {'ga_site':'http://www.google.com/intl/%s/analytics/' \
- % django_settings.LANGUAGE_CODE }
+ 'Obtain is at <a href="%(url)s">'
+ 'Google Analytics</a> site, if you '
+ 'wish to use Google Analytics to monitor '
+ 'your site'
+ ) % {'url': 'http://www.google.com/intl/%s/analytics/' \
+ % django_settings.LANGUAGE_CODE }
)
)
@@ -68,8 +69,8 @@ settings.register(
'Recaptcha is a tool that helps distinguish '
'real people from annoying spam robots. '
'Please get this and a public key at '
- 'the <a href="http://google.com/recaptcha">http://google.com/recaptcha</a>'
- )
+ 'the <a href="%(url)s">%(url)s</a>'
+ ) % {'url': const.DEPENDENCY_URLS['recaptcha']}
)
)
@@ -82,9 +83,9 @@ settings.register(
'Facebook API key and Facebook secret '
'allow to use Facebook Connect login method '
'at your site. Please obtain these keys '
- 'at <a href="http://www.facebook.com/developers/createapp.php">'
+ 'at <a href="%(url)s">'
'facebook create app</a> site'
- )
+ ) % {'url': const.DEPENDENCY_URLS['facebook-apps']}
)
)
@@ -102,9 +103,9 @@ settings.register(
'TWITTER_KEY',
description=_('Twitter consumer key'),
help_text=_(
- 'Please register your forum at <a href="http://dev.twitter.com/apps/">'
+ 'Please register your forum at <a href="%(url)s">'
'twitter applications site</a>'
- ),
+ ) % {'url': const.DEPENDENCY_URLS['twitter-apps']},
)
)
@@ -123,9 +124,9 @@ settings.register(
'LINKEDIN_KEY',
description=_('LinkedIn consumer key'),
help_text=_(
- 'Please register your forum at <a href="https://www.linkedin.com/secure/developer">'
+ 'Please register your forum at <a href="%(url)s">'
'LinkedIn developer site</a>'
- ),
+ ) % {'url': const.DEPENDENCY_URLS['linkedin-apps']},
)
)
@@ -144,9 +145,9 @@ settings.register(
'IDENTICA_KEY',
description=_('ident.ca consumer key'),
help_text=_(
- 'Please register your forum at <a href="http://identi.ca/settings/oauthapps">'
+ 'Please register your forum at <a href="%(url)s">'
'Identi.ca applications site</a>'
- ),
+ ) % {'url': const.DEPENDENCY_URLS['identica-apps']},
)
)
diff --git a/askbot/conf/spam_and_moderation.py b/askbot/conf/spam_and_moderation.py
new file mode 100644
index 00000000..375fbdd5
--- /dev/null
+++ b/askbot/conf/spam_and_moderation.py
@@ -0,0 +1,32 @@
+"""Settings for content moderation and spam control"""
+from django.utils.translation import ugettext as _
+from askbot import const
+from askbot.deps import livesettings
+from askbot.conf.settings_wrapper import settings
+
+SPAM_AND_MODERATION = livesettings.ConfigurationGroup(
+ 'SPAM_AND_MODERATION',
+ _('Spam control and content moderation')
+ )
+
+settings.register(
+ livesettings.BooleanValue(
+ SPAM_AND_MODERATION,
+ 'USE_AKISMET',
+ description=_('Enable Akismet spam detection(keys below are required)'),
+ default=False,
+ help_text = _(
+ 'To get an Akismet key please visit '
+ '<a href="%(url)s">Akismet site</a>'
+ ) % {'url': const.DEPENDENCY_URLS['akismet']}
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ SPAM_AND_MODERATION,
+ 'AKISMET_API_KEY',
+ description=_('Akismet key for spam detection')
+ )
+)
+
diff --git a/askbot/const/__init__.py b/askbot/const/__init__.py
index e62dd2cb..73c71800 100644
--- a/askbot/const/__init__.py
+++ b/askbot/const/__init__.py
@@ -1,10 +1,11 @@
# encoding:utf-8
-from django.utils.translation import ugettext as _
-import re
"""
All constants could be used in other modules
-For reasons that models, views can't have unicode text in this project, all unicode text go here.
+For reasons that models, views can't have unicode
+text in this project, all unicode text go here.
"""
+from django.utils.translation import ugettext as _
+import re
CLOSE_REASONS = (
(1, _('duplicate question')),
(2, _('question is off-topic or not relevant')),
@@ -48,7 +49,8 @@ POST_SORT_METHODS = (
('relevance-desc', _('relevance')),
)
#todo: add assertion here that all sort methods are unique
-#because they are keys to the hash used in implementations of Q.run_advanced_search
+#because they are keys to the hash used in implementations
+#of Q.run_advanced_search
DEFAULT_POST_SORT_METHOD = 'activity-desc'
POST_SCOPE_LIST = (
@@ -91,28 +93,28 @@ TAG_REGEX = r'^[%s]+$' % TAG_CHARS
TAG_SPLIT_REGEX = r'[ ,]+'
EMAIL_REGEX = re.compile(r'\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b', re.I)
-TYPE_ACTIVITY_ASK_QUESTION=1
-TYPE_ACTIVITY_ANSWER=2
-TYPE_ACTIVITY_COMMENT_QUESTION=3
-TYPE_ACTIVITY_COMMENT_ANSWER=4
-TYPE_ACTIVITY_UPDATE_QUESTION=5
-TYPE_ACTIVITY_UPDATE_ANSWER=6
-TYPE_ACTIVITY_PRIZE=7
-TYPE_ACTIVITY_MARK_ANSWER=8
-TYPE_ACTIVITY_VOTE_UP=9
-TYPE_ACTIVITY_VOTE_DOWN=10
-TYPE_ACTIVITY_CANCEL_VOTE=11
-TYPE_ACTIVITY_DELETE_QUESTION=12
-TYPE_ACTIVITY_DELETE_ANSWER=13
-TYPE_ACTIVITY_MARK_OFFENSIVE=14
-TYPE_ACTIVITY_UPDATE_TAGS=15
-TYPE_ACTIVITY_FAVORITE=16
+TYPE_ACTIVITY_ASK_QUESTION = 1
+TYPE_ACTIVITY_ANSWER = 2
+TYPE_ACTIVITY_COMMENT_QUESTION = 3
+TYPE_ACTIVITY_COMMENT_ANSWER = 4
+TYPE_ACTIVITY_UPDATE_QUESTION = 5
+TYPE_ACTIVITY_UPDATE_ANSWER = 6
+TYPE_ACTIVITY_PRIZE = 7
+TYPE_ACTIVITY_MARK_ANSWER = 8
+TYPE_ACTIVITY_VOTE_UP = 9
+TYPE_ACTIVITY_VOTE_DOWN = 10
+TYPE_ACTIVITY_CANCEL_VOTE = 11
+TYPE_ACTIVITY_DELETE_QUESTION = 12
+TYPE_ACTIVITY_DELETE_ANSWER = 13
+TYPE_ACTIVITY_MARK_OFFENSIVE = 14
+TYPE_ACTIVITY_UPDATE_TAGS = 15
+TYPE_ACTIVITY_FAVORITE = 16
TYPE_ACTIVITY_USER_FULL_UPDATED = 17
TYPE_ACTIVITY_EMAIL_UPDATE_SENT = 18
TYPE_ACTIVITY_MENTION = 19
TYPE_ACTIVITY_UNANSWERED_REMINDER_SENT = 20
-#TYPE_ACTIVITY_EDIT_QUESTION=17
-#TYPE_ACTIVITY_EDIT_ANSWER=18
+#TYPE_ACTIVITY_EDIT_QUESTION = 17
+#TYPE_ACTIVITY_EDIT_ANSWER = 18
#todo: rename this to TYPE_ACTIVITY_CHOICES
TYPE_ACTIVITY = (
@@ -250,11 +252,22 @@ DEFAULT_USER_STATUS = 'w'
#number of items to show in user views
USER_VIEW_DATA_SIZE = 50
+#not really dependency, but external links, which it would
+#be nice to test for correctness from time to time
DEPENDENCY_URLS = {
- 'mathjax': 'http://www.mathjax.org/resources/docs/?installation.html',
+ 'akismet': 'https://akismet.com/signup/',
+ 'cc-by-sa': 'http://creativecommons.org/licenses/by-sa/3.0/legalcode',
+ 'embedding-video': \
+ 'http://askbot.org/doc/optional-modules.html#embedding-video',
'favicon': 'http://en.wikipedia.org/wiki/Favicon',
- 'embedding-video': 'http://askbot.org/doc/optional-modules.html#embedding-video',
- 'cc-by-sa': 'http://creativecommons.org/licenses/by-sa/3.0/legalcode'
+ 'facebook-apps': 'http://www.facebook.com/developers/createapp.php',
+ 'google-webmaster-tools': 'https://www.google.com/webmasters/tools/home',
+ 'identica-apps': 'http://identi.ca/settings/oauthapps',
+ 'noscript': 'https://www.google.com/support/bin/answer.py?answer=23852',
+ 'linkedin-apps': 'https://www.linkedin.com/secure/developer',
+ 'mathjax': 'http://www.mathjax.org/resources/docs/?installation.html',
+ 'recaptcha': 'http://google.com/recaptcha',
+ 'twitter-apps': 'http://dev.twitter.com/apps/',
}
PASSWORD_MIN_LENGTH = 8
diff --git a/askbot/context.py b/askbot/context.py
index 5a174585..6dc38f79 100644
--- a/askbot/context.py
+++ b/askbot/context.py
@@ -5,6 +5,7 @@ and the application available for the templates
from django.conf import settings
import askbot
from askbot import api
+from askbot import const
from askbot.conf import settings as askbot_settings
from askbot.skins.loaders import get_skin
from askbot.utils import url_utils
@@ -22,5 +23,6 @@ def application_settings(request):
return {
'settings': my_settings,
'skin': get_skin(request),
- 'moderation_items': api.get_info_on_moderation_items(request.user)
+ 'moderation_items': api.get_info_on_moderation_items(request.user),
+ 'noscript_url': const.DEPENDENCY_URLS['noscript'],
}
diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst
index ade7421c..c1eaa158 100644
--- a/askbot/doc/source/changelog.rst
+++ b/askbot/doc/source/changelog.rst
@@ -3,6 +3,7 @@ Changes in Askbot
Development version
-------------------
+* Added support for Akismet spam detection service (Adolfo Fitoria)
* Added noscript message (Arun SAG)
* Support for url shortening with TinyUrl on link sharing (Rtnpro)
* Allowed logging in with password and email in the place of login name (Evgeny)
diff --git a/askbot/locale/en/LC_MESSAGES/django.po b/askbot/locale/en/LC_MESSAGES/django.po
index 5bb75eca..a1548a93 100644
--- a/askbot/locale/en/LC_MESSAGES/django.po
+++ b/askbot/locale/en/LC_MESSAGES/django.po
@@ -499,7 +499,7 @@ msgstr ""
#: conf/email.py:22
msgid "Prefix for the email subject line"
-msgstr "Welcome to the Q&A forum"
+msgstr ""
#: conf/email.py:24
msgid ""
diff --git a/askbot/skins/default/media/jquery-openid/jquery.openid.js b/askbot/skins/default/media/jquery-openid/jquery.openid.js
index 4af89369..7ba9adce 100644
--- a/askbot/skins/default/media/jquery-openid/jquery.openid.js
+++ b/askbot/skins/default/media/jquery-openid/jquery.openid.js
@@ -298,9 +298,21 @@ $.fn.authenticator = function() {
};
var start_password_login_or_change = function(){
+ //called upon clicking on one of the password login buttons
reset_form();
set_provider_name($(this));
var provider_name = $(this).attr('name');
+ return setup_password_login_or_change(provider_name);
+ };
+
+ var init_always_visible_password_login = function(){
+ reset_form();
+ //will break wordpress and ldap
+ provider_name_input.val('local');
+ setup_password_login_or_change('local');
+ };
+
+ var setup_password_login_or_change = function(provider_name){
var token_name = extra_token_name[provider_name]
var password_action_input = $('input[name=password_action]');
if (userIsAuthenticated === true){
@@ -427,6 +439,9 @@ $.fn.authenticator = function() {
};
setup_default_handlers();
+ if (askbot['settings']['signin_always_show_local_login'] === true){
+ init_always_visible_password_login();
+ }
clear_password_fields();
return this;
};
diff --git a/askbot/skins/default/templates/authopenid/providers_javascript.html b/askbot/skins/default/templates/authopenid/providers_javascript.html
index 85e55e9f..0fe72eb3 100644
--- a/askbot/skins/default/templates/authopenid/providers_javascript.html
+++ b/askbot/skins/default/templates/authopenid/providers_javascript.html
@@ -34,13 +34,8 @@
{% else %}
var userIsAuthenticated = false;
{% endif %}
- $("body").authenticator();
- {% if settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}
- {% if settings.SIGNIN_LOCAL_ENABLED %}
- $('input.password').remove();
- {% endif %}
- {%endif%}
askbot['settings']['signin_always_show_local_login'] = {% if settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}true{% else %}false{% endif %};
+ $("body").authenticator();
</script>
{% if settings.FACEBOOK_KEY and settings.FACEBOOK_SECRET %}
<div id="fb-root"></div>
diff --git a/askbot/skins/default/templates/blocks/bottom_scripts.html b/askbot/skins/default/templates/blocks/bottom_scripts.html
index 6fbd6adc..771c13a4 100644
--- a/askbot/skins/default/templates/blocks/bottom_scripts.html
+++ b/askbot/skins/default/templates/blocks/bottom_scripts.html
@@ -4,7 +4,7 @@
#}
<div id="no-javascript">
<noscript class="noscript">
- {% trans app_name = settings.APP_SHORT_NAME %}Please note: {{app_name}} requires javascript to work properly, please enable javascript in your browser{% endtrans %}
+ {% trans app_name = settings.APP_SHORT_NAME %}Please note: {{app_name}} requires javascript to work properly, please enable javascript in your browser, <a href="{{noscript_url}}">here is how</a>{% endtrans %}
</noscript>
</div>
<script type="text/javascript">
diff --git a/askbot/skins/default/templates/macros.html b/askbot/skins/default/templates/macros.html
index 36ab9692..7ddbd70f 100644
--- a/askbot/skins/default/templates/macros.html
+++ b/askbot/skins/default/templates/macros.html
@@ -138,8 +138,7 @@
{%- macro paginator(p, position='left') -%}{# p is paginator context dictionary #}
{% spaceless %}
{% if p.is_paginated %}
- <div class="paginator">
- <div style="float:{{position}}">
+ <div class="paginator" style="float:{{position}}">
{% if p.has_previous %}
<span class="prev"><a href="{{p.base_url}}page={{ p.previous }}{{ p.extend_url }}" title="{% trans %}previous{% endtrans %}">
&laquo; {% trans %}previous{% endtrans %}</a></span>
@@ -169,7 +168,6 @@
<span class="next"><a href="{{p.base_url}}page={{ p.next }}{{ p.extend_url }}" title="{% trans %}next page{% endtrans %}">{% trans %}next page{% endtrans %} &raquo;</a></span>
{% endif %}
</div>
- </div>
{% endif %}
{% endspaceless %}
{%- endmacro -%}
diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py
index 4fb41eb6..cc7f86c0 100644
--- a/askbot/startup_procedures.py
+++ b/askbot/startup_procedures.py
@@ -136,6 +136,7 @@ def try_import(module_name, pypi_package_name):
def test_modules():
"""tests presence of required modules"""
+ try_import('akismet', 'akismet')
try_import('recaptcha_works', 'django-recaptcha-works')
def test_postgres():
diff --git a/askbot/utils/decorators.py b/askbot/utils/decorators.py
index f2c86cd5..29e92645 100644
--- a/askbot/utils/decorators.py
+++ b/askbot/utils/decorators.py
@@ -7,14 +7,17 @@ import inspect
import logging
from django.conf import settings
from django.core import exceptions as django_exceptions
-from django.core import urlresolvers
+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 import get_version
def auto_now_timestamp(func):
"""decorator that will automatically set
@@ -33,12 +36,12 @@ def auto_now_timestamp(func):
def ajax_login_required(view_func):
@functools.wraps(view_func)
- def wrap(request,*args,**kwargs):
+ def wrap(request, *args, **kwargs):
if request.user.is_authenticated():
- return view_func(request,*args,**kwargs)
+ return view_func(request, *args, **kwargs)
else:
json = simplejson.dumps({'login_required':True})
- return HttpResponseForbidden(json,mimetype='application/json')
+ return HttpResponseForbidden(json, mimetype='application/json')
return wrap
@@ -74,14 +77,13 @@ def post_only(view_func):
return view_func(request, *args, **kwargs)
return wrapper
-
def ajax_only(view_func):
@functools.wraps(view_func)
- def wrapper(request,*args,**kwargs):
+ def wrapper(request, *args, **kwargs):
if not request.is_ajax():
raise Http404
try:
- data = view_func(request,*args,**kwargs)
+ data = view_func(request, *args, **kwargs)
except Exception, e:
message = unicode(e)
if message == '':
@@ -99,7 +101,7 @@ def ajax_only(view_func):
else:
data['success'] = 1
json = simplejson.dumps(data)
- return HttpResponse(json,mimetype='application/json')
+ return HttpResponse(json, mimetype='application/json')
return wrapper
def check_authorization_to_post(func_or_message):
@@ -166,3 +168,53 @@ def profile(log_file):
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(askbot_settings.APP_URL),
+ "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
diff --git a/askbot/utils/functions.py b/askbot/utils/functions.py
index a56ed897..d31d9027 100644
--- a/askbot/utils/functions.py
+++ b/askbot/utils/functions.py
@@ -2,12 +2,13 @@ import re
import datetime
from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
+from django.contrib.auth.models import User
def get_from_dict_or_object(source, key):
try:
return source[key]
except:
- return getattr(source,key)
+ return getattr(source, key)
def is_iterable(thing):
@@ -53,7 +54,7 @@ def not_a_robot_request(request):
return False
-def diff_date(date, limen=2, use_on_prefix = False):
+def diff_date(date, use_on_prefix = False):
now = datetime.datetime.now()#datetime(*time.localtime()[0:6])#???
diff = now - date
days = diff.days
@@ -74,9 +75,17 @@ def diff_date(date, limen=2, use_on_prefix = False):
elif days == 1:
return _('yesterday')
elif minutes >= 60:
- return ungettext('%(hr)d hour ago','%(hr)d hours ago',hours) % {'hr':hours}
+ return ungettext(
+ '%(hr)d hour ago',
+ '%(hr)d hours ago',
+ hours
+ ) % {'hr':hours}
else:
- return ungettext('%(min)d min ago','%(min)d mins ago',minutes) % {'min':minutes}
+ return ungettext(
+ '%(min)d min ago',
+ '%(min)d mins ago',
+ minutes
+ ) % {'min':minutes}
#todo: this function may need to be removed to simplify the paginator functionality
LEADING_PAGE_RANGE_DISPLAYED = TRAILING_PAGE_RANGE_DISPLAYED = 5
@@ -126,3 +135,10 @@ def setup_paginator(context):
"pages_outside_trailing_range": pages_outside_trailing_range,
"extend_url" : extend_url
}
+
+def get_admin():
+ '''Returns an admin users, usefull for raising flags'''
+ try:
+ return User.objects.filter(is_superuser=True)[0]
+ except:
+ raise Exception('there is no admin users')
diff --git a/askbot/views/writers.py b/askbot/views/writers.py
index a2540a90..fcc98761 100644
--- a/askbot/views/writers.py
+++ b/askbot/views/writers.py
@@ -189,6 +189,7 @@ def import_data(request):
#@login_required #actually you can post anonymously, but then must register
@csrf.csrf_protect
@decorators.check_authorization_to_post(_('Please log in to ask questions'))
+@decorators.check_spam('text')
def ask(request):#view used to ask a new question
"""a view to ask a new question
gives space for q title, body, tags and checkbox for to post as wiki
@@ -240,6 +241,18 @@ def ask(request):#view used to ask a new question
)
question.save()
return HttpResponseRedirect(url_utils.get_login_url())
+ else:
+ form = forms.AskForm(request.POST)
+ if 'title' in request.GET:
+ #normally this title is inherited from search query
+ #but it is possible to ask with a parameter title in the url query
+ form.initial['title'] = request.GET['title']
+ else:
+ #attempt to extract title from previous search query
+ search_state = request.session.get('search_state', None)
+ if search_state:
+ query = search_state.query
+ form.initial['title'] = query
else:
#this branch is for the initial load of ask form
form = forms.AskForm()
@@ -249,7 +262,7 @@ def ask(request):#view used to ask a new question
form.initial['title'] = request.GET['title']
else:
#attempt to extract title from previous search query
- search_state = request.session.get('search_state',None)
+ search_state = request.session.get('search_state', None)
if search_state:
query = search_state.query
form.initial['title'] = query
@@ -319,6 +332,7 @@ def retag_question(request, id):
@login_required
@csrf.csrf_protect
+@decorators.check_spam('text')
def edit_question(request, id):
"""edit question view
"""
@@ -406,6 +420,7 @@ def edit_question(request, id):
@login_required
@csrf.csrf_protect
+@decorators.check_spam('text')
def edit_answer(request, id):
answer = get_object_or_404(models.Answer, id=id)
try:
@@ -464,6 +479,7 @@ def edit_answer(request, id):
#todo: rename this function to post_new_answer
@decorators.check_authorization_to_post(_('Please log in to answer questions'))
+@decorators.check_spam('text')
def answer(request, id):#process a new answer
"""view that posts new answer
@@ -548,6 +564,7 @@ def __generate_comments_json(obj, user):#non-view generates json data for the po
data = simplejson.dumps(json_comments)
return HttpResponse(data, mimetype="application/json")
+@decorators.check_spam('comment')
def post_comments(request):#generic ajax handler to load comments to an object
# only support get post comments by ajax now
user = request.user
@@ -587,6 +604,7 @@ def post_comments(request):#generic ajax handler to load comments to an object
raise Http404
@decorators.ajax_only
+@decorators.check_spam('text')
def edit_comment(request):
if request.user.is_authenticated():
comment_id = int(request.POST['comment_id'])
@@ -609,7 +627,7 @@ def edit_comment(request):
'user_id': comment.user.id,
'is_deletable': is_deletable,
'is_editable': is_editable,
- 'score': comment.score,
+ 'score': comment.score,
'voted': comment.is_upvoted_by(request.user),
}
else:
diff --git a/askbot_requirements.txt b/askbot_requirements.txt
index b4b5a1f4..fc11d9d1 100644
--- a/askbot_requirements.txt
+++ b/askbot_requirements.txt
@@ -1,3 +1,4 @@
+akismet
django>=1.1.2
Jinja2
Coffin>=0.3
diff --git a/setup.py b/setup.py
index d319d761..71ed2abb 100644
--- a/setup.py
+++ b/setup.py
@@ -7,6 +7,7 @@ import sys
#you might want to install django-debug-toolbar as well
install_requires = [
+ 'akismet',
'django>=1.1.2',
'Jinja2',
'Coffin>=0.3',