##// END OF EJS Templates
Added localizations to forms. Do not allow users without session to post.
neko259 -
r211:5a120222 default
parent child Browse files
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 }
@@ -1,215 +1,246 b''
1 import re
1 import re
2 from captcha.fields import CaptchaField
2 from captcha.fields import CaptchaField
3 from django import forms
3 from django import forms
4 from django.forms.util import ErrorList
4 from django.forms.util import ErrorList
5 from django.utils.translation import ugettext_lazy as _
5 from django.utils.translation import ugettext_lazy as _
6 import time
6 import time
7 from boards.models import TITLE_MAX_LENGTH, User
7 from boards.models import TITLE_MAX_LENGTH, User
8 from neboard import settings
8 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):
15 def __unicode__(self):
21 def __unicode__(self):
16 return self.as_text()
22 return self.as_text()
17
23
18 def as_text(self):
24 def as_text(self):
19 return ''.join([u'(!) %s ' % e for e in self])
25 return ''.join([u'(!) %s ' % e for e in self])
20
26
21
27
22 class NeboardForm(forms.Form):
28 class NeboardForm(forms.Form):
23
29
24 def as_p(self):
30 def as_p(self):
25 "Returns this form rendered as HTML <p>s."
31 "Returns this form rendered as HTML <p>s."
26 return self._html_output(
32 return self._html_output(
27 normal_row='<div class="form-row">'
33 normal_row='<div class="form-row">'
28 '<div class="form-label">'
34 '<div class="form-label">'
29 '%(label)s'
35 '%(label)s'
30 '</div>'
36 '</div>'
31 '<div class="form-input">'
37 '<div class="form-input">'
32 '%(field)s'
38 '%(field)s'
33 '</div>'
39 '</div>'
34 '%(help_text)s'
40 '%(help_text)s'
35 '</div>',
41 '</div>',
36 error_row='<div class="form-errors">%s</div>',
42 error_row='<div class="form-errors">%s</div>',
37 row_ender='</p>',
43 row_ender='</p>',
38 help_text_html=' <span class="helptext">%s</span>',
44 help_text_html=' <span class="helptext">%s</span>',
39 errors_on_separate_row=True)
45 errors_on_separate_row=True)
40
46
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)
50
53
51 # This field is for spam prevention only
54 # This field is for spam prevention only
52 email = forms.CharField(max_length=100, required=False)
55 email = forms.CharField(max_length=100, required=False)
53
56
54 session = None
57 session = None
55
58
56 def clean_title(self):
59 def clean_title(self):
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 str(TITLE_MAX_LENGTH) +
64 'characters') %
62 ' characters.')
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) > self.MAX_TEXT_LENGTH:
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 str(self.MAX_TEXT_LENGTH) +
73 'characters') %
71 ' characters.')
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 > self.MAX_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(self.MAX_IMAGE_SIZE) +
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 raise forms.ValidationError('A human cannot enter a hidden field')
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()
91
96
92 if not self.errors and self.session:
97 if not self.errors and self.session:
93 self._validate_posting_speed()
98 self._validate_posting_speed()
94
99
95 return cleaned_data
100 return cleaned_data
96
101
97 def _clean_text_image(self):
102 def _clean_text_image(self):
98 text = self.cleaned_data.get('text')
103 text = self.cleaned_data.get('text')
99 image = self.cleaned_data.get('image')
104 image = self.cleaned_data.get('image')
100
105
101 if (not text) and (not image):
106 if (not text) and (not image):
102 error_message = _('Either text or image must be entered.')
107 error_message = _('Either text or image must be entered.')
103 self._errors['text'] = self.error_class([error_message])
108 self._errors['text'] = self.error_class([error_message])
104
109
105 def _validate_posting_speed(self):
110 def _validate_posting_speed(self):
106 can_post = True
111 can_post = True
107
112
108 if LAST_POST_TIME in self.session:
113 if LAST_POST_TIME in self.session:
109 now = time.time()
114 now = time.time()
110 last_post_time = self.session[LAST_POST_TIME]
115 last_post_time = self.session[LAST_POST_TIME]
111
116
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 ' + str(settings.POSTING_DELAY -
120 error_message = _('Wait %s seconds after last posting') % str(
116 current_delay)\
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
121
125
122 if can_post:
126 if can_post:
123 self.session[LAST_POST_TIME] = time.time()
127 self.session[LAST_POST_TIME] = time.time()
124
128
125
129
126 class ThreadForm(PostForm):
130 class ThreadForm(PostForm):
127 regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE)
131 regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE)
128 tags = forms.CharField(max_length=100)
132 tags = forms.CharField(max_length=100)
129
133
130 def clean_tags(self):
134 def clean_tags(self):
131 tags = self.cleaned_data['tags']
135 tags = self.cleaned_data['tags']
132
136
133 if tags:
137 if tags:
134 if not self.regex_tags.match(tags):
138 if not self.regex_tags.match(tags):
135 raise forms.ValidationError(
139 raise forms.ValidationError(
136 _('Inappropriate characters in tags.'))
140 _('Inappropriate characters in tags.'))
137
141
138 return tags
142 return tags
139
143
140 def clean(self):
144 def clean(self):
141 cleaned_data = super(ThreadForm, self).clean()
145 cleaned_data = super(ThreadForm, self).clean()
142
146
143 return cleaned_data
147 return cleaned_data
144
148
145
149
146 class PostCaptchaForm(PostForm):
150 class PostCaptchaForm(PostForm):
147 captcha = CaptchaField()
151 captcha = CaptchaField()
148
152
149 def __init__(self, *args, **kwargs):
153 def __init__(self, *args, **kwargs):
150 self.request = kwargs['request']
154 self.request = kwargs['request']
151 del kwargs['request']
155 del kwargs['request']
152
156
153 super(PostCaptchaForm, self).__init__(*args, **kwargs)
157 super(PostCaptchaForm, self).__init__(*args, **kwargs)
154
158
155 def clean(self):
159 def clean(self):
156 cleaned_data = super(PostCaptchaForm, self).clean()
160 cleaned_data = super(PostCaptchaForm, self).clean()
157
161
158 success = self.is_valid()
162 success = self.is_valid()
159 utils.update_captcha_access(self.request, success)
163 utils.update_captcha_access(self.request, success)
160
164
161 if success:
165 if success:
162 return cleaned_data
166 return cleaned_data
163 else:
167 else:
164 raise forms.ValidationError(_("Captcha validation failed"))
168 raise forms.ValidationError(_("Captcha validation failed"))
165
169
166
170
167 class ThreadCaptchaForm(ThreadForm):
171 class ThreadCaptchaForm(ThreadForm):
168 captcha = CaptchaField()
172 captcha = CaptchaField()
169
173
170 def __init__(self, *args, **kwargs):
174 def __init__(self, *args, **kwargs):
171 self.request = kwargs['request']
175 self.request = kwargs['request']
172 del kwargs['request']
176 del kwargs['request']
173
177
174 super(ThreadCaptchaForm, self).__init__(*args, **kwargs)
178 super(ThreadCaptchaForm, self).__init__(*args, **kwargs)
175
179
176 def clean(self):
180 def clean(self):
177 cleaned_data = super(ThreadCaptchaForm, self).clean()
181 cleaned_data = super(ThreadCaptchaForm, self).clean()
178
182
179 success = self.is_valid()
183 success = self.is_valid()
180 utils.update_captcha_access(self.request, success)
184 utils.update_captcha_access(self.request, success)
181
185
182 if success:
186 if success:
183 return cleaned_data
187 return cleaned_data
184 else:
188 else:
185 raise forms.ValidationError(_("Captcha validation failed"))
189 raise forms.ValidationError(_("Captcha validation failed"))
186
190
187
191
188 class SettingsForm(NeboardForm):
192 class SettingsForm(NeboardForm):
189
193
190 theme = forms.ChoiceField(choices=settings.THEMES,
194 theme = forms.ChoiceField(choices=settings.THEMES,
191 label=_('Theme'))
195 label=_('Theme'))
192
196
193
197
194 class ModeratorSettingsForm(SettingsForm):
198 class ModeratorSettingsForm(SettingsForm):
195
199
196 moderate = forms.BooleanField(required=False, label=_('Enable moderation '
200 moderate = forms.BooleanField(required=False, label=_('Enable moderation '
197 'panel'))
201 'panel'))
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:
206 users = User.objects.filter(user_id=user_id)
213 users = User.objects.filter(user_id=user_id)
207 if len(users) == 0:
214 if len(users) == 0:
208 raise forms.ValidationError(_('No such user found'))
215 raise forms.ValidationError(_('No such user found'))
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
@@ -1,297 +1,329 b''
1 # SOME DESCRIPTIVE TITLE.
1 # SOME DESCRIPTIVE TITLE.
2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 # This file is distributed under the same license as the PACKAGE package.
3 # This file is distributed under the same license as the PACKAGE package.
4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5 #
5 #
6 msgid ""
6 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-17 21:58+0300\n"
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"
14 "Language: ru\n"
14 "Language: ru\n"
15 "MIME-Version: 1.0\n"
15 "MIME-Version: 1.0\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
17 "Content-Transfer-Encoding: 8bit\n"
17 "Content-Transfer-Encoding: 8bit\n"
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 #: forms.py:96
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:130
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:158 forms.py:179
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:185
69 #: forms.py:195
34 msgid "Theme"
70 msgid "Theme"
35 msgstr "Π’Π΅ΠΌΠ°"
71 msgstr "Π’Π΅ΠΌΠ°"
36
72
37 #: forms.py:190
73 #: forms.py:200
38 msgid "Enable moderation panel"
74 msgid "Enable moderation panel"
39 msgstr "Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ панСль ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ†ΠΈΠΈ"
75 msgstr "Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ панСль ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ†ΠΈΠΈ"
40
76
41 #: forms.py:202
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 "НС найдСно"
49
89
50 #: templates/boards/404.html:12
90 #: templates/boards/404.html:12
51 msgid "This page does not exist"
91 msgid "This page does not exist"
52 msgstr "Π­Ρ‚ΠΎΠΉ страницы Π½Π΅ сущСствуСт"
92 msgstr "Π­Ρ‚ΠΎΠΉ страницы Π½Π΅ сущСствуСт"
53
93
54 #: templates/boards/authors.html:6
94 #: templates/boards/authors.html:6
55 msgid "Authors"
95 msgid "Authors"
56 msgstr "Авторы"
96 msgstr "Авторы"
57
97
58 #: templates/boards/authors.html:24
98 #: templates/boards/authors.html:24
59 msgid "Distributed under the"
99 msgid "Distributed under the"
60 msgstr "РаспространяСтся ΠΏΠΎΠ΄"
100 msgstr "РаспространяСтся ΠΏΠΎΠ΄"
61
101
62 #: templates/boards/authors.html:26
102 #: templates/boards/authors.html:26
63 msgid "license"
103 msgid "license"
64 msgstr "Π»ΠΈΡ†Π΅Π½Π·ΠΈΠ΅ΠΉ"
104 msgstr "Π»ΠΈΡ†Π΅Π½Π·ΠΈΠ΅ΠΉ"
65
105
66 #: templates/boards/authors.html:28
106 #: templates/boards/authors.html:28
67 msgid "Repository"
107 msgid "Repository"
68 msgstr "Π Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ"
108 msgstr "Π Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ"
69
109
70 #: templates/boards/base.html:12
110 #: templates/boards/base.html:12
71 msgid "Feed"
111 msgid "Feed"
72 msgstr "Π›Π΅Π½Ρ‚Π°"
112 msgstr "Π›Π΅Π½Ρ‚Π°"
73
113
74 #: templates/boards/base.html:29
114 #: templates/boards/base.html:29
75 msgid "All threads"
115 msgid "All threads"
76 msgstr "ВсС Ρ‚Π΅ΠΌΡ‹"
116 msgstr "ВсС Ρ‚Π΅ΠΌΡ‹"
77
117
78 #: templates/boards/base.html:34
118 #: templates/boards/base.html:34
79 msgid "Tag management"
119 msgid "Tag management"
80 msgstr "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ‚Π΅Π³Π°ΠΌΠΈ"
120 msgstr "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ‚Π΅Π³Π°ΠΌΠΈ"
81
121
82 #: templates/boards/base.html:36
122 #: templates/boards/base.html:36
83 msgid "Settings"
123 msgid "Settings"
84 msgstr "Настройки"
124 msgstr "Настройки"
85
125
86 #: templates/boards/base.html:43 templates/boards/login.html:6
126 #: templates/boards/base.html:43 templates/boards/login.html:6
87 #: templates/boards/login.html.py:21
127 #: templates/boards/login.html.py:21
88 msgid "Login"
128 msgid "Login"
89 msgstr "Π’Ρ…ΠΎΠ΄"
129 msgstr "Π’Ρ…ΠΎΠ΄"
90
130
91 #: templates/boards/base.html:44
131 #: templates/boards/base.html:44
92 msgid "Up"
132 msgid "Up"
93 msgstr "Π’Π²Π΅Ρ€Ρ…"
133 msgstr "Π’Π²Π΅Ρ€Ρ…"
94
134
95 #: templates/boards/login.html:15
135 #: templates/boards/login.html:15
96 msgid "User ID"
136 msgid "User ID"
97 msgstr "ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ"
137 msgstr "ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ"
98
138
99 #: templates/boards/login.html:24
139 #: templates/boards/login.html:24
100 msgid "Insert your user id above"
140 msgid "Insert your user id above"
101 msgstr "Π’ΡΡ‚Π°Π²ΡŒΡ‚Π΅ свой ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π²Ρ‹ΡˆΠ΅"
141 msgstr "Π’ΡΡ‚Π°Π²ΡŒΡ‚Π΅ свой ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π²Ρ‹ΡˆΠ΅"
102
142
103 #: templates/boards/posting_general.html:19
143 #: templates/boards/posting_general.html:19
104 msgid "Tag: "
144 msgid "Tag: "
105 msgstr "Π’Π΅Π³: "
145 msgstr "Π’Π΅Π³: "
106
146
107 #: templates/boards/posting_general.html:44
147 #: templates/boards/posting_general.html:44
108 #: templates/boards/posting_general.html:100 templates/boards/thread.html:29
148 #: templates/boards/posting_general.html:100 templates/boards/thread.html:29
109 #: templates/boards/rss/post.html:5
149 #: templates/boards/rss/post.html:5
110 msgid "Post image"
150 msgid "Post image"
111 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ сообщСния"
151 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ сообщСния"
112
152
113 #: templates/boards/posting_general.html:57
153 #: templates/boards/posting_general.html:57
114 msgid "Reply"
154 msgid "Reply"
115 msgstr "ΠžΡ‚Π²Π΅Ρ‚"
155 msgstr "ΠžΡ‚Π²Π΅Ρ‚"
116
156
117 #: templates/boards/posting_general.html:62 templates/boards/thread.html:47
157 #: templates/boards/posting_general.html:62 templates/boards/thread.html:47
118 msgid "Delete"
158 msgid "Delete"
119 msgstr "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ"
159 msgstr "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ"
120
160
121 #: templates/boards/posting_general.html:65 templates/boards/thread.html:50
161 #: templates/boards/posting_general.html:65 templates/boards/thread.html:50
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:116
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:117
169 #: templates/boards/posting_general.html:75 templates/boards/thread.html:122
130 msgid "images"
170 msgid "images"
131 msgstr "ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ"
171 msgstr "ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ"
132
172
133 #: templates/boards/posting_general.html:77
173 #: templates/boards/posting_general.html:77
134 #: templates/boards/posting_general.html:150 templates/boards/tags.html:7
174 #: templates/boards/posting_general.html:150 templates/boards/tags.html:7
135 #: templates/boards/thread.html:60 templates/boards/rss/post.html:10
175 #: templates/boards/thread.html:60 templates/boards/rss/post.html:10
136 msgid "Tags"
176 msgid "Tags"
137 msgstr "Π’Π΅Π³ΠΈ"
177 msgstr "Π’Π΅Π³ΠΈ"
138
178
139 #: templates/boards/posting_general.html:126
179 #: templates/boards/posting_general.html:126
140 msgid "No threads exist. Create the first one!"
180 msgid "No threads exist. Create the first one!"
141 msgstr "НСт Ρ‚Π΅ΠΌ. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π²ΡƒΡŽ!"
181 msgstr "НСт Ρ‚Π΅ΠΌ. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π²ΡƒΡŽ!"
142
182
143 #: templates/boards/posting_general.html:132
183 #: templates/boards/posting_general.html:132
144 msgid "Create new thread"
184 msgid "Create new thread"
145 msgstr "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ‚Π΅ΠΌΡƒ"
185 msgstr "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ‚Π΅ΠΌΡƒ"
146
186
147 #: templates/boards/posting_general.html:135 templates/boards/thread.html:80
187 #: templates/boards/posting_general.html:135 templates/boards/thread.html:80
148 msgid "Title"
188 msgid "Title"
149 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ"
189 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ"
150
190
151 #: templates/boards/posting_general.html:140 templates/boards/thread.html:85
191 #: templates/boards/posting_general.html:140 templates/boards/thread.html:85
152 msgid "Text"
192 msgid "Text"
153 msgstr "ВСкст"
193 msgstr "ВСкст"
154
194
155 #: templates/boards/posting_general.html:145 templates/boards/thread.html:90
195 #: templates/boards/posting_general.html:145 templates/boards/thread.html:90
156 msgid "Image"
196 msgid "Image"
157 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅"
197 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅"
158
198
159 #: templates/boards/posting_general.html:163 templates/boards/thread.html:104
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:165
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:168 templates/boards/thread.html:106
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:178
216 #: templates/boards/posting_general.html:183
173 msgid "Pages:"
217 msgid "Pages:"
174 msgstr "Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Ρ‹: "
218 msgstr "Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Ρ‹: "
175
219
176 #: templates/boards/settings.html:13
220 #: templates/boards/settings.html:13
177 msgid "User:"
221 msgid "User:"
178 msgstr "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ:"
222 msgstr "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ:"
179
223
180 #: templates/boards/settings.html:15
224 #: templates/boards/settings.html:15
181 msgid "You are moderator."
225 msgid "You are moderator."
182 msgstr "Π’Ρ‹ ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ‚ΠΎΡ€."
226 msgstr "Π’Ρ‹ ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ‚ΠΎΡ€."
183
227
184 #: templates/boards/settings.html:18
228 #: templates/boards/settings.html:18
185 msgid "Posts:"
229 msgid "Posts:"
186 msgstr "Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠΉ:"
230 msgstr "Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠΉ:"
187
231
188 #: templates/boards/settings.html:19
232 #: templates/boards/settings.html:19
189 msgid "First access:"
233 msgid "First access:"
190 msgstr "ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ доступ:"
234 msgstr "ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ доступ:"
191
235
192 #: templates/boards/settings.html:21
236 #: templates/boards/settings.html:21
193 msgid "Last access:"
237 msgid "Last access:"
194 msgstr "ПослСдний доступ: "
238 msgstr "ПослСдний доступ: "
195
239
196 #: templates/boards/settings.html:30
240 #: templates/boards/settings.html:30
197 msgid "Save"
241 msgid "Save"
198 msgstr "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ"
242 msgstr "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ"
199
243
200 #: templates/boards/tags.html:17
244 #: templates/boards/tags.html:17
201 msgid "threads"
245 msgid "threads"
202 msgstr "Ρ‚Π΅ΠΌ"
246 msgstr "Ρ‚Π΅ΠΌ"
203
247
204 #: templates/boards/tags.html:28
248 #: templates/boards/tags.html:28
205 msgid "No tags found."
249 msgid "No tags found."
206 msgstr "Π’Π΅Π³ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹."
250 msgstr "Π’Π΅Π³ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹."
207
251
208 #: templates/boards/thread.html:77
252 #: templates/boards/thread.html:77
209 msgid "Reply to thread"
253 msgid "Reply to thread"
210 msgstr "ΠžΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π² Ρ‚Π΅ΠΌΡƒ"
254 msgstr "ΠžΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π² Ρ‚Π΅ΠΌΡƒ"
211
255
212 #: templates/boards/thread.html:118
256 #: templates/boards/thread.html:123
213 msgid "Last update: "
257 msgid "Last update: "
214 msgstr "ПослСднСС обновлСниС: "
258 msgstr "ПослСднСС обновлСниС: "
215
259
216 #: templates/boards/staticpages/banned.html:6
260 #: templates/boards/staticpages/banned.html:6
217 msgid "Banned"
261 msgid "Banned"
218 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½"
262 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½"
219
263
220 #: templates/boards/staticpages/banned.html:11
264 #: templates/boards/staticpages/banned.html:11
221 msgid "Your IP address has been banned. Contact the administrator"
265 msgid "Your IP address has been banned. Contact the administrator"
222 msgstr "Π’Π°Ρˆ IP адрСс Π±Ρ‹Π» Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½. Π‘Π²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с администратором"
266 msgstr "Π’Π°Ρˆ IP адрСс Π±Ρ‹Π» Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½. Π‘Π²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с администратором"
223
267
224 #: templates/boards/staticpages/help.html:6
268 #: templates/boards/staticpages/help.html:6
225 #: templates/boards/staticpages/help.html:10
269 #: templates/boards/staticpages/help.html:10
226 msgid "Syntax"
270 msgid "Syntax"
227 msgstr "Бинтаксис"
271 msgstr "Бинтаксис"
228
272
229 #: templates/boards/staticpages/help.html:11
273 #: templates/boards/staticpages/help.html:11
230 msgid "2 line breaks for a new line."
274 msgid "2 line breaks for a new line."
231 msgstr "2 ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π° строки ΡΠΎΠ·Π΄Π°ΡŽΡ‚ Π½ΠΎΠ²Ρ‹ΠΉ Π°Π±Π·Π°Ρ†."
275 msgstr "2 ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π° строки ΡΠΎΠ·Π΄Π°ΡŽΡ‚ Π½ΠΎΠ²Ρ‹ΠΉ Π°Π±Π·Π°Ρ†."
232
276
233 #: templates/boards/staticpages/help.html:12
277 #: templates/boards/staticpages/help.html:12
234 msgid "Italic text"
278 msgid "Italic text"
235 msgstr "ΠšΡƒΡ€ΡΠΈΠ²Π½Ρ‹ΠΉ тСкст"
279 msgstr "ΠšΡƒΡ€ΡΠΈΠ²Π½Ρ‹ΠΉ тСкст"
236
280
237 #: templates/boards/staticpages/help.html:13
281 #: templates/boards/staticpages/help.html:13
238 msgid "Bold text"
282 msgid "Bold text"
239 msgstr "ΠŸΠΎΠ»ΡƒΠΆΠΈΡ€Π½Ρ‹ΠΉ тСкст"
283 msgstr "ΠŸΠΎΠ»ΡƒΠΆΠΈΡ€Π½Ρ‹ΠΉ тСкст"
240
284
241 #: templates/boards/staticpages/help.html:14
285 #: templates/boards/staticpages/help.html:14
242 msgid "Spoiler"
286 msgid "Spoiler"
243 msgstr "Π‘ΠΏΠΎΠΉΠ»Π΅Ρ€"
287 msgstr "Π‘ΠΏΠΎΠΉΠ»Π΅Ρ€"
244
288
245 #: templates/boards/staticpages/help.html:15
289 #: templates/boards/staticpages/help.html:15
246 msgid "Comment"
290 msgid "Comment"
247 msgstr "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ"
291 msgstr "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ"
248
292
249 #: templates/boards/staticpages/help.html:16
293 #: templates/boards/staticpages/help.html:16
250 msgid "Quote"
294 msgid "Quote"
251 msgstr "Π¦ΠΈΡ‚Π°Ρ‚Π°"
295 msgstr "Π¦ΠΈΡ‚Π°Ρ‚Π°"
252
296
253 #: templates/boards/staticpages/help.html:17
297 #: templates/boards/staticpages/help.html:17
254 msgid "Link to a post"
298 msgid "Link to a post"
255 msgstr "Бсылка Π½Π° сообщСниС"
299 msgstr "Бсылка Π½Π° сообщСниС"
256
300
257 #~ msgid "Remove"
301 #~ msgid "Remove"
258 #~ msgstr "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ"
302 #~ msgstr "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ"
259
303
260 #~ msgid "Add"
304 #~ msgid "Add"
261 #~ msgstr "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ"
305 #~ msgstr "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ"
262
306
263 #~ msgid "Basic markdown syntax."
307 #~ msgid "Basic markdown syntax."
264 #~ msgstr "Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ синтаксис markdown."
308 #~ msgstr "Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ синтаксис markdown."
265
309
266 #~ msgid "Example: "
310 #~ msgid "Example: "
267 #~ msgstr "ΠŸΡ€ΠΈΠΌΠ΅Ρ€: "
311 #~ msgstr "ΠŸΡ€ΠΈΠΌΠ΅Ρ€: "
268
312
269 #~ msgid "italic"
313 #~ msgid "italic"
270 #~ msgstr "курсив"
314 #~ msgstr "курсив"
271
315
272 #~ msgid "bold"
316 #~ msgid "bold"
273 #~ msgstr "ΠΏΠΎΠ»ΡƒΠΆΠΈΡ€Π½Ρ‹ΠΉ"
317 #~ msgstr "ΠΏΠΎΠ»ΡƒΠΆΠΈΡ€Π½Ρ‹ΠΉ"
274
318
275 #~ msgid "tags"
319 #~ msgid "tags"
276 #~ msgstr "Ρ‚Π΅Π³ΠΎΠ²"
320 #~ msgstr "Ρ‚Π΅Π³ΠΎΠ²"
277
321
278 #~ msgid "Get!"
322 #~ msgid "Get!"
279 #~ msgstr "Π“Π΅Ρ‚!"
323 #~ msgstr "Π“Π΅Ρ‚!"
280
324
281 #~ msgid "View"
325 #~ msgid "View"
282 #~ msgstr "ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€"
326 #~ msgstr "ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€"
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 "Π΄ΠΈΠ·Π°ΠΉΠ½Π΅Ρ€"
@@ -1,369 +1,371 b''
1 import hashlib
1 import hashlib
2 import string
2 import string
3 from django.core.urlresolvers import reverse
3 from django.core.urlresolvers import reverse
4 from django.http import HttpResponseRedirect
4 from django.http import HttpResponseRedirect
5 from django.template import RequestContext
5 from django.template import RequestContext
6 from django.shortcuts import render, redirect, get_object_or_404
6 from django.shortcuts import render, redirect, get_object_or_404
7 from django.utils import timezone
7 from django.utils import timezone
8
8
9 from boards import forms
9 from boards import forms
10 import boards
10 import boards
11 from boards import utils
11 from boards import utils
12 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
12 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
13 ThreadCaptchaForm, PostCaptchaForm, LoginForm, ModeratorSettingsForm
13 ThreadCaptchaForm, PostCaptchaForm, LoginForm, ModeratorSettingsForm
14
14
15 from boards.models import Post, Tag, Ban, User, RANK_USER, SETTING_MODERATE
15 from boards.models import Post, Tag, Ban, User, RANK_USER, SETTING_MODERATE
16 from boards import authors
16 from boards import authors
17 from boards.utils import get_client_ip
17 from boards.utils import get_client_ip
18 import neboard
18 import neboard
19
19
20
20
21 def index(request, page=0):
21 def index(request, page=0):
22 context = _init_default_context(request)
22 context = _init_default_context(request)
23
23
24 if utils.need_include_captcha(request):
24 if utils.need_include_captcha(request):
25 threadFormClass = ThreadCaptchaForm
25 threadFormClass = ThreadCaptchaForm
26 kwargs = {'request': request}
26 kwargs = {'request': request}
27 else:
27 else:
28 threadFormClass = ThreadForm
28 threadFormClass = ThreadForm
29 kwargs = {}
29 kwargs = {}
30
30
31 if request.method == 'POST':
31 if request.method == 'POST':
32 form = threadFormClass(request.POST, request.FILES,
32 form = threadFormClass(request.POST, request.FILES,
33 error_class=PlainErrorList, **kwargs)
33 error_class=PlainErrorList, **kwargs)
34 form.session = request.session
34 form.session = request.session
35
35
36 if form.is_valid():
36 if form.is_valid():
37 return _new_post(request, form)
37 return _new_post(request, form)
38 else:
38 else:
39 form = threadFormClass(error_class=PlainErrorList, **kwargs)
39 form = threadFormClass(error_class=PlainErrorList, **kwargs)
40
40
41 threads = []
41 threads = []
42 for thread in Post.objects.get_threads(page=int(page)):
42 for thread in Post.objects.get_threads(page=int(page)):
43 threads.append({'thread': thread,
43 threads.append({'thread': thread,
44 'bumpable': thread.can_bump()})
44 'bumpable': thread.can_bump()})
45
45
46 context['threads'] = None if len(threads) == 0 else threads
46 context['threads'] = None if len(threads) == 0 else threads
47 context['form'] = form
47 context['form'] = form
48 context['pages'] = range(Post.objects.get_thread_page_count())
48 context['pages'] = range(Post.objects.get_thread_page_count())
49
49
50 return render(request, 'boards/posting_general.html',
50 return render(request, 'boards/posting_general.html',
51 context)
51 context)
52
52
53
53
54 def _new_post(request, form, thread_id=boards.models.NO_PARENT):
54 def _new_post(request, form, thread_id=boards.models.NO_PARENT):
55 """Add a new post (in thread or as a reply)."""
55 """Add a new post (in thread or as a reply)."""
56
56
57 ip = get_client_ip(request)
57 ip = get_client_ip(request)
58 is_banned = Ban.objects.filter(ip=ip).exists()
58 is_banned = Ban.objects.filter(ip=ip).exists()
59
59
60 if is_banned:
60 if is_banned:
61 return redirect(you_are_banned)
61 return redirect(you_are_banned)
62
62
63 data = form.cleaned_data
63 data = form.cleaned_data
64
64
65 title = data['title']
65 title = data['title']
66 text = data['text']
66 text = data['text']
67
67
68 if 'image' in data.keys():
68 if 'image' in data.keys():
69 image = data['image']
69 image = data['image']
70 else:
70 else:
71 image = None
71 image = None
72
72
73 tags = []
73 tags = []
74
74
75 new_thread = thread_id == boards.models.NO_PARENT
75 new_thread = thread_id == boards.models.NO_PARENT
76 if new_thread:
76 if new_thread:
77 tag_strings = data['tags']
77 tag_strings = data['tags']
78
78
79 if tag_strings:
79 if tag_strings:
80 tag_strings = tag_strings.split(' ')
80 tag_strings = tag_strings.split(' ')
81 for tag_name in tag_strings:
81 for tag_name in tag_strings:
82 tag_name = string.lower(tag_name.strip())
82 tag_name = string.lower(tag_name.strip())
83 if len(tag_name) > 0:
83 if len(tag_name) > 0:
84 tag, created = Tag.objects.get_or_create(name=tag_name)
84 tag, created = Tag.objects.get_or_create(name=tag_name)
85 tags.append(tag)
85 tags.append(tag)
86
86
87 op = None if thread_id == boards.models.NO_PARENT else \
87 op = None if thread_id == boards.models.NO_PARENT else \
88 get_object_or_404(Post, id=thread_id)
88 get_object_or_404(Post, id=thread_id)
89 post = Post.objects.create_post(title=title, text=text, ip=ip,
89 post = Post.objects.create_post(title=title, text=text, ip=ip,
90 thread=op, image=image,
90 thread=op, image=image,
91 tags=tags, user=_get_user(request))
91 tags=tags, user=_get_user(request))
92
92
93 thread_to_show = (post.id if new_thread else thread_id)
93 thread_to_show = (post.id if new_thread else thread_id)
94
94
95 if new_thread:
95 if new_thread:
96 return redirect(thread, post_id=thread_to_show)
96 return redirect(thread, post_id=thread_to_show)
97 else:
97 else:
98 return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) +
98 return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) +
99 '#' + str(post.id))
99 '#' + str(post.id))
100
100
101
101
102 def tag(request, tag_name, page=0):
102 def tag(request, tag_name, page=0):
103 """Get all tag threads (posts without a parent)."""
103 """Get all tag threads (posts without a parent)."""
104
104
105 tag = get_object_or_404(Tag, name=tag_name)
105 tag = get_object_or_404(Tag, name=tag_name)
106 threads = []
106 threads = []
107 for thread in Post.objects.get_threads(tag=tag, page=int(page)):
107 for thread in Post.objects.get_threads(tag=tag, page=int(page)):
108 threads.append({'thread': thread,
108 threads.append({'thread': thread,
109 'bumpable': thread.can_bump()})
109 'bumpable': thread.can_bump()})
110
110
111 if request.method == 'POST':
111 if request.method == 'POST':
112 form = ThreadForm(request.POST, request.FILES,
112 form = ThreadForm(request.POST, request.FILES,
113 error_class=PlainErrorList)
113 error_class=PlainErrorList)
114 if form.is_valid():
114 if form.is_valid():
115 return _new_post(request, form)
115 return _new_post(request, form)
116 else:
116 else:
117 form = forms.ThreadForm(initial={'tags': tag_name},
117 form = forms.ThreadForm(initial={'tags': tag_name},
118 error_class=PlainErrorList)
118 error_class=PlainErrorList)
119
119
120 context = _init_default_context(request)
120 context = _init_default_context(request)
121 context['threads'] = None if len(threads) == 0 else threads
121 context['threads'] = None if len(threads) == 0 else threads
122 context['tag'] = tag
122 context['tag'] = tag
123 context['pages'] = range(Post.objects.get_thread_page_count(tag=tag))
123 context['pages'] = range(Post.objects.get_thread_page_count(tag=tag))
124
124
125 context['form'] = form
125 context['form'] = form
126
126
127 return render(request, 'boards/posting_general.html',
127 return render(request, 'boards/posting_general.html',
128 context)
128 context)
129
129
130
130
131 def thread(request, post_id):
131 def thread(request, post_id):
132 """Get all thread posts"""
132 """Get all thread posts"""
133
133
134 if utils.need_include_captcha(request):
134 if utils.need_include_captcha(request):
135 postFormClass = PostCaptchaForm
135 postFormClass = PostCaptchaForm
136 kwargs = {'request': request}
136 kwargs = {'request': request}
137 else:
137 else:
138 postFormClass = PostForm
138 postFormClass = PostForm
139 kwargs = {}
139 kwargs = {}
140
140
141 if request.method == 'POST':
141 if request.method == 'POST':
142 form = postFormClass(request.POST, request.FILES,
142 form = postFormClass(request.POST, request.FILES,
143 error_class=PlainErrorList, **kwargs)
143 error_class=PlainErrorList, **kwargs)
144 form.session = request.session
144 form.session = request.session
145
145
146 if form.is_valid():
146 if form.is_valid():
147 return _new_post(request, form, post_id)
147 return _new_post(request, form, post_id)
148 else:
148 else:
149 form = postFormClass(error_class=PlainErrorList, **kwargs)
149 form = postFormClass(error_class=PlainErrorList, **kwargs)
150
150
151 posts = Post.objects.get_thread(post_id)
151 posts = Post.objects.get_thread(post_id)
152
152
153 context = _init_default_context(request)
153 context = _init_default_context(request)
154
154
155 context['posts'] = posts
155 context['posts'] = posts
156 context['form'] = form
156 context['form'] = form
157 context['bumpable'] = posts[0].can_bump()
157 context['bumpable'] = posts[0].can_bump()
158
158
159 return render(request, 'boards/thread.html', context)
159 return render(request, 'boards/thread.html', context)
160
160
161
161
162 def login(request):
162 def login(request):
163 """Log in with user id"""
163 """Log in with user id"""
164
164
165 context = _init_default_context(request)
165 context = _init_default_context(request)
166
166
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
173 return redirect(index)
175 return redirect(index)
174
176
175 else:
177 else:
176 form = LoginForm()
178 form = LoginForm()
177
179
178 context['form'] = form
180 context['form'] = form
179
181
180 return render(request, 'boards/login.html', context)
182 return render(request, 'boards/login.html', context)
181
183
182
184
183 def settings(request):
185 def settings(request):
184 """User's settings"""
186 """User's settings"""
185
187
186 context = _init_default_context(request)
188 context = _init_default_context(request)
187 user = _get_user(request)
189 user = _get_user(request)
188 is_moderator = user.is_moderator()
190 is_moderator = user.is_moderator()
189
191
190 if request.method == 'POST':
192 if request.method == 'POST':
191 if is_moderator:
193 if is_moderator:
192 form = ModeratorSettingsForm(request.POST,
194 form = ModeratorSettingsForm(request.POST,
193 error_class=PlainErrorList)
195 error_class=PlainErrorList)
194 else:
196 else:
195 form = SettingsForm(request.POST, error_class=PlainErrorList)
197 form = SettingsForm(request.POST, error_class=PlainErrorList)
196
198
197 if form.is_valid():
199 if form.is_valid():
198 selected_theme = form.cleaned_data['theme']
200 selected_theme = form.cleaned_data['theme']
199
201
200 user.save_setting('theme', selected_theme)
202 user.save_setting('theme', selected_theme)
201
203
202 if is_moderator:
204 if is_moderator:
203 moderate = form.cleaned_data['moderate']
205 moderate = form.cleaned_data['moderate']
204 user.save_setting(SETTING_MODERATE, moderate)
206 user.save_setting(SETTING_MODERATE, moderate)
205
207
206 return redirect(settings)
208 return redirect(settings)
207 else:
209 else:
208 selected_theme = _get_theme(request)
210 selected_theme = _get_theme(request)
209
211
210 if is_moderator:
212 if is_moderator:
211 form = ModeratorSettingsForm(initial={'theme': selected_theme,
213 form = ModeratorSettingsForm(initial={'theme': selected_theme,
212 'moderate': context['moderator']},
214 'moderate': context['moderator']},
213 error_class=PlainErrorList)
215 error_class=PlainErrorList)
214 else:
216 else:
215 form = SettingsForm(initial={'theme': selected_theme},
217 form = SettingsForm(initial={'theme': selected_theme},
216 error_class=PlainErrorList)
218 error_class=PlainErrorList)
217
219
218 context['form'] = form
220 context['form'] = form
219
221
220 return render(request, 'boards/settings.html', context)
222 return render(request, 'boards/settings.html', context)
221
223
222
224
223 def all_tags(request):
225 def all_tags(request):
224 """All tags list"""
226 """All tags list"""
225
227
226 context = _init_default_context(request)
228 context = _init_default_context(request)
227 context['all_tags'] = Tag.objects.get_not_empty_tags()
229 context['all_tags'] = Tag.objects.get_not_empty_tags()
228
230
229 return render(request, 'boards/tags.html', context)
231 return render(request, 'boards/tags.html', context)
230
232
231
233
232 def jump_to_post(request, post_id):
234 def jump_to_post(request, post_id):
233 """Determine thread in which the requested post is and open it's page"""
235 """Determine thread in which the requested post is and open it's page"""
234
236
235 post = get_object_or_404(Post, id=post_id)
237 post = get_object_or_404(Post, id=post_id)
236
238
237 if not post.thread:
239 if not post.thread:
238 return redirect(thread, post_id=post.id)
240 return redirect(thread, post_id=post.id)
239 else:
241 else:
240 return redirect(reverse(thread, kwargs={'post_id': post.thread.id})
242 return redirect(reverse(thread, kwargs={'post_id': post.thread.id})
241 + '#' + str(post.id))
243 + '#' + str(post.id))
242
244
243
245
244 def authors(request):
246 def authors(request):
245 context = _init_default_context(request)
247 context = _init_default_context(request)
246 context['authors'] = boards.authors.authors
248 context['authors'] = boards.authors.authors
247
249
248 return render(request, 'boards/authors.html', context)
250 return render(request, 'boards/authors.html', context)
249
251
250
252
251 def delete(request, post_id):
253 def delete(request, post_id):
252 user = _get_user(request)
254 user = _get_user(request)
253 post = get_object_or_404(Post, id=post_id)
255 post = get_object_or_404(Post, id=post_id)
254
256
255 if user.is_moderator():
257 if user.is_moderator():
256 # TODO Show confirmation page before deletion
258 # TODO Show confirmation page before deletion
257 Post.objects.delete_post(post)
259 Post.objects.delete_post(post)
258
260
259 if not post.thread:
261 if not post.thread:
260 return _redirect_to_next(request)
262 return _redirect_to_next(request)
261 else:
263 else:
262 return redirect(thread, post_id=post.thread.id)
264 return redirect(thread, post_id=post.thread.id)
263
265
264
266
265 def ban(request, post_id):
267 def ban(request, post_id):
266 user = _get_user(request)
268 user = _get_user(request)
267 post = get_object_or_404(Post, id=post_id)
269 post = get_object_or_404(Post, id=post_id)
268
270
269 if user.is_moderator():
271 if user.is_moderator():
270 # TODO Show confirmation page before ban
272 # TODO Show confirmation page before ban
271 Ban.objects.get_or_create(ip=post.poster_ip)
273 Ban.objects.get_or_create(ip=post.poster_ip)
272
274
273 return _redirect_to_next(request)
275 return _redirect_to_next(request)
274
276
275
277
276 def you_are_banned(request):
278 def you_are_banned(request):
277 context = _init_default_context(request)
279 context = _init_default_context(request)
278 return render(request, 'boards/staticpages/banned.html', context)
280 return render(request, 'boards/staticpages/banned.html', context)
279
281
280
282
281 def page_404(request):
283 def page_404(request):
282 context = _init_default_context(request)
284 context = _init_default_context(request)
283 return render(request, 'boards/404.html', context)
285 return render(request, 'boards/404.html', context)
284
286
285
287
286 def tag_subscribe(request, tag_name):
288 def tag_subscribe(request, tag_name):
287 user = _get_user(request)
289 user = _get_user(request)
288 tag = get_object_or_404(Tag, name=tag_name)
290 tag = get_object_or_404(Tag, name=tag_name)
289
291
290 if not tag in user.fav_tags.all():
292 if not tag in user.fav_tags.all():
291 user.fav_tags.add(tag)
293 user.fav_tags.add(tag)
292
294
293 return _redirect_to_next(request)
295 return _redirect_to_next(request)
294
296
295
297
296 def tag_unsubscribe(request, tag_name):
298 def tag_unsubscribe(request, tag_name):
297 user = _get_user(request)
299 user = _get_user(request)
298 tag = get_object_or_404(Tag, name=tag_name)
300 tag = get_object_or_404(Tag, name=tag_name)
299
301
300 if tag in user.fav_tags.all():
302 if tag in user.fav_tags.all():
301 user.fav_tags.remove(tag)
303 user.fav_tags.remove(tag)
302
304
303 return _redirect_to_next(request)
305 return _redirect_to_next(request)
304
306
305
307
306 def static_page(request, name):
308 def static_page(request, name):
307 context = _init_default_context(request)
309 context = _init_default_context(request)
308 return render(request, 'boards/staticpages/' + name + '.html', context)
310 return render(request, 'boards/staticpages/' + name + '.html', context)
309
311
310
312
311 def _get_theme(request, user=None):
313 def _get_theme(request, user=None):
312 """Get user's CSS theme"""
314 """Get user's CSS theme"""
313
315
314 if not user:
316 if not user:
315 user = _get_user(request)
317 user = _get_user(request)
316 theme = user.get_setting('theme')
318 theme = user.get_setting('theme')
317 if not theme:
319 if not theme:
318 theme = neboard.settings.DEFAULT_THEME
320 theme = neboard.settings.DEFAULT_THEME
319
321
320 return theme
322 return theme
321
323
322
324
323 def _init_default_context(request):
325 def _init_default_context(request):
324 """Create context with default values that are used in most views"""
326 """Create context with default values that are used in most views"""
325
327
326 context = RequestContext(request)
328 context = RequestContext(request)
327
329
328 user = _get_user(request)
330 user = _get_user(request)
329 context['user'] = user
331 context['user'] = user
330 context['tags'] = user.get_sorted_fav_tags()
332 context['tags'] = user.get_sorted_fav_tags()
331 context['theme'] = _get_theme(request, user)
333 context['theme'] = _get_theme(request, user)
332
334
333 moderate = user.get_setting(SETTING_MODERATE)
335 moderate = user.get_setting(SETTING_MODERATE)
334 if moderate == 'True':
336 if moderate == 'True':
335 context['moderator'] = user.is_moderator()
337 context['moderator'] = user.is_moderator()
336 else:
338 else:
337 context['moderator'] = False
339 context['moderator'] = False
338
340
339 return context
341 return context
340
342
341
343
342 def _get_user(request):
344 def _get_user(request):
343 """Get current user from the session"""
345 """Get current user from the session"""
344
346
345 session = request.session
347 session = request.session
346 if not 'user_id' in session:
348 if not 'user_id' in session:
347 request.session.save()
349 request.session.save()
348
350
349 md5 = hashlib.md5()
351 md5 = hashlib.md5()
350 md5.update(session.session_key)
352 md5.update(session.session_key)
351 new_id = md5.hexdigest()
353 new_id = md5.hexdigest()
352
354
353 time_now = timezone.now()
355 time_now = timezone.now()
354 user = User.objects.create(user_id=new_id, rank=RANK_USER,
356 user = User.objects.create(user_id=new_id, rank=RANK_USER,
355 registration_time=time_now)
357 registration_time=time_now)
356
358
357 session['user_id'] = user.id
359 session['user_id'] = user.id
358 else:
360 else:
359 user = User.objects.get(id=session['user_id'])
361 user = User.objects.get(id=session['user_id'])
360
362
361 return user
363 return user
362
364
363
365
364 def _redirect_to_next(request):
366 def _redirect_to_next(request):
365 if 'next' in request.GET:
367 if 'next' in request.GET:
366 next_page = request.GET['next']
368 next_page = request.GET['next']
367 return HttpResponseRedirect(next_page)
369 return HttpResponseRedirect(next_page)
368 else:
370 else:
369 return redirect(index)
371 return redirect(index)
General Comments 0
You need to be logged in to leave comments. Login now