Show More
@@ -0,0 +1,116 b'' | |||||
|
1 | /* | |||
|
2 | @licstart The following is the entire license notice for the | |||
|
3 | JavaScript code in this page. | |||
|
4 | ||||
|
5 | ||||
|
6 | Copyright (C) 2013 neko259 | |||
|
7 | ||||
|
8 | The JavaScript code in this page is free software: you can | |||
|
9 | redistribute it and/or modify it under the terms of the GNU | |||
|
10 | General Public License (GNU GPL) as published by the Free Software | |||
|
11 | Foundation, either version 3 of the License, or (at your option) | |||
|
12 | any later version. The code is distributed WITHOUT ANY WARRANTY; | |||
|
13 | without even the implied warranty of MERCHANTABILITY or FITNESS | |||
|
14 | FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. | |||
|
15 | ||||
|
16 | As additional permission under GNU GPL version 3 section 7, you | |||
|
17 | may distribute non-source (e.g., minimized or compacted) forms of | |||
|
18 | that code without the copy of the GNU GPL normally required by | |||
|
19 | section 4, provided you include this license notice and a URL | |||
|
20 | through which recipients can access the Corresponding Source. | |||
|
21 | ||||
|
22 | @licend The above is the entire license notice | |||
|
23 | for the JavaScript code in this page. | |||
|
24 | */ | |||
|
25 | ||||
|
26 | var THREAD_UPDATE_DELAY = 10000; | |||
|
27 | ||||
|
28 | var loading = false; | |||
|
29 | var lastUpdateTime = null; | |||
|
30 | ||||
|
31 | function blink(node) { | |||
|
32 | var blinkCount = 2; | |||
|
33 | var blinkDelay = 250; | |||
|
34 | ||||
|
35 | var nodeToAnimate = node; | |||
|
36 | for (var i = 0; i < blinkCount; i++) { | |||
|
37 | nodeToAnimate = nodeToAnimate.fadeOut(blinkDelay).fadeIn(blinkDelay); | |||
|
38 | } | |||
|
39 | } | |||
|
40 | ||||
|
41 | function updateThread() { | |||
|
42 | if (loading) { | |||
|
43 | return; | |||
|
44 | } | |||
|
45 | ||||
|
46 | loading = true; | |||
|
47 | ||||
|
48 | var threadPosts = $('div.thread').children('.post'); | |||
|
49 | ||||
|
50 | var lastPost = threadPosts.last(); | |||
|
51 | var threadId = threadPosts.first().attr('id'); | |||
|
52 | ||||
|
53 | var diffUrl = '/api/diff_thread/' + threadId + '/' + lastUpdateTime + '/'; | |||
|
54 | $.getJSON(diffUrl) | |||
|
55 | .success(function(data) { | |||
|
56 | var bottom = isPageBottom(); | |||
|
57 | ||||
|
58 | var addedPosts = data.added; | |||
|
59 | ||||
|
60 | for (var i = 0; i < addedPosts.length; i++) { | |||
|
61 | var postText = addedPosts[i]; | |||
|
62 | ||||
|
63 | var post = $(postText); | |||
|
64 | post.appendTo(lastPost.parent()); | |||
|
65 | addRefLinkPreview(post[0]); | |||
|
66 | ||||
|
67 | lastPost = post; | |||
|
68 | blink(post); | |||
|
69 | } | |||
|
70 | ||||
|
71 | var updatedPosts = data.updated; | |||
|
72 | for (var i = 0; i < updatedPosts.length; i++) { | |||
|
73 | var postText = updatedPosts[i]; | |||
|
74 | ||||
|
75 | var post = $(postText); | |||
|
76 | var postId = post.attr('id'); | |||
|
77 | ||||
|
78 | var oldPost = $('div.thread').children('.post[id=' + postId + ']'); | |||
|
79 | ||||
|
80 | oldPost.replaceWith(post); | |||
|
81 | addRefLinkPreview(post[0]); | |||
|
82 | ||||
|
83 | blink(post); | |||
|
84 | } | |||
|
85 | ||||
|
86 | // TODO Process deleted posts | |||
|
87 | ||||
|
88 | lastUpdateTime = data.last_update; | |||
|
89 | loading = false; | |||
|
90 | ||||
|
91 | if (bottom) { | |||
|
92 | var $target = $('html,body'); | |||
|
93 | $target.animate({scrollTop: $target.height()}, 1000); | |||
|
94 | } | |||
|
95 | }) | |||
|
96 | .error(function(data) { | |||
|
97 | // TODO Show error message that server is unavailable? | |||
|
98 | ||||
|
99 | loading = false; | |||
|
100 | }); | |||
|
101 | } | |||
|
102 | ||||
|
103 | function isPageBottom() { | |||
|
104 | var scroll = $(window).scrollTop() / ($(document).height() | |||
|
105 | - $(window).height()) | |||
|
106 | ||||
|
107 | return scroll == 1 | |||
|
108 | } | |||
|
109 | ||||
|
110 | function initAutoupdate() { | |||
|
111 | loading = false; | |||
|
112 | ||||
|
113 | lastUpdateTime = $('.metapanel').attr('data-last-update'); | |||
|
114 | ||||
|
115 | setInterval(updateThread, THREAD_UPDATE_DELAY); | |||
|
116 | } |
@@ -47,15 +47,17 b' class PostManager(models.Manager):' | |||||
47 |
|
47 | |||
48 | def create_post(self, title, text, image=None, thread=None, |
|
48 | def create_post(self, title, text, image=None, thread=None, | |
49 | ip=NO_IP, tags=None, user=None): |
|
49 | ip=NO_IP, tags=None, user=None): | |
|
50 | posting_time = timezone.now() | |||
|
51 | ||||
50 | post = self.create(title=title, |
|
52 | post = self.create(title=title, | |
51 | text=text, |
|
53 | text=text, | |
52 |
pub_time=ti |
|
54 | pub_time=posting_time, | |
53 | thread=thread, |
|
55 | thread=thread, | |
54 | image=image, |
|
56 | image=image, | |
55 | poster_ip=ip, |
|
57 | poster_ip=ip, | |
56 | poster_user_agent=UNKNOWN_UA, |
|
58 | poster_user_agent=UNKNOWN_UA, | |
57 |
last_edit_time=ti |
|
59 | last_edit_time=posting_time, | |
58 |
bump_time=ti |
|
60 | bump_time=posting_time, | |
59 | user=user) |
|
61 | user=user) | |
60 |
|
62 | |||
61 | if tags: |
|
63 | if tags: | |
@@ -66,7 +68,7 b' class PostManager(models.Manager):' | |||||
66 | if thread: |
|
68 | if thread: | |
67 | thread.replies.add(post) |
|
69 | thread.replies.add(post) | |
68 | thread.bump() |
|
70 | thread.bump() | |
69 |
thread.last_edit_time = ti |
|
71 | thread.last_edit_time = posting_time | |
70 | thread.save() |
|
72 | thread.save() | |
71 |
|
73 | |||
72 | #cache_key = thread.get_cache_key() |
|
74 | #cache_key = thread.get_cache_key() | |
@@ -179,7 +181,10 b' class PostManager(models.Manager):' | |||||
179 | id = reply_number.group(1) |
|
181 | id = reply_number.group(1) | |
180 | ref_post = self.filter(id=id) |
|
182 | ref_post = self.filter(id=id) | |
181 | if ref_post.count() > 0: |
|
183 | if ref_post.count() > 0: | |
182 |
ref_post[0] |
|
184 | referenced_post = ref_post[0] | |
|
185 | referenced_post.referenced_posts.add(post) | |||
|
186 | referenced_post.last_edit_time = post.pub_time | |||
|
187 | referenced_post.save() | |||
183 |
|
188 | |||
184 | def _get_page_count(self, thread_count): |
|
189 | def _get_page_count(self, thread_count): | |
185 | return int(math.ceil(thread_count / float(settings.THREADS_PER_PAGE))) |
|
190 | return int(math.ceil(thread_count / float(settings.THREADS_PER_PAGE))) | |
@@ -312,7 +317,7 b' class Post(models.Model):' | |||||
312 | def can_bump(self): |
|
317 | def can_bump(self): | |
313 | """Check if the thread can be bumped by replying""" |
|
318 | """Check if the thread can be bumped by replying""" | |
314 |
|
319 | |||
315 |
post_count = self.get_reply_count() |
|
320 | post_count = self.get_reply_count() | |
316 |
|
321 | |||
317 | return post_count <= settings.MAX_POSTS_PER_THREAD |
|
322 | return post_count <= settings.MAX_POSTS_PER_THREAD | |
318 |
|
323 |
@@ -28,7 +28,7 b' function showPostPreview(e) {' | |||||
28 | var pNum = $(this).text().match(/\d+/); |
|
28 | var pNum = $(this).text().match(/\d+/); | |
29 |
|
29 | |||
30 | if (pNum.length == 0) { |
|
30 | if (pNum.length == 0) { | |
31 |
|
|
31 | return; | |
32 | } |
|
32 | } | |
33 |
|
33 | |||
34 | //position |
|
34 | //position | |
@@ -57,7 +57,7 b' function showPostPreview(e) {' | |||||
57 | }; |
|
57 | }; | |
58 |
|
58 | |||
59 |
|
59 | |||
60 | cln.innerHTML = gettext('Loading...'); |
|
60 | cln.innerHTML = "<div class=\"post\">" + gettext('Loading...') + "</div>"; | |
61 |
|
61 | |||
62 | //если пост найден в дереве. |
|
62 | //если пост найден в дереве. | |
63 | if($('div[id='+pNum+']').length > 0) { |
|
63 | if($('div[id='+pNum+']').length > 0) { | |
@@ -72,19 +72,20 b' function showPostPreview(e) {' | |||||
72 | //ajax api |
|
72 | //ajax api | |
73 | else { |
|
73 | else { | |
74 | $.ajax({ |
|
74 | $.ajax({ | |
75 |
|
|
75 | url: '/api/post/' + pNum + '/?truncated' | |
76 | }) |
|
76 | }) | |
77 |
|
|
77 | .success(function(data) { | |
78 |
|
|
78 | // TODO get a json, not post itself | |
79 |
|
|
79 | var postdata = $(data).wrap("<div/>").parent().html(); | |
80 |
|
80 | |||
81 |
|
|
81 | //make preview | |
82 |
|
|
82 | mkPreview(cln, postdata); | |
83 |
|
83 | |||
84 | }) |
|
84 | }) | |
85 |
|
|
85 | .error(function() { | |
86 | cln.innerHTML = gettext('Post not found'); |
|
86 | cln.innerHTML = "<div class=\"post\">" | |
87 | }); |
|
87 | + gettext('Post not found') + "</div>"; | |
|
88 | }); | |||
88 | } |
|
89 | } | |
89 |
|
90 | |||
90 | $del(doc.getElementById(cln.id)); |
|
91 | $del(doc.getElementById(cln.id)); |
@@ -77,4 +77,5 b' function addQuickReply(postId) {' | |||||
77 |
|
77 | |||
78 | $(document).ready(function(){ |
|
78 | $(document).ready(function(){ | |
79 | addGalleryPanel(); |
|
79 | addGalleryPanel(); | |
|
80 | initAutoupdate(); | |||
80 | }); |
|
81 | }); |
@@ -1,14 +1,19 b'' | |||||
1 | {% load i18n %} |
|
1 | {% load i18n %} | |
2 | {% load board %} |
|
2 | {% load board %} | |
3 |
|
3 | |||
4 | <div class="post" id="{{ post.id }}"> |
|
4 | {% if can_bump %} | |
|
5 | <div class="post" id="{{ post.id }}"> | |||
|
6 | {% else %} | |||
|
7 | <div class="post dead_post" id="{{ post.id }}"> | |||
|
8 | {% endif %} | |||
|
9 | ||||
5 | {% if post.image %} |
|
10 | {% if post.image %} | |
6 | <div class="image"> |
|
11 | <div class="image"> | |
7 | <a |
|
12 | <a | |
8 | class="thumb" |
|
13 | class="thumb" | |
9 | href="{{ post.image.url }}"><img |
|
14 | href="{{ post.image.url }}"><img | |
10 | src="{{ post.image.url_200x150 }}" |
|
15 | src="{{ post.image.url_200x150 }}" | |
11 |
alt="{ |
|
16 | alt="{{ post.id }}" | |
12 | data-width="{{ post.image_width }}" |
|
17 | data-width="{{ post.image_width }}" | |
13 | data-height="{{ post.image_height }}"/> |
|
18 | data-height="{{ post.image_height }}"/> | |
14 | </a> |
|
19 | </a> | |
@@ -18,8 +23,10 b'' | |||||
18 | <div class="post-info"> |
|
23 | <div class="post-info"> | |
19 | <span class="title">{{ post.title }}</span> |
|
24 | <span class="title">{{ post.title }}</span> | |
20 | <a class="post_id" href="#{{ post.id }}"> |
|
25 | <a class="post_id" href="#{{ post.id }}"> | |
21 |
( |
|
26 | ({{ post.id }})</a> | |
22 | [{{ post.pub_time }}] |
|
27 | [{{ post.pub_time }}] | |
|
28 | [<a href="#" onclick="javascript:addQuickReply('{{ post.id }}') | |||
|
29 | ; return false;">>></a>] | |||
23 |
|
30 | |||
24 | {% if moderator %} |
|
31 | {% if moderator %} | |
25 | <span class="moderator_info"> |
|
32 | <span class="moderator_info"> | |
@@ -32,24 +39,30 b'' | |||||
32 | {% endif %} |
|
39 | {% endif %} | |
33 | </div> |
|
40 | </div> | |
34 | {% autoescape off %} |
|
41 | {% autoescape off %} | |
35 | {{ post.text.rendered }} |
|
42 | {% if truncated %} | |
|
43 | {{ post.text.rendered|truncatewords_html:50 }} | |||
|
44 | {% else %} | |||
|
45 | {{ post.text.rendered }} | |||
|
46 | {% endif %} | |||
36 | {% endautoescape %} |
|
47 | {% endautoescape %} | |
37 | <div class="refmap"> |
|
48 | {% if post.is_referenced %} | |
38 | {% trans "Replies" %}: |
|
49 | <div class="refmap"> | |
39 | {% for ref_post in post.get_sorted_referenced_posts %} |
|
50 | {% trans "Replies" %}: | |
40 | <a href="{% post_url ref_post.id %}">>>{{ ref_post.id }}</a |
|
51 | {% for ref_post in post.get_sorted_referenced_posts %} | |
41 | >{% if not forloop.last %},{% endif %} |
|
52 | <a href="{% post_url ref_post.id %}">>>{{ ref_post.id }}</a | |
42 | {% endfor %} |
|
53 | >{% if not forloop.last %},{% endif %} | |
43 | </div> |
|
54 | {% endfor %} | |
|
55 | </div> | |||
|
56 | {% endif %} | |||
44 | </div> |
|
57 | </div> | |
45 | {% if post.tags.exists %} |
|
58 | {% if post.tags.exists %} | |
46 | <div class="metadata"> |
|
59 | <div class="metadata"> | |
47 |
|
|
60 | <span class="tags">{% trans 'Tags' %}: | |
48 |
|
|
61 | {% for tag in post.tags.all %} | |
49 |
|
|
62 | <a class="tag" href="{% url 'tag' tag.name %}"> | |
50 |
|
|
63 | {{ tag.name }}</a> | |
51 |
|
|
64 | {% endfor %} | |
52 |
|
|
65 | </span> | |
53 | </div> |
|
66 | </div> | |
54 | {% endif %} |
|
67 | {% endif %} | |
55 | </div> No newline at end of file |
|
68 | </div> |
@@ -13,9 +13,10 b'' | |||||
13 | {% block content %} |
|
13 | {% block content %} | |
14 | {% get_current_language as LANGUAGE_CODE %} |
|
14 | {% get_current_language as LANGUAGE_CODE %} | |
15 |
|
15 | |||
|
16 | <script src="{% static 'js/thread_update.js' %}"></script> | |||
16 | <script src="{% static 'js/thread.js' %}"></script> |
|
17 | <script src="{% static 'js/thread.js' %}"></script> | |
17 |
|
18 | |||
18 |
|
|
19 | {% if posts %} | |
19 | {% cache 600 thread_view posts.0.last_edit_time moderator LANGUAGE_CODE %} |
|
20 | {% cache 600 thread_view posts.0.last_edit_time moderator LANGUAGE_CODE %} | |
20 | {% if bumpable %} |
|
21 | {% if bumpable %} | |
21 | <div class="bar-bg"> |
|
22 | <div class="bar-bg"> | |
@@ -27,7 +28,7 b'' | |||||
27 | </div> |
|
28 | </div> | |
28 | {% endif %} |
|
29 | {% endif %} | |
29 | <div class="thread"> |
|
30 | <div class="thread"> | |
30 |
|
|
31 | {% for post in posts %} | |
31 | {% if bumpable %} |
|
32 | {% if bumpable %} | |
32 | <div class="post" id="{{ post.id }}"> |
|
33 | <div class="post" id="{{ post.id }}"> | |
33 | {% else %} |
|
34 | {% else %} | |
@@ -67,7 +68,7 b'' | |||||
67 | {% autoescape off %} |
|
68 | {% autoescape off %} | |
68 | {{ post.text.rendered }} |
|
69 | {{ post.text.rendered }} | |
69 | {% endautoescape %} |
|
70 | {% endautoescape %} | |
70 |
|
|
71 | {% if post.is_referenced %} | |
71 | <div class="refmap"> |
|
72 | <div class="refmap"> | |
72 | {% trans "Replies" %}: |
|
73 | {% trans "Replies" %}: | |
73 | {% for ref_post in post.get_sorted_referenced_posts %} |
|
74 | {% for ref_post in post.get_sorted_referenced_posts %} | |
@@ -89,15 +90,15 b'' | |||||
89 | </div> |
|
90 | </div> | |
90 | {% endif %} |
|
91 | {% endif %} | |
91 | </div> |
|
92 | </div> | |
92 |
|
|
93 | {% endfor %} | |
93 | </div> |
|
94 | </div> | |
94 | {% endcache %} |
|
95 | {% endcache %} | |
95 |
|
|
96 | {% endif %} | |
96 |
|
97 | |||
97 | <form id="form" enctype="multipart/form-data" method="post" |
|
98 | <form id="form" enctype="multipart/form-data" method="post" | |
98 | >{% csrf_token %} |
|
99 | >{% csrf_token %} | |
99 | <div class="post-form-w"> |
|
100 | <div class="post-form-w"> | |
100 |
|
|
101 | <div class="form-title">{% trans "Reply to thread" %} #{{ posts.0.id }}</div> | |
101 | <div class="post-form"> |
|
102 | <div class="post-form"> | |
102 | <div class="form-row"> |
|
103 | <div class="form-row"> | |
103 | <div class="form-label">{% trans 'Title' %}</div> |
|
104 | <div class="form-label">{% trans 'Title' %}</div> | |
@@ -151,7 +152,7 b'' | |||||
151 |
|
152 | |||
152 | {% get_current_language as LANGUAGE_CODE %} |
|
153 | {% get_current_language as LANGUAGE_CODE %} | |
153 |
|
154 | |||
154 | <span class="metapanel"> |
|
155 | <span class="metapanel" data-last-update="{{ last_update }}"> | |
155 | {% cache 600 thread_meta posts.0.last_edit_time moderator LANGUAGE_CODE %} |
|
156 | {% cache 600 thread_meta posts.0.last_edit_time moderator LANGUAGE_CODE %} | |
156 | {{ posts.0.get_reply_count }} {% trans 'replies' %}, |
|
157 | {{ posts.0.get_reply_count }} {% trans 'replies' %}, | |
157 | {{ posts.0.get_images_count }} {% trans 'images' %}. |
|
158 | {{ posts.0.get_images_count }} {% trans 'images' %}. |
@@ -53,4 +53,6 b" urlpatterns = patterns(''," | |||||
53 |
|
53 | |||
54 | # API |
|
54 | # API | |
55 | url(r'^api/post/(?P<post_id>\w+)/$', views.get_post, name="get_post"), |
|
55 | url(r'^api/post/(?P<post_id>\w+)/$', views.get_post, name="get_post"), | |
|
56 | url(r'^api/diff_thread/(?P<thread_id>\w+)/(?P<last_update_time>\w+)/$', | |||
|
57 | views.api_get_threaddiff, name="get_thread_diff"), | |||
56 | ) |
|
58 | ) |
@@ -1,5 +1,11 b'' | |||||
1 | import hashlib |
|
1 | import hashlib | |
|
2 | import json | |||
2 | import string |
|
3 | import string | |
|
4 | import time | |||
|
5 | import calendar | |||
|
6 | ||||
|
7 | from datetime import datetime | |||
|
8 | ||||
3 | from django.core import serializers |
|
9 | from django.core import serializers | |
4 | from django.core.urlresolvers import reverse |
|
10 | from django.core.urlresolvers import reverse | |
5 | from django.http import HttpResponseRedirect |
|
11 | from django.http import HttpResponseRedirect | |
@@ -8,6 +14,7 b' from django.template import RequestConte' | |||||
8 | from django.shortcuts import render, redirect, get_object_or_404 |
|
14 | from django.shortcuts import render, redirect, get_object_or_404 | |
9 | from django.utils import timezone |
|
15 | from django.utils import timezone | |
10 | from django.db import transaction |
|
16 | from django.db import transaction | |
|
17 | import math | |||
11 |
|
18 | |||
12 | from boards import forms |
|
19 | from boards import forms | |
13 | import boards |
|
20 | import boards | |
@@ -210,6 +217,7 b' def thread(request, post_id):' | |||||
210 | context['bumplimit_progress'] = str( |
|
217 | context['bumplimit_progress'] = str( | |
211 | float(context['posts_left']) / |
|
218 | float(context['posts_left']) / | |
212 | neboard.settings.MAX_POSTS_PER_THREAD * 100) |
|
219 | neboard.settings.MAX_POSTS_PER_THREAD * 100) | |
|
220 | context["last_update"] = _datetime_to_epoch(posts[0].last_edit_time) | |||
213 |
|
221 | |||
214 | return render(request, 'boards/thread.html', context) |
|
222 | return render(request, 'boards/thread.html', context) | |
215 |
|
223 | |||
@@ -245,23 +253,23 b' def settings(request):' | |||||
245 | is_moderator = user.is_moderator() |
|
253 | is_moderator = user.is_moderator() | |
246 |
|
254 | |||
247 | if request.method == 'POST': |
|
255 | if request.method == 'POST': | |
248 |
|
|
256 | with transaction.commit_on_success(): | |
249 |
|
|
257 | if is_moderator: | |
250 |
|
|
258 | form = ModeratorSettingsForm(request.POST, | |
251 | error_class=PlainErrorList) |
|
259 | error_class=PlainErrorList) | |
252 |
|
|
260 | else: | |
253 |
|
|
261 | form = SettingsForm(request.POST, error_class=PlainErrorList) | |
254 |
|
262 | |||
255 |
|
|
263 | if form.is_valid(): | |
256 |
|
|
264 | selected_theme = form.cleaned_data['theme'] | |
257 |
|
265 | |||
258 |
|
|
266 | user.save_setting('theme', selected_theme) | |
259 |
|
267 | |||
260 |
|
|
268 | if is_moderator: | |
261 |
|
|
269 | moderate = form.cleaned_data['moderate'] | |
262 |
|
|
270 | user.save_setting(SETTING_MODERATE, moderate) | |
263 |
|
271 | |||
264 |
|
|
272 | return redirect(settings) | |
265 | else: |
|
273 | else: | |
266 | selected_theme = _get_theme(request) |
|
274 | selected_theme = _get_theme(request) | |
267 |
|
275 | |||
@@ -318,7 +326,7 b' def delete(request, post_id):' | |||||
318 | if user.is_moderator(): |
|
326 | if user.is_moderator(): | |
319 | # TODO Show confirmation page before deletion |
|
327 | # TODO Show confirmation page before deletion | |
320 | Post.objects.delete_post(post) |
|
328 | Post.objects.delete_post(post) | |
321 |
|
329 | |||
322 | if not post.thread: |
|
330 | if not post.thread: | |
323 | return _redirect_to_next(request) |
|
331 | return _redirect_to_next(request) | |
324 | else: |
|
332 | else: | |
@@ -408,13 +416,43 b' def api_get_post(request, post_id):' | |||||
408 | return HttpResponse(content=json) |
|
416 | return HttpResponse(content=json) | |
409 |
|
417 | |||
410 |
|
418 | |||
|
419 | def api_get_threaddiff(request, thread_id, last_update_time): | |||
|
420 | """Get posts that were changed or added since time""" | |||
|
421 | ||||
|
422 | thread = get_object_or_404(Post, id=thread_id) | |||
|
423 | ||||
|
424 | filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000, | |||
|
425 | timezone.get_current_timezone()) | |||
|
426 | ||||
|
427 | json_data = { | |||
|
428 | 'added': [], | |||
|
429 | 'updated': [], | |||
|
430 | 'last_update': None, | |||
|
431 | } | |||
|
432 | added_posts = Post.objects.filter(thread=thread, pub_time__gt=filter_time) | |||
|
433 | updated_posts = Post.objects.filter(thread=thread, | |||
|
434 | pub_time__lt=filter_time, | |||
|
435 | last_edit_time__gt=filter_time) | |||
|
436 | for post in added_posts: | |||
|
437 | json_data['added'].append(get_post(request, post.id).content.strip()) | |||
|
438 | for post in updated_posts: | |||
|
439 | json_data['updated'].append(get_post(request, post.id).content.strip()) | |||
|
440 | json_data['last_update'] = _datetime_to_epoch(thread.last_edit_time) | |||
|
441 | ||||
|
442 | return HttpResponse(content=json.dumps(json_data)) | |||
|
443 | ||||
|
444 | ||||
411 | def get_post(request, post_id): |
|
445 | def get_post(request, post_id): | |
412 | """Get the html of a post. Used for popups.""" |
|
446 | """Get the html of a post. Used for popups.""" | |
413 |
|
447 | |||
414 | post = get_object_or_404(Post, id=post_id) |
|
448 | post = get_object_or_404(Post, id=post_id) | |
|
449 | thread = post.thread | |||
415 |
|
450 | |||
416 | context = RequestContext(request) |
|
451 | context = RequestContext(request) | |
417 | context["post"] = post |
|
452 | context["post"] = post | |
|
453 | context["can_bump"] = thread.can_bump() | |||
|
454 | if "truncated" in request.GET: | |||
|
455 | context["truncated"] = True | |||
418 |
|
456 | |||
419 | return render(request, 'boards/post.html', context) |
|
457 | return render(request, 'boards/post.html', context) | |
420 |
|
458 | |||
@@ -518,3 +556,9 b' def _remove_invalid_links(text):' | |||||
518 | text = string.replace(text, '>>' + id, id) |
|
556 | text = string.replace(text, '>>' + id, id) | |
519 |
|
557 | |||
520 | return text |
|
558 | return text | |
|
559 | ||||
|
560 | ||||
|
561 | def _datetime_to_epoch(datetime): | |||
|
562 | return int(time.mktime(timezone.localtime( | |||
|
563 | datetime,timezone.get_current_timezone()).timetuple()) | |||
|
564 | * 1000000 + datetime.microsecond) No newline at end of file |
@@ -219,7 +219,7 b' LAST_REPLIES_COUNT = 3' | |||||
219 | ENABLE_CAPTCHA = False |
|
219 | ENABLE_CAPTCHA = False | |
220 | # if user tries to post before CAPTCHA_DEFAULT_SAFE_TIME. Captcha will be shown |
|
220 | # if user tries to post before CAPTCHA_DEFAULT_SAFE_TIME. Captcha will be shown | |
221 | CAPTCHA_DEFAULT_SAFE_TIME = 30 # seconds |
|
221 | CAPTCHA_DEFAULT_SAFE_TIME = 30 # seconds | |
222 |
POSTING_DELAY = |
|
222 | POSTING_DELAY = 20 # seconds | |
223 |
|
223 | |||
224 |
|
224 | |||
225 | def custom_show_toolbar(request): |
|
225 | def custom_show_toolbar(request): |
@@ -9,6 +9,8 b' denied". Use second only for autoban for' | |||||
9 | [DONE] Clean up tests and make them run ALWAYS |
|
9 | [DONE] Clean up tests and make them run ALWAYS | |
10 | [DONE] Use transactions in tests |
|
10 | [DONE] Use transactions in tests | |
11 |
|
11 | |||
|
12 | [IN PROGRESS] Thread autoupdate (JS + API) | |||
|
13 | ||||
12 | [NOT STARTED] Tree view (JS) |
|
14 | [NOT STARTED] Tree view (JS) | |
13 | [NOT STARTED] Adding tags to images filename |
|
15 | [NOT STARTED] Adding tags to images filename | |
14 | [NOT STARTED] Federative network for s2s communication |
|
16 | [NOT STARTED] Federative network for s2s communication | |
@@ -16,7 +18,6 b' denied". Use second only for autoban for' | |||||
16 | [NOT STARTED] Bitmessage gate |
|
18 | [NOT STARTED] Bitmessage gate | |
17 | [NOT STARTED] Notification engine |
|
19 | [NOT STARTED] Notification engine | |
18 | [NOT STARTED] Javascript disabling engine |
|
20 | [NOT STARTED] Javascript disabling engine | |
19 | [NOT STARTED] Thread autoupdate (JS + API) |
|
|||
20 | [NOT STARTED] Group tags by first letter in all tags list |
|
21 | [NOT STARTED] Group tags by first letter in all tags list | |
21 | [NOT STARTED] Show board speed in the lower panel (posts per day) |
|
22 | [NOT STARTED] Show board speed in the lower panel (posts per day) | |
22 | [NOT STARTED] Character counter in the post field |
|
23 | [NOT STARTED] Character counter in the post field | |
@@ -30,6 +31,7 b' and move everything that is used only in' | |||||
30 | post or its part (delimited by N characters) into quote of the new post. |
|
31 | post or its part (delimited by N characters) into quote of the new post. | |
31 | [NOT STARTED] Ban confirmation page with reason |
|
32 | [NOT STARTED] Ban confirmation page with reason | |
32 | [NOT STARTED] Post deletion confirmation page |
|
33 | [NOT STARTED] Post deletion confirmation page | |
|
34 | [NOT STARTED] Moderating page. Tags editing and adding | |||
33 |
|
35 | |||
34 | = Bugs = |
|
36 | = Bugs = | |
35 | [DONE] Fix bug with creating threads from tag view |
|
37 | [DONE] Fix bug with creating threads from tag view |
General Comments 0
You need to be logged in to leave comments.
Login now