##// END OF EJS Templates
Added posts count to the profile page.
neko259 -
r185:9f3a047d default
parent child Browse files
Show More
1 NO CONTENT: modified file, binary diff hidden
@@ -1,266 +1,268 b''
1 1 # SOME DESCRIPTIVE TITLE.
2 2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 3 # This file is distributed under the same license as the PACKAGE package.
4 4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5 5 #
6 6 msgid ""
7 7 msgstr ""
8 8 "Project-Id-Version: PACKAGE VERSION\n"
9 9 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2013-09-09 21:52+0300\n"
10 "POT-Creation-Date: 2013-09-14 18:46+0300\n"
11 11 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12 12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13 13 "Language-Team: LANGUAGE <LL@li.org>\n"
14 14 "Language: ru\n"
15 15 "MIME-Version: 1.0\n"
16 16 "Content-Type: text/plain; charset=UTF-8\n"
17 17 "Content-Transfer-Encoding: 8bit\n"
18 18 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
19 19 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
20 20
21 21 #: templates/boards/404.html:6
22 22 msgid "Not found"
23 23 msgstr "Не найдено"
24 24
25 25 #: templates/boards/404.html:12
26 26 msgid "This page does not exist"
27 27 msgstr "Этой страницы не существует"
28 28
29 29 #: templates/boards/authors.html:6
30 30 msgid "Authors"
31 31 msgstr "Авторы"
32 32
33 33 #: templates/boards/authors.html:24
34 34 msgid "Distributed under the"
35 35 msgstr "Распространяется под"
36 36
37 37 #: templates/boards/authors.html:26
38 38 msgid "license"
39 39 msgstr "лицензией"
40 40
41 41 #: templates/boards/authors.html:28
42 42 msgid "Repository"
43 43 msgstr "Репозиторий"
44 44
45 45 #: templates/boards/base.html:12
46 46 msgid "Feed"
47 47 msgstr "Лента"
48 48
49 49 #: templates/boards/base.html:29
50 50 msgid "All threads"
51 51 msgstr "Все темы"
52 52
53 53 #: templates/boards/base.html:34
54 54 msgid "Tag management"
55 55 msgstr "Управление тегами"
56 56
57 57 #: templates/boards/base.html:36
58 58 msgid "Settings"
59 59 msgstr "Настройки"
60 60
61 61 #: templates/boards/base.html:43 templates/boards/login.html:6
62 62 #: templates/boards/login.html.py:21
63 63 msgid "Login"
64 64 msgstr "Вход"
65 65
66 66 #: templates/boards/base.html:44
67 67 msgid "Up"
68 68 msgstr "Вверх"
69 69
70 70 #: templates/boards/login.html:15
71 71 msgid "User ID"
72 72 msgstr "ID пользователя"
73 73
74 74 #: templates/boards/login.html:24
75 75 msgid "Insert your user id above"
76 76 msgstr "Вставьте свой ID пользователя выше"
77 77
78 78 #: templates/boards/posting_general.html:18
79 79 msgid "Tag: "
80 80 msgstr "Тег: "
81 81
82 #: templates/boards/posting_general.html:35
83 #: templates/boards/posting_general.html:89 templates/boards/thread.html:27
82 #: templates/boards/posting_general.html:43
83 #: templates/boards/posting_general.html:99 templates/boards/thread.html:27
84 84 #: templates/boards/rss/post.html:5
85 85 msgid "Post image"
86 86 msgstr "Изображение сообщения"
87 87
88 #: templates/boards/posting_general.html:48
88 #: templates/boards/posting_general.html:56
89 89 msgid "Reply"
90 90 msgstr "Ответ"
91 91
92 #: templates/boards/posting_general.html:54 templates/boards/thread.html:45
92 #: templates/boards/posting_general.html:61 templates/boards/thread.html:45
93 93 msgid "Delete"
94 94 msgstr "Удалить"
95 95
96 #: templates/boards/posting_general.html:63 templates/boards/thread.html:112
96 #: templates/boards/posting_general.html:64 templates/boards/thread.html:48
97 msgid "Ban IP"
98 msgstr "Заблокировать IP"
99
100 #: templates/boards/posting_general.html:73 templates/boards/thread.html:112
97 101 msgid "replies"
98 102 msgstr "ответов"
99 103
100 #: templates/boards/posting_general.html:64 templates/boards/thread.html:113
104 #: templates/boards/posting_general.html:74 templates/boards/thread.html:113
101 105 msgid "images"
102 106 msgstr "изображений"
103 107
104 #: templates/boards/posting_general.html:66
105 #: templates/boards/posting_general.html:139 templates/boards/tags.html:7
108 #: templates/boards/posting_general.html:76
109 #: templates/boards/posting_general.html:149 templates/boards/tags.html:7
106 110 #: templates/boards/thread.html:58 templates/boards/rss/post.html:10
107 111 msgid "Tags"
108 112 msgstr "Теги"
109 113
110 #: templates/boards/posting_general.html:115
114 #: templates/boards/posting_general.html:125
111 115 msgid "No threads exist. Create the first one!"
112 116 msgstr "Нет тем. Создайте первую!"
113 117
114 #: templates/boards/posting_general.html:121
118 #: templates/boards/posting_general.html:131
115 119 msgid "Create new thread"
116 120 msgstr "Создать новую тему"
117 121
118 #: templates/boards/posting_general.html:124 templates/boards/thread.html:77
122 #: templates/boards/posting_general.html:134 templates/boards/thread.html:77
119 123 msgid "Title"
120 124 msgstr "Заголовок"
121 125
122 #: templates/boards/posting_general.html:129 templates/boards/thread.html:82
126 #: templates/boards/posting_general.html:139 templates/boards/thread.html:82
123 127 msgid "Text"
124 128 msgstr "Текст"
125 129
126 #: templates/boards/posting_general.html:134 templates/boards/thread.html:87
130 #: templates/boards/posting_general.html:144 templates/boards/thread.html:87
127 131 msgid "Image"
128 132 msgstr "Изображение"
129 133
130 #: templates/boards/posting_general.html:152 templates/boards/thread.html:101
134 #: templates/boards/posting_general.html:162 templates/boards/thread.html:101
131 135 msgid "Post"
132 136 msgstr "Отправить"
133 137
134 #: templates/boards/posting_general.html:154
138 #: templates/boards/posting_general.html:164
135 139 msgid "Tags must be delimited by spaces. Text or image is required."
136 140 msgstr ""
137 141 "Теги должны быть разделены пробелами. Текст или изображение обязательны."
138 142
139 #: templates/boards/posting_general.html:157 templates/boards/thread.html:103
143 #: templates/boards/posting_general.html:167 templates/boards/thread.html:103
140 144 msgid "Text syntax"
141 145 msgstr "Синтаксис текста"
142 146
143 #: templates/boards/posting_general.html:167
147 #: templates/boards/posting_general.html:177
144 148 msgid "Pages:"
145 149 msgstr "Страницы: "
146 150
147 #: templates/boards/settings.html:12
151 #: templates/boards/settings.html:13
148 152 msgid "User:"
149 153 msgstr "Пользователь:"
150 154
151 #: templates/boards/settings.html:14
155 #: templates/boards/settings.html:15
152 156 msgid "You are moderator."
153 157 msgstr "Вы модератор."
154 158
155 #: templates/boards/settings.html:20
159 #: templates/boards/settings.html:18
160 msgid "Posts:"
161 msgstr "Сообщений:"
162
163 #: templates/boards/settings.html:23
156 164 msgid "Theme"
157 165 msgstr "Тема"
158 166
159 #: templates/boards/settings.html:36
167 #: templates/boards/settings.html:39
160 168 msgid "Save"
161 169 msgstr "Сохранить"
162 170
163 171 #: templates/boards/tags.html:17
164 172 msgid "threads"
165 173 msgstr "тем"
166 174
167 #: templates/boards/tags.html:20
168 msgid "Remove"
169 msgstr "Удалить"
170
171 #: templates/boards/tags.html:23
172 msgid "Add"
173 msgstr "Добавить"
174
175 175 #: templates/boards/tags.html:28
176 176 msgid "No tags found."
177 177 msgstr "Теги не найдены."
178 178
179 #: templates/boards/thread.html:48
180 msgid "Ban IP"
181 msgstr "Заблокировать IP"
182
183 179 #: templates/boards/thread.html:74
184 180 msgid "Reply to thread"
185 181 msgstr "Ответить в тему"
186 182
187 183 #: templates/boards/thread.html:114
188 184 msgid "Last update: "
189 185 msgstr "Последнее обновление: "
190 186
191 187 #: templates/boards/staticpages/banned.html:6
192 188 msgid "Banned"
193 189 msgstr "Заблокирован"
194 190
195 #: templates/boards/staticpages/banned.html:10
191 #: templates/boards/staticpages/banned.html:11
196 192 msgid "Your IP address has been banned. Contact the administrator"
197 193 msgstr "Ваш IP адрес был заблокирован. Свяжитесь с администратором"
198 194
199 195 #: templates/boards/staticpages/help.html:6
200 196 #: templates/boards/staticpages/help.html:10
201 197 msgid "Syntax"
202 198 msgstr "Синтаксис"
203 199
204 200 #: templates/boards/staticpages/help.html:11
205 201 msgid "2 line breaks for a new line."
206 202 msgstr "2 перевода строки создают новый абзац."
207 203
208 204 #: templates/boards/staticpages/help.html:12
209 205 msgid "Italic text"
210 206 msgstr "Курсивный текст"
211 207
212 208 #: templates/boards/staticpages/help.html:13
213 209 msgid "Bold text"
214 210 msgstr "Полужирный текст"
215 211
216 212 #: templates/boards/staticpages/help.html:14
217 213 msgid "Spoiler"
218 214 msgstr "Спойлер"
219 215
220 216 #: templates/boards/staticpages/help.html:15
221 217 msgid "Comment"
222 218 msgstr "Комментарий"
223 219
224 220 #: templates/boards/staticpages/help.html:16
225 221 msgid "Quote"
226 222 msgstr "Цитата"
227 223
228 224 #: templates/boards/staticpages/help.html:17
229 225 msgid "Link to a post"
230 226 msgstr "Ссылка на сообщение"
231 227
228 #~ msgid "Remove"
229 #~ msgstr "Удалить"
230
231 #~ msgid "Add"
232 #~ msgstr "Добавить"
233
232 234 #~ msgid "Basic markdown syntax."
233 235 #~ msgstr "Базовый синтаксис markdown."
234 236
235 237 #~ msgid "Example: "
236 238 #~ msgstr "Пример: "
237 239
238 240 #~ msgid "italic"
239 241 #~ msgstr "курсив"
240 242
241 243 #~ msgid "bold"
242 244 #~ msgstr "полужирный"
243 245
244 246 #~ msgid "tags"
245 247 #~ msgstr "тегов"
246 248
247 249 #~ msgid "Get!"
248 250 #~ msgstr "Гет!"
249 251
250 252 #~ msgid "View"
251 253 #~ msgstr "Просмотр"
252 254
253 255 #~ msgid "gets"
254 256 #~ msgstr "гетов"
255 257
256 258 #~ msgid "author"
257 259 #~ msgstr "автор"
258 260
259 261 #~ msgid "developer"
260 262 #~ msgstr "разработчик"
261 263
262 264 #~ msgid "javascript developer"
263 265 #~ msgstr "разработчик javascript"
264 266
265 267 #~ msgid "designer"
266 268 #~ msgstr "дизайнер"
@@ -1,325 +1,329 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.db.models import Count
9 9 from django.http import Http404
10 10 from django.utils import timezone
11 11 from markupfield.fields import MarkupField
12 12
13 13 from neboard import settings
14 14 import thumbs
15 15
16 16 IMAGE_THUMB_SIZE = (200, 150)
17 17
18 18 TITLE_MAX_LENGTH = 50
19 19
20 20 DEFAULT_MARKUP_TYPE = 'markdown'
21 21
22 22 NO_PARENT = -1
23 23 NO_IP = '0.0.0.0'
24 24 UNKNOWN_UA = ''
25 25 ALL_PAGES = -1
26 26 OPENING_POST_POPULARITY_WEIGHT = 2
27 27 IMAGES_DIRECTORY = 'images/'
28 28 FILE_EXTENSION_DELIMITER = '.'
29 29
30 30 RANK_ADMIN = 0
31 31 RANK_MODERATOR = 10
32 32 RANK_USER = 100
33 33
34 34
35 35 class PostManager(models.Manager):
36
36 37 def create_post(self, title, text, image=None, thread=None,
37 38 ip=NO_IP, tags=None, user=None):
38 39 post = self.create(title=title,
39 40 text=text,
40 41 pub_time=timezone.now(),
41 42 thread=thread,
42 43 image=image,
43 44 poster_ip=ip,
44 45 poster_user_agent=UNKNOWN_UA,
45 46 last_edit_time=timezone.now(),
46 47 user=user)
47 48
48 49 if tags:
49 50 map(post.tags.add, tags)
50 51 for tag in tags:
51 52 tag.threads.add(post)
52 53
53 54 if thread:
54 55 thread.replies.add(post)
55 56 thread.bump()
56 57 else:
57 58 self._delete_old_threads()
58 59
59 60 return post
60 61
61 62 def delete_post(self, post):
62 63 if post.replies.count() > 0:
63 64 map(self.delete_post, post.replies.all())
64 65 post.delete()
65 66
66 67 def delete_posts_by_ip(self, ip):
67 68 posts = self.filter(poster_ip=ip)
68 69 map(self.delete_post, posts)
69 70
70 71 def get_threads(self, tag=None, page=ALL_PAGES,
71 72 order_by='-last_edit_time'):
72 73 if tag:
73 74 threads = tag.threads
74 75
75 76 # TODO This needs to be uncommented when 'all tags' view won't
76 77 # use this method to get threads for tag
77 78
78 79 # if threads.count() == 0:
79 80 # raise Http404
80 81 else:
81 82 threads = self.filter(thread=None)
82 83
83 84 threads = threads.order_by(order_by)
84 85
85 86 if page != ALL_PAGES:
86 87 thread_count = threads.count()
87 88
88 89 if page < self.get_thread_page_count(tag=tag):
89 90 start_thread = page * settings.THREADS_PER_PAGE
90 91 end_thread = min(start_thread + settings.THREADS_PER_PAGE,
91 92 thread_count)
92 93 threads = threads[start_thread:end_thread]
93 94
94 95 return threads
95 96
96 97 def get_thread(self, opening_post_id):
97 98 try:
98 99 opening_post = self.get(id=opening_post_id, thread=None)
99 100 except Post.DoesNotExist:
100 101 raise Http404
101 102
102 103 if opening_post.replies:
103 104 thread = [opening_post]
104 105 thread.extend(opening_post.replies.all())
105 106
106 107 return thread
107 108
108 109 def exists(self, post_id):
109 110 posts = self.filter(id=post_id)
110 111
111 112 return posts.count() > 0
112 113
113 114 def get_thread_page_count(self, tag=None):
114 115 if tag:
115 116 threads = self.filter(thread=None, tags=tag)
116 117 else:
117 118 threads = self.filter(thread=None)
118 119
119 120 return int(math.ceil(threads.count() / float(
120 121 settings.THREADS_PER_PAGE)))
121 122
122 123 def _delete_old_threads(self):
123 124 """
124 125 Preserves maximum thread count. If there are too many threads,
125 126 delete the old ones.
126 127 """
127 128
128 129 # TODO Move old threads to the archive instead of deleting them.
129 130 # Maybe make some 'old' field in the model to indicate the thread
130 131 # must not be shown and be able for replying.
131 132
132 133 threads = self.get_threads()
133 134 thread_count = len(threads)
134 135
135 136 if thread_count > settings.MAX_THREAD_COUNT:
136 137 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
137 138 old_threads = threads[thread_count - num_threads_to_delete:]
138 139
139 140 map(self.delete_post, old_threads)
140 141
141 142
142 143 class TagManager(models.Manager):
143 144
144 145 def get_not_empty_tags(self):
145 146 tags = self.annotate(Count('threads')) \
146 147 .filter(threads__count__gt=0).order_by('name')
147 148
148 149 return tags
149 150
150 151
151 152 class Tag(models.Model):
152 153 """
153 154 A tag is a text node assigned to the post. The tag serves as a board
154 155 section. There can be multiple tags for each message
155 156 """
156 157
157 158 objects = TagManager()
158 159
159 160 name = models.CharField(max_length=100)
160 161 threads = models.ManyToManyField('Post', null=True,
161 162 blank=True, related_name='tag+')
162 163
163 164 def __unicode__(self):
164 165 return self.name
165 166
166 167 def is_empty(self):
167 168 return self.get_post_count() == 0
168 169
169 170 def get_post_count(self):
170 171 return self.threads.count()
171 172
172 173 def get_popularity(self):
173 174 posts_with_tag = Post.objects.get_threads(tag=self)
174 175 reply_count = 0
175 176 for post in posts_with_tag:
176 177 reply_count += post.get_reply_count()
177 178 reply_count += OPENING_POST_POPULARITY_WEIGHT
178 179
179 180 return reply_count
180 181
181 182
182 183 class Post(models.Model):
183 184 """A post is a message."""
184 185
185 186 objects = PostManager()
186 187
187 188 def _update_image_filename(self, filename):
188 189 """Get unique image filename"""
189 190
190 191 path = IMAGES_DIRECTORY
191 192 new_name = str(int(time.mktime(time.gmtime())))
192 193 new_name += str(int(random() * 1000))
193 194 new_name += FILE_EXTENSION_DELIMITER
194 195 new_name += filename.split(FILE_EXTENSION_DELIMITER)[-1:][0]
195 196
196 197 return os.path.join(path, new_name)
197 198
198 199 title = models.CharField(max_length=TITLE_MAX_LENGTH)
199 200 pub_time = models.DateTimeField()
200 201 text = MarkupField(default_markup_type=DEFAULT_MARKUP_TYPE,
201 202 escape_html=False)
202 203
203 204 image_width = models.IntegerField(default=0)
204 205 image_height = models.IntegerField(default=0)
205 206
206 207 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
207 208 blank=True, sizes=(IMAGE_THUMB_SIZE,),
208 209 width_field='image_width',
209 210 height_field='image_height')
210 211
211 212 poster_ip = models.GenericIPAddressField()
212 213 poster_user_agent = models.TextField()
213 214
214 215 # TODO Remove this field after everything has been updated to 'thread'
215 216 parent = models.BigIntegerField(default=NO_PARENT)
216 217
217 218 thread = models.ForeignKey('Post', null=True, default=None)
218 219 tags = models.ManyToManyField(Tag)
219 220 last_edit_time = models.DateTimeField()
220 221 user = models.ForeignKey('User', null=True, default=None)
221 222
222 223 replies = models.ManyToManyField('Post', symmetrical=False, null=True,
223 224 blank=True, related_name='re+')
224 225
225 226 def __unicode__(self):
226 227 return '#' + str(self.id) + ' ' + self.title + ' (' + \
227 228 self.text.raw[:50] + ')'
228 229
229 230 def get_title(self):
230 231 title = self.title
231 232 if len(title) == 0:
232 233 title = self.text.raw[:20]
233 234
234 235 return title
235 236
236 237 def get_reply_count(self):
237 238 return self.replies.count()
238 239
239 240 def get_images_count(self):
240 241 images_count = 1 if self.image else 0
241 242 images_count += self.replies.filter(image_width__gt=0).count()
242 243
243 244 return images_count
244 245
245 246 def can_bump(self):
246 247 """Check if the thread can be bumped by replying"""
247 248
248 249 post_count = self.get_reply_count() + 1
249 250
250 251 return post_count <= settings.MAX_POSTS_PER_THREAD
251 252
252 253 def bump(self):
253 254 """Bump (move to up) thread"""
254 255
255 256 if self.can_bump():
256 257 self.last_edit_time = timezone.now()
257 258 self.save()
258 259
259 260 def get_last_replies(self):
260 261 if settings.LAST_REPLIES_COUNT > 0:
261 262 reply_count = self.get_reply_count()
262 263
263 264 if reply_count > 0:
264 265 reply_count_to_show = min(settings.LAST_REPLIES_COUNT,
265 266 reply_count)
266 267 last_replies = self.replies.all()[reply_count -
267 268 reply_count_to_show:]
268 269
269 270 return last_replies
270 271
271 272
272 273 class User(models.Model):
273 274
274 275 user_id = models.CharField(max_length=50)
275 276 rank = models.IntegerField()
276 277
277 278 registration_time = models.DateTimeField()
278 279 last_access_time = models.DateTimeField()
279 280
280 281 fav_tags = models.ManyToManyField(Tag, null=True, blank=True)
281 282 fav_threads = models.ManyToManyField(Post, related_name='+', null=True,
282 283 blank=True)
283 284
284 285 def save_setting(self, name, value):
285 286 setting, created = Setting.objects.get_or_create(name=name, user=self)
286 287 setting.value = value
287 288 setting.save()
288 289
289 290 return setting
290 291
291 292 def get_setting(self, name):
292 293 if Setting.objects.filter(name=name, user=self).exists():
293 294 setting = Setting.objects.get(name=name, user=self)
294 295 setting_value = setting.value
295 296 else:
296 297 setting_value = None
297 298
298 299 return setting_value
299 300
300 301 def is_moderator(self):
301 302 return RANK_MODERATOR >= self.rank
302 303
303 304 def get_sorted_fav_tags(self):
304 305 tags = self.fav_tags.annotate(Count('threads'))\
305 306 .filter(threads__count__gt=0).order_by('name')
306 307
307 308 return tags
308 309
310 def get_post_count(self):
311 return Post.objects.filter(user=self).count()
312
309 313 def __unicode__(self):
310 314 return self.user_id + '(' + str(self.rank) + ')'
311 315
312 316
313 317 class Setting(models.Model):
314 318
315 319 name = models.CharField(max_length=50)
316 320 value = models.CharField(max_length=50)
317 321 user = models.ForeignKey(User)
318 322
319 323
320 324 class Ban(models.Model):
321 325
322 326 ip = models.GenericIPAddressField()
323 327
324 328 def __unicode__(self):
325 329 return self.ip
@@ -1,41 +1,44 b''
1 1 {% extends "boards/base.html" %}
2 2
3 3 {% load i18n %}
4 4
5 5 {% block head %}
6 6 <title>Neboard settings</title>
7 7 {% endblock %}
8 8
9 9 {% block content %}
10 10
11 11 <div class="post">
12 <p>
12 13 {% trans 'User:' %} <b>{{ user.user_id }}</b>.
13 14 {% if user.is_moderator %}
14 15 {% trans 'You are moderator.' %}
15 16 {% endif %}
17 </p>
18 <p>{% trans 'Posts:' %} {{ user.get_post_count }}</p>
16 19 </div>
17 20
18 21 <div class="post-form-w">
19 22 <div class="post-form">
20 23 <span class="form-title">{% trans "Theme" %}</span>
21 24 <form method="post">{% csrf_token %}
22 25 {% for choice in form.fields.theme.choices %}
23 26 <div class="settings_item">
24 27 <label for="{{ choice.0 }}">
25 28 <input type="radio" name="theme"
26 29 id="{{ choice.0 }}"
27 30 value="{{ choice.0 }}"
28 31 {% ifequal form.initial.theme choice.0 %}
29 32 checked
30 33 {% endifequal %}
31 34 />
32 35 {{ choice.1 }}
33 36 </label>
34 37 </div>
35 38 {% endfor %}
36 39 <input type="submit" value="{% trans "Save" %}" />
37 40 </form>
38 41 </div>
39 42 </div>
40 43
41 44 {% endblock %} No newline at end of file
@@ -1,356 +1,356 b''
1 1 import hashlib
2 2 from django.core.urlresolvers import reverse
3 3 from django.http import HttpResponseRedirect
4 4 from django.template import RequestContext
5 5 from django.shortcuts import render, redirect, get_object_or_404
6 6 from django.utils import timezone
7 7
8 8 from boards import forms
9 9 import boards
10 10 from boards import utils
11 11 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
12 12 ThreadCaptchaForm, PostCaptchaForm, LoginForm
13 13
14 14 from boards.models import Post, Tag, Ban, User, RANK_USER, NO_PARENT
15 15 from boards import authors
16 16 import neboard
17 17
18 18
19 19 def index(request, page=0):
20 20 context = _init_default_context(request)
21 21
22 22 if utils.need_include_captcha(request):
23 23 threadFormClass = ThreadCaptchaForm
24 24 kwargs = {'request': request}
25 25 else:
26 26 threadFormClass = ThreadForm
27 27 kwargs = {}
28 28
29 29 if request.method == 'POST':
30 30 form = threadFormClass(request.POST, request.FILES,
31 31 error_class=PlainErrorList, **kwargs)
32 32 form.session = request.session
33 33
34 34 if form.is_valid():
35 35 return _new_post(request, form)
36 36 else:
37 37 form = threadFormClass(error_class=PlainErrorList, **kwargs)
38 38
39 39 threads = []
40 40 for thread in Post.objects.get_threads(page=int(page)):
41 41 threads.append({'thread': thread,
42 42 'bumpable': thread.can_bump()})
43 43
44 44 context['threads'] = None if len(threads) == 0 else threads
45 45 context['form'] = form
46 46 context['pages'] = range(Post.objects.get_thread_page_count())
47 47
48 48 return render(request, 'boards/posting_general.html',
49 49 context)
50 50
51 51
52 52 def _new_post(request, form, thread_id=boards.models.NO_PARENT):
53 53 """Add a new post (in thread or as a reply)."""
54 54
55 55 ip = _get_client_ip(request)
56 56 is_banned = Ban.objects.filter(ip=ip).count() > 0
57 57
58 58 if is_banned:
59 59 return redirect(you_are_banned)
60 60
61 61 data = form.cleaned_data
62 62
63 63 title = data['title']
64 64 text = data['text']
65 65
66 66 if 'image' in data.keys():
67 67 image = data['image']
68 68 else:
69 69 image = None
70 70
71 71 tags = []
72 72
73 73 new_thread = thread_id == boards.models.NO_PARENT
74 74 if new_thread:
75 75 tag_strings = data['tags']
76 76
77 77 if tag_strings:
78 78 tag_strings = tag_strings.split(' ')
79 79 for tag_name in tag_strings:
80 80 tag_name = tag_name.strip()
81 81 if len(tag_name) > 0:
82 82 tag, created = Tag.objects.get_or_create(name=tag_name)
83 83 tags.append(tag)
84 84
85 85 op = None if thread_id == boards.models.NO_PARENT else \
86 86 get_object_or_404(Post, id=thread_id)
87 87 post = Post.objects.create_post(title=title, text=text, ip=ip,
88 88 thread=op, image=image,
89 tags=tags)
89 tags=tags, user=_get_user(request))
90 90
91 91 thread_to_show = (post.id if new_thread else thread_id)
92 92
93 93 if new_thread:
94 94 return redirect(thread, post_id=thread_to_show)
95 95 else:
96 96 return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) +
97 97 '#' + str(post.id))
98 98
99 99
100 100 def tag(request, tag_name, page=0):
101 101 """Get all tag threads (posts without a parent)."""
102 102
103 103 tag = get_object_or_404(Tag, name=tag_name)
104 104 threads = []
105 105 for thread in Post.objects.get_threads(tag=tag, page=int(page)):
106 106 threads.append({'thread': thread,
107 107 'bumpable': thread.can_bump()})
108 108
109 109 if request.method == 'POST':
110 110 form = ThreadForm(request.POST, request.FILES,
111 111 error_class=PlainErrorList)
112 112 if form.is_valid():
113 113 return _new_post(request, form)
114 114 else:
115 115 form = forms.ThreadForm(initial={'tags': tag_name},
116 116 error_class=PlainErrorList)
117 117
118 118 context = _init_default_context(request)
119 119 context['threads'] = None if len(threads) == 0 else threads
120 120 context['tag'] = tag
121 121 context['pages'] = range(Post.objects.get_thread_page_count(tag=tag))
122 122
123 123 context['form'] = form
124 124
125 125 return render(request, 'boards/posting_general.html',
126 126 context)
127 127
128 128
129 129 def thread(request, post_id):
130 130 """Get all thread posts"""
131 131
132 132 if utils.need_include_captcha(request):
133 133 postFormClass = PostCaptchaForm
134 134 kwargs = {'request': request}
135 135 else:
136 136 postFormClass = PostForm
137 137 kwargs = {}
138 138
139 139 if request.method == 'POST':
140 140 form = postFormClass(request.POST, request.FILES,
141 141 error_class=PlainErrorList, **kwargs)
142 142 form.session = request.session
143 143
144 144 if form.is_valid():
145 145 return _new_post(request, form, post_id)
146 146 else:
147 147 form = postFormClass(error_class=PlainErrorList, **kwargs)
148 148
149 149 posts = Post.objects.get_thread(post_id)
150 150
151 151 context = _init_default_context(request)
152 152
153 153 context['posts'] = posts
154 154 context['form'] = form
155 155 context['bumpable'] = posts[0].can_bump()
156 156
157 157 return render(request, 'boards/thread.html', context)
158 158
159 159
160 160 def login(request):
161 161 """Log in with user id"""
162 162
163 163 context = _init_default_context(request)
164 164
165 165 if request.method == 'POST':
166 166 form = LoginForm(request.POST, request.FILES,
167 167 error_class=PlainErrorList)
168 168 if form.is_valid():
169 169 user = User.objects.get(user_id=form.cleaned_data['user_id'])
170 170 request.session['user_id'] = user.id
171 171 return redirect(index)
172 172
173 173 else:
174 174 form = LoginForm()
175 175
176 176 context['form'] = form
177 177
178 178 return render(request, 'boards/login.html', context)
179 179
180 180
181 181 def settings(request):
182 182 """User's settings"""
183 183
184 184 context = _init_default_context(request)
185 185
186 186 if request.method == 'POST':
187 187 form = SettingsForm(request.POST)
188 188 if form.is_valid():
189 189 selected_theme = form.cleaned_data['theme']
190 190
191 191 user = _get_user(request)
192 192 user.save_setting('theme', selected_theme)
193 193
194 194 return redirect(settings)
195 195 else:
196 196 selected_theme = _get_theme(request)
197 197 form = SettingsForm(initial={'theme': selected_theme})
198 198 context['form'] = form
199 199
200 200 return render(request, 'boards/settings.html', context)
201 201
202 202
203 203 def all_tags(request):
204 204 """All tags list"""
205 205
206 206 context = _init_default_context(request)
207 207 context['all_tags'] = Tag.objects.get_not_empty_tags()
208 208
209 209 return render(request, 'boards/tags.html', context)
210 210
211 211
212 212 def jump_to_post(request, post_id):
213 213 """Determine thread in which the requested post is and open it's page"""
214 214
215 215 post = get_object_or_404(Post, id=post_id)
216 216
217 217 if not post.thread:
218 218 return redirect(thread, post_id=post.id)
219 219 else:
220 220 return redirect(reverse(thread, kwargs={'post_id': post.thread.id})
221 221 + '#' + str(post.id))
222 222
223 223
224 224 def authors(request):
225 225 context = _init_default_context(request)
226 226 context['authors'] = boards.authors.authors
227 227
228 228 return render(request, 'boards/authors.html', context)
229 229
230 230
231 231 def delete(request, post_id):
232 232 user = _get_user(request)
233 233 post = get_object_or_404(Post, id=post_id)
234 234
235 235 if user.is_moderator():
236 236 # TODO Show confirmation page before deletion
237 237 Post.objects.delete_post(post)
238 238
239 239 if not post.thread:
240 240 return _redirect_to_next(request)
241 241 else:
242 242 return redirect(thread, post_id=post.thread.id)
243 243
244 244
245 245 def ban(request, post_id):
246 246 user = _get_user(request)
247 247 post = get_object_or_404(Post, id=post_id)
248 248
249 249 if user.is_moderator():
250 250 # TODO Show confirmation page before ban
251 251 Ban.objects.get_or_create(ip=post.poster_ip)
252 252
253 253 return _redirect_to_next(request)
254 254
255 255
256 256 def you_are_banned(request):
257 257 context = _init_default_context(request)
258 258 return render(request, 'boards/staticpages/banned.html', context)
259 259
260 260
261 261 def page_404(request):
262 262 context = _init_default_context(request)
263 263 return render(request, 'boards/404.html', context)
264 264
265 265
266 266 def tag_subscribe(request, tag_name):
267 267 user = _get_user(request)
268 268 tag = get_object_or_404(Tag, name=tag_name)
269 269
270 270 if not tag in user.fav_tags.all():
271 271 user.fav_tags.add(tag)
272 272
273 273 return _redirect_to_next(request)
274 274
275 275
276 276 def tag_unsubscribe(request, tag_name):
277 277 user = _get_user(request)
278 278 tag = get_object_or_404(Tag, name=tag_name)
279 279
280 280 if tag in user.fav_tags.all():
281 281 user.fav_tags.remove(tag)
282 282
283 283 return _redirect_to_next(request)
284 284
285 285
286 286 def static_page(request, name):
287 287 context = _init_default_context(request)
288 288 return render(request, 'boards/staticpages/' + name + '.html', context)
289 289
290 290
291 291 def _get_theme(request, user=None):
292 292 """Get user's CSS theme"""
293 293
294 294 if not user:
295 295 user = _get_user(request)
296 296 theme = user.get_setting('theme')
297 297 if not theme:
298 298 theme = neboard.settings.DEFAULT_THEME
299 299
300 300 return theme
301 301
302 302
303 303 def _get_client_ip(request):
304 304 x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
305 305 if x_forwarded_for:
306 306 ip = x_forwarded_for.split(',')[-1].strip()
307 307 else:
308 308 ip = request.META.get('REMOTE_ADDR')
309 309 return ip
310 310
311 311
312 312 def _init_default_context(request):
313 313 """Create context with default values that are used in most views"""
314 314
315 315 context = RequestContext(request)
316 316
317 317 user = _get_user(request)
318 318 context['user'] = user
319 319 context['tags'] = user.get_sorted_fav_tags()
320 320 context['theme'] = _get_theme(request, user)
321 321 context['moderator'] = user.is_moderator()
322 322
323 323 return context
324 324
325 325
326 326 def _get_user(request):
327 327 """Get current user from the session"""
328 328
329 329 session = request.session
330 330 if not 'user_id' in session:
331 331 request.session.save()
332 332
333 333 md5 = hashlib.md5()
334 334 md5.update(session.session_key)
335 335 new_id = md5.hexdigest()
336 336
337 337 time_now = timezone.now()
338 338 user = User.objects.create(user_id=new_id, rank=RANK_USER,
339 339 registration_time=time_now,
340 340 last_access_time=time_now)
341 341
342 342 session['user_id'] = user.id
343 343 else:
344 344 user = User.objects.get(id=session['user_id'])
345 345 user.last_access_time = timezone.now()
346 346 user.save()
347 347
348 348 return user
349 349
350 350
351 351 def _redirect_to_next(request):
352 352 if 'next' in request.GET:
353 353 next_page = request.GET['next']
354 354 return HttpResponseRedirect(next_page)
355 355 else:
356 356 return redirect(index)
General Comments 0
You need to be logged in to leave comments. Login now