##// END OF EJS Templates
Implemented search over posts. Moved get_user and get_theme to utils module. Use context processors instead of creating context in the base view. Removed unused imports in some modules
neko259 -
r690:a8dffe47 1.8-dev
parent child Browse files
Show More
@@ -0,0 +1,31 b''
1 from boards import utils
2 from boards.models import Post
3 from boards.models.post import SETTING_MODERATE
4 import neboard
5
6 __author__ = 'neko259'
7
8
9 def user_and_ui_processor(request):
10 context = {}
11
12 user = utils.get_user(request)
13 context['user'] = user
14 context['tags'] = user.fav_tags.all()
15 context['posts_per_day'] = float(Post.objects.get_posts_per_day())
16
17 theme = utils.get_theme(request, user)
18 context['theme'] = theme
19 context['theme_css'] = 'css/' + theme + '/base_page.css'
20
21 # This shows the moderator panel
22 moderate = user.get_setting(SETTING_MODERATE)
23 if moderate == 'True':
24 context['moderator'] = user.is_moderator()
25 else:
26 context['moderator'] = False
27
28 context['version'] = neboard.settings.VERSION
29 context['site_name'] = neboard.settings.SITE_NAME
30
31 return context No newline at end of file
@@ -0,0 +1,14 b''
1 from haystack import indexes
2 from boards.models import Post
3
4 __author__ = 'neko259'
5
6
7 class PostIndex(indexes.SearchIndex, indexes.Indexable):
8 text = indexes.CharField(document=True, use_template=True)
9
10 def get_model(self):
11 return Post
12
13 def index_queryset(self, using=None):
14 return self.get_model().objects.all() No newline at end of file
@@ -0,0 +1,2 b''
1 {{ object.title }}
2 {{ object.text }} No newline at end of file
@@ -0,0 +1,29 b''
1 {% extends 'boards/base.html' %}
2
3 {% load board %}
4 {% load i18n %}
5
6 {% block content %}
7 <div class="post-form-w">
8 <h3>{% trans 'Search' %}</h3>
9 <form method="get" action=".">
10 {{ form.as_p }}
11 <input type="submit" value="{% trans 'Search' %}">
12 </form>
13 </div>
14
15 {% if query %}
16 {% for result in page.object_list %}
17 {% post_view result.object %}
18 {% empty %}
19 <p>{% trans 'No results found.' %}</p>
20 {% endfor %}
21
22 {% if page.has_previous or page.has_next %}
23 <div>
24 {% if page.has_previous %}<a href="?q={{ query }}&amp;page={{ page.previous_page_number }}">{% endif %}&laquo; {% trans 'Previous' %}{% if page.has_previous %}</a>{% endif %}
25 {% if page.has_next %}<a href="?q={{ query }}&amp;page= {{ page.next_page_number }}">{% endif %}{% trans 'Next' %} &raquo; {% if page.has_next %}</a>{% endif %}
26 </div>
27 {% endif %}
28 {% endif %}
29 {% endblock %} No newline at end of file
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -1,390 +1,390 b''
1 # SOME DESCRIPTIVE TITLE.
1 # SOME DESCRIPTIVE TITLE.
2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 # This file is distributed under the same license as the PACKAGE package.
3 # This file is distributed under the same license as the PACKAGE package.
4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5 #
5 #
6 msgid ""
6 msgid ""
7 msgstr ""
7 msgstr ""
8 "Project-Id-Version: PACKAGE VERSION\n"
8 "Project-Id-Version: PACKAGE VERSION\n"
9 "Report-Msgid-Bugs-To: \n"
9 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2014-05-08 21:35+0300\n"
10 "POT-Creation-Date: 2014-06-15 12:34+0300\n"
11 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
11 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13 "Language-Team: LANGUAGE <LL@li.org>\n"
13 "Language-Team: LANGUAGE <LL@li.org>\n"
14 "Language: ru\n"
14 "Language: ru\n"
15 "MIME-Version: 1.0\n"
15 "MIME-Version: 1.0\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
17 "Content-Transfer-Encoding: 8bit\n"
17 "Content-Transfer-Encoding: 8bit\n"
18 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
18 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
19 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
19 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
20
20
21 #: authors.py:5
21 #: authors.py:5
22 msgid "author"
22 msgid "author"
23 msgstr "Π°Π²Ρ‚ΠΎΡ€"
23 msgstr "Π°Π²Ρ‚ΠΎΡ€"
24
24
25 #: authors.py:6
25 #: authors.py:6
26 msgid "developer"
26 msgid "developer"
27 msgstr "Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ"
27 msgstr "Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ"
28
28
29 #: authors.py:7
29 #: authors.py:7
30 msgid "javascript developer"
30 msgid "javascript developer"
31 msgstr "Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ javascript"
31 msgstr "Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ javascript"
32
32
33 #: authors.py:8
33 #: authors.py:8
34 msgid "designer"
34 msgid "designer"
35 msgstr "Π΄ΠΈΠ·Π°ΠΉΠ½Π΅Ρ€"
35 msgstr "Π΄ΠΈΠ·Π°ΠΉΠ½Π΅Ρ€"
36
36
37 #: forms.py:23
37 #: forms.py:23
38 msgid ""
38 msgid ""
39 "Type message here. You can reply to message >>123 like\n"
39 "Type message here. You can reply to message >>123 like\n"
40 " this. 2 new lines are required to start new paragraph."
40 " this. 2 new lines are required to start new paragraph."
41 msgstr ""
41 msgstr ""
42 "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ сообщСниС здСсь. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π½Π° сообщСниС >>123 Π²ΠΎΡ‚ Ρ‚Π°ΠΊ. 2 "
42 "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ сообщСниС здСсь. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π½Π° сообщСниС >>123 Π²ΠΎΡ‚ Ρ‚Π°ΠΊ. 2 "
43 "пСрСноса строки ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ для создания Π½ΠΎΠ²ΠΎΠ³ΠΎ Π°Π±Π·Π°Ρ†Π°."
43 "пСрСноса строки ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ для создания Π½ΠΎΠ²ΠΎΠ³ΠΎ Π°Π±Π·Π°Ρ†Π°."
44
44
45 #: forms.py:25
45 #: forms.py:25
46 msgid "tag1 several_words_tag"
46 msgid "tag1 several_words_tag"
47 msgstr "Ρ‚Π΅Π³1 Ρ‚Π΅Π³_ΠΈΠ·_Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ…_слов"
47 msgstr "Ρ‚Π΅Π³1 Ρ‚Π΅Π³_ΠΈΠ·_Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ…_слов"
48
48
49 #: forms.py:27
49 #: forms.py:27
50 msgid "Such image was already posted"
50 msgid "Such image was already posted"
51 msgstr "Π’Π°ΠΊΠΎΠ΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π±Ρ‹Π»ΠΎ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½ΠΎ"
51 msgstr "Π’Π°ΠΊΠΎΠ΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π±Ρ‹Π»ΠΎ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½ΠΎ"
52
52
53 #: forms.py:29
53 #: forms.py:29
54 msgid "Title"
54 msgid "Title"
55 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ"
55 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ"
56
56
57 #: forms.py:30
57 #: forms.py:30
58 msgid "Text"
58 msgid "Text"
59 msgstr "ВСкст"
59 msgstr "ВСкст"
60
60
61 #: forms.py:31
61 #: forms.py:31
62 msgid "Tag"
62 msgid "Tag"
63 msgstr "Π’Π΅Π³"
63 msgstr "Π’Π΅Π³"
64
64
65 #: forms.py:108
65 #: forms.py:108
66 msgid "Image"
66 msgid "Image"
67 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅"
67 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅"
68
68
69 #: forms.py:112
69 #: forms.py:112
70 msgid "e-mail"
70 msgid "e-mail"
71 msgstr ""
71 msgstr ""
72
72
73 #: forms.py:123
73 #: forms.py:123
74 #, python-format
74 #, python-format
75 msgid "Title must have less than %s characters"
75 msgid "Title must have less than %s characters"
76 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅Ρ‚ΡŒ мСньшС %s символов"
76 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅Ρ‚ΡŒ мСньшС %s символов"
77
77
78 #: forms.py:132
78 #: forms.py:132
79 #, python-format
79 #, python-format
80 msgid "Text must have less than %s characters"
80 msgid "Text must have less than %s characters"
81 msgstr "ВСкст Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΠΊΠΎΡ€ΠΎΡ‡Π΅ %s символов"
81 msgstr "ВСкст Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΠΊΠΎΡ€ΠΎΡ‡Π΅ %s символов"
82
82
83 #: forms.py:143
83 #: forms.py:143
84 #, python-format
84 #, python-format
85 msgid "Image must be less than %s bytes"
85 msgid "Image must be less than %s bytes"
86 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ΠΌΠ΅Π½Π΅Π΅ %s Π±Π°ΠΉΡ‚"
86 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ΠΌΠ΅Π½Π΅Π΅ %s Π±Π°ΠΉΡ‚"
87
87
88 #: forms.py:178
88 #: forms.py:178
89 msgid "Either text or image must be entered."
89 msgid "Either text or image must be entered."
90 msgstr "ВСкст ΠΈΠ»ΠΈ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Π²Π²Π΅Π΄Π΅Π½Ρ‹."
90 msgstr "ВСкст ΠΈΠ»ΠΈ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Π²Π²Π΅Π΄Π΅Π½Ρ‹."
91
91
92 #: forms.py:201
92 #: forms.py:201
93 #, python-format
93 #, python-format
94 msgid "Wait %s seconds after last posting"
94 msgid "Wait %s seconds after last posting"
95 msgstr "ΠŸΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ %s сСкунд послС послСднСго постинга"
95 msgstr "ΠŸΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ %s сСкунд послС послСднСго постинга"
96
96
97 #: forms.py:217 templates/boards/tags.html:7 templates/boards/rss/post.html:10
97 #: forms.py:217 templates/boards/tags.html:7 templates/boards/rss/post.html:10
98 msgid "Tags"
98 msgid "Tags"
99 msgstr "Π’Π΅Π³ΠΈ"
99 msgstr "Π’Π΅Π³ΠΈ"
100
100
101 #: forms.py:225 forms.py:344
101 #: forms.py:224 forms.py:343
102 msgid "Inappropriate characters in tags."
102 msgid "Inappropriate characters in tags."
103 msgstr "НСдопустимыС символы Π² Ρ‚Π΅Π³Π°Ρ…."
103 msgstr "НСдопустимыС символы Π² Ρ‚Π΅Π³Π°Ρ…."
104
104
105 #: forms.py:253 forms.py:274
105 #: forms.py:252 forms.py:273
106 msgid "Captcha validation failed"
106 msgid "Captcha validation failed"
107 msgstr "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠ°ΠΏΡ‡ΠΈ ΠΏΡ€ΠΎΠ²Π°Π»Π΅Π½Π°"
107 msgstr "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠ°ΠΏΡ‡ΠΈ ΠΏΡ€ΠΎΠ²Π°Π»Π΅Π½Π°"
108
108
109 #: forms.py:280
109 #: forms.py:279
110 msgid "Theme"
110 msgid "Theme"
111 msgstr "Π’Π΅ΠΌΠ°"
111 msgstr "Π’Π΅ΠΌΠ°"
112
112
113 #: forms.py:285
113 #: forms.py:284
114 msgid "Enable moderation panel"
114 msgid "Enable moderation panel"
115 msgstr "Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ панСль ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ†ΠΈΠΈ"
115 msgstr "Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ панСль ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ†ΠΈΠΈ"
116
116
117 #: forms.py:300
117 #: forms.py:299
118 msgid "No such user found"
118 msgid "No such user found"
119 msgstr "Π”Π°Π½Π½Ρ‹ΠΉ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½"
119 msgstr "Π”Π°Π½Π½Ρ‹ΠΉ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½"
120
120
121 #: forms.py:314
121 #: forms.py:313
122 #, python-format
122 #, python-format
123 msgid "Wait %s minutes after last login"
123 msgid "Wait %s minutes after last login"
124 msgstr "ΠŸΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ %s ΠΌΠΈΠ½ΡƒΡ‚ послС послСднСго Π²Ρ…ΠΎΠ΄Π°"
124 msgstr "ΠŸΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ %s ΠΌΠΈΠ½ΡƒΡ‚ послС послСднСго Π²Ρ…ΠΎΠ΄Π°"
125
125
126 #: templates/boards/404.html:6
126 #: templates/boards/404.html:6
127 msgid "Not found"
127 msgid "Not found"
128 msgstr "НС найдСно"
128 msgstr "НС найдСно"
129
129
130 #: templates/boards/404.html:12
130 #: templates/boards/404.html:12
131 msgid "This page does not exist"
131 msgid "This page does not exist"
132 msgstr "Π­Ρ‚ΠΎΠΉ страницы Π½Π΅ сущСствуСт"
132 msgstr "Π­Ρ‚ΠΎΠΉ страницы Π½Π΅ сущСствуСт"
133
133
134 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
134 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
135 msgid "Authors"
135 msgid "Authors"
136 msgstr "Авторы"
136 msgstr "Авторы"
137
137
138 #: templates/boards/authors.html:26
138 #: templates/boards/authors.html:26
139 msgid "Distributed under the"
139 msgid "Distributed under the"
140 msgstr "РаспространяСтся ΠΏΠΎΠ΄"
140 msgstr "РаспространяСтся ΠΏΠΎΠ΄"
141
141
142 #: templates/boards/authors.html:28
142 #: templates/boards/authors.html:28
143 msgid "license"
143 msgid "license"
144 msgstr "Π»ΠΈΡ†Π΅Π½Π·ΠΈΠ΅ΠΉ"
144 msgstr "Π»ΠΈΡ†Π΅Π½Π·ΠΈΠ΅ΠΉ"
145
145
146 #: templates/boards/authors.html:30
146 #: templates/boards/authors.html:30
147 msgid "Repository"
147 msgid "Repository"
148 msgstr "Π Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ"
148 msgstr "Π Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ"
149
149
150 #: templates/boards/base.html:14
150 #: templates/boards/base.html:11
151 msgid "Feed"
151 msgid "Feed"
152 msgstr "Π›Π΅Π½Ρ‚Π°"
152 msgstr "Π›Π΅Π½Ρ‚Π°"
153
153
154 #: templates/boards/base.html:31
154 #: templates/boards/base.html:28
155 msgid "All threads"
155 msgid "All threads"
156 msgstr "ВсС Ρ‚Π΅ΠΌΡ‹"
156 msgstr "ВсС Ρ‚Π΅ΠΌΡ‹"
157
157
158 #: templates/boards/base.html:36
158 #: templates/boards/base.html:33
159 msgid "Tag management"
159 msgid "Tag management"
160 msgstr "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ‚Π΅Π³Π°ΠΌΠΈ"
160 msgstr "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ‚Π΅Π³Π°ΠΌΠΈ"
161
161
162 #: templates/boards/base.html:38 templates/boards/settings.html:7
162 #: templates/boards/base.html:35 templates/boards/settings.html:7
163 msgid "Settings"
163 msgid "Settings"
164 msgstr "Настройки"
164 msgstr "Настройки"
165
165
166 #: templates/boards/base.html:50 templates/boards/login.html:6
166 #: templates/boards/base.html:47 templates/boards/login.html:6
167 #: templates/boards/login.html.py:21
167 #: templates/boards/login.html.py:16
168 msgid "Login"
168 msgid "Login"
169 msgstr "Π’Ρ…ΠΎΠ΄"
169 msgstr "Π’Ρ…ΠΎΠ΄"
170
170
171 #: templates/boards/base.html:52
171 #: templates/boards/base.html:48
172 msgid "Search"
173 msgstr "Поиск"
174
175 #: templates/boards/base.html:50
172 #, python-format
176 #, python-format
173 msgid "Speed: %(ppd)s posts per day"
177 msgid "Speed: %(ppd)s posts per day"
174 msgstr "Π‘ΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ: %(ppd)s сообщСний Π² дСнь"
178 msgstr "Π‘ΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ: %(ppd)s сообщСний Π² дСнь"
175
179
176 #: templates/boards/base.html:54
180 #: templates/boards/base.html:52
177 msgid "Up"
181 msgid "Up"
178 msgstr "Π’Π²Π΅Ρ€Ρ…"
182 msgstr "Π’Π²Π΅Ρ€Ρ…"
179
183
180 #: templates/boards/login.html:15
184 #: templates/boards/login.html:19
181 msgid "User ID"
182 msgstr "ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ"
183
184 #: templates/boards/login.html:24
185 msgid "Insert your user id above"
185 msgid "Insert your user id above"
186 msgstr "Π’ΡΡ‚Π°Π²ΡŒΡ‚Π΅ свой ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π²Ρ‹ΡˆΠ΅"
186 msgstr "Π’ΡΡ‚Π°Π²ΡŒΡ‚Π΅ свой ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π²Ρ‹ΡˆΠ΅"
187
187
188 #: templates/boards/post.html:21 templates/boards/staticpages/help.html:19
188 #: templates/boards/post.html:21 templates/boards/staticpages/help.html:19
189 msgid "Quote"
189 msgid "Quote"
190 msgstr "Π¦ΠΈΡ‚Π°Ρ‚Π°"
190 msgstr "Π¦ΠΈΡ‚Π°Ρ‚Π°"
191
191
192 #: templates/boards/post.html:31
192 #: templates/boards/post.html:31
193 msgid "Open"
193 msgid "Open"
194 msgstr "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ"
194 msgstr "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ"
195
195
196 #: templates/boards/post.html:33
196 #: templates/boards/post.html:33
197 msgid "Reply"
197 msgid "Reply"
198 msgstr "ΠžΡ‚Π²Π΅Ρ‚"
198 msgstr "ΠžΡ‚Π²Π΅Ρ‚"
199
199
200 #: templates/boards/post.html:40
200 #: templates/boards/post.html:40
201 msgid "Edit"
201 msgid "Edit"
202 msgstr "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ"
202 msgstr "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ"
203
203
204 #: templates/boards/post.html:42
204 #: templates/boards/post.html:42
205 msgid "Delete"
205 msgid "Delete"
206 msgstr "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ"
206 msgstr "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ"
207
207
208 #: templates/boards/post.html:45
208 #: templates/boards/post.html:45
209 msgid "Ban IP"
209 msgid "Ban IP"
210 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ IP"
210 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ IP"
211
211
212 #: templates/boards/post.html:74
212 #: templates/boards/post.html:74
213 msgid "Replies"
213 msgid "Replies"
214 msgstr "ΠžΡ‚Π²Π΅Ρ‚Ρ‹"
214 msgstr "ΠžΡ‚Π²Π΅Ρ‚Ρ‹"
215
215
216 #: templates/boards/post.html:84 templates/boards/thread.html:102
216 #: templates/boards/post.html:84 templates/boards/thread.html:102
217 #: templates/boards/thread_gallery.html:60
217 #: templates/boards/thread_gallery.html:60
218 msgid "images"
218 msgid "images"
219 msgstr "ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ"
219 msgstr "ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ"
220
220
221 #: templates/boards/post_admin.html:19
221 #: templates/boards/post_admin.html:19
222 msgid "Tags:"
222 msgid "Tags:"
223 msgstr "Π’Π΅Π³ΠΈ:"
223 msgstr "Π’Π΅Π³ΠΈ:"
224
224
225 #: templates/boards/post_admin.html:30
225 #: templates/boards/post_admin.html:30
226 msgid "Add tag"
226 msgid "Add tag"
227 msgstr "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ‚Π΅Π³"
227 msgstr "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ‚Π΅Π³"
228
228
229 #: templates/boards/posting_general.html:56
229 #: templates/boards/posting_general.html:56
230 msgid "Show tag"
230 msgid "Show tag"
231 msgstr "ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚Π΅Π³"
231 msgstr "ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚Π΅Π³"
232
232
233 #: templates/boards/posting_general.html:60
233 #: templates/boards/posting_general.html:60
234 msgid "Hide tag"
234 msgid "Hide tag"
235 msgstr "Π‘ΠΊΡ€Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚Π΅Π³"
235 msgstr "Π‘ΠΊΡ€Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚Π΅Π³"
236
236
237 #: templates/boards/posting_general.html:79
237 #: templates/boards/posting_general.html:79
238 msgid "Previous page"
238 msgid "Previous page"
239 msgstr "ΠŸΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π°Ρ страница"
239 msgstr "ΠŸΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π°Ρ страница"
240
240
241 #: templates/boards/posting_general.html:94
241 #: templates/boards/posting_general.html:94
242 #, python-format
242 #, python-format
243 msgid "Skipped %(count)s replies. Open thread to see all replies."
243 msgid "Skipped %(count)s replies. Open thread to see all replies."
244 msgstr "ΠŸΡ€ΠΎΠΏΡƒΡ‰Π΅Π½ΠΎ %(count)s ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ². ΠžΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ Ρ‚Ρ€Π΅Π΄, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ всС ΠΎΡ‚Π²Π΅Ρ‚Ρ‹."
244 msgstr "ΠŸΡ€ΠΎΠΏΡƒΡ‰Π΅Π½ΠΎ %(count)s ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ². ΠžΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ Ρ‚Ρ€Π΅Π΄, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ всС ΠΎΡ‚Π²Π΅Ρ‚Ρ‹."
245
245
246 #: templates/boards/posting_general.html:121
246 #: templates/boards/posting_general.html:121
247 msgid "Next page"
247 msgid "Next page"
248 msgstr "Π‘Π»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ страница"
248 msgstr "Π‘Π»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ страница"
249
249
250 #: templates/boards/posting_general.html:126
250 #: templates/boards/posting_general.html:126
251 msgid "No threads exist. Create the first one!"
251 msgid "No threads exist. Create the first one!"
252 msgstr "НСт Ρ‚Π΅ΠΌ. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π²ΡƒΡŽ!"
252 msgstr "НСт Ρ‚Π΅ΠΌ. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π²ΡƒΡŽ!"
253
253
254 #: templates/boards/posting_general.html:132
254 #: templates/boards/posting_general.html:132
255 msgid "Create new thread"
255 msgid "Create new thread"
256 msgstr "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ‚Π΅ΠΌΡƒ"
256 msgstr "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ‚Π΅ΠΌΡƒ"
257
257
258 #: templates/boards/posting_general.html:137 templates/boards/thread.html:62
258 #: templates/boards/posting_general.html:137 templates/boards/thread.html:62
259 #: templates/boards/thread.html.py:71
259 #: templates/boards/thread.html.py:71
260 msgid "Post"
260 msgid "Post"
261 msgstr "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ"
261 msgstr "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ"
262
262
263 #: templates/boards/posting_general.html:142
263 #: templates/boards/posting_general.html:142
264 msgid "Tags must be delimited by spaces. Text or image is required."
264 msgid "Tags must be delimited by spaces. Text or image is required."
265 msgstr ""
265 msgstr ""
266 "Π’Π΅Π³ΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Ρ‹ ΠΏΡ€ΠΎΠ±Π΅Π»Π°ΠΌΠΈ. ВСкст ΠΈΠ»ΠΈ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹."
266 "Π’Π΅Π³ΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Ρ‹ ΠΏΡ€ΠΎΠ±Π΅Π»Π°ΠΌΠΈ. ВСкст ΠΈΠ»ΠΈ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹."
267
267
268 #: templates/boards/posting_general.html:145 templates/boards/thread.html:79
268 #: templates/boards/posting_general.html:145 templates/boards/thread.html:79
269 msgid "Text syntax"
269 msgid "Text syntax"
270 msgstr "Бинтаксис тСкста"
270 msgstr "Бинтаксис тСкста"
271
271
272 #: templates/boards/posting_general.html:157
272 #: templates/boards/posting_general.html:157
273 msgid "Pages:"
273 msgid "Pages:"
274 msgstr "Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Ρ‹: "
274 msgstr "Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Ρ‹: "
275
275
276 #: templates/boards/settings.html:14
276 #: templates/boards/settings.html:14
277 msgid "User:"
277 msgid "User:"
278 msgstr "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ:"
278 msgstr "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ:"
279
279
280 #: templates/boards/settings.html:16
280 #: templates/boards/settings.html:16
281 msgid "You are moderator."
281 msgid "You are moderator."
282 msgstr "Π’Ρ‹ ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ‚ΠΎΡ€."
282 msgstr "Π’Ρ‹ ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ‚ΠΎΡ€."
283
283
284 #: templates/boards/settings.html:19
284 #: templates/boards/settings.html:19
285 msgid "You are veteran."
285 msgid "You are veteran."
286 msgstr "Π’Ρ‹ Π²Π΅Ρ‚Π΅Ρ€Π°Π½."
286 msgstr "Π’Ρ‹ Π²Π΅Ρ‚Π΅Ρ€Π°Π½."
287
287
288 #: templates/boards/settings.html:22
288 #: templates/boards/settings.html:22
289 msgid "Posts:"
289 msgid "Posts:"
290 msgstr "Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠΉ:"
290 msgstr "Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠΉ:"
291
291
292 #: templates/boards/settings.html:23
292 #: templates/boards/settings.html:23
293 msgid "First access:"
293 msgid "First access:"
294 msgstr "ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ доступ:"
294 msgstr "ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ доступ:"
295
295
296 #: templates/boards/settings.html:25
296 #: templates/boards/settings.html:25
297 msgid "Last access:"
297 msgid "Last access:"
298 msgstr "ПослСдний доступ: "
298 msgstr "ПослСдний доступ: "
299
299
300 #: templates/boards/settings.html:29
300 #: templates/boards/settings.html:29
301 msgid "Hidden tags:"
301 msgid "Hidden tags:"
302 msgstr "Π‘ΠΊΡ€Ρ‹Ρ‚Ρ‹Π΅ Ρ‚Π΅Π³ΠΈ:"
302 msgstr "Π‘ΠΊΡ€Ρ‹Ρ‚Ρ‹Π΅ Ρ‚Π΅Π³ΠΈ:"
303
303
304 #: templates/boards/settings.html:44
304 #: templates/boards/settings.html:44
305 msgid "Save"
305 msgid "Save"
306 msgstr "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ"
306 msgstr "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ"
307
307
308 #: templates/boards/tags.html:22
308 #: templates/boards/tags.html:22
309 msgid "No tags found."
309 msgid "No tags found."
310 msgstr "Π’Π΅Π³ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹."
310 msgstr "Π’Π΅Π³ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹."
311
311
312 #: templates/boards/thread.html:20 templates/boards/thread_gallery.html:21
312 #: templates/boards/thread.html:20 templates/boards/thread_gallery.html:21
313 msgid "Normal mode"
313 msgid "Normal mode"
314 msgstr "ΠΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ"
314 msgstr "ΠΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ"
315
315
316 #: templates/boards/thread.html:21 templates/boards/thread_gallery.html:22
316 #: templates/boards/thread.html:21 templates/boards/thread_gallery.html:22
317 msgid "Gallery mode"
317 msgid "Gallery mode"
318 msgstr "Π Π΅ΠΆΠΈΠΌ Π³Π°Π»Π΅Ρ€Π΅ΠΈ"
318 msgstr "Π Π΅ΠΆΠΈΠΌ Π³Π°Π»Π΅Ρ€Π΅ΠΈ"
319
319
320 #: templates/boards/thread.html:29
320 #: templates/boards/thread.html:29
321 msgid "posts to bumplimit"
321 msgid "posts to bumplimit"
322 msgstr "сообщСний Π΄ΠΎ Π±Π°ΠΌΠΏΠ»ΠΈΠΌΠΈΡ‚Π°"
322 msgstr "сообщСний Π΄ΠΎ Π±Π°ΠΌΠΏΠ»ΠΈΠΌΠΈΡ‚Π°"
323
323
324 #: templates/boards/thread.html:50
324 #: templates/boards/thread.html:50
325 msgid "Reply to thread"
325 msgid "Reply to thread"
326 msgstr "ΠžΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π² Ρ‚Π΅ΠΌΡƒ"
326 msgstr "ΠžΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π² Ρ‚Π΅ΠΌΡƒ"
327
327
328 #: templates/boards/thread.html:76
328 #: templates/boards/thread.html:76
329 msgid "Switch mode"
329 msgid "Switch mode"
330 msgstr "ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ€Π΅ΠΆΠΈΠΌ"
330 msgstr "ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ€Π΅ΠΆΠΈΠΌ"
331
331
332 #: templates/boards/thread.html:101 templates/boards/thread_gallery.html:59
332 #: templates/boards/thread.html:101 templates/boards/thread_gallery.html:59
333 msgid "replies"
333 msgid "replies"
334 msgstr "ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ²"
334 msgstr "ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ²"
335
335
336 #: templates/boards/thread.html:103 templates/boards/thread_gallery.html:61
336 #: templates/boards/thread.html:103 templates/boards/thread_gallery.html:61
337 msgid "Last update: "
337 msgid "Last update: "
338 msgstr "ПослСднСС обновлСниС: "
338 msgstr "ПослСднСС обновлСниС: "
339
339
340 #: templates/boards/rss/post.html:5
340 #: templates/boards/rss/post.html:5
341 msgid "Post image"
341 msgid "Post image"
342 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ сообщСния"
342 msgstr "Π˜Π·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ сообщСния"
343
343
344 #: templates/boards/staticpages/banned.html:6
344 #: templates/boards/staticpages/banned.html:6
345 msgid "Banned"
345 msgid "Banned"
346 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½"
346 msgstr "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½"
347
347
348 #: templates/boards/staticpages/banned.html:11
348 #: templates/boards/staticpages/banned.html:11
349 msgid "Your IP address has been banned. Contact the administrator"
349 msgid "Your IP address has been banned. Contact the administrator"
350 msgstr "Π’Π°Ρˆ IP адрСс Π±Ρ‹Π» Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½. Π‘Π²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с администратором"
350 msgstr "Π’Π°Ρˆ IP адрСс Π±Ρ‹Π» Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½. Π‘Π²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с администратором"
351
351
352 #: templates/boards/staticpages/help.html:6
352 #: templates/boards/staticpages/help.html:6
353 #: templates/boards/staticpages/help.html:10
353 #: templates/boards/staticpages/help.html:10
354 msgid "Syntax"
354 msgid "Syntax"
355 msgstr "Бинтаксис"
355 msgstr "Бинтаксис"
356
356
357 #: templates/boards/staticpages/help.html:11
357 #: templates/boards/staticpages/help.html:11
358 msgid "2 line breaks for a new line."
358 msgid "2 line breaks for a new line."
359 msgstr "2 ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π° строки ΡΠΎΠ·Π΄Π°ΡŽΡ‚ Π½ΠΎΠ²Ρ‹ΠΉ Π°Π±Π·Π°Ρ†."
359 msgstr "2 ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π° строки ΡΠΎΠ·Π΄Π°ΡŽΡ‚ Π½ΠΎΠ²Ρ‹ΠΉ Π°Π±Π·Π°Ρ†."
360
360
361 #: templates/boards/staticpages/help.html:12
361 #: templates/boards/staticpages/help.html:12
362 msgid "Italic text"
362 msgid "Italic text"
363 msgstr "ΠšΡƒΡ€ΡΠΈΠ²Π½Ρ‹ΠΉ тСкст"
363 msgstr "ΠšΡƒΡ€ΡΠΈΠ²Π½Ρ‹ΠΉ тСкст"
364
364
365 #: templates/boards/staticpages/help.html:13
365 #: templates/boards/staticpages/help.html:13
366 msgid "Bold text"
366 msgid "Bold text"
367 msgstr "ΠŸΠΎΠ»ΡƒΠΆΠΈΡ€Π½Ρ‹ΠΉ тСкст"
367 msgstr "ΠŸΠΎΠ»ΡƒΠΆΠΈΡ€Π½Ρ‹ΠΉ тСкст"
368
368
369 #: templates/boards/staticpages/help.html:14
369 #: templates/boards/staticpages/help.html:14
370 msgid "Spoiler"
370 msgid "Spoiler"
371 msgstr "Π‘ΠΏΠΎΠΉΠ»Π΅Ρ€"
371 msgstr "Π‘ΠΏΠΎΠΉΠ»Π΅Ρ€"
372
372
373 #: templates/boards/staticpages/help.html:15
373 #: templates/boards/staticpages/help.html:15
374 msgid "Link to a post"
374 msgid "Link to a post"
375 msgstr "Бсылка Π½Π° сообщСниС"
375 msgstr "Бсылка Π½Π° сообщСниС"
376
376
377 #: templates/boards/staticpages/help.html:16
377 #: templates/boards/staticpages/help.html:16
378 msgid "Strikethrough text"
378 msgid "Strikethrough text"
379 msgstr "Π—Π°Ρ‡Π΅Ρ€ΠΊΠ½ΡƒΡ‚Ρ‹ΠΉ тСкст"
379 msgstr "Π—Π°Ρ‡Π΅Ρ€ΠΊΠ½ΡƒΡ‚Ρ‹ΠΉ тСкст"
380
380
381 #: templates/boards/staticpages/help.html:17
381 #: templates/boards/staticpages/help.html:17
382 msgid "You need to new line before:"
382 msgid "You need to new line before:"
383 msgstr "ΠŸΠ΅Ρ€Π΅Π΄ этими Ρ‚Π΅Π³Π°ΠΌΠΈ Π½ΡƒΠΆΠ½Π° новая строка:"
383 msgstr "ΠŸΠ΅Ρ€Π΅Π΄ этими Ρ‚Π΅Π³Π°ΠΌΠΈ Π½ΡƒΠΆΠ½Π° новая строка:"
384
384
385 #: templates/boards/staticpages/help.html:18
385 #: templates/boards/staticpages/help.html:18
386 msgid "Comment"
386 msgid "Comment"
387 msgstr "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ"
387 msgstr "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ"
388
388
389 #~ msgid "Archive"
389 #~ msgid "User ID"
390 #~ msgstr "Архив"
390 #~ msgstr "ID ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ"
@@ -1,41 +1,42 b''
1 from django.shortcuts import redirect
1 from django.shortcuts import redirect
2 from boards import views, utils
2 from boards import utils
3 from boards.models import Ban
3 from boards.models import Ban
4 from django.utils.html import strip_spaces_between_tags
4 from django.utils.html import strip_spaces_between_tags
5 from django.conf import settings
5 from django.conf import settings
6 from boards.views.banned import BannedView
6
7
7 RESPONSE_CONTENT_TYPE = 'Content-Type'
8 RESPONSE_CONTENT_TYPE = 'Content-Type'
8
9
9 TYPE_HTML = 'text/html'
10 TYPE_HTML = 'text/html'
10
11
11
12
12 class BanMiddleware:
13 class BanMiddleware:
13 """
14 """
14 This is run before showing the thread. Banned users don't need to see
15 This is run before showing the thread. Banned users don't need to see
15 anything
16 anything
16 """
17 """
17
18
18 def process_view(self, request, view_func, view_args, view_kwargs):
19 def process_view(self, request, view_func, view_args, view_kwargs):
19
20
20 if view_func != views.banned.BannedView.as_view:
21 if view_func != BannedView.as_view:
21 ip = utils.get_client_ip(request)
22 ip = utils.get_client_ip(request)
22 bans = Ban.objects.filter(ip=ip)
23 bans = Ban.objects.filter(ip=ip)
23
24
24 if bans.exists():
25 if bans.exists():
25 ban = bans[0]
26 ban = bans[0]
26 if not ban.can_read:
27 if not ban.can_read:
27 return redirect('banned')
28 return redirect('banned')
28
29
29
30
30 class MinifyHTMLMiddleware(object):
31 class MinifyHTMLMiddleware(object):
31 def process_response(self, request, response):
32 def process_response(self, request, response):
32 try:
33 try:
33 compress_html = settings.COMPRESS_HTML
34 compress_html = settings.COMPRESS_HTML
34 except AttributeError:
35 except AttributeError:
35 compress_html = False
36 compress_html = False
36
37
37 if RESPONSE_CONTENT_TYPE in response\
38 if RESPONSE_CONTENT_TYPE in response\
38 and TYPE_HTML in response[RESPONSE_CONTENT_TYPE] and compress_html:
39 and TYPE_HTML in response[RESPONSE_CONTENT_TYPE] and compress_html:
39 response.content = strip_spaces_between_tags(
40 response.content = strip_spaces_between_tags(
40 response.content.strip())
41 response.content.strip())
41 return response No newline at end of file
42 return response
@@ -1,62 +1,60 b''
1 {% load staticfiles %}
1 {% load staticfiles %}
2 {% load i18n %}
2 {% load i18n %}
3 {% load l10n %}
3 {% load l10n %}
4 {% load static from staticfiles %}
4 {% load static from staticfiles %}
5
5
6 <!DOCTYPE html>
6 <!DOCTYPE html>
7 <html>
7 <html>
8 <head>
8 <head>
9 <link rel="stylesheet" type="text/css"
9 <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}" media="all"/>
10 href="{% static 'css/base.css' %}" media="all"/>
10 <link rel="stylesheet" type="text/css" href="{% static theme_css %}" media="all"/>
11 <link rel="stylesheet" type="text/css"
11 <link rel="alternate" type="application/rss+xml" href="rss/" title="{% trans 'Feed' %}"/>
12 href="{% static theme_css %}" media="all"/>
13 <link rel="alternate" type="application/rss+xml" href="rss/" title=
14 "{% trans 'Feed' %}"/>
15
12
16 <link rel="icon" type="image/png"
13 <link rel="icon" type="image/png"
17 href="{% static 'favicon.png' %}">
14 href="{% static 'favicon.png' %}">
18
15
19 <meta name="viewport" content="width=device-width, initial-scale=1"/>
16 <meta name="viewport" content="width=device-width, initial-scale=1"/>
20 <meta charset="utf-8"/>
17 <meta charset="utf-8"/>
21
18
22 {% block head %}{% endblock %}
19 {% block head %}{% endblock %}
23 </head>
20 </head>
24 <body>
21 <body>
25 <script src="{% static 'js/jquery-2.0.1.min.js' %}"></script>
22 <script src="{% static 'js/jquery-2.0.1.min.js' %}"></script>
26 <script src="{% static 'js/jquery-ui-1.10.3.custom.min.js' %}"></script>
23 <script src="{% static 'js/jquery-ui-1.10.3.custom.min.js' %}"></script>
27 <script src="{% static 'js/jquery.mousewheel.js' %}"></script>
24 <script src="{% static 'js/jquery.mousewheel.js' %}"></script>
28 <script src="{% url 'js_info_dict' %}"></script>
25 <script src="{% url 'js_info_dict' %}"></script>
29
26
30 <div class="navigation_panel">
27 <div class="navigation_panel">
31 <a class="link" href="{% url 'index' %}">{% trans "All threads" %}</a>
28 <a class="link" href="{% url 'index' %}">{% trans "All threads" %}</a>
32 {% for tag in tags %}
29 {% for tag in tags %}
33 <a class="tag" href="{% url 'tag' tag_name=tag.name %}"
30 <a class="tag" href="{% url 'tag' tag_name=tag.name %}"
34 >#{{ tag.name }}</a>,
31 >#{{ tag.name }}</a>,
35 {% endfor %}
32 {% endfor %}
36 <a href="{% url 'tags' %}" title="{% trans 'Tag management' %}"
33 <a href="{% url 'tags' %}" title="{% trans 'Tag management' %}"
37 >[...]</a>
34 >[...]</a>
38 <a class="link" href="{% url 'settings' %}">{% trans 'Settings' %}</a>
35 <a class="link" href="{% url 'settings' %}">{% trans 'Settings' %}</a>
39 </div>
36 </div>
40
37
41 {% block content %}{% endblock %}
38 {% block content %}{% endblock %}
42
39
43 <script src="{% static 'js/popup.js' %}"></script>
40 <script src="{% static 'js/popup.js' %}"></script>
44 <script src="{% static 'js/image.js' %}"></script>
41 <script src="{% static 'js/image.js' %}"></script>
45 <script src="{% static 'js/refpopup.js' %}"></script>
42 <script src="{% static 'js/refpopup.js' %}"></script>
46 <script src="{% static 'js/main.js' %}"></script>
43 <script src="{% static 'js/main.js' %}"></script>
47
44
48 <div class="navigation_panel">
45 <div class="navigation_panel">
49 {% block metapanel %}{% endblock %}
46 {% block metapanel %}{% endblock %}
50 [<a href="{% url "login" %}">{% trans 'Login' %}</a>]
47 [<a href="{% url "login" %}">{% trans 'Login' %}</a>]
48 [<a href="{% url "haystack_search" %}">{% trans 'Search' %}</a>]
51 {% with ppd=posts_per_day|floatformat:2 %}
49 {% with ppd=posts_per_day|floatformat:2 %}
52 {% blocktrans %}Speed: {{ ppd }} posts per day{% endblocktrans %}
50 {% blocktrans %}Speed: {{ ppd }} posts per day{% endblocktrans %}
53 {% endwith %}
51 {% endwith %}
54 <a class="link" href="#top">{% trans 'Up' %}</a>
52 <a class="link" href="#top">{% trans 'Up' %}</a>
55 </div>
53 </div>
56
54
57 <div class="footer">
55 <div class="footer">
58 <!-- Put your banners here -->
56 <!-- Put your banners here -->
59 </div>
57 </div>
60
58
61 </body>
59 </body>
62 </html>
60 </html>
@@ -1,81 +1,84 b''
1 from django.conf.urls import patterns, url, include
1 from django.conf.urls import patterns, url, include
2 from boards import views
2 from boards import views
3 from boards.rss import AllThreadsFeed, TagThreadsFeed, ThreadPostsFeed
3 from boards.rss import AllThreadsFeed, TagThreadsFeed, ThreadPostsFeed
4 from boards.views import api, tag_threads, all_threads, \
4 from boards.views import api, tag_threads, all_threads, \
5 login, settings, all_tags
5 login, settings, all_tags
6 from boards.views.authors import AuthorsView
6 from boards.views.authors import AuthorsView
7 from boards.views.delete_post import DeletePostView
7 from boards.views.delete_post import DeletePostView
8 from boards.views.ban import BanUserView
8 from boards.views.ban import BanUserView
9 from boards.views.static import StaticPageView
9 from boards.views.static import StaticPageView
10 from boards.views.post_admin import PostAdminView
10 from boards.views.post_admin import PostAdminView
11
11
12 js_info_dict = {
12 js_info_dict = {
13 'packages': ('boards',),
13 'packages': ('boards',),
14 }
14 }
15
15
16 urlpatterns = patterns('',
16 urlpatterns = patterns('',
17
17
18 # /boards/
18 # /boards/
19 url(r'^$', all_threads.AllThreadsView.as_view(), name='index'),
19 url(r'^$', all_threads.AllThreadsView.as_view(), name='index'),
20 # /boards/page/
20 # /boards/page/
21 url(r'^page/(?P<page>\w+)/$', all_threads.AllThreadsView.as_view(),
21 url(r'^page/(?P<page>\w+)/$', all_threads.AllThreadsView.as_view(),
22 name='index'),
22 name='index'),
23
23
24 # login page
24 # login page
25 url(r'^login/$', login.LoginView.as_view(), name='login'),
25 url(r'^login/$', login.LoginView.as_view(), name='login'),
26
26
27 # /boards/tag/tag_name/
27 # /boards/tag/tag_name/
28 url(r'^tag/(?P<tag_name>\w+)/$', tag_threads.TagView.as_view(),
28 url(r'^tag/(?P<tag_name>\w+)/$', tag_threads.TagView.as_view(),
29 name='tag'),
29 name='tag'),
30 # /boards/tag/tag_id/page/
30 # /boards/tag/tag_id/page/
31 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/$',
31 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/$',
32 tag_threads.TagView.as_view(), name='tag'),
32 tag_threads.TagView.as_view(), name='tag'),
33
33
34 # /boards/thread/
34 # /boards/thread/
35 url(r'^thread/(?P<post_id>\w+)/$', views.thread.ThreadView.as_view(),
35 url(r'^thread/(?P<post_id>\w+)/$', views.thread.ThreadView.as_view(),
36 name='thread'),
36 name='thread'),
37 url(r'^thread/(?P<post_id>\w+)/mode/(?P<mode>\w+)/$', views.thread.ThreadView
37 url(r'^thread/(?P<post_id>\w+)/mode/(?P<mode>\w+)/$', views.thread.ThreadView
38 .as_view(), name='thread_mode'),
38 .as_view(), name='thread_mode'),
39
39
40 # /boards/post_admin/
40 # /boards/post_admin/
41 url(r'^post_admin/(?P<post_id>\w+)/$', PostAdminView.as_view(),
41 url(r'^post_admin/(?P<post_id>\w+)/$', PostAdminView.as_view(),
42 name='post_admin'),
42 name='post_admin'),
43
43
44 url(r'^settings/$', settings.SettingsView.as_view(), name='settings'),
44 url(r'^settings/$', settings.SettingsView.as_view(), name='settings'),
45 url(r'^tags/$', all_tags.AllTagsView.as_view(), name='tags'),
45 url(r'^tags/$', all_tags.AllTagsView.as_view(), name='tags'),
46 url(r'^captcha/', include('captcha.urls')),
46 url(r'^captcha/', include('captcha.urls')),
47 url(r'^authors/$', AuthorsView.as_view(), name='authors'),
47 url(r'^authors/$', AuthorsView.as_view(), name='authors'),
48 url(r'^delete/(?P<post_id>\w+)/$', DeletePostView.as_view(),
48 url(r'^delete/(?P<post_id>\w+)/$', DeletePostView.as_view(),
49 name='delete'),
49 name='delete'),
50 url(r'^ban/(?P<post_id>\w+)/$', BanUserView.as_view(), name='ban'),
50 url(r'^ban/(?P<post_id>\w+)/$', BanUserView.as_view(), name='ban'),
51
51
52 url(r'^banned/$', views.banned.BannedView.as_view(), name='banned'),
52 url(r'^banned/$', views.banned.BannedView.as_view(), name='banned'),
53 url(r'^staticpage/(?P<name>\w+)/$', StaticPageView.as_view(),
53 url(r'^staticpage/(?P<name>\w+)/$', StaticPageView.as_view(),
54 name='staticpage'),
54 name='staticpage'),
55
55
56 # RSS feeds
56 # RSS feeds
57 url(r'^rss/$', AllThreadsFeed()),
57 url(r'^rss/$', AllThreadsFeed()),
58 url(r'^page/(?P<page>\w+)/rss/$', AllThreadsFeed()),
58 url(r'^page/(?P<page>\w+)/rss/$', AllThreadsFeed()),
59 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
59 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
60 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
60 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
61 url(r'^thread/(?P<post_id>\w+)/rss/$', ThreadPostsFeed()),
61 url(r'^thread/(?P<post_id>\w+)/rss/$', ThreadPostsFeed()),
62
62
63 # i18n
63 # i18n
64 url(r'^jsi18n/$', 'boards.views.cached_js_catalog', js_info_dict,
64 url(r'^jsi18n/$', 'boards.views.cached_js_catalog', js_info_dict,
65 name='js_info_dict'),
65 name='js_info_dict'),
66
66
67 # API
67 # API
68 url(r'^api/post/(?P<post_id>\w+)/$', api.get_post, name="get_post"),
68 url(r'^api/post/(?P<post_id>\w+)/$', api.get_post, name="get_post"),
69 url(r'^api/diff_thread/(?P<thread_id>\w+)/(?P<last_update_time>\w+)/$',
69 url(r'^api/diff_thread/(?P<thread_id>\w+)/(?P<last_update_time>\w+)/$',
70 api.api_get_threaddiff, name="get_thread_diff"),
70 api.api_get_threaddiff, name="get_thread_diff"),
71 url(r'^api/threads/(?P<count>\w+)/$', api.api_get_threads,
71 url(r'^api/threads/(?P<count>\w+)/$', api.api_get_threads,
72 name='get_threads'),
72 name='get_threads'),
73 url(r'^api/tags/$', api.api_get_tags, name='get_tags'),
73 url(r'^api/tags/$', api.api_get_tags, name='get_tags'),
74 url(r'^api/thread/(?P<opening_post_id>\w+)/$', api.api_get_thread_posts,
74 url(r'^api/thread/(?P<opening_post_id>\w+)/$', api.api_get_thread_posts,
75 name='get_thread'),
75 name='get_thread'),
76 url(r'^api/add_post/(?P<opening_post_id>\w+)/$', api.api_add_post,
76 url(r'^api/add_post/(?P<opening_post_id>\w+)/$', api.api_add_post,
77 name='add_post'),
77 name='add_post'),
78 url(r'api/get_tag_popularity/(?P<tag_name>\w+)$', api.get_tag_popularity,
78 url(r'^api/get_tag_popularity/(?P<tag_name>\w+)$', api.get_tag_popularity,
79 name='get_tag_popularity'),
79 name='get_tag_popularity'),
80
80
81 # Search
82 url(r'^search/', include('haystack.urls')),
83
81 )
84 )
@@ -1,80 +1,129 b''
1 """
1 """
2 This module contains helper functions and helper classes.
2 This module contains helper functions and helper classes.
3 """
3 """
4 import hashlib
4 from django.utils import timezone
5 from django.utils import timezone
5
6
6 from neboard import settings
7 from neboard import settings
8 from boards.models import Post, User
9 from boards.models.post import SETTING_MODERATE
10 from boards.models.user import RANK_USER
7 import time
11 import time
12 import neboard
8
13
9
14
10 KEY_CAPTCHA_FAILS = 'key_captcha_fails'
15 KEY_CAPTCHA_FAILS = 'key_captcha_fails'
11 KEY_CAPTCHA_DELAY_TIME = 'key_captcha_delay_time'
16 KEY_CAPTCHA_DELAY_TIME = 'key_captcha_delay_time'
12 KEY_CAPTCHA_LAST_ACTIVITY = 'key_captcha_last_activity'
17 KEY_CAPTCHA_LAST_ACTIVITY = 'key_captcha_last_activity'
13
18
14
19
15 def need_include_captcha(request):
20 def need_include_captcha(request):
16 """
21 """
17 Check if request is made by a user.
22 Check if request is made by a user.
18 It contains rules which check for bots.
23 It contains rules which check for bots.
19 """
24 """
20
25
21 if not settings.ENABLE_CAPTCHA:
26 if not settings.ENABLE_CAPTCHA:
22 return False
27 return False
23
28
24 enable_captcha = False
29 enable_captcha = False
25
30
26 #newcomer
31 #newcomer
27 if KEY_CAPTCHA_LAST_ACTIVITY not in request.session:
32 if KEY_CAPTCHA_LAST_ACTIVITY not in request.session:
28 return settings.ENABLE_CAPTCHA
33 return settings.ENABLE_CAPTCHA
29
34
30 last_activity = request.session[KEY_CAPTCHA_LAST_ACTIVITY]
35 last_activity = request.session[KEY_CAPTCHA_LAST_ACTIVITY]
31 current_delay = int(time.time()) - last_activity
36 current_delay = int(time.time()) - last_activity
32
37
33 delay_time = (request.session[KEY_CAPTCHA_DELAY_TIME]
38 delay_time = (request.session[KEY_CAPTCHA_DELAY_TIME]
34 if KEY_CAPTCHA_DELAY_TIME in request.session
39 if KEY_CAPTCHA_DELAY_TIME in request.session
35 else settings.CAPTCHA_DEFAULT_SAFE_TIME)
40 else settings.CAPTCHA_DEFAULT_SAFE_TIME)
36
41
37 if current_delay < delay_time:
42 if current_delay < delay_time:
38 enable_captcha = True
43 enable_captcha = True
39
44
40 print 'ENABLING' + str(enable_captcha)
45 print 'ENABLING' + str(enable_captcha)
41
46
42 return enable_captcha
47 return enable_captcha
43
48
44
49
45 def update_captcha_access(request, passed):
50 def update_captcha_access(request, passed):
46 """
51 """
47 Update captcha fields.
52 Update captcha fields.
48 It will reduce delay time if user passed captcha verification and
53 It will reduce delay time if user passed captcha verification and
49 it will increase it otherwise.
54 it will increase it otherwise.
50 """
55 """
51 session = request.session
56 session = request.session
52
57
53 delay_time = (request.session[KEY_CAPTCHA_DELAY_TIME]
58 delay_time = (request.session[KEY_CAPTCHA_DELAY_TIME]
54 if KEY_CAPTCHA_DELAY_TIME in request.session
59 if KEY_CAPTCHA_DELAY_TIME in request.session
55 else settings.CAPTCHA_DEFAULT_SAFE_TIME)
60 else settings.CAPTCHA_DEFAULT_SAFE_TIME)
56
61
57 print "DELAY TIME = " + str(delay_time)
62 print "DELAY TIME = " + str(delay_time)
58
63
59 if passed:
64 if passed:
60 delay_time -= 2 if delay_time >= 7 else 5
65 delay_time -= 2 if delay_time >= 7 else 5
61 else:
66 else:
62 delay_time += 10
67 delay_time += 10
63
68
64 session[KEY_CAPTCHA_LAST_ACTIVITY] = int(time.time())
69 session[KEY_CAPTCHA_LAST_ACTIVITY] = int(time.time())
65 session[KEY_CAPTCHA_DELAY_TIME] = delay_time
70 session[KEY_CAPTCHA_DELAY_TIME] = delay_time
66
71
67
72
68 def get_client_ip(request):
73 def get_client_ip(request):
69 x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
74 x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
70 if x_forwarded_for:
75 if x_forwarded_for:
71 ip = x_forwarded_for.split(',')[-1].strip()
76 ip = x_forwarded_for.split(',')[-1].strip()
72 else:
77 else:
73 ip = request.META.get('REMOTE_ADDR')
78 ip = request.META.get('REMOTE_ADDR')
74 return ip
79 return ip
75
80
76
81
77 def datetime_to_epoch(datetime):
82 def datetime_to_epoch(datetime):
78 return int(time.mktime(timezone.localtime(
83 return int(time.mktime(timezone.localtime(
79 datetime,timezone.get_current_timezone()).timetuple())
84 datetime,timezone.get_current_timezone()).timetuple())
80 * 1000000 + datetime.microsecond) No newline at end of file
85 * 1000000 + datetime.microsecond)
86
87
88 def get_user(request):
89 """
90 Get current user from the session. If the user does not exist, create
91 a new one.
92 """
93
94 session = request.session
95 if not 'user_id' in session:
96 request.session.save()
97
98 md5 = hashlib.md5()
99 md5.update(session.session_key)
100 new_id = md5.hexdigest()
101
102 while User.objects.filter(user_id=new_id).exists():
103 md5.update(str(timezone.now()))
104 new_id = md5.hexdigest()
105
106 time_now = timezone.now()
107 user = User.objects.create(user_id=new_id, rank=RANK_USER,
108 registration_time=time_now)
109
110 session['user_id'] = user.id
111 else:
112 user = User.objects.select_related('fav_tags').get(
113 id=session['user_id'])
114
115 return user
116
117
118 def get_theme(request, user=None):
119 """
120 Get user's CSS theme
121 """
122
123 if not user:
124 user = get_user(request)
125 theme = user.get_setting('theme')
126 if not theme:
127 theme = neboard.settings.DEFAULT_THEME
128
129 return theme No newline at end of file
@@ -1,12 +1,13 b''
1 from django.shortcuts import render
1 from django.shortcuts import render
2
2
3 from boards.views.base import BaseBoardView
3 from boards.views.base import BaseBoardView
4 from boards.models.tag import Tag
4 from boards.models.tag import Tag
5
5
6
6 class AllTagsView(BaseBoardView):
7 class AllTagsView(BaseBoardView):
7
8
8 def get(self, request):
9 def get(self, request):
9 context = self.get_context_data(request=request)
10 context = self.get_context_data(request=request)
10 context['all_tags'] = Tag.objects.get_not_empty_tags()
11 context['all_tags'] = Tag.objects.get_not_empty_tags()
11
12
12 return render(request, 'boards/tags.html', context)
13 return render(request, 'boards/tags.html', context)
@@ -1,134 +1,134 b''
1 import string
1 import string
2
2
3 from django.core.urlresolvers import reverse
4 from django.db import transaction
3 from django.db import transaction
5 from django.shortcuts import render, redirect
4 from django.shortcuts import render, redirect
6
5
7 from boards import utils
6 from boards import utils
8 from boards.abstracts.paginator import get_paginator
7 from boards.abstracts.paginator import get_paginator
9 from boards.forms import ThreadForm, PlainErrorList
8 from boards.forms import ThreadForm, PlainErrorList
10 from boards.models import Post, Thread, Ban, Tag
9 from boards.models import Post, Thread, Ban, Tag
11 from boards.views.banned import BannedView
10 from boards.views.banned import BannedView
12 from boards.views.base import BaseBoardView, PARAMETER_FORM
11 from boards.views.base import BaseBoardView, PARAMETER_FORM
13 from boards.views.posting_mixin import PostMixin
12 from boards.views.posting_mixin import PostMixin
14 import neboard
13 import neboard
15
14
16 TAG_DELIMITER = ' '
15 TAG_DELIMITER = ' '
17
16
18 PARAMETER_CURRENT_PAGE = 'current_page'
17 PARAMETER_CURRENT_PAGE = 'current_page'
19 PARAMETER_PAGINATOR = 'paginator'
18 PARAMETER_PAGINATOR = 'paginator'
20 PARAMETER_THREADS = 'threads'
19 PARAMETER_THREADS = 'threads'
21
20
22 TEMPLATE = 'boards/posting_general.html'
21 TEMPLATE = 'boards/posting_general.html'
23 DEFAULT_PAGE = 1
22 DEFAULT_PAGE = 1
24
23
25
24
26 class AllThreadsView(PostMixin, BaseBoardView):
25 class AllThreadsView(PostMixin, BaseBoardView):
27
26
28 user = None
27 user = None
29
28
30 def get(self, request, page=DEFAULT_PAGE, form=None):
29 def get(self, request, page=DEFAULT_PAGE, form=None):
31 context = self.get_context_data(request=request)
30 context = self.get_context_data(request=request)
32
31
33 self.user = context['user']
32 self.user = utils.get_user(request)
34
33
35 if not form:
34 if not form:
36 form = ThreadForm(error_class=PlainErrorList)
35 form = ThreadForm(error_class=PlainErrorList)
37
36
38 paginator = get_paginator(self.get_threads(),
37 paginator = get_paginator(self.get_threads(),
39 neboard.settings.THREADS_PER_PAGE)
38 neboard.settings.THREADS_PER_PAGE)
40 paginator.current_page = int(page)
39 paginator.current_page = int(page)
41
40
42 threads = paginator.page(page).object_list
41 threads = paginator.page(page).object_list
43
42
44 context[PARAMETER_THREADS] = threads
43 context[PARAMETER_THREADS] = threads
45 context[PARAMETER_FORM] = form
44 context[PARAMETER_FORM] = form
46
45
47 self._get_page_context(paginator, context, page)
46 self._get_page_context(paginator, context, page)
48
47
49 return render(request, TEMPLATE, context)
48 return render(request, TEMPLATE, context)
50
49
51 def post(self, request, page=DEFAULT_PAGE):
50 def post(self, request, page=DEFAULT_PAGE):
52 form = ThreadForm(request.POST, request.FILES,
51 form = ThreadForm(request.POST, request.FILES,
53 error_class=PlainErrorList)
52 error_class=PlainErrorList)
54 form.session = request.session
53 form.session = request.session
55
54
56 if form.is_valid():
55 if form.is_valid():
57 return self.create_thread(request, form)
56 return self.create_thread(request, form)
58 if form.need_to_ban:
57 if form.need_to_ban:
59 # Ban user because he is suspected to be a bot
58 # Ban user because he is suspected to be a bot
60 self._ban_current_user(request)
59 self._ban_current_user(request)
61
60
62 return self.get(request, page, form)
61 return self.get(request, page, form)
63
62
64 @staticmethod
63 @staticmethod
65 def _get_page_context(paginator, context, page):
64 def _get_page_context(paginator, context, page):
66 """
65 """
67 Get pagination context variables
66 Get pagination context variables
68 """
67 """
69
68
70 context[PARAMETER_PAGINATOR] = paginator
69 context[PARAMETER_PAGINATOR] = paginator
71 context[PARAMETER_CURRENT_PAGE] = paginator.page(int(page))
70 context[PARAMETER_CURRENT_PAGE] = paginator.page(int(page))
72
71
73 def parse_tags_string(self, tag_strings):
72 @staticmethod
73 def parse_tags_string(tag_strings):
74 """
74 """
75 Parses tag list string and returns tag object list.
75 Parses tag list string and returns tag object list.
76 """
76 """
77
77
78 tags = []
78 tags = []
79
79
80 if tag_strings:
80 if tag_strings:
81 tag_strings = tag_strings.split(TAG_DELIMITER)
81 tag_strings = tag_strings.split(TAG_DELIMITER)
82 for tag_name in tag_strings:
82 for tag_name in tag_strings:
83 tag_name = string.lower(tag_name.strip())
83 tag_name = string.lower(tag_name.strip())
84 if len(tag_name) > 0:
84 if len(tag_name) > 0:
85 tag, created = Tag.objects.get_or_create(name=tag_name)
85 tag, created = Tag.objects.get_or_create(name=tag_name)
86 tags.append(tag)
86 tags.append(tag)
87
87
88 return tags
88 return tags
89
89
90 @transaction.atomic
90 @transaction.atomic
91 def create_thread(self, request, form, html_response=True):
91 def create_thread(self, request, form, html_response=True):
92 """
92 """
93 Creates a new thread with an opening post.
93 Creates a new thread with an opening post.
94 """
94 """
95
95
96 ip = utils.get_client_ip(request)
96 ip = utils.get_client_ip(request)
97 is_banned = Ban.objects.filter(ip=ip).exists()
97 is_banned = Ban.objects.filter(ip=ip).exists()
98
98
99 if is_banned:
99 if is_banned:
100 if html_response:
100 if html_response:
101 return redirect(BannedView().as_view())
101 return redirect(BannedView().as_view())
102 else:
102 else:
103 return
103 return
104
104
105 data = form.cleaned_data
105 data = form.cleaned_data
106
106
107 title = data['title']
107 title = data['title']
108 text = data['text']
108 text = data['text']
109
109
110 text = self._remove_invalid_links(text)
110 text = self._remove_invalid_links(text)
111
111
112 if 'image' in data.keys():
112 if 'image' in data.keys():
113 image = data['image']
113 image = data['image']
114 else:
114 else:
115 image = None
115 image = None
116
116
117 tag_strings = data['tags']
117 tag_strings = data['tags']
118
118
119 tags = self.parse_tags_string(tag_strings)
119 tags = self.parse_tags_string(tag_strings)
120
120
121 post = Post.objects.create_post(title=title, text=text, ip=ip,
121 post = Post.objects.create_post(title=title, text=text, ip=ip,
122 image=image, tags=tags,
122 image=image, tags=tags,
123 user=self._get_user(request))
123 user=utils.get_user(request))
124
124
125 if html_response:
125 if html_response:
126 return redirect(post.get_url())
126 return redirect(post.get_url())
127
127
128 def get_threads(self):
128 def get_threads(self):
129 """
129 """
130 Gets list of threads that will be shown on a page.
130 Gets list of threads that will be shown on a page.
131 """
131 """
132
132
133 return Thread.objects.all().order_by('-bump_time')\
133 return Thread.objects.all().order_by('-bump_time')\
134 .exclude(tags__in=self.user.hidden_tags.all())
134 .exclude(tags__in=self.user.hidden_tags.all())
@@ -1,245 +1,245 b''
1 from datetime import datetime
1 from datetime import datetime
2 import json
2 import json
3 import logging
3 import logging
4 from django.db import transaction
4 from django.db import transaction
5 from django.http import HttpResponse
5 from django.http import HttpResponse
6 from django.shortcuts import get_object_or_404, render
6 from django.shortcuts import get_object_or_404, render
7 from django.template import RequestContext
7 from django.template import RequestContext
8 from django.utils import timezone
8 from django.utils import timezone
9 from django.core import serializers
9 from django.core import serializers
10
10
11 from boards.forms import PostForm, PlainErrorList
11 from boards.forms import PostForm, PlainErrorList
12 from boards.models import Post, Thread, Tag
12 from boards.models import Post, Thread, Tag
13 from boards.utils import datetime_to_epoch
13 from boards.utils import datetime_to_epoch
14 from boards.views.thread import ThreadView
14 from boards.views.thread import ThreadView
15
15
16 __author__ = 'neko259'
16 __author__ = 'neko259'
17
17
18 PARAMETER_TRUNCATED = 'truncated'
18 PARAMETER_TRUNCATED = 'truncated'
19 PARAMETER_TAG = 'tag'
19 PARAMETER_TAG = 'tag'
20 PARAMETER_OFFSET = 'offset'
20 PARAMETER_OFFSET = 'offset'
21 PARAMETER_DIFF_TYPE = 'type'
21 PARAMETER_DIFF_TYPE = 'type'
22
22
23 DIFF_TYPE_HTML = 'html'
23 DIFF_TYPE_HTML = 'html'
24 DIFF_TYPE_JSON = 'json'
24 DIFF_TYPE_JSON = 'json'
25
25
26 STATUS_OK = 'ok'
26 STATUS_OK = 'ok'
27 STATUS_ERROR = 'error'
27 STATUS_ERROR = 'error'
28
28
29 logger = logging.getLogger(__name__)
29 logger = logging.getLogger(__name__)
30
30
31
31
32 @transaction.atomic
32 @transaction.atomic
33 def api_get_threaddiff(request, thread_id, last_update_time):
33 def api_get_threaddiff(request, thread_id, last_update_time):
34 """
34 """
35 Gets posts that were changed or added since time
35 Gets posts that were changed or added since time
36 """
36 """
37
37
38 thread = get_object_or_404(Post, id=thread_id).get_thread()
38 thread = get_object_or_404(Post, id=thread_id).get_thread()
39
39
40 filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000,
40 filter_time = datetime.fromtimestamp(float(last_update_time) / 1000000,
41 timezone.get_current_timezone())
41 timezone.get_current_timezone())
42
42
43 json_data = {
43 json_data = {
44 'added': [],
44 'added': [],
45 'updated': [],
45 'updated': [],
46 'last_update': None,
46 'last_update': None,
47 }
47 }
48 added_posts = Post.objects.filter(thread_new=thread,
48 added_posts = Post.objects.filter(thread_new=thread,
49 pub_time__gt=filter_time) \
49 pub_time__gt=filter_time) \
50 .order_by('pub_time')
50 .order_by('pub_time')
51 updated_posts = Post.objects.filter(thread_new=thread,
51 updated_posts = Post.objects.filter(thread_new=thread,
52 pub_time__lte=filter_time,
52 pub_time__lte=filter_time,
53 last_edit_time__gt=filter_time)
53 last_edit_time__gt=filter_time)
54
54
55 diff_type = DIFF_TYPE_HTML
55 diff_type = DIFF_TYPE_HTML
56 if PARAMETER_DIFF_TYPE in request.GET:
56 if PARAMETER_DIFF_TYPE in request.GET:
57 diff_type = request.GET[PARAMETER_DIFF_TYPE]
57 diff_type = request.GET[PARAMETER_DIFF_TYPE]
58
58
59 for post in added_posts:
59 for post in added_posts:
60 json_data['added'].append(_get_post_data(post.id, diff_type, request))
60 json_data['added'].append(_get_post_data(post.id, diff_type, request))
61 for post in updated_posts:
61 for post in updated_posts:
62 json_data['updated'].append(_get_post_data(post.id, diff_type, request))
62 json_data['updated'].append(_get_post_data(post.id, diff_type, request))
63 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
63 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
64
64
65 return HttpResponse(content=json.dumps(json_data))
65 return HttpResponse(content=json.dumps(json_data))
66
66
67
67
68 def api_add_post(request, opening_post_id):
68 def api_add_post(request, opening_post_id):
69 """
69 """
70 Adds a post and return the JSON response for it
70 Adds a post and return the JSON response for it
71 """
71 """
72
72
73 opening_post = get_object_or_404(Post, id=opening_post_id)
73 opening_post = get_object_or_404(Post, id=opening_post_id)
74
74
75 logger.info('Adding post via api...')
75 logger.info('Adding post via api...')
76
76
77 status = STATUS_OK
77 status = STATUS_OK
78 errors = []
78 errors = []
79
79
80 if request.method == 'POST':
80 if request.method == 'POST':
81 form = PostForm(request.POST, request.FILES, error_class=PlainErrorList)
81 form = PostForm(request.POST, request.FILES, error_class=PlainErrorList)
82 form.session = request.session
82 form.session = request.session
83
83
84 if form.need_to_ban:
84 if form.need_to_ban:
85 # Ban user because he is suspected to be a bot
85 # Ban user because he is suspected to be a bot
86 # _ban_current_user(request)
86 # _ban_current_user(request)
87 status = STATUS_ERROR
87 status = STATUS_ERROR
88 if form.is_valid():
88 if form.is_valid():
89 post = ThreadView().new_post(request, form, opening_post,
89 post = ThreadView().new_post(request, form, opening_post,
90 html_response=False)
90 html_response=False)
91 if not post:
91 if not post:
92 status = STATUS_ERROR
92 status = STATUS_ERROR
93 else:
93 else:
94 logger.info('Added post #%d via api.' % post.id)
94 logger.info('Added post #%d via api.' % post.id)
95 else:
95 else:
96 status = STATUS_ERROR
96 status = STATUS_ERROR
97 errors = form.as_json_errors()
97 errors = form.as_json_errors()
98
98
99 response = {
99 response = {
100 'status': status,
100 'status': status,
101 'errors': errors,
101 'errors': errors,
102 }
102 }
103
103
104 return HttpResponse(content=json.dumps(response))
104 return HttpResponse(content=json.dumps(response))
105
105
106
106
107 def get_post(request, post_id):
107 def get_post(request, post_id):
108 """
108 """
109 Gets the html of a post. Used for popups. Post can be truncated if used
109 Gets the html of a post. Used for popups. Post can be truncated if used
110 in threads list with 'truncated' get parameter.
110 in threads list with 'truncated' get parameter.
111 """
111 """
112
112
113 logger.info('Getting post #%s' % post_id)
113 logger.info('Getting post #%s' % post_id)
114
114
115 post = get_object_or_404(Post, id=post_id)
115 post = get_object_or_404(Post, id=post_id)
116
116
117 context = RequestContext(request)
117 context = RequestContext(request)
118 context['post'] = post
118 context['post'] = post
119 if PARAMETER_TRUNCATED in request.GET:
119 if PARAMETER_TRUNCATED in request.GET:
120 context[PARAMETER_TRUNCATED] = True
120 context[PARAMETER_TRUNCATED] = True
121
121
122 return render(request, 'boards/api_post.html', context)
122 return render(request, 'boards/api_post.html', context)
123
123
124
124
125 # TODO Test this
125 # TODO Test this
126 def api_get_threads(request, count):
126 def api_get_threads(request, count):
127 """
127 """
128 Gets the JSON thread opening posts list.
128 Gets the JSON thread opening posts list.
129 Parameters that can be used for filtering:
129 Parameters that can be used for filtering:
130 tag, offset (from which thread to get results)
130 tag, offset (from which thread to get results)
131 """
131 """
132
132
133 if PARAMETER_TAG in request.GET:
133 if PARAMETER_TAG in request.GET:
134 tag_name = request.GET[PARAMETER_TAG]
134 tag_name = request.GET[PARAMETER_TAG]
135 if tag_name is not None:
135 if tag_name is not None:
136 tag = get_object_or_404(Tag, name=tag_name)
136 tag = get_object_or_404(Tag, name=tag_name)
137 threads = tag.threads.filter(archived=False)
137 threads = tag.threads.filter(archived=False)
138 else:
138 else:
139 threads = Thread.objects.filter(archived=False)
139 threads = Thread.objects.filter(archived=False)
140
140
141 if PARAMETER_OFFSET in request.GET:
141 if PARAMETER_OFFSET in request.GET:
142 offset = request.GET[PARAMETER_OFFSET]
142 offset = request.GET[PARAMETER_OFFSET]
143 offset = int(offset) if offset is not None else 0
143 offset = int(offset) if offset is not None else 0
144 else:
144 else:
145 offset = 0
145 offset = 0
146
146
147 threads = threads.order_by('-bump_time')
147 threads = threads.order_by('-bump_time')
148 threads = threads[offset:offset + int(count)]
148 threads = threads[offset:offset + int(count)]
149
149
150 opening_posts = []
150 opening_posts = []
151 for thread in threads:
151 for thread in threads:
152 opening_post = thread.get_opening_post()
152 opening_post = thread.get_opening_post()
153
153
154 # TODO Add tags, replies and images count
154 # TODO Add tags, replies and images count
155 opening_posts.append(_get_post_data(opening_post.id,
155 opening_posts.append(_get_post_data(opening_post.id,
156 include_last_update=True))
156 include_last_update=True))
157
157
158 return HttpResponse(content=json.dumps(opening_posts))
158 return HttpResponse(content=json.dumps(opening_posts))
159
159
160
160
161 # TODO Test this
161 # TODO Test this
162 def api_get_tags(request):
162 def api_get_tags(request):
163 """
163 """
164 Gets all tags or user tags.
164 Gets all tags or user tags.
165 """
165 """
166
166
167 # TODO Get favorite tags for the given user ID
167 # TODO Get favorite tags for the given user ID
168
168
169 tags = Tag.objects.get_not_empty_tags()
169 tags = Tag.objects.get_not_empty_tags()
170 tag_names = []
170 tag_names = []
171 for tag in tags:
171 for tag in tags:
172 tag_names.append(tag.name)
172 tag_names.append(tag.name)
173
173
174 return HttpResponse(content=json.dumps(tag_names))
174 return HttpResponse(content=json.dumps(tag_names))
175
175
176
176
177 # TODO The result can be cached by the thread last update time
177 # TODO The result can be cached by the thread last update time
178 # TODO Test this
178 # TODO Test this
179 def api_get_thread_posts(request, opening_post_id):
179 def api_get_thread_posts(request, opening_post_id):
180 """
180 """
181 Gets the JSON array of thread posts
181 Gets the JSON array of thread posts
182 """
182 """
183
183
184 opening_post = get_object_or_404(Post, id=opening_post_id)
184 opening_post = get_object_or_404(Post, id=opening_post_id)
185 thread = opening_post.get_thread()
185 thread = opening_post.get_thread()
186 posts = thread.get_replies()
186 posts = thread.get_replies()
187
187
188 json_data = {
188 json_data = {
189 'posts': [],
189 'posts': [],
190 'last_update': None,
190 'last_update': None,
191 }
191 }
192 json_post_list = []
192 json_post_list = []
193
193
194 for post in posts:
194 for post in posts:
195 json_post_list.append(_get_post_data(post.id))
195 json_post_list.append(_get_post_data(post.id))
196 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
196 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
197 json_data['posts'] = json_post_list
197 json_data['posts'] = json_post_list
198
198
199 return HttpResponse(content=json.dumps(json_data))
199 return HttpResponse(content=json.dumps(json_data))
200
200
201
201
202 def api_get_post(request, post_id):
202 def api_get_post(request, post_id):
203 """
203 """
204 Gets the JSON of a post. This can be
204 Gets the JSON of a post. This can be
205 used as and API for external clients.
205 used as and API for external clients.
206 """
206 """
207
207
208 post = get_object_or_404(Post, id=post_id)
208 post = get_object_or_404(Post, id=post_id)
209
209
210 json = serializers.serialize("json", [post], fields=(
210 json = serializers.serialize("json", [post], fields=(
211 "pub_time", "_text_rendered", "title", "text", "image",
211 "pub_time", "_text_rendered", "title", "text", "image",
212 "image_width", "image_height", "replies", "tags"
212 "image_width", "image_height", "replies", "tags"
213 ))
213 ))
214
214
215 return HttpResponse(content=json)
215 return HttpResponse(content=json)
216
216
217
217
218 def get_tag_popularity(request, tag_name):
218 def get_tag_popularity(request, tag_name):
219 tag = get_object_or_404(Tag, name=tag_name)
219 tag = get_object_or_404(Tag, name=tag_name)
220
220
221 json_data = []
221 json_data = []
222 json_data['popularity'] = tag.get_popularity()
222 json_data['popularity'] = tag.get_popularity()
223
223
224 return HttpResponse(content=json.dumps(json_data))
224 return HttpResponse(content=json.dumps(json_data))
225
225
226
226
227 # TODO Add pub time and replies
227 # TODO Add pub time and replies
228 def _get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None,
228 def _get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None,
229 include_last_update=False):
229 include_last_update=False):
230 if format_type == DIFF_TYPE_HTML:
230 if format_type == DIFF_TYPE_HTML:
231 return get_post(request, post_id).content.strip()
231 return get_post(request, post_id).content.strip()
232 elif format_type == DIFF_TYPE_JSON:
232 elif format_type == DIFF_TYPE_JSON:
233 post = get_object_or_404(Post, id=post_id)
233 post = get_object_or_404(Post, id=post_id)
234 post_json = {
234 post_json = {
235 'id': post.id,
235 'id': post.id,
236 'title': post.title,
236 'title': post.title,
237 'text': post.text.rendered,
237 'text': post.text.rendered,
238 }
238 }
239 if post.image:
239 if post.image:
240 post_json['image'] = post.image.url
240 post_json['image'] = post.image.url
241 post_json['image_preview'] = post.image.url_200x150
241 post_json['image_preview'] = post.image.url_200x150
242 if include_last_update:
242 if include_last_update:
243 post_json['bump_time'] = datetime_to_epoch(
243 post_json['bump_time'] = datetime_to_epoch(
244 post.thread_new.bump_time)
244 post.thread_new.bump_time)
245 return post_json
245 return post_json
@@ -1,23 +1,24 b''
1 from django.db import transaction
1 from django.db import transaction
2 from django.shortcuts import get_object_or_404
2 from django.shortcuts import get_object_or_404
3 from boards import utils
3
4
4 from boards.views.base import BaseBoardView
5 from boards.views.base import BaseBoardView
5 from boards.models import Post, Ban
6 from boards.models import Post, Ban
6 from boards.views.mixins import RedirectNextMixin
7 from boards.views.mixins import RedirectNextMixin
7
8
8
9
9 class BanUserView(BaseBoardView, RedirectNextMixin):
10 class BanUserView(BaseBoardView, RedirectNextMixin):
10
11
11 @transaction.atomic
12 @transaction.atomic
12 def get(self, request, post_id):
13 def get(self, request, post_id):
13 user = self._get_user(request)
14 user = utils.get_user(request)
14 post = get_object_or_404(Post, id=post_id)
15 post = get_object_or_404(Post, id=post_id)
15
16
16 if user.is_moderator():
17 if user.is_moderator():
17 # TODO Show confirmation page before ban
18 # TODO Show confirmation page before ban
18 ban, created = Ban.objects.get_or_create(ip=post.poster_ip)
19 ban, created = Ban.objects.get_or_create(ip=post.poster_ip)
19 if created:
20 if created:
20 ban.reason = 'Banned for post ' + str(post_id)
21 ban.reason = 'Banned for post ' + str(post_id)
21 ban.save()
22 ban.save()
22
23
23 return self.redirect_to_next(request)
24 return self.redirect_to_next(request)
@@ -1,107 +1,35 b''
1 from datetime import datetime, timedelta
2 import hashlib
3 from django.db import transaction
1 from django.db import transaction
4 from django.db.models import Count
5 from django.template import RequestContext
2 from django.template import RequestContext
6 from django.utils import timezone
7 from django.views.generic import View
3 from django.views.generic import View
4
8 from boards import utils
5 from boards import utils
9 from boards.models import User, Post
6 from boards.models.user import Ban
10 from boards.models.post import SETTING_MODERATE
7
11 from boards.models.user import RANK_USER, Ban
12 import neboard
13
8
14 BAN_REASON_SPAM = 'Autoban: spam bot'
9 BAN_REASON_SPAM = 'Autoban: spam bot'
15
10
16 PARAMETER_FORM = 'form'
11 PARAMETER_FORM = 'form'
17
12
18
13
19 class BaseBoardView(View):
14 class BaseBoardView(View):
20
15
21 def get_context_data(self, **kwargs):
16 def get_context_data(self, **kwargs):
22 request = kwargs['request']
17 request = kwargs['request']
23 context = self._default_context(request)
18 # context = self._default_context(request)
24
25 context['version'] = neboard.settings.VERSION
26 context['site_name'] = neboard.settings.SITE_NAME
27
28 return context
29
30 def _default_context(self, request):
31 """Create context with default values that are used in most views"""
32
33 context = RequestContext(request)
19 context = RequestContext(request)
34
20
35 user = self._get_user(request)
36 context['user'] = user
37 context['tags'] = user.fav_tags.all()
38 context['posts_per_day'] = float(Post.objects.get_posts_per_day())
39
40 theme = self._get_theme(request, user)
41 context['theme'] = theme
42 context['theme_css'] = 'css/' + theme + '/base_page.css'
43
44 # This shows the moderator panel
45 moderate = user.get_setting(SETTING_MODERATE)
46 if moderate == 'True':
47 context['moderator'] = user.is_moderator()
48 else:
49 context['moderator'] = False
50
51 return context
21 return context
52
22
53 def _get_user(self, request):
54 """
55 Get current user from the session. If the user does not exist, create
56 a new one.
57 """
58
59 session = request.session
60 if not 'user_id' in session:
61 request.session.save()
62
63 md5 = hashlib.md5()
64 md5.update(session.session_key)
65 new_id = md5.hexdigest()
66
67 while User.objects.filter(user_id=new_id).exists():
68 md5.update(str(timezone.now()))
69 new_id = md5.hexdigest()
70
71 time_now = timezone.now()
72 user = User.objects.create(user_id=new_id, rank=RANK_USER,
73 registration_time=time_now)
74
75 session['user_id'] = user.id
76 else:
77 user = User.objects.select_related('fav_tags').get(
78 id=session['user_id'])
79
80 return user
81
82 def _get_theme(self, request, user=None):
83 """
84 Get user's CSS theme
85 """
86
87 if not user:
88 user = self._get_user(request)
89 theme = user.get_setting('theme')
90 if not theme:
91 theme = neboard.settings.DEFAULT_THEME
92
93 return theme
94
95 @transaction.atomic
23 @transaction.atomic
96 def _ban_current_user(self, request):
24 def _ban_current_user(self, request):
97 """
25 """
98 Add current user to the IP ban list
26 Add current user to the IP ban list
99 """
27 """
100
28
101 ip = utils.get_client_ip(request)
29 ip = utils.get_client_ip(request)
102 ban, created = Ban.objects.get_or_create(ip=ip)
30 ban, created = Ban.objects.get_or_create(ip=ip)
103 if created:
31 if created:
104 ban.can_read = False
32 ban.can_read = False
105 ban.reason = BAN_REASON_SPAM
33 ban.reason = BAN_REASON_SPAM
106 ban.save()
34 ban.save()
107
35
@@ -1,26 +1,27 b''
1 from django.shortcuts import redirect, get_object_or_404
1 from django.shortcuts import redirect, get_object_or_404
2 from django.db import transaction
2 from django.db import transaction
3 from boards import utils
3
4
4 from boards.views.base import BaseBoardView
5 from boards.views.base import BaseBoardView
5 from boards.views.mixins import RedirectNextMixin
6 from boards.views.mixins import RedirectNextMixin
6 from boards.models import Post
7 from boards.models import Post
7
8
8
9
9 class DeletePostView(BaseBoardView, RedirectNextMixin):
10 class DeletePostView(BaseBoardView, RedirectNextMixin):
10
11
11 @transaction.atomic
12 @transaction.atomic
12 def get(self, request, post_id):
13 def get(self, request, post_id):
13 user = self._get_user(request)
14 user = utils.get_user(request)
14 post = get_object_or_404(Post, id=post_id)
15 post = get_object_or_404(Post, id=post_id)
15
16
16 opening_post = post.is_opening()
17 opening_post = post.is_opening()
17
18
18 if user.is_moderator():
19 if user.is_moderator():
19 # TODO Show confirmation page before deletion
20 # TODO Show confirmation page before deletion
20 Post.objects.delete_post(post)
21 Post.objects.delete_post(post)
21
22
22 if not opening_post:
23 if not opening_post:
23 thread = post.thread_new
24 thread = post.thread_new
24 return redirect('thread', post_id=thread.get_opening_post().id)
25 return redirect('thread', post_id=thread.get_opening_post().id)
25 else:
26 else:
26 return self.redirect_to_next(request)
27 return self.redirect_to_next(request)
@@ -1,57 +1,57 b''
1 from django.shortcuts import render, get_object_or_404, redirect
1 from django.shortcuts import render, get_object_or_404, redirect
2
2
3 from boards.views.base import BaseBoardView
3 from boards.views.base import BaseBoardView
4 from boards.views.mixins import DispatcherMixin
4 from boards.views.mixins import DispatcherMixin
5 from boards.models.post import Post
5 from boards.models.post import Post
6 from boards.models.tag import Tag
6 from boards.models.tag import Tag
7 from boards.forms import AddTagForm, PlainErrorList
7 from boards.forms import AddTagForm, PlainErrorList
8
8
9 class PostAdminView(BaseBoardView, DispatcherMixin):
9 class PostAdminView(BaseBoardView, DispatcherMixin):
10
10
11 def get(self, request, post_id, form=None):
11 def get(self, request, post_id, form=None):
12 user = self._get_user(request)
12 user = utils.get_user(request)
13 if not user.is_moderator:
13 if not user.is_moderator:
14 redirect('index')
14 redirect('index')
15
15
16 post = get_object_or_404(Post, id=post_id)
16 post = get_object_or_404(Post, id=post_id)
17
17
18 if not form:
18 if not form:
19 dispatch_result = self.dispatch_method(request, post)
19 dispatch_result = self.dispatch_method(request, post)
20 if dispatch_result:
20 if dispatch_result:
21 return dispatch_result
21 return dispatch_result
22 form = AddTagForm()
22 form = AddTagForm()
23
23
24 context = self.get_context_data(request=request)
24 context = self.get_context_data(request=request)
25
25
26 context['post'] = post
26 context['post'] = post
27
27
28 context['tag_form'] = form
28 context['tag_form'] = form
29
29
30 return render(request, 'boards/post_admin.html', context)
30 return render(request, 'boards/post_admin.html', context)
31
31
32 def post(self, request, post_id):
32 def post(self, request, post_id):
33 user = self._get_user(request)
33 user = utils.get_user(request)
34 if not user.is_moderator:
34 if not user.is_moderator:
35 redirect('index')
35 redirect('index')
36
36
37 post = get_object_or_404(Post, id=post_id)
37 post = get_object_or_404(Post, id=post_id)
38 return self.dispatch_method(request, post)
38 return self.dispatch_method(request, post)
39
39
40 def delete_tag(self, request, post):
40 def delete_tag(self, request, post):
41 tag_name = request.GET['tag']
41 tag_name = request.GET['tag']
42 tag = get_object_or_404(Tag, name=tag_name)
42 tag = get_object_or_404(Tag, name=tag_name)
43
43
44 post.remove_tag(tag)
44 post.remove_tag(tag)
45
45
46 return redirect('post_admin', post.id)
46 return redirect('post_admin', post.id)
47
47
48 def add_tag(self, request, post):
48 def add_tag(self, request, post):
49 form = AddTagForm(request.POST, error_class=PlainErrorList)
49 form = AddTagForm(request.POST, error_class=PlainErrorList)
50 if form.is_valid():
50 if form.is_valid():
51 tag_name = form.cleaned_data['tag']
51 tag_name = form.cleaned_data['tag']
52 tag, created = Tag.objects.get_or_create(name=tag_name)
52 tag, created = Tag.objects.get_or_create(name=tag_name)
53
53
54 post.add_tag(tag)
54 post.add_tag(tag)
55 return redirect('post_admin', post.id)
55 return redirect('post_admin', post.id)
56 else:
56 else:
57 return self.get(request, post.id, form)
57 return self.get(request, post.id, form)
@@ -1,52 +1,53 b''
1 from django.db import transaction
1 from django.db import transaction
2 from django.shortcuts import render, redirect
2 from django.shortcuts import render, redirect
3 from boards import utils
3
4
4 from boards.views.base import BaseBoardView, PARAMETER_FORM
5 from boards.views.base import BaseBoardView, PARAMETER_FORM
5 from boards.forms import SettingsForm, ModeratorSettingsForm, PlainErrorList
6 from boards.forms import SettingsForm, ModeratorSettingsForm, PlainErrorList
6 from boards.models.post import SETTING_MODERATE
7 from boards.models.post import SETTING_MODERATE
7
8
8
9
9 class SettingsView(BaseBoardView):
10 class SettingsView(BaseBoardView):
10
11
11 def get(self, request):
12 def get(self, request):
12 context = self.get_context_data(request=request)
13 context = self.get_context_data(request=request)
13 user = context['user']
14 user = utils.get_user(request)
14 is_moderator = user.is_moderator()
15 is_moderator = user.is_moderator()
15
16
16 selected_theme = context['theme']
17 selected_theme = utils.get_theme(request, user)
17
18
18 if is_moderator:
19 if is_moderator:
19 form = ModeratorSettingsForm(initial={
20 form = ModeratorSettingsForm(initial={
20 'theme': selected_theme,
21 'theme': selected_theme,
21 'moderate': context['moderator']
22 'moderate': user.get_setting(SETTING_MODERATE) and \
23 user.is_moderator()
22 }, error_class=PlainErrorList)
24 }, error_class=PlainErrorList)
23 else:
25 else:
24 form = SettingsForm(initial={'theme': selected_theme},
26 form = SettingsForm(initial={'theme': selected_theme},
25 error_class=PlainErrorList)
27 error_class=PlainErrorList)
26
28
27 context[PARAMETER_FORM] = form
29 context[PARAMETER_FORM] = form
28
30
29 return render(request, 'boards/settings.html', context)
31 return render(request, 'boards/settings.html', context)
30
32
31 def post(self, request):
33 def post(self, request):
32 context = self.get_context_data(request=request)
34 user = utils.get_user(request)
33 user = context['user']
34 is_moderator = user.is_moderator()
35 is_moderator = user.is_moderator()
35
36
36 with transaction.atomic():
37 with transaction.atomic():
37 if is_moderator:
38 if is_moderator:
38 form = ModeratorSettingsForm(request.POST,
39 form = ModeratorSettingsForm(request.POST,
39 error_class=PlainErrorList)
40 error_class=PlainErrorList)
40 else:
41 else:
41 form = SettingsForm(request.POST, error_class=PlainErrorList)
42 form = SettingsForm(request.POST, error_class=PlainErrorList)
42
43
43 if form.is_valid():
44 if form.is_valid():
44 selected_theme = form.cleaned_data['theme']
45 selected_theme = form.cleaned_data['theme']
45
46
46 user.save_setting('theme', selected_theme)
47 user.save_setting('theme', selected_theme)
47
48
48 if is_moderator:
49 if is_moderator:
49 moderate = form.cleaned_data['moderate']
50 moderate = form.cleaned_data['moderate']
50 user.save_setting(SETTING_MODERATE, moderate)
51 user.save_setting(SETTING_MODERATE, moderate)
51
52
52 return redirect('settings')
53 return redirect('settings')
@@ -1,13 +1,14 b''
1 from django.shortcuts import render
1 from django.shortcuts import render
2
2
3 from boards.views.base import BaseBoardView
3 from boards.views.base import BaseBoardView
4
4
5
5 class StaticPageView(BaseBoardView):
6 class StaticPageView(BaseBoardView):
6
7
7 def get(self, request, name):
8 def get(self, request, name):
8 """
9 """
9 Show a static page that needs only tags list and a CSS
10 Show a static page that needs only tags list and a CSS
10 """
11 """
11
12
12 context = self.get_context_data(request=request)
13 context = self.get_context_data(request=request)
13 return render(request, 'boards/staticpages/' + name + '.html', context)
14 return render(request, 'boards/staticpages/' + name + '.html', context)
@@ -1,86 +1,87 b''
1 from django.shortcuts import get_object_or_404
1 from django.shortcuts import get_object_or_404
2 from boards import utils
2 from boards.models import Tag, Post
3 from boards.models import Tag, Post
3 from boards.views.all_threads import AllThreadsView, DEFAULT_PAGE
4 from boards.views.all_threads import AllThreadsView, DEFAULT_PAGE
4 from boards.views.mixins import DispatcherMixin, RedirectNextMixin
5 from boards.views.mixins import DispatcherMixin, RedirectNextMixin
5 from boards.forms import ThreadForm, PlainErrorList
6 from boards.forms import ThreadForm, PlainErrorList
6
7
7 __author__ = 'neko259'
8 __author__ = 'neko259'
8
9
9
10
10 class TagView(AllThreadsView, DispatcherMixin, RedirectNextMixin):
11 class TagView(AllThreadsView, DispatcherMixin, RedirectNextMixin):
11
12
12 tag_name = None
13 tag_name = None
13
14
14 def get_threads(self):
15 def get_threads(self):
15 tag = get_object_or_404(Tag, name=self.tag_name)
16 tag = get_object_or_404(Tag, name=self.tag_name)
16
17
17 return tag.threads.all().order_by('-bump_time')
18 return tag.threads.all().order_by('-bump_time')
18
19
19 def get_context_data(self, **kwargs):
20 def get_context_data(self, **kwargs):
20 context = super(TagView, self).get_context_data(**kwargs)
21 context = super(TagView, self).get_context_data(**kwargs)
21
22
22 tag = get_object_or_404(Tag, name=self.tag_name)
23 tag = get_object_or_404(Tag, name=self.tag_name)
23 context['tag'] = tag
24 context['tag'] = tag
24
25
25 return context
26 return context
26
27
27 def get(self, request, tag_name, page=DEFAULT_PAGE, form=None):
28 def get(self, request, tag_name, page=DEFAULT_PAGE, form=None):
28 self.tag_name = tag_name
29 self.tag_name = tag_name
29
30
30 dispatch_result = self.dispatch_method(request)
31 dispatch_result = self.dispatch_method(request)
31 if dispatch_result:
32 if dispatch_result:
32 return dispatch_result
33 return dispatch_result
33 else:
34 else:
34 return super(TagView, self).get(request, page, form)
35 return super(TagView, self).get(request, page, form)
35
36
36 def post(self, request, tag_name, page=DEFAULT_PAGE):
37 def post(self, request, tag_name, page=DEFAULT_PAGE):
37 form = ThreadForm(request.POST, request.FILES,
38 form = ThreadForm(request.POST, request.FILES,
38 error_class=PlainErrorList)
39 error_class=PlainErrorList)
39 form.session = request.session
40 form.session = request.session
40
41
41 if form.is_valid():
42 if form.is_valid():
42 return self.create_thread(request, form)
43 return self.create_thread(request, form)
43 if form.need_to_ban:
44 if form.need_to_ban:
44 # Ban user because he is suspected to be a bot
45 # Ban user because he is suspected to be a bot
45 self._ban_current_user(request)
46 self._ban_current_user(request)
46
47
47 return self.get(request, tag_name, page, form)
48 return self.get(request, tag_name, page, form)
48
49
49 def subscribe(self, request):
50 def subscribe(self, request):
50 user = self._get_user(request)
51 user = utils.get_user(request)
51 tag = get_object_or_404(Tag, name=self.tag_name)
52 tag = get_object_or_404(Tag, name=self.tag_name)
52
53
53 if not tag in user.fav_tags.all():
54 if not tag in user.fav_tags.all():
54 user.add_tag(tag)
55 user.add_tag(tag)
55
56
56 return self.redirect_to_next(request)
57 return self.redirect_to_next(request)
57
58
58 def unsubscribe(self, request):
59 def unsubscribe(self, request):
59 user = self._get_user(request)
60 user = utils.get_user(request)
60 tag = get_object_or_404(Tag, name=self.tag_name)
61 tag = get_object_or_404(Tag, name=self.tag_name)
61
62
62 if tag in user.fav_tags.all():
63 if tag in user.fav_tags.all():
63 user.remove_tag(tag)
64 user.remove_tag(tag)
64
65
65 return self.redirect_to_next(request)
66 return self.redirect_to_next(request)
66
67
67 def hide(self, request):
68 def hide(self, request):
68 """
69 """
69 Adds tag to user's hidden tags. Threads with this tag will not be
70 Adds tag to user's hidden tags. Threads with this tag will not be
70 shown.
71 shown.
71 """
72 """
72
73
73 user = self._get_user(request)
74 user = utils.get_user(request)
74 tag = get_object_or_404(Tag, name=self.tag_name)
75 tag = get_object_or_404(Tag, name=self.tag_name)
75
76
76 user.hide_tag(tag)
77 user.hide_tag(tag)
77
78
78 def unhide(self, request):
79 def unhide(self, request):
79 """
80 """
80 Removed tag from user's hidden tags.
81 Removed tag from user's hidden tags.
81 """
82 """
82
83
83 user = self._get_user(request)
84 user = utils.get_user(request)
84 tag = get_object_or_404(Tag, name=self.tag_name)
85 tag = get_object_or_404(Tag, name=self.tag_name)
85
86
86 user.unhide_tag(tag)
87 user.unhide_tag(tag)
@@ -1,132 +1,133 b''
1 import string
2 from django.core.urlresolvers import reverse
1 from django.core.urlresolvers import reverse
3 from django.db import transaction
2 from django.db import transaction
4 from django.http import Http404
3 from django.http import Http404
5 from django.shortcuts import get_object_or_404, render, redirect
4 from django.shortcuts import get_object_or_404, render, redirect
6 from django.views.generic.edit import FormMixin
5 from django.views.generic.edit import FormMixin
6
7 from boards import utils
7 from boards import utils
8 from boards.forms import PostForm, PlainErrorList
8 from boards.forms import PostForm, PlainErrorList
9 from boards.models import Post, Ban, Tag
9 from boards.models import Post, Ban
10 from boards.views.banned import BannedView
10 from boards.views.banned import BannedView
11 from boards.views.base import BaseBoardView, PARAMETER_FORM
11 from boards.views.base import BaseBoardView, PARAMETER_FORM
12 from boards.views.posting_mixin import PostMixin
12 from boards.views.posting_mixin import PostMixin
13 import neboard
13 import neboard
14
14
15
15 MODE_GALLERY = 'gallery'
16 MODE_GALLERY = 'gallery'
16 MODE_NORMAL = 'normal'
17 MODE_NORMAL = 'normal'
17
18
18 PARAMETER_MAX_REPLIES = 'max_replies'
19 PARAMETER_MAX_REPLIES = 'max_replies'
19 PARAMETER_THREAD = 'thread'
20 PARAMETER_THREAD = 'thread'
20 PARAMETER_BUMPABLE = 'bumpable'
21 PARAMETER_BUMPABLE = 'bumpable'
21
22
22
23
23 class ThreadView(BaseBoardView, PostMixin, FormMixin):
24 class ThreadView(BaseBoardView, PostMixin, FormMixin):
24
25
25 def get(self, request, post_id, mode=MODE_NORMAL, form=None):
26 def get(self, request, post_id, mode=MODE_NORMAL, form=None):
26 try:
27 try:
27 opening_post = Post.objects.filter(id=post_id).only('thread_new')[0]
28 opening_post = Post.objects.filter(id=post_id).only('thread_new')[0]
28 except IndexError:
29 except IndexError:
29 raise Http404
30 raise Http404
30
31
31 # If this is not OP, don't show it as it is
32 # If this is not OP, don't show it as it is
32 if not opening_post or not opening_post.is_opening():
33 if not opening_post or not opening_post.is_opening():
33 raise Http404
34 raise Http404
34
35
35 if not form:
36 if not form:
36 form = PostForm(error_class=PlainErrorList)
37 form = PostForm(error_class=PlainErrorList)
37
38
38 thread_to_show = opening_post.get_thread()
39 thread_to_show = opening_post.get_thread()
39
40
40 context = self.get_context_data(request=request)
41 context = self.get_context_data(request=request)
41
42
42 context[PARAMETER_FORM] = form
43 context[PARAMETER_FORM] = form
43 context["last_update"] = utils.datetime_to_epoch(
44 context["last_update"] = utils.datetime_to_epoch(
44 thread_to_show.last_edit_time)
45 thread_to_show.last_edit_time)
45 context[PARAMETER_THREAD] = thread_to_show
46 context[PARAMETER_THREAD] = thread_to_show
46 context[PARAMETER_MAX_REPLIES] = neboard.settings.MAX_POSTS_PER_THREAD
47 context[PARAMETER_MAX_REPLIES] = neboard.settings.MAX_POSTS_PER_THREAD
47
48
48 if MODE_NORMAL == mode:
49 if MODE_NORMAL == mode:
49 context[PARAMETER_BUMPABLE] = thread_to_show.can_bump()
50 context[PARAMETER_BUMPABLE] = thread_to_show.can_bump()
50 if context[PARAMETER_BUMPABLE]:
51 if context[PARAMETER_BUMPABLE]:
51 context['posts_left'] = neboard.settings.MAX_POSTS_PER_THREAD \
52 context['posts_left'] = neboard.settings.MAX_POSTS_PER_THREAD \
52 - thread_to_show.get_reply_count()
53 - thread_to_show.get_reply_count()
53 context['bumplimit_progress'] = str(
54 context['bumplimit_progress'] = str(
54 float(context['posts_left']) /
55 float(context['posts_left']) /
55 neboard.settings.MAX_POSTS_PER_THREAD * 100)
56 neboard.settings.MAX_POSTS_PER_THREAD * 100)
56
57
57 context['opening_post'] = opening_post
58 context['opening_post'] = opening_post
58
59
59 document = 'boards/thread.html'
60 document = 'boards/thread.html'
60 elif MODE_GALLERY == mode:
61 elif MODE_GALLERY == mode:
61 posts = thread_to_show.get_replies(view_fields_only=True)
62 posts = thread_to_show.get_replies(view_fields_only=True)
62 context['posts'] = posts.filter(image_width__gt=0)
63 context['posts'] = posts.filter(image_width__gt=0)
63
64
64 document = 'boards/thread_gallery.html'
65 document = 'boards/thread_gallery.html'
65 else:
66 else:
66 raise Http404
67 raise Http404
67
68
68 return render(request, document, context)
69 return render(request, document, context)
69
70
70 def post(self, request, post_id, mode=MODE_NORMAL):
71 def post(self, request, post_id, mode=MODE_NORMAL):
71 opening_post = get_object_or_404(Post, id=post_id)
72 opening_post = get_object_or_404(Post, id=post_id)
72
73
73 # If this is not OP, don't show it as it is
74 # If this is not OP, don't show it as it is
74 if not opening_post.is_opening():
75 if not opening_post.is_opening():
75 raise Http404
76 raise Http404
76
77
77 if not opening_post.get_thread().archived:
78 if not opening_post.get_thread().archived:
78 form = PostForm(request.POST, request.FILES,
79 form = PostForm(request.POST, request.FILES,
79 error_class=PlainErrorList)
80 error_class=PlainErrorList)
80 form.session = request.session
81 form.session = request.session
81
82
82 if form.is_valid():
83 if form.is_valid():
83 return self.new_post(request, form, opening_post)
84 return self.new_post(request, form, opening_post)
84 if form.need_to_ban:
85 if form.need_to_ban:
85 # Ban user because he is suspected to be a bot
86 # Ban user because he is suspected to be a bot
86 self._ban_current_user(request)
87 self._ban_current_user(request)
87
88
88 return self.get(request, post_id, mode, form)
89 return self.get(request, post_id, mode, form)
89
90
90 @transaction.atomic
91 @transaction.atomic
91 def new_post(self, request, form, opening_post=None, html_response=True):
92 def new_post(self, request, form, opening_post=None, html_response=True):
92 """Add a new post (in thread or as a reply)."""
93 """Add a new post (in thread or as a reply)."""
93
94
94 ip = utils.get_client_ip(request)
95 ip = utils.get_client_ip(request)
95 is_banned = Ban.objects.filter(ip=ip).exists()
96 is_banned = Ban.objects.filter(ip=ip).exists()
96
97
97 if is_banned:
98 if is_banned:
98 if html_response:
99 if html_response:
99 return redirect(BannedView().as_view())
100 return redirect(BannedView().as_view())
100 else:
101 else:
101 return None
102 return None
102
103
103 data = form.cleaned_data
104 data = form.cleaned_data
104
105
105 title = data['title']
106 title = data['title']
106 text = data['text']
107 text = data['text']
107
108
108 text = self._remove_invalid_links(text)
109 text = self._remove_invalid_links(text)
109
110
110 if 'image' in data.keys():
111 if 'image' in data.keys():
111 image = data['image']
112 image = data['image']
112 else:
113 else:
113 image = None
114 image = None
114
115
115 tags = []
116 tags = []
116
117
117 post_thread = opening_post.get_thread()
118 post_thread = opening_post.get_thread()
118
119
119 post = Post.objects.create_post(title=title, text=text, ip=ip,
120 post = Post.objects.create_post(title=title, text=text, ip=ip,
120 thread=post_thread, image=image,
121 thread=post_thread, image=image,
121 tags=tags,
122 tags=tags,
122 user=self._get_user(request))
123 user=utils.get_user(request))
123
124
124 thread_to_show = (opening_post.id if opening_post else post.id)
125 thread_to_show = (opening_post.id if opening_post else post.id)
125
126
126 if html_response:
127 if html_response:
127 if opening_post:
128 if opening_post:
128 return redirect(reverse(
129 return redirect(reverse(
129 'thread',
130 'thread',
130 kwargs={'post_id': thread_to_show}) + '#' + str(post.id))
131 kwargs={'post_id': thread_to_show}) + '#' + str(post.id))
131 else:
132 else:
132 return post
133 return post
@@ -1,259 +1,276 b''
1 # Django settings for neboard project.
1 # Django settings for neboard project.
2 import os
2 import os
3 from boards.mdx_neboard import markdown_extended
3 from boards.mdx_neboard import markdown_extended
4
4
5 DEBUG = True
5 DEBUG = True
6 TEMPLATE_DEBUG = DEBUG
6 TEMPLATE_DEBUG = DEBUG
7
7
8 ADMINS = (
8 ADMINS = (
9 # ('Your Name', 'your_email@example.com'),
9 # ('Your Name', 'your_email@example.com'),
10 ('admin', 'admin@example.com')
10 ('admin', 'admin@example.com')
11 )
11 )
12
12
13 MANAGERS = ADMINS
13 MANAGERS = ADMINS
14
14
15 DATABASES = {
15 DATABASES = {
16 'default': {
16 'default': {
17 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
17 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
18 'NAME': 'database.db', # Or path to database file if using sqlite3.
18 'NAME': 'database.db', # Or path to database file if using sqlite3.
19 'USER': '', # Not used with sqlite3.
19 'USER': '', # Not used with sqlite3.
20 'PASSWORD': '', # Not used with sqlite3.
20 'PASSWORD': '', # Not used with sqlite3.
21 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
21 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
22 'PORT': '', # Set to empty string for default. Not used with sqlite3.
22 'PORT': '', # Set to empty string for default. Not used with sqlite3.
23 'CONN_MAX_AGE': None,
23 'CONN_MAX_AGE': None,
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 )
85 )
86
86
87 if DEBUG:
87 if DEBUG:
88 STATICFILES_STORAGE = \
88 STATICFILES_STORAGE = \
89 'django.contrib.staticfiles.storage.StaticFilesStorage'
89 'django.contrib.staticfiles.storage.StaticFilesStorage'
90 else:
90 else:
91 STATICFILES_STORAGE = \
91 STATICFILES_STORAGE = \
92 'django.contrib.staticfiles.storage.CachedStaticFilesStorage'
92 'django.contrib.staticfiles.storage.CachedStaticFilesStorage'
93
93
94 # Make this unique, and don't share it with anybody.
94 # Make this unique, and don't share it with anybody.
95 SECRET_KEY = '@1rc$o(7=tt#kd+4s$u6wchm**z^)4x90)7f6z(i&amp;55@o11*8o'
95 SECRET_KEY = '@1rc$o(7=tt#kd+4s$u6wchm**z^)4x90)7f6z(i&amp;55@o11*8o'
96
96
97 # List of callables that know how to import templates from various sources.
97 # List of callables that know how to import templates from various sources.
98 TEMPLATE_LOADERS = (
98 TEMPLATE_LOADERS = (
99 'django.template.loaders.filesystem.Loader',
99 'django.template.loaders.filesystem.Loader',
100 'django.template.loaders.app_directories.Loader',
100 'django.template.loaders.app_directories.Loader',
101 )
101 )
102
102
103 TEMPLATE_CONTEXT_PROCESSORS = (
103 TEMPLATE_CONTEXT_PROCESSORS = (
104 'django.core.context_processors.media',
104 'django.core.context_processors.media',
105 'django.core.context_processors.static',
105 'django.core.context_processors.static',
106 'django.core.context_processors.request',
106 'django.core.context_processors.request',
107 'django.contrib.auth.context_processors.auth',
107 'django.contrib.auth.context_processors.auth',
108 'boards.context_processors.user_and_ui_processor',
108 )
109 )
109
110
110 MIDDLEWARE_CLASSES = (
111 MIDDLEWARE_CLASSES = (
111 'django.contrib.sessions.middleware.SessionMiddleware',
112 'django.contrib.sessions.middleware.SessionMiddleware',
112 'django.middleware.locale.LocaleMiddleware',
113 'django.middleware.locale.LocaleMiddleware',
113 'django.middleware.common.CommonMiddleware',
114 'django.middleware.common.CommonMiddleware',
114 'django.contrib.auth.middleware.AuthenticationMiddleware',
115 'django.contrib.auth.middleware.AuthenticationMiddleware',
115 'django.contrib.messages.middleware.MessageMiddleware',
116 'django.contrib.messages.middleware.MessageMiddleware',
116 'boards.middlewares.BanMiddleware',
117 'boards.middlewares.BanMiddleware',
117 'boards.middlewares.MinifyHTMLMiddleware',
118 'boards.middlewares.MinifyHTMLMiddleware',
118 )
119 )
119
120
120 ROOT_URLCONF = 'neboard.urls'
121 ROOT_URLCONF = 'neboard.urls'
121
122
122 # Python dotted path to the WSGI application used by Django's runserver.
123 # Python dotted path to the WSGI application used by Django's runserver.
123 WSGI_APPLICATION = 'neboard.wsgi.application'
124 WSGI_APPLICATION = 'neboard.wsgi.application'
124
125
125 TEMPLATE_DIRS = (
126 TEMPLATE_DIRS = (
126 # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
127 # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
127 # Always use forward slashes, even on Windows.
128 # Always use forward slashes, even on Windows.
128 # Don't forget to use absolute paths, not relative paths.
129 # Don't forget to use absolute paths, not relative paths.
129 'templates',
130 'templates',
130 )
131 )
131
132
132 INSTALLED_APPS = (
133 INSTALLED_APPS = (
133 'django.contrib.auth',
134 'django.contrib.auth',
134 'django.contrib.contenttypes',
135 'django.contrib.contenttypes',
135 'django.contrib.sessions',
136 'django.contrib.sessions',
136 # 'django.contrib.sites',
137 # 'django.contrib.sites',
137 'django.contrib.messages',
138 'django.contrib.messages',
138 'django.contrib.staticfiles',
139 'django.contrib.staticfiles',
139 # Uncomment the next line to enable the admin:
140 # Uncomment the next line to enable the admin:
140 'django.contrib.admin',
141 'django.contrib.admin',
141 # Uncomment the next line to enable admin documentation:
142 # Uncomment the next line to enable admin documentation:
142 # 'django.contrib.admindocs',
143 # 'django.contrib.admindocs',
143 'django.contrib.humanize',
144 'django.contrib.humanize',
144 'django_cleanup',
145 'django_cleanup',
145 'boards',
146
146 'captcha',
147 # Migrations
147 'south',
148 'south',
148 'debug_toolbar',
149 'debug_toolbar',
150
151 'captcha',
152
153 # Search
154 'haystack',
155
156 'boards',
149 )
157 )
150
158
151 DEBUG_TOOLBAR_PANELS = (
159 DEBUG_TOOLBAR_PANELS = (
152 'debug_toolbar.panels.version.VersionDebugPanel',
160 'debug_toolbar.panels.version.VersionDebugPanel',
153 'debug_toolbar.panels.timer.TimerDebugPanel',
161 'debug_toolbar.panels.timer.TimerDebugPanel',
154 'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
162 'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
155 'debug_toolbar.panels.headers.HeaderDebugPanel',
163 'debug_toolbar.panels.headers.HeaderDebugPanel',
156 'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
164 'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
157 'debug_toolbar.panels.template.TemplateDebugPanel',
165 'debug_toolbar.panels.template.TemplateDebugPanel',
158 'debug_toolbar.panels.sql.SQLDebugPanel',
166 'debug_toolbar.panels.sql.SQLDebugPanel',
159 'debug_toolbar.panels.signals.SignalDebugPanel',
167 'debug_toolbar.panels.signals.SignalDebugPanel',
160 'debug_toolbar.panels.logger.LoggingPanel',
168 'debug_toolbar.panels.logger.LoggingPanel',
161 )
169 )
162
170
163 # TODO: NEED DESIGN FIXES
171 # TODO: NEED DESIGN FIXES
164 CAPTCHA_OUTPUT_FORMAT = (u' %(hidden_field)s '
172 CAPTCHA_OUTPUT_FORMAT = (u' %(hidden_field)s '
165 u'<div class="form-label">%(image)s</div>'
173 u'<div class="form-label">%(image)s</div>'
166 u'<div class="form-text">%(text_field)s</div>')
174 u'<div class="form-text">%(text_field)s</div>')
167
175
168 # A sample logging configuration. The only tangible logging
176 # A sample logging configuration. The only tangible logging
169 # performed by this configuration is to send an email to
177 # performed by this configuration is to send an email to
170 # the site admins on every HTTP 500 error when DEBUG=False.
178 # the site admins on every HTTP 500 error when DEBUG=False.
171 # See http://docs.djangoproject.com/en/dev/topics/logging for
179 # See http://docs.djangoproject.com/en/dev/topics/logging for
172 # more details on how to customize your logging configuration.
180 # more details on how to customize your logging configuration.
173 LOGGING = {
181 LOGGING = {
174 'version': 1,
182 'version': 1,
175 'disable_existing_loggers': False,
183 'disable_existing_loggers': False,
176 'formatters': {
184 'formatters': {
177 'verbose': {
185 'verbose': {
178 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
186 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
179 },
187 },
180 'simple': {
188 'simple': {
181 'format': '%(levelname)s %(asctime)s [%(module)s] %(message)s'
189 'format': '%(levelname)s %(asctime)s [%(module)s] %(message)s'
182 },
190 },
183 },
191 },
184 'filters': {
192 'filters': {
185 'require_debug_false': {
193 'require_debug_false': {
186 '()': 'django.utils.log.RequireDebugFalse'
194 '()': 'django.utils.log.RequireDebugFalse'
187 }
195 }
188 },
196 },
189 'handlers': {
197 'handlers': {
190 'console': {
198 'console': {
191 'level': 'DEBUG',
199 'level': 'DEBUG',
192 'class': 'logging.StreamHandler',
200 'class': 'logging.StreamHandler',
193 'formatter': 'simple'
201 'formatter': 'simple'
194 },
202 },
195 },
203 },
196 'loggers': {
204 'loggers': {
197 'boards': {
205 'boards': {
198 'handlers': ['console'],
206 'handlers': ['console'],
199 'level': 'DEBUG',
207 'level': 'DEBUG',
200 }
208 }
201 },
209 },
202 }
210 }
203
211
212 HAYSTACK_CONNECTIONS = {
213 'default': {
214 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
215 'PATH': os.path.join(os.path.dirname(__file__), 'whoosh_index'),
216 },
217 }
218
219 HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
220
204 MARKUP_FIELD_TYPES = (
221 MARKUP_FIELD_TYPES = (
205 ('markdown', markdown_extended),
222 ('markdown', markdown_extended),
206 )
223 )
207 # Custom imageboard settings
224 # Custom imageboard settings
208 # TODO These should me moved to
225 # TODO These should me moved to
209 MAX_POSTS_PER_THREAD = 10 # Thread bumplimit
226 MAX_POSTS_PER_THREAD = 10 # Thread bumplimit
210 MAX_THREAD_COUNT = 5 # Old threads will be deleted to preserve this count
227 MAX_THREAD_COUNT = 5 # Old threads will be deleted to preserve this count
211 THREADS_PER_PAGE = 3
228 THREADS_PER_PAGE = 3
212 SITE_NAME = 'Neboard'
229 SITE_NAME = 'Neboard'
213
230
214 THEMES = [
231 THEMES = [
215 ('md', 'Mystic Dark'),
232 ('md', 'Mystic Dark'),
216 ('md_centered', 'Mystic Dark (centered)'),
233 ('md_centered', 'Mystic Dark (centered)'),
217 ('sw', 'Snow White'),
234 ('sw', 'Snow White'),
218 ('pg', 'Photon Gray'),
235 ('pg', 'Photon Gray'),
219 ]
236 ]
220
237
221 DEFAULT_THEME = 'md'
238 DEFAULT_THEME = 'md'
222
239
223 POPULAR_TAGS = 10
240 POPULAR_TAGS = 10
224 LAST_REPLIES_COUNT = 3
241 LAST_REPLIES_COUNT = 3
225
242
226 ENABLE_CAPTCHA = False
243 ENABLE_CAPTCHA = False
227 # if user tries to post before CAPTCHA_DEFAULT_SAFE_TIME. Captcha will be shown
244 # if user tries to post before CAPTCHA_DEFAULT_SAFE_TIME. Captcha will be shown
228 CAPTCHA_DEFAULT_SAFE_TIME = 30 # seconds
245 CAPTCHA_DEFAULT_SAFE_TIME = 30 # seconds
229 POSTING_DELAY = 20 # seconds
246 POSTING_DELAY = 20 # seconds
230
247
231 COMPRESS_HTML = True
248 COMPRESS_HTML = True
232
249
233 VERSION = '1.7.4 Anubis'
250 VERSION = '1.7.4 Anubis'
234
251
235 # Debug mode middlewares
252 # Debug mode middlewares
236 if DEBUG:
253 if DEBUG:
237
254
238 SITE_NAME += ' DEBUG'
255 SITE_NAME += ' DEBUG'
239
256
240 MIDDLEWARE_CLASSES += (
257 MIDDLEWARE_CLASSES += (
241 'boards.profiler.ProfilerMiddleware',
258 'boards.profiler.ProfilerMiddleware',
242 'debug_toolbar.middleware.DebugToolbarMiddleware',
259 'debug_toolbar.middleware.DebugToolbarMiddleware',
243 )
260 )
244
261
245 def custom_show_toolbar(request):
262 def custom_show_toolbar(request):
246 return DEBUG
263 return DEBUG
247
264
248 DEBUG_TOOLBAR_CONFIG = {
265 DEBUG_TOOLBAR_CONFIG = {
249 'INTERCEPT_REDIRECTS': False,
266 'INTERCEPT_REDIRECTS': False,
250 'SHOW_TOOLBAR_CALLBACK': custom_show_toolbar,
267 'SHOW_TOOLBAR_CALLBACK': custom_show_toolbar,
251 'HIDE_DJANGO_SQL': False,
268 'HIDE_DJANGO_SQL': False,
252 'ENABLE_STACKTRACES': True,
269 'ENABLE_STACKTRACES': True,
253 }
270 }
254
271
255 # FIXME Uncommenting this fails somehow. Need to investigate this
272 # FIXME Uncommenting this fails somehow. Need to investigate this
256 #DEBUG_TOOLBAR_PANELS += (
273 #DEBUG_TOOLBAR_PANELS += (
257 # 'debug_toolbar.panels.profiling.ProfilingDebugPanel',
274 # 'debug_toolbar.panels.profiling.ProfilingDebugPanel',
258 #)
275 #)
259
276
General Comments 0
You need to be logged in to leave comments. Login now