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