##// END OF EJS Templates
Speed up page loading by caching JS translation catalog
neko259 -
r423:3d225171 default
parent child Browse files
Show More
@@ -1,62 +1,62 b''
1 {% load staticfiles %}
1 {% load staticfiles %}
2 {% load i18n %}
2 {% load i18n %}
3 {% load l10n %}
3 {% load l10n %}
4 {% load static from staticfiles %}
4 {% load static from staticfiles %}
5
5
6 <!DOCTYPE html>
6 <!DOCTYPE html>
7 <html>
7 <html>
8 <head>
8 <head>
9 <link rel="stylesheet" type="text/css"
9 <link rel="stylesheet" type="text/css"
10 href="{% static 'css/base.css' %}" media="all"/>
10 href="{% static 'css/base.css' %}" media="all"/>
11 <link rel="stylesheet" type="text/css"
11 <link rel="stylesheet" type="text/css"
12 href="{% static theme_css %}" media="all"/>
12 href="{% static theme_css %}" media="all"/>
13 <link rel="alternate" type="application/rss+xml" href="rss/" title=
13 <link rel="alternate" type="application/rss+xml" href="rss/" title=
14 "{% trans 'Feed' %}"/>
14 "{% trans 'Feed' %}"/>
15
15
16 <link rel="icon" type="image/png"
16 <link rel="icon" type="image/png"
17 href="{% static 'favicon.png' %}">
17 href="{% static 'favicon.png' %}">
18
18
19 <meta name="viewport" content="width=device-width, initial-scale=1"/>
19 <meta name="viewport" content="width=device-width, initial-scale=1"/>
20 <meta charset="utf-8"/>
20 <meta charset="utf-8"/>
21
21
22 {% block head %}{% endblock %}
22 {% block head %}{% endblock %}
23 </head>
23 </head>
24 <body>
24 <body>
25 <script src="{% static 'js/jquery-2.0.1.min.js' %}"></script>
25 <script src="{% static 'js/jquery-2.0.1.min.js' %}"></script>
26 <script src="{% static 'js/jquery-ui-1.10.3.custom.min.js' %}"></script>
26 <script src="{% static 'js/jquery-ui-1.10.3.custom.min.js' %}"></script>
27 <script src="{% static 'js/jquery.mousewheel.js' %}"></script>
27 <script src="{% static 'js/jquery.mousewheel.js' %}"></script>
28 <script src="{% url 'django.views.i18n.javascript_catalog' %}"></script>
28 <script src="{% url 'js_info_dict' %}"></script>
29 <script src="{% static 'js/panel.js' %}"></script>
29 <script src="{% static 'js/panel.js' %}"></script>
30 <script src="{% static 'js/popup.js' %}"></script>
30 <script src="{% static 'js/popup.js' %}"></script>
31 <script src="{% static 'js/image.js' %}"></script>
31 <script src="{% static 'js/image.js' %}"></script>
32 <script src="{% static 'js/refpopup.js' %}"></script>
32 <script src="{% static 'js/refpopup.js' %}"></script>
33 <script src="{% static 'js/main.js' %}"></script>
33 <script src="{% static 'js/main.js' %}"></script>
34
34
35 <div class="navigation_panel">
35 <div class="navigation_panel">
36 <a class="link" href="{% url 'index' %}">{% trans "All threads" %}</a>
36 <a class="link" href="{% url 'index' %}">{% trans "All threads" %}</a>
37 {% for tag in tags %}
37 {% for tag in tags %}
38 <a class="tag" href="{% url 'tag' tag_name=tag.name %}"
38 <a class="tag" href="{% url 'tag' tag_name=tag.name %}"
39 >#{{ tag.name }}</a>,
39 >#{{ tag.name }}</a>,
40 {% endfor %}
40 {% endfor %}
41 <a class="tag" href="{% url 'tags' %}" title="{% trans 'Tag management' %}"
41 <a class="tag" href="{% url 'tags' %}" title="{% trans 'Tag management' %}"
42 >[...]</a>
42 >[...]</a>
43 <a class="link" href="{% url 'settings' %}">{% trans 'Settings' %}</a>
43 <a class="link" href="{% url 'settings' %}">{% trans 'Settings' %}</a>
44 </div>
44 </div>
45
45
46 {% block content %}{% endblock %}
46 {% block content %}{% endblock %}
47
47
48 <div class="navigation_panel">
48 <div class="navigation_panel">
49 {% block metapanel %}{% endblock %}
49 {% block metapanel %}{% endblock %}
50 [<a href="{% url "login" %}">{% trans 'Login' %}</a>]
50 [<a href="{% url "login" %}">{% trans 'Login' %}</a>]
51 {% with ppd=posts_per_day|floatformat:2 %}
51 {% with ppd=posts_per_day|floatformat:2 %}
52 {% blocktrans %}Speed: {{ ppd }} posts per day{% endblocktrans %}
52 {% blocktrans %}Speed: {{ ppd }} posts per day{% endblocktrans %}
53 {% endwith %}
53 {% endwith %}
54 <a class="link" href="#top">{% trans 'Up' %}</a>
54 <a class="link" href="#top">{% trans 'Up' %}</a>
55 </div>
55 </div>
56
56
57 <div class="footer">
57 <div class="footer">
58 <!-- Put your banners here -->
58 <!-- Put your banners here -->
59 </div>
59 </div>
60
60
61 </body>
61 </body>
62 </html>
62 </html>
@@ -1,58 +1,58 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
4
5 js_info_dict = {
5 js_info_dict = {
6 'packages': ('boards',),
6 'packages': ('boards',),
7 }
7 }
8
8
9 urlpatterns = patterns('',
9 urlpatterns = patterns('',
10
10
11 # /boards/
11 # /boards/
12 url(r'^$', views.index, name='index'),
12 url(r'^$', views.index, name='index'),
13 # /boards/page/
13 # /boards/page/
14 url(r'^page/(?P<page>\w+)/$', views.index, name='index'),
14 url(r'^page/(?P<page>\w+)/$', views.index, name='index'),
15
15
16 # login page
16 # login page
17 url(r'^login/$', views.login, name='login'),
17 url(r'^login/$', views.login, name='login'),
18
18
19 # /boards/tag/tag_name/
19 # /boards/tag/tag_name/
20 url(r'^tag/(?P<tag_name>\w+)/$', views.tag, name='tag'),
20 url(r'^tag/(?P<tag_name>\w+)/$', views.tag, name='tag'),
21 # /boards/tag/tag_id/page/
21 # /boards/tag/tag_id/page/
22 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/$', views.tag, name='tag'),
22 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/$', views.tag, name='tag'),
23
23
24 # /boards/tag/tag_name/unsubscribe/
24 # /boards/tag/tag_name/unsubscribe/
25 url(r'^tag/(?P<tag_name>\w+)/subscribe/$', views.tag_subscribe,
25 url(r'^tag/(?P<tag_name>\w+)/subscribe/$', views.tag_subscribe,
26 name='tag_subscribe'),
26 name='tag_subscribe'),
27 # /boards/tag/tag_name/unsubscribe/
27 # /boards/tag/tag_name/unsubscribe/
28 url(r'^tag/(?P<tag_name>\w+)/unsubscribe/$', views.tag_unsubscribe,
28 url(r'^tag/(?P<tag_name>\w+)/unsubscribe/$', views.tag_unsubscribe,
29 name='tag_unsubscribe'),
29 name='tag_unsubscribe'),
30
30
31 # /boards/thread/
31 # /boards/thread/
32 url(r'^thread/(?P<post_id>\w+)/$', views.thread, name='thread'),
32 url(r'^thread/(?P<post_id>\w+)/$', views.thread, name='thread'),
33 url(r'^settings/$', views.settings, name='settings'),
33 url(r'^settings/$', views.settings, name='settings'),
34 url(r'^tags/$', views.all_tags, name='tags'),
34 url(r'^tags/$', views.all_tags, name='tags'),
35 url(r'^captcha/', include('captcha.urls')),
35 url(r'^captcha/', include('captcha.urls')),
36 url(r'^jump/(?P<post_id>\w+)/$', views.jump_to_post, name='jumper'),
36 url(r'^jump/(?P<post_id>\w+)/$', views.jump_to_post, name='jumper'),
37 url(r'^authors/$', views.authors, name='authors'),
37 url(r'^authors/$', views.authors, name='authors'),
38 url(r'^delete/(?P<post_id>\w+)/$', views.delete, name='delete'),
38 url(r'^delete/(?P<post_id>\w+)/$', views.delete, name='delete'),
39 url(r'^ban/(?P<post_id>\w+)/$', views.ban, name='ban'),
39 url(r'^ban/(?P<post_id>\w+)/$', views.ban, name='ban'),
40
40
41 url(r'^banned/$', views.you_are_banned, name='banned'),
41 url(r'^banned/$', views.you_are_banned, name='banned'),
42 url(r'^staticpage/(?P<name>\w+)/$', views.static_page, name='staticpage'),
42 url(r'^staticpage/(?P<name>\w+)/$', views.static_page, name='staticpage'),
43
43
44 # RSS feeds
44 # RSS feeds
45 url(r'^rss/$', AllThreadsFeed()),
45 url(r'^rss/$', AllThreadsFeed()),
46 url(r'^page/(?P<page>\w+)/rss/$', AllThreadsFeed()),
46 url(r'^page/(?P<page>\w+)/rss/$', AllThreadsFeed()),
47 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
47 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
48 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
48 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
49 url(r'^thread/(?P<post_id>\w+)/rss/$', ThreadPostsFeed()),
49 url(r'^thread/(?P<post_id>\w+)/rss/$', ThreadPostsFeed()),
50
50
51 # i18n
51 # i18n
52 url(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
52 url(r'^jsi18n/$', 'boards.views.cached_js_catalog', js_info_dict, name='js_info_dict'),
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+)/$',
56 url(r'^api/diff_thread/(?P<thread_id>\w+)/(?P<last_update_time>\w+)/$',
57 views.api_get_threaddiff, name="get_thread_diff"),
57 views.api_get_threaddiff, name="get_thread_diff"),
58 )
58 )
@@ -1,571 +1,577 b''
1 import hashlib
1 import hashlib
2 import json
2 import json
3 import string
3 import string
4 import time
4 import time
5 from datetime import datetime
5 from datetime import datetime
6 import re
6 import re
7
7
8 from django.core import serializers
8 from django.core import serializers
9 from django.core.urlresolvers import reverse
9 from django.core.urlresolvers import reverse
10 from django.http import HttpResponseRedirect
10 from django.http import HttpResponseRedirect
11 from django.http.response import HttpResponse
11 from django.http.response import HttpResponse
12 from django.template import RequestContext
12 from django.template import RequestContext
13 from django.shortcuts import render, redirect, get_object_or_404
13 from django.shortcuts import render, redirect, get_object_or_404
14 from django.utils import timezone
14 from django.utils import timezone
15 from django.db import transaction
15 from django.db import transaction
16 from django.views.decorators.cache import cache_page
17 from django.views.i18n import javascript_catalog
16
18
17 from boards import forms
19 from boards import forms
18 import boards
20 import boards
19 from boards import utils
21 from boards import utils
20 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
22 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
21 ThreadCaptchaForm, PostCaptchaForm, LoginForm, ModeratorSettingsForm
23 ThreadCaptchaForm, PostCaptchaForm, LoginForm, ModeratorSettingsForm
22 from boards.models import Post, Tag, Ban, User
24 from boards.models import Post, Tag, Ban, User
23 from boards.models.post import SETTING_MODERATE, REGEX_REPLY
25 from boards.models.post import SETTING_MODERATE, REGEX_REPLY
24 from boards.models.user import RANK_USER
26 from boards.models.user import RANK_USER
25 from boards import authors
27 from boards import authors
26 from boards.utils import get_client_ip
28 from boards.utils import get_client_ip
27 import neboard
29 import neboard
28
30
29
31
30 BAN_REASON_SPAM = 'Autoban: spam bot'
32 BAN_REASON_SPAM = 'Autoban: spam bot'
31
33
32
34
33 def index(request, page=0):
35 def index(request, page=0):
34 context = _init_default_context(request)
36 context = _init_default_context(request)
35
37
36 if utils.need_include_captcha(request):
38 if utils.need_include_captcha(request):
37 threadFormClass = ThreadCaptchaForm
39 threadFormClass = ThreadCaptchaForm
38 kwargs = {'request': request}
40 kwargs = {'request': request}
39 else:
41 else:
40 threadFormClass = ThreadForm
42 threadFormClass = ThreadForm
41 kwargs = {}
43 kwargs = {}
42
44
43 if request.method == 'POST':
45 if request.method == 'POST':
44 form = threadFormClass(request.POST, request.FILES,
46 form = threadFormClass(request.POST, request.FILES,
45 error_class=PlainErrorList, **kwargs)
47 error_class=PlainErrorList, **kwargs)
46 form.session = request.session
48 form.session = request.session
47
49
48 if form.is_valid():
50 if form.is_valid():
49 return _new_post(request, form)
51 return _new_post(request, form)
50 if form.need_to_ban:
52 if form.need_to_ban:
51 # Ban user because he is suspected to be a bot
53 # Ban user because he is suspected to be a bot
52 _ban_current_user(request)
54 _ban_current_user(request)
53 else:
55 else:
54 form = threadFormClass(error_class=PlainErrorList, **kwargs)
56 form = threadFormClass(error_class=PlainErrorList, **kwargs)
55
57
56 threads = []
58 threads = []
57 for thread_to_show in Post.objects.get_threads(page=int(page)):
59 for thread_to_show in Post.objects.get_threads(page=int(page)):
58 threads.append(_get_template_thread(thread_to_show))
60 threads.append(_get_template_thread(thread_to_show))
59
61
60 # TODO Make this generic for tag and threads list pages
62 # TODO Make this generic for tag and threads list pages
61 context['threads'] = None if len(threads) == 0 else threads
63 context['threads'] = None if len(threads) == 0 else threads
62 context['form'] = form
64 context['form'] = form
63
65
64 page_count = Post.objects.get_thread_page_count()
66 page_count = Post.objects.get_thread_page_count()
65 context['pages'] = range(page_count)
67 context['pages'] = range(page_count)
66 page = int(page)
68 page = int(page)
67 if page < page_count - 1:
69 if page < page_count - 1:
68 context['next_page'] = str(page + 1)
70 context['next_page'] = str(page + 1)
69 if page > 0:
71 if page > 0:
70 context['prev_page'] = str(page - 1)
72 context['prev_page'] = str(page - 1)
71
73
72 return render(request, 'boards/posting_general.html',
74 return render(request, 'boards/posting_general.html',
73 context)
75 context)
74
76
75
77
76 @transaction.atomic
78 @transaction.atomic
77 def _new_post(request, form, opening_post=None):
79 def _new_post(request, form, opening_post=None):
78 """Add a new post (in thread or as a reply)."""
80 """Add a new post (in thread or as a reply)."""
79
81
80 ip = get_client_ip(request)
82 ip = get_client_ip(request)
81 is_banned = Ban.objects.filter(ip=ip).exists()
83 is_banned = Ban.objects.filter(ip=ip).exists()
82
84
83 if is_banned:
85 if is_banned:
84 return redirect(you_are_banned)
86 return redirect(you_are_banned)
85
87
86 data = form.cleaned_data
88 data = form.cleaned_data
87
89
88 title = data['title']
90 title = data['title']
89 text = data['text']
91 text = data['text']
90
92
91 text = _remove_invalid_links(text)
93 text = _remove_invalid_links(text)
92
94
93 if 'image' in data.keys():
95 if 'image' in data.keys():
94 image = data['image']
96 image = data['image']
95 else:
97 else:
96 image = None
98 image = None
97
99
98 tags = []
100 tags = []
99
101
100 if not opening_post:
102 if not opening_post:
101 tag_strings = data['tags']
103 tag_strings = data['tags']
102
104
103 if tag_strings:
105 if tag_strings:
104 tag_strings = tag_strings.split(' ')
106 tag_strings = tag_strings.split(' ')
105 for tag_name in tag_strings:
107 for tag_name in tag_strings:
106 tag_name = string.lower(tag_name.strip())
108 tag_name = string.lower(tag_name.strip())
107 if len(tag_name) > 0:
109 if len(tag_name) > 0:
108 tag, created = Tag.objects.get_or_create(name=tag_name)
110 tag, created = Tag.objects.get_or_create(name=tag_name)
109 tags.append(tag)
111 tags.append(tag)
110 post_thread = None
112 post_thread = None
111 else:
113 else:
112 post_thread = opening_post.thread_new
114 post_thread = opening_post.thread_new
113
115
114 post = Post.objects.create_post(title=title, text=text, ip=ip,
116 post = Post.objects.create_post(title=title, text=text, ip=ip,
115 thread=post_thread, image=image,
117 thread=post_thread, image=image,
116 tags=tags, user=_get_user(request))
118 tags=tags, user=_get_user(request))
117
119
118 thread_to_show = (opening_post.id if opening_post else post.id)
120 thread_to_show = (opening_post.id if opening_post else post.id)
119
121
120 if opening_post:
122 if opening_post:
121 return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) +
123 return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) +
122 '#' + str(post.id))
124 '#' + str(post.id))
123 else:
125 else:
124 return redirect(thread, post_id=thread_to_show)
126 return redirect(thread, post_id=thread_to_show)
125
127
126
128
127 def tag(request, tag_name, page=0):
129 def tag(request, tag_name, page=0):
128 """
130 """
129 Get all tag threads. Threads are split in pages, so some page is
131 Get all tag threads. Threads are split in pages, so some page is
130 requested. Default page is 0.
132 requested. Default page is 0.
131 """
133 """
132
134
133 tag = get_object_or_404(Tag, name=tag_name)
135 tag = get_object_or_404(Tag, name=tag_name)
134 threads = []
136 threads = []
135 for thread_to_show in Post.objects.get_threads(page=int(page), tag=tag):
137 for thread_to_show in Post.objects.get_threads(page=int(page), tag=tag):
136 threads.append(_get_template_thread(thread_to_show))
138 threads.append(_get_template_thread(thread_to_show))
137
139
138 if request.method == 'POST':
140 if request.method == 'POST':
139 form = ThreadForm(request.POST, request.FILES,
141 form = ThreadForm(request.POST, request.FILES,
140 error_class=PlainErrorList)
142 error_class=PlainErrorList)
141 form.session = request.session
143 form.session = request.session
142
144
143 if form.is_valid():
145 if form.is_valid():
144 return _new_post(request, form)
146 return _new_post(request, form)
145 if form.need_to_ban:
147 if form.need_to_ban:
146 # Ban user because he is suspected to be a bot
148 # Ban user because he is suspected to be a bot
147 _ban_current_user(request)
149 _ban_current_user(request)
148 else:
150 else:
149 form = forms.ThreadForm(initial={'tags': tag_name},
151 form = forms.ThreadForm(initial={'tags': tag_name},
150 error_class=PlainErrorList)
152 error_class=PlainErrorList)
151
153
152 context = _init_default_context(request)
154 context = _init_default_context(request)
153 context['threads'] = None if len(threads) == 0 else threads
155 context['threads'] = None if len(threads) == 0 else threads
154 context['tag'] = tag
156 context['tag'] = tag
155
157
156 page_count = Post.objects.get_thread_page_count(tag=tag)
158 page_count = Post.objects.get_thread_page_count(tag=tag)
157 context['pages'] = range(page_count)
159 context['pages'] = range(page_count)
158 page = int(page)
160 page = int(page)
159 if page < page_count - 1:
161 if page < page_count - 1:
160 context['next_page'] = str(page + 1)
162 context['next_page'] = str(page + 1)
161 if page > 0:
163 if page > 0:
162 context['prev_page'] = str(page - 1)
164 context['prev_page'] = str(page - 1)
163
165
164 context['form'] = form
166 context['form'] = form
165
167
166 return render(request, 'boards/posting_general.html',
168 return render(request, 'boards/posting_general.html',
167 context)
169 context)
168
170
169
171
170 def thread(request, post_id):
172 def thread(request, post_id):
171 """Get all thread posts"""
173 """Get all thread posts"""
172
174
173 if utils.need_include_captcha(request):
175 if utils.need_include_captcha(request):
174 postFormClass = PostCaptchaForm
176 postFormClass = PostCaptchaForm
175 kwargs = {'request': request}
177 kwargs = {'request': request}
176 else:
178 else:
177 postFormClass = PostForm
179 postFormClass = PostForm
178 kwargs = {}
180 kwargs = {}
179
181
180 if request.method == 'POST':
182 if request.method == 'POST':
181 form = postFormClass(request.POST, request.FILES,
183 form = postFormClass(request.POST, request.FILES,
182 error_class=PlainErrorList, **kwargs)
184 error_class=PlainErrorList, **kwargs)
183 form.session = request.session
185 form.session = request.session
184
186
185 opening_post = get_object_or_404(Post, id=post_id)
187 opening_post = get_object_or_404(Post, id=post_id)
186 if form.is_valid():
188 if form.is_valid():
187 return _new_post(request, form, opening_post)
189 return _new_post(request, form, opening_post)
188 if form.need_to_ban:
190 if form.need_to_ban:
189 # Ban user because he is suspected to be a bot
191 # Ban user because he is suspected to be a bot
190 _ban_current_user(request)
192 _ban_current_user(request)
191 else:
193 else:
192 form = postFormClass(error_class=PlainErrorList, **kwargs)
194 form = postFormClass(error_class=PlainErrorList, **kwargs)
193
195
194 thread_to_show = get_object_or_404(Post, id=post_id).thread_new
196 thread_to_show = get_object_or_404(Post, id=post_id).thread_new
195
197
196 context = _init_default_context(request)
198 context = _init_default_context(request)
197
199
198 posts = thread_to_show.get_replies()
200 posts = thread_to_show.get_replies()
199 context['form'] = form
201 context['form'] = form
200 context['bumpable'] = thread_to_show.can_bump()
202 context['bumpable'] = thread_to_show.can_bump()
201 if context['bumpable']:
203 if context['bumpable']:
202 context['posts_left'] = neboard.settings.MAX_POSTS_PER_THREAD - posts\
204 context['posts_left'] = neboard.settings.MAX_POSTS_PER_THREAD - posts\
203 .count()
205 .count()
204 context['bumplimit_progress'] = str(
206 context['bumplimit_progress'] = str(
205 float(context['posts_left']) /
207 float(context['posts_left']) /
206 neboard.settings.MAX_POSTS_PER_THREAD * 100)
208 neboard.settings.MAX_POSTS_PER_THREAD * 100)
207 context["last_update"] = _datetime_to_epoch(thread_to_show.last_edit_time)
209 context["last_update"] = _datetime_to_epoch(thread_to_show.last_edit_time)
208 context["thread"] = thread_to_show
210 context["thread"] = thread_to_show
209
211
210 return render(request, 'boards/thread.html', context)
212 return render(request, 'boards/thread.html', context)
211
213
212
214
213 def login(request):
215 def login(request):
214 """Log in with user id"""
216 """Log in with user id"""
215
217
216 context = _init_default_context(request)
218 context = _init_default_context(request)
217
219
218 if request.method == 'POST':
220 if request.method == 'POST':
219 form = LoginForm(request.POST, request.FILES,
221 form = LoginForm(request.POST, request.FILES,
220 error_class=PlainErrorList)
222 error_class=PlainErrorList)
221 form.session = request.session
223 form.session = request.session
222
224
223 if form.is_valid():
225 if form.is_valid():
224 user = User.objects.get(user_id=form.cleaned_data['user_id'])
226 user = User.objects.get(user_id=form.cleaned_data['user_id'])
225 request.session['user_id'] = user.id
227 request.session['user_id'] = user.id
226 return redirect(index)
228 return redirect(index)
227
229
228 else:
230 else:
229 form = LoginForm()
231 form = LoginForm()
230
232
231 context['form'] = form
233 context['form'] = form
232
234
233 return render(request, 'boards/login.html', context)
235 return render(request, 'boards/login.html', context)
234
236
235
237
236 def settings(request):
238 def settings(request):
237 """User's settings"""
239 """User's settings"""
238
240
239 context = _init_default_context(request)
241 context = _init_default_context(request)
240 user = _get_user(request)
242 user = _get_user(request)
241 is_moderator = user.is_moderator()
243 is_moderator = user.is_moderator()
242
244
243 if request.method == 'POST':
245 if request.method == 'POST':
244 with transaction.atomic():
246 with transaction.atomic():
245 if is_moderator:
247 if is_moderator:
246 form = ModeratorSettingsForm(request.POST,
248 form = ModeratorSettingsForm(request.POST,
247 error_class=PlainErrorList)
249 error_class=PlainErrorList)
248 else:
250 else:
249 form = SettingsForm(request.POST, error_class=PlainErrorList)
251 form = SettingsForm(request.POST, error_class=PlainErrorList)
250
252
251 if form.is_valid():
253 if form.is_valid():
252 selected_theme = form.cleaned_data['theme']
254 selected_theme = form.cleaned_data['theme']
253
255
254 user.save_setting('theme', selected_theme)
256 user.save_setting('theme', selected_theme)
255
257
256 if is_moderator:
258 if is_moderator:
257 moderate = form.cleaned_data['moderate']
259 moderate = form.cleaned_data['moderate']
258 user.save_setting(SETTING_MODERATE, moderate)
260 user.save_setting(SETTING_MODERATE, moderate)
259
261
260 return redirect(settings)
262 return redirect(settings)
261 else:
263 else:
262 selected_theme = _get_theme(request)
264 selected_theme = _get_theme(request)
263
265
264 if is_moderator:
266 if is_moderator:
265 form = ModeratorSettingsForm(initial={'theme': selected_theme,
267 form = ModeratorSettingsForm(initial={'theme': selected_theme,
266 'moderate': context['moderator']},
268 'moderate': context['moderator']},
267 error_class=PlainErrorList)
269 error_class=PlainErrorList)
268 else:
270 else:
269 form = SettingsForm(initial={'theme': selected_theme},
271 form = SettingsForm(initial={'theme': selected_theme},
270 error_class=PlainErrorList)
272 error_class=PlainErrorList)
271
273
272 context['form'] = form
274 context['form'] = form
273
275
274 return render(request, 'boards/settings.html', context)
276 return render(request, 'boards/settings.html', context)
275
277
276
278
277 def all_tags(request):
279 def all_tags(request):
278 """All tags list"""
280 """All tags list"""
279
281
280 context = _init_default_context(request)
282 context = _init_default_context(request)
281 context['all_tags'] = Tag.objects.get_not_empty_tags()
283 context['all_tags'] = Tag.objects.get_not_empty_tags()
282
284
283 return render(request, 'boards/tags.html', context)
285 return render(request, 'boards/tags.html', context)
284
286
285
287
286 def jump_to_post(request, post_id):
288 def jump_to_post(request, post_id):
287 """Determine thread in which the requested post is and open it's page"""
289 """Determine thread in which the requested post is and open it's page"""
288
290
289 post = get_object_or_404(Post, id=post_id)
291 post = get_object_or_404(Post, id=post_id)
290
292
291 if not post.thread:
293 if not post.thread:
292 return redirect(thread, post_id=post.id)
294 return redirect(thread, post_id=post.id)
293 else:
295 else:
294 return redirect(reverse(thread, kwargs={'post_id': post.thread.id})
296 return redirect(reverse(thread, kwargs={'post_id': post.thread.id})
295 + '#' + str(post.id))
297 + '#' + str(post.id))
296
298
297
299
298 def authors(request):
300 def authors(request):
299 """Show authors list"""
301 """Show authors list"""
300
302
301 context = _init_default_context(request)
303 context = _init_default_context(request)
302 context['authors'] = boards.authors.authors
304 context['authors'] = boards.authors.authors
303
305
304 return render(request, 'boards/authors.html', context)
306 return render(request, 'boards/authors.html', context)
305
307
306
308
307 @transaction.atomic
309 @transaction.atomic
308 def delete(request, post_id):
310 def delete(request, post_id):
309 """Delete post"""
311 """Delete post"""
310
312
311 user = _get_user(request)
313 user = _get_user(request)
312 post = get_object_or_404(Post, id=post_id)
314 post = get_object_or_404(Post, id=post_id)
313
315
314 if user.is_moderator():
316 if user.is_moderator():
315 # TODO Show confirmation page before deletion
317 # TODO Show confirmation page before deletion
316 Post.objects.delete_post(post)
318 Post.objects.delete_post(post)
317
319
318 if not post.thread:
320 if not post.thread:
319 return _redirect_to_next(request)
321 return _redirect_to_next(request)
320 else:
322 else:
321 return redirect(thread, post_id=post.thread.id)
323 return redirect(thread, post_id=post.thread.id)
322
324
323
325
324 @transaction.atomic
326 @transaction.atomic
325 def ban(request, post_id):
327 def ban(request, post_id):
326 """Ban user"""
328 """Ban user"""
327
329
328 user = _get_user(request)
330 user = _get_user(request)
329 post = get_object_or_404(Post, id=post_id)
331 post = get_object_or_404(Post, id=post_id)
330
332
331 if user.is_moderator():
333 if user.is_moderator():
332 # TODO Show confirmation page before ban
334 # TODO Show confirmation page before ban
333 ban, created = Ban.objects.get_or_create(ip=post.poster_ip)
335 ban, created = Ban.objects.get_or_create(ip=post.poster_ip)
334 if created:
336 if created:
335 ban.reason = 'Banned for post ' + str(post_id)
337 ban.reason = 'Banned for post ' + str(post_id)
336 ban.save()
338 ban.save()
337
339
338 return _redirect_to_next(request)
340 return _redirect_to_next(request)
339
341
340
342
341 def you_are_banned(request):
343 def you_are_banned(request):
342 """Show the page that notifies that user is banned"""
344 """Show the page that notifies that user is banned"""
343
345
344 context = _init_default_context(request)
346 context = _init_default_context(request)
345
347
346 ban = get_object_or_404(Ban, ip=utils.get_client_ip(request))
348 ban = get_object_or_404(Ban, ip=utils.get_client_ip(request))
347 context['ban_reason'] = ban.reason
349 context['ban_reason'] = ban.reason
348 return render(request, 'boards/staticpages/banned.html', context)
350 return render(request, 'boards/staticpages/banned.html', context)
349
351
350
352
351 def page_404(request):
353 def page_404(request):
352 """Show page 404 (not found error)"""
354 """Show page 404 (not found error)"""
353
355
354 context = _init_default_context(request)
356 context = _init_default_context(request)
355 return render(request, 'boards/404.html', context)
357 return render(request, 'boards/404.html', context)
356
358
357
359
358 @transaction.atomic
360 @transaction.atomic
359 def tag_subscribe(request, tag_name):
361 def tag_subscribe(request, tag_name):
360 """Add tag to favorites"""
362 """Add tag to favorites"""
361
363
362 user = _get_user(request)
364 user = _get_user(request)
363 tag = get_object_or_404(Tag, name=tag_name)
365 tag = get_object_or_404(Tag, name=tag_name)
364
366
365 if not tag in user.fav_tags.all():
367 if not tag in user.fav_tags.all():
366 user.add_tag(tag)
368 user.add_tag(tag)
367
369
368 return _redirect_to_next(request)
370 return _redirect_to_next(request)
369
371
370
372
371 @transaction.atomic
373 @transaction.atomic
372 def tag_unsubscribe(request, tag_name):
374 def tag_unsubscribe(request, tag_name):
373 """Remove tag from favorites"""
375 """Remove tag from favorites"""
374
376
375 user = _get_user(request)
377 user = _get_user(request)
376 tag = get_object_or_404(Tag, name=tag_name)
378 tag = get_object_or_404(Tag, name=tag_name)
377
379
378 if tag in user.fav_tags.all():
380 if tag in user.fav_tags.all():
379 user.remove_tag(tag)
381 user.remove_tag(tag)
380
382
381 return _redirect_to_next(request)
383 return _redirect_to_next(request)
382
384
383
385
384 def static_page(request, name):
386 def static_page(request, name):
385 """Show a static page that needs only tags list and a CSS"""
387 """Show a static page that needs only tags list and a CSS"""
386
388
387 context = _init_default_context(request)
389 context = _init_default_context(request)
388 return render(request, 'boards/staticpages/' + name + '.html', context)
390 return render(request, 'boards/staticpages/' + name + '.html', context)
389
391
390
392
391 def api_get_post(request, post_id):
393 def api_get_post(request, post_id):
392 """
394 """
393 Get the JSON of a post. This can be
395 Get the JSON of a post. This can be
394 used as and API for external clients.
396 used as and API for external clients.
395 """
397 """
396
398
397 post = get_object_or_404(Post, id=post_id)
399 post = get_object_or_404(Post, id=post_id)
398
400
399 json = serializers.serialize("json", [post], fields=(
401 json = serializers.serialize("json", [post], fields=(
400 "pub_time", "_text_rendered", "title", "text", "image",
402 "pub_time", "_text_rendered", "title", "text", "image",
401 "image_width", "image_height", "replies", "tags"
403 "image_width", "image_height", "replies", "tags"
402 ))
404 ))
403
405
404 return HttpResponse(content=json)
406 return HttpResponse(content=json)
405
407
406
408
407 @transaction.atomic
409 @transaction.atomic
408 def api_get_threaddiff(request, thread_id, last_update_time):
410 def api_get_threaddiff(request, thread_id, last_update_time):
409 """Get posts that were changed or added since time"""
411 """Get posts that were changed or added since time"""
410
412
411 thread = get_object_or_404(Post, id=thread_id).thread_new
413 thread = get_object_or_404(Post, id=thread_id).thread_new
412
414
413 filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000,
415 filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000,
414 timezone.get_current_timezone())
416 timezone.get_current_timezone())
415
417
416 json_data = {
418 json_data = {
417 'added': [],
419 'added': [],
418 'updated': [],
420 'updated': [],
419 'last_update': None,
421 'last_update': None,
420 }
422 }
421 added_posts = Post.objects.filter(thread_new=thread,
423 added_posts = Post.objects.filter(thread_new=thread,
422 pub_time__gt=filter_time)\
424 pub_time__gt=filter_time)\
423 .order_by('pub_time')
425 .order_by('pub_time')
424 updated_posts = Post.objects.filter(thread_new=thread,
426 updated_posts = Post.objects.filter(thread_new=thread,
425 pub_time__lte=filter_time,
427 pub_time__lte=filter_time,
426 last_edit_time__gt=filter_time)
428 last_edit_time__gt=filter_time)
427 for post in added_posts:
429 for post in added_posts:
428 json_data['added'].append(get_post(request, post.id).content.strip())
430 json_data['added'].append(get_post(request, post.id).content.strip())
429 for post in updated_posts:
431 for post in updated_posts:
430 json_data['updated'].append(get_post(request, post.id).content.strip())
432 json_data['updated'].append(get_post(request, post.id).content.strip())
431 json_data['last_update'] = _datetime_to_epoch(thread.last_edit_time)
433 json_data['last_update'] = _datetime_to_epoch(thread.last_edit_time)
432
434
433 return HttpResponse(content=json.dumps(json_data))
435 return HttpResponse(content=json.dumps(json_data))
434
436
435
437
436 def get_post(request, post_id):
438 def get_post(request, post_id):
437 """Get the html of a post. Used for popups."""
439 """Get the html of a post. Used for popups."""
438
440
439 post = get_object_or_404(Post, id=post_id)
441 post = get_object_or_404(Post, id=post_id)
440 thread = post.thread_new
442 thread = post.thread_new
441
443
442 context = RequestContext(request)
444 context = RequestContext(request)
443 context["post"] = post
445 context["post"] = post
444 context["can_bump"] = thread.can_bump()
446 context["can_bump"] = thread.can_bump()
445 if "truncated" in request.GET:
447 if "truncated" in request.GET:
446 context["truncated"] = True
448 context["truncated"] = True
447
449
448 return render(request, 'boards/post.html', context)
450 return render(request, 'boards/post.html', context)
449
451
452 @cache_page(86400)
453 def cached_js_catalog(request, domain='djangojs', packages=None):
454 return javascript_catalog(request, domain, packages)
455
450
456
451 def _get_theme(request, user=None):
457 def _get_theme(request, user=None):
452 """Get user's CSS theme"""
458 """Get user's CSS theme"""
453
459
454 if not user:
460 if not user:
455 user = _get_user(request)
461 user = _get_user(request)
456 theme = user.get_setting('theme')
462 theme = user.get_setting('theme')
457 if not theme:
463 if not theme:
458 theme = neboard.settings.DEFAULT_THEME
464 theme = neboard.settings.DEFAULT_THEME
459
465
460 return theme
466 return theme
461
467
462
468
463 def _init_default_context(request):
469 def _init_default_context(request):
464 """Create context with default values that are used in most views"""
470 """Create context with default values that are used in most views"""
465
471
466 context = RequestContext(request)
472 context = RequestContext(request)
467
473
468 user = _get_user(request)
474 user = _get_user(request)
469 context['user'] = user
475 context['user'] = user
470 context['tags'] = user.get_sorted_fav_tags()
476 context['tags'] = user.get_sorted_fav_tags()
471 context['posts_per_day'] = float(Post.objects.get_posts_per_day())
477 context['posts_per_day'] = float(Post.objects.get_posts_per_day())
472
478
473 theme = _get_theme(request, user)
479 theme = _get_theme(request, user)
474 context['theme'] = theme
480 context['theme'] = theme
475 context['theme_css'] = 'css/' + theme + '/base_page.css'
481 context['theme_css'] = 'css/' + theme + '/base_page.css'
476
482
477 # This shows the moderator panel
483 # This shows the moderator panel
478 moderate = user.get_setting(SETTING_MODERATE)
484 moderate = user.get_setting(SETTING_MODERATE)
479 if moderate == 'True':
485 if moderate == 'True':
480 context['moderator'] = user.is_moderator()
486 context['moderator'] = user.is_moderator()
481 else:
487 else:
482 context['moderator'] = False
488 context['moderator'] = False
483
489
484 return context
490 return context
485
491
486
492
487 def _get_user(request):
493 def _get_user(request):
488 """
494 """
489 Get current user from the session. If the user does not exist, create
495 Get current user from the session. If the user does not exist, create
490 a new one.
496 a new one.
491 """
497 """
492
498
493 session = request.session
499 session = request.session
494 if not 'user_id' in session:
500 if not 'user_id' in session:
495 request.session.save()
501 request.session.save()
496
502
497 md5 = hashlib.md5()
503 md5 = hashlib.md5()
498 md5.update(session.session_key)
504 md5.update(session.session_key)
499 new_id = md5.hexdigest()
505 new_id = md5.hexdigest()
500
506
501 time_now = timezone.now()
507 time_now = timezone.now()
502 user = User.objects.create(user_id=new_id, rank=RANK_USER,
508 user = User.objects.create(user_id=new_id, rank=RANK_USER,
503 registration_time=time_now)
509 registration_time=time_now)
504
510
505 session['user_id'] = user.id
511 session['user_id'] = user.id
506 else:
512 else:
507 user = User.objects.get(id=session['user_id'])
513 user = User.objects.get(id=session['user_id'])
508
514
509 return user
515 return user
510
516
511
517
512 def _redirect_to_next(request):
518 def _redirect_to_next(request):
513 """
519 """
514 If a 'next' parameter was specified, redirect to the next page. This is
520 If a 'next' parameter was specified, redirect to the next page. This is
515 used when the user is required to return to some page after the current
521 used when the user is required to return to some page after the current
516 view has finished its work.
522 view has finished its work.
517 """
523 """
518
524
519 if 'next' in request.GET:
525 if 'next' in request.GET:
520 next_page = request.GET['next']
526 next_page = request.GET['next']
521 return HttpResponseRedirect(next_page)
527 return HttpResponseRedirect(next_page)
522 else:
528 else:
523 return redirect(index)
529 return redirect(index)
524
530
525
531
526 @transaction.atomic
532 @transaction.atomic
527 def _ban_current_user(request):
533 def _ban_current_user(request):
528 """Add current user to the IP ban list"""
534 """Add current user to the IP ban list"""
529
535
530 ip = utils.get_client_ip(request)
536 ip = utils.get_client_ip(request)
531 ban, created = Ban.objects.get_or_create(ip=ip)
537 ban, created = Ban.objects.get_or_create(ip=ip)
532 if created:
538 if created:
533 ban.can_read = False
539 ban.can_read = False
534 ban.reason = BAN_REASON_SPAM
540 ban.reason = BAN_REASON_SPAM
535 ban.save()
541 ban.save()
536
542
537
543
538 def _remove_invalid_links(text):
544 def _remove_invalid_links(text):
539 """
545 """
540 Replace invalid links in posts so that they won't be parsed.
546 Replace invalid links in posts so that they won't be parsed.
541 Invalid links are links to non-existent posts
547 Invalid links are links to non-existent posts
542 """
548 """
543
549
544 for reply_number in re.finditer(REGEX_REPLY, text):
550 for reply_number in re.finditer(REGEX_REPLY, text):
545 post_id = reply_number.group(1)
551 post_id = reply_number.group(1)
546 post = Post.objects.filter(id=post_id)
552 post = Post.objects.filter(id=post_id)
547 if not post.exists():
553 if not post.exists():
548 text = string.replace(text, '>>' + post_id, post_id)
554 text = string.replace(text, '>>' + post_id, post_id)
549
555
550 return text
556 return text
551
557
552
558
553 def _datetime_to_epoch(datetime):
559 def _datetime_to_epoch(datetime):
554 return int(time.mktime(timezone.localtime(
560 return int(time.mktime(timezone.localtime(
555 datetime,timezone.get_current_timezone()).timetuple())
561 datetime,timezone.get_current_timezone()).timetuple())
556 * 1000000 + datetime.microsecond)
562 * 1000000 + datetime.microsecond)
557
563
558
564
559 def _get_template_thread(thread_to_show):
565 def _get_template_thread(thread_to_show):
560 """Get template values for thread"""
566 """Get template values for thread"""
561
567
562 last_replies = thread_to_show.get_last_replies()
568 last_replies = thread_to_show.get_last_replies()
563 skipped_replies_count = thread_to_show.get_replies().count() \
569 skipped_replies_count = thread_to_show.get_replies().count() \
564 - len(last_replies) - 1
570 - len(last_replies) - 1
565 return {
571 return {
566 'thread': thread_to_show,
572 'thread': thread_to_show,
567 'op': thread_to_show.get_replies()[0],
573 'op': thread_to_show.get_replies()[0],
568 'bumpable': thread_to_show.can_bump(),
574 'bumpable': thread_to_show.can_bump(),
569 'last_replies': last_replies,
575 'last_replies': last_replies,
570 'skipped_replies': skipped_replies_count,
576 'skipped_replies': skipped_replies_count,
571 }
577 }
General Comments 0
You need to be logged in to leave comments. Login now