##// END OF EJS Templates
Added error 404 for opening not existing thread or tag. This fixes #8
neko259 -
r79:b95f96a3 default
parent child Browse files
Show More
@@ -1,91 +1,90 b''
1 1 import re
2 2 from django import forms
3 3 from django.forms.util import ErrorList
4 from boards.models import TITLE_MAX_LENGTH
4 5 from neboard import settings
5 6
6 TITLE_MAX_LENGTH = 50
7
8 7
9 8 class PlainErrorList(ErrorList):
10 9 def __unicode__(self):
11 10 return self.as_text()
12 11
13 12 def as_text(self):
14 13 return ''.join([u'(!) %s ' % e for e in self])
15 14
16 15
17 16 class PostForm(forms.Form):
18 17
19 18 MAX_TEXT_LENGTH = 10000
20 19 MAX_IMAGE_SIZE = 8 * 1024 * 1024
21 20
22 21 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False)
23 22 text = forms.CharField(widget=forms.Textarea, required=False)
24 23 image = forms.ImageField(required=False)
25 24
26 25 def clean_title(self):
27 26 title = self.cleaned_data['title']
28 27 if title:
29 28 if len(title) > TITLE_MAX_LENGTH:
30 29 raise forms.ValidationError('Title must have less than' +
31 30 str(TITLE_MAX_LENGTH) +
32 31 ' characters.')
33 32 return title
34 33
35 34 def clean_text(self):
36 35 text = self.cleaned_data['text']
37 36 if text:
38 37 if len(text) > self.MAX_TEXT_LENGTH:
39 38 raise forms.ValidationError('Text must have less than ' +
40 39 str(self.MAX_TEXT_LENGTH) +
41 40 ' characters.')
42 41 return text
43 42
44 43 def clean_image(self):
45 44 image = self.cleaned_data['image']
46 45 if image:
47 46 if image._size > self.MAX_IMAGE_SIZE:
48 47 raise forms.ValidationError('Image must be less than ' +
49 48 str(self.MAX_IMAGE_SIZE) +
50 49 ' bytes.')
51 50 return image
52 51
53 52 def clean(self):
54 53 cleaned_data = super(PostForm, self).clean()
55 54
56 55 self._clean_text_image()
57 56
58 57 return cleaned_data
59 58
60 59 def _clean_text_image(self):
61 60 text = self.cleaned_data.get('text')
62 61 image = self.cleaned_data.get('image')
63 62
64 63 if (not text) and (not image):
65 64 error_message = 'Either text or image must be entered.'
66 65 self._errors['text'] = self.error_class([error_message])
67 66 self._errors['image'] = self.error_class([error_message])
68 67
69 68
70 69 class ThreadForm(PostForm):
71 70 regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE)
72 71 tags = forms.CharField(max_length=100)
73 72
74 73 def clean_tags(self):
75 74 tags = self.cleaned_data['tags']
76 75
77 76 if tags:
78 77 if not self.regex_tags.match(tags):
79 78 raise forms.ValidationError(
80 79 'Inappropriate characters in tags.')
81 80
82 81 return tags
83 82
84 83 def clean(self):
85 84 cleaned_data = super(ThreadForm, self).clean()
86 85
87 86 return cleaned_data
88 87
89 88
90 89 class SettingsForm(forms.Form):
91 90 theme = forms.ChoiceField(choices=settings.THEMES, widget=forms.RadioSelect) No newline at end of file
@@ -1,278 +1,288 b''
1 1 import os
2 2 from random import random
3 3 import re
4 4 import time
5 5 import math
6 6
7 7 from django.db import models
8 8 from django.http import Http404
9 9 from django.utils import timezone
10 10 from markupfield.fields import MarkupField
11 11
12 12 from neboard import settings
13 13 import thumbs
14 14
15 IMAGE_THUMB_SIZE = (200, 150)
16
17 TITLE_MAX_LENGTH = 50
18
19 DEFAULT_MARKUP_TYPE = 'markdown'
15 20
16 21 NO_PARENT = -1
17 22 NO_IP = '0.0.0.0'
18 23 UNKNOWN_UA = ''
19 24 ALL_PAGES = -1
20 25 OPENING_POST_WEIGHT = 5
21 26 IMAGES_DIRECTORY = 'images/'
22 27 FILE_EXTENSION_DELIMITER = '.'
23 28
24 29 REGEX_PRETTY = re.compile(r'^\d(0)+$')
25 30 REGEX_SAME = re.compile(r'^(.)\1+$')
26 31
27 32
28 33 class PostManager(models.Manager):
29 34 def create_post(self, title, text, image=None, parent_id=NO_PARENT,
30 35 ip=NO_IP, tags=None):
31 36 post = self.create(title=title,
32 37 text=text,
33 38 pub_time=timezone.now(),
34 39 parent=parent_id,
35 40 image=image,
36 41 poster_ip=ip,
37 42 poster_user_agent=UNKNOWN_UA,
38 43 last_edit_time=timezone.now())
39 44
40 45 if tags:
41 for tag in tags:
42 post.tags.add(tag)
46 map(post.tags.add, tags)
43 47
44 48 if parent_id != NO_PARENT:
45 49 self._bump_thread(parent_id)
46 50 else:
47 51 self._delete_old_threads()
48 52
49 53 return post
50 54
51 55 def delete_post(self, post):
52 56 children = self.filter(parent=post.id)
53 57 for child in children:
54 58 self.delete_post(child)
55 59 post.delete()
56 60
57 61 def delete_posts_by_ip(self, ip):
58 62 posts = self.filter(poster_ip=ip)
59 63 for post in posts:
60 64 self.delete_post(post)
61 65
62 66 def get_threads(self, tag=None, page=ALL_PAGES):
63 67 if tag:
64 68 threads = self.filter(parent=NO_PARENT, tags=tag)
65 69 else:
66 70 threads = self.filter(parent=NO_PARENT)
71
72 if not threads:
73 raise Http404
74
67 75 threads = threads.order_by('-last_edit_time')
68 76
69 77 if page != ALL_PAGES:
70 78 thread_count = len(threads)
71 79
72 80 if page < self.get_thread_page_count(tag=tag):
73 81 start_thread = page * settings.THREADS_PER_PAGE
74 82 end_thread = min(start_thread + settings.THREADS_PER_PAGE,
75 83 thread_count)
76 84 threads = threads[start_thread:end_thread]
77 85
78 86 return threads
79 87
80 88 def get_thread(self, opening_post_id):
81 opening_post = self.get(id=opening_post_id)
82
83 if not opening_post:
89 try:
90 opening_post = self.get(id=opening_post_id)
91 except Post.DoesNotExist:
84 92 raise Http404
85 93
86 94 if opening_post.parent == NO_PARENT:
87 95 replies = self.filter(parent=opening_post_id)
88 96
89 97 thread = [opening_post]
90 98 thread.extend(replies)
91 99
92 100 return thread
93 101
94 102 def exists(self, post_id):
95 103 posts = self.filter(id=post_id)
96 104
97 105 return posts.count() > 0
98 106
99 107 def get_thread_page_count(self, tag=None):
100 108 if tag:
101 109 threads = self.filter(parent=NO_PARENT, tags=tag)
102 110 else:
103 111 threads = self.filter(parent=NO_PARENT)
104 112
105 113 return int(math.ceil(threads.count() / float(
106 114 settings.THREADS_PER_PAGE)))
107 115
108 116 def _delete_old_threads(self):
109 117 """
110 118 Preserves maximum thread count. If there are too many threads,
111 119 delete the old ones.
112 120 """
113 121
114 122 # TODO Move old threads to the archive instead of deleting them.
115 123 # Maybe make some 'old' field in the model to indicate the thread
116 124 # must not be shown and be able for replying.
117 125
118 126 threads = self.get_threads()
119 127 thread_count = len(threads)
120 128
121 129 if thread_count > settings.MAX_THREAD_COUNT:
122 130 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
123 131 old_threads = threads[thread_count - num_threads_to_delete:]
124 132
125 133 for thread in old_threads:
126 134 self.delete_post(thread)
127 135
128 136 def _bump_thread(self, thread_id):
129 137 thread = self.get(id=thread_id)
130 138
131 139 if thread.can_bump():
132 140 thread.last_edit_time = timezone.now()
133 141 thread.save()
134 142
135 143
136 144 class TagManager(models.Manager):
137 145 def get_not_empty_tags(self):
138 146 all_tags = self.all().order_by('name')
139 147 tags = []
140 148 for tag in all_tags:
141 149 if not tag.is_empty():
142 150 tags.append(tag)
143 151
144 152 return tags
145 153
146 154 def get_popular_tags(self):
147 155 all_tags = self.get_not_empty_tags()
148 156
149 157 sorted_tags = sorted(all_tags, key=lambda tag: tag.get_popularity(),
150 158 reverse=True)
151 159
152 160 return sorted_tags[:settings.POPULAR_TAGS]
153 161
154 162
155 163 class Tag(models.Model):
156 164 """
157 165 A tag is a text node assigned to the post. The tag serves as a board
158 166 section. There can be multiple tags for each message
159 167 """
160 168
161 169 objects = TagManager()
162 170
163 171 name = models.CharField(max_length=100)
164 172 # TODO Connect the tag to its posts to check the number of threads for
165 173 # the tag.
166 174
167 175 def __unicode__(self):
168 176 return self.name
169 177
170 178 def is_empty(self):
171 179 return self.get_post_count() == 0
172 180
173 181 def get_post_count(self):
174 182 posts_with_tag = Post.objects.get_threads(tag=self)
175 183 return posts_with_tag.count()
176 184
177 185 def get_popularity(self):
178 186 posts_with_tag = Post.objects.get_threads(tag=self)
179 187 reply_count = 0
180 188 for post in posts_with_tag:
181 189 reply_count += post.get_reply_count()
182 190 reply_count += OPENING_POST_WEIGHT
183 191
184 192 return reply_count
185 193
186 194
187 195 class Post(models.Model):
188 196 """A post is a message."""
189 197
190 198 objects = PostManager()
191 199
192 200 def _update_image_filename(self, filename):
193 201 """Get unique image filename"""
194 202
195 203 path = IMAGES_DIRECTORY
196 204 new_name = str(int(time.mktime(time.gmtime())))
197 205 new_name += str(int(random() * 1000))
198 206 new_name += FILE_EXTENSION_DELIMITER
199 207 new_name += filename.split(FILE_EXTENSION_DELIMITER)[-1:][0]
200 208
201 209 return os.path.join(path, new_name)
202 210
203 title = models.CharField(max_length=50)
211 title = models.CharField(max_length=TITLE_MAX_LENGTH)
204 212 pub_time = models.DateTimeField()
205 text = MarkupField(default_markup_type='markdown', escape_html=True)
213 text = MarkupField(default_markup_type=DEFAULT_MARKUP_TYPE,
214 escape_html=True)
206 215 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
207 blank=True, sizes=((200, 150),))
216 blank=True, sizes=(IMAGE_THUMB_SIZE,))
208 217 poster_ip = models.IPAddressField()
209 218 poster_user_agent = models.TextField()
210 219 parent = models.BigIntegerField()
211 220 tags = models.ManyToManyField(Tag)
212 221 last_edit_time = models.DateTimeField()
213 222
214 223 def __unicode__(self):
215 return self.title + ' (' + self.text.raw + ')'
224 return '#' + str(self.id) + ' ' + self.title + ' (' + self.text.raw + \
225 ')'
216 226
217 227 def _get_replies(self):
218 228 return Post.objects.filter(parent=self.id)
219 229
220 230 def get_reply_count(self):
221 231 return self._get_replies().count()
222 232
223 233 def get_images_count(self):
224 234 images_count = 1 if self.image else 0
225 235 for reply in self._get_replies():
226 236 if reply.image:
227 237 images_count += 1
228 238
229 239 return images_count
230 240
231 241 def get_gets_count(self):
232 242 gets_count = 1 if self.is_get() else 0
233 243 for reply in self._get_replies():
234 244 if reply.is_get():
235 245 gets_count += 1
236 246
237 247 return gets_count
238 248
239 249 def is_get(self):
240 250 """If the post has pretty id (1, 1000, 77777), than it is called GET"""
241 251
242 252 first = self.id == 1
243 253
244 254 id_str = str(self.id)
245 255 pretty = REGEX_PRETTY.match(id_str)
246 256 same_digits = REGEX_SAME.match(id_str)
247 257
248 258 return first or pretty or same_digits
249 259
250 260 def can_bump(self):
251 261 """Check if the thread can be bumped by replying"""
252 262
253 263 replies_count = len(Post.objects.get_thread(self.id))
254 264
255 265 return replies_count <= settings.MAX_POSTS_PER_THREAD
256 266
257 267 def get_last_replies(self):
258 268 if settings.LAST_REPLIES_COUNT > 0:
259 269 reply_count = self.get_reply_count()
260 270
261 271 if reply_count > 0:
262 272 reply_count_to_show = min(settings.LAST_REPLIES_COUNT,
263 273 reply_count)
264 274 last_replies = self._get_replies()[reply_count
265 275 - reply_count_to_show:]
266 276
267 277 return last_replies
268 278
269 279
270 280 class Admin(models.Model):
271 281 """
272 282 Model for admin users
273 283 """
274 284 name = models.CharField(max_length=100)
275 285 password = models.CharField(max_length=100)
276 286
277 287 def __unicode__(self):
278 288 return self.name + '/' + '*' * len(self.password)
@@ -1,172 +1,210 b''
1 1 # coding=utf-8
2 2 from django.utils.unittest import TestCase
3 3 from django.test.client import Client
4 4
5 5 import boards
6 6
7 7 from boards.models import Post, Admin, Tag
8 8 from neboard import settings
9 9
10 10 TEST_TEXT = 'test text'
11 11
12 12 NEW_THREAD_PAGE = '/'
13 THREAD_PAGE = '/thread/1/'
13 THREAD_PAGE_ONE = '/thread/1/'
14 THREAD_PAGE = '/thread/'
15 TAG_PAGE = '/tag/'
14 16 HTTP_CODE_REDIRECT = 302
17 HTTP_CODE_OK = 200
18 HTTP_CODE_NOT_FOUND = 404
15 19
16 20
17 21 class BoardTests(TestCase):
18 22 def _create_post(self):
19 23 return Post.objects.create_post(title='title',
20 24 text='text')
21 25
22 26 def test_post_add(self):
23 27 post = self._create_post()
24 28
25 29 self.assertIsNotNone(post)
26 30 self.assertEqual(boards.models.NO_PARENT, post.parent)
27 31
28 32 def test_delete_post(self):
29 33 post = self._create_post()
30 34 post_id = post.id
31 35
32 36 Post.objects.delete_post(post)
33 37
34 38 self.assertFalse(Post.objects.exists(post_id))
35 39
36 40 def test_delete_posts_by_ip(self):
37 41 post = self._create_post()
38 42 post_id = post.id
39 43
40 44 Post.objects.delete_posts_by_ip('0.0.0.0')
41 45
42 46 self.assertFalse(Post.objects.exists(post_id))
43 47
44 48 # Authentication tests
45 49
46 50 def _create_test_user(self):
47 51 admin = Admin(name='test_username12313584353165',
48 52 password='test_userpassword135135512')
49 53
50 54 admin.save()
51 55 return admin
52 56
53 57 def test_admin_login(self):
54 58 client = Client()
55 59
56 60 self.assertFalse('admin' in client.session)
57 61
58 62 admin = self._create_test_user()
59 63
60 64 response = client.post('/login',
61 65 {'name': admin.name, 'password': admin.password})
62 66
63 67 # it means that login passed and user are redirected to another page
64 68 self.assertEqual(302, response.status_code)
65 69
66 70 self.assertTrue('admin' in client.session)
67 71 self.assertTrue(client.session['admin'])
68 72
69 73 admin.delete()
70 74
71 75 wrong_name = 'sd2f1s3d21fs3d21f'
72 76 wrong_password = 'sd2f1s3d21fs3d21fsdfsd'
73 77
74 78 client.post('/login', {'name': wrong_name, 'password': wrong_password})
75 79 self.assertFalse(client.session['admin'])
76 80
77 81 def test_admin_logout(self):
78 82 client = Client()
79 83
80 84 self.assertFalse('admin' in client.session)
81 85
82 86 admin = self._create_test_user()
83 87
84 88 client.post('/login',
85 89 {'name': admin.name, 'password': admin.password})
86 90
87 91 self.assertTrue(client.session['admin'])
88 92
89 93 client.get('/logout')
90 94
91 95 self.assertFalse(client.session['admin'])
92 96
93 97 admin.delete()
94 98
95 99 def test_get_thread(self):
96 100 opening_post = self._create_post()
97 101 op_id = opening_post.id
98 102
99 103 for i in range(0, 2):
100 104 Post.objects.create_post('title', 'text',
101 105 parent_id=op_id)
102 106
103 107 thread = Post.objects.get_thread(op_id)
104 108
105 109 self.assertEqual(3, len(thread))
106 110
107 111 def test_create_post_with_tag(self):
108 112 tag = Tag.objects.create(name='test_tag')
109 113 post = Post.objects.create_post(title='title', text='text', tags=[tag])
110 114 self.assertIsNotNone(post)
111 115
112 116 def test_thread_max_count(self):
113 117 for i in range(settings.MAX_THREAD_COUNT + 1):
114 118 self._create_post()
115 119
116 120 self.assertEqual(settings.MAX_THREAD_COUNT,
117 121 len(Post.objects.get_threads()))
118 122
119 123 def test_get(self):
120 124 """Test if the get computes properly"""
121 125
122 126 post = self._create_post()
123 127
124 128 self.assertTrue(post.is_get())
125 129
126 130 def test_pages(self):
127 131 """Test that the thread list is properly split into pages"""
128 132
129 133 for i in range(settings.MAX_THREAD_COUNT):
130 134 self._create_post()
131 135
132 136 all_threads = Post.objects.get_threads()
133 137
134 138 posts_in_second_page = Post.objects.get_threads(page=1)
135 139 first_post = posts_in_second_page[0]
136 140
137 141 self.assertEqual(all_threads[settings.THREADS_PER_PAGE].id,
138 142 first_post.id)
139 143
140 144 def test_post_validation(self):
141 145 """Test the validation of the post form"""
142 146
143 147 Post.objects.all().delete()
144 148
145 149 client = Client()
146 150
147 151 valid_tags = u'tag1 tag_2 Ρ‚Π΅Π³_3'
148 152 invalid_tags = u'$%_356 ---'
149 153
150 154 response = client.post(NEW_THREAD_PAGE, {'title': 'test title',
151 155 'text': TEST_TEXT,
152 156 'tags': valid_tags})
153 157 self.assertEqual(response.status_code, HTTP_CODE_REDIRECT,
154 158 msg='Posting new message failed: got code ' +
155 159 str(response.status_code))
156 160
157 161 self.assertEqual(1, Post.objects.count(),
158 162 msg='No posts were created')
159 163
160 164 client.post(NEW_THREAD_PAGE, {'text': TEST_TEXT,
161 165 'tags': invalid_tags})
162 166 self.assertEqual(1, Post.objects.count(), msg='The validation passed '
163 167 'where it should fail')
164 168
165 response = client.post(THREAD_PAGE, {'text': TEST_TEXT,
169 response = client.post(THREAD_PAGE_ONE, {'text': TEST_TEXT,
166 170 'tags': valid_tags})
167 self.assertEqual(response.status_code, HTTP_CODE_REDIRECT,
168 msg='Posting new message failed: got code ' +
171 self.assertEqual(HTTP_CODE_REDIRECT, response.status_code,
172 msg=u'Posting new message failed: got code ' +
169 173 str(response.status_code))
170 174
171 175 self.assertEqual(2, Post.objects.count(),
172 msg='No posts were created') No newline at end of file
176 msg=u'No posts were created')
177
178 def test_404(self):
179 """Test receiving error 404 when opening a non-existent page"""
180
181 Post.objects.all().delete()
182 Tag.objects.all().delete()
183
184 tag_name = u'test_tag'
185 tags, = [Tag.objects.get_or_create(name=tag_name)]
186 client = Client()
187
188 Post.objects.create_post('title', TEST_TEXT, tags=tags)
189
190 existing_post_id = Post.objects.all()[0].id
191 response_existing = client.get(THREAD_PAGE + str(existing_post_id) +
192 '/')
193 self.assertEqual(HTTP_CODE_OK, response_existing.status_code,
194 u'Cannot open existing thread')
195
196 response_not_existing = client.get(THREAD_PAGE + str(
197 existing_post_id + 1) + '/')
198 self.assertEqual(HTTP_CODE_NOT_FOUND,
199 response_not_existing.status_code,
200 u'Not existing thread is opened')
201
202 response_existing = client.get(TAG_PAGE + tag_name + '/')
203 self.assertEqual(HTTP_CODE_OK,
204 response_existing.status_code,
205 u'Cannot open existing tag')
206
207 response_not_existing = client.get(TAG_PAGE + u'not_tag' + '/')
208 self.assertEqual(HTTP_CODE_NOT_FOUND,
209 response_not_existing.status_code,
210 u'Not existing tag is opened') No newline at end of file
@@ -1,201 +1,201 b''
1 1 from django.core.urlresolvers import reverse
2 2 from django.template import RequestContext
3 from django.shortcuts import render, redirect
3 from django.shortcuts import render, redirect, get_object_or_404
4 4 from django.http import HttpResponseRedirect
5 5
6 6 from boards import forms
7 7 import boards
8 8 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList
9 9 from boards.models import Post, Admin, Tag
10 10 import neboard
11 11
12 12
13 13 def index(request, page=0):
14 14 context = RequestContext(request)
15 15
16 16 if request.method == 'POST':
17 17 form = ThreadForm(request.POST, request.FILES,
18 18 error_class=PlainErrorList)
19 19 if form.is_valid():
20 20 return _new_post(request, form)
21 21 else:
22 22 form = forms.ThreadForm(error_class=PlainErrorList)
23 23
24 24 threads = Post.objects.get_threads(page=int(page))
25 25
26 26 # TODO Get rid of the duplicate code in index and tag views
27 27 context['threads'] = None if len(threads) == 0 else threads
28 28 context['form'] = form
29 29 context['tags'] = Tag.objects.get_popular_tags()
30 30 context['theme'] = _get_theme(request)
31 31 context['pages'] = range(Post.objects.get_thread_page_count())
32 32
33 33 return render(request, 'posting_general.html',
34 34 context)
35 35
36 36
37 37 def _new_post(request, form, thread_id=boards.models.NO_PARENT):
38 38 """Add a new post (in thread or as a reply)."""
39 39
40 40 data = form.cleaned_data
41 41
42 42 title = data['title']
43 43 text = data['text']
44 44
45 45 if 'image' in data.keys():
46 46 image = data['image']
47 47 else:
48 48 image = None
49 49
50 50 ip = _get_client_ip(request)
51 51
52 52 tags = []
53 53
54 54 new_thread = thread_id == boards.models.NO_PARENT
55 55 if new_thread:
56 56 tag_strings = data['tags']
57 57
58 58 if tag_strings:
59 59 tag_strings = tag_strings.split(' ')
60 60 for tag_name in tag_strings:
61 61 tag_name = tag_name.strip()
62 62 if len(tag_name) > 0:
63 63 tag, created = Tag.objects.get_or_create(name=tag_name)
64 64 tags.append(tag)
65 65
66 66 # TODO Add a possibility to define a link image instead of an image file.
67 67 # If a link is given, download the image automatically.
68 68
69 69 post = Post.objects.create_post(title=title, text=text, ip=ip,
70 70 parent_id=thread_id, image=image,
71 71 tags=tags)
72 72
73 73 thread_to_show = (post.id if new_thread else thread_id)
74 74
75 75 if new_thread:
76 76 return redirect(thread, post_id=thread_to_show)
77 77 else:
78 78 return redirect(reverse(thread,
79 79 kwargs={'post_id': thread_to_show}) + '#'
80 80 + str(post.id))
81 81
82 82
83 83 def tag(request, tag_name, page=0):
84 84 """Get all tag threads (posts without a parent)."""
85 85
86 tag = Tag.objects.get(name=tag_name)
86 tag = get_object_or_404(Tag, name=tag_name)
87 87 threads = Post.objects.get_threads(tag=tag, page=int(page))
88 88
89 89 if request.method == 'POST':
90 90 form = ThreadForm(request.POST, request.FILES,
91 91 error_class=PlainErrorList)
92 92 if form.is_valid():
93 93 return _new_post(request, form)
94 94 else:
95 95 form = forms.ThreadForm(initial={'tags': tag_name},
96 96 error_class=PlainErrorList)
97 97
98 98 context = RequestContext(request)
99 99 context['threads'] = None if len(threads) == 0 else threads
100 100 context['tag'] = tag_name
101 101 context['tags'] = Tag.objects.get_popular_tags()
102 102 context['theme'] = _get_theme(request)
103 103 context['pages'] = range(Post.objects.get_thread_page_count(tag=tag))
104 104
105 105 context['form'] = form
106 106
107 107 return render(request, 'posting_general.html',
108 108 context)
109 109
110 110
111 111 def thread(request, post_id):
112 112 """Get all thread posts"""
113 113
114 114 if request.method == 'POST':
115 115 form = PostForm(request.POST, request.FILES,
116 116 error_class=PlainErrorList)
117 117 if form.is_valid():
118 118 return _new_post(request, form, post_id)
119 119 else:
120 120 form = forms.PostForm(error_class=PlainErrorList)
121 121
122 122 posts = Post.objects.get_thread(post_id)
123 123
124 124 context = RequestContext(request)
125 125
126 126 context['posts'] = posts
127 127 context['form'] = form
128 128 context['tags'] = Tag.objects.get_popular_tags()
129 129 context['theme'] = _get_theme(request)
130 130
131 131 return render(request, 'thread.html', context)
132 132
133 133
134 134 def login(request):
135 135 """Log in as admin"""
136 136
137 137 if 'name' in request.POST and 'password' in request.POST:
138 138 request.session['admin'] = False
139 139
140 140 isAdmin = len(Admin.objects.filter(name=request.POST['name'],
141 141 password=request.POST[
142 142 'password'])) > 0
143 143
144 144 if isAdmin:
145 145 request.session['admin'] = True
146 146
147 147 response = HttpResponseRedirect('/')
148 148
149 149 else:
150 150 response = render(request, 'login.html', {'error': 'Login error'})
151 151 else:
152 152 response = render(request, 'login.html', {})
153 153
154 154 return response
155 155
156 156
157 157 def logout(request):
158 158 request.session['admin'] = False
159 159 return HttpResponseRedirect('/')
160 160
161 161
162 162 def settings(request):
163 163 context = RequestContext(request)
164 164
165 165 if request.method == 'POST':
166 166 form = SettingsForm(request.POST)
167 167 if form.is_valid():
168 168 selected_theme = form.cleaned_data['theme']
169 169 request.session['theme'] = selected_theme
170 170
171 171 return redirect(settings)
172 172 else:
173 173 selected_theme = _get_theme(request)
174 174 form = SettingsForm(initial={'theme': selected_theme})
175 175 context['form'] = form
176 176 context['tags'] = Tag.objects.get_popular_tags()
177 177 context['theme'] = _get_theme(request)
178 178
179 179 return render(request, 'settings.html', context)
180 180
181 181
182 182 def all_tags(request):
183 183 context = RequestContext(request)
184 184 context['tags'] = Tag.objects.get_popular_tags()
185 185 context['theme'] = _get_theme(request)
186 186 context['all_tags'] = Tag.objects.get_not_empty_tags()
187 187
188 188 return render(request, 'tags.html', context)
189 189
190 190
191 191 def _get_theme(request):
192 192 return request.session.get('theme', neboard.settings.DEFAULT_THEME)
193 193
194 194
195 195 def _get_client_ip(request):
196 196 x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
197 197 if x_forwarded_for:
198 198 ip = x_forwarded_for.split(',')[-1].strip()
199 199 else:
200 200 ip = request.META.get('REMOTE_ADDR')
201 201 return ip
General Comments 0
You need to be logged in to leave comments. Login now