Show More
@@ -1,1 +0,0 b'' | |||||
1 | import settings No newline at end of file |
|
@@ -2,7 +2,6 b' import re' | |||||
2 | import time |
|
2 | import time | |
3 | import hashlib |
|
3 | import hashlib | |
4 |
|
4 | |||
5 | from captcha.fields import CaptchaField |
|
|||
6 | from django import forms |
|
5 | from django import forms | |
7 | from django.forms.util import ErrorList |
|
6 | from django.forms.util import ErrorList | |
8 | from django.utils.translation import ugettext_lazy as _ |
|
7 | from django.utils.translation import ugettext_lazy as _ | |
@@ -32,18 +31,18 b" LABEL_SEARCH = _('Search')" | |||||
32 |
|
31 | |||
33 | TAG_MAX_LENGTH = 20 |
|
32 | TAG_MAX_LENGTH = 20 | |
34 |
|
33 | |||
35 |
REGEX_TAG = |
|
34 | REGEX_TAG = r'^[\w\d]+$' | |
36 |
|
35 | |||
37 |
|
36 | |||
38 | class FormatPanel(forms.Textarea): |
|
37 | class FormatPanel(forms.Textarea): | |
39 | def render(self, name, value, attrs=None): |
|
38 | def render(self, name, value, attrs=None): | |
40 | output = '<div id="mark-panel">' |
|
39 | output = '<div id="mark-panel">' | |
41 | for formatter in formatters: |
|
40 | for formatter in formatters: | |
42 |
output += |
|
41 | output += '<span class="mark_btn"' + \ | |
43 |
|
|
42 | ' onClick="addMarkToMsg(\'' + formatter.format_left + \ | |
44 | '\', \'' + formatter.format_right + '\')">' + \ |
|
43 | '\', \'' + formatter.format_right + '\')">' + \ | |
45 | formatter.preview_left + formatter.name + \ |
|
44 | formatter.preview_left + formatter.name + \ | |
46 |
formatter.preview_right + |
|
45 | formatter.preview_right + '</span>' | |
47 |
|
46 | |||
48 | output += '</div>' |
|
47 | output += '</div>' | |
49 | output += super(FormatPanel, self).render(name, value, attrs=None) |
|
48 | output += super(FormatPanel, self).render(name, value, attrs=None) | |
@@ -56,7 +55,7 b' class PlainErrorList(ErrorList):' | |||||
56 | return self.as_text() |
|
55 | return self.as_text() | |
57 |
|
56 | |||
58 | def as_text(self): |
|
57 | def as_text(self): | |
59 |
return ''.join([ |
|
58 | return ''.join(['(!) %s ' % e for e in self]) | |
60 |
|
59 | |||
61 |
|
60 | |||
62 | class NeboardForm(forms.Form): |
|
61 | class NeboardForm(forms.Form): | |
@@ -88,7 +87,7 b' class NeboardForm(forms.Form):' | |||||
88 | def as_json_errors(self): |
|
87 | def as_json_errors(self): | |
89 | errors = [] |
|
88 | errors = [] | |
90 |
|
89 | |||
91 | for name, field in self.fields.items(): |
|
90 | for name, field in list(self.fields.items()): | |
92 | if self[name].errors: |
|
91 | if self[name].errors: | |
93 | errors.append({ |
|
92 | errors.append({ | |
94 | 'field': name, |
|
93 | 'field': name, | |
@@ -208,7 +207,7 b' class PostForm(NeboardForm):' | |||||
208 |
|
207 | |||
209 | class ThreadForm(PostForm): |
|
208 | class ThreadForm(PostForm): | |
210 |
|
209 | |||
211 |
regex_tags = re.compile( |
|
210 | regex_tags = re.compile(r'^[\w\s\d]+$', re.UNICODE) | |
212 |
|
211 | |||
213 | tags = forms.CharField( |
|
212 | tags = forms.CharField( | |
214 | widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}), |
|
213 | widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}), | |
@@ -229,48 +228,6 b' class ThreadForm(PostForm):' | |||||
229 | return cleaned_data |
|
228 | return cleaned_data | |
230 |
|
229 | |||
231 |
|
230 | |||
232 | class PostCaptchaForm(PostForm): |
|
|||
233 | captcha = CaptchaField() |
|
|||
234 |
|
||||
235 | def __init__(self, *args, **kwargs): |
|
|||
236 | self.request = kwargs['request'] |
|
|||
237 | del kwargs['request'] |
|
|||
238 |
|
||||
239 | super(PostCaptchaForm, self).__init__(*args, **kwargs) |
|
|||
240 |
|
||||
241 | def clean(self): |
|
|||
242 | cleaned_data = super(PostCaptchaForm, self).clean() |
|
|||
243 |
|
||||
244 | success = self.is_valid() |
|
|||
245 | utils.update_captcha_access(self.request, success) |
|
|||
246 |
|
||||
247 | if success: |
|
|||
248 | return cleaned_data |
|
|||
249 | else: |
|
|||
250 | raise forms.ValidationError(_("Captcha validation failed")) |
|
|||
251 |
|
||||
252 |
|
||||
253 | class ThreadCaptchaForm(ThreadForm): |
|
|||
254 | captcha = CaptchaField() |
|
|||
255 |
|
||||
256 | def __init__(self, *args, **kwargs): |
|
|||
257 | self.request = kwargs['request'] |
|
|||
258 | del kwargs['request'] |
|
|||
259 |
|
||||
260 | super(ThreadCaptchaForm, self).__init__(*args, **kwargs) |
|
|||
261 |
|
||||
262 | def clean(self): |
|
|||
263 | cleaned_data = super(ThreadCaptchaForm, self).clean() |
|
|||
264 |
|
||||
265 | success = self.is_valid() |
|
|||
266 | utils.update_captcha_access(self.request, success) |
|
|||
267 |
|
||||
268 | if success: |
|
|||
269 | return cleaned_data |
|
|||
270 | else: |
|
|||
271 | raise forms.ValidationError(_("Captcha validation failed")) |
|
|||
272 |
|
||||
273 |
|
||||
274 | class SettingsForm(NeboardForm): |
|
231 | class SettingsForm(NeboardForm): | |
275 |
|
232 | |||
276 | theme = forms.ChoiceField(choices=settings.THEMES, |
|
233 | theme = forms.ChoiceField(choices=settings.THEMES, |
@@ -17,7 +17,7 b' class Migration(DataMigration):' | |||||
17 | thread.replies.add(post) |
|
17 | thread.replies.add(post) | |
18 | post.thread_new = thread |
|
18 | post.thread_new = thread | |
19 | post.save() |
|
19 | post.save() | |
20 |
print |
|
20 | print(str(post.thread_new.id)) | |
21 |
|
21 | |||
22 | for reply in post.replies.all(): |
|
22 | for reply in post.replies.all(): | |
23 | thread.replies.add(reply) |
|
23 | thread.replies.add(reply) |
@@ -36,7 +36,7 b" NO_IP = '0.0.0.0'" | |||||
36 | # TODO Real user agent should be saved instead of this |
|
36 | # TODO Real user agent should be saved instead of this | |
37 | UNKNOWN_UA = '' |
|
37 | UNKNOWN_UA = '' | |
38 |
|
38 | |||
39 |
REGEX_REPLY = re.compile( |
|
39 | REGEX_REPLY = re.compile(r'\[post\](\d+)\[/post\]') | |
40 |
|
40 | |||
41 | logger = logging.getLogger(__name__) |
|
41 | logger = logging.getLogger(__name__) | |
42 |
|
42 | |||
@@ -48,6 +48,9 b' class PostManager(models.Manager):' | |||||
48 | Creates new post |
|
48 | Creates new post | |
49 | """ |
|
49 | """ | |
50 |
|
50 | |||
|
51 | if not tags: | |||
|
52 | tags = [] | |||
|
53 | ||||
51 | posting_time = timezone.now() |
|
54 | posting_time = timezone.now() | |
52 | if not thread: |
|
55 | if not thread: | |
53 | thread = Thread.objects.create(bump_time=posting_time, |
|
56 | thread = Thread.objects.create(bump_time=posting_time, | |
@@ -75,8 +78,7 b' class PostManager(models.Manager):' | |||||
75 | post.id)) |
|
78 | post.id)) | |
76 |
|
79 | |||
77 | thread.replies.add(post) |
|
80 | thread.replies.add(post) | |
78 | if tags: |
|
81 | list(map(thread.add_tag, tags)) | |
79 | map(thread.add_tag, tags) |
|
|||
80 |
|
82 | |||
81 | if new_thread: |
|
83 | if new_thread: | |
82 | Thread.objects.process_oldest_threads() |
|
84 | Thread.objects.process_oldest_threads() | |
@@ -112,7 +114,8 b' class PostManager(models.Manager):' | |||||
112 | """ |
|
114 | """ | |
113 |
|
115 | |||
114 | posts = self.filter(poster_ip=ip) |
|
116 | posts = self.filter(poster_ip=ip) | |
115 |
|
|
117 | for post in posts: | |
|
118 | self.delete_post(post) | |||
116 |
|
119 | |||
117 | def connect_replies(self, post): |
|
120 | def connect_replies(self, post): | |
118 | """ |
|
121 | """ |
@@ -222,13 +222,12 b' blockquote {' | |||||
222 | } |
|
222 | } | |
223 |
|
223 | |||
224 | .multiquote { |
|
224 | .multiquote { | |
225 | border-left: solid 4px #ccc; |
|
|||
226 | padding: 3px; |
|
225 | padding: 3px; | |
227 | display: inline-block; |
|
226 | display: inline-block; | |
228 | background: #222; |
|
227 | background: #222; | |
229 |
border- |
|
228 | border-style: solid; | |
230 | border-top: solid 1px #ccc; |
|
229 | border-width: 1px 1px 1px 4px; | |
231 | border-bottom: solid 1px #ccc; |
|
230 | font-size: 0.9em; | |
232 | } |
|
231 | } | |
233 |
|
232 | |||
234 | .spoiler { |
|
233 | .spoiler { |
@@ -182,10 +182,6 b' class PagesTest(TestCase):' | |||||
182 |
|
182 | |||
183 | class FormTest(TestCase): |
|
183 | class FormTest(TestCase): | |
184 | def test_post_validation(self): |
|
184 | def test_post_validation(self): | |
185 | # Disable captcha for the test |
|
|||
186 | captcha_enabled = neboard.settings.ENABLE_CAPTCHA |
|
|||
187 | neboard.settings.ENABLE_CAPTCHA = False |
|
|||
188 |
|
||||
189 | client = Client() |
|
185 | client = Client() | |
190 |
|
186 | |||
191 | valid_tags = u'tag1 tag_2 тег_3' |
|
187 | valid_tags = u'tag1 tag_2 тег_3' | |
@@ -222,9 +218,6 b' class FormTest(TestCase):' | |||||
222 | self.assertEqual(2, Post.objects.count(), |
|
218 | self.assertEqual(2, Post.objects.count(), | |
223 | msg=u'No posts were created') |
|
219 | msg=u'No posts were created') | |
224 |
|
220 | |||
225 | # Restore captcha setting |
|
|||
226 | settings.ENABLE_CAPTCHA = captcha_enabled |
|
|||
227 |
|
||||
228 |
|
221 | |||
229 | class ViewTest(TestCase): |
|
222 | class ViewTest(TestCase): | |
230 |
|
223 | |||
@@ -248,7 +241,7 b' class ViewTest(TestCase):' | |||||
248 | except NoReverseMatch: |
|
241 | except NoReverseMatch: | |
249 | # This view just needs additional arguments |
|
242 | # This view just needs additional arguments | |
250 | pass |
|
243 | pass | |
251 |
except Exception |
|
244 | except Exception as e: | |
252 | self.fail('Got exception %s at %s view' % (e, view_name)) |
|
245 | self.fail('Got exception %s at %s view' % (e, view_name)) | |
253 | except AttributeError: |
|
246 | except AttributeError: | |
254 | # This is normal, some views do not have names |
|
247 | # This is normal, some views do not have names |
@@ -8,7 +8,7 b' from django.db.models import ImageField' | |||||
8 | from django.db.models.fields.files import ImageFieldFile |
|
8 | from django.db.models.fields.files import ImageFieldFile | |
9 | from PIL import Image |
|
9 | from PIL import Image | |
10 | from django.core.files.base import ContentFile |
|
10 | from django.core.files.base import ContentFile | |
11 |
import |
|
11 | import io | |
12 |
|
12 | |||
13 |
|
13 | |||
14 | def generate_thumb(img, thumb_size, format): |
|
14 | def generate_thumb(img, thumb_size, format): | |
@@ -51,13 +51,13 b' def generate_thumb(img, thumb_size, form' | |||||
51 | image2 = image |
|
51 | image2 = image | |
52 | image2.thumbnail(thumb_size, Image.ANTIALIAS) |
|
52 | image2.thumbnail(thumb_size, Image.ANTIALIAS) | |
53 |
|
53 | |||
54 | io = cStringIO.StringIO() |
|
54 | output = io.BytesIO() | |
55 | # PNG and GIF are the same, JPG is JPEG |
|
55 | # PNG and GIF are the same, JPG is JPEG | |
56 | if format.upper() == 'JPG': |
|
56 | if format.upper() == 'JPG': | |
57 | format = 'JPEG' |
|
57 | format = 'JPEG' | |
58 |
|
58 | |||
59 |
image2.save( |
|
59 | image2.save(output, format) | |
60 |
return ContentFile( |
|
60 | return ContentFile(output.getvalue()) | |
61 |
|
61 | |||
62 |
|
62 | |||
63 | class ImageWithThumbsFieldFile(ImageFieldFile): |
|
63 | class ImageWithThumbsFieldFile(ImageFieldFile): |
@@ -45,7 +45,6 b" urlpatterns = patterns(''," | |||||
45 |
|
45 | |||
46 | url(r'^settings/$', settings.SettingsView.as_view(), name='settings'), |
|
46 | url(r'^settings/$', settings.SettingsView.as_view(), name='settings'), | |
47 | url(r'^tags/$', all_tags.AllTagsView.as_view(), name='tags'), |
|
47 | url(r'^tags/$', all_tags.AllTagsView.as_view(), name='tags'), | |
48 | url(r'^captcha/', include('captcha.urls')), |
|
|||
49 | url(r'^authors/$', AuthorsView.as_view(), name='authors'), |
|
48 | url(r'^authors/$', AuthorsView.as_view(), name='authors'), | |
50 | url(r'^delete/(?P<post_id>\w+)/$', DeletePostView.as_view(), |
|
49 | url(r'^delete/(?P<post_id>\w+)/$', DeletePostView.as_view(), | |
51 | name='delete'), |
|
50 | name='delete'), |
@@ -39,8 +39,6 b' def need_include_captcha(request):' | |||||
39 | if current_delay < delay_time: |
|
39 | if current_delay < delay_time: | |
40 | enable_captcha = True |
|
40 | enable_captcha = True | |
41 |
|
41 | |||
42 | print 'ENABLING' + str(enable_captcha) |
|
|||
43 |
|
||||
44 | return enable_captcha |
|
42 | return enable_captcha | |
45 |
|
43 | |||
46 |
|
44 | |||
@@ -56,8 +54,6 b' def update_captcha_access(request, passe' | |||||
56 | if KEY_CAPTCHA_DELAY_TIME in request.session |
|
54 | if KEY_CAPTCHA_DELAY_TIME in request.session | |
57 | else settings.CAPTCHA_DEFAULT_SAFE_TIME) |
|
55 | else settings.CAPTCHA_DEFAULT_SAFE_TIME) | |
58 |
|
56 | |||
59 | print "DELAY TIME = " + str(delay_time) |
|
|||
60 |
|
||||
61 | if passed: |
|
57 | if passed: | |
62 | delay_time -= 2 if delay_time >= 7 else 5 |
|
58 | delay_time -= 2 if delay_time >= 7 else 5 | |
63 | else: |
|
59 | else: | |
@@ -79,4 +75,4 b' def get_client_ip(request):' | |||||
79 | def datetime_to_epoch(datetime): |
|
75 | def datetime_to_epoch(datetime): | |
80 | return int(time.mktime(timezone.localtime( |
|
76 | return int(time.mktime(timezone.localtime( | |
81 | datetime,timezone.get_current_timezone()).timetuple()) |
|
77 | datetime,timezone.get_current_timezone()).timetuple()) | |
82 | * 1000000 + datetime.microsecond) No newline at end of file |
|
78 | * 1000000 + datetime.microsecond) |
@@ -86,7 +86,7 b' class AllThreadsView(PostMixin, BaseBoar' | |||||
86 | if tag_strings: |
|
86 | if tag_strings: | |
87 | tag_strings = tag_strings.split(TAG_DELIMITER) |
|
87 | tag_strings = tag_strings.split(TAG_DELIMITER) | |
88 | for tag_name in tag_strings: |
|
88 | for tag_name in tag_strings: | |
89 |
tag_name = |
|
89 | tag_name = tag_name.strip().lower() | |
90 | if len(tag_name) > 0: |
|
90 | if len(tag_name) > 0: | |
91 | tag, created = Tag.objects.get_or_create(name=tag_name) |
|
91 | tag, created = Tag.objects.get_or_create(name=tag_name) | |
92 | tags.append(tag) |
|
92 | tags.append(tag) | |
@@ -115,7 +115,7 b' class AllThreadsView(PostMixin, BaseBoar' | |||||
115 |
|
115 | |||
116 | text = self._remove_invalid_links(text) |
|
116 | text = self._remove_invalid_links(text) | |
117 |
|
117 | |||
118 | if FORM_IMAGE in data.keys(): |
|
118 | if FORM_IMAGE in list(data.keys()): | |
119 | image = data[FORM_IMAGE] |
|
119 | image = data[FORM_IMAGE] | |
120 | else: |
|
120 | else: | |
121 | image = None |
|
121 | image = None |
@@ -7,6 +7,7 b' from django.shortcuts import get_object_' | |||||
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 | from django.template.loader import render_to_string | |||
10 |
|
11 | |||
11 | from boards.forms import PostForm, PlainErrorList |
|
12 | from boards.forms import PostForm, PlainErrorList | |
12 | from boards.models import Post, Thread, Tag |
|
13 | from boards.models import Post, Thread, Tag | |
@@ -219,7 +220,14 b' def api_get_post(request, post_id):' | |||||
219 | def _get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None, |
|
220 | def _get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None, | |
220 | include_last_update=False): |
|
221 | include_last_update=False): | |
221 | if format_type == DIFF_TYPE_HTML: |
|
222 | if format_type == DIFF_TYPE_HTML: | |
222 | return get_post(request, post_id).content.strip() |
|
223 | post = get_object_or_404(Post, id=post_id) | |
|
224 | ||||
|
225 | context = RequestContext(request) | |||
|
226 | context['post'] = post | |||
|
227 | if PARAMETER_TRUNCATED in request.GET: | |||
|
228 | context[PARAMETER_TRUNCATED] = True | |||
|
229 | ||||
|
230 | return render_to_string('boards/api_post.html', context) | |||
223 | elif format_type == DIFF_TYPE_JSON: |
|
231 | elif format_type == DIFF_TYPE_JSON: | |
224 | post = get_object_or_404(Post, id=post_id) |
|
232 | post = get_object_or_404(Post, id=post_id) | |
225 | post_json = { |
|
233 | post_json = { |
@@ -119,7 +119,7 b' class ThreadView(BaseBoardView, PostMixi' | |||||
119 |
|
119 | |||
120 | text = self._remove_invalid_links(text) |
|
120 | text = self._remove_invalid_links(text) | |
121 |
|
121 | |||
122 | if FORM_IMAGE in data.keys(): |
|
122 | if FORM_IMAGE in list(data.keys()): | |
123 | image = data[FORM_IMAGE] |
|
123 | image = data[FORM_IMAGE] | |
124 | else: |
|
124 | else: | |
125 | image = None |
|
125 | image = None |
@@ -1,1 +0,0 b'' | |||||
1 | import settings No newline at end of file |
|
@@ -148,8 +148,6 b' INSTALLED_APPS = (' | |||||
148 | 'south', |
|
148 | 'south', | |
149 | 'debug_toolbar', |
|
149 | 'debug_toolbar', | |
150 |
|
150 | |||
151 | 'captcha', |
|
|||
152 |
|
||||
153 | # Search |
|
151 | # Search | |
154 | 'haystack', |
|
152 | 'haystack', | |
155 |
|
153 | |||
@@ -168,11 +166,6 b' DEBUG_TOOLBAR_PANELS = (' | |||||
168 | 'debug_toolbar.panels.logger.LoggingPanel', |
|
166 | 'debug_toolbar.panels.logger.LoggingPanel', | |
169 | ) |
|
167 | ) | |
170 |
|
168 | |||
171 | # TODO: NEED DESIGN FIXES |
|
|||
172 | CAPTCHA_OUTPUT_FORMAT = (u' %(hidden_field)s ' |
|
|||
173 | u'<div class="form-label">%(image)s</div>' |
|
|||
174 | u'<div class="form-text">%(text_field)s</div>') |
|
|||
175 |
|
||||
176 | # A sample logging configuration. The only tangible logging |
|
169 | # A sample logging configuration. The only tangible logging | |
177 | # performed by this configuration is to send an email to |
|
170 | # performed by this configuration is to send an email to | |
178 | # the site admins on every HTTP 500 error when DEBUG=False. |
|
171 | # the site admins on every HTTP 500 error when DEBUG=False. | |
@@ -229,9 +222,6 b' THEMES = [' | |||||
229 |
|
222 | |||
230 | POPULAR_TAGS = 10 |
|
223 | POPULAR_TAGS = 10 | |
231 |
|
224 | |||
232 | ENABLE_CAPTCHA = False |
|
|||
233 | # if user tries to post before CAPTCHA_DEFAULT_SAFE_TIME. Captcha will be shown |
|
|||
234 | CAPTCHA_DEFAULT_SAFE_TIME = 30 # seconds |
|
|||
235 | POSTING_DELAY = 20 # seconds |
|
225 | POSTING_DELAY = 20 # seconds | |
236 |
|
226 | |||
237 | COMPRESS_HTML = True |
|
227 | COMPRESS_HTML = True | |
@@ -239,7 +229,7 b' COMPRESS_HTML = True' | |||||
239 | # Debug mode middlewares |
|
229 | # Debug mode middlewares | |
240 | if DEBUG: |
|
230 | if DEBUG: | |
241 | MIDDLEWARE_CLASSES += ( |
|
231 | MIDDLEWARE_CLASSES += ( | |
242 | 'boards.profiler.ProfilerMiddleware', |
|
232 | #'boards.profiler.ProfilerMiddleware', | |
243 | 'debug_toolbar.middleware.DebugToolbarMiddleware', |
|
233 | 'debug_toolbar.middleware.DebugToolbarMiddleware', | |
244 | ) |
|
234 | ) | |
245 |
|
235 |
General Comments 0
You need to be logged in to leave comments.
Login now