##// END OF EJS Templates
Merged with default
neko259 -
r1446:df43af37 merge decentral
parent child Browse files
Show More
@@ -1,295 +1,295 b''
1 import json
1 import json
2 import logging
2 import logging
3
3
4 from django.core import serializers
4 from django.core import serializers
5 from django.db import transaction
5 from django.db import transaction
6 from django.http import HttpResponse
6 from django.http import HttpResponse
7 from django.shortcuts import get_object_or_404
7 from django.shortcuts import get_object_or_404
8 from django.views.decorators.csrf import csrf_protect
8 from django.views.decorators.csrf import csrf_protect
9
9
10 from boards.abstracts.settingsmanager import get_settings_manager
10 from boards.abstracts.settingsmanager import get_settings_manager
11 from boards.forms import PostForm, PlainErrorList
11 from boards.forms import PostForm, PlainErrorList
12 from boards.mdx_neboard import Parser
12 from boards.mdx_neboard import Parser
13 from boards.models import Post, Thread, Tag
13 from boards.models import Post, Thread, Tag
14 from boards.models.thread import STATUS_ARCHIVE
14 from boards.models.thread import STATUS_ARCHIVE
15 from boards.models.user import Notification
15 from boards.models.user import Notification
16 from boards.utils import datetime_to_epoch
16 from boards.utils import datetime_to_epoch
17 from boards.views.thread import ThreadView
17 from boards.views.thread import ThreadView
18
18
19 __author__ = 'neko259'
19 __author__ = 'neko259'
20
20
21 PARAMETER_TRUNCATED = 'truncated'
21 PARAMETER_TRUNCATED = 'truncated'
22 PARAMETER_TAG = 'tag'
22 PARAMETER_TAG = 'tag'
23 PARAMETER_OFFSET = 'offset'
23 PARAMETER_OFFSET = 'offset'
24 PARAMETER_DIFF_TYPE = 'type'
24 PARAMETER_DIFF_TYPE = 'type'
25 PARAMETER_POST = 'post'
25 PARAMETER_POST = 'post'
26 PARAMETER_UPDATED = 'updated'
26 PARAMETER_UPDATED = 'updated'
27 PARAMETER_LAST_UPDATE = 'last_update'
27 PARAMETER_LAST_UPDATE = 'last_update'
28 PARAMETER_THREAD = 'thread'
28 PARAMETER_THREAD = 'thread'
29 PARAMETER_UIDS = 'uids'
29 PARAMETER_UIDS = 'uids'
30
30
31 DIFF_TYPE_HTML = 'html'
31 DIFF_TYPE_HTML = 'html'
32 DIFF_TYPE_JSON = 'json'
32 DIFF_TYPE_JSON = 'json'
33
33
34 STATUS_OK = 'ok'
34 STATUS_OK = 'ok'
35 STATUS_ERROR = 'error'
35 STATUS_ERROR = 'error'
36
36
37 logger = logging.getLogger(__name__)
37 logger = logging.getLogger(__name__)
38
38
39
39
40 @transaction.atomic
40 @transaction.atomic
41 def api_get_threaddiff(request):
41 def api_get_threaddiff(request):
42 """
42 """
43 Gets posts that were changed or added since time
43 Gets posts that were changed or added since time
44 """
44 """
45
45
46 thread_id = request.POST.get(PARAMETER_THREAD)
46 thread_id = request.POST.get(PARAMETER_THREAD)
47 uids_str = request.POST.get(PARAMETER_UIDS)
47 uids_str = request.POST.get(PARAMETER_UIDS)
48
48
49 if not thread_id or not uids_str:
49 if not thread_id or not uids_str:
50 return HttpResponse(content='Invalid request.')
50 return HttpResponse(content='Invalid request.')
51
51
52 uids = uids_str.strip().split(' ')
52 uids = uids_str.strip().split(' ')
53
53
54 opening_post = get_object_or_404(Post, id=thread_id)
54 opening_post = get_object_or_404(Post, id=thread_id)
55 thread = opening_post.get_thread()
55 thread = opening_post.get_thread()
56
56
57 json_data = {
57 json_data = {
58 PARAMETER_UPDATED: [],
58 PARAMETER_UPDATED: [],
59 PARAMETER_LAST_UPDATE: None, # TODO Maybe this can be removed already?
59 PARAMETER_LAST_UPDATE: None, # TODO Maybe this can be removed already?
60 }
60 }
61 posts = Post.objects.filter(threads__in=[thread]).exclude(uid__in=uids)
61 posts = Post.objects.filter(threads__in=[thread]).exclude(uid__in=uids)
62
62
63 diff_type = request.GET.get(PARAMETER_DIFF_TYPE, DIFF_TYPE_HTML)
63 diff_type = request.GET.get(PARAMETER_DIFF_TYPE, DIFF_TYPE_HTML)
64
64
65 for post in posts:
65 for post in posts:
66 json_data[PARAMETER_UPDATED].append(post.get_post_data(
66 json_data[PARAMETER_UPDATED].append(post.get_post_data(
67 format_type=diff_type, request=request))
67 format_type=diff_type, request=request))
68 json_data[PARAMETER_LAST_UPDATE] = str(thread.last_edit_time)
68 json_data[PARAMETER_LAST_UPDATE] = str(thread.last_edit_time)
69
69
70 # If the tag is favorite, update the counter
70 # If the tag is favorite, update the counter
71 settings_manager = get_settings_manager(request)
71 settings_manager = get_settings_manager(request)
72 favorite = settings_manager.thread_is_fav(opening_post)
72 favorite = settings_manager.thread_is_fav(opening_post)
73 if favorite:
73 if favorite:
74 settings_manager.add_or_read_fav_thread(opening_post)
74 settings_manager.add_or_read_fav_thread(opening_post)
75
75
76 return HttpResponse(content=json.dumps(json_data))
76 return HttpResponse(content=json.dumps(json_data))
77
77
78
78
79 @csrf_protect
79 @csrf_protect
80 def api_add_post(request, opening_post_id):
80 def api_add_post(request, opening_post_id):
81 """
81 """
82 Adds a post and return the JSON response for it
82 Adds a post and return the JSON response for it
83 """
83 """
84
84
85 opening_post = get_object_or_404(Post, id=opening_post_id)
85 opening_post = get_object_or_404(Post, id=opening_post_id)
86
86
87 logger.info('Adding post via api...')
87 logger.info('Adding post via api...')
88
88
89 status = STATUS_OK
89 status = STATUS_OK
90 errors = []
90 errors = []
91
91
92 if request.method == 'POST':
92 if request.method == 'POST':
93 form = PostForm(request.POST, request.FILES, error_class=PlainErrorList)
93 form = PostForm(request.POST, request.FILES, error_class=PlainErrorList)
94 form.session = request.session
94 form.session = request.session
95
95
96 if form.need_to_ban:
96 if form.need_to_ban:
97 # Ban user because he is suspected to be a bot
97 # Ban user because he is suspected to be a bot
98 # _ban_current_user(request)
98 # _ban_current_user(request)
99 status = STATUS_ERROR
99 status = STATUS_ERROR
100 if form.is_valid():
100 if form.is_valid():
101 post = ThreadView().new_post(request, form, opening_post,
101 post = ThreadView().new_post(request, form, opening_post,
102 html_response=False)
102 html_response=False)
103 if not post:
103 if not post:
104 status = STATUS_ERROR
104 status = STATUS_ERROR
105 else:
105 else:
106 logger.info('Added post #%d via api.' % post.id)
106 logger.info('Added post #%d via api.' % post.id)
107 else:
107 else:
108 status = STATUS_ERROR
108 status = STATUS_ERROR
109 errors = form.as_json_errors()
109 errors = form.as_json_errors()
110
110
111 response = {
111 response = {
112 'status': status,
112 'status': status,
113 'errors': errors,
113 'errors': errors,
114 }
114 }
115
115
116 return HttpResponse(content=json.dumps(response))
116 return HttpResponse(content=json.dumps(response))
117
117
118
118
119 def get_post(request, post_id):
119 def get_post(request, post_id):
120 """
120 """
121 Gets the html of a post. Used for popups. Post can be truncated if used
121 Gets the html of a post. Used for popups. Post can be truncated if used
122 in threads list with 'truncated' get parameter.
122 in threads list with 'truncated' get parameter.
123 """
123 """
124
124
125 post = get_object_or_404(Post, id=post_id)
125 post = get_object_or_404(Post, id=post_id)
126 truncated = PARAMETER_TRUNCATED in request.GET
126 truncated = PARAMETER_TRUNCATED in request.GET
127
127
128 return HttpResponse(content=post.get_view(truncated=truncated, need_op_data=True))
128 return HttpResponse(content=post.get_view(truncated=truncated, need_op_data=True))
129
129
130
130
131 def api_get_threads(request, count):
131 def api_get_threads(request, count):
132 """
132 """
133 Gets the JSON thread opening posts list.
133 Gets the JSON thread opening posts list.
134 Parameters that can be used for filtering:
134 Parameters that can be used for filtering:
135 tag, offset (from which thread to get results)
135 tag, offset (from which thread to get results)
136 """
136 """
137
137
138 if PARAMETER_TAG in request.GET:
138 if PARAMETER_TAG in request.GET:
139 tag_name = request.GET[PARAMETER_TAG]
139 tag_name = request.GET[PARAMETER_TAG]
140 if tag_name is not None:
140 if tag_name is not None:
141 tag = get_object_or_404(Tag, name=tag_name)
141 tag = get_object_or_404(Tag, name=tag_name)
142 threads = tag.get_threads().exclude(status=STATUS_ARCHIVE)
142 threads = tag.get_threads().exclude(status=STATUS_ARCHIVE)
143 else:
143 else:
144 threads = Thread.objects.exclude(status=STATUS_ARCHIVE)
144 threads = Thread.objects.exclude(status=STATUS_ARCHIVE)
145
145
146 if PARAMETER_OFFSET in request.GET:
146 if PARAMETER_OFFSET in request.GET:
147 offset = request.GET[PARAMETER_OFFSET]
147 offset = request.GET[PARAMETER_OFFSET]
148 offset = int(offset) if offset is not None else 0
148 offset = int(offset) if offset is not None else 0
149 else:
149 else:
150 offset = 0
150 offset = 0
151
151
152 threads = threads.order_by('-bump_time')
152 threads = threads.order_by('-bump_time')
153 threads = threads[offset:offset + int(count)]
153 threads = threads[offset:offset + int(count)]
154
154
155 opening_posts = []
155 opening_posts = []
156 for thread in threads:
156 for thread in threads:
157 opening_post = thread.get_opening_post()
157 opening_post = thread.get_opening_post()
158
158
159 # TODO Add tags, replies and images count
159 # TODO Add tags, replies and images count
160 post_data = opening_post.get_post_data(include_last_update=True)
160 post_data = opening_post.get_post_data(include_last_update=True)
161 post_data['status'] = thread.get_status()
161 post_data['status'] = thread.get_status()
162
162
163 opening_posts.append(post_data)
163 opening_posts.append(post_data)
164
164
165 return HttpResponse(content=json.dumps(opening_posts))
165 return HttpResponse(content=json.dumps(opening_posts))
166
166
167
167
168 # TODO Test this
168 # TODO Test this
169 def api_get_tags(request):
169 def api_get_tags(request):
170 """
170 """
171 Gets all tags or user tags.
171 Gets all tags or user tags.
172 """
172 """
173
173
174 # TODO Get favorite tags for the given user ID
174 # TODO Get favorite tags for the given user ID
175
175
176 tags = Tag.objects.get_not_empty_tags()
176 tags = Tag.objects.get_not_empty_tags()
177
177
178 term = request.GET.get('term')
178 term = request.GET.get('term')
179 if term is not None:
179 if term is not None:
180 tags = tags.filter(name__contains=term)
180 tags = tags.filter(name__contains=term)
181
181
182 tag_names = [tag.name for tag in tags]
182 tag_names = [tag.name for tag in tags]
183
183
184 return HttpResponse(content=json.dumps(tag_names))
184 return HttpResponse(content=json.dumps(tag_names))
185
185
186
186
187 # TODO The result can be cached by the thread last update time
187 # TODO The result can be cached by the thread last update time
188 # TODO Test this
188 # TODO Test this
189 def api_get_thread_posts(request, opening_post_id):
189 def api_get_thread_posts(request, opening_post_id):
190 """
190 """
191 Gets the JSON array of thread posts
191 Gets the JSON array of thread posts
192 """
192 """
193
193
194 opening_post = get_object_or_404(Post, id=opening_post_id)
194 opening_post = get_object_or_404(Post, id=opening_post_id)
195 thread = opening_post.get_thread()
195 thread = opening_post.get_thread()
196 posts = thread.get_replies()
196 posts = thread.get_replies()
197
197
198 json_data = {
198 json_data = {
199 'posts': [],
199 'posts': [],
200 'last_update': None,
200 'last_update': None,
201 }
201 }
202 json_post_list = []
202 json_post_list = []
203
203
204 for post in posts:
204 for post in posts:
205 json_post_list.append(post.get_post_data())
205 json_post_list.append(post.get_post_data())
206 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
206 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
207 json_data['posts'] = json_post_list
207 json_data['posts'] = json_post_list
208
208
209 return HttpResponse(content=json.dumps(json_data))
209 return HttpResponse(content=json.dumps(json_data))
210
210
211
211
212 def api_get_notifications(request, username):
212 def api_get_notifications(request, username):
213 last_notification_id_str = request.GET.get('last', None)
213 last_notification_id_str = request.GET.get('last', None)
214 last_id = int(last_notification_id_str) if last_notification_id_str is not None else None
214 last_id = int(last_notification_id_str) if last_notification_id_str is not None else None
215
215
216 posts = Notification.objects.get_notification_posts(usernames=username,
216 posts = Notification.objects.get_notification_posts(usernames=[username],
217 last=last_id)
217 last=last_id)
218
218
219 json_post_list = []
219 json_post_list = []
220 for post in posts:
220 for post in posts:
221 json_post_list.append(post.get_post_data())
221 json_post_list.append(post.get_post_data())
222 return HttpResponse(content=json.dumps(json_post_list))
222 return HttpResponse(content=json.dumps(json_post_list))
223
223
224
224
225 def api_get_post(request, post_id):
225 def api_get_post(request, post_id):
226 """
226 """
227 Gets the JSON of a post. This can be
227 Gets the JSON of a post. This can be
228 used as and API for external clients.
228 used as and API for external clients.
229 """
229 """
230
230
231 post = get_object_or_404(Post, id=post_id)
231 post = get_object_or_404(Post, id=post_id)
232
232
233 json = serializers.serialize("json", [post], fields=(
233 json = serializers.serialize("json", [post], fields=(
234 "pub_time", "_text_rendered", "title", "text", "image",
234 "pub_time", "_text_rendered", "title", "text", "image",
235 "image_width", "image_height", "replies", "tags"
235 "image_width", "image_height", "replies", "tags"
236 ))
236 ))
237
237
238 return HttpResponse(content=json)
238 return HttpResponse(content=json)
239
239
240
240
241 def api_get_preview(request):
241 def api_get_preview(request):
242 raw_text = request.POST['raw_text']
242 raw_text = request.POST['raw_text']
243
243
244 parser = Parser()
244 parser = Parser()
245 return HttpResponse(content=parser.parse(parser.preparse(raw_text)))
245 return HttpResponse(content=parser.parse(parser.preparse(raw_text)))
246
246
247
247
248 def api_get_new_posts(request):
248 def api_get_new_posts(request):
249 """
249 """
250 Gets favorite threads and unread posts count.
250 Gets favorite threads and unread posts count.
251 """
251 """
252 posts = list()
252 posts = list()
253
253
254 include_posts = 'include_posts' in request.GET
254 include_posts = 'include_posts' in request.GET
255
255
256 settings_manager = get_settings_manager(request)
256 settings_manager = get_settings_manager(request)
257 fav_threads = settings_manager.get_fav_threads()
257 fav_threads = settings_manager.get_fav_threads()
258 fav_thread_ops = Post.objects.filter(id__in=fav_threads.keys())\
258 fav_thread_ops = Post.objects.filter(id__in=fav_threads.keys())\
259 .order_by('-pub_time').prefetch_related('thread')
259 .order_by('-pub_time').prefetch_related('thread')
260
260
261 ops = [{'op': op, 'last_id': fav_threads[str(op.id)]} for op in fav_thread_ops]
261 ops = [{'op': op, 'last_id': fav_threads[str(op.id)]} for op in fav_thread_ops]
262 if include_posts:
262 if include_posts:
263 new_post_threads = Thread.objects.get_new_posts(ops)
263 new_post_threads = Thread.objects.get_new_posts(ops)
264 if new_post_threads:
264 if new_post_threads:
265 thread_ids = {thread.id: thread for thread in new_post_threads}
265 thread_ids = {thread.id: thread for thread in new_post_threads}
266 else:
266 else:
267 thread_ids = dict()
267 thread_ids = dict()
268
268
269 for op in fav_thread_ops:
269 for op in fav_thread_ops:
270 fav_thread_dict = dict()
270 fav_thread_dict = dict()
271
271
272 op_thread = op.get_thread()
272 op_thread = op.get_thread()
273 if op_thread.id in thread_ids:
273 if op_thread.id in thread_ids:
274 thread = thread_ids[op_thread.id]
274 thread = thread_ids[op_thread.id]
275 new_post_count = thread.new_post_count
275 new_post_count = thread.new_post_count
276 fav_thread_dict['newest_post_link'] = thread.get_replies()\
276 fav_thread_dict['newest_post_link'] = thread.get_replies()\
277 .filter(id__gt=fav_threads[str(op.id)])\
277 .filter(id__gt=fav_threads[str(op.id)])\
278 .first().get_absolute_url(thread=thread)
278 .first().get_absolute_url(thread=thread)
279 else:
279 else:
280 new_post_count = 0
280 new_post_count = 0
281 fav_thread_dict['new_post_count'] = new_post_count
281 fav_thread_dict['new_post_count'] = new_post_count
282
282
283 fav_thread_dict['id'] = op.id
283 fav_thread_dict['id'] = op.id
284
284
285 fav_thread_dict['post_url'] = op.get_link_view()
285 fav_thread_dict['post_url'] = op.get_link_view()
286 fav_thread_dict['title'] = op.title
286 fav_thread_dict['title'] = op.title
287
287
288 posts.append(fav_thread_dict)
288 posts.append(fav_thread_dict)
289 else:
289 else:
290 fav_thread_dict = dict()
290 fav_thread_dict = dict()
291 fav_thread_dict['new_post_count'] = \
291 fav_thread_dict['new_post_count'] = \
292 Thread.objects.get_new_post_count(ops)
292 Thread.objects.get_new_post_count(ops)
293 posts.append(fav_thread_dict)
293 posts.append(fav_thread_dict)
294
294
295 return HttpResponse(content=json.dumps(posts))
295 return HttpResponse(content=json.dumps(posts))
General Comments 0
You need to be logged in to leave comments. Login now