##// END OF EJS Templates
Use transactions only in views that need them
neko259 -
r335:172f5ae7 default
parent child Browse files
Show More
@@ -1,485 +1,492 b''
1 1 import hashlib
2 2 import string
3 3 from django.core import serializers
4 4 from django.core.urlresolvers import reverse
5 5 from django.http import HttpResponseRedirect
6 6 from django.http.response import HttpResponse
7 7 from django.template import RequestContext
8 8 from django.shortcuts import render, redirect, get_object_or_404
9 9 from django.utils import timezone
10 from django.db import transaction
10 11
11 12 from boards import forms
12 13 import boards
13 14 from boards import utils
14 15 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
15 16 ThreadCaptchaForm, PostCaptchaForm, LoginForm, ModeratorSettingsForm
16 17
17 18 from boards.models import Post, Tag, Ban, User, RANK_USER, SETTING_MODERATE, \
18 19 REGEX_REPLY
19 20 from boards import authors
20 21 from boards.utils import get_client_ip
21 22 import neboard
22 23 import re
23 24
24 25
25 26 def index(request, page=0):
26 27 context = _init_default_context(request)
27 28
28 29 if utils.need_include_captcha(request):
29 30 threadFormClass = ThreadCaptchaForm
30 31 kwargs = {'request': request}
31 32 else:
32 33 threadFormClass = ThreadForm
33 34 kwargs = {}
34 35
35 36 if request.method == 'POST':
36 37 form = threadFormClass(request.POST, request.FILES,
37 38 error_class=PlainErrorList, **kwargs)
38 39 form.session = request.session
39 40
40 41 if form.is_valid():
41 42 return _new_post(request, form)
42 43 if form.need_to_ban:
43 44 # Ban user because he is suspected to be a bot
44 45 _ban_current_user(request)
45 46 else:
46 47 form = threadFormClass(error_class=PlainErrorList, **kwargs)
47 48
48 49 threads = []
49 50 for thread in Post.objects.get_threads(page=int(page)):
50 51 threads.append({
51 52 'thread': thread,
52 53 'bumpable': thread.can_bump(),
53 54 'last_replies': thread.get_last_replies(),
54 55 })
55 56
56 57 context['threads'] = None if len(threads) == 0 else threads
57 58 context['form'] = form
58 59 context['pages'] = range(Post.objects.get_thread_page_count())
59 60
60 61 return render(request, 'boards/posting_general.html',
61 62 context)
62 63
63 64
65 @transaction.commit_on_success
64 66 def _new_post(request, form, thread_id=boards.models.NO_PARENT):
65 67 """Add a new post (in thread or as a reply)."""
66 68
67 69 ip = get_client_ip(request)
68 70 is_banned = Ban.objects.filter(ip=ip).exists()
69 71
70 72 if is_banned:
71 73 return redirect(you_are_banned)
72 74
73 75 data = form.cleaned_data
74 76
75 77 title = data['title']
76 78 text = data['text']
77 79
78 80 text = _remove_invalid_links(text)
79 81
80 82 if 'image' in data.keys():
81 83 image = data['image']
82 84 else:
83 85 image = None
84 86
85 87 tags = []
86 88
87 89 new_thread = thread_id == boards.models.NO_PARENT
88 90 if new_thread:
89 91 tag_strings = data['tags']
90 92
91 93 if tag_strings:
92 94 tag_strings = tag_strings.split(' ')
93 95 for tag_name in tag_strings:
94 96 tag_name = string.lower(tag_name.strip())
95 97 if len(tag_name) > 0:
96 98 tag, created = Tag.objects.get_or_create(name=tag_name)
97 99 tags.append(tag)
98 100
99 101 linked_tags = tag.get_linked_tags()
100 102 if len(linked_tags) > 0:
101 103 tags.extend(linked_tags)
102 104
103 105 op = None if thread_id == boards.models.NO_PARENT else \
104 106 get_object_or_404(Post, id=thread_id)
105 107 post = Post.objects.create_post(title=title, text=text, ip=ip,
106 108 thread=op, image=image,
107 109 tags=tags, user=_get_user(request))
108 110
109 111 thread_to_show = (post.id if new_thread else thread_id)
110 112
111 113 if new_thread:
112 114 return redirect(thread, post_id=thread_to_show)
113 115 else:
114 116 return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) +
115 117 '#' + str(post.id))
116 118
117 119
118 120 def tag(request, tag_name, page=0):
119 121 """
120 122 Get all tag threads. Threads are split in pages, so some page is
121 123 requested. Default page is 0.
122 124 """
123 125
124 126 tag = get_object_or_404(Tag, name=tag_name)
125 127 threads = []
126 128 for thread in Post.objects.get_threads(tag=tag, page=int(page)):
127 129 threads.append({
128 130 'thread': thread,
129 131 'bumpable': thread.can_bump(),
130 132 'last_replies': thread.get_last_replies(),
131 133 })
132 134
133 135 if request.method == 'POST':
134 136 form = ThreadForm(request.POST, request.FILES,
135 137 error_class=PlainErrorList)
136 138 form.session = request.session
137 139
138 140 if form.is_valid():
139 141 return _new_post(request, form)
140 142 if form.need_to_ban:
141 143 # Ban user because he is suspected to be a bot
142 144 _ban_current_user(request)
143 145 else:
144 146 form = forms.ThreadForm(initial={'tags': tag_name},
145 147 error_class=PlainErrorList)
146 148
147 149 context = _init_default_context(request)
148 150 context['threads'] = None if len(threads) == 0 else threads
149 151 context['tag'] = tag
150 152 context['pages'] = range(Post.objects.get_thread_page_count(tag=tag))
151 153
152 154 context['form'] = form
153 155
154 156 return render(request, 'boards/posting_general.html',
155 157 context)
156 158
157 159
158 160 def thread(request, post_id):
159 161 """Get all thread posts"""
160 162
161 163 if utils.need_include_captcha(request):
162 164 postFormClass = PostCaptchaForm
163 165 kwargs = {'request': request}
164 166 else:
165 167 postFormClass = PostForm
166 168 kwargs = {}
167 169
168 170 if request.method == 'POST':
169 171 form = postFormClass(request.POST, request.FILES,
170 172 error_class=PlainErrorList, **kwargs)
171 173 form.session = request.session
172 174
173 175 if form.is_valid():
174 176 return _new_post(request, form, post_id)
175 177 if form.need_to_ban:
176 178 # Ban user because he is suspected to be a bot
177 179 _ban_current_user(request)
178 180 else:
179 181 form = postFormClass(error_class=PlainErrorList, **kwargs)
180 182
181 183 posts = Post.objects.get_thread(post_id)
182 184
183 185 context = _init_default_context(request)
184 186
185 187 context['posts'] = posts
186 188 context['form'] = form
187 189 context['bumpable'] = posts[0].can_bump()
188 190 if context['bumpable']:
189 191 context['posts_left'] = neboard.settings.MAX_POSTS_PER_THREAD - len(
190 192 posts)
191 193 context['bumplimit_progress'] = str(
192 194 float(context['posts_left']) /
193 195 neboard.settings.MAX_POSTS_PER_THREAD * 100)
194 196
195 197 return render(request, 'boards/thread.html', context)
196 198
197 199
198 200 def login(request):
199 201 """Log in with user id"""
200 202
201 203 context = _init_default_context(request)
202 204
203 205 if request.method == 'POST':
204 206 form = LoginForm(request.POST, request.FILES,
205 207 error_class=PlainErrorList)
206 208 form.session = request.session
207 209
208 210 if form.is_valid():
209 211 user = User.objects.get(user_id=form.cleaned_data['user_id'])
210 212 request.session['user_id'] = user.id
211 213 return redirect(index)
212 214
213 215 else:
214 216 form = LoginForm()
215 217
216 218 context['form'] = form
217 219
218 220 return render(request, 'boards/login.html', context)
219 221
220 222
221 223 def settings(request):
222 224 """User's settings"""
223 225
224 226 context = _init_default_context(request)
225 227 user = _get_user(request)
226 228 is_moderator = user.is_moderator()
227 229
228 230 if request.method == 'POST':
229 if is_moderator:
230 form = ModeratorSettingsForm(request.POST,
231 error_class=PlainErrorList)
232 else:
233 form = SettingsForm(request.POST, error_class=PlainErrorList)
231 with transaction.commit_on_success():
232 if is_moderator:
233 form = ModeratorSettingsForm(request.POST,
234 error_class=PlainErrorList)
235 else:
236 form = SettingsForm(request.POST, error_class=PlainErrorList)
234 237
235 if form.is_valid():
236 selected_theme = form.cleaned_data['theme']
238 if form.is_valid():
239 selected_theme = form.cleaned_data['theme']
237 240
238 user.save_setting('theme', selected_theme)
241 user.save_setting('theme', selected_theme)
239 242
240 if is_moderator:
241 moderate = form.cleaned_data['moderate']
242 user.save_setting(SETTING_MODERATE, moderate)
243 if is_moderator:
244 moderate = form.cleaned_data['moderate']
245 user.save_setting(SETTING_MODERATE, moderate)
243 246
244 return redirect(settings)
247 return redirect(settings)
245 248 else:
246 249 selected_theme = _get_theme(request)
247 250
248 251 if is_moderator:
249 252 form = ModeratorSettingsForm(initial={'theme': selected_theme,
250 253 'moderate': context['moderator']},
251 254 error_class=PlainErrorList)
252 255 else:
253 256 form = SettingsForm(initial={'theme': selected_theme},
254 257 error_class=PlainErrorList)
255 258
256 259 context['form'] = form
257 260
258 261 return render(request, 'boards/settings.html', context)
259 262
260 263
261 264 def all_tags(request):
262 265 """All tags list"""
263 266
264 267 context = _init_default_context(request)
265 268 context['all_tags'] = Tag.objects.get_not_empty_tags()
266 269
267 270 return render(request, 'boards/tags.html', context)
268 271
269 272
270 273 def jump_to_post(request, post_id):
271 274 """Determine thread in which the requested post is and open it's page"""
272 275
273 276 post = get_object_or_404(Post, id=post_id)
274 277
275 278 if not post.thread:
276 279 return redirect(thread, post_id=post.id)
277 280 else:
278 281 return redirect(reverse(thread, kwargs={'post_id': post.thread.id})
279 282 + '#' + str(post.id))
280 283
281 284
282 285 def authors(request):
283 286 """Show authors list"""
284 287
285 288 context = _init_default_context(request)
286 289 context['authors'] = boards.authors.authors
287 290
288 291 return render(request, 'boards/authors.html', context)
289 292
290 293
294 @transaction.commit_on_success
291 295 def delete(request, post_id):
292 296 """Delete post"""
293 297
294 298 user = _get_user(request)
295 299 post = get_object_or_404(Post, id=post_id)
296 300
297 301 if user.is_moderator():
298 302 # TODO Show confirmation page before deletion
299 303 Post.objects.delete_post(post)
300 304
301 305 if not post.thread:
302 306 return _redirect_to_next(request)
303 307 else:
304 308 return redirect(thread, post_id=post.thread.id)
305 309
306 310
311 @transaction.commit_on_success
307 312 def ban(request, post_id):
308 313 """Ban user"""
309 314
310 315 user = _get_user(request)
311 316 post = get_object_or_404(Post, id=post_id)
312 317
313 318 if user.is_moderator():
314 319 # TODO Show confirmation page before ban
315 320 Ban.objects.get_or_create(ip=post.poster_ip)
316 321
317 322 return _redirect_to_next(request)
318 323
319 324
320 325 def you_are_banned(request):
321 326 """Show the page that notifies that user is banned"""
322 327
323 328 context = _init_default_context(request)
324 329 return render(request, 'boards/staticpages/banned.html', context)
325 330
326 331
327 332 def page_404(request):
328 333 """Show page 404 (not found error)"""
329 334
330 335 context = _init_default_context(request)
331 336 return render(request, 'boards/404.html', context)
332 337
333 338
339 @transaction.commit_on_success
334 340 def tag_subscribe(request, tag_name):
335 341 """Add tag to favorites"""
336 342
337 343 user = _get_user(request)
338 344 tag = get_object_or_404(Tag, name=tag_name)
339 345
340 346 if not tag in user.fav_tags.all():
341 347 user.add_tag(tag)
342 348
343 349 return _redirect_to_next(request)
344 350
345 351
352 @transaction.commit_on_success
346 353 def tag_unsubscribe(request, tag_name):
347 354 """Remove tag from favorites"""
348 355
349 356 user = _get_user(request)
350 357 tag = get_object_or_404(Tag, name=tag_name)
351 358
352 359 if tag in user.fav_tags.all():
353 360 user.remove_tag(tag)
354 361
355 362 return _redirect_to_next(request)
356 363
357 364
358 365 def static_page(request, name):
359 366 """Show a static page that needs only tags list and a CSS"""
360 367
361 368 context = _init_default_context(request)
362 369 return render(request, 'boards/staticpages/' + name + '.html', context)
363 370
364 371
365 372 def api_get_post(request, post_id):
366 373 """
367 374 Get the JSON of a post. This can be
368 375 used as and API for external clients.
369 376 """
370 377
371 378 post = get_object_or_404(Post, id=post_id)
372 379
373 380 json = serializers.serialize("json", [post], fields=(
374 381 "pub_time", "_text_rendered", "title", "text", "image",
375 382 "image_width", "image_height", "replies", "tags"
376 383 ))
377 384
378 385 return HttpResponse(content=json)
379 386
380 387
381 388 def get_post(request, post_id):
382 389 """Get the html of a post. Used for popups."""
383 390
384 391 post = get_object_or_404(Post, id=post_id)
385 392
386 393 context = RequestContext(request)
387 394 context["post"] = post
388 395
389 396 return render(request, 'boards/post.html', context)
390 397
391 398
392 399 def _get_theme(request, user=None):
393 400 """Get user's CSS theme"""
394 401
395 402 if not user:
396 403 user = _get_user(request)
397 404 theme = user.get_setting('theme')
398 405 if not theme:
399 406 theme = neboard.settings.DEFAULT_THEME
400 407
401 408 return theme
402 409
403 410
404 411 def _init_default_context(request):
405 412 """Create context with default values that are used in most views"""
406 413
407 414 context = RequestContext(request)
408 415
409 416 user = _get_user(request)
410 417 context['user'] = user
411 418 context['tags'] = user.get_sorted_fav_tags()
412 419
413 420 theme = _get_theme(request, user)
414 421 context['theme'] = theme
415 422 context['theme_css'] = 'css/' + theme + '/base_page.css'
416 423
417 424 # This shows the moderator panel
418 425 moderate = user.get_setting(SETTING_MODERATE)
419 426 if moderate == 'True':
420 427 context['moderator'] = user.is_moderator()
421 428 else:
422 429 context['moderator'] = False
423 430
424 431 return context
425 432
426 433
427 434 def _get_user(request):
428 435 """
429 436 Get current user from the session. If the user does not exist, create
430 437 a new one.
431 438 """
432 439
433 440 session = request.session
434 441 if not 'user_id' in session:
435 442 request.session.save()
436 443
437 444 md5 = hashlib.md5()
438 445 md5.update(session.session_key)
439 446 new_id = md5.hexdigest()
440 447
441 448 time_now = timezone.now()
442 449 user = User.objects.create(user_id=new_id, rank=RANK_USER,
443 450 registration_time=time_now)
444 451
445 452 session['user_id'] = user.id
446 453 else:
447 454 user = User.objects.get(id=session['user_id'])
448 455
449 456 return user
450 457
451 458
452 459 def _redirect_to_next(request):
453 460 """
454 461 If a 'next' parameter was specified, redirect to the next page. This is
455 462 used when the user is required to return to some page after the current
456 463 view has finished its work.
457 464 """
458 465
459 466 if 'next' in request.GET:
460 467 next_page = request.GET['next']
461 468 return HttpResponseRedirect(next_page)
462 469 else:
463 470 return redirect(index)
464 471
465 472
466 473 def _ban_current_user(request):
467 474 """Add current user to the IP ban list"""
468 475
469 476 ip = utils.get_client_ip(request)
470 477 Ban.objects.get_or_create(ip=ip)
471 478
472 479
473 480 def _remove_invalid_links(text):
474 481 """
475 482 Replace invalid links in posts so that they won't be parsed.
476 483 Invalid links are links to non-existent posts
477 484 """
478 485
479 486 for reply_number in re.finditer(REGEX_REPLY, text):
480 487 post_id = reply_number.group(1)
481 488 post = Post.objects.filter(id=post_id)
482 489 if not post.exists():
483 490 text = string.replace(text, '>>' + id, id)
484 491
485 492 return text
@@ -1,241 +1,240 b''
1 1 # Django settings for neboard project.
2 2 import os
3 3 from boards.mdx_neboard import markdown_extended
4 4
5 5 DEBUG = True
6 6 TEMPLATE_DEBUG = DEBUG
7 7
8 8 ADMINS = (
9 9 # ('Your Name', 'your_email@example.com'),
10 10 ('admin', 'admin@example.com')
11 11 )
12 12
13 13 MANAGERS = ADMINS
14 14
15 15 DATABASES = {
16 16 'default': {
17 17 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
18 18 'NAME': 'database.db', # Or path to database file if using sqlite3.
19 19 'USER': '', # Not used with sqlite3.
20 20 'PASSWORD': '', # Not used with sqlite3.
21 21 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
22 22 'PORT': '', # Set to empty string for default. Not used with sqlite3.
23 23 'CONN_MAX_AGE': None,
24 24 }
25 25 }
26 26
27 27 # Local time zone for this installation. Choices can be found here:
28 28 # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
29 29 # although not all choices may be available on all operating systems.
30 30 # In a Windows environment this must be set to your system time zone.
31 31 TIME_ZONE = 'Europe/Kiev'
32 32
33 33 # Language code for this installation. All choices can be found here:
34 34 # http://www.i18nguy.com/unicode/language-identifiers.html
35 35 LANGUAGE_CODE = 'en'
36 36
37 37 SITE_ID = 1
38 38
39 39 # If you set this to False, Django will make some optimizations so as not
40 40 # to load the internationalization machinery.
41 41 USE_I18N = True
42 42
43 43 # If you set this to False, Django will not format dates, numbers and
44 44 # calendars according to the current locale.
45 45 USE_L10N = True
46 46
47 47 # If you set this to False, Django will not use timezone-aware datetimes.
48 48 USE_TZ = True
49 49
50 50 # Absolute filesystem path to the directory that will hold user-uploaded files.
51 51 # Example: "/home/media/media.lawrence.com/media/"
52 52 MEDIA_ROOT = './media/'
53 53
54 54 # URL that handles the media served from MEDIA_ROOT. Make sure to use a
55 55 # trailing slash.
56 56 # Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
57 57 MEDIA_URL = '/media/'
58 58
59 59 # Absolute path to the directory static files should be collected to.
60 60 # Don't put anything in this directory yourself; store your static files
61 61 # in apps' "static/" subdirectories and in STATICFILES_DIRS.
62 62 # Example: "/home/media/media.lawrence.com/static/"
63 63 STATIC_ROOT = ''
64 64
65 65 # URL prefix for static files.
66 66 # Example: "http://media.lawrence.com/static/"
67 67 STATIC_URL = '/static/'
68 68
69 69 # Additional locations of static files
70 70 # It is really a hack, put real paths, not related
71 71 STATICFILES_DIRS = (
72 72 os.path.dirname(__file__) + '/boards/static',
73 73
74 74 # '/d/work/python/django/neboard/neboard/boards/static',
75 75 # Put strings here, like "/home/html/static" or "C:/www/django/static".
76 76 # Always use forward slashes, even on Windows.
77 77 # Don't forget to use absolute paths, not relative paths.
78 78 )
79 79
80 80 # List of finder classes that know how to find static files in
81 81 # various locations.
82 82 STATICFILES_FINDERS = (
83 83 'django.contrib.staticfiles.finders.FileSystemFinder',
84 84 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
85 85 )
86 86
87 87 if DEBUG:
88 88 STATICFILES_STORAGE = \
89 89 'django.contrib.staticfiles.storage.StaticFilesStorage'
90 90 else:
91 91 STATICFILES_STORAGE = \
92 92 'django.contrib.staticfiles.storage.CachedStaticFilesStorage'
93 93
94 94 # Make this unique, and don't share it with anybody.
95 95 SECRET_KEY = '@1rc$o(7=tt#kd+4s$u6wchm**z^)4x90)7f6z(i&55@o11*8o'
96 96
97 97 # List of callables that know how to import templates from various sources.
98 98 TEMPLATE_LOADERS = (
99 99 'django.template.loaders.filesystem.Loader',
100 100 'django.template.loaders.app_directories.Loader',
101 101 )
102 102
103 103 TEMPLATE_CONTEXT_PROCESSORS = (
104 104 'django.core.context_processors.media',
105 105 'django.core.context_processors.static',
106 106 'django.core.context_processors.request',
107 107 'django.contrib.auth.context_processors.auth',
108 108 )
109 109
110 110 MIDDLEWARE_CLASSES = (
111 111 'django.contrib.sessions.middleware.SessionMiddleware',
112 112 'django.middleware.locale.LocaleMiddleware',
113 113 'django.middleware.common.CommonMiddleware',
114 'django.middleware.transaction.TransactionMiddleware',
115 114 'django.contrib.auth.middleware.AuthenticationMiddleware',
116 115 'django.contrib.messages.middleware.MessageMiddleware',
117 116 'boards.middlewares.BanMiddleware',
118 117 )
119 118
120 119 ROOT_URLCONF = 'neboard.urls'
121 120
122 121 # Python dotted path to the WSGI application used by Django's runserver.
123 122 WSGI_APPLICATION = 'neboard.wsgi.application'
124 123
125 124 TEMPLATE_DIRS = (
126 125 # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
127 126 # Always use forward slashes, even on Windows.
128 127 # Don't forget to use absolute paths, not relative paths.
129 128 'templates',
130 129 )
131 130
132 131 INSTALLED_APPS = (
133 132 'django.contrib.auth',
134 133 'django.contrib.contenttypes',
135 134 'django.contrib.sessions',
136 135 # 'django.contrib.sites',
137 136 'django.contrib.messages',
138 137 'django.contrib.staticfiles',
139 138 # Uncomment the next line to enable the admin:
140 139 'django.contrib.admin',
141 140 # Uncomment the next line to enable admin documentation:
142 141 # 'django.contrib.admindocs',
143 142 'django.contrib.markup',
144 143 'django.contrib.humanize',
145 144 'django_cleanup',
146 145 'boards',
147 146 'captcha',
148 147 'south',
149 148 'debug_toolbar',
150 149 )
151 150
152 151 DEBUG_TOOLBAR_PANELS = (
153 152 'debug_toolbar.panels.version.VersionDebugPanel',
154 153 'debug_toolbar.panels.timer.TimerDebugPanel',
155 154 'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
156 155 'debug_toolbar.panels.headers.HeaderDebugPanel',
157 156 'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
158 157 'debug_toolbar.panels.template.TemplateDebugPanel',
159 158 'debug_toolbar.panels.sql.SQLDebugPanel',
160 159 'debug_toolbar.panels.signals.SignalDebugPanel',
161 160 'debug_toolbar.panels.logger.LoggingPanel',
162 161 )
163 162
164 163 # TODO: NEED DESIGN FIXES
165 164 CAPTCHA_OUTPUT_FORMAT = (u' %(hidden_field)s '
166 165 u'<div class="form-label">%(image)s</div>'
167 166 u'<div class="form-text">%(text_field)s</div>')
168 167
169 168 # A sample logging configuration. The only tangible logging
170 169 # performed by this configuration is to send an email to
171 170 # the site admins on every HTTP 500 error when DEBUG=False.
172 171 # See http://docs.djangoproject.com/en/dev/topics/logging for
173 172 # more details on how to customize your logging configuration.
174 173 LOGGING = {
175 174 'version': 1,
176 175 'disable_existing_loggers': False,
177 176 'filters': {
178 177 'require_debug_false': {
179 178 '()': 'django.utils.log.RequireDebugFalse'
180 179 }
181 180 },
182 181 'handlers': {
183 182 'mail_admins': {
184 183 'level': 'ERROR',
185 184 'filters': ['require_debug_false'],
186 185 'class': 'django.utils.log.AdminEmailHandler'
187 186 }
188 187 },
189 188 'loggers': {
190 189 'django.request': {
191 190 'handlers': ['mail_admins'],
192 191 'level': 'ERROR',
193 192 'propagate': True,
194 193 },
195 194 }
196 195 }
197 196
198 197 MARKUP_FIELD_TYPES = (
199 198 ('markdown', markdown_extended),
200 199 )
201 200 # Custom imageboard settings
202 201 # TODO These should me moved to
203 202 MAX_POSTS_PER_THREAD = 10 # Thread bumplimit
204 203 MAX_THREAD_COUNT = 500 # Old threads will be deleted to preserve this count
205 204 THREADS_PER_PAGE = 10
206 205 SITE_NAME = 'Neboard'
207 206
208 207 THEMES = [
209 208 ('md', 'Mystic Dark'),
210 209 ('md_centered', 'Mystic Dark (centered)'),
211 210 ('sw', 'Snow White'),
212 211 ('pg', 'Photon Gray'),
213 212 ]
214 213
215 214 DEFAULT_THEME = 'md'
216 215
217 216 POPULAR_TAGS = 10
218 217 LAST_REPLIES_COUNT = 3
219 218
220 219 ENABLE_CAPTCHA = False
221 220 # if user tries to post before CAPTCHA_DEFAULT_SAFE_TIME. Captcha will be shown
222 221 CAPTCHA_DEFAULT_SAFE_TIME = 30 # seconds
223 222 POSTING_DELAY = 30 # seconds
224 223
225 224
226 225 def custom_show_toolbar(request):
227 226 return DEBUG
228 227
229 228 DEBUG_TOOLBAR_CONFIG = {
230 229 'INTERCEPT_REDIRECTS': False,
231 230 'SHOW_TOOLBAR_CALLBACK': custom_show_toolbar,
232 231 'HIDE_DJANGO_SQL': False,
233 232 'ENABLE_STACKTRACES': True,
234 233 }
235 234
236 235 # Debug mode middlewares
237 236 if DEBUG:
238 237 MIDDLEWARE_CLASSES += (
239 238 'boards.profiler.ProfilerMiddleware',
240 239 'debug_toolbar.middleware.DebugToolbarMiddleware',
241 240 )
General Comments 0
You need to be logged in to leave comments. Login now