##// END OF EJS Templates
Added a todo in the thread view
neko259 -
r859:3138fe55 default
parent child Browse files
Show More
@@ -1,157 +1,158 b''
1 from django.core.urlresolvers import reverse
1 from django.core.urlresolvers import reverse
2 from django.db import transaction
2 from django.db import transaction
3 from django.http import Http404
3 from django.http import Http404
4 from django.shortcuts import get_object_or_404, render, redirect
4 from django.shortcuts import get_object_or_404, render, redirect
5 from django.views.decorators.cache import never_cache, cache_control
5 from django.views.decorators.cache import never_cache, cache_control
6 from django.views.generic.edit import FormMixin
6 from django.views.generic.edit import FormMixin
7
7
8 from boards import utils, settings
8 from boards import utils, settings
9 from boards.forms import PostForm, PlainErrorList
9 from boards.forms import PostForm, PlainErrorList
10 from boards.models import Post, Ban
10 from boards.models import Post, Ban
11 from boards.views.banned import BannedView
11 from boards.views.banned import BannedView
12 from boards.views.base import BaseBoardView, CONTEXT_FORM
12 from boards.views.base import BaseBoardView, CONTEXT_FORM
13 from boards.views.posting_mixin import PostMixin
13 from boards.views.posting_mixin import PostMixin
14 import neboard
14 import neboard
15
15
16 TEMPLATE_GALLERY = 'boards/thread_gallery.html'
16 TEMPLATE_GALLERY = 'boards/thread_gallery.html'
17 TEMPLATE_NORMAL = 'boards/thread.html'
17 TEMPLATE_NORMAL = 'boards/thread.html'
18
18
19 CONTEXT_POSTS = 'posts'
19 CONTEXT_POSTS = 'posts'
20 CONTEXT_OP = 'opening_post'
20 CONTEXT_OP = 'opening_post'
21 CONTEXT_BUMPLIMIT_PRG = 'bumplimit_progress'
21 CONTEXT_BUMPLIMIT_PRG = 'bumplimit_progress'
22 CONTEXT_POSTS_LEFT = 'posts_left'
22 CONTEXT_POSTS_LEFT = 'posts_left'
23 CONTEXT_LASTUPDATE = "last_update"
23 CONTEXT_LASTUPDATE = "last_update"
24 CONTEXT_MAX_REPLIES = 'max_replies'
24 CONTEXT_MAX_REPLIES = 'max_replies'
25 CONTEXT_THREAD = 'thread'
25 CONTEXT_THREAD = 'thread'
26 CONTEXT_BUMPABLE = 'bumpable'
26 CONTEXT_BUMPABLE = 'bumpable'
27 CONTEXT_WS_TOKEN = 'ws_token'
27 CONTEXT_WS_TOKEN = 'ws_token'
28 CONTEXT_WS_PROJECT = 'ws_project'
28 CONTEXT_WS_PROJECT = 'ws_project'
29 CONTEXT_WS_HOST = 'ws_host'
29 CONTEXT_WS_HOST = 'ws_host'
30 CONTEXT_WS_PORT = 'ws_port'
30 CONTEXT_WS_PORT = 'ws_port'
31
31
32 FORM_TITLE = 'title'
32 FORM_TITLE = 'title'
33 FORM_TEXT = 'text'
33 FORM_TEXT = 'text'
34 FORM_IMAGE = 'image'
34 FORM_IMAGE = 'image'
35
35
36 MODE_GALLERY = 'gallery'
36 MODE_GALLERY = 'gallery'
37 MODE_NORMAL = 'normal'
37 MODE_NORMAL = 'normal'
38
38
39
39
40 class ThreadView(BaseBoardView, PostMixin, FormMixin):
40 class ThreadView(BaseBoardView, PostMixin, FormMixin):
41
41
42 @cache_control(no_cache=True)
42 @cache_control(no_cache=True)
43 def get(self, request, post_id, mode=MODE_NORMAL, form=None):
43 def get(self, request, post_id, mode=MODE_NORMAL, form=None):
44 try:
44 try:
45 opening_post = Post.objects.filter(id=post_id).only('thread_new')[0]
45 opening_post = Post.objects.filter(id=post_id).only('thread_new')[0]
46 except IndexError:
46 except IndexError:
47 raise Http404
47 raise Http404
48
48
49 # If this is not OP, don't show it as it is
49 # If this is not OP, don't show it as it is
50 if not opening_post or not opening_post.is_opening():
50 if not opening_post or not opening_post.is_opening():
51 raise Http404
51 raise Http404
52
52
53 if not form:
53 if not form:
54 form = PostForm(error_class=PlainErrorList)
54 form = PostForm(error_class=PlainErrorList)
55
55
56 thread_to_show = opening_post.get_thread()
56 thread_to_show = opening_post.get_thread()
57
57
58 context = self.get_context_data(request=request)
58 context = self.get_context_data(request=request)
59
59
60 context[CONTEXT_FORM] = form
60 context[CONTEXT_FORM] = form
61 context[CONTEXT_LASTUPDATE] = str(utils.datetime_to_epoch(
61 context[CONTEXT_LASTUPDATE] = str(utils.datetime_to_epoch(
62 thread_to_show.last_edit_time))
62 thread_to_show.last_edit_time))
63 context[CONTEXT_THREAD] = thread_to_show
63 context[CONTEXT_THREAD] = thread_to_show
64 context[CONTEXT_MAX_REPLIES] = settings.MAX_POSTS_PER_THREAD
64 context[CONTEXT_MAX_REPLIES] = settings.MAX_POSTS_PER_THREAD
65
65
66 if settings.WEBSOCKETS_ENABLED:
66 if settings.WEBSOCKETS_ENABLED:
67 context[CONTEXT_WS_TOKEN] = utils.get_websocket_token(
67 context[CONTEXT_WS_TOKEN] = utils.get_websocket_token(
68 timestamp=context[CONTEXT_LASTUPDATE])
68 timestamp=context[CONTEXT_LASTUPDATE])
69 context[CONTEXT_WS_PROJECT] = neboard.settings.CENTRIFUGE_PROJECT_ID
69 context[CONTEXT_WS_PROJECT] = neboard.settings.CENTRIFUGE_PROJECT_ID
70 context[CONTEXT_WS_HOST] = request.get_host().split(':')[0]
70 context[CONTEXT_WS_HOST] = request.get_host().split(':')[0]
71 context[CONTEXT_WS_PORT] = neboard.settings.CENTRIFUGE_PORT
71 context[CONTEXT_WS_PORT] = neboard.settings.CENTRIFUGE_PORT
72
72
73 # TODO Move this to subclasses: NormalThreadView, GalleryThreadView etc
73 if MODE_NORMAL == mode:
74 if MODE_NORMAL == mode:
74 bumpable = thread_to_show.can_bump()
75 bumpable = thread_to_show.can_bump()
75 context[CONTEXT_BUMPABLE] = bumpable
76 context[CONTEXT_BUMPABLE] = bumpable
76 if bumpable:
77 if bumpable:
77 left_posts = settings.MAX_POSTS_PER_THREAD \
78 left_posts = settings.MAX_POSTS_PER_THREAD \
78 - thread_to_show.get_reply_count()
79 - thread_to_show.get_reply_count()
79 context[CONTEXT_POSTS_LEFT] = left_posts
80 context[CONTEXT_POSTS_LEFT] = left_posts
80 context[CONTEXT_BUMPLIMIT_PRG] = str(
81 context[CONTEXT_BUMPLIMIT_PRG] = str(
81 float(left_posts) / settings.MAX_POSTS_PER_THREAD * 100)
82 float(left_posts) / settings.MAX_POSTS_PER_THREAD * 100)
82
83
83 context[CONTEXT_OP] = opening_post
84 context[CONTEXT_OP] = opening_post
84
85
85 document = TEMPLATE_NORMAL
86 document = TEMPLATE_NORMAL
86 elif MODE_GALLERY == mode:
87 elif MODE_GALLERY == mode:
87 context[CONTEXT_POSTS] = thread_to_show.get_replies_with_images(
88 context[CONTEXT_POSTS] = thread_to_show.get_replies_with_images(
88 view_fields_only=True)
89 view_fields_only=True)
89
90
90 document = TEMPLATE_GALLERY
91 document = TEMPLATE_GALLERY
91 else:
92 else:
92 raise Http404
93 raise Http404
93
94
94 return render(request, document, context)
95 return render(request, document, context)
95
96
96 def post(self, request, post_id, mode=MODE_NORMAL):
97 def post(self, request, post_id, mode=MODE_NORMAL):
97 opening_post = get_object_or_404(Post, id=post_id)
98 opening_post = get_object_or_404(Post, id=post_id)
98
99
99 # If this is not OP, don't show it as it is
100 # If this is not OP, don't show it as it is
100 if not opening_post.is_opening():
101 if not opening_post.is_opening():
101 raise Http404
102 raise Http404
102
103
103 if not opening_post.get_thread().archived:
104 if not opening_post.get_thread().archived:
104 form = PostForm(request.POST, request.FILES,
105 form = PostForm(request.POST, request.FILES,
105 error_class=PlainErrorList)
106 error_class=PlainErrorList)
106 form.session = request.session
107 form.session = request.session
107
108
108 if form.is_valid():
109 if form.is_valid():
109 return self.new_post(request, form, opening_post)
110 return self.new_post(request, form, opening_post)
110 if form.need_to_ban:
111 if form.need_to_ban:
111 # Ban user because he is suspected to be a bot
112 # Ban user because he is suspected to be a bot
112 self._ban_current_user(request)
113 self._ban_current_user(request)
113
114
114 return self.get(request, post_id, mode, form)
115 return self.get(request, post_id, mode, form)
115
116
116 @transaction.atomic
117 @transaction.atomic
117 def new_post(self, request, form, opening_post=None, html_response=True):
118 def new_post(self, request, form, opening_post=None, html_response=True):
118 """Add a new post (in thread or as a reply)."""
119 """Add a new post (in thread or as a reply)."""
119
120
120 ip = utils.get_client_ip(request)
121 ip = utils.get_client_ip(request)
121 is_banned = Ban.objects.filter(ip=ip).exists()
122 is_banned = Ban.objects.filter(ip=ip).exists()
122
123
123 if is_banned:
124 if is_banned:
124 if html_response:
125 if html_response:
125 return redirect(BannedView().as_view())
126 return redirect(BannedView().as_view())
126 else:
127 else:
127 return None
128 return None
128
129
129 data = form.cleaned_data
130 data = form.cleaned_data
130
131
131 title = data[FORM_TITLE]
132 title = data[FORM_TITLE]
132 text = data[FORM_TEXT]
133 text = data[FORM_TEXT]
133
134
134 text = self._remove_invalid_links(text)
135 text = self._remove_invalid_links(text)
135
136
136 if FORM_IMAGE in list(data.keys()):
137 if FORM_IMAGE in list(data.keys()):
137 image = data[FORM_IMAGE]
138 image = data[FORM_IMAGE]
138 else:
139 else:
139 image = None
140 image = None
140
141
141 tags = []
142 tags = []
142
143
143 post_thread = opening_post.get_thread()
144 post_thread = opening_post.get_thread()
144
145
145 post = Post.objects.create_post(title=title, text=text, image=image,
146 post = Post.objects.create_post(title=title, text=text, image=image,
146 thread=post_thread, ip=ip, tags=tags)
147 thread=post_thread, ip=ip, tags=tags)
147 post.send_to_websocket(request)
148 post.send_to_websocket(request)
148
149
149 thread_to_show = (opening_post.id if opening_post else post.id)
150 thread_to_show = (opening_post.id if opening_post else post.id)
150
151
151 if html_response:
152 if html_response:
152 if opening_post:
153 if opening_post:
153 return redirect(
154 return redirect(
154 reverse('thread', kwargs={'post_id': thread_to_show})
155 reverse('thread', kwargs={'post_id': thread_to_show})
155 + '#' + str(post.id))
156 + '#' + str(post.id))
156 else:
157 else:
157 return post
158 return post
General Comments 0
You need to be logged in to leave comments. Login now