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