##// END OF EJS Templates
Removed tag popularity ratings, they are too slow. Added API to get tag...
neko259 -
r651:582b2d85 default
parent child Browse files
Show More
@@ -1,192 +1,192 b''
1 from django.core.urlresolvers import reverse
2 import markdown
1 import markdown
3 from markdown.inlinepatterns import Pattern
2 from markdown.inlinepatterns import Pattern, SubstituteTagPattern
4 from markdown.util import etree
3 from markdown.util import etree
5 import boards
4 import boards
6
5
7 __author__ = 'neko259'
6 __author__ = 'neko259'
8
7
9
8
10 AUTOLINK_PATTERN = r'(https?://\S+)'
9 AUTOLINK_PATTERN = r'(https?://\S+)'
11 QUOTE_PATTERN = r'^(?<!>)(>[^>].*)$'
10 QUOTE_PATTERN = r'^(?<!>)(>[^>].*)$'
12 REFLINK_PATTERN = r'((>>)(\d+))'
11 REFLINK_PATTERN = r'((>>)(\d+))'
13 SPOILER_PATTERN = r'%%([^(%%)]+)%%'
12 SPOILER_PATTERN = r'%%([^(%%)]+)%%'
14 COMMENT_PATTERN = r'^(//(.+))'
13 COMMENT_PATTERN = r'^(//(.+))'
15 STRIKETHROUGH_PATTERN = r'~(.+)~'
14 STRIKETHROUGH_PATTERN = r'~(.+)~'
16
15
17
16
18 class TextFormatter():
17 class TextFormatter():
19 """
18 """
20 An interface for formatter that can be used in the text format panel
19 An interface for formatter that can be used in the text format panel
21 """
20 """
22
21
23 name = ''
22 name = ''
24
23
25 # Left and right tags for the button preview
24 # Left and right tags for the button preview
26 preview_left = ''
25 preview_left = ''
27 preview_right = ''
26 preview_right = ''
28
27
29 # Left and right characters for the textarea input
28 # Left and right characters for the textarea input
30 format_left = ''
29 format_left = ''
31 format_right = ''
30 format_right = ''
32
31
33
32
34 class AutolinkPattern(Pattern):
33 class AutolinkPattern(Pattern):
35 def handleMatch(self, m):
34 def handleMatch(self, m):
36 link_element = etree.Element('a')
35 link_element = etree.Element('a')
37 href = m.group(2)
36 href = m.group(2)
38 link_element.set('href', href)
37 link_element.set('href', href)
39 link_element.text = href
38 link_element.text = href
40
39
41 return link_element
40 return link_element
42
41
43
42
44 class QuotePattern(Pattern, TextFormatter):
43 class QuotePattern(Pattern, TextFormatter):
45 name = ''
44 name = ''
46 preview_left = '<span class="quote">&gt; '
45 preview_left = '<span class="quote">&gt; '
47 preview_right = '</span>'
46 preview_right = '</span>'
48
47
49 format_left = '&gt;'
48 format_left = '&gt;'
50
49
51 def handleMatch(self, m):
50 def handleMatch(self, m):
52 quote_element = etree.Element('span')
51 quote_element = etree.Element('span')
53 quote_element.set('class', 'quote')
52 quote_element.set('class', 'quote')
54 quote_element.text = m.group(2)
53 quote_element.text = m.group(2)
55
54
56 return quote_element
55 return quote_element
57
56
58
57
59 class ReflinkPattern(Pattern):
58 class ReflinkPattern(Pattern):
60 def handleMatch(self, m):
59 def handleMatch(self, m):
61 post_id = m.group(4)
60 post_id = m.group(4)
62
61
63 posts = boards.models.Post.objects.filter(id=post_id)
62 posts = boards.models.Post.objects.filter(id=post_id)
64 if posts.count() > 0:
63 if posts.count() > 0:
65 ref_element = etree.Element('a')
64 ref_element = etree.Element('a')
66
65
67 post = posts[0]
66 post = posts[0]
68
67
69 ref_element.set('href', post.get_url())
68 ref_element.set('href', post.get_url())
70 ref_element.text = m.group(2)
69 ref_element.text = m.group(2)
71
70
72 return ref_element
71 return ref_element
73
72
74
73
75 class SpoilerPattern(Pattern, TextFormatter):
74 class SpoilerPattern(Pattern, TextFormatter):
76 name = 's'
75 name = 's'
77 preview_left = '<span class="spoiler">'
76 preview_left = '<span class="spoiler">'
78 preview_right = '</span>'
77 preview_right = '</span>'
79
78
80 format_left = '%%'
79 format_left = '%%'
81 format_right = '%%'
80 format_right = '%%'
82
81
83 def handleMatch(self, m):
82 def handleMatch(self, m):
84 quote_element = etree.Element('span')
83 quote_element = etree.Element('span')
85 quote_element.set('class', 'spoiler')
84 quote_element.set('class', 'spoiler')
86 quote_element.text = m.group(2)
85 quote_element.text = m.group(2)
87
86
88 return quote_element
87 return quote_element
89
88
90
89
91 class CommentPattern(Pattern, TextFormatter):
90 class CommentPattern(Pattern, TextFormatter):
92 name = ''
91 name = ''
93 preview_left = '<span class="comment">// '
92 preview_left = '<span class="comment">// '
94 preview_right = '</span>'
93 preview_right = '</span>'
95
94
96 format_left = '//'
95 format_left = '//'
97
96
98 def handleMatch(self, m):
97 def handleMatch(self, m):
99 quote_element = etree.Element('span')
98 quote_element = etree.Element('span')
100 quote_element.set('class', 'comment')
99 quote_element.set('class', 'comment')
101 quote_element.text = '//' + m.group(3)
100 quote_element.text = '//' + m.group(3)
102
101
103 return quote_element
102 return quote_element
104
103
105
104
106 class StrikeThroughPattern(Pattern, TextFormatter):
105 class StrikeThroughPattern(Pattern, TextFormatter):
107 name = 's'
106 name = 's'
108 preview_left = '<span class="strikethrough">'
107 preview_left = '<span class="strikethrough">'
109 preview_right = '</span>'
108 preview_right = '</span>'
110
109
111 format_left = '~'
110 format_left = '~'
112 format_right = '~'
111 format_right = '~'
113
112
114 def handleMatch(self, m):
113 def handleMatch(self, m):
115 quote_element = etree.Element('span')
114 quote_element = etree.Element('span')
116 quote_element.set('class', 'strikethrough')
115 quote_element.set('class', 'strikethrough')
117 quote_element.text = m.group(2)
116 quote_element.text = m.group(2)
118
117
119 return quote_element
118 return quote_element
120
119
121
120
122 class ItalicPattern(TextFormatter):
121 class ItalicPattern(TextFormatter):
123 name = 'i'
122 name = 'i'
124 preview_left = '<i>'
123 preview_left = '<i>'
125 preview_right = '</i>'
124 preview_right = '</i>'
126
125
127 format_left = '_'
126 format_left = '_'
128 format_right = '_'
127 format_right = '_'
129
128
130
129
131 class BoldPattern(TextFormatter):
130 class BoldPattern(TextFormatter):
132 name = 'b'
131 name = 'b'
133 preview_left = '<b>'
132 preview_left = '<b>'
134 preview_right = '</b>'
133 preview_right = '</b>'
135
134
136 format_left = '__'
135 format_left = '__'
137 format_right = '__'
136 format_right = '__'
138
137
139
138
140 class CodePattern(TextFormatter):
139 class CodePattern(TextFormatter):
141 name = 'code'
140 name = 'code'
142 preview_left = '<code>'
141 preview_left = '<code>'
143 preview_right = '</code>'
142 preview_right = '</code>'
144
143
145 format_left = ' '
144 format_left = ' '
146
145
147
146
148 class NeboardMarkdown(markdown.Extension):
147 class NeboardMarkdown(markdown.Extension):
149 def extendMarkdown(self, md, md_globals):
148 def extendMarkdown(self, md, md_globals):
150 self._add_neboard_patterns(md)
149 self._add_neboard_patterns(md)
151 self._delete_patterns(md)
150 self._delete_patterns(md)
152
151
153 def _delete_patterns(self, md):
152 def _delete_patterns(self, md):
154 del md.parser.blockprocessors['quote']
153 del md.parser.blockprocessors['quote']
155
154
156 del md.inlinePatterns['image_link']
155 del md.inlinePatterns['image_link']
157 del md.inlinePatterns['image_reference']
156 del md.inlinePatterns['image_reference']
158
157
159 def _add_neboard_patterns(self, md):
158 def _add_neboard_patterns(self, md):
160 autolink = AutolinkPattern(AUTOLINK_PATTERN, md)
159 autolink = AutolinkPattern(AUTOLINK_PATTERN, md)
161 quote = QuotePattern(QUOTE_PATTERN, md)
160 quote = QuotePattern(QUOTE_PATTERN, md)
162 reflink = ReflinkPattern(REFLINK_PATTERN, md)
161 reflink = ReflinkPattern(REFLINK_PATTERN, md)
163 spoiler = SpoilerPattern(SPOILER_PATTERN, md)
162 spoiler = SpoilerPattern(SPOILER_PATTERN, md)
164 comment = CommentPattern(COMMENT_PATTERN, md)
163 comment = CommentPattern(COMMENT_PATTERN, md)
165 strikethrough = StrikeThroughPattern(STRIKETHROUGH_PATTERN, md)
164 strikethrough = StrikeThroughPattern(STRIKETHROUGH_PATTERN, md)
166
165
167 md.inlinePatterns[u'autolink_ext'] = autolink
166 md.inlinePatterns[u'autolink_ext'] = autolink
168 md.inlinePatterns[u'spoiler'] = spoiler
167 md.inlinePatterns[u'spoiler'] = spoiler
169 md.inlinePatterns[u'strikethrough'] = strikethrough
168 md.inlinePatterns[u'strikethrough'] = strikethrough
170 md.inlinePatterns[u'comment'] = comment
169 md.inlinePatterns[u'comment'] = comment
171 md.inlinePatterns[u'reflink'] = reflink
170 md.inlinePatterns[u'reflink'] = reflink
172 md.inlinePatterns[u'quote'] = quote
171 md.inlinePatterns[u'quote'] = quote
173
172
174
173
175 def make_extension(configs=None):
174 def make_extension(configs=None):
176 return NeboardMarkdown(configs=configs)
175 return NeboardMarkdown(configs=configs)
177
176
178 neboard_extension = make_extension()
177 neboard_extension = make_extension()
179
178
180
179
181 def markdown_extended(markup):
180 def markdown_extended(markup):
182 return markdown.markdown(markup, [neboard_extension], safe_mode=True)
181 return markdown.markdown(markup, [neboard_extension, 'nl2br'],
182 safe_mode=True)
183
183
184 formatters = [
184 formatters = [
185 QuotePattern,
185 QuotePattern,
186 SpoilerPattern,
186 SpoilerPattern,
187 ItalicPattern,
187 ItalicPattern,
188 BoldPattern,
188 BoldPattern,
189 CommentPattern,
189 CommentPattern,
190 StrikeThroughPattern,
190 StrikeThroughPattern,
191 CodePattern,
191 CodePattern,
192 ]
192 ]
@@ -1,27 +1,27 b''
1 {% extends "boards/base.html" %}
1 {% extends "boards/base.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4 {% load cache %}
4 {% load cache %}
5
5
6 {% block head %}
6 {% block head %}
7 <title>Neboard - {% trans "Tags" %}</title>
7 <title>Neboard - {% trans "Tags" %}</title>
8 {% endblock %}
8 {% endblock %}
9
9
10 {% block content %}
10 {% block content %}
11
11
12 {% cache 600 all_tags_list %}
12 {% cache 600 all_tags_list %}
13 <div class="post">
13 <div class="post">
14 {% if all_tags %}
14 {% if all_tags %}
15 {% for tag in all_tags %}
15 {% for tag in all_tags %}
16 <div class="tag_item" style="opacity: {{ tag.get_font_value }}">
16 <div class="tag_item">
17 <a class="tag" href="{% url 'tag' tag.name %}">
17 <a class="tag" href="{% url 'tag' tag.name %}">
18 #{{ tag.name }}</a>
18 #{{ tag.name }}</a>
19 </div>
19 </div>
20 {% endfor %}
20 {% endfor %}
21 {% else %}
21 {% else %}
22 {% trans 'No tags found.' %}
22 {% trans 'No tags found.' %}
23 {% endif %}
23 {% endif %}
24 </div>
24 </div>
25 {% endcache %}
25 {% endcache %}
26
26
27 {% endblock %}
27 {% endblock %}
@@ -1,83 +1,85 b''
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, tag_threads, all_threads, archived_threads, \
4 from boards.views import api, tag_threads, all_threads, archived_threads, \
5 login, settings, all_tags
5 login, settings, all_tags
6 from boards.views.authors import AuthorsView
6 from boards.views.authors import AuthorsView
7 from boards.views.delete_post import DeletePostView
7 from boards.views.delete_post import DeletePostView
8 from boards.views.ban import BanUserView
8 from boards.views.ban import BanUserView
9 from boards.views.static import StaticPageView
9 from boards.views.static import StaticPageView
10 from boards.views.post_admin import PostAdminView
10 from boards.views.post_admin import PostAdminView
11
11
12 js_info_dict = {
12 js_info_dict = {
13 'packages': ('boards',),
13 'packages': ('boards',),
14 }
14 }
15
15
16 urlpatterns = patterns('',
16 urlpatterns = patterns('',
17
17
18 # /boards/
18 # /boards/
19 url(r'^$', all_threads.AllThreadsView.as_view(), name='index'),
19 url(r'^$', all_threads.AllThreadsView.as_view(), name='index'),
20 # /boards/page/
20 # /boards/page/
21 url(r'^page/(?P<page>\w+)/$', all_threads.AllThreadsView.as_view(),
21 url(r'^page/(?P<page>\w+)/$', all_threads.AllThreadsView.as_view(),
22 name='index'),
22 name='index'),
23
23
24 url(r'^archive/$', archived_threads.ArchiveView.as_view(), name='archive'),
24 url(r'^archive/$', archived_threads.ArchiveView.as_view(), name='archive'),
25 url(r'^archive/page/(?P<page>\w+)/$',
25 url(r'^archive/page/(?P<page>\w+)/$',
26 archived_threads.ArchiveView.as_view(), name='archive'),
26 archived_threads.ArchiveView.as_view(), name='archive'),
27
27
28 # login page
28 # login page
29 url(r'^login/$', login.LoginView.as_view(), name='login'),
29 url(r'^login/$', login.LoginView.as_view(), name='login'),
30
30
31 # /boards/tag/tag_name/
31 # /boards/tag/tag_name/
32 url(r'^tag/(?P<tag_name>\w+)/$', tag_threads.TagView.as_view(),
32 url(r'^tag/(?P<tag_name>\w+)/$', tag_threads.TagView.as_view(),
33 name='tag'),
33 name='tag'),
34 # /boards/tag/tag_id/page/
34 # /boards/tag/tag_id/page/
35 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/$',
35 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/$',
36 tag_threads.TagView.as_view(), name='tag'),
36 tag_threads.TagView.as_view(), name='tag'),
37
37
38 # /boards/thread/
38 # /boards/thread/
39 url(r'^thread/(?P<post_id>\w+)/$', views.thread.ThreadView.as_view(),
39 url(r'^thread/(?P<post_id>\w+)/$', views.thread.ThreadView.as_view(),
40 name='thread'),
40 name='thread'),
41 url(r'^thread/(?P<post_id>\w+)/mode/(?P<mode>\w+)/$', views.thread.ThreadView
41 url(r'^thread/(?P<post_id>\w+)/mode/(?P<mode>\w+)/$', views.thread.ThreadView
42 .as_view(), name='thread_mode'),
42 .as_view(), name='thread_mode'),
43
43
44 # /boards/post_admin/
44 # /boards/post_admin/
45 url(r'^post_admin/(?P<post_id>\w+)/$', PostAdminView.as_view(),
45 url(r'^post_admin/(?P<post_id>\w+)/$', PostAdminView.as_view(),
46 name='post_admin'),
46 name='post_admin'),
47
47
48 url(r'^settings/$', settings.SettingsView.as_view(), name='settings'),
48 url(r'^settings/$', settings.SettingsView.as_view(), name='settings'),
49 url(r'^tags/$', all_tags.AllTagsView.as_view(), name='tags'),
49 url(r'^tags/$', all_tags.AllTagsView.as_view(), name='tags'),
50 url(r'^captcha/', include('captcha.urls')),
50 url(r'^captcha/', include('captcha.urls')),
51 url(r'^authors/$', AuthorsView.as_view(), name='authors'),
51 url(r'^authors/$', AuthorsView.as_view(), name='authors'),
52 url(r'^delete/(?P<post_id>\w+)/$', DeletePostView.as_view(),
52 url(r'^delete/(?P<post_id>\w+)/$', DeletePostView.as_view(),
53 name='delete'),
53 name='delete'),
54 url(r'^ban/(?P<post_id>\w+)/$', BanUserView.as_view(), name='ban'),
54 url(r'^ban/(?P<post_id>\w+)/$', BanUserView.as_view(), name='ban'),
55
55
56 url(r'^banned/$', views.banned.BannedView.as_view(), name='banned'),
56 url(r'^banned/$', views.banned.BannedView.as_view(), name='banned'),
57 url(r'^staticpage/(?P<name>\w+)/$', StaticPageView.as_view(),
57 url(r'^staticpage/(?P<name>\w+)/$', StaticPageView.as_view(),
58 name='staticpage'),
58 name='staticpage'),
59
59
60 # RSS feeds
60 # RSS feeds
61 url(r'^rss/$', AllThreadsFeed()),
61 url(r'^rss/$', AllThreadsFeed()),
62 url(r'^page/(?P<page>\w+)/rss/$', AllThreadsFeed()),
62 url(r'^page/(?P<page>\w+)/rss/$', AllThreadsFeed()),
63 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
63 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
64 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
64 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
65 url(r'^thread/(?P<post_id>\w+)/rss/$', ThreadPostsFeed()),
65 url(r'^thread/(?P<post_id>\w+)/rss/$', ThreadPostsFeed()),
66
66
67 # i18n
67 # i18n
68 url(r'^jsi18n/$', 'boards.views.cached_js_catalog', js_info_dict,
68 url(r'^jsi18n/$', 'boards.views.cached_js_catalog', js_info_dict,
69 name='js_info_dict'),
69 name='js_info_dict'),
70
70
71 # API
71 # API
72 url(r'^api/post/(?P<post_id>\w+)/$', api.get_post, name="get_post"),
72 url(r'^api/post/(?P<post_id>\w+)/$', api.get_post, name="get_post"),
73 url(r'^api/diff_thread/(?P<thread_id>\w+)/(?P<last_update_time>\w+)/$',
73 url(r'^api/diff_thread/(?P<thread_id>\w+)/(?P<last_update_time>\w+)/$',
74 api.api_get_threaddiff, name="get_thread_diff"),
74 api.api_get_threaddiff, name="get_thread_diff"),
75 url(r'^api/threads/(?P<count>\w+)/$', api.api_get_threads,
75 url(r'^api/threads/(?P<count>\w+)/$', api.api_get_threads,
76 name='get_threads'),
76 name='get_threads'),
77 url(r'^api/tags/$', api.api_get_tags, name='get_tags'),
77 url(r'^api/tags/$', api.api_get_tags, name='get_tags'),
78 url(r'^api/thread/(?P<opening_post_id>\w+)/$', api.api_get_thread_posts,
78 url(r'^api/thread/(?P<opening_post_id>\w+)/$', api.api_get_thread_posts,
79 name='get_thread'),
79 name='get_thread'),
80 url(r'^api/add_post/(?P<opening_post_id>\w+)/$', api.api_add_post,
80 url(r'^api/add_post/(?P<opening_post_id>\w+)/$', api.api_add_post,
81 name='add_post'),
81 name='add_post'),
82 url(r'api/get_tag_popularity/(?P<tag_name>\w+)$', api.get_tag_popularity,
83 name='get_tag_popularity'),
82
84
83 )
85 )
@@ -1,239 +1,248 b''
1 from datetime import datetime
1 from datetime import datetime
2 import json
2 import json
3 import logging
3 import logging
4 from django.db import transaction
4 from django.db import transaction
5 from django.http import HttpResponse
5 from django.http import HttpResponse
6 from django.shortcuts import get_object_or_404, render
6 from django.shortcuts import get_object_or_404, render
7 from django.template import RequestContext
7 from django.template import RequestContext
8 from django.utils import timezone
8 from django.utils import timezone
9 from django.core import serializers
9 from django.core import serializers
10
10
11 from boards.forms import PostForm, PlainErrorList
11 from boards.forms import PostForm, PlainErrorList
12 from boards.models import Post, Thread, Tag
12 from boards.models import Post, Thread, Tag
13 from boards.utils import datetime_to_epoch
13 from boards.utils import datetime_to_epoch
14 from boards.views.thread import ThreadView
14 from boards.views.thread import ThreadView
15
15
16 __author__ = 'neko259'
16 __author__ = 'neko259'
17
17
18 PARAMETER_TRUNCATED = 'truncated'
18 PARAMETER_TRUNCATED = 'truncated'
19 PARAMETER_TAG = 'tag'
19 PARAMETER_TAG = 'tag'
20 PARAMETER_OFFSET = 'offset'
20 PARAMETER_OFFSET = 'offset'
21 PARAMETER_DIFF_TYPE = 'type'
21 PARAMETER_DIFF_TYPE = 'type'
22
22
23 DIFF_TYPE_HTML = 'html'
23 DIFF_TYPE_HTML = 'html'
24 DIFF_TYPE_JSON = 'json'
24 DIFF_TYPE_JSON = 'json'
25
25
26 STATUS_OK = 'ok'
26 STATUS_OK = 'ok'
27 STATUS_ERROR = 'error'
27 STATUS_ERROR = 'error'
28
28
29 logger = logging.getLogger(__name__)
29 logger = logging.getLogger(__name__)
30
30
31
31
32 @transaction.atomic
32 @transaction.atomic
33 def api_get_threaddiff(request, thread_id, last_update_time):
33 def api_get_threaddiff(request, thread_id, last_update_time):
34 """
34 """
35 Gets posts that were changed or added since time
35 Gets posts that were changed or added since time
36 """
36 """
37
37
38 thread = get_object_or_404(Post, id=thread_id).get_thread()
38 thread = get_object_or_404(Post, id=thread_id).get_thread()
39
39
40 logger.info('Getting thread #%s diff since %s' % (thread_id,
40 logger.info('Getting thread #%s diff since %s' % (thread_id,
41 last_update_time))
41 last_update_time))
42
42
43 filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000,
43 filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000,
44 timezone.get_current_timezone())
44 timezone.get_current_timezone())
45
45
46 json_data = {
46 json_data = {
47 'added': [],
47 'added': [],
48 'updated': [],
48 'updated': [],
49 'last_update': None,
49 'last_update': None,
50 }
50 }
51 added_posts = Post.objects.filter(thread_new=thread,
51 added_posts = Post.objects.filter(thread_new=thread,
52 pub_time__gt=filter_time) \
52 pub_time__gt=filter_time) \
53 .order_by('pub_time')
53 .order_by('pub_time')
54 updated_posts = Post.objects.filter(thread_new=thread,
54 updated_posts = Post.objects.filter(thread_new=thread,
55 pub_time__lte=filter_time,
55 pub_time__lte=filter_time,
56 last_edit_time__gt=filter_time)
56 last_edit_time__gt=filter_time)
57
57
58 diff_type = DIFF_TYPE_HTML
58 diff_type = DIFF_TYPE_HTML
59 if PARAMETER_DIFF_TYPE in request.GET:
59 if PARAMETER_DIFF_TYPE in request.GET:
60 diff_type = request.GET[PARAMETER_DIFF_TYPE]
60 diff_type = request.GET[PARAMETER_DIFF_TYPE]
61
61
62 for post in added_posts:
62 for post in added_posts:
63 json_data['added'].append(_get_post_data(post.id, diff_type, request))
63 json_data['added'].append(_get_post_data(post.id, diff_type, request))
64 for post in updated_posts:
64 for post in updated_posts:
65 json_data['updated'].append(_get_post_data(post.id, diff_type, request))
65 json_data['updated'].append(_get_post_data(post.id, diff_type, request))
66 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
66 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
67
67
68 return HttpResponse(content=json.dumps(json_data))
68 return HttpResponse(content=json.dumps(json_data))
69
69
70
70
71 def api_add_post(request, opening_post_id):
71 def api_add_post(request, opening_post_id):
72 """
72 """
73 Adds a post and return the JSON response for it
73 Adds a post and return the JSON response for it
74 """
74 """
75
75
76 opening_post = get_object_or_404(Post, id=opening_post_id)
76 opening_post = get_object_or_404(Post, id=opening_post_id)
77
77
78 logger.info('Adding post via api...')
78 logger.info('Adding post via api...')
79
79
80 status = STATUS_OK
80 status = STATUS_OK
81 errors = []
81 errors = []
82
82
83 if request.method == 'POST':
83 if request.method == 'POST':
84 form = PostForm(request.POST, request.FILES, error_class=PlainErrorList)
84 form = PostForm(request.POST, request.FILES, error_class=PlainErrorList)
85 form.session = request.session
85 form.session = request.session
86
86
87 if form.need_to_ban:
87 if form.need_to_ban:
88 # Ban user because he is suspected to be a bot
88 # Ban user because he is suspected to be a bot
89 # _ban_current_user(request)
89 # _ban_current_user(request)
90 status = STATUS_ERROR
90 status = STATUS_ERROR
91 if form.is_valid():
91 if form.is_valid():
92 post = ThreadView().new_post(request, form, opening_post,
92 post = ThreadView().new_post(request, form, opening_post,
93 html_response=False)
93 html_response=False)
94 if not post:
94 if not post:
95 status = STATUS_ERROR
95 status = STATUS_ERROR
96 else:
96 else:
97 logger.info('Added post #%d via api.' % post.id)
97 logger.info('Added post #%d via api.' % post.id)
98 else:
98 else:
99 status = STATUS_ERROR
99 status = STATUS_ERROR
100 errors = form.as_json_errors()
100 errors = form.as_json_errors()
101
101
102 response = {
102 response = {
103 'status': status,
103 'status': status,
104 'errors': errors,
104 'errors': errors,
105 }
105 }
106
106
107 return HttpResponse(content=json.dumps(response))
107 return HttpResponse(content=json.dumps(response))
108
108
109
109
110 def get_post(request, post_id):
110 def get_post(request, post_id):
111 """
111 """
112 Gets the html of a post. Used for popups. Post can be truncated if used
112 Gets the html of a post. Used for popups. Post can be truncated if used
113 in threads list with 'truncated' get parameter.
113 in threads list with 'truncated' get parameter.
114 """
114 """
115
115
116 logger.info('Getting post #%s' % post_id)
116 logger.info('Getting post #%s' % post_id)
117
117
118 post = get_object_or_404(Post, id=post_id)
118 post = get_object_or_404(Post, id=post_id)
119
119
120 context = RequestContext(request)
120 context = RequestContext(request)
121 context['post'] = post
121 context['post'] = post
122 if PARAMETER_TRUNCATED in request.GET:
122 if PARAMETER_TRUNCATED in request.GET:
123 context[PARAMETER_TRUNCATED] = True
123 context[PARAMETER_TRUNCATED] = True
124
124
125 return render(request, 'boards/api_post.html', context)
125 return render(request, 'boards/api_post.html', context)
126
126
127
127
128 # TODO Test this
128 # TODO Test this
129 def api_get_threads(request, count):
129 def api_get_threads(request, count):
130 """
130 """
131 Gets the JSON thread opening posts list.
131 Gets the JSON thread opening posts list.
132 Parameters that can be used for filtering:
132 Parameters that can be used for filtering:
133 tag, offset (from which thread to get results)
133 tag, offset (from which thread to get results)
134 """
134 """
135
135
136 if PARAMETER_TAG in request.GET:
136 if PARAMETER_TAG in request.GET:
137 tag_name = request.GET[PARAMETER_TAG]
137 tag_name = request.GET[PARAMETER_TAG]
138 if tag_name is not None:
138 if tag_name is not None:
139 tag = get_object_or_404(Tag, name=tag_name)
139 tag = get_object_or_404(Tag, name=tag_name)
140 threads = tag.threads.filter(archived=False)
140 threads = tag.threads.filter(archived=False)
141 else:
141 else:
142 threads = Thread.objects.filter(archived=False)
142 threads = Thread.objects.filter(archived=False)
143
143
144 if PARAMETER_OFFSET in request.GET:
144 if PARAMETER_OFFSET in request.GET:
145 offset = request.GET[PARAMETER_OFFSET]
145 offset = request.GET[PARAMETER_OFFSET]
146 offset = int(offset) if offset is not None else 0
146 offset = int(offset) if offset is not None else 0
147 else:
147 else:
148 offset = 0
148 offset = 0
149
149
150 threads = threads.order_by('-bump_time')
150 threads = threads.order_by('-bump_time')
151 threads = threads[offset:offset + int(count)]
151 threads = threads[offset:offset + int(count)]
152
152
153 opening_posts = []
153 opening_posts = []
154 for thread in threads:
154 for thread in threads:
155 opening_post = thread.get_opening_post()
155 opening_post = thread.get_opening_post()
156
156
157 # TODO Add tags, replies and images count
157 # TODO Add tags, replies and images count
158 opening_posts.append(_get_post_data(opening_post.id,
158 opening_posts.append(_get_post_data(opening_post.id,
159 include_last_update=True))
159 include_last_update=True))
160
160
161 return HttpResponse(content=json.dumps(opening_posts))
161 return HttpResponse(content=json.dumps(opening_posts))
162
162
163
163
164 # TODO Test this
164 # TODO Test this
165 def api_get_tags(request):
165 def api_get_tags(request):
166 """
166 """
167 Gets all tags or user tags.
167 Gets all tags or user tags.
168 """
168 """
169
169
170 # TODO Get favorite tags for the given user ID
170 # TODO Get favorite tags for the given user ID
171
171
172 tags = Tag.objects.get_not_empty_tags()
172 tags = Tag.objects.get_not_empty_tags()
173 tag_names = []
173 tag_names = []
174 for tag in tags:
174 for tag in tags:
175 tag_names.append(tag.name)
175 tag_names.append(tag.name)
176
176
177 return HttpResponse(content=json.dumps(tag_names))
177 return HttpResponse(content=json.dumps(tag_names))
178
178
179
179
180 # TODO The result can be cached by the thread last update time
180 # TODO The result can be cached by the thread last update time
181 # TODO Test this
181 # TODO Test this
182 def api_get_thread_posts(request, opening_post_id):
182 def api_get_thread_posts(request, opening_post_id):
183 """
183 """
184 Gets the JSON array of thread posts
184 Gets the JSON array of thread posts
185 """
185 """
186
186
187 opening_post = get_object_or_404(Post, id=opening_post_id)
187 opening_post = get_object_or_404(Post, id=opening_post_id)
188 thread = opening_post.get_thread()
188 thread = opening_post.get_thread()
189 posts = thread.get_replies()
189 posts = thread.get_replies()
190
190
191 json_data = {
191 json_data = {
192 'posts': [],
192 'posts': [],
193 'last_update': None,
193 'last_update': None,
194 }
194 }
195 json_post_list = []
195 json_post_list = []
196
196
197 for post in posts:
197 for post in posts:
198 json_post_list.append(_get_post_data(post.id))
198 json_post_list.append(_get_post_data(post.id))
199 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
199 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
200 json_data['posts'] = json_post_list
200 json_data['posts'] = json_post_list
201
201
202 return HttpResponse(content=json.dumps(json_data))
202 return HttpResponse(content=json.dumps(json_data))
203
203
204
204
205 def api_get_post(request, post_id):
205 def api_get_post(request, post_id):
206 """
206 """
207 Gets the JSON of a post. This can be
207 Gets the JSON of a post. This can be
208 used as and API for external clients.
208 used as and API for external clients.
209 """
209 """
210
210
211 post = get_object_or_404(Post, id=post_id)
211 post = get_object_or_404(Post, id=post_id)
212
212
213 json = serializers.serialize("json", [post], fields=(
213 json = serializers.serialize("json", [post], fields=(
214 "pub_time", "_text_rendered", "title", "text", "image",
214 "pub_time", "_text_rendered", "title", "text", "image",
215 "image_width", "image_height", "replies", "tags"
215 "image_width", "image_height", "replies", "tags"
216 ))
216 ))
217
217
218 return HttpResponse(content=json)
218 return HttpResponse(content=json)
219
219
220
220
221 def get_tag_popularity(request, tag_name):
222 tag = get_object_or_404(Tag, name=tag_name)
223
224 json_data = []
225 json_data['popularity'] = tag.get_popularity()
226
227 return HttpResponse(content=json.dumps(json_data))
228
229
221 # TODO Add pub time and replies
230 # TODO Add pub time and replies
222 def _get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None,
231 def _get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None,
223 include_last_update=False):
232 include_last_update=False):
224 if format_type == DIFF_TYPE_HTML:
233 if format_type == DIFF_TYPE_HTML:
225 return get_post(request, post_id).content.strip()
234 return get_post(request, post_id).content.strip()
226 elif format_type == DIFF_TYPE_JSON:
235 elif format_type == DIFF_TYPE_JSON:
227 post = get_object_or_404(Post, id=post_id)
236 post = get_object_or_404(Post, id=post_id)
228 post_json = {
237 post_json = {
229 'id': post.id,
238 'id': post.id,
230 'title': post.title,
239 'title': post.title,
231 'text': post.text.rendered,
240 'text': post.text.rendered,
232 }
241 }
233 if post.image:
242 if post.image:
234 post_json['image'] = post.image.url
243 post_json['image'] = post.image.url
235 post_json['image_preview'] = post.image.url_200x150
244 post_json['image_preview'] = post.image.url_200x150
236 if include_last_update:
245 if include_last_update:
237 post_json['bump_time'] = datetime_to_epoch(
246 post_json['bump_time'] = datetime_to_epoch(
238 post.thread_new.bump_time)
247 post.thread_new.bump_time)
239 return post_json
248 return post_json
General Comments 0
You need to be logged in to leave comments. Login now