##// END OF EJS Templates
Added login and logout for moderators
neko259 -
r729:d56cc46f 2.0-dev
parent child Browse files
Show More
@@ -0,0 +1,33 b''
1 from django.shortcuts import render, redirect
2
3 from boards.abstracts.settingsmanager import SettingsManager, \
4 PERMISSION_MODERATE
5 from boards.forms import LoginForm, PlainErrorList
6 from boards.views.base import BaseBoardView, CONTEXT_FORM
7
8
9 __author__ = 'neko259'
10
11
12 class LoginView(BaseBoardView):
13
14 def get(self, request, form=None):
15 context = self.get_context_data(request=request)
16
17 if not form:
18 form = LoginForm()
19 context[CONTEXT_FORM] = form
20
21 return render(request, 'boards/login.html', context)
22
23 def post(self, request):
24 form = LoginForm(request.POST, request.FILES,
25 error_class=PlainErrorList)
26 form.session = request.session
27
28 if form.is_valid():
29 settings_manager = SettingsManager(request.session)
30 settings_manager.add_permission(PERMISSION_MODERATE)
31 return redirect('index')
32 else:
33 return self.get(request, form)
@@ -0,0 +1,24 b''
1 from django.shortcuts import render
2
3 from boards.abstracts.settingsmanager import SettingsManager, \
4 PERMISSION_MODERATE
5 from boards.forms import LoginForm
6 from boards.views.base import BaseBoardView, CONTEXT_FORM
7
8
9 __author__ = 'neko259'
10
11
12 class LogoutView(BaseBoardView):
13
14 def get(self, request, form=None):
15 settings_manager = SettingsManager(request.session)
16 settings_manager.del_permission(PERMISSION_MODERATE)
17
18 context = self.get_context_data(request=request)
19
20 if not form:
21 form = LoginForm()
22 context[CONTEXT_FORM] = form
23
24 return render(request, 'boards/login.html', context) No newline at end of file
@@ -1,106 +1,114 b''
1 1 from django.shortcuts import get_object_or_404
2 2 from boards.models import Tag
3 3
4 4 __author__ = 'neko259'
5 5
6 6 SESSION_SETTING = 'setting'
7 7
8 8 PERMISSION_MODERATE = 'moderator'
9 9
10 10 SETTING_THEME = 'theme'
11 11 SETTING_FAVORITE_TAGS = 'favorite_tags'
12 12 SETTING_HIDDEN_TAGS = 'hidden_tags'
13 13 SETTING_PERMISSIONS = 'permissions'
14 14
15 15 DEFAULT_THEME = 'md'
16 16
17 17
18 18 class SettingsManager:
19 19
20 20 def __init__(self, session):
21 21 self.session = session
22 22
23 23 def get_theme(self):
24 24 theme = self.get_setting(SETTING_THEME)
25 25 if not theme:
26 26 theme = DEFAULT_THEME
27 27 self.set_setting(SETTING_THEME, theme)
28 28
29 29 return theme
30 30
31 31 def set_theme(self, theme):
32 32 self.set_setting(SETTING_THEME, theme)
33 33
34 34 def has_permission(self, permission):
35 35 permissions = self.get_setting(SETTING_PERMISSIONS)
36 36 if permissions:
37 37 return permission in permissions
38 38 else:
39 39 return False
40 40
41 41 def get_setting(self, setting):
42 42 if setting in self.session:
43 43 return self.session[setting]
44 44 else:
45 45 return None
46 46
47 47 def set_setting(self, setting, value):
48 48 self.session[setting] = value
49 49
50 50 def add_permission(self, permission):
51 51 permissions = self.get_setting(SETTING_PERMISSIONS)
52 52 if not permissions:
53 53 permissions = [permission]
54 54 else:
55 permissions += permission
55 permissions.append(permission)
56 self.set_setting(SETTING_PERMISSIONS, permissions)
57
58 def del_permission(self, permission):
59 permissions = self.get_setting(SETTING_PERMISSIONS)
60 if not permissions:
61 permissions = []
62 else:
63 permissions.remove(permission)
56 64 self.set_setting(SETTING_PERMISSIONS, permissions)
57 65
58 66 def get_fav_tags(self):
59 67 tag_names = self.get_setting(SETTING_FAVORITE_TAGS)
60 68 tags = []
61 69 if tag_names:
62 70 for tag_name in tag_names:
63 71 tag = get_object_or_404(Tag, name=tag_name)
64 72 tags.append(tag)
65 73
66 74 return tags
67 75
68 76 def add_fav_tag(self, tag):
69 77 tags = self.get_setting(SETTING_FAVORITE_TAGS)
70 78 if not tags:
71 79 tags = [tag.name]
72 80 else:
73 81 if not tag.name in tags:
74 82 tags.append(tag.name)
75 83 self.set_setting(SETTING_FAVORITE_TAGS, tags)
76 84
77 85 def del_fav_tag(self, tag):
78 86 tags = self.get_setting(SETTING_FAVORITE_TAGS)
79 87 if tag.name in tags:
80 88 tags.remove(tag.name)
81 89 self.set_setting(SETTING_FAVORITE_TAGS, tags)
82 90
83 91 def get_hidden_tags(self):
84 92 tag_names = self.get_setting(SETTING_HIDDEN_TAGS)
85 93 tags = []
86 94 if tag_names:
87 95 for tag_name in tag_names:
88 96 tag = get_object_or_404(Tag, name=tag_name)
89 97 tags.append(tag)
90 98
91 99 return tags
92 100
93 101 def add_hidden_tag(self, tag):
94 102 tags = self.get_setting(SETTING_HIDDEN_TAGS)
95 103 if not tags:
96 104 tags = [tag.name]
97 105 else:
98 106 if not tag.name in tags:
99 107 tags.append(tag.name)
100 108 self.set_setting(SETTING_HIDDEN_TAGS, tags)
101 109
102 110 def del_hidden_tag(self, tag):
103 111 tags = self.get_setting(SETTING_HIDDEN_TAGS)
104 112 if tag.name in tags:
105 113 tags.remove(tag.name)
106 114 self.set_setting(SETTING_HIDDEN_TAGS, tags)
@@ -1,308 +1,342 b''
1 1 import re
2 2 import time
3 3 import hashlib
4 4
5 5 from captcha.fields import CaptchaField
6 6 from django import forms
7 7 from django.forms.util import ErrorList
8 8 from django.utils.translation import ugettext_lazy as _
9 9
10 10 from boards.mdx_neboard import formatters
11 11 from boards.models.post import TITLE_MAX_LENGTH
12 12 from boards.models import PostImage
13 13 from neboard import settings
14 14 from boards import utils
15 15 import boards.settings as board_settings
16 16
17 17 VETERAN_POSTING_DELAY = 5
18 18
19 19 ATTRIBUTE_PLACEHOLDER = 'placeholder'
20 20
21 21 LAST_POST_TIME = 'last_post_time'
22 22 LAST_LOGIN_TIME = 'last_login_time'
23 23 TEXT_PLACEHOLDER = _('''Type message here. You can reply to message >>123 like
24 24 this. 2 new lines are required to start new paragraph.''')
25 25 TAGS_PLACEHOLDER = _('tag1 several_words_tag')
26 26
27 27 ERROR_IMAGE_DUPLICATE = _('Such image was already posted')
28 28
29 29 LABEL_TITLE = _('Title')
30 30 LABEL_TEXT = _('Text')
31 31 LABEL_TAG = _('Tag')
32 32 LABEL_SEARCH = _('Search')
33 33
34 34 TAG_MAX_LENGTH = 20
35 35
36 36 REGEX_TAG = ur'^[\w\d]+$'
37 37
38 38
39 39 class FormatPanel(forms.Textarea):
40 40 def render(self, name, value, attrs=None):
41 41 output = '<div id="mark-panel">'
42 42 for formatter in formatters:
43 43 output += u'<span class="mark_btn"' + \
44 44 u' onClick="addMarkToMsg(\'' + formatter.format_left + \
45 45 '\', \'' + formatter.format_right + '\')">' + \
46 46 formatter.preview_left + formatter.name + \
47 47 formatter.preview_right + u'</span>'
48 48
49 49 output += '</div>'
50 50 output += super(FormatPanel, self).render(name, value, attrs=None)
51 51
52 52 return output
53 53
54 54
55 55 class PlainErrorList(ErrorList):
56 56 def __unicode__(self):
57 57 return self.as_text()
58 58
59 59 def as_text(self):
60 60 return ''.join([u'(!) %s ' % e for e in self])
61 61
62 62
63 63 class NeboardForm(forms.Form):
64 64
65 65 def as_div(self):
66 66 """
67 67 Returns this form rendered as HTML <as_div>s.
68 68 """
69 69
70 70 return self._html_output(
71 71 # TODO Do not show hidden rows in the list here
72 72 normal_row='<div class="form-row"><div class="form-label">'
73 73 '%(label)s'
74 74 '</div></div>'
75 75 '<div class="form-row"><div class="form-input">'
76 76 '%(field)s'
77 77 '</div></div>'
78 78 '<div class="form-row">'
79 79 '%(help_text)s'
80 80 '</div>',
81 81 error_row='<div class="form-row">'
82 82 '<div class="form-label"></div>'
83 83 '<div class="form-errors">%s</div>'
84 84 '</div>',
85 85 row_ender='</div>',
86 86 help_text_html='%s',
87 87 errors_on_separate_row=True)
88 88
89 89 def as_json_errors(self):
90 90 errors = []
91 91
92 92 for name, field in self.fields.items():
93 93 if self[name].errors:
94 94 errors.append({
95 95 'field': name,
96 96 'errors': self[name].errors.as_text(),
97 97 })
98 98
99 99 return errors
100 100
101 101
102 102 class PostForm(NeboardForm):
103 103
104 104 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False,
105 105 label=LABEL_TITLE)
106 106 text = forms.CharField(
107 107 widget=FormatPanel(attrs={ATTRIBUTE_PLACEHOLDER: TEXT_PLACEHOLDER}),
108 108 required=False, label=LABEL_TEXT)
109 109 image = forms.ImageField(required=False, label=_('Image'),
110 110 widget=forms.ClearableFileInput(
111 111 attrs={'accept': 'image/*'}))
112 112
113 113 # This field is for spam prevention only
114 114 email = forms.CharField(max_length=100, required=False, label=_('e-mail'),
115 115 widget=forms.TextInput(attrs={
116 116 'class': 'form-email'}))
117 117
118 118 session = None
119 119 need_to_ban = False
120 120
121 121 def clean_title(self):
122 122 title = self.cleaned_data['title']
123 123 if title:
124 124 if len(title) > TITLE_MAX_LENGTH:
125 125 raise forms.ValidationError(_('Title must have less than %s '
126 126 'characters') %
127 127 str(TITLE_MAX_LENGTH))
128 128 return title
129 129
130 130 def clean_text(self):
131 131 text = self.cleaned_data['text'].strip()
132 132 if text:
133 133 if len(text) > board_settings.MAX_TEXT_LENGTH:
134 134 raise forms.ValidationError(_('Text must have less than %s '
135 135 'characters') %
136 136 str(board_settings
137 137 .MAX_TEXT_LENGTH))
138 138 return text
139 139
140 140 def clean_image(self):
141 141 image = self.cleaned_data['image']
142 142 if image:
143 143 if image.size > board_settings.MAX_IMAGE_SIZE:
144 144 raise forms.ValidationError(
145 145 _('Image must be less than %s bytes')
146 146 % str(board_settings.MAX_IMAGE_SIZE))
147 147
148 148 md5 = hashlib.md5()
149 149 for chunk in image.chunks():
150 150 md5.update(chunk)
151 151 image_hash = md5.hexdigest()
152 152 if PostImage.objects.filter(hash=image_hash).exists():
153 153 raise forms.ValidationError(ERROR_IMAGE_DUPLICATE)
154 154
155 155 return image
156 156
157 157 def clean(self):
158 158 cleaned_data = super(PostForm, self).clean()
159 159
160 160 if not self.session:
161 161 raise forms.ValidationError('Humans have sessions')
162 162
163 163 if cleaned_data['email']:
164 164 self.need_to_ban = True
165 165 raise forms.ValidationError('A human cannot enter a hidden field')
166 166
167 167 if not self.errors:
168 168 self._clean_text_image()
169 169
170 170 if not self.errors and self.session:
171 171 self._validate_posting_speed()
172 172
173 173 return cleaned_data
174 174
175 175 def _clean_text_image(self):
176 176 text = self.cleaned_data.get('text')
177 177 image = self.cleaned_data.get('image')
178 178
179 179 if (not text) and (not image):
180 180 error_message = _('Either text or image must be entered.')
181 181 self._errors['text'] = self.error_class([error_message])
182 182
183 183 def _validate_posting_speed(self):
184 184 can_post = True
185 185
186 186 # TODO Remove this, it's only for test
187 187 if not 'user_id' in self.session:
188 188 return
189 189
190 190 posting_delay = settings.POSTING_DELAY
191 191
192 192 if board_settings.LIMIT_POSTING_SPEED and LAST_POST_TIME in \
193 193 self.session:
194 194 now = time.time()
195 195 last_post_time = self.session[LAST_POST_TIME]
196 196
197 197 current_delay = int(now - last_post_time)
198 198
199 199 if current_delay < posting_delay:
200 200 error_message = _('Wait %s seconds after last posting') % str(
201 201 posting_delay - current_delay)
202 202 self._errors['text'] = self.error_class([error_message])
203 203
204 204 can_post = False
205 205
206 206 if can_post:
207 207 self.session[LAST_POST_TIME] = time.time()
208 208
209 209
210 210 class ThreadForm(PostForm):
211 211
212 212 regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE)
213 213
214 214 tags = forms.CharField(
215 215 widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}),
216 216 max_length=100, label=_('Tags'), required=True)
217 217
218 218 def clean_tags(self):
219 219 tags = self.cleaned_data['tags'].strip()
220 220
221 221 if not tags or not self.regex_tags.match(tags):
222 222 raise forms.ValidationError(
223 223 _('Inappropriate characters in tags.'))
224 224
225 225 return tags
226 226
227 227 def clean(self):
228 228 cleaned_data = super(ThreadForm, self).clean()
229 229
230 230 return cleaned_data
231 231
232 232
233 233 class PostCaptchaForm(PostForm):
234 234 captcha = CaptchaField()
235 235
236 236 def __init__(self, *args, **kwargs):
237 237 self.request = kwargs['request']
238 238 del kwargs['request']
239 239
240 240 super(PostCaptchaForm, self).__init__(*args, **kwargs)
241 241
242 242 def clean(self):
243 243 cleaned_data = super(PostCaptchaForm, self).clean()
244 244
245 245 success = self.is_valid()
246 246 utils.update_captcha_access(self.request, success)
247 247
248 248 if success:
249 249 return cleaned_data
250 250 else:
251 251 raise forms.ValidationError(_("Captcha validation failed"))
252 252
253 253
254 254 class ThreadCaptchaForm(ThreadForm):
255 255 captcha = CaptchaField()
256 256
257 257 def __init__(self, *args, **kwargs):
258 258 self.request = kwargs['request']
259 259 del kwargs['request']
260 260
261 261 super(ThreadCaptchaForm, self).__init__(*args, **kwargs)
262 262
263 263 def clean(self):
264 264 cleaned_data = super(ThreadCaptchaForm, self).clean()
265 265
266 266 success = self.is_valid()
267 267 utils.update_captcha_access(self.request, success)
268 268
269 269 if success:
270 270 return cleaned_data
271 271 else:
272 272 raise forms.ValidationError(_("Captcha validation failed"))
273 273
274 274
275 275 class SettingsForm(NeboardForm):
276 276
277 277 theme = forms.ChoiceField(choices=settings.THEMES,
278 278 label=_('Theme'))
279 279
280 280
281 class ModeratorSettingsForm(SettingsForm):
282
283 moderate = forms.BooleanField(required=False, label=_('Enable moderation '
284 'panel'))
285
286
287 281 class AddTagForm(NeboardForm):
288 282
289 283 tag = forms.CharField(max_length=TAG_MAX_LENGTH, label=LABEL_TAG)
290 284 method = forms.CharField(widget=forms.HiddenInput(), initial='add_tag')
291 285
292 286 def clean_tag(self):
293 287 tag = self.cleaned_data['tag']
294 288
295 289 regex_tag = re.compile(REGEX_TAG, re.UNICODE)
296 290 if not regex_tag.match(tag):
297 291 raise forms.ValidationError(_('Inappropriate characters in tags.'))
298 292
299 293 return tag
300 294
301 295 def clean(self):
302 296 cleaned_data = super(AddTagForm, self).clean()
303 297
304 298 return cleaned_data
305 299
306 300
307 301 class SearchForm(NeboardForm):
308 query = forms.CharField(max_length=500, label=LABEL_SEARCH, required=False) No newline at end of file
302 query = forms.CharField(max_length=500, label=LABEL_SEARCH, required=False)
303
304
305 class LoginForm(NeboardForm):
306
307 password = forms.CharField()
308
309 session = None
310
311 def clean_password(self):
312 password = self.cleaned_data['password']
313 if board_settings.MASTER_PASSWORD != password:
314 raise forms.ValidationError(_('Invalid master password'))
315
316 return password
317
318 def _validate_login_speed(self):
319 can_post = True
320
321 if LAST_LOGIN_TIME in self.session:
322 now = time.time()
323 last_login_time = self.session[LAST_LOGIN_TIME]
324
325 current_delay = int(now - last_login_time)
326
327 if current_delay < board_settings.LOGIN_TIMEOUT:
328 error_message = _('Wait %s minutes after last login') % str(
329 (board_settings.LOGIN_TIMEOUT - current_delay) / 60)
330 self._errors['password'] = self.error_class([error_message])
331
332 can_post = False
333
334 if can_post:
335 self.session[LAST_LOGIN_TIME] = time.time()
336
337 def clean(self):
338 self._validate_login_speed()
339
340 cleaned_data = super(LoginForm, self).clean()
341
342 return cleaned_data
1 NO CONTENT: modified file, binary diff hidden
@@ -1,392 +1,368 b''
1 1 # SOME DESCRIPTIVE TITLE.
2 2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 3 # This file is distributed under the same license as the PACKAGE package.
4 4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5 5 #
6 6 msgid ""
7 7 msgstr ""
8 8 "Project-Id-Version: PACKAGE VERSION\n"
9 9 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2014-06-29 13:46+0300\n"
10 "POT-Creation-Date: 2014-07-05 18:10+0300\n"
11 11 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12 12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13 13 "Language-Team: LANGUAGE <LL@li.org>\n"
14 14 "Language: ru\n"
15 15 "MIME-Version: 1.0\n"
16 16 "Content-Type: text/plain; charset=UTF-8\n"
17 17 "Content-Transfer-Encoding: 8bit\n"
18 18 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
19 19 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
20 20
21 #: authors.py:5
21 #: authors.py:9
22 22 msgid "author"
23 23 msgstr "Π°Π²Ρ‚ΠΎΡ€"
24 24
25 #: authors.py:6
25 #: authors.py:10
26 26 msgid "developer"
27 27 msgstr "Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ"
28 28
29 #: authors.py:7
29 #: authors.py:11
30 30 msgid "javascript developer"
31 31 msgstr "Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ javascript"
32 32
33 #: authors.py:8
33 #: authors.py:12
34 34 msgid "designer"
35 35 msgstr "Π΄ΠΈΠ·Π°ΠΉΠ½Π΅Ρ€"
36 36
37 37 #: forms.py:23
38 38 msgid ""
39 39 "Type message here. You can reply to message >>123 like\n"
40 40 " this. 2 new lines are required to start new paragraph."
41 41 msgstr ""
42 42 "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ сообщСниС здСсь. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π½Π° сообщСниС >>123 Π²ΠΎΡ‚ Ρ‚Π°ΠΊ. 2 "
43 43 "пСрСноса строки ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ для создания Π½ΠΎΠ²ΠΎΠ³ΠΎ Π°Π±Π·Π°Ρ†Π°."
44 44
45 45 #: forms.py:25
46 46 msgid "tag1 several_words_tag"
47 47 msgstr "Ρ‚Π΅Π³1 Ρ‚Π΅Π³_ΠΈΠ·_Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ…_слов"
48 48
49 49 #: forms.py:27
50 50 msgid "Such image was already posted"
51 51 msgstr "Π’Π°ΠΊΠΎΠ΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π±Ρ‹Π»ΠΎ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½ΠΎ"
52 52
53 53 #: forms.py:29
54 54 msgid "Title"
55 55 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ"
56 56
57 57 #: forms.py:30
58 58 msgid "Text"
59 59 msgstr "ВСкст"
60 60
61 61 #: forms.py:31
62 62 msgid "Tag"
63 63 msgstr "Π’Π΅Π³"
64 64
65 #: forms.py:32 templates/boards/base.html:50 templates/search/search.html:9
65 #: forms.py:32 templates/boards/base.html:54 templates/search/search.html:9
66 66 #: templates/search/search.html.py:13
67 67 msgid "Search"
68 68 msgstr "Поиск"
69 69
70 70 #: forms.py:109
71 71 msgid "Image"
72 72 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅"
73 73
74 #: forms.py:113
74 #: forms.py:114
75 75 msgid "e-mail"
76 76 msgstr ""
77 77
78 #: forms.py:124
78 #: forms.py:125
79 79 #, python-format
80 80 msgid "Title must have less than %s characters"
81 81 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅Ρ‚ΡŒ мСньшС %s символов"
82 82
83 #: forms.py:133
83 #: forms.py:134
84 84 #, python-format
85 85 msgid "Text must have less than %s characters"
86 86 msgstr "ВСкст Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΠΊΠΎΡ€ΠΎΡ‡Π΅ %s символов"
87 87
88 #: forms.py:144
88 #: forms.py:145
89 89 #, python-format
90 90 msgid "Image must be less than %s bytes"
91 91 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ΠΌΠ΅Π½Π΅Π΅ %s Π±Π°ΠΉΡ‚"
92 92
93 #: forms.py:179
93 #: forms.py:180
94 94 msgid "Either text or image must be entered."
95 95 msgstr "ВСкст ΠΈΠ»ΠΈ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Π²Π²Π΅Π΄Π΅Π½Ρ‹."
96 96
97 #: forms.py:202
97 #: forms.py:200
98 98 #, python-format
99 99 msgid "Wait %s seconds after last posting"
100 100 msgstr "ΠŸΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ %s сСкунд послС послСднСго постинга"
101 101
102 #: forms.py:218 templates/boards/tags.html:7 templates/boards/rss/post.html:10
102 #: forms.py:216 templates/boards/tags.html:7 templates/boards/rss/post.html:10
103 103 msgid "Tags"
104 104 msgstr "Π’Π΅Π³ΠΈ"
105 105
106 #: forms.py:225 forms.py:344
106 #: forms.py:223 forms.py:291
107 107 msgid "Inappropriate characters in tags."
108 108 msgstr "НСдопустимыС символы Π² Ρ‚Π΅Π³Π°Ρ…."
109 109
110 #: forms.py:253 forms.py:274
110 #: forms.py:251 forms.py:272
111 111 msgid "Captcha validation failed"
112 112 msgstr "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠ°ΠΏΡ‡ΠΈ ΠΏΡ€ΠΎΠ²Π°Π»Π΅Π½Π°"
113 113
114 #: forms.py:280
114 #: forms.py:278
115 115 msgid "Theme"
116 116 msgstr "Π’Π΅ΠΌΠ°"
117 117
118 #: forms.py:285
119 msgid "Enable moderation panel"
120 msgstr "Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ панСль ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ†ΠΈΠΈ"
118 #: forms.py:314
119 msgid "Invalid master password"
120 msgstr "НСвСрный мастСр-ΠΏΠ°Ρ€ΠΎΠ»ΡŒ"
121 121
122 #: forms.py:300
123 msgid "No such user found"
124 msgstr "Π”Π°Π½Π½Ρ‹ΠΉ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½"
125
126 #: forms.py:314
122 #: forms.py:328
127 123 #, python-format
128 124 msgid "Wait %s minutes after last login"
129 125 msgstr "ΠŸΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ %s ΠΌΠΈΠ½ΡƒΡ‚ послС послСднСго Π²Ρ…ΠΎΠ΄Π°"
130 126
131 127 #: templates/boards/404.html:6
132 128 msgid "Not found"
133 129 msgstr "НС найдСно"
134 130
135 131 #: templates/boards/404.html:12
136 132 msgid "This page does not exist"
137 133 msgstr "Π­Ρ‚ΠΎΠΉ страницы Π½Π΅ сущСствуСт"
138 134
139 135 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
140 136 msgid "Authors"
141 137 msgstr "Авторы"
142 138
143 139 #: templates/boards/authors.html:26
144 140 msgid "Distributed under the"
145 141 msgstr "РаспространяСтся ΠΏΠΎΠ΄"
146 142
147 143 #: templates/boards/authors.html:28
148 144 msgid "license"
149 145 msgstr "Π»ΠΈΡ†Π΅Π½Π·ΠΈΠ΅ΠΉ"
150 146
151 147 #: templates/boards/authors.html:30
152 148 msgid "Repository"
153 149 msgstr "Π Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ"
154 150
155 151 #: templates/boards/base.html:12
156 152 msgid "Feed"
157 153 msgstr "Π›Π΅Π½Ρ‚Π°"
158 154
159 155 #: templates/boards/base.html:29
160 156 msgid "All threads"
161 157 msgstr "ВсС Ρ‚Π΅ΠΌΡ‹"
162 158
163 159 #: templates/boards/base.html:34
164 160 msgid "Tag management"
165 161 msgstr "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ‚Π΅Π³Π°ΠΌΠΈ"
166 162
167 163 #: templates/boards/base.html:36 templates/boards/settings.html:7
168 164 msgid "Settings"
169 165 msgstr "Настройки"
170 166
171 #: templates/boards/base.html:49 templates/boards/login.html:6
167 #: templates/boards/base.html:50
168 msgid "Logout"
169 msgstr "Π’Ρ‹Ρ…ΠΎΠ΄"
170
171 #: templates/boards/base.html:52 templates/boards/login.html:6
172 172 #: templates/boards/login.html.py:16
173 173 msgid "Login"
174 174 msgstr "Π’Ρ…ΠΎΠ΄"
175 175
176 #: templates/boards/base.html:52
176 #: templates/boards/base.html:56
177 177 #, python-format
178 178 msgid "Speed: %(ppd)s posts per day"
179 179 msgstr "Π‘ΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ: %(ppd)s сообщСний Π² дСнь"
180 180
181 #: templates/boards/base.html:54
181 #: templates/boards/base.html:58
182 182 msgid "Up"
183 183 msgstr "Π’Π²Π΅Ρ€Ρ…"
184 184
185 185 #: templates/boards/login.html:19
186 186 msgid "Insert your user id above"
187 187 msgstr "Π’ΡΡ‚Π°Π²ΡŒΡ‚Π΅ свой ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π²Ρ‹ΡˆΠ΅"
188 188
189 189 #: templates/boards/post.html:21 templates/boards/staticpages/help.html:19
190 190 msgid "Quote"
191 191 msgstr "Π¦ΠΈΡ‚Π°Ρ‚Π°"
192 192
193 193 #: templates/boards/post.html:31
194 194 msgid "Open"
195 195 msgstr "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ"
196 196
197 197 #: templates/boards/post.html:33
198 198 msgid "Reply"
199 199 msgstr "ΠžΡ‚Π²Π΅Ρ‚"
200 200
201 201 #: templates/boards/post.html:40
202 202 msgid "Edit"
203 203 msgstr "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ"
204 204
205 205 #: templates/boards/post.html:42
206 206 msgid "Delete"
207 207 msgstr "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ"
208 208
209 209 #: templates/boards/post.html:45
210 210 msgid "Ban IP"
211 211 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ IP"
212 212
213 213 #: templates/boards/post.html:76
214 214 msgid "Replies"
215 215 msgstr "ΠžΡ‚Π²Π΅Ρ‚Ρ‹"
216 216
217 217 #: templates/boards/post.html:86 templates/boards/thread.html:88
218 218 #: templates/boards/thread_gallery.html:61
219 219 msgid "replies"
220 220 msgstr "ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ²"
221 221
222 222 #: templates/boards/post.html:87 templates/boards/thread.html:89
223 223 #: templates/boards/thread_gallery.html:62
224 224 msgid "images"
225 225 msgstr "ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ"
226 226
227 227 #: templates/boards/post_admin.html:19
228 228 msgid "Tags:"
229 229 msgstr "Π’Π΅Π³ΠΈ:"
230 230
231 231 #: templates/boards/post_admin.html:30
232 232 msgid "Add tag"
233 233 msgstr "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ‚Π΅Π³"
234 234
235 235 #: templates/boards/posting_general.html:56
236 236 msgid "Show tag"
237 237 msgstr "ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚Π΅Π³"
238 238
239 239 #: templates/boards/posting_general.html:60
240 240 msgid "Hide tag"
241 241 msgstr "Π‘ΠΊΡ€Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚Π΅Π³"
242 242
243 243 #: templates/boards/posting_general.html:79 templates/search/search.html:22
244 244 msgid "Previous page"
245 245 msgstr "ΠŸΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π°Ρ страница"
246 246
247 247 #: templates/boards/posting_general.html:94
248 248 #, python-format
249 249 msgid "Skipped %(count)s replies. Open thread to see all replies."
250 250 msgstr "ΠŸΡ€ΠΎΠΏΡƒΡ‰Π΅Π½ΠΎ %(count)s ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ². ΠžΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ Ρ‚Ρ€Π΅Π΄, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ всС ΠΎΡ‚Π²Π΅Ρ‚Ρ‹."
251 251
252 #: templates/boards/posting_general.html:121 templates/search/search.html:35
252 #: templates/boards/posting_general.html:121 templates/search/search.html:33
253 253 msgid "Next page"
254 254 msgstr "Π‘Π»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ страница"
255 255
256 256 #: templates/boards/posting_general.html:126
257 257 msgid "No threads exist. Create the first one!"
258 258 msgstr "НСт Ρ‚Π΅ΠΌ. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π²ΡƒΡŽ!"
259 259
260 260 #: templates/boards/posting_general.html:132
261 261 msgid "Create new thread"
262 262 msgstr "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ‚Π΅ΠΌΡƒ"
263 263
264 264 #: templates/boards/posting_general.html:137 templates/boards/thread.html:58
265 265 msgid "Post"
266 266 msgstr "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ"
267 267
268 268 #: templates/boards/posting_general.html:142
269 269 msgid "Tags must be delimited by spaces. Text or image is required."
270 270 msgstr ""
271 271 "Π’Π΅Π³ΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Ρ‹ ΠΏΡ€ΠΎΠ±Π΅Π»Π°ΠΌΠΈ. ВСкст ΠΈΠ»ΠΈ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹."
272 272
273 273 #: templates/boards/posting_general.html:145 templates/boards/thread.html:66
274 274 msgid "Text syntax"
275 275 msgstr "Бинтаксис тСкста"
276 276
277 277 #: templates/boards/posting_general.html:157
278 278 msgid "Pages:"
279 279 msgstr "Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Ρ‹: "
280 280
281 #: templates/boards/settings.html:14
282 msgid "User:"
283 msgstr "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ:"
284
285 #: templates/boards/settings.html:16
281 #: templates/boards/settings.html:15
286 282 msgid "You are moderator."
287 283 msgstr "Π’Ρ‹ ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ‚ΠΎΡ€."
288 284
289 #: templates/boards/settings.html:19
290 msgid "You are veteran."
291 msgstr "Π’Ρ‹ Π²Π΅Ρ‚Π΅Ρ€Π°Π½."
292
293 #: templates/boards/settings.html:22
294 msgid "Posts:"
295 msgstr "Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠΉ:"
296
297 #: templates/boards/settings.html:23
298 msgid "First access:"
299 msgstr "ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ доступ:"
300
301 #: templates/boards/settings.html:25
302 msgid "Last access:"
303 msgstr "ПослСдний доступ: "
304
305 #: templates/boards/settings.html:29
285 #: templates/boards/settings.html:20
306 286 msgid "Hidden tags:"
307 287 msgstr "Π‘ΠΊΡ€Ρ‹Ρ‚Ρ‹Π΅ Ρ‚Π΅Π³ΠΈ:"
308 288
309 #: templates/boards/settings.html:44
289 #: templates/boards/settings.html:35
310 290 msgid "Save"
311 291 msgstr "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ"
312 292
313 293 #: templates/boards/tags.html:22
314 294 msgid "No tags found."
315 295 msgstr "Π’Π΅Π³ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹."
316 296
317 297 #: templates/boards/thread.html:20 templates/boards/thread_gallery.html:21
318 298 msgid "Normal mode"
319 299 msgstr "ΠΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ"
320 300
321 301 #: templates/boards/thread.html:21 templates/boards/thread_gallery.html:22
322 302 msgid "Gallery mode"
323 303 msgstr "Π Π΅ΠΆΠΈΠΌ Π³Π°Π»Π΅Ρ€Π΅ΠΈ"
324 304
325 305 #: templates/boards/thread.html:29
326 306 msgid "posts to bumplimit"
327 307 msgstr "сообщСний Π΄ΠΎ Π±Π°ΠΌΠΏΠ»ΠΈΠΌΠΈΡ‚Π°"
328 308
329 309 #: templates/boards/thread.html:50
330 310 msgid "Reply to thread"
331 311 msgstr "ΠžΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π² Ρ‚Π΅ΠΌΡƒ"
332 312
333 313 #: templates/boards/thread.html:63
334 314 msgid "Switch mode"
335 315 msgstr "ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ€Π΅ΠΆΠΈΠΌ"
336 316
337 317 #: templates/boards/thread.html:90 templates/boards/thread_gallery.html:63
338 318 msgid "Last update: "
339 319 msgstr "ПослСднСС обновлСниС: "
340 320
341 321 #: templates/boards/rss/post.html:5
342 322 msgid "Post image"
343 323 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ сообщСния"
344 324
345 325 #: templates/boards/staticpages/banned.html:6
346 326 msgid "Banned"
347 327 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½"
348 328
349 329 #: templates/boards/staticpages/banned.html:11
350 330 msgid "Your IP address has been banned. Contact the administrator"
351 331 msgstr "Π’Π°Ρˆ IP адрСс Π±Ρ‹Π» Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½. Π‘Π²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с администратором"
352 332
353 333 #: templates/boards/staticpages/help.html:6
354 334 #: templates/boards/staticpages/help.html:10
355 335 msgid "Syntax"
356 336 msgstr "Бинтаксис"
357 337
358 338 #: templates/boards/staticpages/help.html:11
359 339 msgid "2 line breaks for a new line."
360 340 msgstr "2 ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π° строки ΡΠΎΠ·Π΄Π°ΡŽΡ‚ Π½ΠΎΠ²Ρ‹ΠΉ Π°Π±Π·Π°Ρ†."
361 341
362 342 #: templates/boards/staticpages/help.html:12
363 343 msgid "Italic text"
364 344 msgstr "ΠšΡƒΡ€ΡΠΈΠ²Π½Ρ‹ΠΉ тСкст"
365 345
366 346 #: templates/boards/staticpages/help.html:13
367 347 msgid "Bold text"
368 348 msgstr "ΠŸΠΎΠ»ΡƒΠΆΠΈΡ€Π½Ρ‹ΠΉ тСкст"
369 349
370 350 #: templates/boards/staticpages/help.html:14
371 351 msgid "Spoiler"
372 352 msgstr "Π‘ΠΏΠΎΠΉΠ»Π΅Ρ€"
373 353
374 354 #: templates/boards/staticpages/help.html:15
375 355 msgid "Link to a post"
376 356 msgstr "Бсылка Π½Π° сообщСниС"
377 357
378 358 #: templates/boards/staticpages/help.html:16
379 359 msgid "Strikethrough text"
380 360 msgstr "Π—Π°Ρ‡Π΅Ρ€ΠΊΠ½ΡƒΡ‚Ρ‹ΠΉ тСкст"
381 361
382 362 #: templates/boards/staticpages/help.html:17
383 363 msgid "You need to new line before:"
384 364 msgstr "ΠŸΠ΅Ρ€Π΅Π΄ этими Ρ‚Π΅Π³Π°ΠΌΠΈ Π½ΡƒΠΆΠ½Π° новая строка:"
385 365
386 366 #: templates/boards/staticpages/help.html:18
387 367 msgid "Comment"
388 msgstr "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ"
389
390 #: templates/search/search.html:30
391 msgid "No results found."
392 msgstr "Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹."
368 msgstr "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ" No newline at end of file
@@ -1,20 +1,23 b''
1 1 VERSION = '1.8.1 Kara'
2 2 SITE_NAME = 'Neboard'
3 3
4 4 CACHE_TIMEOUT = 600 # Timeout for caching, if cache is used
5 5 LOGIN_TIMEOUT = 3600 # Timeout between login tries
6 6 MAX_TEXT_LENGTH = 30000 # Max post length in characters
7 7 MAX_IMAGE_SIZE = 8 * 1024 * 1024 # Max image size
8 8
9 9 # Thread bumplimit
10 10 MAX_POSTS_PER_THREAD = 10
11 11 # Old posts will be archived or deleted if this value is reached
12 12 MAX_THREAD_COUNT = 5
13 13 THREADS_PER_PAGE = 3
14 14 DEFAULT_THEME = 'md'
15 15 LAST_REPLIES_COUNT = 3
16 16
17 17 # Enable archiving threads instead of deletion when the thread limit is reached
18 18 ARCHIVE_THREADS = True
19 19 # Limit posting speed
20 LIMIT_POSTING_SPEED = False No newline at end of file
20 LIMIT_POSTING_SPEED = False
21
22 # This password is used to add admin permissions to the user
23 MASTER_PASSWORD = u'password' No newline at end of file
@@ -1,61 +1,66 b''
1 1 {% load staticfiles %}
2 2 {% load i18n %}
3 3 {% load l10n %}
4 4 {% load static from staticfiles %}
5 5
6 6 <!DOCTYPE html>
7 7 <html>
8 8 <head>
9 9 <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}" media="all"/>
10 10 <link rel="stylesheet" type="text/css" href="{% static 'css/3party/highlight.css' %}" media="all"/>
11 11 <link rel="stylesheet" type="text/css" href="{% static theme_css %}" media="all"/>
12 12 <link rel="alternate" type="application/rss+xml" href="rss/" title="{% trans 'Feed' %}"/>
13 13
14 14 <link rel="icon" type="image/png"
15 15 href="{% static 'favicon.png' %}">
16 16
17 17 <meta name="viewport" content="width=device-width, initial-scale=1"/>
18 18 <meta charset="utf-8"/>
19 19
20 20 {% block head %}{% endblock %}
21 21 </head>
22 22 <body>
23 23 <script src="{% static 'js/jquery-2.0.1.min.js' %}"></script>
24 24 <script src="{% static 'js/jquery-ui-1.10.3.custom.min.js' %}"></script>
25 25 <script src="{% static 'js/jquery.mousewheel.js' %}"></script>
26 26 <script src="{% url 'js_info_dict' %}"></script>
27 27
28 28 <div class="navigation_panel">
29 29 <a class="link" href="{% url 'index' %}">{% trans "All threads" %}</a>
30 30 {% for tag in tags %}
31 31 <a class="tag" href="{% url 'tag' tag_name=tag.name %}"
32 32 >#{{ tag.name }}</a>,
33 33 {% endfor %}
34 34 <a href="{% url 'tags' %}" title="{% trans 'Tag management' %}"
35 35 >[...]</a>
36 36 <a class="link" href="{% url 'settings' %}">{% trans 'Settings' %}</a>
37 37 </div>
38 38
39 39 {% block content %}{% endblock %}
40 40
41 41 <script src="{% static 'js/popup.js' %}"></script>
42 42 <script src="{% static 'js/image.js' %}"></script>
43 43 <script src="{% static 'js/3party/highlight.min.js' %}"></script>
44 44 <script src="{% static 'js/refpopup.js' %}"></script>
45 45 <script src="{% static 'js/main.js' %}"></script>
46 46
47 47 <div class="navigation_panel">
48 48 {% block metapanel %}{% endblock %}
49 {% if moderator %}
50 [<a href="{% url "logout" %}">{% trans 'Logout' %}</a>]
51 {% else %}
52 [<a href="{% url "login" %}">{% trans 'Login' %}</a>]
53 {% endif %}
49 54 [<a href="{% url "search" %}">{% trans 'Search' %}</a>]
50 55 {% with ppd=posts_per_day|floatformat:2 %}
51 56 {% blocktrans %}Speed: {{ ppd }} posts per day{% endblocktrans %}
52 57 {% endwith %}
53 58 <a class="link" href="#top">{% trans 'Up' %}</a>
54 59 </div>
55 60
56 61 <div class="footer">
57 62 <!-- Put your banners here -->
58 63 </div>
59 64
60 65 </body>
61 66 </html>
@@ -1,80 +1,84 b''
1 1 from django.conf.urls import patterns, url, include
2 2 from boards import views
3 3 from boards.rss import AllThreadsFeed, TagThreadsFeed, ThreadPostsFeed
4 4 from boards.views import api, tag_threads, all_threads, \
5 settings, all_tags
5 login, settings, all_tags, logout
6 6 from boards.views.authors import AuthorsView
7 7 from boards.views.delete_post import DeletePostView
8 8 from boards.views.ban import BanUserView
9 9 from boards.views.search import BoardSearchView
10 10 from boards.views.static import StaticPageView
11 11 from boards.views.post_admin import PostAdminView
12 12
13 13 js_info_dict = {
14 14 'packages': ('boards',),
15 15 }
16 16
17 17 urlpatterns = patterns('',
18 18
19 19 # /boards/
20 20 url(r'^$', all_threads.AllThreadsView.as_view(), name='index'),
21 21 # /boards/page/
22 22 url(r'^page/(?P<page>\w+)/$', all_threads.AllThreadsView.as_view(),
23 23 name='index'),
24 24
25 # login page
26 url(r'^login/$', login.LoginView.as_view(), name='login'),
27 url(r'^logout/$', logout.LogoutView.as_view(), name='logout'),
28
25 29 # /boards/tag/tag_name/
26 30 url(r'^tag/(?P<tag_name>\w+)/$', tag_threads.TagView.as_view(),
27 31 name='tag'),
28 32 # /boards/tag/tag_id/page/
29 33 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/$',
30 34 tag_threads.TagView.as_view(), name='tag'),
31 35
32 36 # /boards/thread/
33 37 url(r'^thread/(?P<post_id>\w+)/$', views.thread.ThreadView.as_view(),
34 38 name='thread'),
35 39 url(r'^thread/(?P<post_id>\w+)/mode/(?P<mode>\w+)/$', views.thread.ThreadView
36 40 .as_view(), name='thread_mode'),
37 41
38 42 # /boards/post_admin/
39 43 url(r'^post_admin/(?P<post_id>\w+)/$', PostAdminView.as_view(),
40 44 name='post_admin'),
41 45
42 46 url(r'^settings/$', settings.SettingsView.as_view(), name='settings'),
43 47 url(r'^tags/$', all_tags.AllTagsView.as_view(), name='tags'),
44 48 url(r'^captcha/', include('captcha.urls')),
45 49 url(r'^authors/$', AuthorsView.as_view(), name='authors'),
46 50 url(r'^delete/(?P<post_id>\w+)/$', DeletePostView.as_view(),
47 51 name='delete'),
48 52 url(r'^ban/(?P<post_id>\w+)/$', BanUserView.as_view(), name='ban'),
49 53
50 54 url(r'^banned/$', views.banned.BannedView.as_view(), name='banned'),
51 55 url(r'^staticpage/(?P<name>\w+)/$', StaticPageView.as_view(),
52 56 name='staticpage'),
53 57
54 58 # RSS feeds
55 59 url(r'^rss/$', AllThreadsFeed()),
56 60 url(r'^page/(?P<page>\w+)/rss/$', AllThreadsFeed()),
57 61 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
58 62 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
59 63 url(r'^thread/(?P<post_id>\w+)/rss/$', ThreadPostsFeed()),
60 64
61 65 # i18n
62 66 url(r'^jsi18n/$', 'boards.views.cached_js_catalog', js_info_dict,
63 67 name='js_info_dict'),
64 68
65 69 # API
66 70 url(r'^api/post/(?P<post_id>\w+)/$', api.get_post, name="get_post"),
67 71 url(r'^api/diff_thread/(?P<thread_id>\w+)/(?P<last_update_time>\w+)/$',
68 72 api.api_get_threaddiff, name="get_thread_diff"),
69 73 url(r'^api/threads/(?P<count>\w+)/$', api.api_get_threads,
70 74 name='get_threads'),
71 75 url(r'^api/tags/$', api.api_get_tags, name='get_tags'),
72 76 url(r'^api/thread/(?P<opening_post_id>\w+)/$', api.api_get_thread_posts,
73 77 name='get_thread'),
74 78 url(r'^api/add_post/(?P<opening_post_id>\w+)/$', api.api_add_post,
75 79 name='add_post'),
76 80
77 81 # Search
78 82 url(r'^search/$', BoardSearchView.as_view(), name='search'),
79 83
80 84 )
@@ -1,55 +1,35 b''
1 1 from django.db import transaction
2 2 from django.shortcuts import render, redirect
3 from boards import utils
4 from boards.abstracts.settingsmanager import SettingsManager, \
5 PERMISSION_MODERATE
3 from boards.abstracts.settingsmanager import SettingsManager
6 4
7 5 from boards.views.base import BaseBoardView, CONTEXT_FORM
8 from boards.forms import SettingsForm, ModeratorSettingsForm, PlainErrorList
9 from boards.models.post import SETTING_MODERATE
6 from boards.forms import SettingsForm, PlainErrorList
10 7
11 8
12 9 class SettingsView(BaseBoardView):
13 10
14 11 def get(self, request):
15 12 context = self.get_context_data(request=request)
16 13 settings_manager = SettingsManager(request.session)
17 is_moderator = settings_manager.has_permission(PERMISSION_MODERATE)
18 14
19 15 selected_theme = settings_manager.get_theme()
20 16
21 if is_moderator:
22 form = ModeratorSettingsForm(initial={
23 'theme': selected_theme,
24 'moderate': settings_manager.has_permission(PERMISSION_MODERATE)
25 }, error_class=PlainErrorList)
26 else:
27 form = SettingsForm(initial={'theme': selected_theme},
28 error_class=PlainErrorList)
17 form = SettingsForm(initial={'theme': selected_theme},
18 error_class=PlainErrorList)
29 19
30 20 context[CONTEXT_FORM] = form
31 21
32 22 return render(request, 'boards/settings.html', context)
33 23
34 24 def post(self, request):
35 25 settings_manager = SettingsManager(request.session)
36 is_moderator = settings_manager.has_permission(PERMISSION_MODERATE)
37 26
38 27 with transaction.atomic():
39 if is_moderator:
40 form = ModeratorSettingsForm(request.POST,
41 error_class=PlainErrorList)
42 else:
43 form = SettingsForm(request.POST, error_class=PlainErrorList)
28 form = SettingsForm(request.POST, error_class=PlainErrorList)
44 29
45 30 if form.is_valid():
46 31 selected_theme = form.cleaned_data['theme']
47 32
48 33 settings_manager.set_theme(selected_theme)
49 34
50 if is_moderator:
51 moderate = form.cleaned_data['moderate']
52 if moderate == 'True':
53 settings_manager.add_permission(PERMISSION_MODERATE)
54
55 35 return redirect('settings')
General Comments 0
You need to be logged in to leave comments. Login now