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