##// END OF EJS Templates
Added autoban by the hidden field (to ban spammers and prevent them from trying to post anything).
neko259 -
r271:ac659dae default
parent child Browse files
Show More
@@ -1,252 +1,254 b''
1 import re
1 import re
2 from captcha.fields import CaptchaField
2 from captcha.fields import CaptchaField
3 from django import forms
3 from django import forms
4 from django.forms.util import ErrorList
4 from django.forms.util import ErrorList
5 from django.utils.translation import ugettext_lazy as _
5 from django.utils.translation import ugettext_lazy as _
6 import time
6 import time
7 from boards.models import TITLE_MAX_LENGTH, User
7 from boards.models import TITLE_MAX_LENGTH, User
8 from neboard import settings
8 from neboard import settings
9 from boards import utils
9 from boards import utils
10
10
11 LAST_POST_TIME = "last_post_time"
11 LAST_POST_TIME = "last_post_time"
12 LAST_LOGIN_TIME = "last_login_time"
12 LAST_LOGIN_TIME = "last_login_time"
13
13
14 LOGIN_DELAY = 60 * 60
14 LOGIN_DELAY = 60 * 60
15
15
16 MAX_TEXT_LENGTH = 30000
16 MAX_TEXT_LENGTH = 30000
17 MAX_IMAGE_SIZE = 8 * 1024 * 1024
17 MAX_IMAGE_SIZE = 8 * 1024 * 1024
18
18
19
19
20 class PlainErrorList(ErrorList):
20 class PlainErrorList(ErrorList):
21 def __unicode__(self):
21 def __unicode__(self):
22 return self.as_text()
22 return self.as_text()
23
23
24 def as_text(self):
24 def as_text(self):
25 return ''.join([u'(!) %s ' % e for e in self])
25 return ''.join([u'(!) %s ' % e for e in self])
26
26
27
27
28 class NeboardForm(forms.Form):
28 class NeboardForm(forms.Form):
29
29
30 def as_p(self):
30 def as_p(self):
31 "Returns this form rendered as HTML <p>s."
31 "Returns this form rendered as HTML <p>s."
32 return self._html_output(
32 return self._html_output(
33 normal_row='<div class="form-row">'
33 normal_row='<div class="form-row">'
34 '<div class="form-label">'
34 '<div class="form-label">'
35 '%(label)s'
35 '%(label)s'
36 '</div>'
36 '</div>'
37 '<div class="form-input">'
37 '<div class="form-input">'
38 '%(field)s'
38 '%(field)s'
39 '</div>'
39 '</div>'
40 '%(help_text)s'
40 '%(help_text)s'
41 '</div>',
41 '</div>',
42 error_row='<div class="form-errors">%s</div>',
42 error_row='<div class="form-errors">%s</div>',
43 row_ender='</p>',
43 row_ender='</p>',
44 help_text_html=' <span class="helptext">%s</span>',
44 help_text_html=' <span class="helptext">%s</span>',
45 errors_on_separate_row=True)
45 errors_on_separate_row=True)
46
46
47
47
48 class PostForm(NeboardForm):
48 class PostForm(NeboardForm):
49
49
50 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False,
50 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False,
51 label=_('Title'))
51 label=_('Title'))
52 text = forms.CharField(widget=forms.Textarea, required=False,
52 text = forms.CharField(widget=forms.Textarea, required=False,
53 label=_('Text'))
53 label=_('Text'))
54 image = forms.ImageField(required=False, label=_('Image'))
54 image = forms.ImageField(required=False, label=_('Image'))
55
55
56 # This field is for spam prevention only
56 # This field is for spam prevention only
57 email = forms.CharField(max_length=100, required=False, label=_('e-mail'),
57 email = forms.CharField(max_length=100, required=False, label=_('e-mail'),
58 widget=forms.TextInput(attrs={
58 widget=forms.TextInput(attrs={
59 'class': 'form-email'}))
59 'class': 'form-email'}))
60
60
61 session = None
61 session = None
62 need_to_ban = False
62
63
63 def clean_title(self):
64 def clean_title(self):
64 title = self.cleaned_data['title']
65 title = self.cleaned_data['title']
65 if title:
66 if title:
66 if len(title) > TITLE_MAX_LENGTH:
67 if len(title) > TITLE_MAX_LENGTH:
67 raise forms.ValidationError(_('Title must have less than %s '
68 raise forms.ValidationError(_('Title must have less than %s '
68 'characters') %
69 'characters') %
69 str(TITLE_MAX_LENGTH))
70 str(TITLE_MAX_LENGTH))
70 return title
71 return title
71
72
72 def clean_text(self):
73 def clean_text(self):
73 text = self.cleaned_data['text']
74 text = self.cleaned_data['text']
74 if text:
75 if text:
75 if len(text) > MAX_TEXT_LENGTH:
76 if len(text) > MAX_TEXT_LENGTH:
76 raise forms.ValidationError(_('Text must have less than %s '
77 raise forms.ValidationError(_('Text must have less than %s '
77 'characters') %
78 'characters') %
78 str(MAX_TEXT_LENGTH))
79 str(MAX_TEXT_LENGTH))
79 return text
80 return text
80
81
81 def clean_image(self):
82 def clean_image(self):
82 image = self.cleaned_data['image']
83 image = self.cleaned_data['image']
83 if image:
84 if image:
84 if image._size > MAX_IMAGE_SIZE:
85 if image._size > MAX_IMAGE_SIZE:
85 raise forms.ValidationError(_('Image must be less than %s '
86 raise forms.ValidationError(_('Image must be less than %s '
86 'bytes') % str(MAX_IMAGE_SIZE))
87 'bytes') % str(MAX_IMAGE_SIZE))
87 return image
88 return image
88
89
89 def clean(self):
90 def clean(self):
90 cleaned_data = super(PostForm, self).clean()
91 cleaned_data = super(PostForm, self).clean()
91
92
92 if not self.session:
93 if not self.session:
93 raise forms.ValidationError('Humans have sessions')
94 raise forms.ValidationError('Humans have sessions')
94
95
95 if cleaned_data['email']:
96 if cleaned_data['email']:
97 self.need_to_ban = True
96 raise forms.ValidationError('A human cannot enter a hidden field')
98 raise forms.ValidationError('A human cannot enter a hidden field')
97
99
98 if not self.errors:
100 if not self.errors:
99 self._clean_text_image()
101 self._clean_text_image()
100
102
101 if not self.errors and self.session:
103 if not self.errors and self.session:
102 self._validate_posting_speed()
104 self._validate_posting_speed()
103
105
104 return cleaned_data
106 return cleaned_data
105
107
106 def _clean_text_image(self):
108 def _clean_text_image(self):
107 text = self.cleaned_data.get('text')
109 text = self.cleaned_data.get('text')
108 image = self.cleaned_data.get('image')
110 image = self.cleaned_data.get('image')
109
111
110 if (not text) and (not image):
112 if (not text) and (not image):
111 error_message = _('Either text or image must be entered.')
113 error_message = _('Either text or image must be entered.')
112 self._errors['text'] = self.error_class([error_message])
114 self._errors['text'] = self.error_class([error_message])
113
115
114 def _validate_posting_speed(self):
116 def _validate_posting_speed(self):
115 can_post = True
117 can_post = True
116
118
117 if LAST_POST_TIME in self.session:
119 if LAST_POST_TIME in self.session:
118 now = time.time()
120 now = time.time()
119 last_post_time = self.session[LAST_POST_TIME]
121 last_post_time = self.session[LAST_POST_TIME]
120
122
121 current_delay = int(now - last_post_time)
123 current_delay = int(now - last_post_time)
122
124
123 if current_delay < settings.POSTING_DELAY:
125 if current_delay < settings.POSTING_DELAY:
124 error_message = _('Wait %s seconds after last posting') % str(
126 error_message = _('Wait %s seconds after last posting') % str(
125 settings.POSTING_DELAY - current_delay)
127 settings.POSTING_DELAY - current_delay)
126 self._errors['text'] = self.error_class([error_message])
128 self._errors['text'] = self.error_class([error_message])
127
129
128 can_post = False
130 can_post = False
129
131
130 if can_post:
132 if can_post:
131 self.session[LAST_POST_TIME] = time.time()
133 self.session[LAST_POST_TIME] = time.time()
132
134
133
135
134 class ThreadForm(PostForm):
136 class ThreadForm(PostForm):
135
137
136 regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE)
138 regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE)
137
139
138 tags = forms.CharField(max_length=100, label=_('Tags'))
140 tags = forms.CharField(max_length=100, label=_('Tags'))
139
141
140 def clean_tags(self):
142 def clean_tags(self):
141 tags = self.cleaned_data['tags']
143 tags = self.cleaned_data['tags']
142
144
143 if tags:
145 if tags:
144 if not self.regex_tags.match(tags):
146 if not self.regex_tags.match(tags):
145 raise forms.ValidationError(
147 raise forms.ValidationError(
146 _('Inappropriate characters in tags.'))
148 _('Inappropriate characters in tags.'))
147
149
148 return tags
150 return tags
149
151
150 def clean(self):
152 def clean(self):
151 cleaned_data = super(ThreadForm, self).clean()
153 cleaned_data = super(ThreadForm, self).clean()
152
154
153 return cleaned_data
155 return cleaned_data
154
156
155
157
156 class PostCaptchaForm(PostForm):
158 class PostCaptchaForm(PostForm):
157 captcha = CaptchaField()
159 captcha = CaptchaField()
158
160
159 def __init__(self, *args, **kwargs):
161 def __init__(self, *args, **kwargs):
160 self.request = kwargs['request']
162 self.request = kwargs['request']
161 del kwargs['request']
163 del kwargs['request']
162
164
163 super(PostCaptchaForm, self).__init__(*args, **kwargs)
165 super(PostCaptchaForm, self).__init__(*args, **kwargs)
164
166
165 def clean(self):
167 def clean(self):
166 cleaned_data = super(PostCaptchaForm, self).clean()
168 cleaned_data = super(PostCaptchaForm, self).clean()
167
169
168 success = self.is_valid()
170 success = self.is_valid()
169 utils.update_captcha_access(self.request, success)
171 utils.update_captcha_access(self.request, success)
170
172
171 if success:
173 if success:
172 return cleaned_data
174 return cleaned_data
173 else:
175 else:
174 raise forms.ValidationError(_("Captcha validation failed"))
176 raise forms.ValidationError(_("Captcha validation failed"))
175
177
176
178
177 class ThreadCaptchaForm(ThreadForm):
179 class ThreadCaptchaForm(ThreadForm):
178 captcha = CaptchaField()
180 captcha = CaptchaField()
179
181
180 def __init__(self, *args, **kwargs):
182 def __init__(self, *args, **kwargs):
181 self.request = kwargs['request']
183 self.request = kwargs['request']
182 del kwargs['request']
184 del kwargs['request']
183
185
184 super(ThreadCaptchaForm, self).__init__(*args, **kwargs)
186 super(ThreadCaptchaForm, self).__init__(*args, **kwargs)
185
187
186 def clean(self):
188 def clean(self):
187 cleaned_data = super(ThreadCaptchaForm, self).clean()
189 cleaned_data = super(ThreadCaptchaForm, self).clean()
188
190
189 success = self.is_valid()
191 success = self.is_valid()
190 utils.update_captcha_access(self.request, success)
192 utils.update_captcha_access(self.request, success)
191
193
192 if success:
194 if success:
193 return cleaned_data
195 return cleaned_data
194 else:
196 else:
195 raise forms.ValidationError(_("Captcha validation failed"))
197 raise forms.ValidationError(_("Captcha validation failed"))
196
198
197
199
198 class SettingsForm(NeboardForm):
200 class SettingsForm(NeboardForm):
199
201
200 theme = forms.ChoiceField(choices=settings.THEMES,
202 theme = forms.ChoiceField(choices=settings.THEMES,
201 label=_('Theme'))
203 label=_('Theme'))
202
204
203
205
204 class ModeratorSettingsForm(SettingsForm):
206 class ModeratorSettingsForm(SettingsForm):
205
207
206 moderate = forms.BooleanField(required=False, label=_('Enable moderation '
208 moderate = forms.BooleanField(required=False, label=_('Enable moderation '
207 'panel'))
209 'panel'))
208
210
209
211
210 class LoginForm(NeboardForm):
212 class LoginForm(NeboardForm):
211
213
212 user_id = forms.CharField()
214 user_id = forms.CharField()
213
215
214 session = None
216 session = None
215
217
216 def clean_user_id(self):
218 def clean_user_id(self):
217 user_id = self.cleaned_data['user_id']
219 user_id = self.cleaned_data['user_id']
218 if user_id:
220 if user_id:
219 users = User.objects.filter(user_id=user_id)
221 users = User.objects.filter(user_id=user_id)
220 if len(users) == 0:
222 if len(users) == 0:
221 raise forms.ValidationError(_('No such user found'))
223 raise forms.ValidationError(_('No such user found'))
222
224
223 return user_id
225 return user_id
224
226
225 def _validate_login_speed(self):
227 def _validate_login_speed(self):
226 can_post = True
228 can_post = True
227
229
228 if LAST_LOGIN_TIME in self.session:
230 if LAST_LOGIN_TIME in self.session:
229 now = time.time()
231 now = time.time()
230 last_login_time = self.session[LAST_LOGIN_TIME]
232 last_login_time = self.session[LAST_LOGIN_TIME]
231
233
232 current_delay = int(now - last_login_time)
234 current_delay = int(now - last_login_time)
233
235
234 if current_delay < LOGIN_DELAY:
236 if current_delay < LOGIN_DELAY:
235 error_message = _('Wait %s minutes after last login') % str(
237 error_message = _('Wait %s minutes after last login') % str(
236 (LOGIN_DELAY - current_delay) / 60)
238 (LOGIN_DELAY - current_delay) / 60)
237 self._errors['user_id'] = self.error_class([error_message])
239 self._errors['user_id'] = self.error_class([error_message])
238
240
239 can_post = False
241 can_post = False
240
242
241 if can_post:
243 if can_post:
242 self.session[LAST_LOGIN_TIME] = time.time()
244 self.session[LAST_LOGIN_TIME] = time.time()
243
245
244 def clean(self):
246 def clean(self):
245 if not self.session:
247 if not self.session:
246 raise forms.ValidationError('Humans have sessions')
248 raise forms.ValidationError('Humans have sessions')
247
249
248 self._validate_login_speed()
250 self._validate_login_speed()
249
251
250 cleaned_data = super(LoginForm, self).clean()
252 cleaned_data = super(LoginForm, self).clean()
251
253
252 return cleaned_data No newline at end of file
254 return cleaned_data
@@ -1,419 +1,448 b''
1 import hashlib
1 import hashlib
2 import string
2 import string
3 from django.core import serializers
3 from django.core import serializers
4 from django.core.urlresolvers import reverse
4 from django.core.urlresolvers import reverse
5 from django.http import HttpResponseRedirect
5 from django.http import HttpResponseRedirect
6 from django.http.response import HttpResponse
6 from django.http.response import HttpResponse
7 from django.template import RequestContext
7 from django.template import RequestContext
8 from django.shortcuts import render, redirect, get_object_or_404
8 from django.shortcuts import render, redirect, get_object_or_404
9 from django.utils import timezone
9 from django.utils import timezone
10
10
11 from boards import forms
11 from boards import forms
12 import boards
12 import boards
13 from boards import utils
13 from boards import utils
14 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
14 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
15 ThreadCaptchaForm, PostCaptchaForm, LoginForm, ModeratorSettingsForm
15 ThreadCaptchaForm, PostCaptchaForm, LoginForm, ModeratorSettingsForm
16
16
17 from boards.models import Post, Tag, Ban, User, RANK_USER, SETTING_MODERATE
17 from boards.models import Post, Tag, Ban, User, RANK_USER, SETTING_MODERATE
18 from boards import authors
18 from boards import authors
19 from boards.utils import get_client_ip
19 from boards.utils import get_client_ip
20 import neboard
20 import neboard
21
21
22
22
23 def index(request, page=0):
23 def index(request, page=0):
24 context = _init_default_context(request)
24 context = _init_default_context(request)
25
25
26 if utils.need_include_captcha(request):
26 if utils.need_include_captcha(request):
27 threadFormClass = ThreadCaptchaForm
27 threadFormClass = ThreadCaptchaForm
28 kwargs = {'request': request}
28 kwargs = {'request': request}
29 else:
29 else:
30 threadFormClass = ThreadForm
30 threadFormClass = ThreadForm
31 kwargs = {}
31 kwargs = {}
32
32
33 if request.method == 'POST':
33 if request.method == 'POST':
34 form = threadFormClass(request.POST, request.FILES,
34 form = threadFormClass(request.POST, request.FILES,
35 error_class=PlainErrorList, **kwargs)
35 error_class=PlainErrorList, **kwargs)
36 form.session = request.session
36 form.session = request.session
37
37
38 if form.is_valid():
38 if form.is_valid():
39 return _new_post(request, form)
39 return _new_post(request, form)
40 if form.need_to_ban:
41 # Ban user because he is suspected to be a bot
42 _ban_current_user(request)
40 else:
43 else:
41 form = threadFormClass(error_class=PlainErrorList, **kwargs)
44 form = threadFormClass(error_class=PlainErrorList, **kwargs)
42
45
43 threads = []
46 threads = []
44 for thread in Post.objects.get_threads(page=int(page)):
47 for thread in Post.objects.get_threads(page=int(page)):
45 threads.append({'thread': thread,
48 threads.append({'thread': thread,
46 'bumpable': thread.can_bump()})
49 'bumpable': thread.can_bump()})
47
50
48 context['threads'] = None if len(threads) == 0 else threads
51 context['threads'] = None if len(threads) == 0 else threads
49 context['form'] = form
52 context['form'] = form
50 context['pages'] = range(Post.objects.get_thread_page_count())
53 context['pages'] = range(Post.objects.get_thread_page_count())
51
54
52 return render(request, 'boards/posting_general.html',
55 return render(request, 'boards/posting_general.html',
53 context)
56 context)
54
57
55
58
56 def _new_post(request, form, thread_id=boards.models.NO_PARENT):
59 def _new_post(request, form, thread_id=boards.models.NO_PARENT):
57 """Add a new post (in thread or as a reply)."""
60 """Add a new post (in thread or as a reply)."""
58
61
59 ip = get_client_ip(request)
62 ip = get_client_ip(request)
60 is_banned = Ban.objects.filter(ip=ip).exists()
63 is_banned = Ban.objects.filter(ip=ip).exists()
61
64
62 if is_banned:
65 if is_banned:
63 return redirect(you_are_banned)
66 return redirect(you_are_banned)
64
67
65 data = form.cleaned_data
68 data = form.cleaned_data
66
69
67 title = data['title']
70 title = data['title']
68 text = data['text']
71 text = data['text']
69
72
70 if 'image' in data.keys():
73 if 'image' in data.keys():
71 image = data['image']
74 image = data['image']
72 else:
75 else:
73 image = None
76 image = None
74
77
75 tags = []
78 tags = []
76
79
77 new_thread = thread_id == boards.models.NO_PARENT
80 new_thread = thread_id == boards.models.NO_PARENT
78 if new_thread:
81 if new_thread:
79 tag_strings = data['tags']
82 tag_strings = data['tags']
80
83
81 if tag_strings:
84 if tag_strings:
82 tag_strings = tag_strings.split(' ')
85 tag_strings = tag_strings.split(' ')
83 for tag_name in tag_strings:
86 for tag_name in tag_strings:
84 tag_name = string.lower(tag_name.strip())
87 tag_name = string.lower(tag_name.strip())
85 if len(tag_name) > 0:
88 if len(tag_name) > 0:
86 tag, created = Tag.objects.get_or_create(name=tag_name)
89 tag, created = Tag.objects.get_or_create(name=tag_name)
87 tags.append(tag)
90 tags.append(tag)
88
91
89 op = None if thread_id == boards.models.NO_PARENT else \
92 op = None if thread_id == boards.models.NO_PARENT else \
90 get_object_or_404(Post, id=thread_id)
93 get_object_or_404(Post, id=thread_id)
91 post = Post.objects.create_post(title=title, text=text, ip=ip,
94 post = Post.objects.create_post(title=title, text=text, ip=ip,
92 thread=op, image=image,
95 thread=op, image=image,
93 tags=tags, user=_get_user(request))
96 tags=tags, user=_get_user(request))
94
97
95 thread_to_show = (post.id if new_thread else thread_id)
98 thread_to_show = (post.id if new_thread else thread_id)
96
99
97 if new_thread:
100 if new_thread:
98 return redirect(thread, post_id=thread_to_show)
101 return redirect(thread, post_id=thread_to_show)
99 else:
102 else:
100 return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) +
103 return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) +
101 '#' + str(post.id))
104 '#' + str(post.id))
102
105
103
106
104 def tag(request, tag_name, page=0):
107 def tag(request, tag_name, page=0):
105 """Get all tag threads (posts without a parent)."""
108 """
109 Get all tag threads. Threads are split in pages, so some page is
110 requested. Default page is 0.
111 """
106
112
107 tag = get_object_or_404(Tag, name=tag_name)
113 tag = get_object_or_404(Tag, name=tag_name)
108 threads = []
114 threads = []
109 for thread in Post.objects.get_threads(tag=tag, page=int(page)):
115 for thread in Post.objects.get_threads(tag=tag, page=int(page)):
110 threads.append({'thread': thread,
116 threads.append({'thread': thread,
111 'bumpable': thread.can_bump()})
117 'bumpable': thread.can_bump()})
112
118
113 if request.method == 'POST':
119 if request.method == 'POST':
114 form = ThreadForm(request.POST, request.FILES,
120 form = ThreadForm(request.POST, request.FILES,
115 error_class=PlainErrorList)
121 error_class=PlainErrorList)
116 if form.is_valid():
122 if form.is_valid():
117 return _new_post(request, form)
123 return _new_post(request, form)
124 if form.need_to_ban:
125 # Ban user because he is suspected to be a bot
126 _ban_current_user(request)
118 else:
127 else:
119 form = forms.ThreadForm(initial={'tags': tag_name},
128 form = forms.ThreadForm(initial={'tags': tag_name},
120 error_class=PlainErrorList)
129 error_class=PlainErrorList)
121
130
122 context = _init_default_context(request)
131 context = _init_default_context(request)
123 context['threads'] = None if len(threads) == 0 else threads
132 context['threads'] = None if len(threads) == 0 else threads
124 context['tag'] = tag
133 context['tag'] = tag
125 context['pages'] = range(Post.objects.get_thread_page_count(tag=tag))
134 context['pages'] = range(Post.objects.get_thread_page_count(tag=tag))
126
135
127 context['form'] = form
136 context['form'] = form
128
137
129 return render(request, 'boards/posting_general.html',
138 return render(request, 'boards/posting_general.html',
130 context)
139 context)
131
140
132
141
133 def thread(request, post_id):
142 def thread(request, post_id):
134 """Get all thread posts"""
143 """Get all thread posts"""
135
144
136 if utils.need_include_captcha(request):
145 if utils.need_include_captcha(request):
137 postFormClass = PostCaptchaForm
146 postFormClass = PostCaptchaForm
138 kwargs = {'request': request}
147 kwargs = {'request': request}
139 else:
148 else:
140 postFormClass = PostForm
149 postFormClass = PostForm
141 kwargs = {}
150 kwargs = {}
142
151
143 if request.method == 'POST':
152 if request.method == 'POST':
144 form = postFormClass(request.POST, request.FILES,
153 form = postFormClass(request.POST, request.FILES,
145 error_class=PlainErrorList, **kwargs)
154 error_class=PlainErrorList, **kwargs)
146 form.session = request.session
155 form.session = request.session
147
156
148 if form.is_valid():
157 if form.is_valid():
149 return _new_post(request, form, post_id)
158 return _new_post(request, form, post_id)
159 if form.need_to_ban:
160 # Ban user because he is suspected to be a bot
161 _ban_current_user(request)
150 else:
162 else:
151 form = postFormClass(error_class=PlainErrorList, **kwargs)
163 form = postFormClass(error_class=PlainErrorList, **kwargs)
152
164
153 posts = Post.objects.get_thread(post_id)
165 posts = Post.objects.get_thread(post_id)
154
166
155 context = _init_default_context(request)
167 context = _init_default_context(request)
156
168
157 context['posts'] = posts
169 context['posts'] = posts
158 context['form'] = form
170 context['form'] = form
159 context['bumpable'] = posts[0].can_bump()
171 context['bumpable'] = posts[0].can_bump()
160
172
161 return render(request, 'boards/thread.html', context)
173 return render(request, 'boards/thread.html', context)
162
174
163
175
164 def login(request):
176 def login(request):
165 """Log in with user id"""
177 """Log in with user id"""
166
178
167 context = _init_default_context(request)
179 context = _init_default_context(request)
168
180
169 if request.method == 'POST':
181 if request.method == 'POST':
170 form = LoginForm(request.POST, request.FILES,
182 form = LoginForm(request.POST, request.FILES,
171 error_class=PlainErrorList)
183 error_class=PlainErrorList)
172 form.session = request.session
184 form.session = request.session
173
185
174 if form.is_valid():
186 if form.is_valid():
175 user = User.objects.get(user_id=form.cleaned_data['user_id'])
187 user = User.objects.get(user_id=form.cleaned_data['user_id'])
176 request.session['user_id'] = user.id
188 request.session['user_id'] = user.id
177 return redirect(index)
189 return redirect(index)
178
190
179 else:
191 else:
180 form = LoginForm()
192 form = LoginForm()
181
193
182 context['form'] = form
194 context['form'] = form
183
195
184 return render(request, 'boards/login.html', context)
196 return render(request, 'boards/login.html', context)
185
197
186
198
187 def settings(request):
199 def settings(request):
188 """User's settings"""
200 """User's settings"""
189
201
190 context = _init_default_context(request)
202 context = _init_default_context(request)
191 user = _get_user(request)
203 user = _get_user(request)
192 is_moderator = user.is_moderator()
204 is_moderator = user.is_moderator()
193
205
194 if request.method == 'POST':
206 if request.method == 'POST':
195 if is_moderator:
207 if is_moderator:
196 form = ModeratorSettingsForm(request.POST,
208 form = ModeratorSettingsForm(request.POST,
197 error_class=PlainErrorList)
209 error_class=PlainErrorList)
198 else:
210 else:
199 form = SettingsForm(request.POST, error_class=PlainErrorList)
211 form = SettingsForm(request.POST, error_class=PlainErrorList)
200
212
201 if form.is_valid():
213 if form.is_valid():
202 selected_theme = form.cleaned_data['theme']
214 selected_theme = form.cleaned_data['theme']
203
215
204 user.save_setting('theme', selected_theme)
216 user.save_setting('theme', selected_theme)
205
217
206 if is_moderator:
218 if is_moderator:
207 moderate = form.cleaned_data['moderate']
219 moderate = form.cleaned_data['moderate']
208 user.save_setting(SETTING_MODERATE, moderate)
220 user.save_setting(SETTING_MODERATE, moderate)
209
221
210 return redirect(settings)
222 return redirect(settings)
211 else:
223 else:
212 selected_theme = _get_theme(request)
224 selected_theme = _get_theme(request)
213
225
214 if is_moderator:
226 if is_moderator:
215 form = ModeratorSettingsForm(initial={'theme': selected_theme,
227 form = ModeratorSettingsForm(initial={'theme': selected_theme,
216 'moderate': context['moderator']},
228 'moderate': context['moderator']},
217 error_class=PlainErrorList)
229 error_class=PlainErrorList)
218 else:
230 else:
219 form = SettingsForm(initial={'theme': selected_theme},
231 form = SettingsForm(initial={'theme': selected_theme},
220 error_class=PlainErrorList)
232 error_class=PlainErrorList)
221
233
222 context['form'] = form
234 context['form'] = form
223
235
224 return render(request, 'boards/settings.html', context)
236 return render(request, 'boards/settings.html', context)
225
237
226
238
227 def all_tags(request):
239 def all_tags(request):
228 """All tags list"""
240 """All tags list"""
229
241
230 context = _init_default_context(request)
242 context = _init_default_context(request)
231 context['all_tags'] = Tag.objects.get_not_empty_tags()
243 context['all_tags'] = Tag.objects.get_not_empty_tags()
232
244
233 return render(request, 'boards/tags.html', context)
245 return render(request, 'boards/tags.html', context)
234
246
235
247
236 def jump_to_post(request, post_id):
248 def jump_to_post(request, post_id):
237 """Determine thread in which the requested post is and open it's page"""
249 """Determine thread in which the requested post is and open it's page"""
238
250
239 post = get_object_or_404(Post, id=post_id)
251 post = get_object_or_404(Post, id=post_id)
240
252
241 if not post.thread:
253 if not post.thread:
242 return redirect(thread, post_id=post.id)
254 return redirect(thread, post_id=post.id)
243 else:
255 else:
244 return redirect(reverse(thread, kwargs={'post_id': post.thread.id})
256 return redirect(reverse(thread, kwargs={'post_id': post.thread.id})
245 + '#' + str(post.id))
257 + '#' + str(post.id))
246
258
247
259
248 def authors(request):
260 def authors(request):
249 """Show authors list"""
261 """Show authors list"""
250
262
251 context = _init_default_context(request)
263 context = _init_default_context(request)
252 context['authors'] = boards.authors.authors
264 context['authors'] = boards.authors.authors
253
265
254 return render(request, 'boards/authors.html', context)
266 return render(request, 'boards/authors.html', context)
255
267
256
268
257 def delete(request, post_id):
269 def delete(request, post_id):
258 """Delete post"""
270 """Delete post"""
259
271
260 user = _get_user(request)
272 user = _get_user(request)
261 post = get_object_or_404(Post, id=post_id)
273 post = get_object_or_404(Post, id=post_id)
262
274
263 if user.is_moderator():
275 if user.is_moderator():
264 # TODO Show confirmation page before deletion
276 # TODO Show confirmation page before deletion
265 Post.objects.delete_post(post)
277 Post.objects.delete_post(post)
266
278
267 if not post.thread:
279 if not post.thread:
268 return _redirect_to_next(request)
280 return _redirect_to_next(request)
269 else:
281 else:
270 return redirect(thread, post_id=post.thread.id)
282 return redirect(thread, post_id=post.thread.id)
271
283
272
284
273 def ban(request, post_id):
285 def ban(request, post_id):
274 """Ban user"""
286 """Ban user"""
275
287
276 user = _get_user(request)
288 user = _get_user(request)
277 post = get_object_or_404(Post, id=post_id)
289 post = get_object_or_404(Post, id=post_id)
278
290
279 if user.is_moderator():
291 if user.is_moderator():
280 # TODO Show confirmation page before ban
292 # TODO Show confirmation page before ban
281 Ban.objects.get_or_create(ip=post.poster_ip)
293 Ban.objects.get_or_create(ip=post.poster_ip)
282
294
283 return _redirect_to_next(request)
295 return _redirect_to_next(request)
284
296
285
297
286 def you_are_banned(request):
298 def you_are_banned(request):
287 """Show the page that notifies that user is banned"""
299 """Show the page that notifies that user is banned"""
288
300
289 context = _init_default_context(request)
301 context = _init_default_context(request)
290 return render(request, 'boards/staticpages/banned.html', context)
302 return render(request, 'boards/staticpages/banned.html', context)
291
303
292
304
293 def page_404(request):
305 def page_404(request):
294 """Show page 404 (not found error)"""
306 """Show page 404 (not found error)"""
295
307
296 context = _init_default_context(request)
308 context = _init_default_context(request)
297 return render(request, 'boards/404.html', context)
309 return render(request, 'boards/404.html', context)
298
310
299
311
300 def tag_subscribe(request, tag_name):
312 def tag_subscribe(request, tag_name):
301 """Add tag to favorites"""
313 """Add tag to favorites"""
302
314
303 user = _get_user(request)
315 user = _get_user(request)
304 tag = get_object_or_404(Tag, name=tag_name)
316 tag = get_object_or_404(Tag, name=tag_name)
305
317
306 if not tag in user.fav_tags.all():
318 if not tag in user.fav_tags.all():
307 user.fav_tags.add(tag)
319 user.fav_tags.add(tag)
308
320
309 return _redirect_to_next(request)
321 return _redirect_to_next(request)
310
322
311
323
312 def tag_unsubscribe(request, tag_name):
324 def tag_unsubscribe(request, tag_name):
313 """Remove tag from favorites"""
325 """Remove tag from favorites"""
314
326
315 user = _get_user(request)
327 user = _get_user(request)
316 tag = get_object_or_404(Tag, name=tag_name)
328 tag = get_object_or_404(Tag, name=tag_name)
317
329
318 if tag in user.fav_tags.all():
330 if tag in user.fav_tags.all():
319 user.fav_tags.remove(tag)
331 user.fav_tags.remove(tag)
320
332
321 return _redirect_to_next(request)
333 return _redirect_to_next(request)
322
334
323
335
324 def static_page(request, name):
336 def static_page(request, name):
325 """Show a static page that needs only tags list and a CSS"""
337 """Show a static page that needs only tags list and a CSS"""
326
338
327 context = _init_default_context(request)
339 context = _init_default_context(request)
328 return render(request, 'boards/staticpages/' + name + '.html', context)
340 return render(request, 'boards/staticpages/' + name + '.html', context)
329
341
330
342
331 def api_get_post(request, post_id):
343 def api_get_post(request, post_id):
332 """
344 """
333 Get the JSON of a post. This can be
345 Get the JSON of a post. This can be
334 used as and API for external clients.
346 used as and API for external clients.
335 """
347 """
336
348
337 post = get_object_or_404(Post, id=post_id)
349 post = get_object_or_404(Post, id=post_id)
338
350
339 json = serializers.serialize("json", [post], fields=(
351 json = serializers.serialize("json", [post], fields=(
340 "pub_time", "_text_rendered", "title", "text", "image",
352 "pub_time", "_text_rendered", "title", "text", "image",
341 "image_width", "image_height", "replies", "tags"
353 "image_width", "image_height", "replies", "tags"
342 ))
354 ))
343
355
344 return HttpResponse(content=json)
356 return HttpResponse(content=json)
345
357
346
358
347 def get_post(request, post_id):
359 def get_post(request, post_id):
348 """ Get the html of a post. Used for popups. """
360 """Get the html of a post. Used for popups."""
349
361
350 post = get_object_or_404(Post, id=post_id)
362 post = get_object_or_404(Post, id=post_id)
351
363
352 context = RequestContext(request)
364 context = RequestContext(request)
353 context["post"] = post
365 context["post"] = post
354
366
355 return render(request, 'boards/post.html', context)
367 return render(request, 'boards/post.html', context)
356
368
357
369
358 def _get_theme(request, user=None):
370 def _get_theme(request, user=None):
359 """Get user's CSS theme"""
371 """Get user's CSS theme"""
360
372
361 if not user:
373 if not user:
362 user = _get_user(request)
374 user = _get_user(request)
363 theme = user.get_setting('theme')
375 theme = user.get_setting('theme')
364 if not theme:
376 if not theme:
365 theme = neboard.settings.DEFAULT_THEME
377 theme = neboard.settings.DEFAULT_THEME
366
378
367 return theme
379 return theme
368
380
369
381
370 def _init_default_context(request):
382 def _init_default_context(request):
371 """Create context with default values that are used in most views"""
383 """Create context with default values that are used in most views"""
372
384
373 context = RequestContext(request)
385 context = RequestContext(request)
374
386
375 user = _get_user(request)
387 user = _get_user(request)
376 context['user'] = user
388 context['user'] = user
377 context['tags'] = user.get_sorted_fav_tags()
389 context['tags'] = user.get_sorted_fav_tags()
378
390
379 theme = _get_theme(request, user)
391 theme = _get_theme(request, user)
380 context['theme'] = theme
392 context['theme'] = theme
381 context['theme_css'] = 'css/' + theme + '/base_page.css'
393 context['theme_css'] = 'css/' + theme + '/base_page.css'
382
394
395 # This shows the moderator panel
383 moderate = user.get_setting(SETTING_MODERATE)
396 moderate = user.get_setting(SETTING_MODERATE)
384 if moderate == 'True':
397 if moderate == 'True':
385 context['moderator'] = user.is_moderator()
398 context['moderator'] = user.is_moderator()
386 else:
399 else:
387 context['moderator'] = False
400 context['moderator'] = False
388
401
389 return context
402 return context
390
403
391
404
392 def _get_user(request):
405 def _get_user(request):
393 """Get current user from the session"""
406 """
407 Get current user from the session. If the user does not exist, create
408 a new one.
409 """
394
410
395 session = request.session
411 session = request.session
396 if not 'user_id' in session:
412 if not 'user_id' in session:
397 request.session.save()
413 request.session.save()
398
414
399 md5 = hashlib.md5()
415 md5 = hashlib.md5()
400 md5.update(session.session_key)
416 md5.update(session.session_key)
401 new_id = md5.hexdigest()
417 new_id = md5.hexdigest()
402
418
403 time_now = timezone.now()
419 time_now = timezone.now()
404 user = User.objects.create(user_id=new_id, rank=RANK_USER,
420 user = User.objects.create(user_id=new_id, rank=RANK_USER,
405 registration_time=time_now)
421 registration_time=time_now)
406
422
407 session['user_id'] = user.id
423 session['user_id'] = user.id
408 else:
424 else:
409 user = User.objects.get(id=session['user_id'])
425 user = User.objects.get(id=session['user_id'])
410
426
411 return user
427 return user
412
428
413
429
414 def _redirect_to_next(request):
430 def _redirect_to_next(request):
431 """
432 If a 'next' parameter was specified, redirect to the next page. This is
433 used when the user is required to return to some page after the current
434 view has finished its work.
435 """
436
415 if 'next' in request.GET:
437 if 'next' in request.GET:
416 next_page = request.GET['next']
438 next_page = request.GET['next']
417 return HttpResponseRedirect(next_page)
439 return HttpResponseRedirect(next_page)
418 else:
440 else:
419 return redirect(index)
441 return redirect(index)
442
443
444 def _ban_current_user(request):
445 """Add current user to the IP ban list"""
446
447 ip = utils.get_client_ip(request)
448 Ban.objects.get_or_create(ip=ip)
General Comments 0
You need to be logged in to leave comments. Login now