##// END OF EJS Templates
Added veterans (old users). Veterans currently have lower posting speed limit
neko259 -
r642:67b694de default
parent child Browse files
Show More
@@ -1,339 +1,347 b''
1 import re
1 import re
2 import time
2 import time
3 import hashlib
3 import hashlib
4
4
5 from captcha.fields import CaptchaField
5 from captcha.fields import CaptchaField
6 from django import forms
6 from django import forms
7 from django.forms.util import ErrorList
7 from django.forms.util import ErrorList
8 from django.utils.translation import ugettext_lazy as _
8 from django.utils.translation import ugettext_lazy as _
9
9
10 from boards.mdx_neboard import formatters
10 from boards.mdx_neboard import formatters
11 from boards.models.post import TITLE_MAX_LENGTH
11 from boards.models.post import TITLE_MAX_LENGTH
12 from boards.models import User, Post
12 from boards.models import User, Post
13 from neboard import settings
13 from neboard import settings
14 from boards import utils
14 from boards import utils
15 import boards.settings as board_settings
15 import boards.settings as board_settings
16
16
17 VETERAN_POSTING_DELAY = 5
18
17 ATTRIBUTE_PLACEHOLDER = 'placeholder'
19 ATTRIBUTE_PLACEHOLDER = 'placeholder'
18
20
19 LAST_POST_TIME = 'last_post_time'
21 LAST_POST_TIME = 'last_post_time'
20 LAST_LOGIN_TIME = 'last_login_time'
22 LAST_LOGIN_TIME = 'last_login_time'
21 TEXT_PLACEHOLDER = _('''Type message here. You can reply to message >>123 like
23 TEXT_PLACEHOLDER = _('''Type message here. You can reply to message >>123 like
22 this. 2 new lines are required to start new paragraph.''')
24 this. 2 new lines are required to start new paragraph.''')
23 TAGS_PLACEHOLDER = _('tag1 several_words_tag')
25 TAGS_PLACEHOLDER = _('tag1 several_words_tag')
24
26
25 ERROR_IMAGE_DUPLICATE = _('Such image was already posted')
27 ERROR_IMAGE_DUPLICATE = _('Such image was already posted')
26
28
27 LABEL_TITLE = _('Title')
29 LABEL_TITLE = _('Title')
28 LABEL_TEXT = _('Text')
30 LABEL_TEXT = _('Text')
29 LABEL_TAG = _('Tag')
31 LABEL_TAG = _('Tag')
30
32
31 TAG_MAX_LENGTH = 20
33 TAG_MAX_LENGTH = 20
32
34
33 REGEX_TAG = ur'^[\w\d]+$'
35 REGEX_TAG = ur'^[\w\d]+$'
34
36
35
37
36 class FormatPanel(forms.Textarea):
38 class FormatPanel(forms.Textarea):
37 def render(self, name, value, attrs=None):
39 def render(self, name, value, attrs=None):
38 output = '<div id="mark-panel">'
40 output = '<div id="mark-panel">'
39 for formatter in formatters:
41 for formatter in formatters:
40 output += u'<span class="mark_btn"' + \
42 output += u'<span class="mark_btn"' + \
41 u' onClick="addMarkToMsg(\'' + formatter.format_left + \
43 u' onClick="addMarkToMsg(\'' + formatter.format_left + \
42 '\', \'' + formatter.format_right + '\')">' + \
44 '\', \'' + formatter.format_right + '\')">' + \
43 formatter.preview_left + formatter.name + \
45 formatter.preview_left + formatter.name + \
44 formatter.preview_right + u'</span>'
46 formatter.preview_right + u'</span>'
45
47
46 output += '</div>'
48 output += '</div>'
47 output += super(FormatPanel, self).render(name, value, attrs=None)
49 output += super(FormatPanel, self).render(name, value, attrs=None)
48
50
49 return output
51 return output
50
52
51
53
52 class PlainErrorList(ErrorList):
54 class PlainErrorList(ErrorList):
53 def __unicode__(self):
55 def __unicode__(self):
54 return self.as_text()
56 return self.as_text()
55
57
56 def as_text(self):
58 def as_text(self):
57 return ''.join([u'(!) %s ' % e for e in self])
59 return ''.join([u'(!) %s ' % e for e in self])
58
60
59
61
60 class NeboardForm(forms.Form):
62 class NeboardForm(forms.Form):
61
63
62 def as_div(self):
64 def as_div(self):
63 """
65 """
64 Returns this form rendered as HTML <as_div>s.
66 Returns this form rendered as HTML <as_div>s.
65 """
67 """
66
68
67 return self._html_output(
69 return self._html_output(
68 # TODO Do not show hidden rows in the list here
70 # TODO Do not show hidden rows in the list here
69 normal_row='<div class="form-row">'
71 normal_row='<div class="form-row">'
70 '<div class="form-label">'
72 '<div class="form-label">'
71 '%(label)s'
73 '%(label)s'
72 '</div>'
74 '</div>'
73 '<div class="form-input">'
75 '<div class="form-input">'
74 '%(field)s'
76 '%(field)s'
75 '</div>'
77 '</div>'
76 '%(help_text)s'
78 '%(help_text)s'
77 '</div>',
79 '</div>',
78 error_row='<div class="form-row">'
80 error_row='<div class="form-row">'
79 '<div class="form-label"></div>'
81 '<div class="form-label"></div>'
80 '<div class="form-errors">%s</div>'
82 '<div class="form-errors">%s</div>'
81 '</div>',
83 '</div>',
82 row_ender='</div>',
84 row_ender='</div>',
83 help_text_html='%s',
85 help_text_html='%s',
84 errors_on_separate_row=True)
86 errors_on_separate_row=True)
85
87
86 def as_json_errors(self):
88 def as_json_errors(self):
87 errors = []
89 errors = []
88
90
89 for name, field in self.fields.items():
91 for name, field in self.fields.items():
90 if self[name].errors:
92 if self[name].errors:
91 errors.append({
93 errors.append({
92 'field': name,
94 'field': name,
93 'errors': self[name].errors.as_text(),
95 'errors': self[name].errors.as_text(),
94 })
96 })
95
97
96 return errors
98 return errors
97
99
98
100
99 class PostForm(NeboardForm):
101 class PostForm(NeboardForm):
100
102
101 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False,
103 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False,
102 label=LABEL_TITLE)
104 label=LABEL_TITLE)
103 text = forms.CharField(
105 text = forms.CharField(
104 widget=FormatPanel(attrs={ATTRIBUTE_PLACEHOLDER: TEXT_PLACEHOLDER}),
106 widget=FormatPanel(attrs={ATTRIBUTE_PLACEHOLDER: TEXT_PLACEHOLDER}),
105 required=False, label=LABEL_TEXT)
107 required=False, label=LABEL_TEXT)
106 image = forms.ImageField(required=False, label=_('Image'))
108 image = forms.ImageField(required=False, label=_('Image'))
107
109
108 # This field is for spam prevention only
110 # This field is for spam prevention only
109 email = forms.CharField(max_length=100, required=False, label=_('e-mail'),
111 email = forms.CharField(max_length=100, required=False, label=_('e-mail'),
110 widget=forms.TextInput(attrs={
112 widget=forms.TextInput(attrs={
111 'class': 'form-email'}))
113 'class': 'form-email'}))
112
114
113 session = None
115 session = None
114 need_to_ban = False
116 need_to_ban = False
115
117
116 def clean_title(self):
118 def clean_title(self):
117 title = self.cleaned_data['title']
119 title = self.cleaned_data['title']
118 if title:
120 if title:
119 if len(title) > TITLE_MAX_LENGTH:
121 if len(title) > TITLE_MAX_LENGTH:
120 raise forms.ValidationError(_('Title must have less than %s '
122 raise forms.ValidationError(_('Title must have less than %s '
121 'characters') %
123 'characters') %
122 str(TITLE_MAX_LENGTH))
124 str(TITLE_MAX_LENGTH))
123 return title
125 return title
124
126
125 def clean_text(self):
127 def clean_text(self):
126 text = self.cleaned_data['text']
128 text = self.cleaned_data['text']
127 if text:
129 if text:
128 if len(text) > board_settings.MAX_TEXT_LENGTH:
130 if len(text) > board_settings.MAX_TEXT_LENGTH:
129 raise forms.ValidationError(_('Text must have less than %s '
131 raise forms.ValidationError(_('Text must have less than %s '
130 'characters') %
132 'characters') %
131 str(board_settings
133 str(board_settings
132 .MAX_TEXT_LENGTH))
134 .MAX_TEXT_LENGTH))
133 return text
135 return text
134
136
135 def clean_image(self):
137 def clean_image(self):
136 image = self.cleaned_data['image']
138 image = self.cleaned_data['image']
137 if image:
139 if image:
138 if image._size > board_settings.MAX_IMAGE_SIZE:
140 if image._size > board_settings.MAX_IMAGE_SIZE:
139 raise forms.ValidationError(
141 raise forms.ValidationError(
140 _('Image must be less than %s bytes')
142 _('Image must be less than %s bytes')
141 % str(board_settings.MAX_IMAGE_SIZE))
143 % str(board_settings.MAX_IMAGE_SIZE))
142
144
143 md5 = hashlib.md5()
145 md5 = hashlib.md5()
144 for chunk in image.chunks():
146 for chunk in image.chunks():
145 md5.update(chunk)
147 md5.update(chunk)
146 image_hash = md5.hexdigest()
148 image_hash = md5.hexdigest()
147 if Post.objects.filter(image_hash=image_hash).exists():
149 if Post.objects.filter(image_hash=image_hash).exists():
148 raise forms.ValidationError(ERROR_IMAGE_DUPLICATE)
150 raise forms.ValidationError(ERROR_IMAGE_DUPLICATE)
149
151
150 return image
152 return image
151
153
152 def clean(self):
154 def clean(self):
153 cleaned_data = super(PostForm, self).clean()
155 cleaned_data = super(PostForm, self).clean()
154
156
155 if not self.session:
157 if not self.session:
156 raise forms.ValidationError('Humans have sessions')
158 raise forms.ValidationError('Humans have sessions')
157
159
158 if cleaned_data['email']:
160 if cleaned_data['email']:
159 self.need_to_ban = True
161 self.need_to_ban = True
160 raise forms.ValidationError('A human cannot enter a hidden field')
162 raise forms.ValidationError('A human cannot enter a hidden field')
161
163
162 if not self.errors:
164 if not self.errors:
163 self._clean_text_image()
165 self._clean_text_image()
164
166
165 if not self.errors and self.session:
167 if not self.errors and self.session:
166 self._validate_posting_speed()
168 self._validate_posting_speed()
167
169
168 return cleaned_data
170 return cleaned_data
169
171
170 def _clean_text_image(self):
172 def _clean_text_image(self):
171 text = self.cleaned_data.get('text')
173 text = self.cleaned_data.get('text')
172 image = self.cleaned_data.get('image')
174 image = self.cleaned_data.get('image')
173
175
174 if (not text) and (not image):
176 if (not text) and (not image):
175 error_message = _('Either text or image must be entered.')
177 error_message = _('Either text or image must be entered.')
176 self._errors['text'] = self.error_class([error_message])
178 self._errors['text'] = self.error_class([error_message])
177
179
178 def _validate_posting_speed(self):
180 def _validate_posting_speed(self):
179 can_post = True
181 can_post = True
180
182
183 user = User.objects.get(id=self.session['user_id'])
184 if user.is_veteran():
185 posting_delay = VETERAN_POSTING_DELAY
186 else:
187 posting_delay = settings.POSTING_DELAY
188
181 if LAST_POST_TIME in self.session:
189 if LAST_POST_TIME in self.session:
182 now = time.time()
190 now = time.time()
183 last_post_time = self.session[LAST_POST_TIME]
191 last_post_time = self.session[LAST_POST_TIME]
184
192
185 current_delay = int(now - last_post_time)
193 current_delay = int(now - last_post_time)
186
194
187 if current_delay < settings.POSTING_DELAY:
195 if current_delay < posting_delay:
188 error_message = _('Wait %s seconds after last posting') % str(
196 error_message = _('Wait %s seconds after last posting') % str(
189 settings.POSTING_DELAY - current_delay)
197 posting_delay - current_delay)
190 self._errors['text'] = self.error_class([error_message])
198 self._errors['text'] = self.error_class([error_message])
191
199
192 can_post = False
200 can_post = False
193
201
194 if can_post:
202 if can_post:
195 self.session[LAST_POST_TIME] = time.time()
203 self.session[LAST_POST_TIME] = time.time()
196
204
197
205
198 class ThreadForm(PostForm):
206 class ThreadForm(PostForm):
199
207
200 regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE)
208 regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE)
201
209
202 tags = forms.CharField(
210 tags = forms.CharField(
203 widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}),
211 widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}),
204 max_length=100, label=_('Tags'))
212 max_length=100, label=_('Tags'))
205
213
206 def clean_tags(self):
214 def clean_tags(self):
207 tags = self.cleaned_data['tags']
215 tags = self.cleaned_data['tags']
208
216
209 if tags:
217 if tags:
210 if not self.regex_tags.match(tags):
218 if not self.regex_tags.match(tags):
211 raise forms.ValidationError(
219 raise forms.ValidationError(
212 _('Inappropriate characters in tags.'))
220 _('Inappropriate characters in tags.'))
213
221
214 return tags
222 return tags
215
223
216 def clean(self):
224 def clean(self):
217 cleaned_data = super(ThreadForm, self).clean()
225 cleaned_data = super(ThreadForm, self).clean()
218
226
219 return cleaned_data
227 return cleaned_data
220
228
221
229
222 class PostCaptchaForm(PostForm):
230 class PostCaptchaForm(PostForm):
223 captcha = CaptchaField()
231 captcha = CaptchaField()
224
232
225 def __init__(self, *args, **kwargs):
233 def __init__(self, *args, **kwargs):
226 self.request = kwargs['request']
234 self.request = kwargs['request']
227 del kwargs['request']
235 del kwargs['request']
228
236
229 super(PostCaptchaForm, self).__init__(*args, **kwargs)
237 super(PostCaptchaForm, self).__init__(*args, **kwargs)
230
238
231 def clean(self):
239 def clean(self):
232 cleaned_data = super(PostCaptchaForm, self).clean()
240 cleaned_data = super(PostCaptchaForm, self).clean()
233
241
234 success = self.is_valid()
242 success = self.is_valid()
235 utils.update_captcha_access(self.request, success)
243 utils.update_captcha_access(self.request, success)
236
244
237 if success:
245 if success:
238 return cleaned_data
246 return cleaned_data
239 else:
247 else:
240 raise forms.ValidationError(_("Captcha validation failed"))
248 raise forms.ValidationError(_("Captcha validation failed"))
241
249
242
250
243 class ThreadCaptchaForm(ThreadForm):
251 class ThreadCaptchaForm(ThreadForm):
244 captcha = CaptchaField()
252 captcha = CaptchaField()
245
253
246 def __init__(self, *args, **kwargs):
254 def __init__(self, *args, **kwargs):
247 self.request = kwargs['request']
255 self.request = kwargs['request']
248 del kwargs['request']
256 del kwargs['request']
249
257
250 super(ThreadCaptchaForm, self).__init__(*args, **kwargs)
258 super(ThreadCaptchaForm, self).__init__(*args, **kwargs)
251
259
252 def clean(self):
260 def clean(self):
253 cleaned_data = super(ThreadCaptchaForm, self).clean()
261 cleaned_data = super(ThreadCaptchaForm, self).clean()
254
262
255 success = self.is_valid()
263 success = self.is_valid()
256 utils.update_captcha_access(self.request, success)
264 utils.update_captcha_access(self.request, success)
257
265
258 if success:
266 if success:
259 return cleaned_data
267 return cleaned_data
260 else:
268 else:
261 raise forms.ValidationError(_("Captcha validation failed"))
269 raise forms.ValidationError(_("Captcha validation failed"))
262
270
263
271
264 class SettingsForm(NeboardForm):
272 class SettingsForm(NeboardForm):
265
273
266 theme = forms.ChoiceField(choices=settings.THEMES,
274 theme = forms.ChoiceField(choices=settings.THEMES,
267 label=_('Theme'))
275 label=_('Theme'))
268
276
269
277
270 class ModeratorSettingsForm(SettingsForm):
278 class ModeratorSettingsForm(SettingsForm):
271
279
272 moderate = forms.BooleanField(required=False, label=_('Enable moderation '
280 moderate = forms.BooleanField(required=False, label=_('Enable moderation '
273 'panel'))
281 'panel'))
274
282
275
283
276 class LoginForm(NeboardForm):
284 class LoginForm(NeboardForm):
277
285
278 user_id = forms.CharField()
286 user_id = forms.CharField()
279
287
280 session = None
288 session = None
281
289
282 def clean_user_id(self):
290 def clean_user_id(self):
283 user_id = self.cleaned_data['user_id']
291 user_id = self.cleaned_data['user_id']
284 if user_id:
292 if user_id:
285 users = User.objects.filter(user_id=user_id)
293 users = User.objects.filter(user_id=user_id)
286 if len(users) == 0:
294 if len(users) == 0:
287 raise forms.ValidationError(_('No such user found'))
295 raise forms.ValidationError(_('No such user found'))
288
296
289 return user_id
297 return user_id
290
298
291 def _validate_login_speed(self):
299 def _validate_login_speed(self):
292 can_post = True
300 can_post = True
293
301
294 if LAST_LOGIN_TIME in self.session:
302 if LAST_LOGIN_TIME in self.session:
295 now = time.time()
303 now = time.time()
296 last_login_time = self.session[LAST_LOGIN_TIME]
304 last_login_time = self.session[LAST_LOGIN_TIME]
297
305
298 current_delay = int(now - last_login_time)
306 current_delay = int(now - last_login_time)
299
307
300 if current_delay < board_settings.LOGIN_TIMEOUT:
308 if current_delay < board_settings.LOGIN_TIMEOUT:
301 error_message = _('Wait %s minutes after last login') % str(
309 error_message = _('Wait %s minutes after last login') % str(
302 (board_settings.LOGIN_TIMEOUT - current_delay) / 60)
310 (board_settings.LOGIN_TIMEOUT - current_delay) / 60)
303 self._errors['user_id'] = self.error_class([error_message])
311 self._errors['user_id'] = self.error_class([error_message])
304
312
305 can_post = False
313 can_post = False
306
314
307 if can_post:
315 if can_post:
308 self.session[LAST_LOGIN_TIME] = time.time()
316 self.session[LAST_LOGIN_TIME] = time.time()
309
317
310 def clean(self):
318 def clean(self):
311 if not self.session:
319 if not self.session:
312 raise forms.ValidationError('Humans have sessions')
320 raise forms.ValidationError('Humans have sessions')
313
321
314 self._validate_login_speed()
322 self._validate_login_speed()
315
323
316 cleaned_data = super(LoginForm, self).clean()
324 cleaned_data = super(LoginForm, self).clean()
317
325
318 return cleaned_data
326 return cleaned_data
319
327
320
328
321 class AddTagForm(NeboardForm):
329 class AddTagForm(NeboardForm):
322
330
323 tag = forms.CharField(max_length=TAG_MAX_LENGTH, label=LABEL_TAG)
331 tag = forms.CharField(max_length=TAG_MAX_LENGTH, label=LABEL_TAG)
324 method = forms.CharField(widget=forms.HiddenInput(), initial='add_tag')
332 method = forms.CharField(widget=forms.HiddenInput(), initial='add_tag')
325
333
326 def clean_tag(self):
334 def clean_tag(self):
327 tag = self.cleaned_data['tag']
335 tag = self.cleaned_data['tag']
328
336
329 regex_tag = re.compile(REGEX_TAG, re.UNICODE)
337 regex_tag = re.compile(REGEX_TAG, re.UNICODE)
330 if not regex_tag.match(tag):
338 if not regex_tag.match(tag):
331 raise forms.ValidationError(_('Inappropriate characters in tags.'))
339 raise forms.ValidationError(_('Inappropriate characters in tags.'))
332
340
333 return tag
341 return tag
334
342
335 def clean(self):
343 def clean(self):
336 cleaned_data = super(AddTagForm, self).clean()
344 cleaned_data = super(AddTagForm, self).clean()
337
345
338 return cleaned_data
346 return cleaned_data
339
347
@@ -1,382 +1,386 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: 2014-02-08 20:55+0200\n"
10 "POT-Creation-Date: 2014-03-08 12:24+0200\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 #: authors.py:5
21 #: authors.py:5
22 msgid "author"
22 msgid "author"
23 msgstr "Π°Π²Ρ‚ΠΎΡ€"
23 msgstr "Π°Π²Ρ‚ΠΎΡ€"
24
24
25 #: authors.py:6
25 #: authors.py:6
26 msgid "developer"
26 msgid "developer"
27 msgstr "Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ"
27 msgstr "Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ"
28
28
29 #: authors.py:7
29 #: authors.py:7
30 msgid "javascript developer"
30 msgid "javascript developer"
31 msgstr "Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ javascript"
31 msgstr "Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ javascript"
32
32
33 #: authors.py:8
33 #: authors.py:8
34 msgid "designer"
34 msgid "designer"
35 msgstr "Π΄ΠΈΠ·Π°ΠΉΠ½Π΅Ρ€"
35 msgstr "Π΄ΠΈΠ·Π°ΠΉΠ½Π΅Ρ€"
36
36
37 #: forms.py:21
37 #: forms.py:21
38 msgid ""
38 msgid ""
39 "Type message here. You can reply to message >>123 like\n"
39 "Type message here. You can reply to message >>123 like\n"
40 " this. 2 new lines are required to start new paragraph."
40 " this. 2 new lines are required to start new paragraph."
41 msgstr ""
41 msgstr ""
42 "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ сообщСниС здСсь. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π½Π° сообщСниС >>123 Π²ΠΎΡ‚ Ρ‚Π°ΠΊ. 2 "
42 "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ сообщСниС здСсь. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π½Π° сообщСниС >>123 Π²ΠΎΡ‚ Ρ‚Π°ΠΊ. 2 "
43 "пСрСноса строки ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ для создания Π½ΠΎΠ²ΠΎΠ³ΠΎ Π°Π±Π·Π°Ρ†Π°."
43 "пСрСноса строки ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ для создания Π½ΠΎΠ²ΠΎΠ³ΠΎ Π°Π±Π·Π°Ρ†Π°."
44
44
45 #: forms.py:23
45 #: forms.py:23
46 msgid "tag1 several_words_tag"
46 msgid "tag1 several_words_tag"
47 msgstr "Ρ‚Π΅Π³1 Ρ‚Π΅Π³_ΠΈΠ·_Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ…_слов"
47 msgstr "Ρ‚Π΅Π³1 Ρ‚Π΅Π³_ΠΈΠ·_Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ…_слов"
48
48
49 #: forms.py:25
49 #: forms.py:25
50 msgid "Such image was already posted"
50 msgid "Such image was already posted"
51 msgstr "Π’Π°ΠΊΠΎΠ΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π±Ρ‹Π»ΠΎ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½ΠΎ"
51 msgstr "Π’Π°ΠΊΠΎΠ΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π±Ρ‹Π»ΠΎ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½ΠΎ"
52
52
53 #: forms.py:27
53 #: forms.py:27
54 msgid "Title"
54 msgid "Title"
55 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ"
55 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ"
56
56
57 #: forms.py:28
57 #: forms.py:28
58 msgid "Text"
58 msgid "Text"
59 msgstr "ВСкст"
59 msgstr "ВСкст"
60
60
61 #: forms.py:29
61 #: forms.py:29
62 msgid "Tag"
62 msgid "Tag"
63 msgstr "Π’Π΅Π³"
63 msgstr "Π’Π΅Π³"
64
64
65 #: forms.py:106
65 #: forms.py:106
66 msgid "Image"
66 msgid "Image"
67 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅"
67 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅"
68
68
69 #: forms.py:109
69 #: forms.py:109
70 msgid "e-mail"
70 msgid "e-mail"
71 msgstr ""
71 msgstr ""
72
72
73 #: forms.py:120
73 #: forms.py:120
74 #, python-format
74 #, python-format
75 msgid "Title must have less than %s characters"
75 msgid "Title must have less than %s characters"
76 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅Ρ‚ΡŒ мСньшС %s символов"
76 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅Ρ‚ΡŒ мСньшС %s символов"
77
77
78 #: forms.py:129
78 #: forms.py:129
79 #, python-format
79 #, python-format
80 msgid "Text must have less than %s characters"
80 msgid "Text must have less than %s characters"
81 msgstr "ВСкст Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΠΊΠΎΡ€ΠΎΡ‡Π΅ %s символов"
81 msgstr "ВСкст Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΠΊΠΎΡ€ΠΎΡ‡Π΅ %s символов"
82
82
83 #: forms.py:140
83 #: forms.py:140
84 #, python-format
84 #, python-format
85 msgid "Image must be less than %s bytes"
85 msgid "Image must be less than %s bytes"
86 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ΠΌΠ΅Π½Π΅Π΅ %s Π±Π°ΠΉΡ‚"
86 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ΠΌΠ΅Π½Π΅Π΅ %s Π±Π°ΠΉΡ‚"
87
87
88 #: forms.py:175
88 #: forms.py:175
89 msgid "Either text or image must be entered."
89 msgid "Either text or image must be entered."
90 msgstr "ВСкст ΠΈΠ»ΠΈ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Π²Π²Π΅Π΄Π΅Π½Ρ‹."
90 msgstr "ВСкст ΠΈΠ»ΠΈ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Π²Π²Π΅Π΄Π΅Π½Ρ‹."
91
91
92 #: forms.py:188
92 #: forms.py:193
93 #, python-format
93 #, python-format
94 msgid "Wait %s seconds after last posting"
94 msgid "Wait %s seconds after last posting"
95 msgstr "ΠŸΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ %s сСкунд послС послСднСго постинга"
95 msgstr "ΠŸΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ %s сСкунд послС послСднСго постинга"
96
96
97 #: forms.py:204 templates/boards/tags.html:7 templates/boards/rss/post.html:10
97 #: forms.py:209 templates/boards/tags.html:7 templates/boards/rss/post.html:10
98 msgid "Tags"
98 msgid "Tags"
99 msgstr "Π’Π΅Π³ΠΈ"
99 msgstr "Π’Π΅Π³ΠΈ"
100
100
101 #: forms.py:212 forms.py:331
101 #: forms.py:217 forms.py:336
102 msgid "Inappropriate characters in tags."
102 msgid "Inappropriate characters in tags."
103 msgstr "НСдопустимыС символы Π² Ρ‚Π΅Π³Π°Ρ…."
103 msgstr "НСдопустимыС символы Π² Ρ‚Π΅Π³Π°Ρ…."
104
104
105 #: forms.py:240 forms.py:261
105 #: forms.py:245 forms.py:266
106 msgid "Captcha validation failed"
106 msgid "Captcha validation failed"
107 msgstr "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠ°ΠΏΡ‡ΠΈ ΠΏΡ€ΠΎΠ²Π°Π»Π΅Π½Π°"
107 msgstr "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠ°ΠΏΡ‡ΠΈ ΠΏΡ€ΠΎΠ²Π°Π»Π΅Π½Π°"
108
108
109 #: forms.py:267
109 #: forms.py:272
110 msgid "Theme"
110 msgid "Theme"
111 msgstr "Π’Π΅ΠΌΠ°"
111 msgstr "Π’Π΅ΠΌΠ°"
112
112
113 #: forms.py:272
113 #: forms.py:277
114 msgid "Enable moderation panel"
114 msgid "Enable moderation panel"
115 msgstr "Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ панСль ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ†ΠΈΠΈ"
115 msgstr "Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ панСль ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ†ΠΈΠΈ"
116
116
117 #: forms.py:287
117 #: forms.py:292
118 msgid "No such user found"
118 msgid "No such user found"
119 msgstr "Π”Π°Π½Π½Ρ‹ΠΉ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½"
119 msgstr "Π”Π°Π½Π½Ρ‹ΠΉ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½"
120
120
121 #: forms.py:301
121 #: forms.py:306
122 #, python-format
122 #, python-format
123 msgid "Wait %s minutes after last login"
123 msgid "Wait %s minutes after last login"
124 msgstr "ΠŸΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ %s ΠΌΠΈΠ½ΡƒΡ‚ послС послСднСго Π²Ρ…ΠΎΠ΄Π°"
124 msgstr "ΠŸΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ %s ΠΌΠΈΠ½ΡƒΡ‚ послС послСднСго Π²Ρ…ΠΎΠ΄Π°"
125
125
126 #: templates/boards/404.html:6
126 #: templates/boards/404.html:6
127 msgid "Not found"
127 msgid "Not found"
128 msgstr "НС найдСно"
128 msgstr "НС найдСно"
129
129
130 #: templates/boards/404.html:12
130 #: templates/boards/404.html:12
131 msgid "This page does not exist"
131 msgid "This page does not exist"
132 msgstr "Π­Ρ‚ΠΎΠΉ страницы Π½Π΅ сущСствуСт"
132 msgstr "Π­Ρ‚ΠΎΠΉ страницы Π½Π΅ сущСствуСт"
133
133
134 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
134 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
135 msgid "Authors"
135 msgid "Authors"
136 msgstr "Авторы"
136 msgstr "Авторы"
137
137
138 #: templates/boards/authors.html:26
138 #: templates/boards/authors.html:26
139 msgid "Distributed under the"
139 msgid "Distributed under the"
140 msgstr "РаспространяСтся ΠΏΠΎΠ΄"
140 msgstr "РаспространяСтся ΠΏΠΎΠ΄"
141
141
142 #: templates/boards/authors.html:28
142 #: templates/boards/authors.html:28
143 msgid "license"
143 msgid "license"
144 msgstr "Π»ΠΈΡ†Π΅Π½Π·ΠΈΠ΅ΠΉ"
144 msgstr "Π»ΠΈΡ†Π΅Π½Π·ΠΈΠ΅ΠΉ"
145
145
146 #: templates/boards/authors.html:30
146 #: templates/boards/authors.html:30
147 msgid "Repository"
147 msgid "Repository"
148 msgstr "Π Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ"
148 msgstr "Π Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ"
149
149
150 #: templates/boards/base.html:14
150 #: templates/boards/base.html:14
151 msgid "Feed"
151 msgid "Feed"
152 msgstr "Π›Π΅Π½Ρ‚Π°"
152 msgstr "Π›Π΅Π½Ρ‚Π°"
153
153
154 #: templates/boards/base.html:31
154 #: templates/boards/base.html:31
155 msgid "All threads"
155 msgid "All threads"
156 msgstr "ВсС Ρ‚Π΅ΠΌΡ‹"
156 msgstr "ВсС Ρ‚Π΅ΠΌΡ‹"
157
157
158 #: templates/boards/base.html:36
158 #: templates/boards/base.html:36
159 msgid "Tag management"
159 msgid "Tag management"
160 msgstr "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ‚Π΅Π³Π°ΠΌΠΈ"
160 msgstr "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ‚Π΅Π³Π°ΠΌΠΈ"
161
161
162 #: templates/boards/base.html:38 templates/boards/settings.html:7
162 #: templates/boards/base.html:38 templates/boards/settings.html:7
163 msgid "Settings"
163 msgid "Settings"
164 msgstr "Настройки"
164 msgstr "Настройки"
165
165
166 #: templates/boards/base.html:50 templates/boards/login.html:6
166 #: templates/boards/base.html:50 templates/boards/login.html:6
167 #: templates/boards/login.html.py:21
167 #: templates/boards/login.html.py:21
168 msgid "Login"
168 msgid "Login"
169 msgstr "Π’Ρ…ΠΎΠ΄"
169 msgstr "Π’Ρ…ΠΎΠ΄"
170
170
171 #: templates/boards/base.html:51
171 #: templates/boards/base.html:51
172 msgid "Archive"
172 msgid "Archive"
173 msgstr "Архив"
173 msgstr "Архив"
174
174
175 #: templates/boards/base.html:53
175 #: templates/boards/base.html:53
176 #, python-format
176 #, python-format
177 msgid "Speed: %(ppd)s posts per day"
177 msgid "Speed: %(ppd)s posts per day"
178 msgstr "Π‘ΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ: %(ppd)s сообщСний Π² дСнь"
178 msgstr "Π‘ΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ: %(ppd)s сообщСний Π² дСнь"
179
179
180 #: templates/boards/base.html:55
180 #: templates/boards/base.html:55
181 msgid "Up"
181 msgid "Up"
182 msgstr "Π’Π²Π΅Ρ€Ρ…"
182 msgstr "Π’Π²Π΅Ρ€Ρ…"
183
183
184 #: templates/boards/login.html:15
184 #: templates/boards/login.html:15
185 msgid "User ID"
185 msgid "User ID"
186 msgstr "ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ"
186 msgstr "ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ"
187
187
188 #: templates/boards/login.html:24
188 #: templates/boards/login.html:24
189 msgid "Insert your user id above"
189 msgid "Insert your user id above"
190 msgstr "Π’ΡΡ‚Π°Π²ΡŒΡ‚Π΅ свой ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π²Ρ‹ΡˆΠ΅"
190 msgstr "Π’ΡΡ‚Π°Π²ΡŒΡ‚Π΅ свой ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π²Ρ‹ΡˆΠ΅"
191
191
192 #: templates/boards/post.html:46
192 #: templates/boards/post.html:46
193 msgid "Open"
193 msgid "Open"
194 msgstr "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ"
194 msgstr "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ"
195
195
196 #: templates/boards/post.html:48
196 #: templates/boards/post.html:48
197 msgid "Reply"
197 msgid "Reply"
198 msgstr "ΠžΡ‚Π²Π΅Ρ‚"
198 msgstr "ΠžΡ‚Π²Π΅Ρ‚"
199
199
200 #: templates/boards/post.html:55
200 #: templates/boards/post.html:55
201 msgid "Edit"
201 msgid "Edit"
202 msgstr "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ"
202 msgstr "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ"
203
203
204 #: templates/boards/post.html:57
204 #: templates/boards/post.html:57
205 msgid "Delete"
205 msgid "Delete"
206 msgstr "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ"
206 msgstr "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ"
207
207
208 #: templates/boards/post.html:60
208 #: templates/boards/post.html:60
209 msgid "Ban IP"
209 msgid "Ban IP"
210 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ IP"
210 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ IP"
211
211
212 #: templates/boards/post.html:74
212 #: templates/boards/post.html:74
213 msgid "Replies"
213 msgid "Replies"
214 msgstr "ΠžΡ‚Π²Π΅Ρ‚Ρ‹"
214 msgstr "ΠžΡ‚Π²Π΅Ρ‚Ρ‹"
215
215
216 #: templates/boards/post.html:87 templates/boards/thread.html:82
216 #: templates/boards/post.html:87 templates/boards/thread.html:82
217 #: templates/boards/thread_gallery.html:60
217 #: templates/boards/thread_gallery.html:60
218 msgid "images"
218 msgid "images"
219 msgstr "ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ"
219 msgstr "ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ"
220
220
221 #: templates/boards/post_admin.html:19
221 #: templates/boards/post_admin.html:19
222 msgid "Tags:"
222 msgid "Tags:"
223 msgstr "Π’Π΅Π³ΠΈ:"
223 msgstr "Π’Π΅Π³ΠΈ:"
224
224
225 #: templates/boards/post_admin.html:30
225 #: templates/boards/post_admin.html:30
226 msgid "Add tag"
226 msgid "Add tag"
227 msgstr "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ‚Π΅Π³"
227 msgstr "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ‚Π΅Π³"
228
228
229 #: templates/boards/posting_general.html:56
229 #: templates/boards/posting_general.html:56
230 msgid "Show tag"
230 msgid "Show tag"
231 msgstr "ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚Π΅Π³"
231 msgstr "ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚Π΅Π³"
232
232
233 #: templates/boards/posting_general.html:60
233 #: templates/boards/posting_general.html:60
234 msgid "Hide tag"
234 msgid "Hide tag"
235 msgstr "Π‘ΠΊΡ€Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚Π΅Π³"
235 msgstr "Π‘ΠΊΡ€Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚Π΅Π³"
236
236
237 #: templates/boards/posting_general.html:79
237 #: templates/boards/posting_general.html:79
238 msgid "Previous page"
238 msgid "Previous page"
239 msgstr "ΠŸΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π°Ρ страница"
239 msgstr "ΠŸΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π°Ρ страница"
240
240
241 #: templates/boards/posting_general.html:93
241 #: templates/boards/posting_general.html:93
242 #, python-format
242 #, python-format
243 msgid "Skipped %(count)s replies. Open thread to see all replies."
243 msgid "Skipped %(count)s replies. Open thread to see all replies."
244 msgstr "ΠŸΡ€ΠΎΠΏΡƒΡ‰Π΅Π½ΠΎ %(count)s ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ². ΠžΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ Ρ‚Ρ€Π΅Π΄, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ всС ΠΎΡ‚Π²Π΅Ρ‚Ρ‹."
244 msgstr "ΠŸΡ€ΠΎΠΏΡƒΡ‰Π΅Π½ΠΎ %(count)s ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ². ΠžΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ Ρ‚Ρ€Π΅Π΄, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ всС ΠΎΡ‚Π²Π΅Ρ‚Ρ‹."
245
245
246 #: templates/boards/posting_general.html:119
246 #: templates/boards/posting_general.html:119
247 msgid "Next page"
247 msgid "Next page"
248 msgstr "Π‘Π»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ страница"
248 msgstr "Π‘Π»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ страница"
249
249
250 #: templates/boards/posting_general.html:124
250 #: templates/boards/posting_general.html:124
251 msgid "No threads exist. Create the first one!"
251 msgid "No threads exist. Create the first one!"
252 msgstr "НСт Ρ‚Π΅ΠΌ. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π²ΡƒΡŽ!"
252 msgstr "НСт Ρ‚Π΅ΠΌ. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π²ΡƒΡŽ!"
253
253
254 #: templates/boards/posting_general.html:130
254 #: templates/boards/posting_general.html:130
255 msgid "Create new thread"
255 msgid "Create new thread"
256 msgstr "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ‚Π΅ΠΌΡƒ"
256 msgstr "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ‚Π΅ΠΌΡƒ"
257
257
258 #: templates/boards/posting_general.html:134 templates/boards/thread.html:56
258 #: templates/boards/posting_general.html:134 templates/boards/thread.html:56
259 msgid "Post"
259 msgid "Post"
260 msgstr "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ"
260 msgstr "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ"
261
261
262 #: templates/boards/posting_general.html:138
262 #: templates/boards/posting_general.html:138
263 msgid "Tags must be delimited by spaces. Text or image is required."
263 msgid "Tags must be delimited by spaces. Text or image is required."
264 msgstr ""
264 msgstr ""
265 "Π’Π΅Π³ΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Ρ‹ ΠΏΡ€ΠΎΠ±Π΅Π»Π°ΠΌΠΈ. ВСкст ΠΈΠ»ΠΈ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹."
265 "Π’Π΅Π³ΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Ρ‹ ΠΏΡ€ΠΎΠ±Π΅Π»Π°ΠΌΠΈ. ВСкст ΠΈΠ»ΠΈ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹."
266
266
267 #: templates/boards/posting_general.html:141 templates/boards/thread.html:60
267 #: templates/boards/posting_general.html:141 templates/boards/thread.html:60
268 msgid "Text syntax"
268 msgid "Text syntax"
269 msgstr "Бинтаксис тСкста"
269 msgstr "Бинтаксис тСкста"
270
270
271 #: templates/boards/posting_general.html:151
271 #: templates/boards/posting_general.html:151
272 msgid "Pages:"
272 msgid "Pages:"
273 msgstr "Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Ρ‹: "
273 msgstr "Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Ρ‹: "
274
274
275 #: templates/boards/settings.html:14
275 #: templates/boards/settings.html:14
276 msgid "User:"
276 msgid "User:"
277 msgstr "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ:"
277 msgstr "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ:"
278
278
279 #: templates/boards/settings.html:16
279 #: templates/boards/settings.html:16
280 msgid "You are moderator."
280 msgid "You are moderator."
281 msgstr "Π’Ρ‹ ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ‚ΠΎΡ€."
281 msgstr "Π’Ρ‹ ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ‚ΠΎΡ€."
282
282
283 #: templates/boards/settings.html:19
283 #: templates/boards/settings.html:19
284 msgid "You are veteran."
285 msgstr "Π’Ρ‹ Π²Π΅Ρ‚Π΅Ρ€Π°Π½."
286
287 #: templates/boards/settings.html:22
284 msgid "Posts:"
288 msgid "Posts:"
285 msgstr "Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠΉ:"
289 msgstr "Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠΉ:"
286
290
287 #: templates/boards/settings.html:20
291 #: templates/boards/settings.html:23
288 msgid "First access:"
292 msgid "First access:"
289 msgstr "ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ доступ:"
293 msgstr "ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ доступ:"
290
294
291 #: templates/boards/settings.html:22
295 #: templates/boards/settings.html:25
292 msgid "Last access:"
296 msgid "Last access:"
293 msgstr "ПослСдний доступ: "
297 msgstr "ПослСдний доступ: "
294
298
295 #: templates/boards/settings.html:26
299 #: templates/boards/settings.html:29
296 msgid "Hidden tags:"
300 msgid "Hidden tags:"
297 msgstr "Π‘ΠΊΡ€Ρ‹Ρ‚Ρ‹Π΅ Ρ‚Π΅Π³ΠΈ:"
301 msgstr "Π‘ΠΊΡ€Ρ‹Ρ‚Ρ‹Π΅ Ρ‚Π΅Π³ΠΈ:"
298
302
299 #: templates/boards/settings.html:41
303 #: templates/boards/settings.html:44
300 msgid "Save"
304 msgid "Save"
301 msgstr "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ"
305 msgstr "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ"
302
306
303 #: templates/boards/tags.html:22
307 #: templates/boards/tags.html:22
304 msgid "No tags found."
308 msgid "No tags found."
305 msgstr "Π’Π΅Π³ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹."
309 msgstr "Π’Π΅Π³ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹."
306
310
307 #: templates/boards/thread.html:20 templates/boards/thread_gallery.html:21
311 #: templates/boards/thread.html:20 templates/boards/thread_gallery.html:21
308 msgid "Normal mode"
312 msgid "Normal mode"
309 msgstr "ΠΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ"
313 msgstr "ΠΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ"
310
314
311 #: templates/boards/thread.html:21 templates/boards/thread_gallery.html:22
315 #: templates/boards/thread.html:21 templates/boards/thread_gallery.html:22
312 msgid "Gallery mode"
316 msgid "Gallery mode"
313 msgstr "Π Π΅ΠΆΠΈΠΌ Π³Π°Π»Π΅Ρ€Π΅ΠΈ"
317 msgstr "Π Π΅ΠΆΠΈΠΌ Π³Π°Π»Π΅Ρ€Π΅ΠΈ"
314
318
315 #: templates/boards/thread.html:29
319 #: templates/boards/thread.html:29
316 msgid "posts to bumplimit"
320 msgid "posts to bumplimit"
317 msgstr "сообщСний Π΄ΠΎ Π±Π°ΠΌΠΏΠ»ΠΈΠΌΠΈΡ‚Π°"
321 msgstr "сообщСний Π΄ΠΎ Π±Π°ΠΌΠΏΠ»ΠΈΠΌΠΈΡ‚Π°"
318
322
319 #: templates/boards/thread.html:50
323 #: templates/boards/thread.html:50
320 msgid "Reply to thread"
324 msgid "Reply to thread"
321 msgstr "ΠžΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π² Ρ‚Π΅ΠΌΡƒ"
325 msgstr "ΠžΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π² Ρ‚Π΅ΠΌΡƒ"
322
326
323 #: templates/boards/thread.html:81 templates/boards/thread_gallery.html:59
327 #: templates/boards/thread.html:81 templates/boards/thread_gallery.html:59
324 msgid "replies"
328 msgid "replies"
325 msgstr "ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ²"
329 msgstr "ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ²"
326
330
327 #: templates/boards/thread.html:83 templates/boards/thread_gallery.html:61
331 #: templates/boards/thread.html:83 templates/boards/thread_gallery.html:61
328 msgid "Last update: "
332 msgid "Last update: "
329 msgstr "ПослСднСС обновлСниС: "
333 msgstr "ПослСднСС обновлСниС: "
330
334
331 #: templates/boards/rss/post.html:5
335 #: templates/boards/rss/post.html:5
332 msgid "Post image"
336 msgid "Post image"
333 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ сообщСния"
337 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ сообщСния"
334
338
335 #: templates/boards/staticpages/banned.html:6
339 #: templates/boards/staticpages/banned.html:6
336 msgid "Banned"
340 msgid "Banned"
337 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½"
341 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½"
338
342
339 #: templates/boards/staticpages/banned.html:11
343 #: templates/boards/staticpages/banned.html:11
340 msgid "Your IP address has been banned. Contact the administrator"
344 msgid "Your IP address has been banned. Contact the administrator"
341 msgstr "Π’Π°Ρˆ IP адрСс Π±Ρ‹Π» Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½. Π‘Π²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с администратором"
345 msgstr "Π’Π°Ρˆ IP адрСс Π±Ρ‹Π» Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½. Π‘Π²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с администратором"
342
346
343 #: templates/boards/staticpages/help.html:6
347 #: templates/boards/staticpages/help.html:6
344 #: templates/boards/staticpages/help.html:10
348 #: templates/boards/staticpages/help.html:10
345 msgid "Syntax"
349 msgid "Syntax"
346 msgstr "Бинтаксис"
350 msgstr "Бинтаксис"
347
351
348 #: templates/boards/staticpages/help.html:11
352 #: templates/boards/staticpages/help.html:11
349 msgid "2 line breaks for a new line."
353 msgid "2 line breaks for a new line."
350 msgstr "2 ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π° строки ΡΠΎΠ·Π΄Π°ΡŽΡ‚ Π½ΠΎΠ²Ρ‹ΠΉ Π°Π±Π·Π°Ρ†."
354 msgstr "2 ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π° строки ΡΠΎΠ·Π΄Π°ΡŽΡ‚ Π½ΠΎΠ²Ρ‹ΠΉ Π°Π±Π·Π°Ρ†."
351
355
352 #: templates/boards/staticpages/help.html:12
356 #: templates/boards/staticpages/help.html:12
353 msgid "Italic text"
357 msgid "Italic text"
354 msgstr "ΠšΡƒΡ€ΡΠΈΠ²Π½Ρ‹ΠΉ тСкст"
358 msgstr "ΠšΡƒΡ€ΡΠΈΠ²Π½Ρ‹ΠΉ тСкст"
355
359
356 #: templates/boards/staticpages/help.html:13
360 #: templates/boards/staticpages/help.html:13
357 msgid "Bold text"
361 msgid "Bold text"
358 msgstr "ΠŸΠΎΠ»ΡƒΠΆΠΈΡ€Π½Ρ‹ΠΉ тСкст"
362 msgstr "ΠŸΠΎΠ»ΡƒΠΆΠΈΡ€Π½Ρ‹ΠΉ тСкст"
359
363
360 #: templates/boards/staticpages/help.html:14
364 #: templates/boards/staticpages/help.html:14
361 msgid "Spoiler"
365 msgid "Spoiler"
362 msgstr "Π‘ΠΏΠΎΠΉΠ»Π΅Ρ€"
366 msgstr "Π‘ΠΏΠΎΠΉΠ»Π΅Ρ€"
363
367
364 #: templates/boards/staticpages/help.html:15
368 #: templates/boards/staticpages/help.html:15
365 msgid "Link to a post"
369 msgid "Link to a post"
366 msgstr "Бсылка Π½Π° сообщСниС"
370 msgstr "Бсылка Π½Π° сообщСниС"
367
371
368 #: templates/boards/staticpages/help.html:16
372 #: templates/boards/staticpages/help.html:16
369 msgid "Strikethrough text"
373 msgid "Strikethrough text"
370 msgstr "Π—Π°Ρ‡Π΅Ρ€ΠΊΠ½ΡƒΡ‚Ρ‹ΠΉ тСкст"
374 msgstr "Π—Π°Ρ‡Π΅Ρ€ΠΊΠ½ΡƒΡ‚Ρ‹ΠΉ тСкст"
371
375
372 #: templates/boards/staticpages/help.html:17
376 #: templates/boards/staticpages/help.html:17
373 msgid "You need to new line before:"
377 msgid "You need to new line before:"
374 msgstr "ΠŸΠ΅Ρ€Π΅Π΄ этими Ρ‚Π΅Π³Π°ΠΌΠΈ Π½ΡƒΠΆΠ½Π° новая строка:"
378 msgstr "ΠŸΠ΅Ρ€Π΅Π΄ этими Ρ‚Π΅Π³Π°ΠΌΠΈ Π½ΡƒΠΆΠ½Π° новая строка:"
375
379
376 #: templates/boards/staticpages/help.html:18
380 #: templates/boards/staticpages/help.html:18
377 msgid "Comment"
381 msgid "Comment"
378 msgstr "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ"
382 msgstr "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ"
379
383
380 #: templates/boards/staticpages/help.html:19
384 #: templates/boards/staticpages/help.html:19
381 msgid "Quote"
385 msgid "Quote"
382 msgstr "Π¦ΠΈΡ‚Π°Ρ‚Π°"
386 msgstr "Π¦ΠΈΡ‚Π°Ρ‚Π°"
@@ -1,123 +1,132 b''
1 from django.db import models
1 from django.db import models
2 from django.db.models import Count
2 from django.db.models import Count
3 from boards import settings
3 from boards import settings
4 from boards.models import Post
4 from boards.models import Post
5 from django.core.cache import cache
5 from django.core.cache import cache
6
6
7 __author__ = 'neko259'
7 __author__ = 'neko259'
8
8
9 RANK_ADMIN = 0
9 RANK_ADMIN = 0
10 RANK_MODERATOR = 10
10 RANK_MODERATOR = 10
11 RANK_USER = 100
11 RANK_USER = 100
12
12
13 BAN_REASON_AUTO = 'Auto'
13 BAN_REASON_AUTO = 'Auto'
14 BAN_REASON_MAX_LENGTH = 200
14 BAN_REASON_MAX_LENGTH = 200
15
15
16 VETERAN_POSTS = 1000
17
16
18
17 class User(models.Model):
19 class User(models.Model):
18
20
19 class Meta:
21 class Meta:
20 app_label = 'boards'
22 app_label = 'boards'
21
23
22 user_id = models.CharField(max_length=50)
24 user_id = models.CharField(max_length=50)
23 rank = models.IntegerField()
25 rank = models.IntegerField()
24
26
25 registration_time = models.DateTimeField()
27 registration_time = models.DateTimeField()
26
28
27 fav_tags = models.ManyToManyField('Tag', null=True, blank=True)
29 fav_tags = models.ManyToManyField('Tag', null=True, blank=True)
28 fav_threads = models.ManyToManyField(Post, related_name='+', null=True,
30 fav_threads = models.ManyToManyField(Post, related_name='+', null=True,
29 blank=True)
31 blank=True)
30
32
31 hidden_tags = models.ManyToManyField('Tag', null=True, blank=True,
33 hidden_tags = models.ManyToManyField('Tag', null=True, blank=True,
32 related_name='ht+')
34 related_name='ht+')
33 hidden_threads = models.ManyToManyField('Post', null=True, blank=True,
35 hidden_threads = models.ManyToManyField('Post', null=True, blank=True,
34 related_name='hth+')
36 related_name='hth+')
35
37
36 def save_setting(self, name, value):
38 def save_setting(self, name, value):
37 setting, created = Setting.objects.get_or_create(name=name, user=self)
39 setting, created = Setting.objects.get_or_create(name=name, user=self)
38 setting.value = str(value)
40 setting.value = str(value)
39 setting.save()
41 setting.save()
40
42
41 return setting
43 return setting
42
44
43 def get_setting(self, name):
45 def get_setting(self, name):
44 if Setting.objects.filter(name=name, user=self).exists():
46 if Setting.objects.filter(name=name, user=self).exists():
45 setting = Setting.objects.get(name=name, user=self)
47 setting = Setting.objects.get(name=name, user=self)
46 setting_value = setting.value
48 setting_value = setting.value
47 else:
49 else:
48 setting_value = None
50 setting_value = None
49
51
50 return setting_value
52 return setting_value
51
53
52 def is_moderator(self):
54 def is_moderator(self):
53 return RANK_MODERATOR >= self.rank
55 return RANK_MODERATOR >= self.rank
54
56
55 def get_sorted_fav_tags(self):
57 def get_sorted_fav_tags(self):
56 cache_key = self._get_tag_cache_key()
58 cache_key = self._get_tag_cache_key()
57 fav_tags = cache.get(cache_key)
59 fav_tags = cache.get(cache_key)
58 if fav_tags:
60 if fav_tags:
59 return fav_tags
61 return fav_tags
60
62
61 tags = self.fav_tags.annotate(Count('threads')) \
63 tags = self.fav_tags.annotate(Count('threads')) \
62 .filter(threads__count__gt=0).order_by('name')
64 .filter(threads__count__gt=0).order_by('name')
63
65
64 if tags:
66 if tags:
65 cache.set(cache_key, tags)
67 cache.set(cache_key, tags)
66
68
67 return tags
69 return tags
68
70
69 def get_post_count(self):
71 def get_post_count(self):
70 return Post.objects.filter(user=self).count()
72 return Post.objects.filter(user=self).count()
71
73
72 def __unicode__(self):
74 def __unicode__(self):
73 return self.user_id + '(' + str(self.rank) + ')'
75 return self.user_id + '(' + str(self.rank) + ')'
74
76
75 def get_last_access_time(self):
77 def get_last_access_time(self):
76 """
78 """
77 Gets user's last post time.
79 Gets user's last post time.
78 """
80 """
79
81
80 posts = Post.objects.filter(user=self)
82 posts = Post.objects.filter(user=self)
81 if posts.exists() > 0:
83 if posts.exists() > 0:
82 return posts.latest('pub_time').pub_time
84 return posts.latest('pub_time').pub_time
83
85
84 def add_tag(self, tag):
86 def add_tag(self, tag):
85 self.fav_tags.add(tag)
87 self.fav_tags.add(tag)
86 cache.delete(self._get_tag_cache_key())
88 cache.delete(self._get_tag_cache_key())
87
89
88 def remove_tag(self, tag):
90 def remove_tag(self, tag):
89 self.fav_tags.remove(tag)
91 self.fav_tags.remove(tag)
90 cache.delete(self._get_tag_cache_key())
92 cache.delete(self._get_tag_cache_key())
91
93
92 def hide_tag(self, tag):
94 def hide_tag(self, tag):
93 self.hidden_tags.add(tag)
95 self.hidden_tags.add(tag)
94
96
95 def unhide_tag(self, tag):
97 def unhide_tag(self, tag):
96 self.hidden_tags.remove(tag)
98 self.hidden_tags.remove(tag)
97
99
100 def is_veteran(self):
101 """
102 Returns if a user is old (veteran).
103 """
104
105 return self.get_post_count() >= VETERAN_POSTS
106
98 def _get_tag_cache_key(self):
107 def _get_tag_cache_key(self):
99 return self.user_id + '_tags'
108 return self.user_id + '_tags'
100
109
101
110
102 class Setting(models.Model):
111 class Setting(models.Model):
103
112
104 class Meta:
113 class Meta:
105 app_label = 'boards'
114 app_label = 'boards'
106
115
107 name = models.CharField(max_length=50)
116 name = models.CharField(max_length=50)
108 value = models.CharField(max_length=50)
117 value = models.CharField(max_length=50)
109 user = models.ForeignKey(User)
118 user = models.ForeignKey(User)
110
119
111
120
112 class Ban(models.Model):
121 class Ban(models.Model):
113
122
114 class Meta:
123 class Meta:
115 app_label = 'boards'
124 app_label = 'boards'
116
125
117 ip = models.GenericIPAddressField()
126 ip = models.GenericIPAddressField()
118 reason = models.CharField(default=BAN_REASON_AUTO,
127 reason = models.CharField(default=BAN_REASON_AUTO,
119 max_length=BAN_REASON_MAX_LENGTH)
128 max_length=BAN_REASON_MAX_LENGTH)
120 can_read = models.BooleanField(default=True)
129 can_read = models.BooleanField(default=True)
121
130
122 def __unicode__(self):
131 def __unicode__(self):
123 return self.ip
132 return self.ip
@@ -1,47 +1,50 b''
1 {% extends "boards/base.html" %}
1 {% extends "boards/base.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4 {% load humanize %}
4 {% load humanize %}
5
5
6 {% block head %}
6 {% block head %}
7 <title>{% trans 'Settings' %} - {{ site_name }}</title>
7 <title>{% trans 'Settings' %} - {{ site_name }}</title>
8 {% endblock %}
8 {% endblock %}
9
9
10 {% block content %}
10 {% block content %}
11
11
12 <div class="post">
12 <div class="post">
13 <p>
13 <p>
14 {% trans 'User:' %} <b>{{ user.user_id }}</b>.
14 {% trans 'User:' %} <b>{{ user.user_id }}</b>.
15 {% if user.is_moderator %}
15 {% if user.is_moderator %}
16 {% trans 'You are moderator.' %}
16 {% trans 'You are moderator.' %}
17 {% endif %}
17 {% endif %}
18 {% if user.is_veteran %}
19 {% trans 'You are veteran.' %}
20 {% endif %}
18 </p>
21 </p>
19 <p>{% trans 'Posts:' %} {{ user.get_post_count }}</p>
22 <p>{% trans 'Posts:' %} {{ user.get_post_count }}</p>
20 <p>{% trans 'First access:' %} {{ user.registration_time|naturaltime }}</p>
23 <p>{% trans 'First access:' %} {{ user.registration_time|naturaltime }}</p>
21 {% if user.get_last_access_time %}
24 {% if user.get_last_access_time %}
22 <p>{% trans 'Last access:' %} {{ user.get_last_access_time|naturaltime }}</p>
25 <p>{% trans 'Last access:' %} {{ user.get_last_access_time|naturaltime }}</p>
23 {% endif %}
26 {% endif %}
24 {% with hidden_tags=user.hidden_tags.all %}
27 {% with hidden_tags=user.hidden_tags.all %}
25 {% if hidden_tags %}
28 {% if hidden_tags %}
26 <p>{% trans 'Hidden tags:' %}
29 <p>{% trans 'Hidden tags:' %}
27 {% for tag in hidden_tags %}
30 {% for tag in hidden_tags %}
28 <a class="tag" href="{% url 'tag' tag.name %}">
31 <a class="tag" href="{% url 'tag' tag.name %}">
29 #{{ tag.name }}</a>{% if not forloop.last %},{% endif %}
32 #{{ tag.name }}</a>{% if not forloop.last %},{% endif %}
30 {% endfor %}
33 {% endfor %}
31 </p>
34 </p>
32 {% endif %}
35 {% endif %}
33 {% endwith %}
36 {% endwith %}
34 </div>
37 </div>
35
38
36 <div class="post-form-w">
39 <div class="post-form-w">
37 <div class="post-form">
40 <div class="post-form">
38 <form method="post">{% csrf_token %}
41 <form method="post">{% csrf_token %}
39 {{ form.as_div }}
42 {{ form.as_div }}
40 <div class="form-submit">
43 <div class="form-submit">
41 <input type="submit" value="{% trans "Save" %}" />
44 <input type="submit" value="{% trans "Save" %}" />
42 </div>
45 </div>
43 </form>
46 </form>
44 </div>
47 </div>
45 </div>
48 </div>
46
49
47 {% endblock %}
50 {% endblock %}
General Comments 0
You need to be logged in to leave comments. Login now