diff --git a/boards/forms.py b/boards/forms.py --- a/boards/forms.py +++ b/boards/forms.py @@ -4,7 +4,7 @@ from django import forms from django.forms.util import ErrorList from boards.models import TITLE_MAX_LENGTH from neboard import settings - +from boards import utils class PlainErrorList(ErrorList): def __unicode__(self): @@ -67,9 +67,6 @@ class PostForm(forms.Form): self._errors['image'] = self.error_class([error_message]) -class PostCaptchaForm(PostForm): - captcha = CaptchaField() - class ThreadForm(PostForm): regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE) @@ -91,9 +88,47 @@ class ThreadForm(PostForm): return cleaned_data +class PostCaptchaForm(PostForm): + captcha = CaptchaField() + + def __init__(self, *args, **kwargs): + self.request = kwargs['request'] + del kwargs['request'] + + super(PostCaptchaForm, self).__init__(*args, **kwargs) + + def clean(self): + cleaned_data = super(PostCaptchaForm, self).clean() + + success = self.is_valid() + utils.update_captcha_access(self.request, success) + + if success: + return cleaned_data + else: + raise forms.ValidationError("captcha validation failed") + + class ThreadCaptchaForm(ThreadForm): captcha = CaptchaField() + def __init__(self, *args, **kwargs): + self.request = kwargs['request'] + del kwargs['request'] + + super(ThreadCaptchaForm, self).__init__(*args, **kwargs) + + def clean(self): + cleaned_data = super(ThreadCaptchaForm, self).clean() + + success = self.is_valid() + utils.update_captcha_access(self.request, success) + + if success: + return cleaned_data + else: + raise forms.ValidationError("captcha validation failed") + class SettingsForm(forms.Form): - theme = forms.ChoiceField(choices=settings.THEMES, widget=forms.RadioSelect) \ No newline at end of file + theme = forms.ChoiceField(choices=settings.THEMES, widget=forms.RadioSelect) diff --git a/boards/models.py b/boards/models.py --- a/boards/models.py +++ b/boards/models.py @@ -8,6 +8,7 @@ from django.db import models from django.http import Http404 from django.utils import timezone from markupfield.fields import MarkupField +from threading import Thread from neboard import settings import thumbs diff --git a/boards/templates/boards/posting_general.html b/boards/templates/boards/posting_general.html --- a/boards/templates/boards/posting_general.html +++ b/boards/templates/boards/posting_general.html @@ -130,6 +130,7 @@
{{ form.captcha }} +
{{ form.captcha.errors }}
diff --git a/boards/templates/boards/thread.html b/boards/templates/boards/thread.html --- a/boards/templates/boards/thread.html +++ b/boards/templates/boards/thread.html @@ -84,6 +84,7 @@
{{ form.captcha }} +
{{ form.captcha.errors }}
diff --git a/boards/utils.py b/boards/utils.py --- a/boards/utils.py +++ b/boards/utils.py @@ -1,14 +1,64 @@ """ This module contains helper functions and helper classes. """ + from neboard import settings +import time -def check_if_human(request): +KEY_CAPTCHA_FAILS = 'key_captcha_fails' +KEY_CAPTCHA_DELAY_TIME = 'key_captcha_delay_time' +KEY_CAPTCHA_LAST_ACTIVITY = 'key_captcha_last_activity' + + +def need_include_captcha(request): """ Check if request is made by a user. It contains rules which check for bots. """ - # FIXME: need to insert checking logic - return not settings.ENABLE_CAPTCHA + if not settings.ENABLE_CAPTCHA: + return False + + enable_captcha = False + + #newcomer + if KEY_CAPTCHA_LAST_ACTIVITY not in request.session: + return settings.ENABLE_CAPTCHA + + last_activity = request.session[KEY_CAPTCHA_LAST_ACTIVITY] + current_delay = int(time.time()) - last_activity + + delay_time = (request.session[KEY_CAPTCHA_DELAY_TIME] + if KEY_CAPTCHA_DELAY_TIME in request.session + else settings.CAPTCHA_DEFAULT_SAFE_TIME) + + if current_delay < delay_time: + enable_captcha = True + + print 'ENABLING' + str(enable_captcha) + + return enable_captcha + + +def update_captcha_access(request, passed): + """ + Update captcha fields. + It will reduce delay time if user passed captcha verification and + it will increase it otherwise. + """ + session = request.session + + delay_time = (request.session[KEY_CAPTCHA_DELAY_TIME] + if KEY_CAPTCHA_DELAY_TIME in request.session + else settings.CAPTCHA_DEFAULT_SAFE_TIME) + + print "DELAY TIME = " + str(delay_time) + + if passed: + delay_time -= 2 if delay_time >= 7 else 5 + else: + delay_time += 10 + + session[KEY_CAPTCHA_LAST_ACTIVITY] = int(time.time()) + session[KEY_CAPTCHA_DELAY_TIME] = delay_time diff --git a/boards/views.py b/boards/views.py --- a/boards/views.py +++ b/boards/views.py @@ -16,18 +16,21 @@ import neboard def index(request, page=0): context = RequestContext(request) - threadFormClass = (ThreadForm - if utils.check_if_human(request) - else ThreadCaptchaForm) + if utils.need_include_captcha(request): + threadFormClass = ThreadCaptchaForm + kwargs = {'request': request} + else: + threadFormClass = ThreadForm + kwargs = {} if request.method == 'POST': form = threadFormClass(request.POST, request.FILES, - error_class=PlainErrorList) + error_class=PlainErrorList, **kwargs) if form.is_valid(): return _new_post(request, form) else: - form = threadFormClass(error_class=PlainErrorList) + form = threadFormClass(error_class=PlainErrorList, **kwargs) threads = Post.objects.get_threads(page=int(page)) @@ -119,16 +122,20 @@ def tag(request, tag_name, page=0): def thread(request, post_id): """Get all thread posts""" - postFormClass = (PostForm if utils.check_if_human(request) else - PostCaptchaForm) + if utils.need_include_captcha(request): + postFormClass = PostCaptchaForm + kwargs = {'request': request} + else: + postFormClass = PostForm + kwargs = {} if request.method == 'POST': form = postFormClass(request.POST, request.FILES, - error_class=PlainErrorList) + error_class=PlainErrorList, **kwargs) if form.is_valid(): return _new_post(request, form, post_id) else: - form = postFormClass(error_class=PlainErrorList) + form = postFormClass(error_class=PlainErrorList, **kwargs) posts = Post.objects.get_thread(post_id) diff --git a/neboard/settings.py b/neboard/settings.py --- a/neboard/settings.py +++ b/neboard/settings.py @@ -187,9 +187,12 @@ SITE_NAME = 'Neboard' THEMES = [ ('md', 'Mystic Dark'), ('sw', 'Snow White') ] + DEFAULT_THEME = 'md' POPULAR_TAGS = 10 LAST_REPLIES_COUNT = 3 -ENABLE_CAPTCHA = False \ No newline at end of file +ENABLE_CAPTCHA = True +# if user tries to post before CAPTCHA_DEFAULT_SAFE_TIME. Captcha will be shown +CAPTCHA_DEFAULT_SAFE_TIME = 30 # seconds \ No newline at end of file