Show More
@@ -1,72 +1,74 b'' | |||||
1 | {% load i18n %} |
|
1 | {% load i18n %} | |
2 | {% load board %} |
|
2 | {% load board %} | |
3 |
|
3 | |||
4 | {% spaceless %} |
|
4 | {% spaceless %} | |
5 | {% if can_bump %} |
|
5 | {% if post.thread_new.archived %} | |
|
6 | <div class="post archive_post" id="{{ post.id }}"> | |||
|
7 | {% elif post.thread_new.can_bump %} | |||
6 | <div class="post" id="{{ post.id }}"> |
|
8 | <div class="post" id="{{ post.id }}"> | |
7 | {% else %} |
|
9 | {% else %} | |
8 | <div class="post dead_post" id="{{ post.id }}"> |
|
10 | <div class="post dead_post" id="{{ post.id }}"> | |
9 | {% endif %} |
|
11 | {% endif %} | |
10 |
|
12 | |||
11 | {% if post.image %} |
|
13 | {% if post.image %} | |
12 | <div class="image"> |
|
14 | <div class="image"> | |
13 | <a |
|
15 | <a | |
14 | class="thumb" |
|
16 | class="thumb" | |
15 | href="{{ post.image.url }}"><img |
|
17 | href="{{ post.image.url }}"><img | |
16 | src="{{ post.image.url_200x150 }}" |
|
18 | src="{{ post.image.url_200x150 }}" | |
17 | alt="{{ post.id }}" |
|
19 | alt="{{ post.id }}" | |
18 | width="{{ post.image_pre_width }}" |
|
20 | width="{{ post.image_pre_width }}" | |
19 | height="{{ post.image_pre_height }}" |
|
21 | height="{{ post.image_pre_height }}" | |
20 | data-width="{{ post.image_width }}" |
|
22 | data-width="{{ post.image_width }}" | |
21 | data-height="{{ post.image_height }}"/> |
|
23 | data-height="{{ post.image_height }}"/> | |
22 | </a> |
|
24 | </a> | |
23 | </div> |
|
25 | </div> | |
24 | {% endif %} |
|
26 | {% endif %} | |
25 | <div class="message"> |
|
27 | <div class="message"> | |
26 | <div class="post-info"> |
|
28 | <div class="post-info"> | |
27 | <span class="title">{{ post.title }}</span> |
|
29 | <span class="title">{{ post.title }}</span> | |
28 | <a class="post_id" href="{% post_url post.id %}"> |
|
30 | <a class="post_id" href="{% post_url post.id %}"> | |
29 | ({{ post.id }})</a> |
|
31 | ({{ post.id }})</a> | |
30 | [{{ post.pub_time }}] |
|
32 | [{{ post.pub_time }}] | |
31 | [<a href="#" onclick="javascript:addQuickReply('{{ post.id }}') |
|
33 | [<a href="#" onclick="javascript:addQuickReply('{{ post.id }}') | |
32 | ; return false;">>></a>] |
|
34 | ; return false;">>></a>] | |
33 |
|
35 | |||
34 | {% if moderator %} |
|
36 | {% if moderator %} | |
35 | <span class="moderator_info"> |
|
37 | <span class="moderator_info"> | |
36 | [<a href="{% url 'delete' post_id=post.id %}" |
|
38 | [<a href="{% url 'delete' post_id=post.id %}" | |
37 | >{% trans 'Delete' %}</a>] |
|
39 | >{% trans 'Delete' %}</a>] | |
38 | ({{ post.poster_ip }}) |
|
40 | ({{ post.poster_ip }}) | |
39 | [<a href="{% url 'ban' post_id=post.id %}?next={{ request.path }}" |
|
41 | [<a href="{% url 'ban' post_id=post.id %}?next={{ request.path }}" | |
40 | >{% trans 'Ban IP' %}</a>] |
|
42 | >{% trans 'Ban IP' %}</a>] | |
41 | </span> |
|
43 | </span> | |
42 | {% endif %} |
|
44 | {% endif %} | |
43 | </div> |
|
45 | </div> | |
44 | {% autoescape off %} |
|
46 | {% autoescape off %} | |
45 | {% if truncated %} |
|
47 | {% if truncated %} | |
46 | {{ post.text.rendered|truncatewords_html:50 }} |
|
48 | {{ post.text.rendered|truncatewords_html:50 }} | |
47 | {% else %} |
|
49 | {% else %} | |
48 | {{ post.text.rendered }} |
|
50 | {{ post.text.rendered }} | |
49 | {% endif %} |
|
51 | {% endif %} | |
50 | {% endautoescape %} |
|
52 | {% endautoescape %} | |
51 | {% if post.is_referenced %} |
|
53 | {% if post.is_referenced %} | |
52 | <div class="refmap"> |
|
54 | <div class="refmap"> | |
53 | {% trans "Replies" %}: |
|
55 | {% trans "Replies" %}: | |
54 | {% for ref_post in post.get_sorted_referenced_posts %} |
|
56 | {% for ref_post in post.get_sorted_referenced_posts %} | |
55 | <a href="{% post_url ref_post.id %}">>>{{ ref_post.id }}</a |
|
57 | <a href="{% post_url ref_post.id %}">>>{{ ref_post.id }}</a | |
56 | >{% if not forloop.last %},{% endif %} |
|
58 | >{% if not forloop.last %},{% endif %} | |
57 | {% endfor %} |
|
59 | {% endfor %} | |
58 | </div> |
|
60 | </div> | |
59 | {% endif %} |
|
61 | {% endif %} | |
60 | </div> |
|
62 | </div> | |
61 | {% if post.is_opening and post.thread_new.tags.exists %} |
|
63 | {% if post.is_opening and post.thread_new.tags.exists %} | |
62 | <div class="metadata"> |
|
64 | <div class="metadata"> | |
63 | <span class="tags"> |
|
65 | <span class="tags"> | |
64 | {% for tag in post.thread_new.get_tags %} |
|
66 | {% for tag in post.thread_new.get_tags %} | |
65 | <a class="tag" href="{% url 'tag' tag.name %}"> |
|
67 | <a class="tag" href="{% url 'tag' tag.name %}"> | |
66 | #{{ tag.name }}</a>{% if not forloop.last %},{% endif %} |
|
68 | #{{ tag.name }}</a>{% if not forloop.last %},{% endif %} | |
67 | {% endfor %} |
|
69 | {% endfor %} | |
68 | </span> |
|
70 | </span> | |
69 | </div> |
|
71 | </div> | |
70 | {% endif %} |
|
72 | {% endif %} | |
71 | </div> |
|
73 | </div> | |
72 | {% endspaceless %} |
|
74 | {% endspaceless %} |
@@ -1,205 +1,204 b'' | |||||
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 | PARAMETER_DIFF_TYPE = 'type' |
|
18 | PARAMETER_DIFF_TYPE = 'type' | |
19 |
|
19 | |||
20 | DIFF_TYPE_HTML = 'html' |
|
20 | DIFF_TYPE_HTML = 'html' | |
21 | DIFF_TYPE_JSON = 'json' |
|
21 | DIFF_TYPE_JSON = 'json' | |
22 |
|
22 | |||
23 |
|
23 | |||
24 | @transaction.atomic |
|
24 | @transaction.atomic | |
25 | def api_get_threaddiff(request, thread_id, last_update_time): |
|
25 | def api_get_threaddiff(request, thread_id, last_update_time): | |
26 | """Get posts that were changed or added since time""" |
|
26 | """Get posts that were changed or added since time""" | |
27 |
|
27 | |||
28 | thread = get_object_or_404(Post, id=thread_id).thread_new |
|
28 | thread = get_object_or_404(Post, id=thread_id).thread_new | |
29 |
|
29 | |||
30 | filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000, |
|
30 | filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000, | |
31 | timezone.get_current_timezone()) |
|
31 | timezone.get_current_timezone()) | |
32 |
|
32 | |||
33 | json_data = { |
|
33 | json_data = { | |
34 | 'added': [], |
|
34 | 'added': [], | |
35 | 'updated': [], |
|
35 | 'updated': [], | |
36 | 'last_update': None, |
|
36 | 'last_update': None, | |
37 | } |
|
37 | } | |
38 | added_posts = Post.objects.filter(thread_new=thread, |
|
38 | added_posts = Post.objects.filter(thread_new=thread, | |
39 | pub_time__gt=filter_time) \ |
|
39 | pub_time__gt=filter_time) \ | |
40 | .order_by('pub_time') |
|
40 | .order_by('pub_time') | |
41 | updated_posts = Post.objects.filter(thread_new=thread, |
|
41 | updated_posts = Post.objects.filter(thread_new=thread, | |
42 | pub_time__lte=filter_time, |
|
42 | pub_time__lte=filter_time, | |
43 | last_edit_time__gt=filter_time) |
|
43 | last_edit_time__gt=filter_time) | |
44 |
|
44 | |||
45 | diff_type = DIFF_TYPE_HTML |
|
45 | diff_type = DIFF_TYPE_HTML | |
46 | if PARAMETER_DIFF_TYPE in request.GET: |
|
46 | if PARAMETER_DIFF_TYPE in request.GET: | |
47 | diff_type = request.GET[PARAMETER_DIFF_TYPE] |
|
47 | diff_type = request.GET[PARAMETER_DIFF_TYPE] | |
48 |
|
48 | |||
49 | for post in added_posts: |
|
49 | for post in added_posts: | |
50 | json_data['added'].append(_get_post_data(post.id, diff_type, request)) |
|
50 | json_data['added'].append(_get_post_data(post.id, diff_type, request)) | |
51 | for post in updated_posts: |
|
51 | for post in updated_posts: | |
52 | json_data['updated'].append(_get_post_data(post.id, diff_type, request)) |
|
52 | json_data['updated'].append(_get_post_data(post.id, diff_type, request)) | |
53 | json_data['last_update'] = _datetime_to_epoch(thread.last_edit_time) |
|
53 | json_data['last_update'] = _datetime_to_epoch(thread.last_edit_time) | |
54 |
|
54 | |||
55 | return HttpResponse(content=json.dumps(json_data)) |
|
55 | return HttpResponse(content=json.dumps(json_data)) | |
56 |
|
56 | |||
57 |
|
57 | |||
58 | # TODO This method needs to be implemented properly |
|
58 | # TODO This method needs to be implemented properly | |
59 | # def api_add_post(request, form): |
|
59 | # def api_add_post(request, form): | |
60 | # """ |
|
60 | # """ | |
61 | # Add a post and return the JSON response for it |
|
61 | # Add a post and return the JSON response for it | |
62 | # """ |
|
62 | # """ | |
63 | # |
|
63 | # | |
64 | # status = 'ok' |
|
64 | # status = 'ok' | |
65 | # errors = [] |
|
65 | # errors = [] | |
66 | # |
|
66 | # | |
67 | # if request.method == 'POST': |
|
67 | # if request.method == 'POST': | |
68 | # form = ThreadForm(request.POST, request.FILES, |
|
68 | # form = ThreadForm(request.POST, request.FILES, | |
69 | # error_class=PlainErrorList) |
|
69 | # error_class=PlainErrorList) | |
70 | # form.session = request.session |
|
70 | # form.session = request.session | |
71 | # |
|
71 | # | |
72 | # if form.is_valid(): |
|
72 | # if form.is_valid(): | |
73 | # # TODO Don't form a response here cause we'll not need it |
|
73 | # # TODO Don't form a response here cause we'll not need it | |
74 | # _new_post(request, form) |
|
74 | # _new_post(request, form) | |
75 | # if form.need_to_ban: |
|
75 | # if form.need_to_ban: | |
76 | # # Ban user because he is suspected to be a bot |
|
76 | # # Ban user because he is suspected to be a bot | |
77 | # _ban_current_user(request) |
|
77 | # _ban_current_user(request) | |
78 | # else: |
|
78 | # else: | |
79 | # status = 'error' |
|
79 | # status = 'error' | |
80 | # for field in form.fields: |
|
80 | # for field in form.fields: | |
81 | # if field.errors: |
|
81 | # if field.errors: | |
82 | # errors.append(field.errors) |
|
82 | # errors.append(field.errors) | |
83 | # |
|
83 | # | |
84 | # response = { |
|
84 | # response = { | |
85 | # 'status': status, |
|
85 | # 'status': status, | |
86 | # 'errors': errors, |
|
86 | # 'errors': errors, | |
87 | # } |
|
87 | # } | |
88 | # |
|
88 | # | |
89 | # return HttpResponse(content=json.dumps(response)) |
|
89 | # return HttpResponse(content=json.dumps(response)) | |
90 |
|
90 | |||
91 |
|
91 | |||
92 | def get_post(request, post_id): |
|
92 | def get_post(request, post_id): | |
93 | """ |
|
93 | """ | |
94 | Get the html of a post. Used for popups. Post can be truncated if used |
|
94 | Get the html of a post. Used for popups. Post can be truncated if used | |
95 | in threads list with 'truncated' get parameter. |
|
95 | in threads list with 'truncated' get parameter. | |
96 | """ |
|
96 | """ | |
97 |
|
97 | |||
98 | post = get_object_or_404(Post, id=post_id) |
|
98 | post = get_object_or_404(Post, id=post_id) | |
99 | thread = post.thread_new |
|
99 | thread = post.thread_new | |
100 |
|
100 | |||
101 | context = RequestContext(request) |
|
101 | context = RequestContext(request) | |
102 | context['post'] = post |
|
102 | context['post'] = post | |
103 | context['can_bump'] = thread.can_bump() |
|
|||
104 | if PARAMETER_TRUNCATED in request.GET: |
|
103 | if PARAMETER_TRUNCATED in request.GET: | |
105 | context[PARAMETER_TRUNCATED] = True |
|
104 | context[PARAMETER_TRUNCATED] = True | |
106 |
|
105 | |||
107 | return render(request, 'boards/post.html', context) |
|
106 | return render(request, 'boards/post.html', context) | |
108 |
|
107 | |||
109 |
|
108 | |||
110 | # TODO Test this |
|
109 | # TODO Test this | |
111 | def api_get_threads(request, count): |
|
110 | def api_get_threads(request, count): | |
112 | """ |
|
111 | """ | |
113 | Get the JSON thread opening posts list. |
|
112 | Get the JSON thread opening posts list. | |
114 | Parameters that can be used for filtering: |
|
113 | Parameters that can be used for filtering: | |
115 | tag, offset (from which thread to get results) |
|
114 | tag, offset (from which thread to get results) | |
116 | """ |
|
115 | """ | |
117 |
|
116 | |||
118 | if PARAMETER_TAG in request.GET: |
|
117 | if PARAMETER_TAG in request.GET: | |
119 | tag_name = request.GET[PARAMETER_TAG] |
|
118 | tag_name = request.GET[PARAMETER_TAG] | |
120 | if tag_name is not None: |
|
119 | if tag_name is not None: | |
121 | tag = get_object_or_404(Tag, name=tag_name) |
|
120 | tag = get_object_or_404(Tag, name=tag_name) | |
122 | threads = tag.threads.filter(archived=False) |
|
121 | threads = tag.threads.filter(archived=False) | |
123 | else: |
|
122 | else: | |
124 | threads = Thread.objects.filter(archived=False) |
|
123 | threads = Thread.objects.filter(archived=False) | |
125 |
|
124 | |||
126 | if PARAMETER_OFFSET in request.GET: |
|
125 | if PARAMETER_OFFSET in request.GET: | |
127 | offset = request.GET[PARAMETER_OFFSET] |
|
126 | offset = request.GET[PARAMETER_OFFSET] | |
128 | offset = int(offset) if offset is not None else 0 |
|
127 | offset = int(offset) if offset is not None else 0 | |
129 | else: |
|
128 | else: | |
130 | offset = 0 |
|
129 | offset = 0 | |
131 |
|
130 | |||
132 | threads = threads.order_by('-bump_time') |
|
131 | threads = threads.order_by('-bump_time') | |
133 | threads = threads[offset:offset + int(count)] |
|
132 | threads = threads[offset:offset + int(count)] | |
134 |
|
133 | |||
135 | opening_posts = [] |
|
134 | opening_posts = [] | |
136 | for thread in threads: |
|
135 | for thread in threads: | |
137 | opening_post = thread.get_opening_post() |
|
136 | opening_post = thread.get_opening_post() | |
138 |
|
137 | |||
139 | # TODO Add tags, replies and images count |
|
138 | # TODO Add tags, replies and images count | |
140 | opening_posts.append(_get_post_data(opening_post.id, |
|
139 | opening_posts.append(_get_post_data(opening_post.id, | |
141 | include_last_update=True)) |
|
140 | include_last_update=True)) | |
142 |
|
141 | |||
143 | return HttpResponse(content=json.dumps(opening_posts)) |
|
142 | return HttpResponse(content=json.dumps(opening_posts)) | |
144 |
|
143 | |||
145 |
|
144 | |||
146 | # TODO Test this |
|
145 | # TODO Test this | |
147 | def api_get_tags(request): |
|
146 | def api_get_tags(request): | |
148 | """ |
|
147 | """ | |
149 | Get all tags or user tags. |
|
148 | Get all tags or user tags. | |
150 | """ |
|
149 | """ | |
151 |
|
150 | |||
152 | # TODO Get favorite tags for the given user ID |
|
151 | # TODO Get favorite tags for the given user ID | |
153 |
|
152 | |||
154 | tags = Tag.objects.get_not_empty_tags() |
|
153 | tags = Tag.objects.get_not_empty_tags() | |
155 | tag_names = [] |
|
154 | tag_names = [] | |
156 | for tag in tags: |
|
155 | for tag in tags: | |
157 | tag_names.append(tag.name) |
|
156 | tag_names.append(tag.name) | |
158 |
|
157 | |||
159 | return HttpResponse(content=json.dumps(tag_names)) |
|
158 | return HttpResponse(content=json.dumps(tag_names)) | |
160 |
|
159 | |||
161 |
|
160 | |||
162 | # TODO The result can be cached by the thread last update time |
|
161 | # TODO The result can be cached by the thread last update time | |
163 | # TODO Test this |
|
162 | # TODO Test this | |
164 | def api_get_thread_posts(request, opening_post_id): |
|
163 | def api_get_thread_posts(request, opening_post_id): | |
165 | """ |
|
164 | """ | |
166 | Get the JSON array of thread posts |
|
165 | Get the JSON array of thread posts | |
167 | """ |
|
166 | """ | |
168 |
|
167 | |||
169 | opening_post = get_object_or_404(Post, id=opening_post_id) |
|
168 | opening_post = get_object_or_404(Post, id=opening_post_id) | |
170 | thread = opening_post.thread_new |
|
169 | thread = opening_post.thread_new | |
171 | posts = thread.get_replies() |
|
170 | posts = thread.get_replies() | |
172 |
|
171 | |||
173 | json_data = { |
|
172 | json_data = { | |
174 | 'posts': [], |
|
173 | 'posts': [], | |
175 | 'last_update': None, |
|
174 | 'last_update': None, | |
176 | } |
|
175 | } | |
177 | json_post_list = [] |
|
176 | json_post_list = [] | |
178 |
|
177 | |||
179 | for post in posts: |
|
178 | for post in posts: | |
180 | json_post_list.append(_get_post_data(post.id)) |
|
179 | json_post_list.append(_get_post_data(post.id)) | |
181 | json_data['last_update'] = _datetime_to_epoch(thread.last_edit_time) |
|
180 | json_data['last_update'] = _datetime_to_epoch(thread.last_edit_time) | |
182 | json_data['posts'] = json_post_list |
|
181 | json_data['posts'] = json_post_list | |
183 |
|
182 | |||
184 | return HttpResponse(content=json.dumps(json_data)) |
|
183 | return HttpResponse(content=json.dumps(json_data)) | |
185 |
|
184 | |||
186 |
|
185 | |||
187 | # TODO Add pub time and replies |
|
186 | # TODO Add pub time and replies | |
188 | def _get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None, |
|
187 | def _get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None, | |
189 | include_last_update=False): |
|
188 | include_last_update=False): | |
190 | if format_type == DIFF_TYPE_HTML: |
|
189 | if format_type == DIFF_TYPE_HTML: | |
191 | return get_post(request, post_id).content.strip() |
|
190 | return get_post(request, post_id).content.strip() | |
192 | elif format_type == DIFF_TYPE_JSON: |
|
191 | elif format_type == DIFF_TYPE_JSON: | |
193 | post = get_object_or_404(Post, id=post_id) |
|
192 | post = get_object_or_404(Post, id=post_id) | |
194 | post_json = { |
|
193 | post_json = { | |
195 | 'id': post.id, |
|
194 | 'id': post.id, | |
196 | 'title': post.title, |
|
195 | 'title': post.title, | |
197 | 'text': post.text.rendered, |
|
196 | 'text': post.text.rendered, | |
198 | } |
|
197 | } | |
199 | if post.image: |
|
198 | if post.image: | |
200 | post_json['image'] = post.image.url |
|
199 | post_json['image'] = post.image.url | |
201 | post_json['image_preview'] = post.image.url_200x150 |
|
200 | post_json['image_preview'] = post.image.url_200x150 | |
202 | if include_last_update: |
|
201 | if include_last_update: | |
203 | post_json['bump_time'] = _datetime_to_epoch( |
|
202 | post_json['bump_time'] = _datetime_to_epoch( | |
204 | post.thread_new.bump_time) |
|
203 | post.thread_new.bump_time) | |
205 | return post_json |
|
204 | return post_json |
General Comments 0
You need to be logged in to leave comments.
Login now