diff --git a/boards/forms.py b/boards/forms.py --- a/boards/forms.py +++ b/boards/forms.py @@ -4,7 +4,7 @@ from django import forms from django.forms.util import ErrorList from django.utils.translation import ugettext_lazy as _ import time -from boards.models import TITLE_MAX_LENGTH, User +from boards.models.post import TITLE_MAX_LENGTH, User from neboard import settings from boards import utils import boards.settings as board_settings diff --git a/boards/migrations/0005_auto.py b/boards/migrations/0005_auto.py --- a/boards/migrations/0005_auto.py +++ b/boards/migrations/0005_auto.py @@ -3,7 +3,7 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models -from boards.models import Post, NO_PARENT +from boards.models.post import Post, NO_PARENT class Migration(SchemaMigration): diff --git a/boards/models.py b/boards/models.py deleted file mode 100644 --- a/boards/models.py +++ /dev/null @@ -1,461 +0,0 @@ -import os -from random import random -import time -import math -from django.core.cache import cache - -from django.db import models -from django.db.models import Count -from django.http import Http404 -from django.utils import timezone -from markupfield.fields import MarkupField -from boards import settings as board_settings - -from neboard import settings -import thumbs - -import re - -TAG_FONT_MULTIPLIER = 0.2 - -MAX_TAG_FONT = 4 - -BAN_REASON_MAX_LENGTH = 200 - -BAN_REASON_AUTO = 'Auto' - -IMAGE_THUMB_SIZE = (200, 150) - -TITLE_MAX_LENGTH = 50 - -DEFAULT_MARKUP_TYPE = 'markdown' - -NO_PARENT = -1 -NO_IP = '0.0.0.0' -UNKNOWN_UA = '' -ALL_PAGES = -1 -OPENING_POST_POPULARITY_WEIGHT = 2 -IMAGES_DIRECTORY = 'images/' -FILE_EXTENSION_DELIMITER = '.' - -RANK_ADMIN = 0 -RANK_MODERATOR = 10 -RANK_USER = 100 - -SETTING_MODERATE = "moderate" - -REGEX_REPLY = re.compile('>>(\d+)') - - -class PostManager(models.Manager): - - def create_post(self, title, text, image=None, thread=None, - ip=NO_IP, tags=None, user=None): - posting_time = timezone.now() - - post = self.create(title=title, - text=text, - pub_time=posting_time, - thread=thread, - image=image, - poster_ip=ip, - poster_user_agent=UNKNOWN_UA, - last_edit_time=posting_time, - bump_time=posting_time, - user=user) - - if tags: - linked_tags = [] - for tag in tags: - tag_linked_tags = tag.get_linked_tags() - if len(tag_linked_tags) > 0: - linked_tags.extend(tag_linked_tags) - - tags.extend(linked_tags) - map(post.tags.add, tags) - for tag in tags: - tag.threads.add(post) - - if thread: - thread.replies.add(post) - thread.bump() - thread.last_edit_time = posting_time - thread.save() - - #cache_key = thread.get_cache_key() - #cache.delete(cache_key) - - else: - self._delete_old_threads() - - self.connect_replies(post) - - return post - - def delete_post(self, post): - if post.replies.count() > 0: - map(self.delete_post, post.replies.all()) - - # Update thread's last edit time (used as cache key) - thread = post.thread - if thread: - thread.last_edit_time = timezone.now() - thread.save() - - #cache_key = thread.get_cache_key() - #cache.delete(cache_key) - - post.delete() - - def delete_posts_by_ip(self, ip): - posts = self.filter(poster_ip=ip) - map(self.delete_post, posts) - - def get_threads(self, tag=None, page=ALL_PAGES, - order_by='-bump_time'): - if tag: - threads = tag.threads - - if threads.count() == 0: - raise Http404 - else: - threads = self.filter(thread=None) - - threads = threads.order_by(order_by) - - if page != ALL_PAGES: - thread_count = threads.count() - - if page < self._get_page_count(thread_count): - start_thread = page * settings.THREADS_PER_PAGE - end_thread = min(start_thread + settings.THREADS_PER_PAGE, - thread_count) - threads = threads[start_thread:end_thread] - - return threads - - def get_thread(self, opening_post_id): - try: - opening_post = self.get(id=opening_post_id, thread=None) - except Post.DoesNotExist: - raise Http404 - - #cache_key = opening_post.get_cache_key() - #thread = cache.get(cache_key) - #if thread: - # return thread - - if opening_post.replies: - thread = [opening_post] - thread.extend(opening_post.replies.all().order_by('pub_time')) - - #cache.set(cache_key, thread, board_settings.CACHE_TIMEOUT) - - return thread - - def exists(self, post_id): - posts = self.filter(id=post_id) - - return posts.count() > 0 - - def get_thread_page_count(self, tag=None): - if tag: - threads = self.filter(thread=None, tags=tag) - else: - threads = self.filter(thread=None) - - return self._get_page_count(threads.count()) - - def _delete_old_threads(self): - """ - Preserves maximum thread count. If there are too many threads, - delete the old ones. - """ - - # TODO Move old threads to the archive instead of deleting them. - # Maybe make some 'old' field in the model to indicate the thread - # must not be shown and be able for replying. - - threads = self.get_threads() - thread_count = threads.count() - - if thread_count > settings.MAX_THREAD_COUNT: - num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT - old_threads = threads[thread_count - num_threads_to_delete:] - - map(self.delete_post, old_threads) - - def connect_replies(self, post): - """Connect replies to a post to show them as a refmap""" - - for reply_number in re.finditer(REGEX_REPLY, post.text.raw): - post_id = reply_number.group(1) - ref_post = self.filter(id=post_id) - if ref_post.count() > 0: - referenced_post = ref_post[0] - referenced_post.referenced_posts.add(post) - referenced_post.last_edit_time = post.pub_time - referenced_post.save() - - def _get_page_count(self, thread_count): - return int(math.ceil(thread_count / float(settings.THREADS_PER_PAGE))) - - -class TagManager(models.Manager): - - def get_not_empty_tags(self): - tags = self.annotate(Count('threads')) \ - .filter(threads__count__gt=0).order_by('name') - - return tags - - -class Tag(models.Model): - """ - A tag is a text node assigned to the post. The tag serves as a board - section. There can be multiple tags for each message - """ - - objects = TagManager() - - name = models.CharField(max_length=100) - threads = models.ManyToManyField('Post', null=True, - blank=True, related_name='tag+') - linked = models.ForeignKey('Tag', null=True, blank=True) - - def __unicode__(self): - return self.name - - def is_empty(self): - return self.get_post_count() == 0 - - def get_post_count(self): - return self.threads.count() - - def get_popularity(self): - posts_with_tag = Post.objects.get_threads(tag=self) - reply_count = 0 - for post in posts_with_tag: - reply_count += post.get_reply_count() - reply_count += OPENING_POST_POPULARITY_WEIGHT - - return reply_count - - def get_linked_tags(self): - tag_list = [] - self.get_linked_tags_list(tag_list) - - return tag_list - - def get_linked_tags_list(self, tag_list=[]): - """ - Returns the list of tags linked to current. The list can be got - through returned value or tag_list parameter - """ - - linked_tag = self.linked - - if linked_tag and not (linked_tag in tag_list): - tag_list.append(linked_tag) - - linked_tag.get_linked_tags_list(tag_list) - - def get_font_value(self): - """Get tag font value to differ most popular tags in the list""" - - post_count = self.get_post_count() - if post_count > MAX_TAG_FONT: - post_count = MAX_TAG_FONT - - font_value = str(1 + (post_count - 1) * TAG_FONT_MULTIPLIER) - - return font_value - - -class Post(models.Model): - """A post is a message.""" - - objects = PostManager() - - def _update_image_filename(self, filename): - """Get unique image filename""" - - path = IMAGES_DIRECTORY - new_name = str(int(time.mktime(time.gmtime()))) - new_name += str(int(random() * 1000)) - new_name += FILE_EXTENSION_DELIMITER - new_name += filename.split(FILE_EXTENSION_DELIMITER)[-1:][0] - - return os.path.join(path, new_name) - - title = models.CharField(max_length=TITLE_MAX_LENGTH) - pub_time = models.DateTimeField() - text = MarkupField(default_markup_type=DEFAULT_MARKUP_TYPE, - escape_html=False) - - image_width = models.IntegerField(default=0) - image_height = models.IntegerField(default=0) - - image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename, - blank=True, sizes=(IMAGE_THUMB_SIZE,), - width_field='image_width', - height_field='image_height') - - poster_ip = models.GenericIPAddressField() - poster_user_agent = models.TextField() - - thread = models.ForeignKey('Post', null=True, default=None) - tags = models.ManyToManyField(Tag) - last_edit_time = models.DateTimeField() - bump_time = models.DateTimeField() - user = models.ForeignKey('User', null=True, default=None) - - replies = models.ManyToManyField('Post', symmetrical=False, null=True, - blank=True, related_name='re+') - referenced_posts = models.ManyToManyField('Post', symmetrical=False, - null=True, - blank=True, related_name='rfp+') - - def __unicode__(self): - return '#' + str(self.id) + ' ' + self.title + ' (' + \ - self.text.raw[:50] + ')' - - def get_title(self): - title = self.title - if len(title) == 0: - title = self.text.raw[:20] - - return title - - def get_reply_count(self): - return self.replies.count() - - def get_images_count(self): - images_count = 1 if self.image else 0 - images_count += self.replies.filter(image_width__gt=0).count() - - return images_count - - def can_bump(self): - """Check if the thread can be bumped by replying""" - - post_count = self.get_reply_count() - - return post_count <= settings.MAX_POSTS_PER_THREAD - - def bump(self): - """Bump (move to up) thread""" - - if self.can_bump(): - self.bump_time = timezone.now() - - def get_last_replies(self): - if settings.LAST_REPLIES_COUNT > 0: - reply_count = self.get_reply_count() - - if reply_count > 0: - reply_count_to_show = min(settings.LAST_REPLIES_COUNT, - reply_count) - last_replies = self.replies.all().order_by('pub_time')[ - reply_count - reply_count_to_show:] - - return last_replies - - def get_tags(self): - """Get a sorted tag list""" - - return self.tags.order_by('name') - - def get_cache_key(self): - return str(self.id) + str(self.last_edit_time.microsecond) - - def get_sorted_referenced_posts(self): - return self.referenced_posts.order_by('id') - - def is_referenced(self): - return self.referenced_posts.count() > 0 - - -class User(models.Model): - - user_id = models.CharField(max_length=50) - rank = models.IntegerField() - - registration_time = models.DateTimeField() - - fav_tags = models.ManyToManyField(Tag, null=True, blank=True) - fav_threads = models.ManyToManyField(Post, related_name='+', null=True, - blank=True) - - def save_setting(self, name, value): - setting, created = Setting.objects.get_or_create(name=name, user=self) - setting.value = str(value) - setting.save() - - return setting - - def get_setting(self, name): - if Setting.objects.filter(name=name, user=self).exists(): - setting = Setting.objects.get(name=name, user=self) - setting_value = setting.value - else: - setting_value = None - - return setting_value - - def is_moderator(self): - return RANK_MODERATOR >= self.rank - - def get_sorted_fav_tags(self): - cache_key = self._get_tag_cache_key() - fav_tags = cache.get(cache_key) - if fav_tags: - return fav_tags - - tags = self.fav_tags.annotate(Count('threads'))\ - .filter(threads__count__gt=0).order_by('name') - - if tags: - cache.set(cache_key, tags, board_settings.CACHE_TIMEOUT) - - return tags - - def get_post_count(self): - return Post.objects.filter(user=self).count() - - def __unicode__(self): - return self.user_id + '(' + str(self.rank) + ')' - - def get_last_access_time(self): - posts = Post.objects.filter(user=self) - if posts.count() > 0: - return posts.latest('pub_time').pub_time - - def add_tag(self, tag): - self.fav_tags.add(tag) - cache.delete(self._get_tag_cache_key()) - - def remove_tag(self, tag): - self.fav_tags.remove(tag) - cache.delete(self._get_tag_cache_key()) - - def _get_tag_cache_key(self): - return self.user_id + '_tags' - - -class Setting(models.Model): - - name = models.CharField(max_length=50) - value = models.CharField(max_length=50) - user = models.ForeignKey(User) - - -class Ban(models.Model): - - ip = models.GenericIPAddressField() - reason = models.CharField(default=BAN_REASON_AUTO, - max_length=BAN_REASON_MAX_LENGTH) - can_read = models.BooleanField(default=True) - - def __unicode__(self): - return self.ip diff --git a/boards/models/__init__.py b/boards/models/__init__.py new file mode 100644 --- /dev/null +++ b/boards/models/__init__.py @@ -0,0 +1,7 @@ +__author__ = 'neko259' + +from boards.models.post import Post +from boards.models.post import Tag +from boards.models.post import Ban +from boards.models.post import Setting +from boards.models.post import User diff --git a/boards/models/post.py b/boards/models/post.py new file mode 100644 --- /dev/null +++ b/boards/models/post.py @@ -0,0 +1,476 @@ +import os +from random import random +import time +import math +from django.core.cache import cache + +from django.db import models +from django.db.models import Count +from django.http import Http404 +from django.utils import timezone +from markupfield.fields import MarkupField +from boards import settings as board_settings + +from neboard import settings +from boards import thumbs + +import re + +TAG_FONT_MULTIPLIER = 0.2 + +MAX_TAG_FONT = 4 + +BAN_REASON_MAX_LENGTH = 200 + +BAN_REASON_AUTO = 'Auto' + +IMAGE_THUMB_SIZE = (200, 150) + +TITLE_MAX_LENGTH = 50 + +DEFAULT_MARKUP_TYPE = 'markdown' + +NO_PARENT = -1 +NO_IP = '0.0.0.0' +UNKNOWN_UA = '' +ALL_PAGES = -1 +OPENING_POST_POPULARITY_WEIGHT = 2 +IMAGES_DIRECTORY = 'images/' +FILE_EXTENSION_DELIMITER = '.' + +RANK_ADMIN = 0 +RANK_MODERATOR = 10 +RANK_USER = 100 + +SETTING_MODERATE = "moderate" + +REGEX_REPLY = re.compile('>>(\d+)') + + +class PostManager(models.Manager): + + def create_post(self, title, text, image=None, thread=None, + ip=NO_IP, tags=None, user=None): + posting_time = timezone.now() + + post = self.create(title=title, + text=text, + pub_time=posting_time, + thread=thread, + image=image, + poster_ip=ip, + poster_user_agent=UNKNOWN_UA, + last_edit_time=posting_time, + bump_time=posting_time, + user=user) + + if tags: + linked_tags = [] + for tag in tags: + tag_linked_tags = tag.get_linked_tags() + if len(tag_linked_tags) > 0: + linked_tags.extend(tag_linked_tags) + + tags.extend(linked_tags) + map(post.tags.add, tags) + for tag in tags: + tag.threads.add(post) + + if thread: + thread.replies.add(post) + thread.bump() + thread.last_edit_time = posting_time + thread.save() + + #cache_key = thread.get_cache_key() + #cache.delete(cache_key) + + else: + self._delete_old_threads() + + self.connect_replies(post) + + return post + + def delete_post(self, post): + if post.replies.count() > 0: + map(self.delete_post, post.replies.all()) + + # Update thread's last edit time (used as cache key) + thread = post.thread + if thread: + thread.last_edit_time = timezone.now() + thread.save() + + #cache_key = thread.get_cache_key() + #cache.delete(cache_key) + + post.delete() + + def delete_posts_by_ip(self, ip): + posts = self.filter(poster_ip=ip) + map(self.delete_post, posts) + + def get_threads(self, tag=None, page=ALL_PAGES, + order_by='-bump_time'): + if tag: + threads = tag.threads + + if threads.count() == 0: + raise Http404 + else: + threads = self.filter(thread=None) + + threads = threads.order_by(order_by) + + if page != ALL_PAGES: + thread_count = threads.count() + + if page < self._get_page_count(thread_count): + start_thread = page * settings.THREADS_PER_PAGE + end_thread = min(start_thread + settings.THREADS_PER_PAGE, + thread_count) + threads = threads[start_thread:end_thread] + + return threads + + def get_thread(self, opening_post_id): + try: + opening_post = self.get(id=opening_post_id, thread=None) + except Post.DoesNotExist: + raise Http404 + + #cache_key = opening_post.get_cache_key() + #thread = cache.get(cache_key) + #if thread: + # return thread + + if opening_post.replies: + thread = [opening_post] + thread.extend(opening_post.replies.all().order_by('pub_time')) + + #cache.set(cache_key, thread, board_settings.CACHE_TIMEOUT) + + return thread + + def exists(self, post_id): + posts = self.filter(id=post_id) + + return posts.count() > 0 + + def get_thread_page_count(self, tag=None): + if tag: + threads = self.filter(thread=None, tags=tag) + else: + threads = self.filter(thread=None) + + return self._get_page_count(threads.count()) + + def _delete_old_threads(self): + """ + Preserves maximum thread count. If there are too many threads, + delete the old ones. + """ + + # TODO Move old threads to the archive instead of deleting them. + # Maybe make some 'old' field in the model to indicate the thread + # must not be shown and be able for replying. + + threads = self.get_threads() + thread_count = threads.count() + + if thread_count > settings.MAX_THREAD_COUNT: + num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT + old_threads = threads[thread_count - num_threads_to_delete:] + + map(self.delete_post, old_threads) + + def connect_replies(self, post): + """Connect replies to a post to show them as a refmap""" + + for reply_number in re.finditer(REGEX_REPLY, post.text.raw): + post_id = reply_number.group(1) + ref_post = self.filter(id=post_id) + if ref_post.count() > 0: + referenced_post = ref_post[0] + referenced_post.referenced_posts.add(post) + referenced_post.last_edit_time = post.pub_time + referenced_post.save() + + def _get_page_count(self, thread_count): + return int(math.ceil(thread_count / float(settings.THREADS_PER_PAGE))) + + +class TagManager(models.Manager): + + def get_not_empty_tags(self): + tags = self.annotate(Count('threads')) \ + .filter(threads__count__gt=0).order_by('name') + + return tags + + +class Tag(models.Model): + """ + A tag is a text node assigned to the post. The tag serves as a board + section. There can be multiple tags for each message + """ + + objects = TagManager() + + class Meta: + app_label = 'boards' + + name = models.CharField(max_length=100) + threads = models.ManyToManyField('Post', null=True, + blank=True, related_name='tag+') + linked = models.ForeignKey('Tag', null=True, blank=True) + + def __unicode__(self): + return self.name + + def is_empty(self): + return self.get_post_count() == 0 + + def get_post_count(self): + return self.threads.count() + + def get_popularity(self): + posts_with_tag = Post.objects.get_threads(tag=self) + reply_count = 0 + for post in posts_with_tag: + reply_count += post.get_reply_count() + reply_count += OPENING_POST_POPULARITY_WEIGHT + + return reply_count + + def get_linked_tags(self): + tag_list = [] + self.get_linked_tags_list(tag_list) + + return tag_list + + def get_linked_tags_list(self, tag_list=[]): + """ + Returns the list of tags linked to current. The list can be got + through returned value or tag_list parameter + """ + + linked_tag = self.linked + + if linked_tag and not (linked_tag in tag_list): + tag_list.append(linked_tag) + + linked_tag.get_linked_tags_list(tag_list) + + def get_font_value(self): + """Get tag font value to differ most popular tags in the list""" + + post_count = self.get_post_count() + if post_count > MAX_TAG_FONT: + post_count = MAX_TAG_FONT + + font_value = str(1 + (post_count - 1) * TAG_FONT_MULTIPLIER) + + return font_value + + +class Post(models.Model): + """A post is a message.""" + + objects = PostManager() + + class Meta: + app_label = 'boards' + + def _update_image_filename(self, filename): + """Get unique image filename""" + + path = IMAGES_DIRECTORY + new_name = str(int(time.mktime(time.gmtime()))) + new_name += str(int(random() * 1000)) + new_name += FILE_EXTENSION_DELIMITER + new_name += filename.split(FILE_EXTENSION_DELIMITER)[-1:][0] + + return os.path.join(path, new_name) + + title = models.CharField(max_length=TITLE_MAX_LENGTH) + pub_time = models.DateTimeField() + text = MarkupField(default_markup_type=DEFAULT_MARKUP_TYPE, + escape_html=False) + + image_width = models.IntegerField(default=0) + image_height = models.IntegerField(default=0) + + image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename, + blank=True, sizes=(IMAGE_THUMB_SIZE,), + width_field='image_width', + height_field='image_height') + + poster_ip = models.GenericIPAddressField() + poster_user_agent = models.TextField() + + thread = models.ForeignKey('Post', null=True, default=None) + tags = models.ManyToManyField(Tag) + last_edit_time = models.DateTimeField() + bump_time = models.DateTimeField() + user = models.ForeignKey('User', null=True, default=None) + + replies = models.ManyToManyField('Post', symmetrical=False, null=True, + blank=True, related_name='re+') + referenced_posts = models.ManyToManyField('Post', symmetrical=False, + null=True, + blank=True, related_name='rfp+') + + def __unicode__(self): + return '#' + str(self.id) + ' ' + self.title + ' (' + \ + self.text.raw[:50] + ')' + + def get_title(self): + title = self.title + if len(title) == 0: + title = self.text.raw[:20] + + return title + + def get_reply_count(self): + return self.replies.count() + + def get_images_count(self): + images_count = 1 if self.image else 0 + images_count += self.replies.filter(image_width__gt=0).count() + + return images_count + + def can_bump(self): + """Check if the thread can be bumped by replying""" + + post_count = self.get_reply_count() + + return post_count <= settings.MAX_POSTS_PER_THREAD + + def bump(self): + """Bump (move to up) thread""" + + if self.can_bump(): + self.bump_time = timezone.now() + + def get_last_replies(self): + if settings.LAST_REPLIES_COUNT > 0: + reply_count = self.get_reply_count() + + if reply_count > 0: + reply_count_to_show = min(settings.LAST_REPLIES_COUNT, + reply_count) + last_replies = self.replies.all().order_by('pub_time')[ + reply_count - reply_count_to_show:] + + return last_replies + + def get_tags(self): + """Get a sorted tag list""" + + return self.tags.order_by('name') + + def get_cache_key(self): + return str(self.id) + str(self.last_edit_time.microsecond) + + def get_sorted_referenced_posts(self): + return self.referenced_posts.order_by('id') + + def is_referenced(self): + return self.referenced_posts.count() > 0 + + +class User(models.Model): + + class Meta: + app_label = 'boards' + + user_id = models.CharField(max_length=50) + rank = models.IntegerField() + + registration_time = models.DateTimeField() + + fav_tags = models.ManyToManyField(Tag, null=True, blank=True) + fav_threads = models.ManyToManyField(Post, related_name='+', null=True, + blank=True) + + def save_setting(self, name, value): + setting, created = Setting.objects.get_or_create(name=name, user=self) + setting.value = str(value) + setting.save() + + return setting + + def get_setting(self, name): + if Setting.objects.filter(name=name, user=self).exists(): + setting = Setting.objects.get(name=name, user=self) + setting_value = setting.value + else: + setting_value = None + + return setting_value + + def is_moderator(self): + return RANK_MODERATOR >= self.rank + + def get_sorted_fav_tags(self): + cache_key = self._get_tag_cache_key() + fav_tags = cache.get(cache_key) + if fav_tags: + return fav_tags + + tags = self.fav_tags.annotate(Count('threads')) \ + .filter(threads__count__gt=0).order_by('name') + + if tags: + cache.set(cache_key, tags, board_settings.CACHE_TIMEOUT) + + return tags + + def get_post_count(self): + return Post.objects.filter(user=self).count() + + def __unicode__(self): + return self.user_id + '(' + str(self.rank) + ')' + + def get_last_access_time(self): + posts = Post.objects.filter(user=self) + if posts.count() > 0: + return posts.latest('pub_time').pub_time + + def add_tag(self, tag): + self.fav_tags.add(tag) + cache.delete(self._get_tag_cache_key()) + + def remove_tag(self, tag): + self.fav_tags.remove(tag) + cache.delete(self._get_tag_cache_key()) + + def _get_tag_cache_key(self): + return self.user_id + '_tags' + + +class Setting(models.Model): + + class Meta: + app_label = 'boards' + + name = models.CharField(max_length=50) + value = models.CharField(max_length=50) + user = models.ForeignKey(User) + + +class Ban(models.Model): + + class Meta: + app_label = 'boards' + + ip = models.GenericIPAddressField() + reason = models.CharField(default=BAN_REASON_AUTO, + max_length=BAN_REASON_MAX_LENGTH) + can_read = models.BooleanField(default=True) + + def __unicode__(self): + return self.ip diff --git a/boards/views.py b/boards/views.py --- a/boards/views.py +++ b/boards/views.py @@ -2,9 +2,8 @@ import hashlib import json import string import time -import calendar - from datetime import datetime +import re from django.core import serializers from django.core.urlresolvers import reverse @@ -14,20 +13,18 @@ from django.template import RequestConte from django.shortcuts import render, redirect, get_object_or_404 from django.utils import timezone from django.db import transaction -import math from boards import forms import boards from boards import utils from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \ ThreadCaptchaForm, PostCaptchaForm, LoginForm, ModeratorSettingsForm - -from boards.models import Post, Tag, Ban, User, RANK_USER, SETTING_MODERATE, \ - REGEX_REPLY +from boards.models.post import Post, Tag, Ban, User, RANK_USER, \ + SETTING_MODERATE, REGEX_REPLY from boards import authors from boards.utils import get_client_ip import neboard -import re + BAN_REASON_SPAM = 'Autoban: spam bot' @@ -80,7 +77,7 @@ def index(request, page=0): @transaction.commit_on_success -def _new_post(request, form, thread_id=boards.models.NO_PARENT): +def _new_post(request, form, opening_post=None): """Add a new post (in thread or as a reply).""" ip = get_client_ip(request) @@ -103,8 +100,7 @@ def _new_post(request, form, thread_id=b tags = [] - new_thread = thread_id == boards.models.NO_PARENT - if new_thread: + if not opening_post: tag_strings = data['tags'] if tag_strings: @@ -115,19 +111,17 @@ def _new_post(request, form, thread_id=b tag, created = Tag.objects.get_or_create(name=tag_name) tags.append(tag) - op = None if thread_id == boards.models.NO_PARENT else \ - get_object_or_404(Post, id=thread_id) post = Post.objects.create_post(title=title, text=text, ip=ip, - thread=op, image=image, + thread=opening_post, image=image, tags=tags, user=_get_user(request)) - thread_to_show = (post.id if new_thread else thread_id) + thread_to_show = (opening_post.id if opening_post else post.id) - if new_thread: - return redirect(thread, post_id=thread_to_show) - else: + if opening_post: return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) + '#' + str(post.id)) + else: + return redirect(thread, post_id=thread_to_show) def tag(request, tag_name, page=0): @@ -192,8 +186,9 @@ def thread(request, post_id): error_class=PlainErrorList, **kwargs) form.session = request.session + opening_post = get_object_or_404(Post, id=post_id) if form.is_valid(): - return _new_post(request, form, post_id) + return _new_post(request, form, opening_post) if form.need_to_ban: # Ban user because he is suspected to be a bot _ban_current_user(request)