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