##// END OF EJS Templates
Optimized thread view a lot.
Optimized thread view a lot.

File last commit:

r161:cc12beaa default
r161:cc12beaa default
Show More
models.py
326 lines | 9.2 KiB | text/x-python | PythonLexer
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29 import os
neko259
Converting file name to a preudo-unique number instead of the original name.
r50 from random import random
neko259
Changed metadata design. Make space split tags.
r31 import re
neko259
Implemented form validation. When the form fails validation, showing the index page.
r29 import time
neko259
Compiling regexes for gets. #17 Added pagination. #28 Visually differing the dead (not bumpable) threads.
r46 import math
neko259
Fixed unicode tags validation. Moved constants from classes to modules. Added error 404 when trying to get the non-existent thread. This fixes #19
r71
from django.db import models
from django.http import Http404
from django.utils import timezone
from markupfield.fields import MarkupField
wnc_21
Added captcha support
r95 from threading import Thread
neko259
Removed images directory. Removed old urls. Added a bit code for the views.
r4
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 from neboard import settings
neko259
Fixed unicode tags validation. Moved constants from classes to modules. Added error 404 when trying to get the non-existent thread. This fixes #19
r71 import thumbs
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22
neko259
Added error 404 for opening not existing thread or tag. This fixes #8
r79 IMAGE_THUMB_SIZE = (200, 150)
TITLE_MAX_LENGTH = 50
DEFAULT_MARKUP_TYPE = 'markdown'
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22
neko259
Removed images directory. Removed old urls. Added a bit code for the views.
r4 NO_PARENT = -1
NO_IP = '0.0.0.0'
UNKNOWN_UA = ''
neko259
Fixed unicode tags validation. Moved constants from classes to modules. Added error 404 when trying to get the non-existent thread. This fixes #19
r71 ALL_PAGES = -1
neko259
Fixed some translation issues. Changed default captcha setting to "off" to pass tests. Removed the maximum page scale. This refs #36 and fixes #26, #2
r85 OPENING_POST_POPULARITY_WEIGHT = 2
neko259
Fixed unicode tags validation. Moved constants from classes to modules. Added error 404 when trying to get the non-existent thread. This fixes #19
r71 IMAGES_DIRECTORY = 'images/'
FILE_EXTENSION_DELIMITER = '.'
neko259
Added admin actions (showing IP, post removal). Added user ranks. This refs #61, #12
r112 RANK_ADMIN = 0
RANK_MODERATOR = 10
RANK_USER = 100
neko259
Initial commit. One test doesn't work, missing posting form.
r0
neko259
Fixed style of 'no threads' text in the main page. Added translation for this string.
r143
neko259
Added the new posting abstraction.
r2 class PostManager(models.Manager):
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 def create_post(self, title, text, image=None, parent_id=NO_PARENT,
neko259
Added user to the posts. This refs #12
r113 ip=NO_IP, tags=None, user=None):
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 post = self.create(title=title,
text=text,
pub_time=timezone.now(),
parent=parent_id,
image=image,
poster_ip=ip,
neko259
Added thread bumping.
r25 poster_user_agent=UNKNOWN_UA,
neko259
Added user to the posts. This refs #12
r113 last_edit_time=timezone.now(),
user=user)
neko259
Initial commit. One test doesn't work, missing posting form.
r0
neko259
Added localization (not fully working). Added tags posting. Changed the design a bit.
r24 if tags:
neko259
Added error 404 for opening not existing thread or tag. This fixes #8
r79 map(post.tags.add, tags)
neko259
Added localization (not fully working). Added tags posting. Changed the design a bit.
r24
neko259
Added thread bumping.
r25 if parent_id != NO_PARENT:
neko259
Implemented bumplimit.
r38 self._bump_thread(parent_id)
neko259
Added maximum threads count parameter to the settings. Delete the old posts to preserve the max count. Small design tweaks.
r28 else:
self._delete_old_threads()
neko259
Added thread bumping.
r25
neko259
Fixed indents for pycharm. Moved images upload path to settings. Some cosmetic changes.
r1 return post
neko259
Initial commit. One test doesn't work, missing posting form.
r0
def delete_post(self, post):
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 children = self.filter(parent=post.id)
neko259
Refactored code. Added thread title if the opening post has no title.
r147
map(self.delete_post, children)
neko259
Added the new posting abstraction.
r2 post.delete()
neko259
Initial commit. One test doesn't work, missing posting form.
r0 def delete_posts_by_ip(self, ip):
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 posts = self.filter(poster_ip=ip)
neko259
Refactored code. Added thread title if the opening post has no title.
r147 map(self.delete_post, posts)
neko259
Initial commit. One test doesn't work, missing posting form.
r0
neko259
Quick fix for the 404 page defect. Now 404 page is not shown for tags, this must be investigated further. This refs #50
r87 def get_threads(self, tag=None, page=ALL_PAGES,
order_by='-last_edit_time'):
neko259
Truncating thread text in threads list. Fixed tag threads order.
r27 if tag:
threads = self.filter(parent=NO_PARENT, tags=tag)
neko259
Quick fix for the 404 page defect. Now 404 page is not shown for tags, this must be investigated further. This refs #50
r87
# TODO Throw error 404 if no threads for tag found?
neko259
Truncating thread text in threads list. Fixed tag threads order.
r27 else:
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 threads = self.filter(parent=NO_PARENT)
neko259
Added error 404 for opening not existing thread or tag. This fixes #8
r79
neko259
Quick fix for the 404 page defect. Now 404 page is not shown for tags, this must be investigated further. This refs #50
r87 threads = threads.order_by(order_by)
neko259
Added methods for getting opening posts and threads.
r5
neko259
Fixed unicode tags validation. Moved constants from classes to modules. Added error 404 when trying to get the non-existent thread. This fixes #19
r71 if page != ALL_PAGES:
neko259
Compiling regexes for gets. #17 Added pagination. #28 Visually differing the dead (not bumpable) threads.
r46 thread_count = len(threads)
if page < self.get_thread_page_count(tag=tag):
start_thread = page * settings.THREADS_PER_PAGE
end_thread = min(start_thread + settings.THREADS_PER_PAGE,
thread_count)
threads = threads[start_thread:end_thread]
neko259
Added methods for getting opening posts and threads.
r5 return threads
def get_thread(self, opening_post_id):
neko259
Added error 404 for opening not existing thread or tag. This fixes #8
r79 try:
neko259
Defined encoding in the HTML. Fixed error 404 page on opening reply as thread. This fixes #46, #47
r86 opening_post = self.get(id=opening_post_id, parent=NO_PARENT)
neko259
Added error 404 for opening not existing thread or tag. This fixes #8
r79 except Post.DoesNotExist:
neko259
Fixed unicode tags validation. Moved constants from classes to modules. Added error 404 when trying to get the non-existent thread. This fixes #19
r71 raise Http404
neko259
Fixed medadata design when an image is present. Added a method to determine if the tag is empty (has no attached threads).
r33 if opening_post.parent == NO_PARENT:
replies = self.filter(parent=opening_post_id)
neko259
Added methods for getting opening posts and threads.
r5
neko259
Fixed medadata design when an image is present. Added a method to determine if the tag is empty (has no attached threads).
r33 thread = [opening_post]
thread.extend(replies)
neko259
Fixed getting posts for a thread. Implemented thread getting test.
r17
neko259
Fixed medadata design when an image is present. Added a method to determine if the tag is empty (has no attached threads).
r33 return thread
neko259
Added methods for getting opening posts and threads.
r5
neko259
Fixed the tests. Added exists() method for the post.
r8 def exists(self, post_id):
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 posts = self.filter(id=post_id)
neko259
Fixed the tests. Added exists() method for the post.
r8
neko259
Optimized some post count calls.
r58 return posts.count() > 0
neko259
Fixed the tests. Added exists() method for the post.
r8
neko259
Compiling regexes for gets. #17 Added pagination. #28 Visually differing the dead (not bumpable) threads.
r46 def get_thread_page_count(self, tag=None):
if tag:
threads = self.filter(parent=NO_PARENT, tags=tag)
else:
threads = self.filter(parent=NO_PARENT)
neko259
Optimized some post count calls.
r58 return int(math.ceil(threads.count() / float(
settings.THREADS_PER_PAGE)))
neko259
Compiling regexes for gets. #17 Added pagination. #28 Visually differing the dead (not bumpable) threads.
r46
neko259
Added maximum threads count parameter to the settings. Delete the old posts to preserve the max count. Small design tweaks.
r28 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 = len(threads)
if thread_count > settings.MAX_THREAD_COUNT:
num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
neko259
Optimized some post count calls.
r58 old_threads = threads[thread_count - num_threads_to_delete:]
neko259
Added maximum threads count parameter to the settings. Delete the old posts to preserve the max count. Small design tweaks.
r28
neko259
Refactored code. Added thread title if the opening post has no title.
r147 map(self.delete_post, old_threads)
neko259
Added maximum threads count parameter to the settings. Delete the old posts to preserve the max count. Small design tweaks.
r28
neko259
Implemented bumplimit.
r38 def _bump_thread(self, thread_id):
thread = self.get(id=thread_id)
neko259
Compiling regexes for gets. #17 Added pagination. #28 Visually differing the dead (not bumpable) threads.
r46 if thread.can_bump():
neko259
Implemented bumplimit.
r38 thread.last_edit_time = timezone.now()
thread.save()
neko259
Added methods for getting opening posts and threads.
r5
neko259
Fixed medadata design when an image is present. Added a method to determine if the tag is empty (has no attached threads).
r33 class TagManager(models.Manager):
def get_not_empty_tags(self):
neko259
Sort threads by name. Previous commit: added navigation panel, added tag manager to get active tags.
r34 all_tags = self.all().order_by('name')
neko259
Fixed medadata design when an image is present. Added a method to determine if the tag is empty (has no attached threads).
r33 tags = []
for tag in all_tags:
if not tag.is_empty():
tags.append(tag)
return tags
neko259
Limit number of tags shown in the navigation bar to only the most popular ones.
r57 def get_popular_tags(self):
all_tags = self.get_not_empty_tags()
sorted_tags = sorted(all_tags, key=lambda tag: tag.get_popularity(),
reverse=True)
return sorted_tags[:settings.POPULAR_TAGS]
neko259
Fixed medadata design when an image is present. Added a method to determine if the tag is empty (has no attached threads).
r33
neko259
Removed images directory. Removed old urls. Added a bit code for the views.
r4 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
"""
neko259
Fixed medadata design when an image is present. Added a method to determine if the tag is empty (has no attached threads).
r33 objects = TagManager()
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 name = models.CharField(max_length=100)
neko259
Removed images directory. Removed old urls. Added a bit code for the views.
r4
neko259
Changed metadata design. Make space split tags.
r31 def __unicode__(self):
return self.name
neko259
Fixed medadata design when an image is present. Added a method to determine if the tag is empty (has no attached threads).
r32 def is_empty(self):
neko259
Fixed medadata design when an image is present. Added a method to determine if the tag is empty (has no attached threads).
r33 return self.get_post_count() == 0
def get_post_count(self):
neko259
Fixed medadata design when an image is present. Added a method to determine if the tag is empty (has no attached threads).
r32 posts_with_tag = Post.objects.get_threads(tag=self)
neko259
Optimized some post count calls.
r58 return posts_with_tag.count()
neko259
Fixed medadata design when an image is present. Added a method to determine if the tag is empty (has no attached threads).
r32
neko259
Limit number of tags shown in the navigation bar to only the most popular ones.
r57 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()
neko259
Fixed some translation issues. Changed default captcha setting to "off" to pass tests. Removed the maximum page scale. This refs #36 and fixes #26, #2
r85 reply_count += OPENING_POST_POPULARITY_WEIGHT
neko259
Limit number of tags shown in the navigation bar to only the most popular ones.
r57
return reply_count
neko259
Fixed the tests. Added exists() method for the post.
r8
neko259
Added the new posting abstraction.
r2 class Post(models.Model):
neko259
Removed images directory. Removed old urls. Added a bit code for the views.
r4 """A post is a message."""
neko259
Initial commit. One test doesn't work, missing posting form.
r0
neko259
Added the new posting abstraction.
r2 objects = PostManager()
neko259
Initial commit. One test doesn't work, missing posting form.
r0
neko259
Converting file name to a preudo-unique number instead of the original name.
r50 def _update_image_filename(self, filename):
"""Get unique image filename"""
neko259
Fixed unicode tags validation. Moved constants from classes to modules. Added error 404 when trying to get the non-existent thread. This fixes #19
r71 path = IMAGES_DIRECTORY
neko259
Converting file name to a preudo-unique number instead of the original name.
r50 new_name = str(int(time.mktime(time.gmtime())))
new_name += str(int(random() * 1000))
neko259
Fixed unicode tags validation. Moved constants from classes to modules. Added error 404 when trying to get the non-existent thread. This fixes #19
r71 new_name += FILE_EXTENSION_DELIMITER
new_name += filename.split(FILE_EXTENSION_DELIMITER)[-1:][0]
neko259
Converting file name to a preudo-unique number instead of the original name.
r50
return os.path.join(path, new_name)
neko259
Added error 404 for opening not existing thread or tag. This fixes #8
r79 title = models.CharField(max_length=TITLE_MAX_LENGTH)
neko259
Added the new posting abstraction.
r2 pub_time = models.DateTimeField()
neko259
Added error 404 for opening not existing thread or tag. This fixes #8
r79 text = MarkupField(default_markup_type=DEFAULT_MARKUP_TYPE,
neko259
Changed parser to show quotes and reflinks as they are posted, not with borders and '#' character.
r90 escape_html=False)
neko259
Removed method that checks gets (this will be implemented in JS). Added image width and height fields that will be used for image previews. This refs #72
r127
neko259
Added default value for image dimensions fields.
r129 image_width = models.IntegerField(default=0)
image_height = models.IntegerField(default=0)
neko259
Removed method that checks gets (this will be implemented in JS). Added image width and height fields that will be used for image previews. This refs #72
r127
neko259
Converting file name to a preudo-unique number instead of the original name.
r50 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
neko259
Removed method that checks gets (this will be implemented in JS). Added image width and height fields that will be used for image previews. This refs #72
r127 blank=True, sizes=(IMAGE_THUMB_SIZE,),
width_field='image_width',
height_field='image_height')
neko259
Added IP ban lists. Added migration for bans. Use generic ip address for posting instead of ipv4 only.
r116 poster_ip = models.GenericIPAddressField()
neko259
Added the new posting abstraction.
r2 poster_user_agent = models.TextField()
parent = models.BigIntegerField()
neko259
Partially fixed tests and model definition
r7 tags = models.ManyToManyField(Tag)
neko259
Added thread bumping.
r25 last_edit_time = models.DateTimeField()
neko259
Fixed an import issue in models. Removed tests for admin because the user model has changed.
r140 user = models.ForeignKey('User', null=True, default=None)
neko259
Initial commit. One test doesn't work, missing posting form.
r0
def __unicode__(self):
Pavel Ryapolov
Made post unicode string value shorter for the admin interface.
r105 return '#' + str(self.id) + ' ' + self.title + ' (' + \
neko259
Removed method that checks gets (this will be implemented in JS). Added image width and height fields that will be used for image previews. This refs #72
r127 self.text.raw[:50] + ')'
Ilyas
Added admin loing possibility. Now it is abailable under {BASE_URL}/boards/login...
r9
neko259
Refactored code. Added thread title if the opening post has no title.
r147 def get_title(self):
title = self.title
if len(title) == 0:
title = self.text.raw[:20]
return title
neko259
Added thread metadata (replies, images, gets) to the threads list.
r30 def _get_replies(self):
return Post.objects.filter(parent=self.id)
def get_reply_count(self):
neko259
Optimized some post count calls.
r58 return self._get_replies().count()
neko259
Added thread metadata (replies, images, gets) to the threads list.
r30
def get_images_count(self):
images_count = 1 if self.image else 0
neko259
Optimized thread view a lot.
r161
replies = self._get_replies()
for reply in replies:
neko259
Added thread metadata (replies, images, gets) to the threads list.
r30 if reply.image:
images_count += 1
return images_count
neko259
Compiling regexes for gets. #17 Added pagination. #28 Visually differing the dead (not bumpable) threads.
r46 def can_bump(self):
"""Check if the thread can be bumped by replying"""
neko259
Optimized thread view a lot.
r161 replies_count = self.get_reply_count() + 1
neko259
Compiling regexes for gets. #17 Added pagination. #28 Visually differing the dead (not bumpable) threads.
r46
return replies_count <= settings.MAX_POSTS_PER_THREAD
neko259
Changed metadata design. Make space split tags.
r31
neko259
#44 Show last replies in the threads list.
r59 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._get_replies()[reply_count
- reply_count_to_show:]
return last_replies
Ilyas
Added admin loing possibility. Now it is abailable under {BASE_URL}/boards/login...
r9
neko259
Added last access time and registration time for user. This refs #61
r121 class User(models.Model):
user_id = models.CharField(max_length=50)
rank = models.IntegerField()
registration_time = models.DateTimeField()
last_access_time = models.DateTimeField()
neko259
Added login functionality.
r144 fav_tags = models.ManyToManyField(Tag, null=True, blank=True)
fav_threads = models.ManyToManyField(Post, related_name='+', null=True,
blank=True)
neko259
Added last access time and registration time for user. This refs #61
r121
def save_setting(self, name, value):
setting, created = Setting.objects.get_or_create(name=name, user=self)
setting.value = value
setting.save()
return setting
def get_setting(self, name):
neko259
Optimized thread view a lot.
r161 if Setting.objects.filter(name=name, user=self).exists():
setting = Setting.objects.get(name=name, user=self)
neko259
Added last access time and registration time for user. This refs #61
r121 setting_value = setting.value
else:
setting_value = None
return setting_value
def is_moderator(self):
return RANK_MODERATOR >= self.rank
Ilyas
Added admin loing possibility. Now it is abailable under {BASE_URL}/boards/login...
r9
neko259
Speed up tags ordering in the navigation panel.
r149 def get_sorted_fav_tags(self):
return self.fav_tags.order_by('name')
Ilyas
Added admin loing possibility. Now it is abailable under {BASE_URL}/boards/login...
r9 def __unicode__(self):
neko259
Added 'ban' button to the moderator panel.
r156 return self.user_id + '(' + str(self.rank) + ')'
neko259
Added users with unique (sort of) IDs. Moved theme setting to user instead of session. This refs #61
r110
neko259
Fixed an import issue in models. Removed tests for admin because the user model has changed.
r140
neko259
Added admin actions (showing IP, post removal). Added user ranks. This refs #61, #12
r112 class Setting(models.Model):
neko259
Added IP ban lists. Added migration for bans. Use generic ip address for posting instead of ipv4 only.
r116
neko259
Added admin actions (showing IP, post removal). Added user ranks. This refs #61, #12
r112 name = models.CharField(max_length=50)
value = models.CharField(max_length=50)
user = models.ForeignKey(User)
neko259
Added IP ban lists. Added migration for bans. Use generic ip address for posting instead of ipv4 only.
r116
neko259
Added login functionality.
r144
neko259
Added IP ban lists. Added migration for bans. Use generic ip address for posting instead of ipv4 only.
r116 class Ban(models.Model):
ip = models.GenericIPAddressField()
def __unicode__(self):
return self.ip