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