##// END OF EJS Templates
Do not allow banning users by not a moderator. Show 403 error when posting as a banned user, not 500
neko259 -
r1902:fa079980 default
parent child Browse files
Show More
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -1,592 +1,595 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: 2015-10-09 23:21+0300\n"
10 "POT-Creation-Date: 2015-10-09 23:21+0300\n"
11 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
11 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13 "Language-Team: LANGUAGE <LL@li.org>\n"
13 "Language-Team: LANGUAGE <LL@li.org>\n"
14 "Language: ru\n"
14 "Language: ru\n"
15 "MIME-Version: 1.0\n"
15 "MIME-Version: 1.0\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
17 "Content-Transfer-Encoding: 8bit\n"
17 "Content-Transfer-Encoding: 8bit\n"
18 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
18 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
19 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
19 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
20
20
21 #: admin.py:22
21 #: admin.py:22
22 msgid "{} posters were banned"
22 msgid "{} posters were banned"
23 msgstr ""
23 msgstr ""
24
24
25 #: authors.py:9
25 #: authors.py:9
26 msgid "author"
26 msgid "author"
27 msgstr "автор"
27 msgstr "автор"
28
28
29 #: authors.py:10
29 #: authors.py:10
30 msgid "developer"
30 msgid "developer"
31 msgstr "разработчик"
31 msgstr "разработчик"
32
32
33 #: authors.py:11
33 #: authors.py:11
34 msgid "javascript developer"
34 msgid "javascript developer"
35 msgstr "разработчик javascript"
35 msgstr "разработчик javascript"
36
36
37 #: authors.py:12
37 #: authors.py:12
38 msgid "designer"
38 msgid "designer"
39 msgstr "дизайнер"
39 msgstr "дизайнер"
40
40
41 #: forms.py:30
41 #: forms.py:30
42 msgid "Type message here. Use formatting panel for more advanced usage."
42 msgid "Type message here. Use formatting panel for more advanced usage."
43 msgstr ""
43 msgstr ""
44 "Вводите сообщение сюда. Используйте панель для более сложного форматирования."
44 "Вводите сообщение сюда. Используйте панель для более сложного форматирования."
45
45
46 #: forms.py:31
46 #: forms.py:31
47 msgid "music images i_dont_like_tags"
47 msgid "music images i_dont_like_tags"
48 msgstr "музыка картинки теги_не_нужны"
48 msgstr "музыка картинки теги_не_нужны"
49
49
50 #: forms.py:33
50 #: forms.py:33
51 msgid "Title"
51 msgid "Title"
52 msgstr "Заголовок"
52 msgstr "Заголовок"
53
53
54 #: forms.py:34
54 #: forms.py:34
55 msgid "Text"
55 msgid "Text"
56 msgstr "Текст"
56 msgstr "Текст"
57
57
58 #: forms.py:35
58 #: forms.py:35
59 msgid "Tag"
59 msgid "Tag"
60 msgstr "Метка"
60 msgstr "Метка"
61
61
62 #: forms.py:36 templates/boards/base.html:40 templates/search/search.html:7
62 #: forms.py:36 templates/boards/base.html:40 templates/search/search.html:7
63 msgid "Search"
63 msgid "Search"
64 msgstr "Поиск"
64 msgstr "Поиск"
65
65
66 #: forms.py:48
66 #: forms.py:48
67 msgid "File 1"
67 msgid "File 1"
68 msgstr "Файл 1"
68 msgstr "Файл 1"
69
69
70 #: forms.py:48
70 #: forms.py:48
71 msgid "File 2"
71 msgid "File 2"
72 msgstr "Файл 2"
72 msgstr "Файл 2"
73
73
74 #: forms.py:142
74 #: forms.py:142
75 msgid "File URL"
75 msgid "File URL"
76 msgstr "URL файла"
76 msgstr "URL файла"
77
77
78 #: forms.py:148
78 #: forms.py:148
79 msgid "e-mail"
79 msgid "e-mail"
80 msgstr ""
80 msgstr ""
81
81
82 #: forms.py:151
82 #: forms.py:151
83 msgid "Additional threads"
83 msgid "Additional threads"
84 msgstr "Дополнительные темы"
84 msgstr "Дополнительные темы"
85
85
86 #: forms.py:162
86 #: forms.py:162
87 #, python-format
87 #, python-format
88 msgid "Title must have less than %s characters"
88 msgid "Title must have less than %s characters"
89 msgstr "Заголовок должен иметь меньше %s символов"
89 msgstr "Заголовок должен иметь меньше %s символов"
90
90
91 #: forms.py:172
91 #: forms.py:172
92 #, python-format
92 #, python-format
93 msgid "Text must have less than %s characters"
93 msgid "Text must have less than %s characters"
94 msgstr "Текст должен быть короче %s символов"
94 msgstr "Текст должен быть короче %s символов"
95
95
96 #: forms.py:192
96 #: forms.py:192
97 msgid "Invalid URL"
97 msgid "Invalid URL"
98 msgstr "Неверный URL"
98 msgstr "Неверный URL"
99
99
100 #: forms.py:213
100 #: forms.py:213
101 msgid "Invalid additional thread list"
101 msgid "Invalid additional thread list"
102 msgstr "Неверный список дополнительных тем"
102 msgstr "Неверный список дополнительных тем"
103
103
104 #: forms.py:258
104 #: forms.py:258
105 msgid "Either text or file must be entered."
105 msgid "Either text or file must be entered."
106 msgstr "Текст или файл должны быть введены."
106 msgstr "Текст или файл должны быть введены."
107
107
108 #: forms.py:317 templates/boards/all_threads.html:153
108 #: forms.py:317 templates/boards/all_threads.html:153
109 #: templates/boards/rss/post.html:10 templates/boards/tags.html:6
109 #: templates/boards/rss/post.html:10 templates/boards/tags.html:6
110 msgid "Tags"
110 msgid "Tags"
111 msgstr "Метки"
111 msgstr "Метки"
112
112
113 #: forms.py:324
113 #: forms.py:324
114 msgid "Inappropriate characters in tags."
114 msgid "Inappropriate characters in tags."
115 msgstr "Недопустимые символы в метках."
115 msgstr "Недопустимые символы в метках."
116
116
117 #: forms.py:344
117 #: forms.py:344
118 msgid "Need at least one section."
118 msgid "Need at least one section."
119 msgstr "Нужен хотя бы один раздел."
119 msgstr "Нужен хотя бы один раздел."
120
120
121 #: forms.py:356
121 #: forms.py:356
122 msgid "Theme"
122 msgid "Theme"
123 msgstr "Тема"
123 msgstr "Тема"
124
124
125 #: forms.py:357
125 #: forms.py:357
126 msgid "Image view mode"
126 msgid "Image view mode"
127 msgstr "Режим просмотра изображений"
127 msgstr "Режим просмотра изображений"
128
128
129 #: forms.py:358
129 #: forms.py:358
130 msgid "User name"
130 msgid "User name"
131 msgstr "Имя пользователя"
131 msgstr "Имя пользователя"
132
132
133 #: forms.py:359
133 #: forms.py:359
134 msgid "Time zone"
134 msgid "Time zone"
135 msgstr "Часовой пояс"
135 msgstr "Часовой пояс"
136
136
137 #: forms.py:365
137 #: forms.py:365
138 msgid "Inappropriate characters."
138 msgid "Inappropriate characters."
139 msgstr "Недопустимые символы."
139 msgstr "Недопустимые символы."
140
140
141 #: templates/boards/404.html:6
141 #: templates/boards/404.html:6
142 msgid "Not found"
142 msgid "Not found"
143 msgstr "Не найдено"
143 msgstr "Не найдено"
144
144
145 #: templates/boards/404.html:12
145 #: templates/boards/404.html:12
146 msgid "This page does not exist"
146 msgid "This page does not exist"
147 msgstr "Этой страницы не существует"
147 msgstr "Этой страницы не существует"
148
148
149 #: templates/boards/all_threads.html:35
149 #: templates/boards/all_threads.html:35
150 msgid "Details"
150 msgid "Details"
151 msgstr "Подробности"
151 msgstr "Подробности"
152
152
153 #: templates/boards/all_threads.html:69
153 #: templates/boards/all_threads.html:69
154 msgid "Edit tag"
154 msgid "Edit tag"
155 msgstr "Изменить метку"
155 msgstr "Изменить метку"
156
156
157 #: templates/boards/all_threads.html:76
157 #: templates/boards/all_threads.html:76
158 #, python-format
158 #, python-format
159 msgid "%(count)s active thread"
159 msgid "%(count)s active thread"
160 msgid_plural "%(count)s active threads"
160 msgid_plural "%(count)s active threads"
161 msgstr[0] "%(count)s активная тема"
161 msgstr[0] "%(count)s активная тема"
162 msgstr[1] "%(count)s активные темы"
162 msgstr[1] "%(count)s активные темы"
163 msgstr[2] "%(count)s активных тем"
163 msgstr[2] "%(count)s активных тем"
164
164
165 #: templates/boards/all_threads.html:76
165 #: templates/boards/all_threads.html:76
166 #, python-format
166 #, python-format
167 msgid "%(count)s thread in bumplimit"
167 msgid "%(count)s thread in bumplimit"
168 msgid_plural "%(count)s threads in bumplimit"
168 msgid_plural "%(count)s threads in bumplimit"
169 msgstr[0] "%(count)s тема в бамплимите"
169 msgstr[0] "%(count)s тема в бамплимите"
170 msgstr[1] "%(count)s темы в бамплимите"
170 msgstr[1] "%(count)s темы в бамплимите"
171 msgstr[2] "%(count)s тем в бамплимите"
171 msgstr[2] "%(count)s тем в бамплимите"
172
172
173 #: templates/boards/all_threads.html:77
173 #: templates/boards/all_threads.html:77
174 #, python-format
174 #, python-format
175 msgid "%(count)s archived thread"
175 msgid "%(count)s archived thread"
176 msgid_plural "%(count)s archived thread"
176 msgid_plural "%(count)s archived thread"
177 msgstr[0] "%(count)s архивная тема"
177 msgstr[0] "%(count)s архивная тема"
178 msgstr[1] "%(count)s архивные темы"
178 msgstr[1] "%(count)s архивные темы"
179 msgstr[2] "%(count)s архивных тем"
179 msgstr[2] "%(count)s архивных тем"
180
180
181 #: templates/boards/all_threads.html:78 templates/boards/post.html:102
181 #: templates/boards/all_threads.html:78 templates/boards/post.html:102
182 #, python-format
182 #, python-format
183 #| msgid "%(count)s message"
183 #| msgid "%(count)s message"
184 #| msgid_plural "%(count)s messages"
184 #| msgid_plural "%(count)s messages"
185 msgid "%(count)s message"
185 msgid "%(count)s message"
186 msgid_plural "%(count)s messages"
186 msgid_plural "%(count)s messages"
187 msgstr[0] "%(count)s сообщение"
187 msgstr[0] "%(count)s сообщение"
188 msgstr[1] "%(count)s сообщения"
188 msgstr[1] "%(count)s сообщения"
189 msgstr[2] "%(count)s сообщений"
189 msgstr[2] "%(count)s сообщений"
190
190
191 #: templates/boards/all_threads.html:95 templates/boards/feed.html:30
191 #: templates/boards/all_threads.html:95 templates/boards/feed.html:30
192 #: templates/boards/notifications.html:17 templates/search/search.html:26
192 #: templates/boards/notifications.html:17 templates/search/search.html:26
193 msgid "Previous page"
193 msgid "Previous page"
194 msgstr "Предыдущая страница"
194 msgstr "Предыдущая страница"
195
195
196 #: templates/boards/all_threads.html:109
196 #: templates/boards/all_threads.html:109
197 #, python-format
197 #, python-format
198 msgid "Skipped %(count)s reply. Open thread to see all replies."
198 msgid "Skipped %(count)s reply. Open thread to see all replies."
199 msgid_plural "Skipped %(count)s replies. Open thread to see all replies."
199 msgid_plural "Skipped %(count)s replies. Open thread to see all replies."
200 msgstr[0] "Пропущен %(count)s ответ. Откройте тред, чтобы увидеть все ответы."
200 msgstr[0] "Пропущен %(count)s ответ. Откройте тред, чтобы увидеть все ответы."
201 msgstr[1] ""
201 msgstr[1] ""
202 "Пропущено %(count)s ответа. Откройте тред, чтобы увидеть все ответы."
202 "Пропущено %(count)s ответа. Откройте тред, чтобы увидеть все ответы."
203 msgstr[2] ""
203 msgstr[2] ""
204 "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы."
204 "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы."
205
205
206 #: templates/boards/all_threads.html:127 templates/boards/feed.html:40
206 #: templates/boards/all_threads.html:127 templates/boards/feed.html:40
207 #: templates/boards/notifications.html:27 templates/search/search.html:37
207 #: templates/boards/notifications.html:27 templates/search/search.html:37
208 msgid "Next page"
208 msgid "Next page"
209 msgstr "Следующая страница"
209 msgstr "Следующая страница"
210
210
211 #: templates/boards/all_threads.html:132
211 #: templates/boards/all_threads.html:132
212 msgid "No threads exist. Create the first one!"
212 msgid "No threads exist. Create the first one!"
213 msgstr "Нет тем. Создайте первую!"
213 msgstr "Нет тем. Создайте первую!"
214
214
215 #: templates/boards/all_threads.html:138
215 #: templates/boards/all_threads.html:138
216 msgid "Create new thread"
216 msgid "Create new thread"
217 msgstr "Создать новую тему"
217 msgstr "Создать новую тему"
218
218
219 #: templates/boards/all_threads.html:143 templates/boards/preview.html:16
219 #: templates/boards/all_threads.html:143 templates/boards/preview.html:16
220 #: templates/boards/thread_normal.html:51
220 #: templates/boards/thread_normal.html:51
221 msgid "Post"
221 msgid "Post"
222 msgstr "Отправить"
222 msgstr "Отправить"
223
223
224 #: templates/boards/all_threads.html:144 templates/boards/preview.html:6
224 #: templates/boards/all_threads.html:144 templates/boards/preview.html:6
225 #: templates/boards/staticpages/help.html:21
225 #: templates/boards/staticpages/help.html:21
226 #: templates/boards/thread_normal.html:52
226 #: templates/boards/thread_normal.html:52
227 msgid "Preview"
227 msgid "Preview"
228 msgstr "Предпросмотр"
228 msgstr "Предпросмотр"
229
229
230 #: templates/boards/all_threads.html:149
230 #: templates/boards/all_threads.html:149
231 msgid "Tags must be delimited by spaces. Text or image is required."
231 msgid "Tags must be delimited by spaces. Text or image is required."
232 msgstr ""
232 msgstr ""
233 "Метки должны быть разделены пробелами. Текст или изображение обязательны."
233 "Метки должны быть разделены пробелами. Текст или изображение обязательны."
234
234
235 #: templates/boards/all_threads.html:152 templates/boards/thread_normal.html:58
235 #: templates/boards/all_threads.html:152 templates/boards/thread_normal.html:58
236 msgid "Text syntax"
236 msgid "Text syntax"
237 msgstr "Синтаксис текста"
237 msgstr "Синтаксис текста"
238
238
239 #: templates/boards/all_threads.html:166 templates/boards/feed.html:53
239 #: templates/boards/all_threads.html:166 templates/boards/feed.html:53
240 msgid "Pages:"
240 msgid "Pages:"
241 msgstr "Страницы: "
241 msgstr "Страницы: "
242
242
243 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
243 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
244 msgid "Authors"
244 msgid "Authors"
245 msgstr "Авторы"
245 msgstr "Авторы"
246
246
247 #: templates/boards/authors.html:26
247 #: templates/boards/authors.html:26
248 msgid "Distributed under the"
248 msgid "Distributed under the"
249 msgstr "Распространяется под"
249 msgstr "Распространяется под"
250
250
251 #: templates/boards/authors.html:28
251 #: templates/boards/authors.html:28
252 msgid "license"
252 msgid "license"
253 msgstr "лицензией"
253 msgstr "лицензией"
254
254
255 #: templates/boards/authors.html:30
255 #: templates/boards/authors.html:30
256 msgid "Repository"
256 msgid "Repository"
257 msgstr "Репозиторий"
257 msgstr "Репозиторий"
258
258
259 #: templates/boards/base.html:14 templates/boards/base.html.py:41
259 #: templates/boards/base.html:14 templates/boards/base.html.py:41
260 msgid "Feed"
260 msgid "Feed"
261 msgstr "Лента"
261 msgstr "Лента"
262
262
263 #: templates/boards/base.html:31
263 #: templates/boards/base.html:31
264 msgid "All threads"
264 msgid "All threads"
265 msgstr "Все темы"
265 msgstr "Все темы"
266
266
267 #: templates/boards/base.html:37
267 #: templates/boards/base.html:37
268 msgid "Add tags"
268 msgid "Add tags"
269 msgstr "Добавить метки"
269 msgstr "Добавить метки"
270
270
271 #: templates/boards/base.html:39
271 #: templates/boards/base.html:39
272 msgid "Tag management"
272 msgid "Tag management"
273 msgstr "Управление метками"
273 msgstr "Управление метками"
274
274
275 #: templates/boards/base.html:39
275 #: templates/boards/base.html:39
276 msgid "tags"
276 msgid "tags"
277 msgstr "метки"
277 msgstr "метки"
278
278
279 #: templates/boards/base.html:40
279 #: templates/boards/base.html:40
280 msgid "search"
280 msgid "search"
281 msgstr "поиск"
281 msgstr "поиск"
282
282
283 #: templates/boards/base.html:41 templates/boards/feed.html:11
283 #: templates/boards/base.html:41 templates/boards/feed.html:11
284 msgid "feed"
284 msgid "feed"
285 msgstr "лента"
285 msgstr "лента"
286
286
287 #: templates/boards/base.html:42 templates/boards/random.html:6
287 #: templates/boards/base.html:42 templates/boards/random.html:6
288 msgid "Random images"
288 msgid "Random images"
289 msgstr "Случайные изображения"
289 msgstr "Случайные изображения"
290
290
291 #: templates/boards/base.html:42
291 #: templates/boards/base.html:42
292 msgid "random"
292 msgid "random"
293 msgstr "случайные"
293 msgstr "случайные"
294
294
295 #: templates/boards/base.html:44
295 #: templates/boards/base.html:44
296 msgid "favorites"
296 msgid "favorites"
297 msgstr "избранное"
297 msgstr "избранное"
298
298
299 #: templates/boards/base.html:48 templates/boards/base.html.py:49
299 #: templates/boards/base.html:48 templates/boards/base.html.py:49
300 #: templates/boards/notifications.html:8
300 #: templates/boards/notifications.html:8
301 msgid "Notifications"
301 msgid "Notifications"
302 msgstr "Уведомления"
302 msgstr "Уведомления"
303
303
304 #: templates/boards/base.html:56 templates/boards/settings.html:8
304 #: templates/boards/base.html:56 templates/boards/settings.html:8
305 msgid "Settings"
305 msgid "Settings"
306 msgstr "Настройки"
306 msgstr "Настройки"
307
307
308 #: templates/boards/base.html:59
308 #: templates/boards/base.html:59
309 msgid "Loading..."
309 msgid "Loading..."
310 msgstr "Загрузка..."
310 msgstr "Загрузка..."
311
311
312 #: templates/boards/base.html:71
312 #: templates/boards/base.html:71
313 msgid "Admin"
313 msgid "Admin"
314 msgstr "Администрирование"
314 msgstr "Администрирование"
315
315
316 #: templates/boards/base.html:73
316 #: templates/boards/base.html:73
317 #, python-format
317 #, python-format
318 msgid "Speed: %(ppd)s posts per day"
318 msgid "Speed: %(ppd)s posts per day"
319 msgstr "Скорость: %(ppd)s сообщений в день"
319 msgstr "Скорость: %(ppd)s сообщений в день"
320
320
321 #: templates/boards/base.html:75
321 #: templates/boards/base.html:75
322 msgid "Up"
322 msgid "Up"
323 msgstr "Вверх"
323 msgstr "Вверх"
324
324
325 #: templates/boards/feed.html:45
325 #: templates/boards/feed.html:45
326 msgid "No posts exist. Create the first one!"
326 msgid "No posts exist. Create the first one!"
327 msgstr "Нет сообщений. Создайте первое!"
327 msgstr "Нет сообщений. Создайте первое!"
328
328
329 #: templates/boards/post.html:33
329 #: templates/boards/post.html:33
330 msgid "Open"
330 msgid "Open"
331 msgstr "Открыть"
331 msgstr "Открыть"
332
332
333 #: templates/boards/post.html:35 templates/boards/post.html.py:46
333 #: templates/boards/post.html:35 templates/boards/post.html.py:46
334 msgid "Reply"
334 msgid "Reply"
335 msgstr "Ответить"
335 msgstr "Ответить"
336
336
337 #: templates/boards/post.html:41
337 #: templates/boards/post.html:41
338 msgid " in "
338 msgid " in "
339 msgstr " в "
339 msgstr " в "
340
340
341 #: templates/boards/post.html:51
341 #: templates/boards/post.html:51
342 msgid "Edit"
342 msgid "Edit"
343 msgstr "Изменить"
343 msgstr "Изменить"
344
344
345 #: templates/boards/post.html:53
345 #: templates/boards/post.html:53
346 msgid "Edit thread"
346 msgid "Edit thread"
347 msgstr "Изменить тему"
347 msgstr "Изменить тему"
348
348
349 #: templates/boards/post.html:91
349 #: templates/boards/post.html:91
350 msgid "Replies"
350 msgid "Replies"
351 msgstr "Ответы"
351 msgstr "Ответы"
352
352
353 #: templates/boards/post.html:103
353 #: templates/boards/post.html:103
354 #, python-format
354 #, python-format
355 msgid "%(count)s image"
355 msgid "%(count)s image"
356 msgid_plural "%(count)s images"
356 msgid_plural "%(count)s images"
357 msgstr[0] "%(count)s изображение"
357 msgstr[0] "%(count)s изображение"
358 msgstr[1] "%(count)s изображения"
358 msgstr[1] "%(count)s изображения"
359 msgstr[2] "%(count)s изображений"
359 msgstr[2] "%(count)s изображений"
360
360
361 #: templates/boards/rss/post.html:5
361 #: templates/boards/rss/post.html:5
362 msgid "Post image"
362 msgid "Post image"
363 msgstr "Изображение сообщения"
363 msgstr "Изображение сообщения"
364
364
365 #: templates/boards/settings.html:15
365 #: templates/boards/settings.html:15
366 msgid "You are moderator."
366 msgid "You are moderator."
367 msgstr "Вы модератор."
367 msgstr "Вы модератор."
368
368
369 #: templates/boards/settings.html:19
369 #: templates/boards/settings.html:19
370 msgid "Hidden tags:"
370 msgid "Hidden tags:"
371 msgstr "Скрытые метки:"
371 msgstr "Скрытые метки:"
372
372
373 #: templates/boards/settings.html:25
373 #: templates/boards/settings.html:25
374 msgid "No hidden tags."
374 msgid "No hidden tags."
375 msgstr "Нет скрытых меток."
375 msgstr "Нет скрытых меток."
376
376
377 #: templates/boards/settings.html:34
377 #: templates/boards/settings.html:34
378 msgid "Save"
378 msgid "Save"
379 msgstr "Сохранить"
379 msgstr "Сохранить"
380
380
381 #: templates/boards/staticpages/banned.html:6
381 #: templates/boards/staticpages/banned.html:6
382 msgid "Banned"
382 msgid "Banned"
383 msgstr "Заблокирован"
383 msgstr "Заблокирован"
384
384
385 #: templates/boards/staticpages/banned.html:11
385 #: templates/boards/staticpages/banned.html:11
386 msgid "Your IP address has been banned. Contact the administrator"
386 msgid "Your IP address has been banned. Contact the administrator"
387 msgstr "Ваш IP адрес был заблокирован. Свяжитесь с администратором"
387 msgstr "Ваш IP адрес был заблокирован. Свяжитесь с администратором"
388
388
389 #: templates/boards/staticpages/help.html:6
389 #: templates/boards/staticpages/help.html:6
390 #: templates/boards/staticpages/help.html:10
390 #: templates/boards/staticpages/help.html:10
391 msgid "Syntax"
391 msgid "Syntax"
392 msgstr "Синтаксис"
392 msgstr "Синтаксис"
393
393
394 #: templates/boards/staticpages/help.html:11
394 #: templates/boards/staticpages/help.html:11
395 msgid "Italic text"
395 msgid "Italic text"
396 msgstr "Курсивный текст"
396 msgstr "Курсивный текст"
397
397
398 #: templates/boards/staticpages/help.html:12
398 #: templates/boards/staticpages/help.html:12
399 msgid "Bold text"
399 msgid "Bold text"
400 msgstr "Полужирный текст"
400 msgstr "Полужирный текст"
401
401
402 #: templates/boards/staticpages/help.html:13
402 #: templates/boards/staticpages/help.html:13
403 msgid "Spoiler"
403 msgid "Spoiler"
404 msgstr "Спойлер"
404 msgstr "Спойлер"
405
405
406 #: templates/boards/staticpages/help.html:14
406 #: templates/boards/staticpages/help.html:14
407 msgid "Link to a post"
407 msgid "Link to a post"
408 msgstr "Ссылка на сообщение"
408 msgstr "Ссылка на сообщение"
409
409
410 #: templates/boards/staticpages/help.html:15
410 #: templates/boards/staticpages/help.html:15
411 msgid "Strikethrough text"
411 msgid "Strikethrough text"
412 msgstr "Зачеркнутый текст"
412 msgstr "Зачеркнутый текст"
413
413
414 #: templates/boards/staticpages/help.html:16
414 #: templates/boards/staticpages/help.html:16
415 msgid "Comment"
415 msgid "Comment"
416 msgstr "Комментарий"
416 msgstr "Комментарий"
417
417
418 #: templates/boards/staticpages/help.html:17
418 #: templates/boards/staticpages/help.html:17
419 #: templates/boards/staticpages/help.html:18
419 #: templates/boards/staticpages/help.html:18
420 msgid "Quote"
420 msgid "Quote"
421 msgstr "Цитата"
421 msgstr "Цитата"
422
422
423 #: templates/boards/staticpages/help.html:21
423 #: templates/boards/staticpages/help.html:21
424 msgid "You can try pasting the text and previewing the result here:"
424 msgid "You can try pasting the text and previewing the result here:"
425 msgstr "Вы можете попробовать вставить текст и проверить результат здесь:"
425 msgstr "Вы можете попробовать вставить текст и проверить результат здесь:"
426
426
427 #: templates/boards/tags.html:17
427 #: templates/boards/tags.html:17
428 msgid "Sections:"
428 msgid "Sections:"
429 msgstr "Разделы:"
429 msgstr "Разделы:"
430
430
431 #: templates/boards/tags.html:30
431 #: templates/boards/tags.html:30
432 msgid "Other tags:"
432 msgid "Other tags:"
433 msgstr "Другие метки:"
433 msgstr "Другие метки:"
434
434
435 #: templates/boards/tags.html:43
435 #: templates/boards/tags.html:43
436 msgid "All tags..."
436 msgid "All tags..."
437 msgstr "Все метки..."
437 msgstr "Все метки..."
438
438
439 #: templates/boards/thread.html:14
439 #: templates/boards/thread.html:14
440 msgid "Normal"
440 msgid "Normal"
441 msgstr "Нормальный"
441 msgstr "Нормальный"
442
442
443 #: templates/boards/thread.html:15
443 #: templates/boards/thread.html:15
444 msgid "Gallery"
444 msgid "Gallery"
445 msgstr "Галерея"
445 msgstr "Галерея"
446
446
447 #: templates/boards/thread.html:16
447 #: templates/boards/thread.html:16
448 msgid "Tree"
448 msgid "Tree"
449 msgstr "Дерево"
449 msgstr "Дерево"
450
450
451 #: templates/boards/thread.html:35
451 #: templates/boards/thread.html:35
452 msgid "message"
452 msgid "message"
453 msgid_plural "messages"
453 msgid_plural "messages"
454 msgstr[0] "сообщение"
454 msgstr[0] "сообщение"
455 msgstr[1] "сообщения"
455 msgstr[1] "сообщения"
456 msgstr[2] "сообщений"
456 msgstr[2] "сообщений"
457
457
458 #: templates/boards/thread.html:38
458 #: templates/boards/thread.html:38
459 msgid "image"
459 msgid "image"
460 msgid_plural "images"
460 msgid_plural "images"
461 msgstr[0] "изображение"
461 msgstr[0] "изображение"
462 msgstr[1] "изображения"
462 msgstr[1] "изображения"
463 msgstr[2] "изображений"
463 msgstr[2] "изображений"
464
464
465 #: templates/boards/thread.html:40
465 #: templates/boards/thread.html:40
466 msgid "Last update: "
466 msgid "Last update: "
467 msgstr "Последнее обновление: "
467 msgstr "Последнее обновление: "
468
468
469 #: templates/boards/thread_gallery.html:36
469 #: templates/boards/thread_gallery.html:36
470 msgid "No images."
470 msgid "No images."
471 msgstr "Нет изображений."
471 msgstr "Нет изображений."
472
472
473 #: templates/boards/thread_normal.html:30
473 #: templates/boards/thread_normal.html:30
474 msgid "posts to bumplimit"
474 msgid "posts to bumplimit"
475 msgstr "сообщений до бамплимита"
475 msgstr "сообщений до бамплимита"
476
476
477 #: templates/boards/thread_normal.html:44
477 #: templates/boards/thread_normal.html:44
478 msgid "Reply to thread"
478 msgid "Reply to thread"
479 msgstr "Ответить в тему"
479 msgstr "Ответить в тему"
480
480
481 #: templates/boards/thread_normal.html:44
481 #: templates/boards/thread_normal.html:44
482 msgid "to message "
482 msgid "to message "
483 msgstr "на сообщение"
483 msgstr "на сообщение"
484
484
485 #: templates/boards/thread_normal.html:59
485 #: templates/boards/thread_normal.html:59
486 msgid "Reset form"
486 msgid "Reset form"
487 msgstr "Сбросить форму"
487 msgstr "Сбросить форму"
488
488
489 #: templates/search/search.html:17
489 #: templates/search/search.html:17
490 msgid "Ok"
490 msgid "Ok"
491 msgstr "Ок"
491 msgstr "Ок"
492
492
493 #: utils.py:120
493 #: utils.py:120
494 #, python-format
494 #, python-format
495 msgid "File must be less than %s but is %s."
495 msgid "File must be less than %s but is %s."
496 msgstr "Файл должен быть менее %s, но его размер %s."
496 msgstr "Файл должен быть менее %s, но его размер %s."
497
497
498 msgid "Please wait %(delay)d second before sending message"
498 msgid "Please wait %(delay)d second before sending message"
499 msgid_plural "Please wait %(delay)d seconds before sending message"
499 msgid_plural "Please wait %(delay)d seconds before sending message"
500 msgstr[0] "Пожалуйста подождите %(delay)d секунду перед отправкой сообщения"
500 msgstr[0] "Пожалуйста подождите %(delay)d секунду перед отправкой сообщения"
501 msgstr[1] "Пожалуйста подождите %(delay)d секунды перед отправкой сообщения"
501 msgstr[1] "Пожалуйста подождите %(delay)d секунды перед отправкой сообщения"
502 msgstr[2] "Пожалуйста подождите %(delay)d секунд перед отправкой сообщения"
502 msgstr[2] "Пожалуйста подождите %(delay)d секунд перед отправкой сообщения"
503
503
504 msgid "New threads"
504 msgid "New threads"
505 msgstr "Новые темы"
505 msgstr "Новые темы"
506
506
507 #, python-format
507 #, python-format
508 msgid "Max file size is %(size)s."
508 msgid "Max file size is %(size)s."
509 msgstr "Максимальный размер файла %(size)s."
509 msgstr "Максимальный размер файла %(size)s."
510
510
511 msgid "Size of media:"
511 msgid "Size of media:"
512 msgstr "Размер медиа:"
512 msgstr "Размер медиа:"
513
513
514 msgid "Statistics"
514 msgid "Statistics"
515 msgstr "Статистика"
515 msgstr "Статистика"
516
516
517 msgid "Invalid PoW."
517 msgid "Invalid PoW."
518 msgstr "Неверный PoW."
518 msgstr "Неверный PoW."
519
519
520 msgid "Stale PoW."
520 msgid "Stale PoW."
521 msgstr "PoW устарел."
521 msgstr "PoW устарел."
522
522
523 msgid "Show"
523 msgid "Show"
524 msgstr "Показывать"
524 msgstr "Показывать"
525
525
526 msgid "Hide"
526 msgid "Hide"
527 msgstr "Скрывать"
527 msgstr "Скрывать"
528
528
529 msgid "Add to favorites"
529 msgid "Add to favorites"
530 msgstr "Добавить в избранное"
530 msgstr "Добавить в избранное"
531
531
532 msgid "Remove from favorites"
532 msgid "Remove from favorites"
533 msgstr "Убрать из избранного"
533 msgstr "Убрать из избранного"
534
534
535 msgid "Monochrome"
535 msgid "Monochrome"
536 msgstr "Монохромный"
536 msgstr "Монохромный"
537
537
538 msgid "Subsections: "
538 msgid "Subsections: "
539 msgstr "Подразделы: "
539 msgstr "Подразделы: "
540
540
541 msgid "Change file source"
541 msgid "Change file source"
542 msgstr "Изменить источник файла"
542 msgstr "Изменить источник файла"
543
543
544 msgid "interesting"
544 msgid "interesting"
545 msgstr "интересное"
545 msgstr "интересное"
546
546
547 msgid "images"
547 msgid "images"
548 msgstr "изображения"
548 msgstr "изображения"
549
549
550 msgid "Delete post"
550 msgid "Delete post"
551 msgstr "Удалить пост"
551 msgstr "Удалить пост"
552
552
553 msgid "Delete thread"
553 msgid "Delete thread"
554 msgstr "Удалить тему"
554 msgstr "Удалить тему"
555
555
556 msgid "Messages per day/week/month:"
556 msgid "Messages per day/week/month:"
557 msgstr "Сообщений за день/неделю/месяц:"
557 msgstr "Сообщений за день/неделю/месяц:"
558
558
559 msgid "Subscribe to thread"
559 msgid "Subscribe to thread"
560 msgstr "Подписаться на тему"
560 msgstr "Подписаться на тему"
561
561
562 msgid "Active threads:"
562 msgid "Active threads:"
563 msgstr "Активные темы:"
563 msgstr "Активные темы:"
564
564
565 msgid "No active threads today."
565 msgid "No active threads today."
566 msgstr "Сегодня нет активных тем."
566 msgstr "Сегодня нет активных тем."
567
567
568 msgid "Insert URLs on separate lines."
568 msgid "Insert URLs on separate lines."
569 msgstr "Вставляйте ссылки на отдельных строках."
569 msgstr "Вставляйте ссылки на отдельных строках."
570
570
571 msgid "You can post no more than %(files)d file."
571 msgid "You can post no more than %(files)d file."
572 msgid_plural "You can post no more than %(files)d files."
572 msgid_plural "You can post no more than %(files)d files."
573 msgstr[0] "Вы можете отправить не более %(files)d файла."
573 msgstr[0] "Вы можете отправить не более %(files)d файла."
574 msgstr[1] "Вы можете отправить не более %(files)d файлов."
574 msgstr[1] "Вы можете отправить не более %(files)d файлов."
575 msgstr[2] "Вы можете отправить не более %(files)d файлов."
575 msgstr[2] "Вы можете отправить не более %(files)d файлов."
576
576
577 #, python-format
577 #, python-format
578 msgid "Max file number is %(max_files)s."
578 msgid "Max file number is %(max_files)s."
579 msgstr "Максимальное количество файлов %(max_files)s."
579 msgstr "Максимальное количество файлов %(max_files)s."
580
580
581 msgid "Moderation"
581 msgid "Moderation"
582 msgstr "Модерация"
582 msgstr "Модерация"
583
583
584 msgid "Check for duplicates"
584 msgid "Check for duplicates"
585 msgstr "Проверять на дубликаты"
585 msgstr "Проверять на дубликаты"
586
586
587 msgid "Some files are already present on the board."
587 msgid "Some files are already present on the board."
588 msgstr "Некоторые файлы уже присутствуют на борде."
588 msgstr "Некоторые файлы уже присутствуют на борде."
589
589
590 msgid "Do not download URLs"
590 msgid "Do not download URLs"
591 msgstr "Не загружать ссылки"
591 msgstr "Не загружать ссылки"
592
592
593 msgid "Ban and delete"
594 msgstr "Забанить и удалить"
595
@@ -1,193 +1,194 b''
1 import logging
1 import logging
2
2
3 from datetime import datetime, timedelta, date
3 from datetime import datetime, timedelta, date
4 from datetime import time as dtime
4 from datetime import time as dtime
5
5
6 from boards.abstracts.exceptions import BannedException, ArchiveException
6 from boards.abstracts.exceptions import BannedException, ArchiveException
7 from django.db import models, transaction
7 from django.db import models, transaction
8 from django.utils import timezone
8 from django.utils import timezone
9 from django.dispatch import Signal
9 from django.dispatch import Signal
10 from django.core.exceptions import PermissionDenied
10
11
11 import boards
12 import boards
12
13
13 from boards.models.user import Ban
14 from boards.models.user import Ban
14 from boards.mdx_neboard import Parser
15 from boards.mdx_neboard import Parser
15 from boards.models import Attachment
16 from boards.models import Attachment
16 from boards import utils
17 from boards import utils
17
18
18 __author__ = 'neko259'
19 __author__ = 'neko259'
19
20
20 POSTS_PER_DAY_RANGE = 7
21 POSTS_PER_DAY_RANGE = 7
21 NO_IP = '0.0.0.0'
22 NO_IP = '0.0.0.0'
22
23
23
24
24 post_import_deps = Signal()
25 post_import_deps = Signal()
25
26
26
27
27 class PostManager(models.Manager):
28 class PostManager(models.Manager):
28 @transaction.atomic
29 @transaction.atomic
29 def create_post(self, title: str, text: str, files=[], thread=None,
30 def create_post(self, title: str, text: str, files=[], thread=None,
30 ip=NO_IP, tags: list=None,
31 ip=NO_IP, tags: list=None,
31 tripcode='', monochrome=False, images=[],
32 tripcode='', monochrome=False, images=[],
32 file_urls=[]):
33 file_urls=[]):
33 """
34 """
34 Creates new post
35 Creates new post
35 """
36 """
36
37
37 if thread is not None and thread.is_archived():
38 if thread is not None and thread.is_archived():
38 raise ArchiveException('Cannot post into an archived thread')
39 raise ArchiveException('Cannot post into an archived thread')
39
40
40 if not utils.is_anonymous_mode():
41 if not utils.is_anonymous_mode():
41 is_banned = Ban.objects.filter(ip=ip).exists()
42 is_banned = Ban.objects.filter(ip=ip).exists()
42 else:
43 else:
43 is_banned = False
44 is_banned = False
44
45
45 if is_banned:
46 if is_banned:
46 raise BannedException("This user is banned")
47 raise PermissionDenied()
47
48
48 if not tags:
49 if not tags:
49 tags = []
50 tags = []
50
51
51 posting_time = timezone.now()
52 posting_time = timezone.now()
52 new_thread = False
53 new_thread = False
53 if not thread:
54 if not thread:
54 thread = boards.models.thread.Thread.objects.create(
55 thread = boards.models.thread.Thread.objects.create(
55 bump_time=posting_time, last_edit_time=posting_time,
56 bump_time=posting_time, last_edit_time=posting_time,
56 monochrome=monochrome)
57 monochrome=monochrome)
57 list(map(thread.tags.add, tags))
58 list(map(thread.tags.add, tags))
58 new_thread = True
59 new_thread = True
59
60
60 pre_text = Parser().preparse(text)
61 pre_text = Parser().preparse(text)
61
62
62 post = self.create(title=title,
63 post = self.create(title=title,
63 text=pre_text,
64 text=pre_text,
64 pub_time=posting_time,
65 pub_time=posting_time,
65 poster_ip=ip,
66 poster_ip=ip,
66 thread=thread,
67 thread=thread,
67 last_edit_time=posting_time,
68 last_edit_time=posting_time,
68 tripcode=tripcode,
69 tripcode=tripcode,
69 opening=new_thread)
70 opening=new_thread)
70
71
71 logger = logging.getLogger('boards.post.create')
72 logger = logging.getLogger('boards.post.create')
72
73
73 logger.info('Created post [{}] with text [{}] by {}'.format(post,
74 logger.info('Created post [{}] with text [{}] by {}'.format(post,
74 post.get_text(),post.poster_ip))
75 post.get_text(),post.poster_ip))
75
76
76 for file in files:
77 for file in files:
77 self._add_file_to_post(file, post)
78 self._add_file_to_post(file, post)
78 for image in images:
79 for image in images:
79 post.attachments.add(image)
80 post.attachments.add(image)
80 for file_url in file_urls:
81 for file_url in file_urls:
81 post.attachments.add(Attachment.objects.create_from_url(file_url))
82 post.attachments.add(Attachment.objects.create_from_url(file_url))
82
83
83 post.set_global_id()
84 post.set_global_id()
84
85
85 # Thread needs to be bumped only when the post is already created
86 # Thread needs to be bumped only when the post is already created
86 if not new_thread:
87 if not new_thread:
87 thread.last_edit_time = posting_time
88 thread.last_edit_time = posting_time
88 thread.bump()
89 thread.bump()
89 thread.save()
90 thread.save()
90
91
91 return post
92 return post
92
93
93 def delete_posts_by_ip(self, ip):
94 def delete_posts_by_ip(self, ip):
94 """
95 """
95 Deletes all posts of the author with same IP
96 Deletes all posts of the author with same IP
96 """
97 """
97
98
98 posts = self.filter(poster_ip=ip)
99 posts = self.filter(poster_ip=ip)
99 for post in posts:
100 for post in posts:
100 post.delete()
101 post.delete()
101
102
102 @utils.cached_result()
103 @utils.cached_result()
103 def get_posts_per_day(self) -> float:
104 def get_posts_per_day(self) -> float:
104 """
105 """
105 Gets average count of posts per day for the last 7 days
106 Gets average count of posts per day for the last 7 days
106 """
107 """
107
108
108 day_end = date.today()
109 day_end = date.today()
109 day_start = day_end - timedelta(POSTS_PER_DAY_RANGE)
110 day_start = day_end - timedelta(POSTS_PER_DAY_RANGE)
110
111
111 day_time_start = timezone.make_aware(datetime.combine(
112 day_time_start = timezone.make_aware(datetime.combine(
112 day_start, dtime()), timezone.get_current_timezone())
113 day_start, dtime()), timezone.get_current_timezone())
113 day_time_end = timezone.make_aware(datetime.combine(
114 day_time_end = timezone.make_aware(datetime.combine(
114 day_end, dtime()), timezone.get_current_timezone())
115 day_end, dtime()), timezone.get_current_timezone())
115
116
116 posts_per_period = float(self.filter(
117 posts_per_period = float(self.filter(
117 pub_time__lte=day_time_end,
118 pub_time__lte=day_time_end,
118 pub_time__gte=day_time_start).count())
119 pub_time__gte=day_time_start).count())
119
120
120 ppd = posts_per_period / POSTS_PER_DAY_RANGE
121 ppd = posts_per_period / POSTS_PER_DAY_RANGE
121
122
122 return ppd
123 return ppd
123
124
124 def get_post_per_days(self, days) -> int:
125 def get_post_per_days(self, days) -> int:
125 day_end = date.today() + timedelta(1)
126 day_end = date.today() + timedelta(1)
126 day_start = day_end - timedelta(days)
127 day_start = day_end - timedelta(days)
127
128
128 day_time_start = timezone.make_aware(datetime.combine(
129 day_time_start = timezone.make_aware(datetime.combine(
129 day_start, dtime()), timezone.get_current_timezone())
130 day_start, dtime()), timezone.get_current_timezone())
130 day_time_end = timezone.make_aware(datetime.combine(
131 day_time_end = timezone.make_aware(datetime.combine(
131 day_end, dtime()), timezone.get_current_timezone())
132 day_end, dtime()), timezone.get_current_timezone())
132
133
133 return self.filter(
134 return self.filter(
134 pub_time__lte=day_time_end,
135 pub_time__lte=day_time_end,
135 pub_time__gte=day_time_start).count()
136 pub_time__gte=day_time_start).count()
136
137
137 @transaction.atomic
138 @transaction.atomic
138 def import_post(self, title: str, text: str, pub_time: str, global_id,
139 def import_post(self, title: str, text: str, pub_time: str, global_id,
139 opening_post=None, tags=list(), files=list(),
140 opening_post=None, tags=list(), files=list(),
140 file_urls=list(), tripcode=None, version=1):
141 file_urls=list(), tripcode=None, version=1):
141 is_opening = opening_post is None
142 is_opening = opening_post is None
142 if is_opening:
143 if is_opening:
143 thread = boards.models.thread.Thread.objects.create(
144 thread = boards.models.thread.Thread.objects.create(
144 bump_time=pub_time, last_edit_time=pub_time)
145 bump_time=pub_time, last_edit_time=pub_time)
145 list(map(thread.tags.add, tags))
146 list(map(thread.tags.add, tags))
146 else:
147 else:
147 thread = opening_post.get_thread()
148 thread = opening_post.get_thread()
148
149
149 post = self.create(title=title,
150 post = self.create(title=title,
150 text=text,
151 text=text,
151 pub_time=pub_time,
152 pub_time=pub_time,
152 poster_ip=NO_IP,
153 poster_ip=NO_IP,
153 last_edit_time=pub_time,
154 last_edit_time=pub_time,
154 global_id=global_id,
155 global_id=global_id,
155 opening=is_opening,
156 opening=is_opening,
156 thread=thread,
157 thread=thread,
157 tripcode=tripcode,
158 tripcode=tripcode,
158 version=version)
159 version=version)
159
160
160 for file in files:
161 for file in files:
161 self._add_file_to_post(file, post)
162 self._add_file_to_post(file, post)
162 for file_url in file_urls:
163 for file_url in file_urls:
163 post.attachments.add(Attachment.objects.create_from_url(file_url))
164 post.attachments.add(Attachment.objects.create_from_url(file_url))
164
165
165 url_to_post = '[post]{}[/post]'.format(str(global_id))
166 url_to_post = '[post]{}[/post]'.format(str(global_id))
166 replies = self.filter(text__contains=url_to_post)
167 replies = self.filter(text__contains=url_to_post)
167 for reply in replies:
168 for reply in replies:
168 post_import_deps.send(reply)
169 post_import_deps.send(reply)
169
170
170 @transaction.atomic
171 @transaction.atomic
171 def update_post(self, post, title: str, text: str, pub_time: str,
172 def update_post(self, post, title: str, text: str, pub_time: str,
172 tags=list(), files=list(), file_urls=list(), tripcode=None, version=1):
173 tags=list(), files=list(), file_urls=list(), tripcode=None, version=1):
173 post.title = title
174 post.title = title
174 post.text = text
175 post.text = text
175 post.pub_time = pub_time
176 post.pub_time = pub_time
176 post.tripcode = tripcode
177 post.tripcode = tripcode
177 post.version = version
178 post.version = version
178 post.save()
179 post.save()
179
180
180 post.clear_cache()
181 post.clear_cache()
181
182
182 post.attachments.clear()
183 post.attachments.clear()
183 for file in files:
184 for file in files:
184 self._add_file_to_post(file, post)
185 self._add_file_to_post(file, post)
185 for file_url in file_urls:
186 for file_url in file_urls:
186 post.attachments.add(Attachment.objects.create_from_url(file_url))
187 post.attachments.add(Attachment.objects.create_from_url(file_url))
187
188
188 thread = post.get_thread()
189 thread = post.get_thread()
189 thread.tags.clear()
190 thread.tags.clear()
190 list(map(thread.tags.add, tags))
191 list(map(thread.tags.add, tags))
191
192
192 def _add_file_to_post(self, file, post):
193 def _add_file_to_post(self, file, post):
193 post.attachments.add(Attachment.objects.create_with_hash(file))
194 post.attachments.add(Attachment.objects.create_with_hash(file))
@@ -1,157 +1,157 b''
1 {% load i18n %}
1 {% load i18n %}
2 {% load board %}
2 {% load board %}
3
3
4 {% get_current_language as LANGUAGE_CODE %}
4 {% get_current_language as LANGUAGE_CODE %}
5
5
6 <div class="{{ css_class }}" id="{{ post.id }}" data-uid="{{ post.uid }}" {% if tree_depth %}style="margin-left: {{ tree_depth }}em;"{% endif %}>
6 <div class="{{ css_class }}" id="{{ post.id }}" data-uid="{{ post.uid }}" {% if tree_depth %}style="margin-left: {{ tree_depth }}em;"{% endif %}>
7 <div class="post-info">
7 <div class="post-info">
8 <a class="post_id" href="{{ post.get_absolute_url }}">#{{ post.id }}</a>
8 <a class="post_id" href="{{ post.get_absolute_url }}">#{{ post.id }}</a>
9 <span class="title">{{ post.title }}</span>
9 <span class="title">{{ post.title }}</span>
10 {% if perms.boards.change_post and post.has_ip %}
10 {% if perms.boards.change_post and post.has_ip %}
11 <span class="pub_time" style="border-bottom: solid 2px #{{ post.get_ip_color }};" title="{{ post.poster_ip }}">
11 <span class="pub_time" style="border-bottom: solid 2px #{{ post.get_ip_color }};" title="{{ post.poster_ip }}">
12 {% else %}
12 {% else %}
13 <span class="pub_time">
13 <span class="pub_time">
14 {% endif %}
14 {% endif %}
15 <time datetime="{{ post.pub_time|date:'c' }}">{{ post.pub_time }}</time></span>
15 <time datetime="{{ post.pub_time|date:'c' }}">{{ post.pub_time }}</time></span>
16 {% if post.tripcode %}
16 {% if post.tripcode %}
17 /
17 /
18 {% with tripcode=post.get_tripcode %}
18 {% with tripcode=post.get_tripcode %}
19 <a href="{% url 'feed' %}?tripcode={{ tripcode.get_full_text }}"
19 <a href="{% url 'feed' %}?tripcode={{ tripcode.get_full_text }}"
20 class="tripcode" title="{{ tripcode.get_full_text }}"
20 class="tripcode" title="{{ tripcode.get_full_text }}"
21 style="border: solid 2px #{{ tripcode.get_color }}; border-left: solid 1ex #{{ tripcode.get_color }};">{{ tripcode.get_short_text }}</a>
21 style="border: solid 2px #{{ tripcode.get_color }}; border-left: solid 1ex #{{ tripcode.get_color }};">{{ tripcode.get_short_text }}</a>
22 {% endwith %}
22 {% endwith %}
23 {% endif %}
23 {% endif %}
24 {% comment %}
24 {% comment %}
25 Thread death time needs to be shown only if the thread is alredy archived
25 Thread death time needs to be shown only if the thread is alredy archived
26 and this is an opening post (thread death time) or a post for popup
26 and this is an opening post (thread death time) or a post for popup
27 (we don't see OP here so we show the death time in the post itself).
27 (we don't see OP here so we show the death time in the post itself).
28 {% endcomment %}
28 {% endcomment %}
29 {% if is_opening and thread.is_archived %}
29 {% if is_opening and thread.is_archived %}
30 <time datetime="{{ thread.bump_time|date:'c' }}">{{ thread.bump_time }}</time>
30 <time datetime="{{ thread.bump_time|date:'c' }}">{{ thread.bump_time }}</time>
31 {% endif %}
31 {% endif %}
32 {% if is_opening %}
32 {% if is_opening %}
33 {% if need_open_link %}
33 {% if need_open_link %}
34 {% if thread.is_archived %}
34 {% if thread.is_archived %}
35 <a class="link" href="{% url 'thread' post.id %}">{% trans "Open" %}</a>
35 <a class="link" href="{% url 'thread' post.id %}">{% trans "Open" %}</a>
36 {% else %}
36 {% else %}
37 <a class="link" href="{% url 'thread' post.id %}#form">{% trans "Reply" %}</a>
37 <a class="link" href="{% url 'thread' post.id %}#form">{% trans "Reply" %}</a>
38 {% endif %}
38 {% endif %}
39 {% endif %}
39 {% endif %}
40 {% else %}
40 {% else %}
41 {% if need_op_data %}
41 {% if need_op_data %}
42 {% with thread.get_opening_post as op %}
42 {% with thread.get_opening_post as op %}
43 {% trans " in " %}{{ op.get_link_view|safe }} <span class="title">{{ op.get_title_or_text }}</span>
43 {% trans " in " %}{{ op.get_link_view|safe }} <span class="title">{{ op.get_title_or_text }}</span>
44 {% endwith %}
44 {% endwith %}
45 {% endif %}
45 {% endif %}
46 {% endif %}
46 {% endif %}
47 {% if reply_link and not thread.is_archived %}
47 {% if reply_link and not thread.is_archived %}
48 <a href="#form" onclick="addQuickReply('{{ post.id }}'); return false;">{% trans 'Reply' %}</a>
48 <a href="#form" onclick="addQuickReply('{{ post.id }}'); return false;">{% trans 'Reply' %}</a>
49 {% endif %}
49 {% endif %}
50
50
51 {% if perms.boards.change_post or perms.boards.delete_post or perms.boards.change_thread or perms_boards.delete_thread %}
51 {% if perms.boards.change_post or perms.boards.delete_post or perms.boards.change_thread or perms_boards.delete_thread %}
52 <a class="moderation-menu" href="#">🔒</a>
52 <a class="moderation-menu" href="#">🔒</a>
53 <script>
53 <script>
54 $.contextMenu({
54 $.contextMenu({
55 selector: '#{{ post.id }} .moderation-menu',
55 selector: '#{{ post.id }} .moderation-menu',
56 trigger: 'left',
56 trigger: 'left',
57 build: function($trigger, e) {
57 build: function($trigger, e) {
58 return {
58 return {
59 items: {
59 items: {
60 edit: {
60 edit: {
61 name: '{% trans "Edit" %}',
61 name: '{% trans "Edit" %}',
62 callback: function(key, opt) {
62 callback: function(key, opt) {
63 window.location = '{% url 'admin:boards_post_change' post.id %}';
63 window.location = '{% url 'admin:boards_post_change' post.id %}';
64 },
64 },
65 visible: {% if perms.boards.change_post %}true{% else %}false{% endif %}
65 visible: {% if perms.boards.change_post %}true{% else %}false{% endif %}
66 },
66 },
67 deletePost: {
67 deletePost: {
68 name: '{% trans "Delete post" %}',
68 name: '{% trans "Delete post" %}',
69 callback: function(key, opt) {
69 callback: function(key, opt) {
70 window.location = '{% url 'admin:boards_post_delete' post.id %}';
70 window.location = '{% url 'admin:boards_post_delete' post.id %}';
71 },
71 },
72 visible: {% if not is_opening and perms.boards.delete_post %}true{% else %}false{% endif %}
72 visible: {% if not is_opening and perms.boards.delete_post %}true{% else %}false{% endif %}
73 },
73 },
74 editThread: {
74 editThread: {
75 name: '{% trans "Edit thread" %}',
75 name: '{% trans "Edit thread" %}',
76 callback: function(key, opt) {
76 callback: function(key, opt) {
77 window.location = '{% url 'admin:boards_thread_change' thread.id %}';
77 window.location = '{% url 'admin:boards_thread_change' thread.id %}';
78 },
78 },
79 visible: {% if is_opening and perms.boards.change_thread %}true{% else %}false{% endif %}
79 visible: {% if is_opening and perms.boards.change_thread %}true{% else %}false{% endif %}
80 },
80 },
81 deleteThread: {
81 deleteThread: {
82 name: '{% trans "Delete thread" %}',
82 name: '{% trans "Delete thread" %}',
83 callback: function(key, opt) {
83 callback: function(key, opt) {
84 window.location = '{% url 'admin:boards_thread_delete' thread.id %}';
84 window.location = '{% url 'admin:boards_thread_delete' thread.id %}';
85 },
85 },
86 visible: {% if is_opening and perms.boards.delete_thread %}true{% else %}false{% endif %}
86 visible: {% if is_opening and perms.boards.delete_thread %}true{% else %}false{% endif %}
87 },
87 },
88 findByIp: {
88 findByIp: {
89 name: 'IP = {{ post.poster_ip }}',
89 name: 'IP = {{ post.poster_ip }}',
90 callback: function(key, opt) {
90 callback: function(key, opt) {
91 window.location = '{% url "feed" %}?ip={{ post.poster_ip }}';
91 window.location = '{% url "feed" %}?ip={{ post.poster_ip }}';
92 },
92 },
93 visible: {% if post.has_ip %}true{% else %}false{% endif %}
93 visible: {% if post.has_ip %}true{% else %}false{% endif %}
94 },
94 },
95 raw: {
95 raw: {
96 name: 'RAW',
96 name: 'RAW',
97 callback: function(key, opt) {
97 callback: function(key, opt) {
98 window.location = '{% url 'post_sync_data' post.id %}';
98 window.location = '{% url 'post_sync_data' post.id %}';
99 },
99 },
100 visible: {% if post.global_id_id %}true{% else %}false{% endif %}
100 visible: {% if post.global_id_id %}true{% else %}false{% endif %}
101 },
101 },
102 banAndDelete: {
102 banAndDelete: {
103 name: 'Ban and delete',
103 name: '{% trans "Ban and delete" %}',
104 callback: function(key, opt) {
104 callback: function(key, opt) {
105 window.location = '{% url 'utils' %}?method=ban_and_delete&post_id={{ post.id }}';
105 window.location = '{% url 'utils' %}?method=ban_and_delete&post_id={{ post.id }}';
106 },
106 },
107 visible: {% if post.has_ip %}true{% else %}false{% endif %}
107 visible: {% if post.has_ip %}true{% else %}false{% endif %}
108 }
108 }
109 }
109 }
110 };
110 };
111 }
111 }
112 });
112 });
113 </script>
113 </script>
114 {% endif %}
114 {% endif %}
115 </div>
115 </div>
116 {% comment %}
116 {% comment %}
117 Post images. Currently only 1 image can be posted and shown, but post model
117 Post images. Currently only 1 image can be posted and shown, but post model
118 supports multiple.
118 supports multiple.
119 {% endcomment %}
119 {% endcomment %}
120 {% for image in post.images.all %}
120 {% for image in post.images.all %}
121 {{ image.get_view|safe }}
121 {{ image.get_view|safe }}
122 {% endfor %}
122 {% endfor %}
123 {% for file in post.attachments.all %}
123 {% for file in post.attachments.all %}
124 {{ file.get_view|safe }}
124 {{ file.get_view|safe }}
125 {% endfor %}
125 {% endfor %}
126 {% comment %}
126 {% comment %}
127 Post message (text)
127 Post message (text)
128 {% endcomment %}
128 {% endcomment %}
129 <div class="message">
129 <div class="message">
130 {% if truncated %}
130 {% if truncated %}
131 {{ post.get_text|truncatewords_html:50|truncatenewlines_html:3|safe }}
131 {{ post.get_text|truncatewords_html:50|truncatenewlines_html:3|safe }}
132 {% else %}
132 {% else %}
133 {{ post.get_text|safe }}
133 {{ post.get_text|safe }}
134 {% endif %}
134 {% endif %}
135 </div>
135 </div>
136 {% if post.is_referenced and not mode_tree %}
136 {% if post.is_referenced and not mode_tree %}
137 <div class="refmap">
137 <div class="refmap">
138 {% trans "Replies" %}: {{ post.refmap|safe }}
138 {% trans "Replies" %}: {{ post.refmap|safe }}
139 </div>
139 </div>
140 {% endif %}
140 {% endif %}
141 {% comment %}
141 {% comment %}
142 Thread metadata: counters, tags etc
142 Thread metadata: counters, tags etc
143 {% endcomment %}
143 {% endcomment %}
144 {% if is_opening %}
144 {% if is_opening %}
145 <div class="metadata">
145 <div class="metadata">
146 {% if need_open_link %}
146 {% if need_open_link %}
147 ♥ {{ thread.get_reply_count }}
147 ♥ {{ thread.get_reply_count }}
148 ❄ {{ thread.get_images_count }}
148 ❄ {{ thread.get_images_count }}
149 <a href="{% url 'thread_gallery' post.id %}">G</a>
149 <a href="{% url 'thread_gallery' post.id %}">G</a>
150 <a href="{% url 'thread_tree' post.id %}">T</a>
150 <a href="{% url 'thread_tree' post.id %}">T</a>
151 {% endif %}
151 {% endif %}
152 <span class="tags">
152 <span class="tags">
153 {{ thread.get_tag_url_list|safe }}
153 {{ thread.get_tag_url_list|safe }}
154 </span>
154 </span>
155 </div>
155 </div>
156 {% endif %}
156 {% endif %}
157 </div>
157 </div>
@@ -1,24 +1,26 b''
1 from django.shortcuts import redirect
1 from django.shortcuts import redirect
2 from django.utils.decorators import method_decorator
2 from django.utils.decorators import method_decorator
3 from django.views.decorators.csrf import csrf_protect
3 from django.views.decorators.csrf import csrf_protect
4 from django.contrib.auth.decorators import permission_required
5
4 from boards.views.base import BaseBoardView, CONTEXT_FORM
6 from boards.views.base import BaseBoardView, CONTEXT_FORM
5 from boards.views.mixins import DispatcherMixin, PARAMETER_METHOD
7 from boards.views.mixins import DispatcherMixin, PARAMETER_METHOD
6 from boards.models import Post, Ban
8 from boards.models import Post, Ban
7
9
8
10
9 class UtilsView(BaseBoardView, DispatcherMixin):
11 class UtilsView(BaseBoardView, DispatcherMixin):
10 @method_decorator(csrf_protect)
12 @method_decorator(csrf_protect)
11 def get(self, request):
13 def get(self, request):
12 self.dispatch_method(request)
14 self.dispatch_method(request)
13
15
14 return redirect('index')
16 return redirect('index')
15
17
16
18 @permission_required('boards.delete_post')
17 def ban_and_delete(self, request):
19 def ban_and_delete(self, request):
18 post = Post.objects.get(id=request.GET['post_id'])
20 post = Post.objects.get(id=request.GET['post_id'])
19 Ban.objects.get_or_create(ip=post.poster_ip)
21 Ban.objects.get_or_create(ip=post.poster_ip)
20 if post.is_opening():
22 if post.is_opening():
21 post.get_thread().delete()
23 post.get_thread().delete()
22 else:
24 else:
23 post.delete()
25 post.delete()
24
26
General Comments 0
You need to be logged in to leave comments. Login now