Show More
@@ -1,6 +1,5 b'' | |||
|
1 | 1 | import re |
|
2 | 2 | import time |
|
3 | import hashlib | |
|
4 | 3 | |
|
5 | 4 | from django import forms |
|
6 | 5 | from django.forms.util import ErrorList |
@@ -10,16 +9,17 b' from boards.mdx_neboard import formatter' | |||
|
10 | 9 | from boards.models.post import TITLE_MAX_LENGTH |
|
11 | 10 | from boards.models import PostImage, Tag |
|
12 | 11 | from neboard import settings |
|
13 | from boards import utils | |
|
14 | 12 | import boards.settings as board_settings |
|
15 | 13 | |
|
14 | REGEX_TAGS = re.compile(r'^[\w\s\d]+$', re.UNICODE) | |
|
15 | ||
|
16 | 16 | VETERAN_POSTING_DELAY = 5 |
|
17 | 17 | |
|
18 | 18 | ATTRIBUTE_PLACEHOLDER = 'placeholder' |
|
19 | 19 | |
|
20 | 20 | LAST_POST_TIME = 'last_post_time' |
|
21 | 21 | LAST_LOGIN_TIME = 'last_login_time' |
|
22 |
TEXT_PLACEHOLDER = _(' |
|
|
22 | TEXT_PLACEHOLDER = _('Type message here. Use formatting panel for more advanced usage.') | |
|
23 | 23 | TAGS_PLACEHOLDER = _('tag1 several_words_tag') |
|
24 | 24 | |
|
25 | 25 | ERROR_IMAGE_DUPLICATE = _('Such image was already posted') |
@@ -31,10 +31,13 b" LABEL_SEARCH = _('Search')" | |||
|
31 | 31 | |
|
32 | 32 | TAG_MAX_LENGTH = 20 |
|
33 | 33 | |
|
34 | REGEX_TAG = r'^[\w\d]+$' | |
|
35 | ||
|
36 | 34 | |
|
37 | 35 | class FormatPanel(forms.Textarea): |
|
36 | """ | |
|
37 | Panel for text formatting. Consists of buttons to add different tags to the | |
|
38 | form text area. | |
|
39 | """ | |
|
40 | ||
|
38 | 41 | def render(self, name, value, attrs=None): |
|
39 | 42 | output = '<div id="mark-panel">' |
|
40 | 43 | for formatter in formatters: |
@@ -59,6 +62,9 b' class PlainErrorList(ErrorList):' | |||
|
59 | 62 | |
|
60 | 63 | |
|
61 | 64 | class NeboardForm(forms.Form): |
|
65 | """ | |
|
66 | Form with neboard-specific formatting. | |
|
67 | """ | |
|
62 | 68 | |
|
63 | 69 | def as_div(self): |
|
64 | 70 | """ |
@@ -143,10 +149,7 b' class PostForm(NeboardForm):' | |||
|
143 | 149 | _('Image must be less than %s bytes') |
|
144 | 150 | % str(board_settings.MAX_IMAGE_SIZE)) |
|
145 | 151 | |
|
146 | md5 = hashlib.md5() | |
|
147 | for chunk in image.chunks(): | |
|
148 | md5.update(chunk) | |
|
149 | image_hash = md5.hexdigest() | |
|
152 | image_hash = PostImage.get_hash(image) | |
|
150 | 153 | if PostImage.objects.filter(hash=image_hash).exists(): |
|
151 | 154 | raise forms.ValidationError(ERROR_IMAGE_DUPLICATE) |
|
152 | 155 | |
@@ -203,8 +206,6 b' class PostForm(NeboardForm):' | |||
|
203 | 206 | |
|
204 | 207 | class ThreadForm(PostForm): |
|
205 | 208 | |
|
206 | regex_tags = re.compile(r'^[\w\s\d]+$', re.UNICODE) | |
|
207 | ||
|
208 | 209 | tags = forms.CharField( |
|
209 | 210 | widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}), |
|
210 | 211 | max_length=100, label=_('Tags'), required=True) |
@@ -212,17 +213,17 b' class ThreadForm(PostForm):' | |||
|
212 | 213 | def clean_tags(self): |
|
213 | 214 | tags = self.cleaned_data['tags'].strip() |
|
214 | 215 | |
|
215 |
if not tags or not |
|
|
216 | if not tags or not REGEX_TAGS.match(tags): | |
|
216 | 217 | raise forms.ValidationError( |
|
217 | 218 | _('Inappropriate characters in tags.')) |
|
218 | 219 | |
|
219 | tag_models = [] | |
|
220 | 220 | required_tag_exists = False |
|
221 | 221 | for tag in tags.split(): |
|
222 | 222 | tag_model = Tag.objects.filter(name=tag.strip().lower(), |
|
223 | required=True) | |
|
223 | required=True) | |
|
224 | 224 | if tag_model.exists(): |
|
225 | 225 | required_tag_exists = True |
|
226 | break | |
|
226 | 227 | |
|
227 | 228 | if not required_tag_exists: |
|
228 | 229 | raise forms.ValidationError(_('Need at least 1 required tag.')) |
@@ -241,65 +242,5 b' class SettingsForm(NeboardForm):' | |||
|
241 | 242 | label=_('Theme')) |
|
242 | 243 | |
|
243 | 244 | |
|
244 | class AddTagForm(NeboardForm): | |
|
245 | ||
|
246 | tag = forms.CharField(max_length=TAG_MAX_LENGTH, label=LABEL_TAG) | |
|
247 | method = forms.CharField(widget=forms.HiddenInput(), initial='add_tag') | |
|
248 | ||
|
249 | def clean_tag(self): | |
|
250 | tag = self.cleaned_data['tag'] | |
|
251 | ||
|
252 | regex_tag = re.compile(REGEX_TAG, re.UNICODE) | |
|
253 | if not regex_tag.match(tag): | |
|
254 | raise forms.ValidationError(_('Inappropriate characters in tags.')) | |
|
255 | ||
|
256 | return tag | |
|
257 | ||
|
258 | def clean(self): | |
|
259 | cleaned_data = super(AddTagForm, self).clean() | |
|
260 | ||
|
261 | return cleaned_data | |
|
262 | ||
|
263 | ||
|
264 | 245 | class SearchForm(NeboardForm): |
|
265 | 246 | query = forms.CharField(max_length=500, label=LABEL_SEARCH, required=False) |
|
266 | ||
|
267 | ||
|
268 | class LoginForm(NeboardForm): | |
|
269 | ||
|
270 | password = forms.CharField() | |
|
271 | ||
|
272 | session = None | |
|
273 | ||
|
274 | def clean_password(self): | |
|
275 | password = self.cleaned_data['password'] | |
|
276 | if board_settings.MASTER_PASSWORD != password: | |
|
277 | raise forms.ValidationError(_('Invalid master password')) | |
|
278 | ||
|
279 | return password | |
|
280 | ||
|
281 | def _validate_login_speed(self): | |
|
282 | can_post = True | |
|
283 | ||
|
284 | if LAST_LOGIN_TIME in self.session: | |
|
285 | now = time.time() | |
|
286 | last_login_time = self.session[LAST_LOGIN_TIME] | |
|
287 | ||
|
288 | current_delay = int(now - last_login_time) | |
|
289 | ||
|
290 | if current_delay < board_settings.LOGIN_TIMEOUT: | |
|
291 | error_message = _('Wait %s minutes after last login') % str( | |
|
292 | (board_settings.LOGIN_TIMEOUT - current_delay) / 60) | |
|
293 | self._errors['password'] = self.error_class([error_message]) | |
|
294 | ||
|
295 | can_post = False | |
|
296 | ||
|
297 | if can_post: | |
|
298 | self.session[LAST_LOGIN_TIME] = time.time() | |
|
299 | ||
|
300 | def clean(self): | |
|
301 | self._validate_login_speed() | |
|
302 | ||
|
303 | cleaned_data = super(LoginForm, self).clean() | |
|
304 | ||
|
305 | return cleaned_data |
@@ -56,10 +56,7 b' class PostImage(models.Model, Viewable):' | |||
|
56 | 56 | """ |
|
57 | 57 | |
|
58 | 58 | if not self.pk and self.image: |
|
59 | md5 = hashlib.md5() | |
|
60 | for chunk in self.image.chunks(): | |
|
61 | md5.update(chunk) | |
|
62 | self.hash = md5.hexdigest() | |
|
59 | self.hash = PostImage.get_hash(self.image) | |
|
63 | 60 | super(PostImage, self).save(*args, **kwargs) |
|
64 | 61 | |
|
65 | 62 | def __str__(self): |
@@ -81,3 +78,13 b' class PostImage(models.Model, Viewable):' | |||
|
81 | 78 | self.image.url_200x150, |
|
82 | 79 | str(self.hash), str(self.pre_width), |
|
83 | 80 | str(self.pre_height), str(self.width), str(self.height)) |
|
81 | ||
|
82 | @staticmethod | |
|
83 | def get_hash(image): | |
|
84 | """ | |
|
85 | Gets hash of an image. | |
|
86 | """ | |
|
87 | md5 = hashlib.md5() | |
|
88 | for chunk in image.chunks(): | |
|
89 | md5.update(chunk) | |
|
90 | return md5.hexdigest() |
General Comments 0
You need to be logged in to leave comments.
Login now