##// END OF EJS Templates
Making tags lower case.
neko259 -
r199:1b4fd6ab default
parent child Browse files
Show More
@@ -1,354 +1,355 b''
1 1 import hashlib
2 import string
2 3 from django.core.urlresolvers import reverse
3 4 from django.http import HttpResponseRedirect
4 5 from django.template import RequestContext
5 6 from django.shortcuts import render, redirect, get_object_or_404
6 7 from django.utils import timezone
7 8
8 9 from boards import forms
9 10 import boards
10 11 from boards import utils
11 12 from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \
12 13 ThreadCaptchaForm, PostCaptchaForm, LoginForm
13 14
14 15 from boards.models import Post, Tag, Ban, User, RANK_USER, NO_PARENT
15 16 from boards import authors
16 17 import neboard
17 18
18 19
19 20 def index(request, page=0):
20 21 context = _init_default_context(request)
21 22
22 23 if utils.need_include_captcha(request):
23 24 threadFormClass = ThreadCaptchaForm
24 25 kwargs = {'request': request}
25 26 else:
26 27 threadFormClass = ThreadForm
27 28 kwargs = {}
28 29
29 30 if request.method == 'POST':
30 31 form = threadFormClass(request.POST, request.FILES,
31 32 error_class=PlainErrorList, **kwargs)
32 33 form.session = request.session
33 34
34 35 if form.is_valid():
35 36 return _new_post(request, form)
36 37 else:
37 38 form = threadFormClass(error_class=PlainErrorList, **kwargs)
38 39
39 40 threads = []
40 41 for thread in Post.objects.get_threads(page=int(page)):
41 42 threads.append({'thread': thread,
42 43 'bumpable': thread.can_bump()})
43 44
44 45 context['threads'] = None if len(threads) == 0 else threads
45 46 context['form'] = form
46 47 context['pages'] = range(Post.objects.get_thread_page_count())
47 48
48 49 return render(request, 'boards/posting_general.html',
49 50 context)
50 51
51 52
52 53 def _new_post(request, form, thread_id=boards.models.NO_PARENT):
53 54 """Add a new post (in thread or as a reply)."""
54 55
55 56 ip = _get_client_ip(request)
56 57 is_banned = Ban.objects.filter(ip=ip).count() > 0
57 58
58 59 if is_banned:
59 60 return redirect(you_are_banned)
60 61
61 62 data = form.cleaned_data
62 63
63 64 title = data['title']
64 65 text = data['text']
65 66
66 67 if 'image' in data.keys():
67 68 image = data['image']
68 69 else:
69 70 image = None
70 71
71 72 tags = []
72 73
73 74 new_thread = thread_id == boards.models.NO_PARENT
74 75 if new_thread:
75 76 tag_strings = data['tags']
76 77
77 78 if tag_strings:
78 79 tag_strings = tag_strings.split(' ')
79 80 for tag_name in tag_strings:
80 tag_name = tag_name.strip()
81 tag_name = string.lower(tag_name.strip())
81 82 if len(tag_name) > 0:
82 83 tag, created = Tag.objects.get_or_create(name=tag_name)
83 84 tags.append(tag)
84 85
85 86 op = None if thread_id == boards.models.NO_PARENT else \
86 87 get_object_or_404(Post, id=thread_id)
87 88 post = Post.objects.create_post(title=title, text=text, ip=ip,
88 89 thread=op, image=image,
89 90 tags=tags, user=_get_user(request))
90 91
91 92 thread_to_show = (post.id if new_thread else thread_id)
92 93
93 94 if new_thread:
94 95 return redirect(thread, post_id=thread_to_show)
95 96 else:
96 97 return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) +
97 98 '#' + str(post.id))
98 99
99 100
100 101 def tag(request, tag_name, page=0):
101 102 """Get all tag threads (posts without a parent)."""
102 103
103 104 tag = get_object_or_404(Tag, name=tag_name)
104 105 threads = []
105 106 for thread in Post.objects.get_threads(tag=tag, page=int(page)):
106 107 threads.append({'thread': thread,
107 108 'bumpable': thread.can_bump()})
108 109
109 110 if request.method == 'POST':
110 111 form = ThreadForm(request.POST, request.FILES,
111 112 error_class=PlainErrorList)
112 113 if form.is_valid():
113 114 return _new_post(request, form)
114 115 else:
115 116 form = forms.ThreadForm(initial={'tags': tag_name},
116 117 error_class=PlainErrorList)
117 118
118 119 context = _init_default_context(request)
119 120 context['threads'] = None if len(threads) == 0 else threads
120 121 context['tag'] = tag
121 122 context['pages'] = range(Post.objects.get_thread_page_count(tag=tag))
122 123
123 124 context['form'] = form
124 125
125 126 return render(request, 'boards/posting_general.html',
126 127 context)
127 128
128 129
129 130 def thread(request, post_id):
130 131 """Get all thread posts"""
131 132
132 133 if utils.need_include_captcha(request):
133 134 postFormClass = PostCaptchaForm
134 135 kwargs = {'request': request}
135 136 else:
136 137 postFormClass = PostForm
137 138 kwargs = {}
138 139
139 140 if request.method == 'POST':
140 141 form = postFormClass(request.POST, request.FILES,
141 142 error_class=PlainErrorList, **kwargs)
142 143 form.session = request.session
143 144
144 145 if form.is_valid():
145 146 return _new_post(request, form, post_id)
146 147 else:
147 148 form = postFormClass(error_class=PlainErrorList, **kwargs)
148 149
149 150 posts = Post.objects.get_thread(post_id)
150 151
151 152 context = _init_default_context(request)
152 153
153 154 context['posts'] = posts
154 155 context['form'] = form
155 156 context['bumpable'] = posts[0].can_bump()
156 157
157 158 return render(request, 'boards/thread.html', context)
158 159
159 160
160 161 def login(request):
161 162 """Log in with user id"""
162 163
163 164 context = _init_default_context(request)
164 165
165 166 if request.method == 'POST':
166 167 form = LoginForm(request.POST, request.FILES,
167 168 error_class=PlainErrorList)
168 169 if form.is_valid():
169 170 user = User.objects.get(user_id=form.cleaned_data['user_id'])
170 171 request.session['user_id'] = user.id
171 172 return redirect(index)
172 173
173 174 else:
174 175 form = LoginForm()
175 176
176 177 context['form'] = form
177 178
178 179 return render(request, 'boards/login.html', context)
179 180
180 181
181 182 def settings(request):
182 183 """User's settings"""
183 184
184 185 context = _init_default_context(request)
185 186
186 187 if request.method == 'POST':
187 188 form = SettingsForm(request.POST)
188 189 if form.is_valid():
189 190 selected_theme = form.cleaned_data['theme']
190 191
191 192 user = _get_user(request)
192 193 user.save_setting('theme', selected_theme)
193 194
194 195 return redirect(settings)
195 196 else:
196 197 selected_theme = _get_theme(request)
197 198 form = SettingsForm(initial={'theme': selected_theme})
198 199 context['form'] = form
199 200
200 201 return render(request, 'boards/settings.html', context)
201 202
202 203
203 204 def all_tags(request):
204 205 """All tags list"""
205 206
206 207 context = _init_default_context(request)
207 208 context['all_tags'] = Tag.objects.get_not_empty_tags()
208 209
209 210 return render(request, 'boards/tags.html', context)
210 211
211 212
212 213 def jump_to_post(request, post_id):
213 214 """Determine thread in which the requested post is and open it's page"""
214 215
215 216 post = get_object_or_404(Post, id=post_id)
216 217
217 218 if not post.thread:
218 219 return redirect(thread, post_id=post.id)
219 220 else:
220 221 return redirect(reverse(thread, kwargs={'post_id': post.thread.id})
221 222 + '#' + str(post.id))
222 223
223 224
224 225 def authors(request):
225 226 context = _init_default_context(request)
226 227 context['authors'] = boards.authors.authors
227 228
228 229 return render(request, 'boards/authors.html', context)
229 230
230 231
231 232 def delete(request, post_id):
232 233 user = _get_user(request)
233 234 post = get_object_or_404(Post, id=post_id)
234 235
235 236 if user.is_moderator():
236 237 # TODO Show confirmation page before deletion
237 238 Post.objects.delete_post(post)
238 239
239 240 if not post.thread:
240 241 return _redirect_to_next(request)
241 242 else:
242 243 return redirect(thread, post_id=post.thread.id)
243 244
244 245
245 246 def ban(request, post_id):
246 247 user = _get_user(request)
247 248 post = get_object_or_404(Post, id=post_id)
248 249
249 250 if user.is_moderator():
250 251 # TODO Show confirmation page before ban
251 252 Ban.objects.get_or_create(ip=post.poster_ip)
252 253
253 254 return _redirect_to_next(request)
254 255
255 256
256 257 def you_are_banned(request):
257 258 context = _init_default_context(request)
258 259 return render(request, 'boards/staticpages/banned.html', context)
259 260
260 261
261 262 def page_404(request):
262 263 context = _init_default_context(request)
263 264 return render(request, 'boards/404.html', context)
264 265
265 266
266 267 def tag_subscribe(request, tag_name):
267 268 user = _get_user(request)
268 269 tag = get_object_or_404(Tag, name=tag_name)
269 270
270 271 if not tag in user.fav_tags.all():
271 272 user.fav_tags.add(tag)
272 273
273 274 return _redirect_to_next(request)
274 275
275 276
276 277 def tag_unsubscribe(request, tag_name):
277 278 user = _get_user(request)
278 279 tag = get_object_or_404(Tag, name=tag_name)
279 280
280 281 if tag in user.fav_tags.all():
281 282 user.fav_tags.remove(tag)
282 283
283 284 return _redirect_to_next(request)
284 285
285 286
286 287 def static_page(request, name):
287 288 context = _init_default_context(request)
288 289 return render(request, 'boards/staticpages/' + name + '.html', context)
289 290
290 291
291 292 def _get_theme(request, user=None):
292 293 """Get user's CSS theme"""
293 294
294 295 if not user:
295 296 user = _get_user(request)
296 297 theme = user.get_setting('theme')
297 298 if not theme:
298 299 theme = neboard.settings.DEFAULT_THEME
299 300
300 301 return theme
301 302
302 303
303 304 def _get_client_ip(request):
304 305 x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
305 306 if x_forwarded_for:
306 307 ip = x_forwarded_for.split(',')[-1].strip()
307 308 else:
308 309 ip = request.META.get('REMOTE_ADDR')
309 310 return ip
310 311
311 312
312 313 def _init_default_context(request):
313 314 """Create context with default values that are used in most views"""
314 315
315 316 context = RequestContext(request)
316 317
317 318 user = _get_user(request)
318 319 context['user'] = user
319 320 context['tags'] = user.get_sorted_fav_tags()
320 321 context['theme'] = _get_theme(request, user)
321 322 context['moderator'] = user.is_moderator()
322 323
323 324 return context
324 325
325 326
326 327 def _get_user(request):
327 328 """Get current user from the session"""
328 329
329 330 session = request.session
330 331 if not 'user_id' in session:
331 332 request.session.save()
332 333
333 334 md5 = hashlib.md5()
334 335 md5.update(session.session_key)
335 336 new_id = md5.hexdigest()
336 337
337 338 time_now = timezone.now()
338 339 user = User.objects.create(user_id=new_id, rank=RANK_USER,
339 340 registration_time=time_now,
340 341 last_access_time=time_now)
341 342
342 343 session['user_id'] = user.id
343 344 else:
344 345 user = User.objects.get(id=session['user_id'])
345 346
346 347 return user
347 348
348 349
349 350 def _redirect_to_next(request):
350 351 if 'next' in request.GET:
351 352 next_page = request.GET['next']
352 353 return HttpResponseRedirect(next_page)
353 354 else:
354 355 return redirect(index)
@@ -1,214 +1,214 b''
1 1 # Django settings for neboard project.
2 2 import os
3 3 import markdown
4 4 from boards.mdx_neboard import markdown_extended
5 5
6 6 DEBUG = True
7 7 TEMPLATE_DEBUG = DEBUG
8 8
9 9 ADMINS = (
10 10 # ('Your Name', 'your_email@example.com'),
11 11 ('admin', 'admin@example.com')
12 12 )
13 13
14 14 MANAGERS = ADMINS
15 15
16 16 DATABASES = {
17 17 'default': {
18 18 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
19 19 'NAME': 'database.db', # Or path to database file if using sqlite3.
20 20 'USER': '', # Not used with sqlite3.
21 21 'PASSWORD': '', # Not used with sqlite3.
22 22 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
23 23 'PORT': '', # Set to empty string for default. Not used with sqlite3.
24 24 }
25 25 }
26 26
27 27 CACHES = {
28 28 'default': {
29 29 'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
30 30 'LOCATION': 'neboard_cache',
31 31 }
32 32 }
33 33
34 34 # Local time zone for this installation. Choices can be found here:
35 35 # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
36 36 # although not all choices may be available on all operating systems.
37 37 # In a Windows environment this must be set to your system time zone.
38 38 TIME_ZONE = 'Europe/Kiev'
39 39
40 40 # Language code for this installation. All choices can be found here:
41 41 # http://www.i18nguy.com/unicode/language-identifiers.html
42 42 LANGUAGE_CODE = 'en'
43 43
44 44 SITE_ID = 1
45 45
46 46 # If you set this to False, Django will make some optimizations so as not
47 47 # to load the internationalization machinery.
48 48 USE_I18N = True
49 49
50 50 # If you set this to False, Django will not format dates, numbers and
51 51 # calendars according to the current locale.
52 52 USE_L10N = True
53 53
54 54 # If you set this to False, Django will not use timezone-aware datetimes.
55 55 USE_TZ = True
56 56
57 57 # Absolute filesystem path to the directory that will hold user-uploaded files.
58 58 # Example: "/home/media/media.lawrence.com/media/"
59 59 MEDIA_ROOT = './media/'
60 60
61 61 # URL that handles the media served from MEDIA_ROOT. Make sure to use a
62 62 # trailing slash.
63 63 # Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
64 64 MEDIA_URL = '/media/'
65 65
66 66 # Absolute path to the directory static files should be collected to.
67 67 # Don't put anything in this directory yourself; store your static files
68 68 # in apps' "static/" subdirectories and in STATICFILES_DIRS.
69 69 # Example: "/home/media/media.lawrence.com/static/"
70 70 STATIC_ROOT = ''
71 71
72 72 # URL prefix for static files.
73 73 # Example: "http://media.lawrence.com/static/"
74 74 STATIC_URL = '/static/'
75 75
76 76 # Additional locations of static files
77 77 # It is really a hack, put real paths, not related
78 78 STATICFILES_DIRS = (
79 79 os.path.dirname(__file__) + '/boards/static',
80 80
81 81 # '/d/work/python/django/neboard/neboard/boards/static',
82 82 # Put strings here, like "/home/html/static" or "C:/www/django/static".
83 83 # Always use forward slashes, even on Windows.
84 84 # Don't forget to use absolute paths, not relative paths.
85 85 )
86 86
87 87 # List of finder classes that know how to find static files in
88 88 # various locations.
89 89 STATICFILES_FINDERS = (
90 90 'django.contrib.staticfiles.finders.FileSystemFinder',
91 91 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
92 92 # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
93 93 )
94 94
95 95 # Make this unique, and don't share it with anybody.
96 96 SECRET_KEY = '@1rc$o(7=tt#kd+4s$u6wchm**z^)4x90)7f6z(i&55@o11*8o'
97 97
98 98 # List of callables that know how to import templates from various sources.
99 99 TEMPLATE_LOADERS = (
100 100 'django.template.loaders.filesystem.Loader',
101 101 'django.template.loaders.app_directories.Loader',
102 102 # 'django.template.loaders.eggs.Loader',
103 103 )
104 104
105 105 TEMPLATE_CONTEXT_PROCESSORS = (
106 106 'django.core.context_processors.media',
107 107 'django.core.context_processors.static',
108 108 'django.core.context_processors.request',
109 109 'django.contrib.auth.context_processors.auth',
110 110 )
111 111
112 112 MIDDLEWARE_CLASSES = (
113 113 'django.contrib.sessions.middleware.SessionMiddleware',
114 114 'django.middleware.locale.LocaleMiddleware',
115 115 'django.middleware.common.CommonMiddleware',
116 116 # 'django.middleware.csrf.CsrfViewMiddleware',
117 117 'django.contrib.auth.middleware.AuthenticationMiddleware',
118 118 'django.contrib.messages.middleware.MessageMiddleware',
119 119 # Uncomment the next line for simple clickjacking protection:
120 120 # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
121 121 )
122 122
123 123 ROOT_URLCONF = 'neboard.urls'
124 124
125 125 # Python dotted path to the WSGI application used by Django's runserver.
126 126 WSGI_APPLICATION = 'neboard.wsgi.application'
127 127
128 128 TEMPLATE_DIRS = (
129 129 # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
130 130 # Always use forward slashes, even on Windows.
131 131 # Don't forget to use absolute paths, not relative paths.
132 132 'templates',
133 133 )
134 134
135 135 INSTALLED_APPS = (
136 136 'django.contrib.auth',
137 137 'django.contrib.contenttypes',
138 138 'django.contrib.sessions',
139 139 # 'django.contrib.sites',
140 140 'django.contrib.messages',
141 141 'django.contrib.staticfiles',
142 142 # Uncomment the next line to enable the admin:
143 143 'django.contrib.admin',
144 144 # Uncomment the next line to enable admin documentation:
145 145 # 'django.contrib.admindocs',
146 146 'django.contrib.markup',
147 147 'django_cleanup',
148 148 'boards',
149 149 'captcha',
150 150 'south',
151 151 )
152 152
153 153 # TODO: NEED DESIGN FIXES
154 154 CAPTCHA_OUTPUT_FORMAT = (u' %(hidden_field)s '
155 155 u'<div class="form-label">%(image)s</div>'
156 156 u'<div class="form-text">%(text_field)s</div>')
157 157
158 158 # A sample logging configuration. The only tangible logging
159 159 # performed by this configuration is to send an email to
160 160 # the site admins on every HTTP 500 error when DEBUG=False.
161 161 # See http://docs.djangoproject.com/en/dev/topics/logging for
162 162 # more details on how to customize your logging configuration.
163 163 LOGGING = {
164 164 'version': 1,
165 165 'disable_existing_loggers': False,
166 166 'filters': {
167 167 'require_debug_false': {
168 168 '()': 'django.utils.log.RequireDebugFalse'
169 169 }
170 170 },
171 171 'handlers': {
172 172 'mail_admins': {
173 173 'level': 'ERROR',
174 174 'filters': ['require_debug_false'],
175 175 'class': 'django.utils.log.AdminEmailHandler'
176 176 }
177 177 },
178 178 'loggers': {
179 179 'django.request': {
180 180 'handlers': ['mail_admins'],
181 181 'level': 'ERROR',
182 182 'propagate': True,
183 183 },
184 184 }
185 185 }
186 186
187 187 MARKUP_FIELD_TYPES = (
188 188 ('markdown', markdown_extended),
189 189 )
190 190 # Custom imageboard settings
191 191 MAX_POSTS_PER_THREAD = 10 # Thread bumplimit
192 192 MAX_THREAD_COUNT = 500 # Old threads will be deleted to preserve this count
193 193 THREADS_PER_PAGE = 10
194 194 SITE_NAME = 'Neboard'
195 195
196 196 THEMES = [
197 197 ('md', 'Mystic Dark'),
198 198 ('sw', 'Snow White'),
199 199 ('pg', 'Photon Gray'),
200 200 ]
201 201
202 202 DEFAULT_THEME = 'md'
203 203
204 204 POPULAR_TAGS = 10
205 205 LAST_REPLIES_COUNT = 3
206 206
207 207 ENABLE_CAPTCHA = False
208 208 # if user tries to post before CAPTCHA_DEFAULT_SAFE_TIME. Captcha will be shown
209 209 CAPTCHA_DEFAULT_SAFE_TIME = 30 # seconds
210 210 POSTING_DELAY = 30 # seconds
211 211
212 212 # Debug mode middlewares
213 213 if DEBUG:
214 MIDDLEWARE_CLASSES += ( 'boards.profiler.ProfilerMiddleware', )
214 MIDDLEWARE_CLASSES += ( 'boards.profiler.ProfilerMiddleware', )
General Comments 0
You need to be logged in to leave comments. Login now