##// END OF EJS Templates
Fixed issues with new images storage
Fixed issues with new images storage

File last commit:

r1553:ea5ac58d default
r1591:af1d8bd1 default
Show More
forms.py
462 lines | 15.0 KiB | text/x-python | PythonLexer
neko259
Use password-hash tripcodes
r1299 import hashlib
neko259
Added a regex for validation of tags. This refs #10
r69 import re
neko259
Added image duplicate check
r527 import time
neko259
Autodetect only a white list of mimetypes
r1372 import logging
neko259
Added PoW instead of 30-second captcha
r1428
neko259
Autodetect only a white list of mimetypes
r1372 import pytz
neko259
Added ability to reset tripcode
r1296
Ilyas
Added creating new thread form...
r14 from django import forms
neko259
Load image from URL (BB-56)
r954 from django.core.files.uploadedfile import SimpleUploadedFile
neko259
Added a form field for additional threads list in multi-thread posts
r1077 from django.core.exceptions import ObjectDoesNotExist
neko259
Rename util module decause it was removed in 1.9
r1483 from django.forms.utils import ErrorList
neko259
Plural in form error
r1333 from django.utils.translation import ugettext_lazy as _, ungettext_lazy
neko259
Added PoW instead of 30-second captcha
r1428 from django.utils import timezone
neko259
Added image duplicate check
r527
neko259
Limit only first posting by this session. Assume messages created by spam bots...
r1494 from boards.abstracts.settingsmanager import get_settings_manager
neko259
Added image aliases to upload the same images (like "fake" or "gtfo")
r1500 from boards.abstracts.attachment_alias import get_image_by_alias
neko259
Added a new format panel to the text form
r438 from boards.mdx_neboard import formatters
neko259
Download attached filed to the post during sync
r1511 from boards.models.attachment.downloaders import download
neko259
Split up user models
r386 from boards.models.post import TITLE_MAX_LENGTH
neko259
Added a form field for additional threads list in multi-thread posts
r1077 from boards.models import Tag, Post
neko259
Get mimetype for file in the form and use it for both images and attachments
r1371 from boards.utils import validate_file_size, get_file_mimetype, \
FILE_EXTENSION_DELIMITER
neko259
Added themes support. Added 'snow white' theme by Mystra_x64.
r35 from neboard import settings
neko259
Moved some settings to boards.settings
r333 import boards.settings as board_settings
neko259
Use password-hash tripcodes
r1299 import neboard
neko259
Added form validation, added style for the tag panel. This fixes #13
r76
neko259
Added PoW instead of 30-second captcha
r1428 POW_HASH_LENGTH = 16
neko259
Extend PoW lifetime to 5 mins
r1447 POW_LIFE_MINUTES = 5
neko259
Added PoW instead of 30-second captcha
r1428
neko259
Removed old forms, refactored some code for forms and images. Use the same code to compute hash of an image in form and when saving image
r937 REGEX_TAGS = re.compile(r'^[\w\s\d]+$', re.UNICODE)
neko259
Subscribe to a multiple of users for notifications
r1429 REGEX_USERNAMES = re.compile(r'^[\w\s\d,]+$', re.UNICODE)
neko259
Removed old forms, refactored some code for forms and images. Use the same code to compute hash of an image in form and when saving image
r937
neko259
Added veterans (old users). Veterans currently have lower posting speed limit
r642 VETERAN_POSTING_DELAY = 5
neko259
Added placeholders to forms
r517 ATTRIBUTE_PLACEHOLDER = 'placeholder'
neko259
Lower textarea rows count
r1006 ATTRIBUTE_ROWS = 'rows'
neko259
Added placeholders to forms
r517
LAST_POST_TIME = 'last_post_time'
LAST_LOGIN_TIME = 'last_login_time'
neko259
Removed old forms, refactored some code for forms and images. Use the same code to compute hash of an image in form and when saving image
r937 TEXT_PLACEHOLDER = _('Type message here. Use formatting panel for more advanced usage.')
neko259
Refactored post view, added a hint of how to add new tags to favorites
r1093 TAGS_PLACEHOLDER = _('music images i_dont_like_tags')
neko259
Added localizations to forms. Do not allow users without session to post.
r211
neko259
Added image duplicate check
r527 LABEL_TITLE = _('Title')
LABEL_TEXT = _('Text')
neko259
Added post admin page with tags edit capability
r566 LABEL_TAG = _('Tag')
neko259
Use own search form and view
r718 LABEL_SEARCH = _('Search')
neko259
Added post admin page with tags edit capability
r566
neko259
Plural in form error
r1333 ERROR_SPEED = 'Please wait %(delay)d second before sending message'
ERROR_SPEED_PLURAL = 'Please wait %(delay)d seconds before sending message'
neko259
Give a 30 second delay to the user that posts for the first time, because he...
r1105
neko259
Added post admin page with tags edit capability
r566 TAG_MAX_LENGTH = 20
neko259
Lower textarea rows count
r1006 TEXTAREA_ROWS = 4
neko259
Allow to edit tag and post in the admin site
r1367 TRIPCODE_DELIM = '#'
neko259
Autodetect only a white list of mimetypes
r1372 # TODO Maybe this may be converted into the database table?
MIMETYPE_EXTENSIONS = {
'image/jpeg': 'jpeg',
'image/png': 'png',
'image/gif': 'gif',
'video/webm': 'webm',
'application/pdf': 'pdf',
'x-diff': 'diff',
neko259
Recognize svg mimetype
r1373 'image/svg+xml': 'svg',
neko259
Recognize flash mimetype properly. Store extension as mimetype in attachment...
r1382 'application/x-shockwave-flash': 'swf',
neko259
Added max width to tag description in MD style. Recognize bmp extension from...
r1454 'image/x-ms-bmp': 'bmp',
'image/bmp': 'bmp',
neko259
Autodetect only a white list of mimetypes
r1372 }
neko259
Implemented posting delay. User must wait some time before posting (a measure against flood).
r153
neko259
Added timezone support (time zone is selected in settings)
r1065 def get_timezones():
timezones = []
for tz in pytz.common_timezones:
timezones.append((tz, tz),)
return timezones
neko259
Added a new format panel to the text form
r438 class FormatPanel(forms.Textarea):
neko259
Removed old forms, refactored some code for forms and images. Use the same code to compute hash of an image in form and when saving image
r937 """
Panel for text formatting. Consists of buttons to add different tags to the
form text area.
"""
neko259
Added a new format panel to the text form
r438 def render(self, name, value, attrs=None):
output = '<div id="mark-panel">'
for formatter in formatters:
neko259
Removed 'u' that was indicating a unicode string
r769 output += '<span class="mark_btn"' + \
' onClick="addMarkToMsg(\'' + formatter.format_left + \
neko259
Added a new format panel to the text form
r438 '\', \'' + formatter.format_right + '\')">' + \
formatter.preview_left + formatter.name + \
neko259
Removed 'u' that was indicating a unicode string
r769 formatter.preview_right + '</span>'
neko259
Added a new format panel to the text form
r438
output += '</div>'
neko259
Pass textarea attributes to fix w3c validation of label
r1408 output += super(FormatPanel, self).render(name, value, attrs=attrs)
neko259
Added a new format panel to the text form
r438
return output
neko259
Added form validation, added style for the tag panel. This fixes #13
r76 class PlainErrorList(ErrorList):
def __unicode__(self):
return self.as_text()
def as_text(self):
neko259
Removed 'u' that was indicating a unicode string
r769 return ''.join(['(!) %s ' % e for e in self])
neko259
Added form validation, added style for the tag panel. This fixes #13
r76
neko259
Added a text area to the posting form. Added a basic CSS style. Changed threads list a bit.
r16
neko259
Added ability to disable moderator panel. Refactored forms code. Translating forms.
r205 class NeboardForm(forms.Form):
neko259
Removed old forms, refactored some code for forms and images. Use the same code to compute hash of an image in form and when saving image
r937 """
Form with neboard-specific formatting.
"""
neko259
Added ability to disable moderator panel. Refactored forms code. Translating forms.
r205
neko259
Small style and forms rendering changes
r426 def as_div(self):
neko259
Added a new format panel to the text form
r438 """
Returns this form rendered as HTML <as_div>s.
"""
neko259
Added ability to disable moderator panel. Refactored forms code. Translating forms.
r205 return self._html_output(
neko259
Basic support for the generic forms. Still need to fix some things in the form...
r425 # TODO Do not show hidden rows in the list here
neko259
Show labels and inputs of rorms in one line
r1132 normal_row='<div class="form-row">'
'<div class="form-label">'
neko259
Added ability to disable moderator panel. Refactored forms code. Translating forms.
r205 '%(label)s'
neko259
Show labels and inputs of rorms in one line
r1132 '</div>'
'<div class="form-input">'
neko259
Added ability to disable moderator panel. Refactored forms code. Translating forms.
r205 '%(field)s'
neko259
Show labels and inputs of rorms in one line
r1132 '</div>'
'</div>'
neko259
Updated form to a new style. Fixed mark manel
r680 '<div class="form-row">'
neko259
Added ability to disable moderator panel. Refactored forms code. Translating forms.
r205 '%(help_text)s'
'</div>',
neko259
Small style and forms rendering changes
r426 error_row='<div class="form-row">'
'<div class="form-label"></div>'
'<div class="form-errors">%s</div>'
'</div>',
row_ender='</div>',
help_text_html='%s',
neko259
Added ability to disable moderator panel. Refactored forms code. Translating forms.
r205 errors_on_separate_row=True)
neko259
Added posting over ajax
r533 def as_json_errors(self):
errors = []
neko259
Some additional improvements from 2to3
r771 for name, field in list(self.fields.items()):
neko259
Added posting over ajax
r533 if self[name].errors:
errors.append({
'field': name,
'errors': self[name].errors.as_text(),
})
return errors
neko259
Added a new format panel to the text form
r438
neko259
Added ability to disable moderator panel. Refactored forms code. Translating forms.
r205 class PostForm(NeboardForm):
neko259
Added form validation, added style for the tag panel. This fixes #13
r76
neko259
Added some labels to the forms.
r232 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False,
neko259
Use password-hash tripcodes
r1299 label=LABEL_TITLE,
widget=forms.TextInput(
attrs={ATTRIBUTE_PLACEHOLDER:
'test#tripcode'}))
neko259
Added placeholders to forms
r517 text = forms.CharField(
neko259
Lower textarea rows count
r1006 widget=FormatPanel(attrs={
ATTRIBUTE_PLACEHOLDER: TEXT_PLACEHOLDER,
ATTRIBUTE_ROWS: TEXTAREA_ROWS,
}),
neko259
Added image duplicate check
r527 required=False, label=LABEL_TEXT)
neko259
Added support for different attachment types
r1273 file = forms.FileField(required=False, label=_('File'),
neko259
Small code cleanups
r721 widget=forms.ClearableFileInput(
neko259
Added support for different attachment types
r1273 attrs={'accept': 'file/*'}))
file_url = forms.CharField(required=False, label=_('File URL'),
neko259
Load image from URL (BB-56)
r954 widget=forms.TextInput(
attrs={ATTRIBUTE_PLACEHOLDER:
'http://example.com/image.png'}))
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29
neko259
Added a hidden antispam field to the forms.
r207 # This field is for spam prevention only
neko259
Added some labels to the forms.
r232 email = forms.CharField(max_length=100, required=False, label=_('e-mail'),
widget=forms.TextInput(attrs={
'class': 'form-email'}))
neko259
Added a form field for additional threads list in multi-thread posts
r1077 threads = forms.CharField(required=False, label=_('Additional threads'),
widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER:
'123 456 789'}))
neko259
Added a hidden antispam field to the forms.
r207
neko259
Added PoW instead of 30-second captcha
r1428 guess = forms.CharField(widget=forms.HiddenInput(), required=False)
timestamp = forms.CharField(widget=forms.HiddenInput(), required=False)
iteration = forms.CharField(widget=forms.HiddenInput(), required=False)
neko259
Implemented posting delay. User must wait some time before posting (a measure against flood).
r153 session = None
neko259
Added autoban by the hidden field (to ban spammers and prevent them from trying to post anything).
r271 need_to_ban = False
neko259
Added image aliases to upload the same images (like "fake" or "gtfo")
r1500 image = None
neko259
Implemented posting delay. User must wait some time before posting (a measure against flood).
r153
neko259
Get mimetype for file in the form and use it for both images and attachments
r1371 def _update_file_extension(self, file):
if file:
neko259
Autodetect only a white list of mimetypes
r1372 mimetype = get_file_mimetype(file)
extension = MIMETYPE_EXTENSIONS.get(mimetype)
if extension:
filename = file.name.split(FILE_EXTENSION_DELIMITER, 1)[0]
new_filename = filename + FILE_EXTENSION_DELIMITER + extension
neko259
Get mimetype for file in the form and use it for both images and attachments
r1371
neko259
Autodetect only a white list of mimetypes
r1372 file.name = new_filename
else:
logger = logging.getLogger('boards.forms.extension')
logger.info('Unrecognized file mimetype: {}'.format(mimetype))
neko259
Get mimetype for file in the form and use it for both images and attachments
r1371
neko259
Added form validation, added style for the tag panel. This fixes #13
r76 def clean_title(self):
title = self.cleaned_data['title']
if title:
if len(title) > TITLE_MAX_LENGTH:
neko259
Added localizations to forms. Do not allow users without session to post.
r211 raise forms.ValidationError(_('Title must have less than %s '
'characters') %
str(TITLE_MAX_LENGTH))
neko259
Added form validation, added style for the tag panel. This fixes #13
r76 return title
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29 def clean_text(self):
neko259
Strip text and tags before saving
r678 text = self.cleaned_data['text'].strip()
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29 if text:
neko259
Implemented ini settings parser
r1153 max_length = board_settings.get_int('Forms', 'MaxTextLength')
if len(text) > max_length:
neko259
Added localizations to forms. Do not allow users without session to post.
r211 raise forms.ValidationError(_('Text must have less than %s '
neko259
Implemented ini settings parser
r1153 'characters') % str(max_length))
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29 return text
neko259
Added support for different attachment types
r1273 def clean_file(self):
file = self.cleaned_data['file']
neko259
Load image from URL (BB-56)
r954
neko259
Added support for different attachment types
r1273 if file:
neko259
Download webm videos from youtube
r1328 validate_file_size(file.size)
neko259
Get mimetype for file in the form and use it for both images and attachments
r1371 self._update_file_extension(file)
neko259
Load image from URL (BB-56)
r954
neko259
Added support for different attachment types
r1273 return file
neko259
Load image from URL (BB-56)
r954
neko259
Added support for different attachment types
r1273 def clean_file_url(self):
url = self.cleaned_data['file_url']
neko259
Load image from URL (BB-56)
r954
neko259
Added support for different attachment types
r1273 file = None
neko259
Added image aliases to upload the same images (like "fake" or "gtfo")
r1500
neko259
Load image from URL (BB-56)
r954 if url:
neko259
Added image aliases to upload the same images (like "fake" or "gtfo")
r1500 file = get_image_by_alias(url, self.session)
self.image = file
neko259
Load image from URL (BB-56)
r954
neko259
Added image aliases to upload the same images (like "fake" or "gtfo")
r1500 if file is not None:
return
if file is None:
file = self._get_file_from_url(url)
if not file:
raise forms.ValidationError(_('Invalid URL'))
else:
validate_file_size(file.size)
neko259
Get mimetype for file in the form and use it for both images and attachments
r1371 self._update_file_extension(file)
neko259
Added image duplicate check
r527
neko259
Added support for different attachment types
r1273 return file
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29
neko259
Added a form field for additional threads list in multi-thread posts
r1077 def clean_threads(self):
threads_str = self.cleaned_data['threads']
if len(threads_str) > 0:
threads_id_list = threads_str.split(' ')
threads = list()
for thread_id in threads_id_list:
try:
thread = Post.objects.get(id=int(thread_id))
neko259
Thread status field instead of bumpable and archived fields (per BB-73)
r1414 if not thread.is_opening() or thread.get_thread().is_archived():
neko259
Added a form field for additional threads list in multi-thread posts
r1077 raise ObjectDoesNotExist()
threads.append(thread)
except (ObjectDoesNotExist, ValueError):
raise forms.ValidationError(_('Invalid additional thread list'))
return threads
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29 def clean(self):
cleaned_data = super(PostForm, self).clean()
neko259
Added localizations to forms. Do not allow users without session to post.
r211 if cleaned_data['email']:
neko259
Added autoban by the hidden field (to ban spammers and prevent them from trying to post anything).
r271 self.need_to_ban = True
neko259
Added localizations to forms. Do not allow users without session to post.
r211 raise forms.ValidationError('A human cannot enter a hidden field')
neko259
Added a hidden antispam field to the forms.
r207
neko259
Fixed validation message. 'text or image must be entered' was shown instead of the read one.
r151 if not self.errors:
neko259
Added support for different attachment types
r1273 self._clean_text_file()
neko259
Fixed validation of image without text. This refs #13
r77
neko259
Added PoW instead of 30-second captcha
r1428 limit_speed = board_settings.get_bool('Forms', 'LimitPostingSpeed')
neko259
Limit only first posting by this session. Assume messages created by spam bots...
r1494
settings_manager = get_settings_manager(self)
if not self.errors and limit_speed and not settings_manager.get_setting('confirmed_user'):
neko259
Added PoW instead of 30-second captcha
r1428 pow_difficulty = board_settings.get_int('Forms', 'PowDifficulty')
neko259
Limit only first posting by this session. Assume messages created by spam bots...
r1494 if pow_difficulty > 0:
# Limit only first post
if cleaned_data['timestamp'] \
and cleaned_data['iteration'] and cleaned_data['guess'] \
and not settings_manager.get_setting('confirmed_user'):
self._validate_hash(cleaned_data['timestamp'], cleaned_data['iteration'], cleaned_data['guess'], cleaned_data['text'])
neko259
Added PoW instead of 30-second captcha
r1428 else:
neko259
Limit only first posting by this session. Assume messages created by spam bots...
r1494 # Limit every post
neko259
Added PoW instead of 30-second captcha
r1428 self._validate_posting_speed()
neko259
Limit only first posting by this session. Assume messages created by spam bots...
r1494 settings_manager.set_setting('confirmed_user', True)
neko259
Implemented posting delay. User must wait some time before posting (a measure against flood).
r153
neko259
Added form validation, added style for the tag panel. This fixes #13
r76 return cleaned_data
neko259
Added support for different attachment types
r1273 def get_file(self):
neko259
Load image from URL (BB-56)
r954 """
neko259
Added support for different attachment types
r1273 Gets file from form or URL.
neko259
Load image from URL (BB-56)
r954 """
neko259
Added support for different attachment types
r1273 file = self.cleaned_data['file']
return file or self.cleaned_data['file_url']
neko259
Load image from URL (BB-56)
r954
neko259
Added tripcodes
r1293 def get_tripcode(self):
neko259
Use password-hash tripcodes
r1299 title = self.cleaned_data['title']
neko259
Allow to edit tag and post in the admin site
r1367 if title is not None and TRIPCODE_DELIM in title:
code = title.split(TRIPCODE_DELIM, maxsplit=1)[1] + neboard.settings.SECRET_KEY
tripcode = hashlib.md5(code.encode()).hexdigest()
else:
tripcode = ''
return tripcode
neko259
Use password-hash tripcodes
r1299
def get_title(self):
title = self.cleaned_data['title']
neko259
Allow to edit tag and post in the admin site
r1367 if title is not None and TRIPCODE_DELIM in title:
return title.split(TRIPCODE_DELIM, maxsplit=1)[0]
neko259
Use password-hash tripcodes
r1299 else:
return title
neko259
Added tripcodes
r1293
neko259
Added image aliases to upload the same images (like "fake" or "gtfo")
r1500 def get_images(self):
if self.image:
return [self.image]
else:
return []
neko259
Added support for different attachment types
r1273 def _clean_text_file(self):
neko259
Added form validation, added style for the tag panel. This fixes #13
r76 text = self.cleaned_data.get('text')
neko259
Added support for different attachment types
r1273 file = self.get_file()
neko259
Added image aliases to upload the same images (like "fake" or "gtfo")
r1500 images = self.get_images()
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29
neko259
Added image aliases to upload the same images (like "fake" or "gtfo")
r1500 if (not text) and (not file) and len(images) == 0:
neko259
Added support for different attachment types
r1273 error_message = _('Either text or file must be entered.')
neko259
Fixed validation of image without text. This refs #13
r77 self._errors['text'] = self.error_class([error_message])
neko259
Implemented posting delay. User must wait some time before posting (a measure against flood).
r153
def _validate_posting_speed(self):
can_post = True
neko259
Removed user and settings mode. Added settings manager to manage settings and keep them in the session (or any other backend like cookie in the future
r728 posting_delay = settings.POSTING_DELAY
neko259
Added veterans (old users). Veterans currently have lower posting speed limit
r642
neko259
Implemented ini settings parser
r1153 if board_settings.get_bool('Forms', 'LimitPostingSpeed'):
neko259
Implemented posting delay. User must wait some time before posting (a measure against flood).
r153 now = time.time()
neko259
Give a 30 second delay to the user that posts for the first time, because he...
r1105
current_delay = 0
neko259
Plural in form error
r1333 if LAST_POST_TIME not in self.session:
neko259
Give a 30 second delay to the user that posts for the first time, because he...
r1105 self.session[LAST_POST_TIME] = now
neko259
Implemented posting delay. User must wait some time before posting (a measure against flood).
r153
neko259
Give a 30 second delay to the user that posts for the first time, because he...
r1105 need_delay = True
else:
last_post_time = self.session.get(LAST_POST_TIME)
current_delay = int(now - last_post_time)
neko259
Implemented posting delay. User must wait some time before posting (a measure against flood).
r153
neko259
Give a 30 second delay to the user that posts for the first time, because he...
r1105 need_delay = current_delay < posting_delay
if need_delay:
neko259
Plural in form error
r1333 delay = posting_delay - current_delay
error_message = ungettext_lazy(ERROR_SPEED, ERROR_SPEED_PLURAL,
delay) % {'delay': delay}
neko259
Implemented posting delay. User must wait some time before posting (a measure against flood).
r153 self._errors['text'] = self.error_class([error_message])
can_post = False
neko259
Show moderator controls when downloading a single post over API. Removed duplicate code from get_post_data
r1109 if can_post:
self.session[LAST_POST_TIME] = now
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29
neko259
Added support for different attachment types
r1273 def _get_file_from_url(self, url: str) -> SimpleUploadedFile:
neko259
Load image from URL (BB-56)
r954 """
neko259
Added support for different attachment types
r1273 Gets an file file from URL.
neko259
Load image from URL (BB-56)
r954 """
try:
neko259
Fixed image downloading
r1553 return download(url)
neko259
Download webm videos from youtube
r1328 except forms.ValidationError as e:
raise e
neko259
Fixed upload from url
r1276 except Exception as e:
neko259
Added support for youtu.be links. Show file size when size validation failed
r1433 raise forms.ValidationError(e)
neko259
Load image from URL (BB-56)
r954
neko259
Added PoW instead of 30-second captcha
r1428 def _validate_hash(self, timestamp: str, iteration: str, guess: str, message: str):
post_time = timezone.datetime.fromtimestamp(
int(timestamp[:-3]), tz=timezone.get_current_timezone())
payload = timestamp + message.replace('\r\n', '\n')
difficulty = board_settings.get_int('Forms', 'PowDifficulty')
target = str(int(2 ** (POW_HASH_LENGTH * 3) / difficulty))
if len(target) < POW_HASH_LENGTH:
target = '0' * (POW_HASH_LENGTH - len(target)) + target
computed_guess = hashlib.sha256((payload + iteration).encode())\
.hexdigest()[0:POW_HASH_LENGTH]
if guess != computed_guess or guess > target:
self._errors['text'] = self.error_class(
[_('Invalid PoW.')])
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29
neko259
Limit only first posting by this session. Assume messages created by spam bots...
r1494
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29 class ThreadForm(PostForm):
neko259
Added some labels to the forms.
r232
neko259
Added placeholders to forms
r517 tags = forms.CharField(
widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}),
neko259
Disallow threads with space-only tags
r679 max_length=100, label=_('Tags'), required=True)
neko259
Added ability to create monochrome threads
r1434 monochrome = forms.BooleanField(label=_('Monochrome'), required=False)
neko259
Changed metadata design. Make space split tags.
r31
def clean_tags(self):
neko259
Strip text and tags before saving
r678 tags = self.cleaned_data['tags'].strip()
neko259
Added a regex for validation of tags. This refs #10
r69
neko259
Removed old forms, refactored some code for forms and images. Use the same code to compute hash of an image in form and when saving image
r937 if not tags or not REGEX_TAGS.match(tags):
neko259
Disallow threads with space-only tags
r679 raise forms.ValidationError(
_('Inappropriate characters in tags.'))
neko259
Changed metadata design. Make space split tags.
r31
neko259
Added required tags. At least one such tag is needed to create a thread. All...
r922 required_tag_exists = False
neko259
Added categories -- a redesign of old-style linked tags, a tree-based...
r1348 tag_set = set()
for tag_string in tags.split():
tag, created = Tag.objects.get_or_create(name=tag_string.strip().lower())
tag_set.add(tag)
# If this is a new tag, don't check for its parents because nobody
# added them yet
if not created:
neko259
Show all tag parents at the tag page
r1361 tag_set |= set(tag.get_all_parents())
neko259
Added categories -- a redesign of old-style linked tags, a tree-based...
r1348
for tag in tag_set:
if tag.required:
neko259
Don't use natural time because it does not update itself on the client. Fixed...
r1102 required_tag_exists = True
neko259
Removed old forms, refactored some code for forms and images. Use the same code to compute hash of an image in form and when saving image
r937 break
neko259
Added required tags. At least one such tag is needed to create a thread. All...
r922
if not required_tag_exists:
neko259
Show the list of required tags when non was entered at thread creation
r1099 raise forms.ValidationError(
neko259
Don't show list of all sections when none is entered
r1259 _('Need at least one section.'))
neko259
Added required tags. At least one such tag is needed to create a thread. All...
r922
neko259
Added categories -- a redesign of old-style linked tags, a tree-based...
r1348 return tag_set
neko259
Changed metadata design. Make space split tags.
r31
def clean(self):
cleaned_data = super(ThreadForm, self).clean()
neko259
Added themes support. Added 'snow white' theme by Mystra_x64.
r35 return cleaned_data
neko259
Added ability to create monochrome threads
r1434 def is_monochrome(self):
return self.cleaned_data['monochrome']
neko259
Added themes support. Added 'snow white' theme by Mystra_x64.
r35
neko259
Added ability to disable moderator panel. Refactored forms code. Translating forms.
r205 class SettingsForm(NeboardForm):
neko259
Added timezone support (time zone is selected in settings)
r1065 theme = forms.ChoiceField(choices=settings.THEMES, label=_('Theme'))
neko259
Added ability to reset tripcode
r1296 image_viewer = forms.ChoiceField(choices=settings.IMAGE_VIEWERS, label=_('Image view mode'))
neko259
User notifications (BB-59)
r990 username = forms.CharField(label=_('User name'), required=False)
neko259
Added timezone support (time zone is selected in settings)
r1065 timezone = forms.ChoiceField(choices=get_timezones(), label=_('Time zone'))
neko259
Added login functionality.
r144
neko259
Don't allow characters in username that we cannot use as a URL
r995 def clean_username(self):
username = self.cleaned_data['username']
neko259
Subscribe to a multiple of users for notifications
r1429 if username and not REGEX_USERNAMES.match(username):
neko259
Don't allow characters in username that we cannot use as a URL
r995 raise forms.ValidationError(_('Inappropriate characters.'))
return username
neko259
Added login functionality.
r144
neko259
Use own search form and view
r718 class SearchForm(NeboardForm):
neko259
Added login and logout for moderators
r729 query = forms.CharField(max_length=500, label=LABEL_SEARCH, required=False)