Show More
@@ -1,24 +1,31 b'' | |||||
|
1 | from django.utils.translation import ugettext_lazy as _ | |||
|
2 | ||||
1 | __author__ = 'neko259' |
|
3 | __author__ = 'neko259' | |
2 |
|
4 | |||
|
5 | ROLE_AUTHOR = _('author') | |||
|
6 | ROLE_DEVELOPER = _('developer') | |||
|
7 | ROLE_JS_DEV = _('javascript developer') | |||
|
8 | ROLE_DESIGNER = _('designer') | |||
|
9 | ||||
3 | authors = { |
|
10 | authors = { | |
4 | 'neko259': { |
|
11 | 'neko259': { | |
5 | 'name': 'Pavel Ryapolov', |
|
12 | 'name': 'Pavel Ryapolov', | |
6 | 'contacts': ['neko259@gmail.com'], |
|
13 | 'contacts': ['neko259@gmail.com'], | |
7 | 'roles': ['author', 'developer'], |
|
14 | 'roles': [ROLE_AUTHOR, ROLE_DEVELOPER], | |
8 | }, |
|
15 | }, | |
9 | 'ilyas': { |
|
16 | 'ilyas': { | |
10 | 'name': 'Ilyas Babayev', |
|
17 | 'name': 'Ilyas Babayev', | |
11 | 'contacts': ['zamesilyasa@gmail.com'], |
|
18 | 'contacts': ['zamesilyasa@gmail.com'], | |
12 | 'roles': ['author', 'developer'], |
|
19 | 'roles': [ROLE_AUTHOR, ROLE_DEVELOPER], | |
13 | }, |
|
20 | }, | |
14 | 'ritsufag': { |
|
21 | 'ritsufag': { | |
15 | 'name': 'Aiko Kirino', |
|
22 | 'name': 'Aiko Kirino', | |
16 | 'contacts': ['ritsufag@gmail.com'], |
|
23 | 'contacts': ['ritsufag@gmail.com'], | |
17 | 'roles': ['javascript developer', 'designer'], |
|
24 | 'roles': [ROLE_JS_DEV, ROLE_DESIGNER], | |
18 | }, |
|
25 | }, | |
19 | 'Tenno Seremel': { |
|
26 | 'Tenno Seremel': { | |
20 | 'name': 'anonymous', |
|
27 | 'name': 'anonymous', | |
21 | 'contacts': ['html@serenareem.net'], |
|
28 | 'contacts': ['html@serenareem.net'], | |
22 | 'roles': ['javascript developer', 'designer'], |
|
29 | 'roles': [ROLE_JS_DEV, ROLE_DESIGNER], | |
23 | }, |
|
30 | }, | |
24 | } No newline at end of file |
|
31 | } |
@@ -9,6 +9,12 b' from neboard import settings' | |||||
9 | from boards import utils |
|
9 | from boards import utils | |
10 |
|
10 | |||
11 | LAST_POST_TIME = "last_post_time" |
|
11 | LAST_POST_TIME = "last_post_time" | |
|
12 | LAST_LOGIN_TIME = "last_login_time" | |||
|
13 | ||||
|
14 | LOGIN_DELAY = 60 * 60 | |||
|
15 | ||||
|
16 | MAX_TEXT_LENGTH = 30000 | |||
|
17 | MAX_IMAGE_SIZE = 8 * 1024 * 1024 | |||
12 |
|
18 | |||
13 |
|
19 | |||
14 | class PlainErrorList(ErrorList): |
|
20 | class PlainErrorList(ErrorList): | |
@@ -41,9 +47,6 b' class NeboardForm(forms.Form):' | |||||
41 |
|
47 | |||
42 | class PostForm(NeboardForm): |
|
48 | class PostForm(NeboardForm): | |
43 |
|
49 | |||
44 | MAX_TEXT_LENGTH = 30000 |
|
|||
45 | MAX_IMAGE_SIZE = 8 * 1024 * 1024 |
|
|||
46 |
|
||||
47 | title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False) |
|
50 | title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False) | |
48 | text = forms.CharField(widget=forms.Textarea, required=False) |
|
51 | text = forms.CharField(widget=forms.Textarea, required=False) | |
49 | image = forms.ImageField(required=False) |
|
52 | image = forms.ImageField(required=False) | |
@@ -57,34 +60,36 b' class PostForm(NeboardForm):' | |||||
57 | title = self.cleaned_data['title'] |
|
60 | title = self.cleaned_data['title'] | |
58 | if title: |
|
61 | if title: | |
59 | if len(title) > TITLE_MAX_LENGTH: |
|
62 | if len(title) > TITLE_MAX_LENGTH: | |
60 |
raise forms.ValidationError('Title must have less than' |
|
63 | raise forms.ValidationError(_('Title must have less than %s ' | |
61 |
|
|
64 | 'characters') % | |
62 |
|
|
65 | str(TITLE_MAX_LENGTH)) | |
63 | return title |
|
66 | return title | |
64 |
|
67 | |||
65 | def clean_text(self): |
|
68 | def clean_text(self): | |
66 | text = self.cleaned_data['text'] |
|
69 | text = self.cleaned_data['text'] | |
67 | if text: |
|
70 | if text: | |
68 |
if len(text) > |
|
71 | if len(text) > MAX_TEXT_LENGTH: | |
69 |
raise forms.ValidationError('Text must have less than ' |
|
72 | raise forms.ValidationError(_('Text must have less than %s ' | |
70 |
|
|
73 | 'characters') % | |
71 |
|
|
74 | str(MAX_TEXT_LENGTH)) | |
72 | return text |
|
75 | return text | |
73 |
|
76 | |||
74 | def clean_image(self): |
|
77 | def clean_image(self): | |
75 | image = self.cleaned_data['image'] |
|
78 | image = self.cleaned_data['image'] | |
76 | if image: |
|
79 | if image: | |
77 |
if image._size > |
|
80 | if image._size > MAX_IMAGE_SIZE: | |
78 |
raise forms.ValidationError('Image must be less than ' |
|
81 | raise forms.ValidationError(_('Image must be less than %s ' | |
79 |
str( |
|
82 | 'bytes') % str(MAX_IMAGE_SIZE)) | |
80 | ' bytes.') |
|
|||
81 | return image |
|
83 | return image | |
82 |
|
84 | |||
83 | def clean(self): |
|
85 | def clean(self): | |
84 | cleaned_data = super(PostForm, self).clean() |
|
86 | cleaned_data = super(PostForm, self).clean() | |
85 |
|
87 | |||
86 | if cleaned_data['email']: |
|
88 | if not self.session: | |
87 |
|
|
89 | raise forms.ValidationError('Humans have sessions') | |
|
90 | ||||
|
91 | if cleaned_data['email']: | |||
|
92 | raise forms.ValidationError('A human cannot enter a hidden field') | |||
88 |
|
93 | |||
89 | if not self.errors: |
|
94 | if not self.errors: | |
90 | self._clean_text_image() |
|
95 | self._clean_text_image() | |
@@ -112,9 +117,8 b' class PostForm(NeboardForm):' | |||||
112 | current_delay = int(now - last_post_time) |
|
117 | current_delay = int(now - last_post_time) | |
113 |
|
118 | |||
114 | if current_delay < settings.POSTING_DELAY: |
|
119 | if current_delay < settings.POSTING_DELAY: | |
115 |
error_message = 'Wait ' |
|
120 | error_message = _('Wait %s seconds after last posting') % str( | |
116 |
|
|
121 | settings.POSTING_DELAY - current_delay) | |
117 | + ' seconds after last posting' |
|
|||
118 | self._errors['text'] = self.error_class([error_message]) |
|
122 | self._errors['text'] = self.error_class([error_message]) | |
119 |
|
123 | |||
120 | can_post = False |
|
124 | can_post = False | |
@@ -198,8 +202,11 b' class ModeratorSettingsForm(SettingsForm' | |||||
198 |
|
202 | |||
199 |
|
203 | |||
200 | class LoginForm(NeboardForm): |
|
204 | class LoginForm(NeboardForm): | |
|
205 | ||||
201 | user_id = forms.CharField() |
|
206 | user_id = forms.CharField() | |
202 |
|
207 | |||
|
208 | session = None | |||
|
209 | ||||
203 | def clean_user_id(self): |
|
210 | def clean_user_id(self): | |
204 | user_id = self.cleaned_data['user_id'] |
|
211 | user_id = self.cleaned_data['user_id'] | |
205 | if user_id: |
|
212 | if user_id: | |
@@ -209,7 +216,31 b' class LoginForm(NeboardForm):' | |||||
209 |
|
216 | |||
210 | return user_id |
|
217 | return user_id | |
211 |
|
218 | |||
|
219 | def _validate_login_speed(self): | |||
|
220 | can_post = True | |||
|
221 | ||||
|
222 | if LAST_LOGIN_TIME in self.session: | |||
|
223 | now = time.time() | |||
|
224 | last_login_time = self.session[LAST_LOGIN_TIME] | |||
|
225 | ||||
|
226 | current_delay = int(now - last_login_time) | |||
|
227 | ||||
|
228 | if current_delay < LOGIN_DELAY: | |||
|
229 | error_message = _('Wait %s minutes after last login') % str( | |||
|
230 | (LOGIN_DELAY - current_delay) / 60) | |||
|
231 | self._errors['user_id'] = self.error_class([error_message]) | |||
|
232 | ||||
|
233 | can_post = False | |||
|
234 | ||||
|
235 | if can_post: | |||
|
236 | self.session[LAST_LOGIN_TIME] = time.time() | |||
|
237 | ||||
212 | def clean(self): |
|
238 | def clean(self): | |
|
239 | if not self.session: | |||
|
240 | raise forms.ValidationError('Humans have sessions') | |||
|
241 | ||||
|
242 | self._validate_login_speed() | |||
|
243 | ||||
213 | cleaned_data = super(LoginForm, self).clean() |
|
244 | cleaned_data = super(LoginForm, self).clean() | |
214 |
|
245 | |||
215 |
return cleaned_data |
|
246 | return cleaned_data No newline at end of file |
1 | NO CONTENT: modified file, binary diff hidden |
|
NO CONTENT: modified file, binary diff hidden |
@@ -7,7 +7,7 b' msgid ""' | |||||
7 | msgstr "" |
|
7 | msgstr "" | |
8 | "Project-Id-Version: PACKAGE VERSION\n" |
|
8 | "Project-Id-Version: PACKAGE VERSION\n" | |
9 | "Report-Msgid-Bugs-To: \n" |
|
9 | "Report-Msgid-Bugs-To: \n" | |
10 |
"POT-Creation-Date: 2013-09-1 |
|
10 | "POT-Creation-Date: 2013-09-18 21:02+0300\n" | |
11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
|
11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | |
12 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
|
12 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | |
13 | "Language-Team: LANGUAGE <LL@li.org>\n" |
|
13 | "Language-Team: LANGUAGE <LL@li.org>\n" | |
@@ -18,31 +18,71 b' msgstr ""' | |||||
18 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" |
|
18 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" | |
19 | "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" |
|
19 | "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" | |
20 |
|
20 | |||
21 |
#: |
|
21 | #: authors.py:5 | |
|
22 | msgid "author" | |||
|
23 | msgstr "автор" | |||
|
24 | ||||
|
25 | #: authors.py:6 | |||
|
26 | msgid "developer" | |||
|
27 | msgstr "разработчик" | |||
|
28 | ||||
|
29 | #: authors.py:7 | |||
|
30 | msgid "javascript developer" | |||
|
31 | msgstr "разработчик javascript" | |||
|
32 | ||||
|
33 | #: authors.py:8 | |||
|
34 | msgid "designer" | |||
|
35 | msgstr "дизайнер" | |||
|
36 | ||||
|
37 | #: forms.py:63 | |||
|
38 | #, python-format | |||
|
39 | msgid "Title must have less than %s characters" | |||
|
40 | msgstr "Заголовок должен иметь меньше %s символов" | |||
|
41 | ||||
|
42 | #: forms.py:72 | |||
|
43 | #, python-format | |||
|
44 | msgid "Text must have less than %s characters" | |||
|
45 | msgstr "Текст должен быть короче %s символов" | |||
|
46 | ||||
|
47 | #: forms.py:81 | |||
|
48 | #, python-format | |||
|
49 | msgid "Image must be less than %s bytes" | |||
|
50 | msgstr "Изображение должно быть менее %s байт" | |||
|
51 | ||||
|
52 | #: forms.py:107 | |||
22 | msgid "Either text or image must be entered." |
|
53 | msgid "Either text or image must be entered." | |
23 | msgstr "Текст или картинка должны быть введены." |
|
54 | msgstr "Текст или картинка должны быть введены." | |
24 |
|
55 | |||
25 |
#: forms.py:1 |
|
56 | #: forms.py:120 | |
|
57 | #, python-format | |||
|
58 | msgid "Wait %s seconds after last posting" | |||
|
59 | msgstr "Подождите %s секунд после последнего постинга" | |||
|
60 | ||||
|
61 | #: forms.py:140 | |||
26 | msgid "Inappropriate characters in tags." |
|
62 | msgid "Inappropriate characters in tags." | |
27 | msgstr "Недопустимые символы в тегах." |
|
63 | msgstr "Недопустимые символы в тегах." | |
28 |
|
64 | |||
29 |
#: forms.py:1 |
|
65 | #: forms.py:168 forms.py:189 | |
30 | msgid "Captcha validation failed" |
|
66 | msgid "Captcha validation failed" | |
31 | msgstr "Проверка капчи провалена" |
|
67 | msgstr "Проверка капчи провалена" | |
32 |
|
68 | |||
33 |
#: forms.py:1 |
|
69 | #: forms.py:195 | |
34 | msgid "Theme" |
|
70 | msgid "Theme" | |
35 | msgstr "Тема" |
|
71 | msgstr "Тема" | |
36 |
|
72 | |||
37 |
#: forms.py: |
|
73 | #: forms.py:200 | |
38 | msgid "Enable moderation panel" |
|
74 | msgid "Enable moderation panel" | |
39 | msgstr "Включить панель модерации" |
|
75 | msgstr "Включить панель модерации" | |
40 |
|
76 | |||
41 |
#: forms.py:2 |
|
77 | #: forms.py:215 | |
42 | #, fuzzy |
|
|||
43 | msgid "No such user found" |
|
78 | msgid "No such user found" | |
44 | msgstr "Теги не найдены." |
|
79 | msgstr "Теги не найдены." | |
45 |
|
80 | |||
|
81 | #: forms.py:229 | |||
|
82 | #, python-format | |||
|
83 | msgid "Wait %s minutes after last login" | |||
|
84 | msgstr "Подождите %s минут после последнего входа" | |||
|
85 | ||||
46 | #: templates/boards/404.html:6 |
|
86 | #: templates/boards/404.html:6 | |
47 | msgid "Not found" |
|
87 | msgid "Not found" | |
48 | msgstr "Не найдено" |
|
88 | msgstr "Не найдено" | |
@@ -122,11 +162,11 b' msgstr "\xd0\xa3\xd0\xb4\xd0\xb0\xd0\xbb\xd0\xb8\xd1\x82\xd1\x8c"' | |||||
122 | msgid "Ban IP" |
|
162 | msgid "Ban IP" | |
123 | msgstr "Заблокировать IP" |
|
163 | msgstr "Заблокировать IP" | |
124 |
|
164 | |||
125 |
#: templates/boards/posting_general.html:74 templates/boards/thread.html:11 |
|
165 | #: templates/boards/posting_general.html:74 templates/boards/thread.html:121 | |
126 | msgid "replies" |
|
166 | msgid "replies" | |
127 | msgstr "ответов" |
|
167 | msgstr "ответов" | |
128 |
|
168 | |||
129 |
#: templates/boards/posting_general.html:75 templates/boards/thread.html:1 |
|
169 | #: templates/boards/posting_general.html:75 templates/boards/thread.html:122 | |
130 | msgid "images" |
|
170 | msgid "images" | |
131 | msgstr "изображений" |
|
171 | msgstr "изображений" | |
132 |
|
172 | |||
@@ -156,20 +196,24 b' msgstr "\xd0\xa2\xd0\xb5\xd0\xba\xd1\x81\xd1\x82"' | |||||
156 | msgid "Image" |
|
196 | msgid "Image" | |
157 | msgstr "Изображение" |
|
197 | msgstr "Изображение" | |
158 |
|
198 | |||
159 |
#: templates/boards/posting_general.html:1 |
|
199 | #: templates/boards/posting_general.html:155 templates/boards/thread.html:95 | |
|
200 | msgid "e-mail" | |||
|
201 | msgstr "" | |||
|
202 | ||||
|
203 | #: templates/boards/posting_general.html:168 templates/boards/thread.html:109 | |||
160 | msgid "Post" |
|
204 | msgid "Post" | |
161 | msgstr "Отправить" |
|
205 | msgstr "Отправить" | |
162 |
|
206 | |||
163 |
#: templates/boards/posting_general.html:1 |
|
207 | #: templates/boards/posting_general.html:170 | |
164 | msgid "Tags must be delimited by spaces. Text or image is required." |
|
208 | msgid "Tags must be delimited by spaces. Text or image is required." | |
165 | msgstr "" |
|
209 | msgstr "" | |
166 | "Теги должны быть разделены пробелами. Текст или изображение обязательны." |
|
210 | "Теги должны быть разделены пробелами. Текст или изображение обязательны." | |
167 |
|
211 | |||
168 |
#: templates/boards/posting_general.html:1 |
|
212 | #: templates/boards/posting_general.html:173 templates/boards/thread.html:111 | |
169 | msgid "Text syntax" |
|
213 | msgid "Text syntax" | |
170 | msgstr "Синтаксис текста" |
|
214 | msgstr "Синтаксис текста" | |
171 |
|
215 | |||
172 |
#: templates/boards/posting_general.html:1 |
|
216 | #: templates/boards/posting_general.html:183 | |
173 | msgid "Pages:" |
|
217 | msgid "Pages:" | |
174 | msgstr "Страницы: " |
|
218 | msgstr "Страницы: " | |
175 |
|
219 | |||
@@ -209,7 +253,7 b' msgstr "\xd0\xa2\xd0\xb5\xd0\xb3\xd0\xb8 \xd0\xbd\xd0\xb5 \xd0\xbd\xd0\xb0\xd0\xb9\xd0\xb4\xd0\xb5\xd0\xbd\xd1\x8b."' | |||||
209 | msgid "Reply to thread" |
|
253 | msgid "Reply to thread" | |
210 | msgstr "Ответить в тему" |
|
254 | msgstr "Ответить в тему" | |
211 |
|
255 | |||
212 |
#: templates/boards/thread.html:1 |
|
256 | #: templates/boards/thread.html:123 | |
213 | msgid "Last update: " |
|
257 | msgid "Last update: " | |
214 | msgstr "Последнее обновление: " |
|
258 | msgstr "Последнее обновление: " | |
215 |
|
259 | |||
@@ -283,15 +327,3 b' msgstr "\xd0\xa1\xd1\x81\xd1\x8b\xd0\xbb\xd0\xba\xd0\xb0 \xd0\xbd\xd0\xb0 \xd1\x81\xd0\xbe\xd0\xbe\xd0\xb1\xd1\x89\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb5"' | |||||
283 |
|
327 | |||
284 | #~ msgid "gets" |
|
328 | #~ msgid "gets" | |
285 | #~ msgstr "гетов" |
|
329 | #~ msgstr "гетов" | |
286 |
|
||||
287 | #~ msgid "author" |
|
|||
288 | #~ msgstr "автор" |
|
|||
289 |
|
||||
290 | #~ msgid "developer" |
|
|||
291 | #~ msgstr "разработчик" |
|
|||
292 |
|
||||
293 | #~ msgid "javascript developer" |
|
|||
294 | #~ msgstr "разработчик javascript" |
|
|||
295 |
|
||||
296 | #~ msgid "designer" |
|
|||
297 | #~ msgstr "дизайнер" |
|
@@ -167,6 +167,8 b' def login(request):' | |||||
167 | if request.method == 'POST': |
|
167 | if request.method == 'POST': | |
168 | form = LoginForm(request.POST, request.FILES, |
|
168 | form = LoginForm(request.POST, request.FILES, | |
169 | error_class=PlainErrorList) |
|
169 | error_class=PlainErrorList) | |
|
170 | form.session = request.session | |||
|
171 | ||||
170 | if form.is_valid(): |
|
172 | if form.is_valid(): | |
171 | user = User.objects.get(user_id=form.cleaned_data['user_id']) |
|
173 | user = User.objects.get(user_id=form.cleaned_data['user_id']) | |
172 | request.session['user_id'] = user.id |
|
174 | request.session['user_id'] = user.id |
General Comments 0
You need to be logged in to leave comments.
Login now