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