##// END OF EJS Templates
Added api for getting thread posts
neko259 -
r502:8f6c65f4 1.6-dev
parent child Browse files
Show More
@@ -1,67 +1,69
1 from django.conf.urls import patterns, url, include
1 from django.conf.urls import patterns, url, include
2 from boards import views
2 from boards import views
3 from boards.rss import AllThreadsFeed, TagThreadsFeed, ThreadPostsFeed
3 from boards.rss import AllThreadsFeed, TagThreadsFeed, ThreadPostsFeed
4 from boards.views import api
4 from boards.views import api
5
5
6 js_info_dict = {
6 js_info_dict = {
7 'packages': ('boards',),
7 'packages': ('boards',),
8 }
8 }
9
9
10 urlpatterns = patterns('',
10 urlpatterns = patterns('',
11
11
12 # /boards/
12 # /boards/
13 url(r'^$', views.index, name='index'),
13 url(r'^$', views.index, name='index'),
14 # /boards/page/
14 # /boards/page/
15 url(r'^page/(?P<page>\w+)/$', views.index, name='index'),
15 url(r'^page/(?P<page>\w+)/$', views.index, name='index'),
16
16
17 url(r'^archive/$', views.archive, name='archive'),
17 url(r'^archive/$', views.archive, name='archive'),
18 url(r'^archive/page/(?P<page>\w+)/$', views.archive, name='archive'),
18 url(r'^archive/page/(?P<page>\w+)/$', views.archive, name='archive'),
19
19
20 # login page
20 # login page
21 url(r'^login/$', views.login, name='login'),
21 url(r'^login/$', views.login, name='login'),
22
22
23 # /boards/tag/tag_name/
23 # /boards/tag/tag_name/
24 url(r'^tag/(?P<tag_name>\w+)/$', views.tag, name='tag'),
24 url(r'^tag/(?P<tag_name>\w+)/$', views.tag, name='tag'),
25 # /boards/tag/tag_id/page/
25 # /boards/tag/tag_id/page/
26 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/$', views.tag, name='tag'),
26 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/$', views.tag, name='tag'),
27
27
28 # /boards/tag/tag_name/unsubscribe/
28 # /boards/tag/tag_name/unsubscribe/
29 url(r'^tag/(?P<tag_name>\w+)/subscribe/$', views.tag_subscribe,
29 url(r'^tag/(?P<tag_name>\w+)/subscribe/$', views.tag_subscribe,
30 name='tag_subscribe'),
30 name='tag_subscribe'),
31 # /boards/tag/tag_name/unsubscribe/
31 # /boards/tag/tag_name/unsubscribe/
32 url(r'^tag/(?P<tag_name>\w+)/unsubscribe/$', views.tag_unsubscribe,
32 url(r'^tag/(?P<tag_name>\w+)/unsubscribe/$', views.tag_unsubscribe,
33 name='tag_unsubscribe'),
33 name='tag_unsubscribe'),
34
34
35 # /boards/thread/
35 # /boards/thread/
36 url(r'^thread/(?P<post_id>\w+)/$', views.thread, name='thread'),
36 url(r'^thread/(?P<post_id>\w+)/$', views.thread, name='thread'),
37 url(r'^thread/(?P<post_id>\w+)/(?P<mode>\w+)/$', views.thread, name='thread_mode'),
37 url(r'^thread/(?P<post_id>\w+)/(?P<mode>\w+)/$', views.thread, name='thread_mode'),
38 url(r'^settings/$', views.settings, name='settings'),
38 url(r'^settings/$', views.settings, name='settings'),
39 url(r'^tags/$', views.all_tags, name='tags'),
39 url(r'^tags/$', views.all_tags, name='tags'),
40 url(r'^captcha/', include('captcha.urls')),
40 url(r'^captcha/', include('captcha.urls')),
41 url(r'^jump/(?P<post_id>\w+)/$', views.jump_to_post, name='jumper'),
41 url(r'^jump/(?P<post_id>\w+)/$', views.jump_to_post, name='jumper'),
42 url(r'^authors/$', views.authors, name='authors'),
42 url(r'^authors/$', views.authors, name='authors'),
43 url(r'^delete/(?P<post_id>\w+)/$', views.delete, name='delete'),
43 url(r'^delete/(?P<post_id>\w+)/$', views.delete, name='delete'),
44 url(r'^ban/(?P<post_id>\w+)/$', views.ban, name='ban'),
44 url(r'^ban/(?P<post_id>\w+)/$', views.ban, name='ban'),
45
45
46 url(r'^banned/$', views.you_are_banned, name='banned'),
46 url(r'^banned/$', views.you_are_banned, name='banned'),
47 url(r'^staticpage/(?P<name>\w+)/$', views.static_page, name='staticpage'),
47 url(r'^staticpage/(?P<name>\w+)/$', views.static_page, name='staticpage'),
48
48
49 # RSS feeds
49 # RSS feeds
50 url(r'^rss/$', AllThreadsFeed()),
50 url(r'^rss/$', AllThreadsFeed()),
51 url(r'^page/(?P<page>\w+)/rss/$', AllThreadsFeed()),
51 url(r'^page/(?P<page>\w+)/rss/$', AllThreadsFeed()),
52 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
52 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
53 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
53 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
54 url(r'^thread/(?P<post_id>\w+)/rss/$', ThreadPostsFeed()),
54 url(r'^thread/(?P<post_id>\w+)/rss/$', ThreadPostsFeed()),
55
55
56 # i18n
56 # i18n
57 url(r'^jsi18n/$', 'boards.views.cached_js_catalog', js_info_dict, name='js_info_dict'),
57 url(r'^jsi18n/$', 'boards.views.cached_js_catalog', js_info_dict, name='js_info_dict'),
58
58
59 # API
59 # API
60 url(r'^api/post/(?P<post_id>\w+)/$', api.get_post, name="get_post"),
60 url(r'^api/post/(?P<post_id>\w+)/$', api.get_post, name="get_post"),
61 url(r'^api/diff_thread/(?P<thread_id>\w+)/(?P<last_update_time>\w+)/$',
61 url(r'^api/diff_thread/(?P<thread_id>\w+)/(?P<last_update_time>\w+)/$',
62 api.api_get_threaddiff, name="get_thread_diff"),
62 api.api_get_threaddiff, name="get_thread_diff"),
63 url(r'^api/threads/(?P<count>\w+)/$', api.api_get_threads,
63 url(r'^api/threads/(?P<count>\w+)/$', api.api_get_threads,
64 name='get_threads'),
64 name='get_threads'),
65 url(r'api/tags/$', api.api_get_tags, name='get_tags'),
65 url(r'api/tags/$', api.api_get_tags, name='get_tags'),
66 url(r'api/thread/(?P<opening_post_id>\w+)/$', api.api_get_thread_posts,
67 name='get_thread'),
66
68
67 )
69 )
@@ -1,157 +1,189
1 from datetime import datetime
1 from datetime import datetime
2 import json
2 import json
3 from django.db import transaction
3 from django.db import transaction
4 from django.http import HttpResponse
4 from django.http import HttpResponse
5 from django.shortcuts import get_object_or_404, render
5 from django.shortcuts import get_object_or_404, render
6 from django.template import RequestContext
6 from django.template import RequestContext
7 from django.utils import timezone
7 from django.utils import timezone
8 from boards.forms import ThreadForm, PlainErrorList
8 from boards.forms import ThreadForm, PlainErrorList
9 from boards.models import Post, Thread, Tag
9 from boards.models import Post, Thread, Tag
10 from boards.views import _datetime_to_epoch, _new_post, \
10 from boards.views import _datetime_to_epoch, _new_post, \
11 _ban_current_user
11 _ban_current_user
12
12
13 __author__ = 'neko259'
13 __author__ = 'neko259'
14
14
15 PARAMETER_TRUNCATED = 'truncated'
15 PARAMETER_TRUNCATED = 'truncated'
16 PARAMETER_TAG = 'tag'
16 PARAMETER_TAG = 'tag'
17 PARAMETER_OFFSET = 'offset'
17 PARAMETER_OFFSET = 'offset'
18
18
19
19
20 @transaction.atomic
20 @transaction.atomic
21 def api_get_threaddiff(request, thread_id, last_update_time):
21 def api_get_threaddiff(request, thread_id, last_update_time):
22 """Get posts that were changed or added since time"""
22 """Get posts that were changed or added since time"""
23
23
24 thread = get_object_or_404(Post, id=thread_id).thread_new
24 thread = get_object_or_404(Post, id=thread_id).thread_new
25
25
26 filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000,
26 filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000,
27 timezone.get_current_timezone())
27 timezone.get_current_timezone())
28
28
29 json_data = {
29 json_data = {
30 'added': [],
30 'added': [],
31 'updated': [],
31 'updated': [],
32 'last_update': None,
32 'last_update': None,
33 }
33 }
34 added_posts = Post.objects.filter(thread_new=thread,
34 added_posts = Post.objects.filter(thread_new=thread,
35 pub_time__gt=filter_time) \
35 pub_time__gt=filter_time) \
36 .order_by('pub_time')
36 .order_by('pub_time')
37 updated_posts = Post.objects.filter(thread_new=thread,
37 updated_posts = Post.objects.filter(thread_new=thread,
38 pub_time__lte=filter_time,
38 pub_time__lte=filter_time,
39 last_edit_time__gt=filter_time)
39 last_edit_time__gt=filter_time)
40 for post in added_posts:
40 for post in added_posts:
41 json_data['added'].append(get_post(request, post.id).content.strip())
41 json_data['added'].append(get_post(request, post.id).content.strip())
42 for post in updated_posts:
42 for post in updated_posts:
43 json_data['updated'].append(get_post(request, post.id).content.strip())
43 json_data['updated'].append(get_post(request, post.id).content.strip())
44 json_data['last_update'] = _datetime_to_epoch(thread.last_edit_time)
44 json_data['last_update'] = _datetime_to_epoch(thread.last_edit_time)
45
45
46 return HttpResponse(content=json.dumps(json_data))
46 return HttpResponse(content=json.dumps(json_data))
47
47
48
48
49 # TODO This method needs to be implemented properly
49 # TODO This method needs to be implemented properly
50 # def api_add_post(request, form):
50 # def api_add_post(request, form):
51 # """
51 # """
52 # Add a post and return the JSON response for it
52 # Add a post and return the JSON response for it
53 # """
53 # """
54 #
54 #
55 # status = 'ok'
55 # status = 'ok'
56 # errors = []
56 # errors = []
57 #
57 #
58 # if request.method == 'POST':
58 # if request.method == 'POST':
59 # form = ThreadForm(request.POST, request.FILES,
59 # form = ThreadForm(request.POST, request.FILES,
60 # error_class=PlainErrorList)
60 # error_class=PlainErrorList)
61 # form.session = request.session
61 # form.session = request.session
62 #
62 #
63 # if form.is_valid():
63 # if form.is_valid():
64 # # TODO Don't form a response here cause we'll not need it
64 # # TODO Don't form a response here cause we'll not need it
65 # _new_post(request, form)
65 # _new_post(request, form)
66 # if form.need_to_ban:
66 # if form.need_to_ban:
67 # # Ban user because he is suspected to be a bot
67 # # Ban user because he is suspected to be a bot
68 # _ban_current_user(request)
68 # _ban_current_user(request)
69 # else:
69 # else:
70 # status = 'error'
70 # status = 'error'
71 # for field in form.fields:
71 # for field in form.fields:
72 # if field.errors:
72 # if field.errors:
73 # errors.append(field.errors)
73 # errors.append(field.errors)
74 #
74 #
75 # response = {
75 # response = {
76 # 'status': status,
76 # 'status': status,
77 # 'errors': errors,
77 # 'errors': errors,
78 # }
78 # }
79 #
79 #
80 # return HttpResponse(content=json.dumps(response))
80 # return HttpResponse(content=json.dumps(response))
81
81
82
82
83 def get_post(request, post_id):
83 def get_post(request, post_id):
84 """
84 """
85 Get the html of a post. Used for popups. Post can be truncated if used
85 Get the html of a post. Used for popups. Post can be truncated if used
86 in threads list with 'truncated' get parameter.
86 in threads list with 'truncated' get parameter.
87 """
87 """
88
88
89 post = get_object_or_404(Post, id=post_id)
89 post = get_object_or_404(Post, id=post_id)
90 thread = post.thread_new
90 thread = post.thread_new
91
91
92 context = RequestContext(request)
92 context = RequestContext(request)
93 context['post'] = post
93 context['post'] = post
94 context['can_bump'] = thread.can_bump()
94 context['can_bump'] = thread.can_bump()
95 if PARAMETER_TRUNCATED in request.GET:
95 if PARAMETER_TRUNCATED in request.GET:
96 context[PARAMETER_TRUNCATED] = True
96 context[PARAMETER_TRUNCATED] = True
97
97
98 return render(request, 'boards/post.html', context)
98 return render(request, 'boards/post.html', context)
99
99
100
100
101 # TODO Test this
101 def api_get_threads(request, count):
102 def api_get_threads(request, count):
102 """
103 """
103 Get the JSON thread opening posts list.
104 Get the JSON thread opening posts list.
104 Parameters that can be used for filtering:
105 Parameters that can be used for filtering:
105 tag, offset (from which thread to get results)
106 tag, offset (from which thread to get results)
106 """
107 """
107
108
108 if PARAMETER_TAG in request.GET:
109 if PARAMETER_TAG in request.GET:
109 tag_name = request.GET[PARAMETER_TAG]
110 tag_name = request.GET[PARAMETER_TAG]
110 if tag_name is not None:
111 if tag_name is not None:
111 tag = get_object_or_404(Tag, name=tag_name)
112 tag = get_object_or_404(Tag, name=tag_name)
112 threads = tag.threads.filter(archived=False)
113 threads = tag.threads.filter(archived=False)
113 else:
114 else:
114 threads = Thread.objects.filter(archived=False)
115 threads = Thread.objects.filter(archived=False)
115
116
116 if PARAMETER_OFFSET in request.GET:
117 if PARAMETER_OFFSET in request.GET:
117 offset = request.GET[PARAMETER_OFFSET]
118 offset = request.GET[PARAMETER_OFFSET]
118 offset = int(offset) if offset is not None else 0
119 offset = int(offset) if offset is not None else 0
119 else:
120 else:
120 offset = 0
121 offset = 0
121
122
122 threads = threads.order_by('-bump_time')
123 threads = threads.order_by('-bump_time')
123 threads = threads[offset:offset + int(count)]
124 threads = threads[offset:offset + int(count)]
124
125
125 opening_posts = []
126 opening_posts = []
126 for thread in threads:
127 for thread in threads:
127 opening_post = thread.get_opening_post()
128 opening_post = thread.get_opening_post()
128
129
129 # TODO Add pub time, tags, replies and images count
130 # TODO Add pub time, tags, replies and images count
130 post_json = {
131 post_json = {
131 'id' : opening_post.id,
132 'id' : opening_post.id,
132 'title' : opening_post.title,
133 'title' : opening_post.title,
133 'text' : opening_post.text.rendered,
134 'text' : opening_post.text.rendered,
134 }
135 }
135 if opening_post.image:
136 if opening_post.image:
136 post_json += {
137 post_json += {
137 'image' : opening_post.image.url,
138 'image' : opening_post.image.url,
138 'image_preview' : opening_post.image.url_200x150,
139 'image_preview' : opening_post.image.url_200x150,
139 }
140 }
140 opening_posts.append(post_json)
141 opening_posts.append(post_json)
141
142
142 return HttpResponse(content=json.dumps(opening_posts))
143 return HttpResponse(content=json.dumps(opening_posts))
143
144
144
145
146 # TODO Test this
145 def api_get_tags(request):
147 def api_get_tags(request):
146 """
148 """
147 Get all tags or user tags.
149 Get all tags or user tags.
148 """
150 """
149
151
150 # TODO Get favorite tags for the given user ID
152 # TODO Get favorite tags for the given user ID
151
153
152 tags = Tag.objects.get_not_empty_tags()
154 tags = Tag.objects.get_not_empty_tags()
153 tag_names = []
155 tag_names = []
154 for tag in tags:
156 for tag in tags:
155 tag_names.append(tag.name)
157 tag_names.append(tag.name)
156
158
157 return HttpResponse(content=json.dumps(tag_names))
159 return HttpResponse(content=json.dumps(tag_names))
160
161
162 # TODO The result can be cached by the thread last update time
163 # TODO Test this
164 def api_get_thread_posts(request, opening_post_id):
165 """
166 Get the JSON array of thread posts
167 """
168
169 opening_post = get_object_or_404(Post, id=opening_post_id)
170 thread = opening_post.thread_new
171 posts = thread.get_replies()
172
173 json_post_list = []
174
175 for post in posts:
176 # TODO Add pub time and replies
177 post_json = {
178 'id' : post.id,
179 'title' : post.title,
180 'text' : post.text.rendered,
181 }
182 if post.image:
183 post_json += {
184 'image' : post.image.url,
185 'image_preview' : post.image.url_200x150,
186 }
187 json_post_list.append(post_json)
188
189 return HttpResponse(content=json.dumps(json_post_list))
General Comments 0
You need to be logged in to leave comments. Login now