##// END OF EJS Templates
Partly merged with default branch
neko259 -
r1157:d41f2b1c merge decentral
parent child Browse files
Show More
@@ -0,0 +1,33 b''
1 [Version]
2 Version = 2.7.0 Chani
3 SiteName = Neboard
4
5 [Cache]
6 # Timeout for caching, if cache is used
7 CacheTimeout = 600
8
9 [Forms]
10 # Max post length in characters
11 MaxTextLength = 30000
12 MaxImageSize = 8000000
13 LimitPostingSpeed = false
14
15 [Messages]
16 # Thread bumplimit
17 MaxPostsPerThread = 10
18 # Old posts will be archived or deleted if this value is reached
19 MaxThreadCount = 5
20
21 [View]
22 DefaultTheme = md
23 DefaultImageViewer = simple
24 LastRepliesCount = 3
25 ThreadsPerPage = 3
26
27 [Storage]
28 # Enable archiving threads instead of deletion when the thread limit is reached
29 ArchiveThreads = true
30
31 [External]
32 # Thread update
33 WebsocketsEnabled = false
@@ -0,0 +1,23 b''
1 # -*- coding: utf-8 -*-
2 from __future__ import unicode_literals
3
4 from django.db import models, migrations
5
6
7 class Migration(migrations.Migration):
8
9 dependencies = [
10 ('boards', '0017_auto_20150503_1847'),
11 ]
12
13 operations = [
14 migrations.CreateModel(
15 name='Banner',
16 fields=[
17 ('id', models.AutoField(serialize=False, primary_key=True, verbose_name='ID', auto_created=True)),
18 ('title', models.TextField()),
19 ('text', models.TextField()),
20 ('post', models.ForeignKey(to='boards.Post')),
21 ],
22 ),
23 ]
@@ -0,0 +1,10 b''
1 from django.db import models
2
3
4 class Banner(models.Model):
5 title = models.TextField()
6 text = models.TextField()
7 post = models.ForeignKey('Post')
8
9 def __str__(self):
10 return self.title
@@ -0,0 +1,55 b''
1 from boards import utils
2
3
4 PARAMETER_TRUNCATED = 'truncated'
5
6 DIFF_TYPE_HTML = 'html'
7 DIFF_TYPE_JSON = 'json'
8
9
10 class Exporter():
11 @staticmethod
12 def export(post, request, include_last_update) -> str:
13 pass
14
15
16 class HtmlExporter(Exporter):
17 @staticmethod
18 def export(post, request, include_last_update):
19 if request is not None and PARAMETER_TRUNCATED in request.GET:
20 truncated = True
21 reply_link = False
22 else:
23 truncated = False
24 reply_link = True
25
26 return post.get_view(truncated=truncated, reply_link=reply_link,
27 moderator=utils.is_moderator(request))
28
29
30 class JsonExporter(Exporter):
31 @staticmethod
32 def export(post, request, include_last_update):
33 post_json = {
34 'id': post.id,
35 'title': post.title,
36 'text': post.get_raw_text(),
37 }
38 if post.images.exists():
39 post_image = post.get_first_image()
40 post_json['image'] = post_image.image.url
41 post_json['image_preview'] = post_image.image.url_200x150
42 if include_last_update:
43 post_json['bump_time'] = utils.datetime_to_epoch(
44 post.get_thread().bump_time)
45 return post_json
46
47
48 EXPORTERS = {
49 DIFF_TYPE_HTML: HtmlExporter,
50 DIFF_TYPE_JSON: JsonExporter,
51 }
52
53
54 def get_exporter(export_type: str) -> Exporter:
55 return EXPORTERS[export_type]()
@@ -28,3 +28,4 b' 119fafc5381b933bf30d97be0b278349f6135075'
28 28 d528d76d3242cced614fa11bb63f3d342e4e1d09 2.5.2
29 29 1b631781ced34fbdeec032e7674bc4e131724699 2.6.0
30 30 0f2ef17dc0de678ada279bf7eedf6c5585f1fd7a 2.6.1
31 d53fc814a424d7fd90f23025c87b87baa164450e 2.7.0
@@ -1,5 +1,5 b''
1 1 from django.contrib import admin
2 from boards.models import Post, Tag, Ban, Thread, KeyPair
2 from boards.models import Post, Tag, Ban, Thread, KeyPair, Banner
3 3 from django.utils.translation import ugettext_lazy as _
4 4
5 5
@@ -64,3 +64,8 b' class BanAdmin(admin.ModelAdmin):'
64 64 list_display = ('ip', 'can_read')
65 65 list_filter = ('can_read',)
66 66 search_fields = ('ip',)
67
68
69 @admin.register(Banner)
70 class BannerAdmin(admin.ModelAdmin):
71 list_display = ('title', 'text')
@@ -51,11 +51,12 b' def user_and_ui_processor(request):'
51 51 # This shows the moderator panel
52 52 context[CONTEXT_MODERATOR] = utils.is_moderator(request)
53 53
54 context[CONTEXT_VERSION] = settings.VERSION
55 context[CONTEXT_SITE_NAME] = settings.SITE_NAME
54 context[CONTEXT_VERSION] = settings.get('Version', 'Version')
55 context[CONTEXT_SITE_NAME] = settings.get('Version', 'SiteName')
56 56
57 57 context[CONTEXT_IMAGE_VIEWER] = settings_manager.get_setting(
58 SETTING_IMAGE_VIEWER, default=settings.DEFAULT_IMAGE_VIEWER)
58 SETTING_IMAGE_VIEWER,
59 default=settings.get('View', 'DefaultImageViewer'))
59 60
60 61 get_notifications(context, request)
61 62
@@ -172,11 +172,10 b' class PostForm(NeboardForm):'
172 172 def clean_text(self):
173 173 text = self.cleaned_data['text'].strip()
174 174 if text:
175 if len(text) > board_settings.MAX_TEXT_LENGTH:
175 max_length = board_settings.get_int('Forms', 'MaxTextLength')
176 if len(text) > max_length:
176 177 raise forms.ValidationError(_('Text must have less than %s '
177 'characters') %
178 str(board_settings
179 .MAX_TEXT_LENGTH))
178 'characters') % str(max_length))
180 179 return text
181 180
182 181 def clean_image(self):
@@ -256,7 +255,7 b' class PostForm(NeboardForm):'
256 255
257 256 posting_delay = settings.POSTING_DELAY
258 257
259 if board_settings.LIMIT_POSTING_SPEED:
258 if board_settings.get_bool('Forms', 'LimitPostingSpeed'):
260 259 now = time.time()
261 260
262 261 current_delay = 0
@@ -283,10 +282,11 b' class PostForm(NeboardForm):'
283 282 self.session[LAST_POST_TIME] = now
284 283
285 284 def validate_image_size(self, size: int):
286 if size > board_settings.MAX_IMAGE_SIZE:
285 max_size = board_settings.get_int('Forms', 'MaxImageSize')
286 if size > max_size:
287 287 raise forms.ValidationError(
288 288 _('Image must be less than %s bytes')
289 % str(board_settings.MAX_IMAGE_SIZE))
289 % str(max_size))
290 290
291 291 def _get_image_from_url(self, url: str) -> SimpleUploadedFile:
292 292 """
1 NO CONTENT: modified file, binary diff hidden
@@ -7,7 +7,7 b' msgid ""'
7 7 msgstr ""
8 8 "Project-Id-Version: PACKAGE VERSION\n"
9 9 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-04-21 21:10+0300\n"
10 "POT-Creation-Date: 2015-05-07 13:10+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"
@@ -68,79 +68,79 b' msgstr "\xd0\x9f\xd0\xbe\xd0\xb8\xd1\x81\xd0\xba"'
68 68 msgid "Please wait %s seconds before sending message"
69 69 msgstr "Пожалуйста подождите %s секунд перед отправкой сообщения"
70 70
71 #: forms.py:142
71 #: forms.py:144
72 72 msgid "Image"
73 73 msgstr "Изображение"
74 74
75 #: forms.py:145
75 #: forms.py:147
76 76 msgid "Image URL"
77 77 msgstr "URL изображения"
78 78
79 #: forms.py:151
79 #: forms.py:153
80 80 msgid "e-mail"
81 81 msgstr ""
82 82
83 #: forms.py:154
83 #: forms.py:156
84 84 msgid "Additional threads"
85 85 msgstr "Дополнительные темы"
86 86
87 #: forms.py:165
87 #: forms.py:167
88 88 #, python-format
89 89 msgid "Title must have less than %s characters"
90 90 msgstr "Заголовок должен иметь меньше %s символов"
91 91
92 #: forms.py:174
92 #: forms.py:176
93 93 #, python-format
94 94 msgid "Text must have less than %s characters"
95 95 msgstr "Текст должен быть короче %s символов"
96 96
97 #: forms.py:196
97 #: forms.py:198
98 98 msgid "Invalid URL"
99 99 msgstr "Неверный URL"
100 100
101 #: forms.py:217
101 #: forms.py:219
102 102 msgid "Invalid additional thread list"
103 103 msgstr "Неверный список дополнительных тем"
104 104
105 #: forms.py:249
105 #: forms.py:251
106 106 msgid "Either text or image must be entered."
107 107 msgstr "Текст или картинка должны быть введены."
108 108
109 #: forms.py:286
109 #: forms.py:288
110 110 #, python-format
111 111 msgid "Image must be less than %s bytes"
112 112 msgstr "Изображение должно быть менее %s байт"
113 113
114 #: forms.py:333 templates/boards/posting_general.html:145
114 #: forms.py:335 templates/boards/posting_general.html:129
115 115 #: templates/boards/rss/post.html:10 templates/boards/tags.html:7
116 116 msgid "Tags"
117 117 msgstr "Метки"
118 118
119 #: forms.py:340
119 #: forms.py:342
120 120 msgid "Inappropriate characters in tags."
121 121 msgstr "Недопустимые символы в метках."
122 122
123 #: forms.py:354
123 #: forms.py:356
124 124 msgid "Need at least one of the tags: "
125 125 msgstr "Нужна хотя бы одна из меток: "
126 126
127 #: forms.py:367
127 #: forms.py:369
128 128 msgid "Theme"
129 129 msgstr "Тема"
130 130
131 #: forms.py:368
131 #: forms.py:370
132 132 msgid "Image view mode"
133 133 msgstr "Режим просмотра изображений"
134 134
135 #: forms.py:369
135 #: forms.py:371
136 136 msgid "User name"
137 137 msgstr "Имя пользователя"
138 138
139 #: forms.py:370
139 #: forms.py:372
140 140 msgid "Time zone"
141 141 msgstr "Часовой пояс"
142 142
143 #: forms.py:376
143 #: forms.py:378
144 144 msgid "Inappropriate characters."
145 145 msgstr "Недопустимые символы."
146 146
@@ -189,7 +189,7 b' msgstr "\xd0\xa3\xd0\xbf\xd1\x80\xd0\xb0\xd0\xb2\xd0\xbb\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb5 \xd0\xbc\xd0\xb5\xd1\x82\xd0\xba\xd0\xb0\xd0\xbc\xd0\xb8"'
189 189 msgid "Notifications"
190 190 msgstr "Уведомления"
191 191
192 #: templates/boards/base.html:52 templates/boards/settings.html:9
192 #: templates/boards/base.html:52 templates/boards/settings.html:8
193 193 msgid "Settings"
194 194 msgstr "Настройки"
195 195
@@ -207,12 +207,12 b' msgid "Up"'
207 207 msgstr "Вверх"
208 208
209 209 #: templates/boards/notifications.html:17
210 #: templates/boards/posting_general.html:80 templates/search/search.html:26
210 #: templates/boards/posting_general.html:70 templates/search/search.html:26
211 211 msgid "Previous page"
212 212 msgstr "Предыдущая страница"
213 213
214 214 #: templates/boards/notifications.html:27
215 #: templates/boards/posting_general.html:118 templates/search/search.html:37
215 #: templates/boards/posting_general.html:102 templates/search/search.html:37
216 216 msgid "Next page"
217 217 msgstr "Следующая страница"
218 218
@@ -244,44 +244,49 b' msgstr "\xd1\x81\xd0\xbe\xd0\xbe\xd0\xb1\xd1\x89\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb9"'
244 244 msgid "images"
245 245 msgstr "изображений"
246 246
247 #: templates/boards/posting_general.html:64
247 #: templates/boards/posting_general.html:35
248 #| msgid "messages"
249 msgid "Related message"
250 msgstr "Связанное сообщение"
251
252 #: templates/boards/posting_general.html:60
248 253 msgid "Edit tag"
249 254 msgstr "Изменить метку"
250 255
251 #: templates/boards/posting_general.html:67
256 #: templates/boards/posting_general.html:63
252 257 #, python-format
253 258 msgid "This tag has %(thread_count)s threads and %(post_count)s posts."
254 259 msgstr "С этой меткой есть %(thread_count)s тем и %(post_count)s сообщений."
255 260
256 #: templates/boards/posting_general.html:94
261 #: templates/boards/posting_general.html:84
257 262 #, python-format
258 263 msgid "Skipped %(count)s replies. Open thread to see all replies."
259 264 msgstr "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы."
260 265
261 #: templates/boards/posting_general.html:123
266 #: templates/boards/posting_general.html:107
262 267 msgid "No threads exist. Create the first one!"
263 268 msgstr "Нет тем. Создайте первую!"
264 269
265 #: templates/boards/posting_general.html:129
270 #: templates/boards/posting_general.html:113
266 271 msgid "Create new thread"
267 272 msgstr "Создать новую тему"
268 273
269 #: templates/boards/posting_general.html:134 templates/boards/preview.html:16
274 #: templates/boards/posting_general.html:118 templates/boards/preview.html:16
270 275 #: templates/boards/thread_normal.html:43
271 276 msgid "Post"
272 277 msgstr "Отправить"
273 278
274 #: templates/boards/posting_general.html:139
279 #: templates/boards/posting_general.html:123
275 280 msgid "Tags must be delimited by spaces. Text or image is required."
276 281 msgstr ""
277 282 "Метки должны быть разделены пробелами. Текст или изображение обязательны."
278 283
279 #: templates/boards/posting_general.html:142
284 #: templates/boards/posting_general.html:126
280 285 #: templates/boards/thread_normal.html:48
281 286 msgid "Text syntax"
282 287 msgstr "Синтаксис текста"
283 288
284 #: templates/boards/posting_general.html:159
289 #: templates/boards/posting_general.html:143
285 290 msgid "Pages:"
286 291 msgstr "Страницы: "
287 292
@@ -293,19 +298,19 b' msgstr "\xd0\x9f\xd1\x80\xd0\xb5\xd0\xb4\xd0\xbf\xd1\x80\xd0\xbe\xd1\x81\xd0\xbc\xd0\xbe\xd1\x82\xd1\x80"'
293 298 msgid "Post image"
294 299 msgstr "Изображение сообщения"
295 300
296 #: templates/boards/settings.html:17
301 #: templates/boards/settings.html:16
297 302 msgid "You are moderator."
298 303 msgstr "Вы модератор."
299 304
300 #: templates/boards/settings.html:21
305 #: templates/boards/settings.html:20
301 306 msgid "Hidden tags:"
302 307 msgstr "Скрытые метки:"
303 308
304 #: templates/boards/settings.html:29
309 #: templates/boards/settings.html:28
305 310 msgid "No hidden tags."
306 311 msgstr "Нет скрытых меток."
307 312
308 #: templates/boards/settings.html:38
313 #: templates/boards/settings.html:37
309 314 msgid "Save"
310 315 msgstr "Сохранить"
311 316
@@ -377,7 +382,7 b' msgstr "\xd0\x9d\xd0\xbe\xd1\x80\xd0\xbc\xd0\xb0\xd0\xbb\xd1\x8c\xd0\xbd\xd1\x8b\xd0\xb9 \xd1\x80\xd0\xb5\xd0\xb6\xd0\xb8\xd0\xbc"'
377 382 msgid "Gallery mode"
378 383 msgstr "Режим галереи"
379 384
380 #: templates/boards/thread_gallery.html:50
385 #: templates/boards/thread_gallery.html:41
381 386 msgid "No images."
382 387 msgstr "Нет изображений."
383 388
@@ -401,8 +406,3 b' msgstr "\xd0\x9e\xd0\xb1\xd0\xbd\xd0\xbe\xd0\xb2\xd0\xb8\xd1\x82\xd1\x8c"'
401 406 msgid "Ok"
402 407 msgstr "Ок"
403 408
404 #~ msgid "Wait %s seconds after last posting"
405 #~ msgstr "Подождите %s секунд после последнего постинга"
406
407 #~ msgid "tag1 several_words_tag"
408 #~ msgstr "метка1 метка_из_нескольких_слов"
@@ -7,3 +7,4 b' from boards.models.thread import Thread'
7 7 from boards.models.post import Post
8 8 from boards.models.tag import Tag
9 9 from boards.models.user import Ban
10 from boards.models.banner import Banner
1 NO CONTENT: file renamed from boards/models/post.py to boards/models/post/__init__.py
@@ -56,9 +56,13 b' class Tag(models.Model, Viewable):'
56 56 def get_thread_count(self) -> int:
57 57 return self.get_threads().count()
58 58
59 # TODO Remove this and use get_absolute_url
59 60 def get_url(self):
60 61 return reverse('tag', kwargs={'tag_name': self.name})
61 62
63 def get_absolute_url(self):
64 return self.get_url()
65
62 66 def get_threads(self):
63 67 return self.thread_set.order_by('-bump_time')
64 68
@@ -67,7 +71,7 b' class Tag(models.Model, Viewable):'
67 71
68 72 def get_view(self):
69 73 link = '<a class="tag" href="{}">{}</a>'.format(
70 self.get_url(), self.name)
74 self.get_absolute_url(), self.name)
71 75 if self.is_required():
72 76 link = '<b>{}</b>'.format(link)
73 77 return link
@@ -34,12 +34,13 b' class ThreadManager(models.Manager):'
34 34 threads = Thread.objects.filter(archived=False).order_by('-bump_time')
35 35 thread_count = threads.count()
36 36
37 if thread_count > settings.MAX_THREAD_COUNT:
38 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
37 max_thread_count = settings.get_int('Messages', 'MaxThreadCount')
38 if thread_count > max_thread_count:
39 num_threads_to_delete = thread_count - max_thread_count
39 40 old_threads = threads[thread_count - num_threads_to_delete:]
40 41
41 42 for thread in old_threads:
42 if settings.ARCHIVE_THREADS:
43 if settings.get_bool('Storage', 'ArchiveThreads'):
43 44 self._archive_thread(thread)
44 45 else:
45 46 thread.delete()
@@ -55,7 +56,7 b' class ThreadManager(models.Manager):'
55 56
56 57
57 58 def get_thread_max_posts():
58 return settings.MAX_POSTS_PER_THREAD
59 return settings.get_int('Messages', 'MaxPostsPerThread')
59 60
60 61
61 62 class Thread(models.Model):
@@ -122,11 +123,13 b' class Thread(models.Model):'
122 123 Gets several last replies, not including opening post
123 124 """
124 125
125 if settings.LAST_REPLIES_COUNT > 0:
126 last_replies_count = settings.get_int('View', 'LastRepliesCount')
127
128 if last_replies_count > 0:
126 129 reply_count = self.get_reply_count()
127 130
128 131 if reply_count > 0:
129 reply_count_to_show = min(settings.LAST_REPLIES_COUNT,
132 reply_count_to_show = min(last_replies_count,
130 133 reply_count - 1)
131 134 replies = self.get_replies()
132 135 last_replies = replies[reply_count - reply_count_to_show:]
@@ -138,7 +141,7 b' class Thread(models.Model):'
138 141 Gets number of posts between opening post and last replies.
139 142 """
140 143 reply_count = self.get_reply_count()
141 last_replies_count = min(settings.LAST_REPLIES_COUNT,
144 last_replies_count = min(settings.get_int('View', 'LastRepliesCount'),
142 145 reply_count - 1)
143 146 return reply_count - last_replies_count - 1
144 147
@@ -222,7 +225,7 b' class Thread(models.Model):'
222 225 post.threads.update(last_edit_time=self.last_edit_time)
223 226
224 227 def notify_clients(self):
225 if not settings.WEBSOCKETS_ENABLED:
228 if not settings.get_bool('External', 'WebsocketsEnabled'):
226 229 return
227 230
228 231 client = Client()
@@ -232,3 +235,6 b' class Thread(models.Model):'
232 235 WS_NOTIFICATION_TYPE: WS_NOTIFICATION_TYPE_NEW_POST,
233 236 })
234 237 client.send()
238
239 def get_absolute_url(self):
240 return self.get_opening_post().get_absolute_url()
@@ -10,7 +10,7 b' from boards import settings'
10 10 # TODO Make tests for all of these
11 11 class AllThreadsFeed(Feed):
12 12
13 title = settings.SITE_NAME + ' - All threads'
13 title = settings.get('Version', 'SiteName') + ' - All threads'
14 14 link = '/'
15 15 description_template = 'boards/rss/post.html'
16 16
@@ -1,2 +1,18 b''
1 from boards.default_settings import *
1 import configparser
2
3
4 config = configparser.ConfigParser()
5 config.read('boards/config/default_settings.ini')
6 config.read('boards/config/settings.ini')
7
2 8
9 def get(section, name):
10 return config[section][name]
11
12
13 def get_int(section, name):
14 return int(get(section, name))
15
16
17 def get_bool(section, name):
18 return get(section, name) == 'true'
@@ -28,6 +28,8 b" var CLASS_POST = '.post'"
28 28 var POST_ADDED = 0;
29 29 var POST_UPDATED = 1;
30 30
31 var JS_AUTOUPDATE_PERIOD = 20000;
32
31 33 var wsUser = '';
32 34
33 35 var unreadPosts = 0;
@@ -48,36 +50,39 b' function connectWebsocket() {'
48 50 var wsHost = metapanel.getAttribute('data-ws-host');
49 51 var wsPort = metapanel.getAttribute('data-ws-port');
50 52
51 if (wsHost.length > 0 && wsPort.length > 0)
52 var centrifuge = new Centrifuge({
53 "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket",
54 "project": metapanel.getAttribute('data-ws-project'),
55 "user": wsUser,
56 "timestamp": metapanel.getAttribute('data-ws-token-time'),
57 "token": metapanel.getAttribute('data-ws-token'),
58 "debug": false
59 });
53 if (wsHost.length > 0 && wsPort.length > 0) {
54 var centrifuge = new Centrifuge({
55 "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket",
56 "project": metapanel.getAttribute('data-ws-project'),
57 "user": wsUser,
58 "timestamp": metapanel.getAttribute('data-ws-token-time'),
59 "token": metapanel.getAttribute('data-ws-token'),
60 "debug": false
61 });
60 62
61 centrifuge.on('error', function(error_message) {
62 console.log("Error connecting to websocket server.");
63 console.log(error_message);
64 return false;
65 });
66
67 centrifuge.on('connect', function() {
68 var channelName = 'thread:' + threadId;
69 centrifuge.subscribe(channelName, function(message) {
70 getThreadDiff();
63 centrifuge.on('error', function(error_message) {
64 console.log("Error connecting to websocket server.");
65 console.log(error_message);
66 return false;
71 67 });
72 68
73 // For the case we closed the browser and missed some updates
74 getThreadDiff();
75 $('#autoupdate').hide();
76 });
69 centrifuge.on('connect', function() {
70 var channelName = 'thread:' + threadId;
71 centrifuge.subscribe(channelName, function(message) {
72 getThreadDiff();
73 });
77 74
78 centrifuge.connect();
75 // For the case we closed the browser and missed some updates
76 getThreadDiff();
77 $('#autoupdate').hide();
78 });
79 79
80 return true;
80 centrifuge.connect();
81
82 return true;
83 } else {
84 return false;
85 }
81 86 }
82 87
83 88 /**
@@ -193,8 +198,21 b' function isPageBottom() {'
193 198 return scroll == 1
194 199 }
195 200
201 function enableJsUpdate() {
202 setInterval(getThreadDiff, JS_AUTOUPDATE_PERIOD);
203 return true;
204 }
205
196 206 function initAutoupdate() {
197 return connectWebsocket();
207 if (location.protocol === 'https:') {
208 return enableJsUpdate();
209 } else {
210 if (connectWebsocket()) {
211 return true;
212 } else {
213 return enableJsUpdate();
214 }
215 }
198 216 }
199 217
200 218 function getReplyCount() {
@@ -28,6 +28,14 b''
28 28 {% get_current_language as LANGUAGE_CODE %}
29 29 {% get_current_timezone as TIME_ZONE %}
30 30
31 {% for banner in banners %}
32 <div class="post">
33 <div class="title">{{ banner.title }}</div>
34 <div>{{ banner.text }}</div>
35 <div>{% trans 'Related message' %}: <a href="{{ banner.post.get_url }}">>>{{ banner.post.id }}</a></div>
36 </div>
37 {% endfor %}
38
31 39 {% if tag %}
32 40 <div class="tag_info">
33 41 <h2>
@@ -1,7 +1,6 b''
1 1 {% extends "boards/base.html" %}
2 2
3 3 {% load i18n %}
4 {% load humanize %}
5 4 {% load tz %}
6 5
7 6 {% block head %}
@@ -91,26 +91,26 b' class PostTests(TestCase):'
91 91 def test_thread_max_count(self):
92 92 """Test deletion of old posts when the max thread count is reached"""
93 93
94 for i in range(settings.MAX_THREAD_COUNT + 1):
94 for i in range(settings.get_int('Messages', 'MaxThreadCount') + 1):
95 95 self._create_post()
96 96
97 self.assertEqual(settings.MAX_THREAD_COUNT,
97 self.assertEqual(settings.get_int('Messages', 'MaxThreadCount'),
98 98 len(Thread.objects.filter(archived=False)))
99 99
100 100 def test_pages(self):
101 101 """Test that the thread list is properly split into pages"""
102 102
103 for i in range(settings.MAX_THREAD_COUNT):
103 for i in range(settings.get_int('Messages', 'MaxThreadCount')):
104 104 self._create_post()
105 105
106 106 all_threads = Thread.objects.filter(archived=False)
107 107
108 108 paginator = Paginator(Thread.objects.filter(archived=False),
109 settings.THREADS_PER_PAGE)
109 settings.get_int('View', 'ThreadsPerPage'))
110 110 posts_in_second_page = paginator.page(2).object_list
111 111 first_post = posts_in_second_page[0]
112 112
113 self.assertEqual(all_threads[settings.THREADS_PER_PAGE].id,
113 self.assertEqual(all_threads[settings.get_int('View', 'ThreadsPerPage')].id,
114 114 first_post.id)
115 115
116 116 def test_reflinks(self):
@@ -11,7 +11,7 b' from boards import utils, settings'
11 11 from boards.abstracts.paginator import get_paginator
12 12 from boards.abstracts.settingsmanager import get_settings_manager
13 13 from boards.forms import ThreadForm, PlainErrorList
14 from boards.models import Post, Thread, Ban, Tag, PostImage
14 from boards.models import Post, Thread, Ban, Tag, PostImage, Banner
15 15 from boards.views.banned import BannedView
16 16 from boards.views.base import BaseBoardView, CONTEXT_FORM
17 17 from boards.views.posting_mixin import PostMixin
@@ -28,6 +28,7 b" TAG_DELIMITER = ' '"
28 28 PARAMETER_CURRENT_PAGE = 'current_page'
29 29 PARAMETER_PAGINATOR = 'paginator'
30 30 PARAMETER_THREADS = 'threads'
31 PARAMETER_BANNERS = 'banners'
31 32
32 33 PARAMETER_PREV_LINK = 'prev_page_link'
33 34 PARAMETER_NEXT_LINK = 'next_page_link'
@@ -50,7 +51,7 b' class AllThreadsView(PostMixin, BaseBoar'
50 51
51 52 self.settings_manager = get_settings_manager(request)
52 53 paginator = get_paginator(self.get_threads(),
53 settings.THREADS_PER_PAGE)
54 settings.get_int('View', 'ThreadsPerPage'))
54 55 paginator.current_page = int(page)
55 56
56 57 try:
@@ -60,6 +61,7 b' class AllThreadsView(PostMixin, BaseBoar'
60 61
61 62 params[PARAMETER_THREADS] = threads
62 63 params[CONTEXT_FORM] = form
64 params[PARAMETER_BANNERS] = Banner.objects.order_by('-id').all()
63 65
64 66 self.get_page_context(paginator, params, page)
65 67
@@ -32,7 +32,8 b' class SettingsView(BaseBoardView):'
32 32 initial={
33 33 FORM_THEME: selected_theme,
34 34 FORM_IMAGE_VIEWER: settings_manager.get_setting(
35 SETTING_IMAGE_VIEWER, default=settings.DEFAULT_IMAGE_VIEWER),
35 SETTING_IMAGE_VIEWER,
36 default=settings.get('View', 'DefaultImageViewer')),
36 37 FORM_USERNAME: settings_manager.get_setting(SETTING_USERNAME),
37 38 FORM_TIMEZONE: request.session.get(
38 39 SESSION_TIMEZONE, timezone.get_current_timezone()),
@@ -51,7 +51,7 b' class ThreadView(BaseBoardView, PostMixi'
51 51 params[CONTEXT_LASTUPDATE] = str(thread_to_show.last_edit_time)
52 52 params[CONTEXT_THREAD] = thread_to_show
53 53
54 if settings.WEBSOCKETS_ENABLED:
54 if settings.get_bool('External', 'WebsocketsEnabled'):
55 55 token_time = format(timezone.now(), u'U')
56 56
57 57 params[CONTEXT_WS_TIME] = token_time
@@ -144,7 +144,7 b' INSTALLED_APPS = ('
144 144 'django.contrib.admin',
145 145 # Uncomment the next line to enable admin documentation:
146 146 # 'django.contrib.admindocs',
147 'django.contrib.humanize',
147 #'django.contrib.humanize',
148 148
149 149 'debug_toolbar',
150 150
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now