1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-02 23:48:47 +00:00

Update captcha

This commit is contained in:
zhengxie
2014-08-05 14:41:04 +08:00
parent 10ea577fb2
commit 2dd360e5e7
31 changed files with 339 additions and 100 deletions

View File

@@ -1,6 +1,6 @@
import re import re
VERSION = (0, 4, 0) VERSION = (0, 4, 3)
def get_version(svn=False): def get_version(svn=False):
@@ -20,8 +20,8 @@ def pillow_required():
except ImportError: except ImportError:
try: try:
import Image import Image
import ImageDraw import ImageDraw # NOQA
import ImageFont import ImageFont # NOQA
except ImportError: except ImportError:
return True return True

View File

@@ -1,6 +1,5 @@
import os import os
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
CAPTCHA_FONT_PATH = getattr(settings, 'CAPTCHA_FONT_PATH', os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'fonts/Vera.ttf'))) CAPTCHA_FONT_PATH = getattr(settings, 'CAPTCHA_FONT_PATH', os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'fonts/Vera.ttf')))
CAPTCHA_FONT_SIZE = getattr(settings, 'CAPTCHA_FONT_SIZE', 22) CAPTCHA_FONT_SIZE = getattr(settings, 'CAPTCHA_FONT_SIZE', 22)
@@ -19,9 +18,9 @@ CAPTCHA_IMAGE_BEFORE_FIELD = getattr(settings, 'CAPTCHA_IMAGE_BEFORE_FIELD', Tru
CAPTCHA_DICTIONARY_MIN_LENGTH = getattr(settings, 'CAPTCHA_DICTIONARY_MIN_LENGTH', 0) CAPTCHA_DICTIONARY_MIN_LENGTH = getattr(settings, 'CAPTCHA_DICTIONARY_MIN_LENGTH', 0)
CAPTCHA_DICTIONARY_MAX_LENGTH = getattr(settings, 'CAPTCHA_DICTIONARY_MAX_LENGTH', 99) CAPTCHA_DICTIONARY_MAX_LENGTH = getattr(settings, 'CAPTCHA_DICTIONARY_MAX_LENGTH', 99)
if CAPTCHA_IMAGE_BEFORE_FIELD: if CAPTCHA_IMAGE_BEFORE_FIELD:
CAPTCHA_OUTPUT_FORMAT = getattr(settings, 'CAPTCHA_OUTPUT_FORMAT', u'%(image)s %(hidden_field)s %(text_field)s') CAPTCHA_OUTPUT_FORMAT = getattr(settings, 'CAPTCHA_OUTPUT_FORMAT', '%(image)s %(hidden_field)s %(text_field)s')
else: else:
CAPTCHA_OUTPUT_FORMAT = getattr(settings, 'CAPTCHA_OUTPUT_FORMAT', u'%(hidden_field)s %(text_field)s %(image)s') CAPTCHA_OUTPUT_FORMAT = getattr(settings, 'CAPTCHA_OUTPUT_FORMAT', '%(hidden_field)s %(text_field)s %(image)s')
CAPTCHA_TEST_MODE = getattr(settings, 'CAPTCHA_TEST_MODE', getattr(settings, 'CATPCHA_TEST_MODE', False)) CAPTCHA_TEST_MODE = getattr(settings, 'CAPTCHA_TEST_MODE', getattr(settings, 'CATPCHA_TEST_MODE', False))

View File

@@ -1,12 +1,12 @@
from captcha.conf import settings from captcha.conf import settings
from django.conf import settings as django_settings
from captcha.models import CaptchaStore, get_safe_now from captcha.models import CaptchaStore, get_safe_now
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import reverse, NoReverseMatch from django.core.urlresolvers import reverse, NoReverseMatch
from django.forms import ValidationError from django.forms import ValidationError
from django.forms.fields import CharField, MultiValueField from django.forms.fields import CharField, MultiValueField
from django.forms.widgets import TextInput, MultiWidget, HiddenInput from django.forms.widgets import TextInput, MultiWidget, HiddenInput
from django.utils.translation import ugettext, ugettext_lazy from django.utils.translation import ugettext, ugettext_lazy
from six import u
class BaseCaptchaTextInput(MultiWidget): class BaseCaptchaTextInput(MultiWidget):
@@ -38,14 +38,10 @@ class BaseCaptchaTextInput(MultiWidget):
key = CaptchaStore.generate_key() key = CaptchaStore.generate_key()
# these can be used by format_output and render # these can be used by format_output and render
self._value = [key, u''] self._value = [key, u('')]
self._key = key self._key = key
self.id_ = self.build_attrs(attrs).get('id', None) self.id_ = self.build_attrs(attrs).get('id', None)
def render(self, name, value, attrs=None):
#self.fetch_captcha_store(name, value, attrs)
return super(BaseCaptchaTextInput, self).render(name, self._value, attrs=attrs)
def id_for_label(self, id_): def id_for_label(self, id_):
if id_: if id_:
return id_ + '_1' return id_ + '_1'
@@ -76,6 +72,7 @@ class CaptchaTextInput(BaseCaptchaTextInput):
def format_output(self, rendered_widgets): def format_output(self, rendered_widgets):
hidden_field, text_field = rendered_widgets hidden_field, text_field = rendered_widgets
text_field = text_field.replace('<input', '<input autocomplete="off"')
return self._args['output_format'] % { return self._args['output_format'] % {
'image': self.image_and_audio, 'image': self.image_and_audio,
'hidden_field': hidden_field, 'hidden_field': hidden_field,
@@ -88,8 +85,6 @@ class CaptchaTextInput(BaseCaptchaTextInput):
self.image_and_audio = '<img src="%s" alt="captcha" class="captcha" />' % self.image_url() self.image_and_audio = '<img src="%s" alt="captcha" class="captcha" />' % self.image_url()
if settings.CAPTCHA_FLITE_PATH: if settings.CAPTCHA_FLITE_PATH:
self.image_and_audio = '<a href="%s" title="%s">%s</a>' % (self.audio_url(), ugettext('Play CAPTCHA as audio file'), self.image_and_audio) self.image_and_audio = '<a href="%s" title="%s">%s</a>' % (self.audio_url(), ugettext('Play CAPTCHA as audio file'), self.image_and_audio)
return super(CaptchaTextInput, self).render(name, self._value, attrs=attrs) return super(CaptchaTextInput, self).render(name, self._value, attrs=attrs)

View File

@@ -2,6 +2,7 @@
import random import random
from captcha.conf import settings from captcha.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from six import u
def math_challenge(): def math_challenge():
@@ -15,14 +16,14 @@ def math_challenge():
def random_char_challenge(): def random_char_challenge():
chars, ret = u'abcdefghijklmnopqrstuvwxyz', u'' chars, ret = u('abcdefghijklmnopqrstuvwxyz'), u('')
for i in range(settings.CAPTCHA_LENGTH): for i in range(settings.CAPTCHA_LENGTH):
ret += random.choice(chars) ret += random.choice(chars)
return ret.upper(), ret return ret.upper(), ret
def unicode_challenge(): def unicode_challenge():
chars, ret = u'äàáëéèïíîöóòüúù', u'' chars, ret = u('äàáëéèïíîöóòüúù'), u('')
for i in range(settings.CAPTCHA_LENGTH): for i in range(settings.CAPTCHA_LENGTH):
ret += random.choice(chars) ret += random.choice(chars)
return ret.upper(), ret return ret.upper(), ret
@@ -70,6 +71,10 @@ def noise_dots(draw, image):
return draw return draw
def noise_null(draw, image):
return draw
def post_smooth(image): def post_smooth(image):
try: try:
import ImageFilter import ImageFilter

View File

@@ -0,0 +1,31 @@
# django-simple-captcha Bulgarian translation
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the django-simple-captcha package.
# Venelin Stoykov <vkstoykov@gmail.com>, 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.4.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-02-10 14:43+0200\n"
"PO-Revision-Date: 2014-02-10 15:00+0200\n"
"Last-Translator: Venelin Stoykov <vkstoykov@gmail.com>\n"
"Language-Team: bg <vkstoykov@gmail.com>\n"
"Language: bg\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: fields.py:91
msgid "Play CAPTCHA as audio file"
msgstr "Чуй текста като аудио файл"
#: fields.py:106 fields.py:135 tests/tests.py:99 tests/tests.py:239
#: tests/tests.py:246
msgid "Invalid CAPTCHA"
msgstr "Сгрешен текст"
#: tests/tests.py:125
msgid "This field is required."
msgstr "Това поле е задължително"

View File

@@ -11,7 +11,7 @@ msgstr ""
"PO-Revision-Date: 2012-10-09 07:08+0200\n" "PO-Revision-Date: 2012-10-09 07:08+0200\n"
"Last-Translator: Beda Kosata <bedrich.kosata@nic.cz>\n" "Last-Translator: Beda Kosata <bedrich.kosata@nic.cz>\n"
"Language-Team: Czech <>\n" "Language-Team: Czech <>\n"
"Language: \n" "Language: cs\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"

View File

@@ -11,6 +11,7 @@ msgstr ""
"PO-Revision-Date: 2013-07-16 12:10+0100\n" "PO-Revision-Date: 2013-07-16 12:10+0100\n"
"Last-Translator: Patrick Lauber <patrick.lauber@divio.ch>\n" "Last-Translator: Patrick Lauber <patrick.lauber@divio.ch>\n"
"Language-Team: DE <digi@treepy.com>\n" "Language-Team: DE <digi@treepy.com>\n"
"Language: de\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"

View File

@@ -0,0 +1,32 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-07-16 12:06+0200\n"
"PO-Revision-Date: 2014-05-20 21:22+0100\n"
"Last-Translator: https://github.com/dragosdobrota\n"
"Language-Team: es\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.6.5\n"
#: fields.py:90
msgid "Play CAPTCHA as audio file"
msgstr "Reproducir CAPTCHA de audio"
#: fields.py:105 fields.py:134 tests/tests.py:99 tests/tests.py:239
#: tests/tests.py:246
msgid "Invalid CAPTCHA"
msgstr "CAPTCHA no válido"
#: tests/tests.py:125
msgid "This field is required."
msgstr "Este campo es obligatorio."

View File

@@ -3,7 +3,6 @@
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# Patrick Samson <maxcom@laposte.net>, 2010. # Patrick Samson <maxcom@laposte.net>, 2010.
# #
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: django-simple-captcha 0.2.0\n" "Project-Id-Version: django-simple-captcha 0.2.0\n"
@@ -11,8 +10,8 @@ msgstr ""
"POT-Creation-Date: 2012-07-25 11:44+0300\n" "POT-Creation-Date: 2012-07-25 11:44+0300\n"
"PO-Revision-Date: 2010-09-16 12:16+0200\n" "PO-Revision-Date: 2010-09-16 12:16+0200\n"
"Last-Translator: Patrick Samson <maxcom@laposte.net>\n" "Last-Translator: Patrick Samson <maxcom@laposte.net>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: fr <maxcom@laposte.net>\n"
"Language: \n" "Language: fr\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"

View File

@@ -3,7 +3,6 @@
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# Arjuna Del Toso <stupidate@gmail.net>, 2012 # Arjuna Del Toso <stupidate@gmail.net>, 2012
# #
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.6\n" "Project-Id-Version: django-simple-captcha 0.3.6\n"
@@ -12,6 +11,8 @@ msgstr ""
"PO-Revision-Date: 2012-11-14 02:53+0000\n" "PO-Revision-Date: 2012-11-14 02:53+0000\n"
"Last-Translator: Arjuna Del Toso <stupidate@gmail.com>\n" "Last-Translator: Arjuna Del Toso <stupidate@gmail.com>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Language-Team: Arjuna Del Toso <stupidate@gmail.com>\n"
"Language: it\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n>1;\n" "Plural-Forms: nplurals=2; plural=n>1;\n"

View File

@@ -0,0 +1,31 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Keisuke URAGO <bravo@resourcez.org>, 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-02-13 07:11+0900\n"
"PO-Revision-Date: 2014-02-13 07:11+0900\n"
"Last-Translator: Keisuke URAGO <bravo@resourcez.org>\n"
"Language-Team: Keisuke URAGO <bravo@resourcez.org>\n"
"Language: ja\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: fields.py:90
msgid "Play CAPTCHA as audio file"
msgstr "CAPTCHAをオーディオで読み上げる"
#: fields.py:105 fields.py:134 tests/tests.py:99 tests/tests.py:239
#: tests/tests.py:246
msgid "Invalid CAPTCHA"
msgstr "CAPTCHAの値が違っています"
#: tests/tests.py:125
msgid "This field is required."
msgstr "この項目は必須です"

View File

@@ -3,15 +3,16 @@
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# Leon de Rijke <leon@cmsworks.nl>, 2013. # Leon de Rijke <leon@cmsworks.nl>, 2013.
# #
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.6\n" "Project-Id-Version: django-simple-captcha 0.3.6\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-15 13:26+0100\n" "POT-Creation-Date: 2013-02-15 13:26+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: 2013-02-15 13:26+0100\n"
"Last-Translator: Leon de Rijke <leon@cmsworks.nl>\n" "Last-Translator: Leon de Rijke <leon@cmsworks.nl>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Language-Team: Leon de Rijke <leon@cmsworks.nl>\n"
"Language: nl\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"

View File

@@ -3,16 +3,15 @@
# This file is distributed under the same license as the django-simple-captcha package. # This file is distributed under the same license as the django-simple-captcha package.
# Sławomir Zborowski <slawomir.zborowski@hotmail.com>, 2013. # Sławomir Zborowski <slawomir.zborowski@hotmail.com>, 2013.
# #
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: django-simple-captcha 0.3.6\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-18 18:49+0200\n" "POT-Creation-Date: 2013-08-18 18:49+0200\n"
"PO-Revision-Date: 2013-08-18 18:52+0200\n" "PO-Revision-Date: 2013-08-18 18:52+0200\n"
"Last-Translator: Sławomir Zborowski <slawomir.zborowski@hotmail.com>\n" "Last-Translator: Sławomir Zborowski <slawomir.zborowski@hotmail.com>\n"
"Language-Team: Polisch\n" "Language-Team: Polisch\n"
"Language: \n" "Language: pl\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"

View File

@@ -3,7 +3,6 @@
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# Alisson Patricio <eu@alisson.net>, 2013. # Alisson Patricio <eu@alisson.net>, 2013.
# #
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.7\n" "Project-Id-Version: django-simple-captcha 0.3.7\n"
@@ -11,7 +10,8 @@ msgstr ""
"POT-Creation-Date: 2013-05-18 10:58-0300\n" "POT-Creation-Date: 2013-05-18 10:58-0300\n"
"PO-Revision-Date: 2013-05-18 13:12-0300\n" "PO-Revision-Date: 2013-05-18 13:12-0300\n"
"Last-Translator: Alisson Patricio <eu@alisson.net>\n" "Last-Translator: Alisson Patricio <eu@alisson.net>\n"
"Language: Portuguese (Brazilian)\n" "Language-Team: Alisson Patricio <eu@alisson.net>\n"
"Language: pt_br\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"

View File

@@ -3,16 +3,15 @@
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# #
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: django-simple-captcha 0.3.7\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-07-25 11:17+0300\n" "POT-Creation-Date: 2012-07-25 11:17+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: 2012-07-25 11:17+0300\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: \n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: ru <LL@li.org>\n"
"Language: \n" "Language: ru\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"

View File

@@ -0,0 +1,32 @@
# Slovak translation of django-simple-captcha.
# Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Pavol Otto <pavol.otto@nic.cz>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.7\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-10-15 17:16+0200\n"
"PO-Revision-Date: 2013-10-15 17:16+0200\n"
"Last-Translator: Pavol Otto <pavol.otto@nic.cz>\n"
"Language-Team: SK\n"
"Language: sk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
#: fields.py:90
msgid "Play CAPTCHA as audio file"
msgstr "Prehrať captchu ako audio súbor"
#: fields.py:105 fields.py:134 tests/tests.py:99 tests/tests.py:239
#: tests/tests.py:246
msgid "Invalid CAPTCHA"
msgstr "Neplatná CAPTCHA"
#: tests/tests.py:125
msgid "This field is required."
msgstr "Toto pole je povinné."

View File

@@ -3,7 +3,6 @@
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# #
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.6\n" "Project-Id-Version: django-simple-captcha 0.3.6\n"
@@ -11,7 +10,8 @@ msgstr ""
"POT-Creation-Date: 2013-01-19 16:33-0200\n" "POT-Creation-Date: 2013-01-19 16:33-0200\n"
"PO-Revision-Date: 2013-01-19 20:52+0200\n" "PO-Revision-Date: 2013-01-19 20:52+0200\n"
"Last-Translator: Gokmen Gorgen <gokmen@alageek.com>\n" "Last-Translator: Gokmen Gorgen <gokmen@alageek.com>\n"
"Language: \n" "Language-Team: TR Gokmen Gorgen <gokmen@alageek.com>\n"
"Language: tr\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"

View File

@@ -0,0 +1,32 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.6\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-02-21 22:05+0200\n"
"PO-Revision-Date: 2014-02-21 22:05+0200\n"
"Last-Translator: @FuriousCoder\n"
"Language-Team: uk @FuriousCoder\n"
"Language: uk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#: fields.py:91
msgid "Play CAPTCHA as audio file"
msgstr "Відтворити CAPTCHA як аудіо файл."
#: fields.py:106 fields.py:135 tests/tests.py:99 tests/tests.py:239
#: tests/tests.py:246
msgid "Invalid CAPTCHA"
msgstr "Неправильна відповідь."
#: tests/tests.py:125
msgid "This field is required."
msgstr "Це поле є обов'язковим."

View File

@@ -3,15 +3,15 @@
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# Ming Chen <c.ming@live.com>, 2013. # Ming Chen <c.ming@live.com>, 2013.
# #
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.6\n" "Project-Id-Version: django-simple-captcha 0.3.6\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-03-01 05:04+0800\n" "POT-Creation-Date: 2013-03-01 05:04+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: 2013-03-01 05:04+0800\n"
"Last-Translator: Ming Chen <c.ming@live.com>\n" "Last-Translator: Ming Chen <c.ming@live.com>\n"
"Language: \n" "Language-Team: zh_cn Ming Chen <c.ming@live.com>\n"
"Language: zh_cn\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"

View File

@@ -11,15 +11,15 @@ class Command(BaseCommand):
verbose = int(options.get('verbosity')) verbose = int(options.get('verbosity'))
expired_keys = CaptchaStore.objects.filter(expiration__lte=get_safe_now()).count() expired_keys = CaptchaStore.objects.filter(expiration__lte=get_safe_now()).count()
if verbose >= 1: if verbose >= 1:
print "Currently %d expired hashkeys" % expired_keys print("Currently %d expired hashkeys" % expired_keys)
try: try:
CaptchaStore.remove_expired() CaptchaStore.remove_expired()
except: except:
if verbose >= 1: if verbose >= 1:
print "Unable to delete expired hashkeys." print("Unable to delete expired hashkeys.")
sys.exit(1) sys.exit(1)
if verbose >= 1: if verbose >= 1:
if expired_keys > 0: if expired_keys > 0:
print "%d expired hashkeys removed." % expired_keys print("%d expired hashkeys removed." % expired_keys)
else: else:
print "No keys to remove." print("No keys to remove.")

View File

@@ -1,39 +1,26 @@
# encoding: utf-8 # -*- coding: utf-8 -*-
import datetime from __future__ import unicode_literals
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration): from django.db import models, migrations
def forwards(self, orm):
# Adding model 'CaptchaStore'
db.create_table('captcha_captchastore', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('challenge', self.gf('django.db.models.fields.CharField')(max_length=32)),
('response', self.gf('django.db.models.fields.CharField')(max_length=32)),
('hashkey', self.gf('django.db.models.fields.CharField')(unique=True, max_length=40)),
('expiration', self.gf('django.db.models.fields.DateTimeField')()),
))
db.send_create_signal('captcha', ['CaptchaStore'])
def backwards(self, orm): class Migration(migrations.Migration):
# Deleting model 'CaptchaStore'
db.delete_table('captcha_captchastore')
dependencies = [
]
models = { operations = [
'captcha.captchastore': { migrations.CreateModel(
'Meta': {'object_name': 'CaptchaStore'}, name='CaptchaStore',
'challenge': ('django.db.models.fields.CharField', [], {'max_length': '32'}), fields=[
'expiration': ('django.db.models.fields.DateTimeField', [], {}), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
'hashkey': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}), ('challenge', models.CharField(max_length=32)),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ('response', models.CharField(max_length=32)),
'response': ('django.db.models.fields.CharField', [], {'max_length': '32'}) ('hashkey', models.CharField(unique=True, max_length=40)),
} ('expiration', models.DateTimeField()),
} ],
options={
complete_apps = ['captcha'] },
bases=(models.Model,),
),
]

View File

@@ -0,0 +1,21 @@
"""
Django migrations for django-simple-captcha app
This package does not contain South migrations. South migrations can be found
in the ``south_migrations`` package.
"""
SOUTH_ERROR_MESSAGE = """\n
For South support, customize the SOUTH_MIGRATION_MODULES setting like so:
SOUTH_MIGRATION_MODULES = {
'captcha': 'captcha.south_migrations',
}
"""
# Ensure the user is not using Django 1.6 or below with South
try:
from django.db import migrations # noqa
except ImportError:
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured(SOUTH_ERROR_MESSAGE)

View File

@@ -40,10 +40,9 @@ class CaptchaStore(models.Model):
expiration = models.DateTimeField(blank=False) expiration = models.DateTimeField(blank=False)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
#import ipdb; ipdb.set_trace()
self.response = six.text_type(self.response).lower() self.response = six.text_type(self.response).lower()
if not self.expiration: if not self.expiration:
#self.expiration = datetime.datetime.now() + datetime.timedelta(minutes=int(captcha_settings.CAPTCHA_TIMEOUT))
self.expiration = get_safe_now() + datetime.timedelta(minutes=int(captcha_settings.CAPTCHA_TIMEOUT)) self.expiration = get_safe_now() + datetime.timedelta(minutes=int(captcha_settings.CAPTCHA_TIMEOUT))
if not self.hashkey: if not self.hashkey:
key_ = unicodedata.normalize('NFKD', str(randrange(0, MAX_RANDOM_KEY)) + str(time.time()) + six.text_type(self.challenge)).encode('ascii', 'ignore') + unicodedata.normalize('NFKD', six.text_type(self.response)).encode('ascii', 'ignore') key_ = unicodedata.normalize('NFKD', str(randrange(0, MAX_RANDOM_KEY)) + str(time.time()) + six.text_type(self.challenge)).encode('ascii', 'ignore') + unicodedata.normalize('NFKD', six.text_type(self.response)).encode('ascii', 'ignore')

View File

@@ -0,0 +1,39 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'CaptchaStore'
db.create_table('captcha_captchastore', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('challenge', self.gf('django.db.models.fields.CharField')(max_length=32)),
('response', self.gf('django.db.models.fields.CharField')(max_length=32)),
('hashkey', self.gf('django.db.models.fields.CharField')(unique=True, max_length=40)),
('expiration', self.gf('django.db.models.fields.DateTimeField')()),
))
db.send_create_signal('captcha', ['CaptchaStore'])
def backwards(self, orm):
# Deleting model 'CaptchaStore'
db.delete_table('captcha_captchastore')
models = {
'captcha.captchastore': {
'Meta': {'object_name': 'CaptchaStore'},
'challenge': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'expiration': ('django.db.models.fields.DateTimeField', [], {}),
'hashkey': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'response': ('django.db.models.fields.CharField', [], {'max_length': '32'})
}
}
complete_apps = ['captcha']

View File

@@ -1 +1 @@
from .tests import CaptchaCase, trivial_challenge from .tests import CaptchaCase, trivial_challenge # NOQA

View File

@@ -12,6 +12,7 @@ import json
import re import re
import six import six
import os import os
from six import u
class CaptchaCase(TestCase): class CaptchaCase(TestCase):
@@ -42,7 +43,6 @@ class CaptchaCase(TestCase):
settings.CAPTCHA_WORDS_DICTIONARY = self.__current_settings_dictionary settings.CAPTCHA_WORDS_DICTIONARY = self.__current_settings_dictionary
settings.CAPTCHA_PUNCTUATION = self.__current_settings_punctuation settings.CAPTCHA_PUNCTUATION = self.__current_settings_punctuation
def __extract_hash_and_response(self, r): def __extract_hash_and_response(self, r):
hash_ = re.findall(r'value="([0-9a-f]+)"', str(r.content))[0] hash_ = re.findall(r'value="([0-9a-f]+)"', str(r.content))[0]
response = CaptchaStore.objects.get(hashkey=hash_).response response = CaptchaStore.objects.get(hashkey=hash_).response
@@ -175,7 +175,7 @@ class CaptchaCase(TestCase):
def testOutputFormat(self): def testOutputFormat(self):
for urlname in ('captcha-test', 'captcha-test-model-form'): for urlname in ('captcha-test', 'captcha-test-model-form'):
settings.CAPTCHA_OUTPUT_FORMAT = u'%(image)s<p>Hello, captcha world</p>%(hidden_field)s%(text_field)s' settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s<p>Hello, captcha world</p>%(hidden_field)s%(text_field)s')
r = self.client.get(reverse(urlname)) r = self.client.get(reverse(urlname))
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertTrue('<p>Hello, captcha world</p>' in str(r.content)) self.assertTrue('<p>Hello, captcha world</p>' in str(r.content))
@@ -186,7 +186,7 @@ class CaptchaCase(TestCase):
# we turn on DEBUG because CAPTCHA_OUTPUT_FORMAT is only checked debug # we turn on DEBUG because CAPTCHA_OUTPUT_FORMAT is only checked debug
django_settings.DEBUG = True django_settings.DEBUG = True
settings.CAPTCHA_OUTPUT_FORMAT = u'%(image)s' settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s')
try: try:
self.client.get(reverse(urlname)) self.client.get(reverse(urlname))
self.fail() self.fail()
@@ -195,14 +195,14 @@ class CaptchaCase(TestCase):
django_settings.DEBUG = __current_settings_debug django_settings.DEBUG = __current_settings_debug
def testPerFormFormat(self): def testPerFormFormat(self):
settings.CAPTCHA_OUTPUT_FORMAT = u'%(image)s testCustomFormatString %(hidden_field)s %(text_field)s' settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s testCustomFormatString %(hidden_field)s %(text_field)s')
r = self.client.get(reverse('captcha-test')) r = self.client.get(reverse('captcha-test'))
self.assertTrue('testCustomFormatString' in str(r.content)) self.assertTrue('testCustomFormatString' in str(r.content))
r = self.client.get(reverse('test_per_form_format')) r = self.client.get(reverse('test_per_form_format'))
self.assertTrue('testPerFieldCustomFormatString' in str(r.content)) self.assertTrue('testPerFieldCustomFormatString' in str(r.content))
def testIssue31ProperLabel(self): def testIssue31ProperLabel(self):
settings.CAPTCHA_OUTPUT_FORMAT = u'%(image)s %(hidden_field)s %(text_field)s' settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s %(hidden_field)s %(text_field)s')
r = self.client.get(reverse('captcha-test')) r = self.client.get(reverse('captcha-test'))
self.assertTrue('<label for="id_captcha_1"' in str(r.content)) self.assertTrue('<label for="id_captcha_1"' in str(r.content))
@@ -226,12 +226,12 @@ class CaptchaCase(TestCase):
This test covers a default django field and widget behavior This test covers a default django field and widget behavior
It not assert anything. If something is wrong it will raise a error! It not assert anything. If something is wrong it will raise a error!
""" """
settings.CAPTCHA_OUTPUT_FORMAT = u'%(image)s %(hidden_field)s %(text_field)s' settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s %(hidden_field)s %(text_field)s')
widget = CaptchaTextInput(attrs={'class': 'required'}) widget = CaptchaTextInput(attrs={'class': 'required'})
CaptchaField(widget=widget) CaptchaField(widget=widget)
def testTestMode_Issue15(self): def testTestMode_Issue15(self):
__current_test_mode_setting = settings.CAPTCHA_TEST_MODE __current_test_mode_setting = settings.CAPTCHA_TEST_MODE
settings.CAPTCHA_TEST_MODE = False settings.CAPTCHA_TEST_MODE = False
r = self.client.get(reverse('captcha-test')) r = self.client.get(reverse('captcha-test'))
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
@@ -270,11 +270,30 @@ class CaptchaCase(TestCase):
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
hash_, response = self.__extract_hash_and_response(r) hash_, response = self.__extract_hash_and_response(r)
r = self.client.post(reverse('captcha-test-non-required'), dict(captcha_0=hash_, captcha_1=response, subject='xxx', sender='asasd@asdasd.com')) r = self.client.post(reverse('captcha-test-non-required'), dict(captcha_0=hash_, captcha_1=response, subject='xxx', sender='asasd@asdasd.com'))
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertTrue(str(r.content).find('Form validated') > 0) self.assertTrue(str(r.content).find('Form validated') > 0)
def test_autocomplete_off(self):
r = self.client.get(reverse('captcha-test'))
self.assertTrue('<input autocomplete="off" ' in six.text_type(r.content))
def test_autocomplete_not_on_hidden_input(self):
r = self.client.get(reverse('captcha-test'))
self.assertFalse('autocomplete="off" type="hidden" name="captcha_0"' in six.text_type(r.content))
self.assertFalse('autocomplete="off" id="id_captcha_0" name="captcha_0" type="hidden"' in six.text_type(r.content))
def test_transparent_background(self):
__current_test_mode_setting = settings.CAPTCHA_BACKGROUND_COLOR
settings.CAPTCHA_BACKGROUND_COLOR = "transparent"
for key in [store.hashkey for store in six.itervalues(self.stores)]:
response = self.client.get(reverse('captcha-image', kwargs=dict(key=key)))
self.assertEqual(response.status_code, 200)
self.assertTrue(response.has_header('content-type'))
self.assertEqual(response._headers.get('content-type'), ('Content-Type', 'image/png'))
settings.CAPTCHA_BACKGROUND_COLOR = __current_test_mode_setting
def trivial_challenge(): def trivial_challenge():
return 'trivial', 'trivial' return 'trivial', 'trivial'

View File

@@ -3,7 +3,8 @@ try:
except ImportError: except ImportError:
from django.conf.urls.defaults import url, patterns, include from django.conf.urls.defaults import url, patterns, include
urlpatterns = patterns('', urlpatterns = patterns(
'',
url(r'test/$', 'captcha.tests.views.test', name='captcha-test'), url(r'test/$', 'captcha.tests.views.test', name='captcha-test'),
url(r'test-modelform/$', 'captcha.tests.views.test_model_form', name='captcha-test-model-form'), url(r'test-modelform/$', 'captcha.tests.views.test_model_form', name='captcha-test-model-form'),
url(r'test2/$', 'captcha.tests.views.test_custom_error_message', name='captcha-test-custom-error-message'), url(r'test2/$', 'captcha.tests.views.test_custom_error_message', name='captcha-test-custom-error-message'),

View File

@@ -3,7 +3,7 @@ from captcha.fields import CaptchaField
from django.template import RequestContext, loader from django.template import RequestContext, loader
from django.http import HttpResponse from django.http import HttpResponse
from django.contrib.auth.models import User from django.contrib.auth.models import User
from six import u
TEST_TEMPLATE = r''' TEST_TEMPLATE = r'''
{% load url from future %} {% load url from future %}
@@ -30,6 +30,7 @@ TEST_TEMPLATE = r'''
</html> </html>
''' '''
def _test(request, form_class): def _test(request, form_class):
passed = False passed = False
if request.POST: if request.POST:
@@ -80,8 +81,10 @@ def test_per_form_format(request):
help_text='asdasd', help_text='asdasd',
error_messages=dict(invalid='TEST CUSTOM ERROR MESSAGE'), error_messages=dict(invalid='TEST CUSTOM ERROR MESSAGE'),
output_format=( output_format=(
u'%(image)s testPerFieldCustomFormatString ' u(
u'%(hidden_field)s %(text_field)s' '%(image)s testPerFieldCustomFormatString '
'%(hidden_field)s %(text_field)s'
)
) )
) )
return _test(request, CaptchaTestFormatForm) return _test(request, CaptchaTestFormatForm)

View File

@@ -3,7 +3,8 @@ try:
except ImportError: except ImportError:
from django.conf.urls.defaults import patterns, url from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('captcha.views', urlpatterns = patterns(
'captcha.views',
url(r'image/(?P<key>\w+)/$', 'captcha_image', name='captcha-image', kwargs={'scale': 1}), url(r'image/(?P<key>\w+)/$', 'captcha_image', name='captcha-image', kwargs={'scale': 1}),
url(r'image/(?P<key>\w+)@2/$', 'captcha_image', name='captcha-image-2x', kwargs={'scale': 2}), url(r'image/(?P<key>\w+)@2/$', 'captcha_image', name='captcha-image-2x', kwargs={'scale': 2}),
url(r'audio/(?P<key>\w+)/$', 'captcha_audio', name='captcha-audio'), url(r'audio/(?P<key>\w+)/$', 'captcha_audio', name='captcha-audio'),

View File

@@ -1,4 +1,4 @@
from captcha.conf import settings from captcha.conf import settings
from captcha.helpers import captcha_image_url from captcha.helpers import captcha_image_url
from captcha.models import CaptchaStore from captcha.models import CaptchaStore
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
@@ -27,6 +27,15 @@ except ImportError:
from django.utils import simplejson as json from django.utils import simplejson as json
NON_DIGITS_RX = re.compile('[^\d]') NON_DIGITS_RX = re.compile('[^\d]')
# Distance of the drawn text from the top of the captcha image
from_top = 4
def getsize(font, text):
if hasattr(font, 'getoffset'):
return [x + y for x, y in zip(font.getsize(text), font.getoffset(text))]
else:
return font.getsize(text)
def captcha_image(request, key, scale=1): def captcha_image(request, key, scale=1):
@@ -38,9 +47,12 @@ def captcha_image(request, key, scale=1):
else: else:
font = ImageFont.load(settings.CAPTCHA_FONT_PATH) font = ImageFont.load(settings.CAPTCHA_FONT_PATH)
size = font.getsize(text) size = getsize(font, text)
size = (size[0] * 2, int(size[1] * 1.2)) size = (size[0] * 2, int(size[1] * 1.4))
image = Image.new('RGB', size, settings.CAPTCHA_BACKGROUND_COLOR) if settings.CAPTCHA_BACKGROUND_COLOR == "transparent":
image = Image.new('RGBA', size)
else:
image = Image.new('RGB', size, settings.CAPTCHA_BACKGROUND_COLOR)
try: try:
PIL_VERSION = int(NON_DIGITS_RX.sub('', Image.VERSION)) PIL_VERSION = int(NON_DIGITS_RX.sub('', Image.VERSION))
@@ -56,7 +68,7 @@ def captcha_image(request, key, scale=1):
charlist.append(char) charlist.append(char)
for char in charlist: for char in charlist:
fgimage = Image.new('RGB', size, settings.CAPTCHA_FOREGROUND_COLOR) fgimage = Image.new('RGB', size, settings.CAPTCHA_FOREGROUND_COLOR)
charimage = Image.new('L', font.getsize(' %s ' % char), '#000000') charimage = Image.new('L', getsize(font, ' %s ' % char), '#000000')
chardraw = ImageDraw.Draw(charimage) chardraw = ImageDraw.Draw(charimage)
chardraw.text((0, 0), ' %s ' % char, font=font, fill='#ffffff') chardraw.text((0, 0), ' %s ' % char, font=font, fill='#ffffff')
if settings.CAPTCHA_LETTER_ROTATION: if settings.CAPTCHA_LETTER_ROTATION:
@@ -67,7 +79,7 @@ def captcha_image(request, key, scale=1):
charimage = charimage.crop(charimage.getbbox()) charimage = charimage.crop(charimage.getbbox())
maskimage = Image.new('L', size) maskimage = Image.new('L', size)
maskimage.paste(charimage, (xpos, 4, xpos + charimage.size[0], 4 + charimage.size[1])) maskimage.paste(charimage, (xpos, from_top, xpos + charimage.size[0], from_top + charimage.size[1]))
size = maskimage.size size = maskimage.size
image = Image.composite(fgimage, image, maskimage) image = Image.composite(fgimage, image, maskimage)
xpos = xpos + 2 + charimage.size[0] xpos = xpos + 2 + charimage.size[0]