##// END OF EJS Templates
Added last access time and registration time for user. This refs #61
neko259 -
r121:a76c11ea 1.1
parent child Browse files
Show More
@@ -1,335 +1,330 b''
1 import os
1 import os
2 from random import random
2 from random import random
3 import re
3 import re
4 import time
4 import time
5 import math
5 import math
6
6
7 from django.db import models
7 from django.db import models
8 from django.http import Http404
8 from django.http import Http404
9 from django.utils import timezone
9 from django.utils import timezone
10 from markupfield.fields import MarkupField
10 from markupfield.fields import MarkupField
11 from threading import Thread
11 from threading import Thread
12
12
13 from neboard import settings
13 from neboard import settings
14 import thumbs
14 import thumbs
15
15
16 IMAGE_THUMB_SIZE = (200, 150)
16 IMAGE_THUMB_SIZE = (200, 150)
17
17
18 TITLE_MAX_LENGTH = 50
18 TITLE_MAX_LENGTH = 50
19
19
20 DEFAULT_MARKUP_TYPE = 'markdown'
20 DEFAULT_MARKUP_TYPE = 'markdown'
21
21
22 NO_PARENT = -1
22 NO_PARENT = -1
23 NO_IP = '0.0.0.0'
23 NO_IP = '0.0.0.0'
24 UNKNOWN_UA = ''
24 UNKNOWN_UA = ''
25 ALL_PAGES = -1
25 ALL_PAGES = -1
26 OPENING_POST_POPULARITY_WEIGHT = 2
26 OPENING_POST_POPULARITY_WEIGHT = 2
27 IMAGES_DIRECTORY = 'images/'
27 IMAGES_DIRECTORY = 'images/'
28 FILE_EXTENSION_DELIMITER = '.'
28 FILE_EXTENSION_DELIMITER = '.'
29
29
30 REGEX_PRETTY = re.compile(r'^\d(0)+$')
30 REGEX_PRETTY = re.compile(r'^\d(0)+$')
31 REGEX_SAME = re.compile(r'^(.)\1+$')
31 REGEX_SAME = re.compile(r'^(.)\1+$')
32
32
33 RANK_ADMIN = 0
33 RANK_ADMIN = 0
34 RANK_MODERATOR = 10
34 RANK_MODERATOR = 10
35 RANK_USER = 100
35 RANK_USER = 100
36
36
37
37
38 class User(models.Model):
39
40 user_id = models.CharField(max_length=50)
41 rank = models.IntegerField()
42
43 def save_setting(self, name, value):
44 setting, created = Setting.objects.get_or_create(name=name, user=self)
45 setting.value = value
46 setting.save()
47
48 return setting
49
50 def get_setting(self, name):
51 settings = Setting.objects.filter(name=name, user=self)
52 if len(settings) > 0:
53 setting = settings[0]
54 else:
55 setting = None
56
57 if setting:
58 setting_value = setting.value
59 else:
60 setting_value = None
61
62 return setting_value
63
64 def is_moderator(self):
65 return RANK_MODERATOR >= self.rank
66
67 def __unicode__(self):
68 return self.user_id
69
70
71 class PostManager(models.Manager):
38 class PostManager(models.Manager):
72 def create_post(self, title, text, image=None, parent_id=NO_PARENT,
39 def create_post(self, title, text, image=None, parent_id=NO_PARENT,
73 ip=NO_IP, tags=None, user=None):
40 ip=NO_IP, tags=None, user=None):
74 post = self.create(title=title,
41 post = self.create(title=title,
75 text=text,
42 text=text,
76 pub_time=timezone.now(),
43 pub_time=timezone.now(),
77 parent=parent_id,
44 parent=parent_id,
78 image=image,
45 image=image,
79 poster_ip=ip,
46 poster_ip=ip,
80 poster_user_agent=UNKNOWN_UA,
47 poster_user_agent=UNKNOWN_UA,
81 last_edit_time=timezone.now(),
48 last_edit_time=timezone.now(),
82 user=user)
49 user=user)
83
50
84 if tags:
51 if tags:
85 map(post.tags.add, tags)
52 map(post.tags.add, tags)
86
53
87 if parent_id != NO_PARENT:
54 if parent_id != NO_PARENT:
88 self._bump_thread(parent_id)
55 self._bump_thread(parent_id)
89 else:
56 else:
90 self._delete_old_threads()
57 self._delete_old_threads()
91
58
92 return post
59 return post
93
60
94 def delete_post(self, post):
61 def delete_post(self, post):
95 children = self.filter(parent=post.id)
62 children = self.filter(parent=post.id)
96 for child in children:
63 for child in children:
97 self.delete_post(child)
64 self.delete_post(child)
98 post.delete()
65 post.delete()
99
66
100 def delete_posts_by_ip(self, ip):
67 def delete_posts_by_ip(self, ip):
101 posts = self.filter(poster_ip=ip)
68 posts = self.filter(poster_ip=ip)
102 for post in posts:
69 for post in posts:
103 self.delete_post(post)
70 self.delete_post(post)
104
71
105 def get_threads(self, tag=None, page=ALL_PAGES,
72 def get_threads(self, tag=None, page=ALL_PAGES,
106 order_by='-last_edit_time'):
73 order_by='-last_edit_time'):
107 if tag:
74 if tag:
108 threads = self.filter(parent=NO_PARENT, tags=tag)
75 threads = self.filter(parent=NO_PARENT, tags=tag)
109
76
110 # TODO Throw error 404 if no threads for tag found?
77 # TODO Throw error 404 if no threads for tag found?
111 else:
78 else:
112 threads = self.filter(parent=NO_PARENT)
79 threads = self.filter(parent=NO_PARENT)
113
80
114 threads = threads.order_by(order_by)
81 threads = threads.order_by(order_by)
115
82
116 if page != ALL_PAGES:
83 if page != ALL_PAGES:
117 thread_count = len(threads)
84 thread_count = len(threads)
118
85
119 if page < self.get_thread_page_count(tag=tag):
86 if page < self.get_thread_page_count(tag=tag):
120 start_thread = page * settings.THREADS_PER_PAGE
87 start_thread = page * settings.THREADS_PER_PAGE
121 end_thread = min(start_thread + settings.THREADS_PER_PAGE,
88 end_thread = min(start_thread + settings.THREADS_PER_PAGE,
122 thread_count)
89 thread_count)
123 threads = threads[start_thread:end_thread]
90 threads = threads[start_thread:end_thread]
124
91
125 return threads
92 return threads
126
93
127 def get_thread(self, opening_post_id):
94 def get_thread(self, opening_post_id):
128 try:
95 try:
129 opening_post = self.get(id=opening_post_id, parent=NO_PARENT)
96 opening_post = self.get(id=opening_post_id, parent=NO_PARENT)
130 except Post.DoesNotExist:
97 except Post.DoesNotExist:
131 raise Http404
98 raise Http404
132
99
133 if opening_post.parent == NO_PARENT:
100 if opening_post.parent == NO_PARENT:
134 replies = self.filter(parent=opening_post_id)
101 replies = self.filter(parent=opening_post_id)
135
102
136 thread = [opening_post]
103 thread = [opening_post]
137 thread.extend(replies)
104 thread.extend(replies)
138
105
139 return thread
106 return thread
140
107
141 def exists(self, post_id):
108 def exists(self, post_id):
142 posts = self.filter(id=post_id)
109 posts = self.filter(id=post_id)
143
110
144 return posts.count() > 0
111 return posts.count() > 0
145
112
146 def get_thread_page_count(self, tag=None):
113 def get_thread_page_count(self, tag=None):
147 if tag:
114 if tag:
148 threads = self.filter(parent=NO_PARENT, tags=tag)
115 threads = self.filter(parent=NO_PARENT, tags=tag)
149 else:
116 else:
150 threads = self.filter(parent=NO_PARENT)
117 threads = self.filter(parent=NO_PARENT)
151
118
152 return int(math.ceil(threads.count() / float(
119 return int(math.ceil(threads.count() / float(
153 settings.THREADS_PER_PAGE)))
120 settings.THREADS_PER_PAGE)))
154
121
155 def _delete_old_threads(self):
122 def _delete_old_threads(self):
156 """
123 """
157 Preserves maximum thread count. If there are too many threads,
124 Preserves maximum thread count. If there are too many threads,
158 delete the old ones.
125 delete the old ones.
159 """
126 """
160
127
161 # TODO Move old threads to the archive instead of deleting them.
128 # TODO Move old threads to the archive instead of deleting them.
162 # Maybe make some 'old' field in the model to indicate the thread
129 # Maybe make some 'old' field in the model to indicate the thread
163 # must not be shown and be able for replying.
130 # must not be shown and be able for replying.
164
131
165 threads = self.get_threads()
132 threads = self.get_threads()
166 thread_count = len(threads)
133 thread_count = len(threads)
167
134
168 if thread_count > settings.MAX_THREAD_COUNT:
135 if thread_count > settings.MAX_THREAD_COUNT:
169 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
136 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
170 old_threads = threads[thread_count - num_threads_to_delete:]
137 old_threads = threads[thread_count - num_threads_to_delete:]
171
138
172 for thread in old_threads:
139 for thread in old_threads:
173 self.delete_post(thread)
140 self.delete_post(thread)
174
141
175 def _bump_thread(self, thread_id):
142 def _bump_thread(self, thread_id):
176 thread = self.get(id=thread_id)
143 thread = self.get(id=thread_id)
177
144
178 if thread.can_bump():
145 if thread.can_bump():
179 thread.last_edit_time = timezone.now()
146 thread.last_edit_time = timezone.now()
180 thread.save()
147 thread.save()
181
148
182
149
183 class TagManager(models.Manager):
150 class TagManager(models.Manager):
184 def get_not_empty_tags(self):
151 def get_not_empty_tags(self):
185 all_tags = self.all().order_by('name')
152 all_tags = self.all().order_by('name')
186 tags = []
153 tags = []
187 for tag in all_tags:
154 for tag in all_tags:
188 if not tag.is_empty():
155 if not tag.is_empty():
189 tags.append(tag)
156 tags.append(tag)
190
157
191 return tags
158 return tags
192
159
193 def get_popular_tags(self):
160 def get_popular_tags(self):
194 all_tags = self.get_not_empty_tags()
161 all_tags = self.get_not_empty_tags()
195
162
196 sorted_tags = sorted(all_tags, key=lambda tag: tag.get_popularity(),
163 sorted_tags = sorted(all_tags, key=lambda tag: tag.get_popularity(),
197 reverse=True)
164 reverse=True)
198
165
199 return sorted_tags[:settings.POPULAR_TAGS]
166 return sorted_tags[:settings.POPULAR_TAGS]
200
167
201
168
202 class Tag(models.Model):
169 class Tag(models.Model):
203 """
170 """
204 A tag is a text node assigned to the post. The tag serves as a board
171 A tag is a text node assigned to the post. The tag serves as a board
205 section. There can be multiple tags for each message
172 section. There can be multiple tags for each message
206 """
173 """
207
174
208 objects = TagManager()
175 objects = TagManager()
209
176
210 name = models.CharField(max_length=100)
177 name = models.CharField(max_length=100)
211 # TODO Connect the tag to its posts to check the number of threads for
178 # TODO Connect the tag to its posts to check the number of threads for
212 # the tag.
179 # the tag.
213
180
214 def __unicode__(self):
181 def __unicode__(self):
215 return self.name
182 return self.name
216
183
217 def is_empty(self):
184 def is_empty(self):
218 return self.get_post_count() == 0
185 return self.get_post_count() == 0
219
186
220 def get_post_count(self):
187 def get_post_count(self):
221 posts_with_tag = Post.objects.get_threads(tag=self)
188 posts_with_tag = Post.objects.get_threads(tag=self)
222 return posts_with_tag.count()
189 return posts_with_tag.count()
223
190
224 def get_popularity(self):
191 def get_popularity(self):
225 posts_with_tag = Post.objects.get_threads(tag=self)
192 posts_with_tag = Post.objects.get_threads(tag=self)
226 reply_count = 0
193 reply_count = 0
227 for post in posts_with_tag:
194 for post in posts_with_tag:
228 reply_count += post.get_reply_count()
195 reply_count += post.get_reply_count()
229 reply_count += OPENING_POST_POPULARITY_WEIGHT
196 reply_count += OPENING_POST_POPULARITY_WEIGHT
230
197
231 return reply_count
198 return reply_count
232
199
233
200
234 class Post(models.Model):
201 class Post(models.Model):
235 """A post is a message."""
202 """A post is a message."""
236
203
237 objects = PostManager()
204 objects = PostManager()
238
205
239 def _update_image_filename(self, filename):
206 def _update_image_filename(self, filename):
240 """Get unique image filename"""
207 """Get unique image filename"""
241
208
242 path = IMAGES_DIRECTORY
209 path = IMAGES_DIRECTORY
243 new_name = str(int(time.mktime(time.gmtime())))
210 new_name = str(int(time.mktime(time.gmtime())))
244 new_name += str(int(random() * 1000))
211 new_name += str(int(random() * 1000))
245 new_name += FILE_EXTENSION_DELIMITER
212 new_name += FILE_EXTENSION_DELIMITER
246 new_name += filename.split(FILE_EXTENSION_DELIMITER)[-1:][0]
213 new_name += filename.split(FILE_EXTENSION_DELIMITER)[-1:][0]
247
214
248 return os.path.join(path, new_name)
215 return os.path.join(path, new_name)
249
216
250 title = models.CharField(max_length=TITLE_MAX_LENGTH)
217 title = models.CharField(max_length=TITLE_MAX_LENGTH)
251 pub_time = models.DateTimeField()
218 pub_time = models.DateTimeField()
252 text = MarkupField(default_markup_type=DEFAULT_MARKUP_TYPE,
219 text = MarkupField(default_markup_type=DEFAULT_MARKUP_TYPE,
253 escape_html=False)
220 escape_html=False)
254 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
221 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
255 blank=True, sizes=(IMAGE_THUMB_SIZE,))
222 blank=True, sizes=(IMAGE_THUMB_SIZE,))
256 poster_ip = models.IPAddressField()
223 poster_ip = models.IPAddressField()
257 poster_user_agent = models.TextField()
224 poster_user_agent = models.TextField()
258 parent = models.BigIntegerField()
225 parent = models.BigIntegerField()
259 tags = models.ManyToManyField(Tag)
226 tags = models.ManyToManyField(Tag)
260 last_edit_time = models.DateTimeField()
227 last_edit_time = models.DateTimeField()
261 user = models.ForeignKey(User, null=True, default=None)
228 user = models.ForeignKey(User, null=True, default=None)
262
229
263 def __unicode__(self):
230 def __unicode__(self):
264 return '#' + str(self.id) + ' ' + self.title + ' (' + self.text.raw + \
231 return '#' + str(self.id) + ' ' + self.title + ' (' + self.text.raw + \
265 ')'
232 ')'
266
233
267 def _get_replies(self):
234 def _get_replies(self):
268 return Post.objects.filter(parent=self.id)
235 return Post.objects.filter(parent=self.id)
269
236
270 def get_reply_count(self):
237 def get_reply_count(self):
271 return self._get_replies().count()
238 return self._get_replies().count()
272
239
273 def get_images_count(self):
240 def get_images_count(self):
274 images_count = 1 if self.image else 0
241 images_count = 1 if self.image else 0
275 for reply in self._get_replies():
242 for reply in self._get_replies():
276 if reply.image:
243 if reply.image:
277 images_count += 1
244 images_count += 1
278
245
279 return images_count
246 return images_count
280
247
281 def get_gets_count(self):
248 def get_gets_count(self):
282 gets_count = 1 if self.is_get() else 0
249 gets_count = 1 if self.is_get() else 0
283 for reply in self._get_replies():
250 for reply in self._get_replies():
284 if reply.is_get():
251 if reply.is_get():
285 gets_count += 1
252 gets_count += 1
286
253
287 return gets_count
254 return gets_count
288
255
289 def is_get(self):
256 def is_get(self):
290 """If the post has pretty id (1, 1000, 77777), than it is called GET"""
257 """If the post has pretty id (1, 1000, 77777), than it is called GET"""
291
258
292 first = self.id == 1
259 first = self.id == 1
293
260
294 id_str = str(self.id)
261 id_str = str(self.id)
295 pretty = REGEX_PRETTY.match(id_str)
262 pretty = REGEX_PRETTY.match(id_str)
296 same_digits = REGEX_SAME.match(id_str)
263 same_digits = REGEX_SAME.match(id_str)
297
264
298 return first or pretty or same_digits
265 return first or pretty or same_digits
299
266
300 def can_bump(self):
267 def can_bump(self):
301 """Check if the thread can be bumped by replying"""
268 """Check if the thread can be bumped by replying"""
302
269
303 replies_count = len(Post.objects.get_thread(self.id))
270 replies_count = len(Post.objects.get_thread(self.id))
304
271
305 return replies_count <= settings.MAX_POSTS_PER_THREAD
272 return replies_count <= settings.MAX_POSTS_PER_THREAD
306
273
307 def get_last_replies(self):
274 def get_last_replies(self):
308 if settings.LAST_REPLIES_COUNT > 0:
275 if settings.LAST_REPLIES_COUNT > 0:
309 reply_count = self.get_reply_count()
276 reply_count = self.get_reply_count()
310
277
311 if reply_count > 0:
278 if reply_count > 0:
312 reply_count_to_show = min(settings.LAST_REPLIES_COUNT,
279 reply_count_to_show = min(settings.LAST_REPLIES_COUNT,
313 reply_count)
280 reply_count)
314 last_replies = self._get_replies()[reply_count
281 last_replies = self._get_replies()[reply_count
315 - reply_count_to_show:]
282 - reply_count_to_show:]
316
283
317 return last_replies
284 return last_replies
318
285
319
286
320 class Admin(models.Model):
287 class User(models.Model):
321 """
288
322 Model for admin users
289 user_id = models.CharField(max_length=50)
323 """
290 rank = models.IntegerField()
324 name = models.CharField(max_length=100)
291
325 password = models.CharField(max_length=100)
292 registration_time = models.DateTimeField()
293 last_access_time = models.DateTimeField()
294
295 fav_tags = models.ManyToManyField(Tag)
296 fav_threads = models.ManyToManyField(Post)
297
298 def save_setting(self, name, value):
299 setting, created = Setting.objects.get_or_create(name=name, user=self)
300 setting.value = value
301 setting.save()
302
303 return setting
304
305 def get_setting(self, name):
306 settings = Setting.objects.filter(name=name, user=self)
307 if len(settings) > 0:
308 setting = settings[0]
309 else:
310 setting = None
311
312 if setting:
313 setting_value = setting.value
314 else:
315 setting_value = None
316
317 return setting_value
318
319 def is_moderator(self):
320 return RANK_MODERATOR >= self.rank
326
321
327 def __unicode__(self):
322 def __unicode__(self):
328 return self.name + '/' + '*' * len(self.password)
323 return self.user_id
329
324
330
325
331 class Setting(models.Model):
326 class Setting(models.Model):
332
327
333 name = models.CharField(max_length=50)
328 name = models.CharField(max_length=50)
334 value = models.CharField(max_length=50)
329 value = models.CharField(max_length=50)
335 user = models.ForeignKey(User)
330 user = models.ForeignKey(User)
@@ -1,287 +1,292 b''
1 import hashlib
1 import hashlib
2 from django.core.urlresolvers import reverse
2 from django.core.urlresolvers import reverse
3 from django.template import RequestContext
3 from django.template import RequestContext
4 from django.shortcuts import render, redirect, get_object_or_404
4 from django.shortcuts import render, redirect, get_object_or_404
5 from django.http import HttpResponseRedirect
5 from django.http import HttpResponseRedirect
6 from django.utils import timezone
6
7
7 from boards import forms
8 from boards import forms
8 import boards
9 import boards
9 from boards import utils
10 from boards import utils
10 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
11 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
11 ThreadCaptchaForm, PostCaptchaForm
12 ThreadCaptchaForm, PostCaptchaForm
12
13
13 from boards.models import Post, Admin, Tag, User, RANK_USER, RANK_MODERATOR, NO_PARENT
14 from boards.models import Post, Admin, Tag, User, RANK_USER, RANK_MODERATOR, NO_PARENT
14 from boards import authors
15 from boards import authors
15 import neboard
16 import neboard
16
17
17
18
18 def index(request, page=0):
19 def index(request, page=0):
19 context = _init_default_context(request)
20 context = _init_default_context(request)
20
21
21 if utils.need_include_captcha(request):
22 if utils.need_include_captcha(request):
22 threadFormClass = ThreadCaptchaForm
23 threadFormClass = ThreadCaptchaForm
23 kwargs = {'request': request}
24 kwargs = {'request': request}
24 else:
25 else:
25 threadFormClass = ThreadForm
26 threadFormClass = ThreadForm
26 kwargs = {}
27 kwargs = {}
27
28
28 if request.method == 'POST':
29 if request.method == 'POST':
29 form = threadFormClass(request.POST, request.FILES,
30 form = threadFormClass(request.POST, request.FILES,
30 error_class=PlainErrorList, **kwargs)
31 error_class=PlainErrorList, **kwargs)
31
32
32 if form.is_valid():
33 if form.is_valid():
33 return _new_post(request, form)
34 return _new_post(request, form)
34 else:
35 else:
35 form = threadFormClass(error_class=PlainErrorList, **kwargs)
36 form = threadFormClass(error_class=PlainErrorList, **kwargs)
36
37
37 threads = Post.objects.get_threads(page=int(page))
38 threads = Post.objects.get_threads(page=int(page))
38
39
39 context['threads'] = None if len(threads) == 0 else threads
40 context['threads'] = None if len(threads) == 0 else threads
40 context['form'] = form
41 context['form'] = form
41 context['pages'] = range(Post.objects.get_thread_page_count())
42 context['pages'] = range(Post.objects.get_thread_page_count())
42
43
43 return render(request, 'boards/posting_general.html',
44 return render(request, 'boards/posting_general.html',
44 context)
45 context)
45
46
46
47
47 def _new_post(request, form, thread_id=boards.models.NO_PARENT):
48 def _new_post(request, form, thread_id=boards.models.NO_PARENT):
48 """Add a new post (in thread or as a reply)."""
49 """Add a new post (in thread or as a reply)."""
49
50
50 data = form.cleaned_data
51 data = form.cleaned_data
51
52
52 title = data['title']
53 title = data['title']
53 text = data['text']
54 text = data['text']
54
55
55 if 'image' in data.keys():
56 if 'image' in data.keys():
56 image = data['image']
57 image = data['image']
57 else:
58 else:
58 image = None
59 image = None
59
60
60 ip = _get_client_ip(request)
61 ip = _get_client_ip(request)
61
62
62 tags = []
63 tags = []
63
64
64 new_thread = thread_id == boards.models.NO_PARENT
65 new_thread = thread_id == boards.models.NO_PARENT
65 if new_thread:
66 if new_thread:
66 tag_strings = data['tags']
67 tag_strings = data['tags']
67
68
68 if tag_strings:
69 if tag_strings:
69 tag_strings = tag_strings.split(' ')
70 tag_strings = tag_strings.split(' ')
70 for tag_name in tag_strings:
71 for tag_name in tag_strings:
71 tag_name = tag_name.strip()
72 tag_name = tag_name.strip()
72 if len(tag_name) > 0:
73 if len(tag_name) > 0:
73 tag, created = Tag.objects.get_or_create(name=tag_name)
74 tag, created = Tag.objects.get_or_create(name=tag_name)
74 tags.append(tag)
75 tags.append(tag)
75
76
76 # TODO Add a possibility to define a link image instead of an image file.
77 # TODO Add a possibility to define a link image instead of an image file.
77 # If a link is given, download the image automatically.
78 # If a link is given, download the image automatically.
78
79
79 post = Post.objects.create_post(title=title, text=text, ip=ip,
80 post = Post.objects.create_post(title=title, text=text, ip=ip,
80 parent_id=thread_id, image=image,
81 parent_id=thread_id, image=image,
81 tags=tags)
82 tags=tags)
82
83
83 thread_to_show = (post.id if new_thread else thread_id)
84 thread_to_show = (post.id if new_thread else thread_id)
84
85
85 if new_thread:
86 if new_thread:
86 return redirect(thread, post_id=thread_to_show)
87 return redirect(thread, post_id=thread_to_show)
87 else:
88 else:
88 return redirect(reverse(thread,
89 return redirect(reverse(thread,
89 kwargs={'post_id': thread_to_show}) + '#'
90 kwargs={'post_id': thread_to_show}) + '#'
90 + str(post.id))
91 + str(post.id))
91
92
92
93
93 def tag(request, tag_name, page=0):
94 def tag(request, tag_name, page=0):
94 """Get all tag threads (posts without a parent)."""
95 """Get all tag threads (posts without a parent)."""
95
96
96 tag = get_object_or_404(Tag, name=tag_name)
97 tag = get_object_or_404(Tag, name=tag_name)
97 threads = Post.objects.get_threads(tag=tag, page=int(page))
98 threads = Post.objects.get_threads(tag=tag, page=int(page))
98
99
99 if request.method == 'POST':
100 if request.method == 'POST':
100 form = ThreadForm(request.POST, request.FILES,
101 form = ThreadForm(request.POST, request.FILES,
101 error_class=PlainErrorList)
102 error_class=PlainErrorList)
102 if form.is_valid():
103 if form.is_valid():
103 return _new_post(request, form)
104 return _new_post(request, form)
104 else:
105 else:
105 form = forms.ThreadForm(initial={'tags': tag_name},
106 form = forms.ThreadForm(initial={'tags': tag_name},
106 error_class=PlainErrorList)
107 error_class=PlainErrorList)
107
108
108 context = _init_default_context(request)
109 context = _init_default_context(request)
109 context['threads'] = None if len(threads) == 0 else threads
110 context['threads'] = None if len(threads) == 0 else threads
110 context['tag'] = tag_name
111 context['tag'] = tag_name
111 context['pages'] = range(Post.objects.get_thread_page_count(tag=tag))
112 context['pages'] = range(Post.objects.get_thread_page_count(tag=tag))
112
113
113 context['form'] = form
114 context['form'] = form
114
115
115 return render(request, 'boards/posting_general.html',
116 return render(request, 'boards/posting_general.html',
116 context)
117 context)
117
118
118
119
119 def thread(request, post_id):
120 def thread(request, post_id):
120 """Get all thread posts"""
121 """Get all thread posts"""
121
122
122 if utils.need_include_captcha(request):
123 if utils.need_include_captcha(request):
123 postFormClass = PostCaptchaForm
124 postFormClass = PostCaptchaForm
124 kwargs = {'request': request}
125 kwargs = {'request': request}
125 else:
126 else:
126 postFormClass = PostForm
127 postFormClass = PostForm
127 kwargs = {}
128 kwargs = {}
128
129
129 if request.method == 'POST':
130 if request.method == 'POST':
130 form = postFormClass(request.POST, request.FILES,
131 form = postFormClass(request.POST, request.FILES,
131 error_class=PlainErrorList, **kwargs)
132 error_class=PlainErrorList, **kwargs)
132 if form.is_valid():
133 if form.is_valid():
133 return _new_post(request, form, post_id)
134 return _new_post(request, form, post_id)
134 else:
135 else:
135 form = postFormClass(error_class=PlainErrorList, **kwargs)
136 form = postFormClass(error_class=PlainErrorList, **kwargs)
136
137
137 posts = Post.objects.get_thread(post_id)
138 posts = Post.objects.get_thread(post_id)
138
139
139 context = _init_default_context(request)
140 context = _init_default_context(request)
140
141
141 context['posts'] = posts
142 context['posts'] = posts
142 context['form'] = form
143 context['form'] = form
143
144
144 return render(request, 'boards/thread.html', context)
145 return render(request, 'boards/thread.html', context)
145
146
146
147
147 def login(request):
148 def login(request):
148 """Log in as admin"""
149 """Log in as admin"""
149
150
150 if 'name' in request.POST and 'password' in request.POST:
151 if 'name' in request.POST and 'password' in request.POST:
151 request.session['admin'] = False
152 request.session['admin'] = False
152
153
153 isAdmin = len(Admin.objects.filter(name=request.POST['name'],
154 isAdmin = len(Admin.objects.filter(name=request.POST['name'],
154 password=request.POST[
155 password=request.POST[
155 'password'])) > 0
156 'password'])) > 0
156
157
157 if isAdmin:
158 if isAdmin:
158 request.session['admin'] = True
159 request.session['admin'] = True
159
160
160 response = HttpResponseRedirect('/')
161 response = HttpResponseRedirect('/')
161
162
162 else:
163 else:
163 response = render(request, 'boards/login.html', {'error': 'Login error'})
164 response = render(request, 'boards/login.html', {'error': 'Login error'})
164 else:
165 else:
165 response = render(request, 'boards/login.html', {})
166 response = render(request, 'boards/login.html', {})
166
167
167 return response
168 return response
168
169
169
170
170 def logout(request):
171 def logout(request):
171 request.session['admin'] = False
172 request.session['admin'] = False
172 return HttpResponseRedirect('/')
173 return HttpResponseRedirect('/')
173
174
174
175
175 def settings(request):
176 def settings(request):
176 """User's settings"""
177 """User's settings"""
177
178
178 context = _init_default_context(request)
179 context = _init_default_context(request)
179
180
180 if request.method == 'POST':
181 if request.method == 'POST':
181 form = SettingsForm(request.POST)
182 form = SettingsForm(request.POST)
182 if form.is_valid():
183 if form.is_valid():
183 selected_theme = form.cleaned_data['theme']
184 selected_theme = form.cleaned_data['theme']
184
185
185 user = _get_user(request)
186 user = _get_user(request)
186 user.save_setting('theme', selected_theme)
187 user.save_setting('theme', selected_theme)
187
188
188 return redirect(settings)
189 return redirect(settings)
189 else:
190 else:
190 selected_theme = _get_theme(request)
191 selected_theme = _get_theme(request)
191 form = SettingsForm(initial={'theme': selected_theme})
192 form = SettingsForm(initial={'theme': selected_theme})
192 context['form'] = form
193 context['form'] = form
193
194
194 return render(request, 'boards/settings.html', context)
195 return render(request, 'boards/settings.html', context)
195
196
196
197
197 def all_tags(request):
198 def all_tags(request):
198 """All tags list"""
199 """All tags list"""
199
200
200 context = _init_default_context(request)
201 context = _init_default_context(request)
201 context['all_tags'] = Tag.objects.get_not_empty_tags()
202 context['all_tags'] = Tag.objects.get_not_empty_tags()
202
203
203 return render(request, 'boards/tags.html', context)
204 return render(request, 'boards/tags.html', context)
204
205
205
206
206 def jump_to_post(request, post_id):
207 def jump_to_post(request, post_id):
207 """Determine thread in which the requested post is and open it's page"""
208 """Determine thread in which the requested post is and open it's page"""
208
209
209 post = get_object_or_404(Post, id=post_id)
210 post = get_object_or_404(Post, id=post_id)
210
211
211 if boards.models.NO_PARENT == post.parent:
212 if boards.models.NO_PARENT == post.parent:
212 return redirect(thread, post_id=post.id)
213 return redirect(thread, post_id=post.id)
213 else:
214 else:
214 parent_thread = get_object_or_404(Post, id=post.parent)
215 parent_thread = get_object_or_404(Post, id=post.parent)
215 return redirect(reverse(thread, kwargs={'post_id': parent_thread.id})
216 return redirect(reverse(thread, kwargs={'post_id': parent_thread.id})
216 + '#' + str(post.id))
217 + '#' + str(post.id))
217
218
218
219
219 def authors(request):
220 def authors(request):
220 context = _init_default_context(request)
221 context = _init_default_context(request)
221 context['authors'] = boards.authors.authors
222 context['authors'] = boards.authors.authors
222
223
223 return render(request, 'boards/authors.html', context)
224 return render(request, 'boards/authors.html', context)
224
225
225
226
226 def delete(request, post_id):
227 def delete(request, post_id):
227 user = _get_user(request)
228 user = _get_user(request)
228 post = get_object_or_404(Post, id=post_id)
229 post = get_object_or_404(Post, id=post_id)
229
230
230 if user.is_moderator():
231 if user.is_moderator():
231 Post.objects.delete_post(post)
232 Post.objects.delete_post(post)
232
233
233 if NO_PARENT == post.parent:
234 if NO_PARENT == post.parent:
234 return redirect(index)
235 return redirect(index)
235 else:
236 else:
236 return redirect(thread, post_id=post.parent)
237 return redirect(thread, post_id=post.parent)
237
238
238
239
239 def _get_theme(request):
240 def _get_theme(request):
240 """Get user's CSS theme"""
241 """Get user's CSS theme"""
241
242
242 user = _get_user(request)
243 user = _get_user(request)
243 theme = user.get_setting('theme')
244 theme = user.get_setting('theme')
244 if not theme:
245 if not theme:
245 theme = neboard.settings.DEFAULT_THEME
246 theme = neboard.settings.DEFAULT_THEME
246
247
247 return theme
248 return theme
248
249
249
250
250 def _get_client_ip(request):
251 def _get_client_ip(request):
251 x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
252 x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
252 if x_forwarded_for:
253 if x_forwarded_for:
253 ip = x_forwarded_for.split(',')[-1].strip()
254 ip = x_forwarded_for.split(',')[-1].strip()
254 else:
255 else:
255 ip = request.META.get('REMOTE_ADDR')
256 ip = request.META.get('REMOTE_ADDR')
256 return ip
257 return ip
257
258
258
259
259 def _init_default_context(request):
260 def _init_default_context(request):
260 """Create context with default values that are used in most views"""
261 """Create context with default values that are used in most views"""
261
262
262 context = RequestContext(request)
263 context = RequestContext(request)
263 context['tags'] = Tag.objects.get_popular_tags()
264 context['tags'] = Tag.objects.get_popular_tags()
264 context['theme'] = _get_theme(request)
265 context['theme'] = _get_theme(request)
265 context['user'] = _get_user(request)
266 context['user'] = _get_user(request)
266
267
267 return context
268 return context
268
269
269
270
270 def _get_user(request):
271 def _get_user(request):
271 """Get current user from the session"""
272 """Get current user from the session"""
272
273
273 session = request.session
274 session = request.session
274 if not 'user_id' in session:
275 if not 'user_id' in session:
275 request.session.save()
276 request.session.save()
276
277
277 md5 = hashlib.md5()
278 md5 = hashlib.md5()
278 md5.update(session.session_key)
279 md5.update(session.session_key)
279 new_id = md5.hexdigest()
280 new_id = md5.hexdigest()
280
281
281 user = User.objects.create(user_id=new_id, rank=RANK_USER)
282 user = User.objects.create(user_id=new_id, rank=RANK_USER,
283 registration_time=timezone.now())
282
284
283 session['user_id'] = user.id
285 session['user_id'] = user.id
284 else:
286 else:
285 user = User.objects.get(id=session['user_id'])
287 user = User.objects.get(id=session['user_id'])
288 user.save()
289
290 user.last_access_time = timezone.now()
286
291
287 return user No newline at end of file
292 return user
General Comments 0
You need to be logged in to leave comments. Login now