##// END OF EJS Templates
Fixed loading previews of OPs in bumplimit
neko259 -
r378:57d21b81 default
parent child Browse files
Show More
@@ -1,564 +1,566 b''
1 1 import hashlib
2 2 import json
3 3 import string
4 4 import time
5 5 import calendar
6 6
7 7 from datetime import datetime
8 8
9 9 from django.core import serializers
10 10 from django.core.urlresolvers import reverse
11 11 from django.http import HttpResponseRedirect
12 12 from django.http.response import HttpResponse
13 13 from django.template import RequestContext
14 14 from django.shortcuts import render, redirect, get_object_or_404
15 15 from django.utils import timezone
16 16 from django.db import transaction
17 17 import math
18 18
19 19 from boards import forms
20 20 import boards
21 21 from boards import utils
22 22 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
23 23 ThreadCaptchaForm, PostCaptchaForm, LoginForm, ModeratorSettingsForm
24 24
25 25 from boards.models import Post, Tag, Ban, User, RANK_USER, SETTING_MODERATE, \
26 26 REGEX_REPLY
27 27 from boards import authors
28 28 from boards.utils import get_client_ip
29 29 import neboard
30 30 import re
31 31
32 32 BAN_REASON_SPAM = 'Autoban: spam bot'
33 33
34 34
35 35 def index(request, page=0):
36 36 context = _init_default_context(request)
37 37
38 38 if utils.need_include_captcha(request):
39 39 threadFormClass = ThreadCaptchaForm
40 40 kwargs = {'request': request}
41 41 else:
42 42 threadFormClass = ThreadForm
43 43 kwargs = {}
44 44
45 45 if request.method == 'POST':
46 46 form = threadFormClass(request.POST, request.FILES,
47 47 error_class=PlainErrorList, **kwargs)
48 48 form.session = request.session
49 49
50 50 if form.is_valid():
51 51 return _new_post(request, form)
52 52 if form.need_to_ban:
53 53 # Ban user because he is suspected to be a bot
54 54 _ban_current_user(request)
55 55 else:
56 56 form = threadFormClass(error_class=PlainErrorList, **kwargs)
57 57
58 58 threads = []
59 59 for thread in Post.objects.get_threads(page=int(page)):
60 60 threads.append({
61 61 'thread': thread,
62 62 'bumpable': thread.can_bump(),
63 63 'last_replies': thread.get_last_replies(),
64 64 })
65 65
66 66 # TODO Make this generic for tag and threads list pages
67 67 context['threads'] = None if len(threads) == 0 else threads
68 68 context['form'] = form
69 69
70 70 page_count = Post.objects.get_thread_page_count()
71 71 context['pages'] = range(page_count)
72 72 page = int(page)
73 73 if page < page_count - 1:
74 74 context['next_page'] = str(page + 1)
75 75 if page > 0:
76 76 context['prev_page'] = str(page - 1)
77 77
78 78 return render(request, 'boards/posting_general.html',
79 79 context)
80 80
81 81
82 82 @transaction.commit_on_success
83 83 def _new_post(request, form, thread_id=boards.models.NO_PARENT):
84 84 """Add a new post (in thread or as a reply)."""
85 85
86 86 ip = get_client_ip(request)
87 87 is_banned = Ban.objects.filter(ip=ip).exists()
88 88
89 89 if is_banned:
90 90 return redirect(you_are_banned)
91 91
92 92 data = form.cleaned_data
93 93
94 94 title = data['title']
95 95 text = data['text']
96 96
97 97 text = _remove_invalid_links(text)
98 98
99 99 if 'image' in data.keys():
100 100 image = data['image']
101 101 else:
102 102 image = None
103 103
104 104 tags = []
105 105
106 106 new_thread = thread_id == boards.models.NO_PARENT
107 107 if new_thread:
108 108 tag_strings = data['tags']
109 109
110 110 if tag_strings:
111 111 tag_strings = tag_strings.split(' ')
112 112 for tag_name in tag_strings:
113 113 tag_name = string.lower(tag_name.strip())
114 114 if len(tag_name) > 0:
115 115 tag, created = Tag.objects.get_or_create(name=tag_name)
116 116 tags.append(tag)
117 117
118 118 linked_tags = tag.get_linked_tags()
119 119 if len(linked_tags) > 0:
120 120 tags.extend(linked_tags)
121 121
122 122 op = None if thread_id == boards.models.NO_PARENT else \
123 123 get_object_or_404(Post, id=thread_id)
124 124 post = Post.objects.create_post(title=title, text=text, ip=ip,
125 125 thread=op, image=image,
126 126 tags=tags, user=_get_user(request))
127 127
128 128 thread_to_show = (post.id if new_thread else thread_id)
129 129
130 130 if new_thread:
131 131 return redirect(thread, post_id=thread_to_show)
132 132 else:
133 133 return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) +
134 134 '#' + str(post.id))
135 135
136 136
137 137 def tag(request, tag_name, page=0):
138 138 """
139 139 Get all tag threads. Threads are split in pages, so some page is
140 140 requested. Default page is 0.
141 141 """
142 142
143 143 tag = get_object_or_404(Tag, name=tag_name)
144 144 threads = []
145 145 for thread in Post.objects.get_threads(tag=tag, page=int(page)):
146 146 threads.append({
147 147 'thread': thread,
148 148 'bumpable': thread.can_bump(),
149 149 'last_replies': thread.get_last_replies(),
150 150 })
151 151
152 152 if request.method == 'POST':
153 153 form = ThreadForm(request.POST, request.FILES,
154 154 error_class=PlainErrorList)
155 155 form.session = request.session
156 156
157 157 if form.is_valid():
158 158 return _new_post(request, form)
159 159 if form.need_to_ban:
160 160 # Ban user because he is suspected to be a bot
161 161 _ban_current_user(request)
162 162 else:
163 163 form = forms.ThreadForm(initial={'tags': tag_name},
164 164 error_class=PlainErrorList)
165 165
166 166 context = _init_default_context(request)
167 167 context['threads'] = None if len(threads) == 0 else threads
168 168 context['tag'] = tag
169 169
170 170 page_count = Post.objects.get_thread_page_count(tag=tag)
171 171 context['pages'] = range(page_count)
172 172 page = int(page)
173 173 if page < page_count - 1:
174 174 context['next_page'] = str(page + 1)
175 175 if page > 0:
176 176 context['prev_page'] = str(page - 1)
177 177
178 178 context['form'] = form
179 179
180 180 return render(request, 'boards/posting_general.html',
181 181 context)
182 182
183 183
184 184 def thread(request, post_id):
185 185 """Get all thread posts"""
186 186
187 187 if utils.need_include_captcha(request):
188 188 postFormClass = PostCaptchaForm
189 189 kwargs = {'request': request}
190 190 else:
191 191 postFormClass = PostForm
192 192 kwargs = {}
193 193
194 194 if request.method == 'POST':
195 195 form = postFormClass(request.POST, request.FILES,
196 196 error_class=PlainErrorList, **kwargs)
197 197 form.session = request.session
198 198
199 199 if form.is_valid():
200 200 return _new_post(request, form, post_id)
201 201 if form.need_to_ban:
202 202 # Ban user because he is suspected to be a bot
203 203 _ban_current_user(request)
204 204 else:
205 205 form = postFormClass(error_class=PlainErrorList, **kwargs)
206 206
207 207 posts = Post.objects.get_thread(post_id)
208 208
209 209 context = _init_default_context(request)
210 210
211 211 context['posts'] = posts
212 212 context['form'] = form
213 213 context['bumpable'] = posts[0].can_bump()
214 214 if context['bumpable']:
215 215 context['posts_left'] = neboard.settings.MAX_POSTS_PER_THREAD - len(
216 216 posts)
217 217 context['bumplimit_progress'] = str(
218 218 float(context['posts_left']) /
219 219 neboard.settings.MAX_POSTS_PER_THREAD * 100)
220 220 context["last_update"] = _datetime_to_epoch(posts[0].last_edit_time)
221 221
222 222 return render(request, 'boards/thread.html', context)
223 223
224 224
225 225 def login(request):
226 226 """Log in with user id"""
227 227
228 228 context = _init_default_context(request)
229 229
230 230 if request.method == 'POST':
231 231 form = LoginForm(request.POST, request.FILES,
232 232 error_class=PlainErrorList)
233 233 form.session = request.session
234 234
235 235 if form.is_valid():
236 236 user = User.objects.get(user_id=form.cleaned_data['user_id'])
237 237 request.session['user_id'] = user.id
238 238 return redirect(index)
239 239
240 240 else:
241 241 form = LoginForm()
242 242
243 243 context['form'] = form
244 244
245 245 return render(request, 'boards/login.html', context)
246 246
247 247
248 248 def settings(request):
249 249 """User's settings"""
250 250
251 251 context = _init_default_context(request)
252 252 user = _get_user(request)
253 253 is_moderator = user.is_moderator()
254 254
255 255 if request.method == 'POST':
256 256 with transaction.commit_on_success():
257 257 if is_moderator:
258 258 form = ModeratorSettingsForm(request.POST,
259 259 error_class=PlainErrorList)
260 260 else:
261 261 form = SettingsForm(request.POST, error_class=PlainErrorList)
262 262
263 263 if form.is_valid():
264 264 selected_theme = form.cleaned_data['theme']
265 265
266 266 user.save_setting('theme', selected_theme)
267 267
268 268 if is_moderator:
269 269 moderate = form.cleaned_data['moderate']
270 270 user.save_setting(SETTING_MODERATE, moderate)
271 271
272 272 return redirect(settings)
273 273 else:
274 274 selected_theme = _get_theme(request)
275 275
276 276 if is_moderator:
277 277 form = ModeratorSettingsForm(initial={'theme': selected_theme,
278 278 'moderate': context['moderator']},
279 279 error_class=PlainErrorList)
280 280 else:
281 281 form = SettingsForm(initial={'theme': selected_theme},
282 282 error_class=PlainErrorList)
283 283
284 284 context['form'] = form
285 285
286 286 return render(request, 'boards/settings.html', context)
287 287
288 288
289 289 def all_tags(request):
290 290 """All tags list"""
291 291
292 292 context = _init_default_context(request)
293 293 context['all_tags'] = Tag.objects.get_not_empty_tags()
294 294
295 295 return render(request, 'boards/tags.html', context)
296 296
297 297
298 298 def jump_to_post(request, post_id):
299 299 """Determine thread in which the requested post is and open it's page"""
300 300
301 301 post = get_object_or_404(Post, id=post_id)
302 302
303 303 if not post.thread:
304 304 return redirect(thread, post_id=post.id)
305 305 else:
306 306 return redirect(reverse(thread, kwargs={'post_id': post.thread.id})
307 307 + '#' + str(post.id))
308 308
309 309
310 310 def authors(request):
311 311 """Show authors list"""
312 312
313 313 context = _init_default_context(request)
314 314 context['authors'] = boards.authors.authors
315 315
316 316 return render(request, 'boards/authors.html', context)
317 317
318 318
319 319 @transaction.commit_on_success
320 320 def delete(request, post_id):
321 321 """Delete post"""
322 322
323 323 user = _get_user(request)
324 324 post = get_object_or_404(Post, id=post_id)
325 325
326 326 if user.is_moderator():
327 327 # TODO Show confirmation page before deletion
328 328 Post.objects.delete_post(post)
329 329
330 330 if not post.thread:
331 331 return _redirect_to_next(request)
332 332 else:
333 333 return redirect(thread, post_id=post.thread.id)
334 334
335 335
336 336 @transaction.commit_on_success
337 337 def ban(request, post_id):
338 338 """Ban user"""
339 339
340 340 user = _get_user(request)
341 341 post = get_object_or_404(Post, id=post_id)
342 342
343 343 if user.is_moderator():
344 344 # TODO Show confirmation page before ban
345 345 ban, created = Ban.objects.get_or_create(ip=post.poster_ip)
346 346 if created:
347 347 ban.reason = 'Banned for post ' + str(post_id)
348 348 ban.save()
349 349
350 350 return _redirect_to_next(request)
351 351
352 352
353 353 def you_are_banned(request):
354 354 """Show the page that notifies that user is banned"""
355 355
356 356 context = _init_default_context(request)
357 357
358 358 ban = get_object_or_404(Ban, ip=utils.get_client_ip(request))
359 359 context['ban_reason'] = ban.reason
360 360 return render(request, 'boards/staticpages/banned.html', context)
361 361
362 362
363 363 def page_404(request):
364 364 """Show page 404 (not found error)"""
365 365
366 366 context = _init_default_context(request)
367 367 return render(request, 'boards/404.html', context)
368 368
369 369
370 370 @transaction.commit_on_success
371 371 def tag_subscribe(request, tag_name):
372 372 """Add tag to favorites"""
373 373
374 374 user = _get_user(request)
375 375 tag = get_object_or_404(Tag, name=tag_name)
376 376
377 377 if not tag in user.fav_tags.all():
378 378 user.add_tag(tag)
379 379
380 380 return _redirect_to_next(request)
381 381
382 382
383 383 @transaction.commit_on_success
384 384 def tag_unsubscribe(request, tag_name):
385 385 """Remove tag from favorites"""
386 386
387 387 user = _get_user(request)
388 388 tag = get_object_or_404(Tag, name=tag_name)
389 389
390 390 if tag in user.fav_tags.all():
391 391 user.remove_tag(tag)
392 392
393 393 return _redirect_to_next(request)
394 394
395 395
396 396 def static_page(request, name):
397 397 """Show a static page that needs only tags list and a CSS"""
398 398
399 399 context = _init_default_context(request)
400 400 return render(request, 'boards/staticpages/' + name + '.html', context)
401 401
402 402
403 403 def api_get_post(request, post_id):
404 404 """
405 405 Get the JSON of a post. This can be
406 406 used as and API for external clients.
407 407 """
408 408
409 409 post = get_object_or_404(Post, id=post_id)
410 410
411 411 json = serializers.serialize("json", [post], fields=(
412 412 "pub_time", "_text_rendered", "title", "text", "image",
413 413 "image_width", "image_height", "replies", "tags"
414 414 ))
415 415
416 416 return HttpResponse(content=json)
417 417
418 418
419 419 def api_get_threaddiff(request, thread_id, last_update_time):
420 420 """Get posts that were changed or added since time"""
421 421
422 422 thread = get_object_or_404(Post, id=thread_id)
423 423
424 424 filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000,
425 425 timezone.get_current_timezone())
426 426
427 427 json_data = {
428 428 'added': [],
429 429 'updated': [],
430 430 'last_update': None,
431 431 }
432 432 added_posts = Post.objects.filter(thread=thread, pub_time__gt=filter_time)
433 433 updated_posts = Post.objects.filter(thread=thread,
434 434 pub_time__lt=filter_time,
435 435 last_edit_time__gt=filter_time)
436 436 for post in added_posts:
437 437 json_data['added'].append(get_post(request, post.id).content.strip())
438 438 for post in updated_posts:
439 439 json_data['updated'].append(get_post(request, post.id).content.strip())
440 440 json_data['last_update'] = _datetime_to_epoch(thread.last_edit_time)
441 441
442 442 return HttpResponse(content=json.dumps(json_data))
443 443
444 444
445 445 def get_post(request, post_id):
446 446 """Get the html of a post. Used for popups."""
447 447
448 448 post = get_object_or_404(Post, id=post_id)
449 449 thread = post.thread
450 if not thread:
451 thread = post
450 452
451 453 context = RequestContext(request)
452 454 context["post"] = post
453 455 context["can_bump"] = thread.can_bump()
454 456 if "truncated" in request.GET:
455 457 context["truncated"] = True
456 458
457 459 return render(request, 'boards/post.html', context)
458 460
459 461
460 462 def _get_theme(request, user=None):
461 463 """Get user's CSS theme"""
462 464
463 465 if not user:
464 466 user = _get_user(request)
465 467 theme = user.get_setting('theme')
466 468 if not theme:
467 469 theme = neboard.settings.DEFAULT_THEME
468 470
469 471 return theme
470 472
471 473
472 474 def _init_default_context(request):
473 475 """Create context with default values that are used in most views"""
474 476
475 477 context = RequestContext(request)
476 478
477 479 user = _get_user(request)
478 480 context['user'] = user
479 481 context['tags'] = user.get_sorted_fav_tags()
480 482
481 483 theme = _get_theme(request, user)
482 484 context['theme'] = theme
483 485 context['theme_css'] = 'css/' + theme + '/base_page.css'
484 486
485 487 # This shows the moderator panel
486 488 moderate = user.get_setting(SETTING_MODERATE)
487 489 if moderate == 'True':
488 490 context['moderator'] = user.is_moderator()
489 491 else:
490 492 context['moderator'] = False
491 493
492 494 return context
493 495
494 496
495 497 def _get_user(request):
496 498 """
497 499 Get current user from the session. If the user does not exist, create
498 500 a new one.
499 501 """
500 502
501 503 session = request.session
502 504 if not 'user_id' in session:
503 505 request.session.save()
504 506
505 507 md5 = hashlib.md5()
506 508 md5.update(session.session_key)
507 509 new_id = md5.hexdigest()
508 510
509 511 time_now = timezone.now()
510 512 user = User.objects.create(user_id=new_id, rank=RANK_USER,
511 513 registration_time=time_now)
512 514
513 515 session['user_id'] = user.id
514 516 else:
515 517 user = User.objects.get(id=session['user_id'])
516 518
517 519 return user
518 520
519 521
520 522 def _redirect_to_next(request):
521 523 """
522 524 If a 'next' parameter was specified, redirect to the next page. This is
523 525 used when the user is required to return to some page after the current
524 526 view has finished its work.
525 527 """
526 528
527 529 if 'next' in request.GET:
528 530 next_page = request.GET['next']
529 531 return HttpResponseRedirect(next_page)
530 532 else:
531 533 return redirect(index)
532 534
533 535
534 536 @transaction.commit_on_success
535 537 def _ban_current_user(request):
536 538 """Add current user to the IP ban list"""
537 539
538 540 ip = utils.get_client_ip(request)
539 541 ban, created = Ban.objects.get_or_create(ip=ip)
540 542 if created:
541 543 ban.can_read = False
542 544 ban.reason = BAN_REASON_SPAM
543 545 ban.save()
544 546
545 547
546 548 def _remove_invalid_links(text):
547 549 """
548 550 Replace invalid links in posts so that they won't be parsed.
549 551 Invalid links are links to non-existent posts
550 552 """
551 553
552 554 for reply_number in re.finditer(REGEX_REPLY, text):
553 555 post_id = reply_number.group(1)
554 556 post = Post.objects.filter(id=post_id)
555 557 if not post.exists():
556 558 text = string.replace(text, '>>' + id, id)
557 559
558 560 return text
559 561
560 562
561 563 def _datetime_to_epoch(datetime):
562 564 return int(time.mktime(timezone.localtime(
563 565 datetime,timezone.get_current_timezone()).timetuple())
564 566 * 1000000 + datetime.microsecond) No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now