##// END OF EJS Templates
Show title after post number, not before
Show title after post number, not before

File last commit:

r639:905cd0bf default
r647:c1fe00c6 default
Show More
post.py
474 lines | 13.1 KiB | text/x-python | PythonLexer
neko259
Optimized getting current date in PPD calculation
r586 from datetime import datetime, timedelta, date
neko259
Show posts per
r407 from datetime import time as dtime
neko259
Added some logging
r639 import logging
neko259
Moved models to a separate module folder. Starting to split up models file
r384 import os
from random import random
import time
neko259
Split up user models
r386 import re
neko259
Added image duplicate check
r527 import hashlib
neko259
Use cache for PPD value
r410 from django.core.cache import cache
neko259
Added post url caching to cache post replies and id urls
r589 from django.core.urlresolvers import reverse
neko259
Added post admin page with tags edit capability
r566 from django.db import models, transaction
neko259
Moved models to a separate module folder. Starting to split up models file
r384 from django.utils import timezone
from markupfield.fields import MarkupField
from neboard import settings
from boards import thumbs
neko259
Optimized imports and added some docstrings to the post module
r622
neko259
Use cache for PPD value
r410 APP_LABEL_BOARDS = 'boards'
CACHE_KEY_PPD = 'ppd'
neko259
Added post url caching to cache post replies and id urls
r589 CACHE_KEY_POST_URL = 'post_url'
neko259
Added cache for opening post id
r620 CACHE_KEY_OPENING_POST = 'opening_post_id'
neko259
Use cache for PPD value
r410
neko259
Get PPD for the last week
r408 POSTS_PER_DAY_RANGE = range(7)
neko259
Moved models to a separate module folder. Starting to split up models file
r384 BAN_REASON_AUTO = 'Auto'
IMAGE_THUMB_SIZE = (200, 150)
neko259
Enlarged title field
r612 TITLE_MAX_LENGTH = 200
neko259
Moved models to a separate module folder. Starting to split up models file
r384
DEFAULT_MARKUP_TYPE = 'markdown'
NO_PARENT = -1
NO_IP = '0.0.0.0'
UNKNOWN_UA = ''
ALL_PAGES = -1
IMAGES_DIRECTORY = 'images/'
FILE_EXTENSION_DELIMITER = '.'
SETTING_MODERATE = "moderate"
REGEX_REPLY = re.compile('>>(\d+)')
neko259
Added some logging
r639 logger = logging.getLogger(__name__)
neko259
Moved models to a separate module folder. Starting to split up models file
r384
class PostManager(models.Manager):
def create_post(self, title, text, image=None, thread=None,
ip=NO_IP, tags=None, user=None):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Creates new post
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Moved models to a separate module folder. Starting to split up models file
r384 posting_time = timezone.now()
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 if not thread:
thread = Thread.objects.create(bump_time=posting_time,
last_edit_time=posting_time)
neko259
Delete old threads only on thread creation, not on every added post
r615 new_thread = True
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 else:
thread.bump()
thread.last_edit_time = posting_time
thread.save()
neko259
Delete old threads only on thread creation, not on every added post
r615 new_thread = False
neko259
Moved models to a separate module folder. Starting to split up models file
r384
post = self.create(title=title,
text=text,
pub_time=posting_time,
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 thread_new=thread,
neko259
Moved models to a separate module folder. Starting to split up models file
r384 image=image,
poster_ip=ip,
neko259
Fixed threads title in the browser title bar. Moving old threads to archive instead of deleting them.
r484 poster_user_agent=UNKNOWN_UA, # TODO Get UA at
# last!
neko259
Moved models to a separate module folder. Starting to split up models file
r384 last_edit_time=posting_time,
user=user)
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 thread.replies.add(post)
neko259
Moved models to a separate module folder. Starting to split up models file
r384 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)
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 map(thread.add_tag, tags)
neko259
Moved models to a separate module folder. Starting to split up models file
r384
neko259
Delete old threads only on thread creation, not on every added post
r615 if new_thread:
self._delete_old_threads()
neko259
Moved models to a separate module folder. Starting to split up models file
r384 self.connect_replies(post)
neko259
Added some logging
r639 logger.info('Created post #%d' % post.id)
neko259
Moved models to a separate module folder. Starting to split up models file
r384 return post
def delete_post(self, post):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Deletes post and update or delete its thread
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Moved delete view to class-based views
r552
neko259
Added some logging
r639 post_id = post.id
neko259
Changed thread_new to get_thread() in the post model
r619 thread = post.get_thread()
neko259
Small changes to the docstrings. Added some TODOs
r418
neko259
Moved delete view to class-based views
r552 if post.is_opening():
thread.delete_with_posts()
neko259
Fixed thread moderation
r456 else:
thread.last_edit_time = timezone.now()
thread.save()
neko259
Moved models to a separate module folder. Starting to split up models file
r384
neko259
Fixed deleting old threads when reaching limit
r470 post.delete()
neko259
Moved models to a separate module folder. Starting to split up models file
r384
neko259
Added some logging
r639 logger.info('Deleted post #%d' % post_id)
neko259
Moved models to a separate module folder. Starting to split up models file
r384 def delete_posts_by_ip(self, ip):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Deletes all posts of the author with same IP
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Moved models to a separate module folder. Starting to split up models file
r384 posts = self.filter(poster_ip=ip)
map(self.delete_post, posts)
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 # TODO Move this method to thread manager
neko259
Moved models to a separate module folder. Starting to split up models file
r384 def _delete_old_threads(self):
"""
Preserves maximum thread count. If there are too many threads,
neko259
Fixed threads title in the browser title bar. Moving old threads to archive instead of deleting them.
r484 archive the old ones.
neko259
Moved models to a separate module folder. Starting to split up models file
r384 """
neko259
Fixed thread autoarchiving
r603 threads = Thread.objects.filter(archived=False).order_by('-bump_time')
neko259
Moved models to a separate module folder. Starting to split up models file
r384 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:]
neko259
Fixed threads title in the browser title bar. Moving old threads to archive instead of deleting them.
r484 for thread in old_threads:
thread.archived = True
neko259
Updating last update time of the thread when archiving it
r492 thread.last_edit_time = timezone.now()
neko259
Fixed threads title in the browser title bar. Moving old threads to archive instead of deleting them.
r484 thread.save()
neko259
Moved models to a separate module folder. Starting to split up models file
r384
neko259
Added some logging
r639 logger.info('Archived %d old threads' % num_threads_to_delete)
neko259
Moved models to a separate module folder. Starting to split up models file
r384 def connect_replies(self, post):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Connects replies to a post to show them as a reflink map
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Moved models to a separate module folder. Starting to split up models file
r384
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()
neko259
Changed thread_new to get_thread() in the post model
r619 referenced_thread = referenced_post.get_thread()
neko259
Update referenced post's thread last edit time on connecting replies
r535 referenced_thread.last_edit_time = post.pub_time
referenced_thread.save()
neko259
Show posts per
r407 def get_posts_per_day(self):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Gets average count of posts per day for the last 7 days
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Show posts per
r407
neko259
Optimized getting current date in PPD calculation
r586 today = date.today()
neko259
Caching PPD by day, removed manual cache removal
r424 ppd = cache.get(CACHE_KEY_PPD + str(today))
neko259
Use cache for PPD value
r410 if ppd:
return ppd
neko259
Get PPD for the last week
r408 posts_per_days = []
for i in POSTS_PER_DAY_RANGE:
neko259
Fixed PPD counting. Before this it was count from the future week
r413 day_end = today - timedelta(i + 1)
day_start = today - timedelta(i + 2)
neko259
Style cleanup
r608 day_time_start = timezone.make_aware(datetime.combine(
day_start, dtime()), timezone.get_current_timezone())
day_time_end = timezone.make_aware(datetime.combine(
day_end, dtime()), timezone.get_current_timezone())
neko259
Get PPD for the last week
r408
neko259
Use cache for PPD value
r410 posts_per_days.append(float(self.filter(
pub_time__lte=day_time_end,
pub_time__gte=day_time_start).count()))
neko259
Get PPD for the last week
r408
neko259
Use cache for PPD value
r410 ppd = (sum(posts_per_day for posts_per_day in posts_per_days) /
len(posts_per_days))
neko259
Fixed PPD cache. Optimized thread view a little bit
r569 cache.set(CACHE_KEY_PPD + str(today), ppd)
neko259
Use cache for PPD value
r410 return ppd
neko259
Show posts per
r407
neko259
Moved models to a separate module folder. Starting to split up models file
r384
class Post(models.Model):
"""A post is a message."""
objects = PostManager()
class Meta:
neko259
Use cache for PPD value
r410 app_label = APP_LABEL_BOARDS
neko259
Moved models to a separate module folder. Starting to split up models file
r384
neko259
Small changes to the docstrings. Added some TODOs
r418 # TODO Save original file name to some field
neko259
Moved models to a separate module folder. Starting to split up models file
r384 def _update_image_filename(self, filename):
neko259
Optimized imports and added some docstrings to the post module
r622 """
Gets unique image filename
"""
neko259
Moved models to a separate module folder. Starting to split up models file
r384
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)
neko259
Saving image thumbnails size to the database and using this size in the HTML
r452 image_pre_width = models.IntegerField(default=0)
image_pre_height = models.IntegerField(default=0)
neko259
Moved models to a separate module folder. Starting to split up models file
r384 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
blank=True, sizes=(IMAGE_THUMB_SIZE,),
width_field='image_width',
neko259
Saving image thumbnails size to the database and using this size in the HTML
r452 height_field='image_height',
preview_width_field='image_pre_width',
preview_height_field='image_pre_height')
neko259
Added image duplicate check
r527 image_hash = models.CharField(max_length=36)
neko259
Moved models to a separate module folder. Starting to split up models file
r384
poster_ip = models.GenericIPAddressField()
poster_user_agent = models.TextField()
thread = models.ForeignKey('Post', null=True, default=None)
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 thread_new = models.ForeignKey('Thread', null=True, default=None)
neko259
Moved models to a separate module folder. Starting to split up models file
r384 last_edit_time = models.DateTimeField()
user = models.ForeignKey('User', null=True, default=None)
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):
neko259
Optimized imports and added some docstrings to the post module
r622 """
Gets original post title or part of its text.
"""
neko259
Moved models to a separate module folder. Starting to split up models file
r384 title = self.title
neko259
Fixed some issues based on feedback at linux.org.ru
r618 if not title:
neko259
Fixed tags field placeholder. Fixed thread title
r521 title = self.text.rendered
neko259
Moved models to a separate module folder. Starting to split up models file
r384
return title
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 def get_sorted_referenced_posts(self):
return self.referenced_posts.order_by('id')
def is_referenced(self):
neko259
Fixed some issues based on feedback at linux.org.ru
r618 return self.referenced_posts.exists()
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398
neko259
Fixed some issues with post model migration
r400 def is_opening(self):
neko259
Optimized imports and added some docstrings to the post module
r622 """
Checks if this is an opening post or just a reply.
"""
neko259
Added cache for opening post id
r620 return self.get_thread().get_opening_post_id() == self.id
neko259
Fixed some issues with post model migration
r400
neko259
Added image duplicate check
r527 def save(self, *args, **kwargs):
"""
neko259
Optimized imports and added some docstrings to the post module
r622 Saves the model and computes the image hash for deduplication purposes.
neko259
Added image duplicate check
r527 """
if not self.pk and self.image:
md5 = hashlib.md5()
for chunk in self.image.chunks():
md5.update(chunk)
self.image_hash = md5.hexdigest()
super(Post, self).save(*args, **kwargs)
neko259
Added post admin page with tags edit capability
r566 @transaction.atomic
def add_tag(self, tag):
edit_time = timezone.now()
neko259
Changed thread_new to get_thread() in the post model
r619 thread = self.get_thread()
neko259
Added post admin page with tags edit capability
r566 thread.add_tag(tag)
self.last_edit_time = edit_time
self.save()
thread.last_edit_time = edit_time
thread.save()
@transaction.atomic
def remove_tag(self, tag):
edit_time = timezone.now()
neko259
Changed thread_new to get_thread() in the post model
r619 thread = self.get_thread()
neko259
Fixed tag removal from thread and thread from tag
r576 thread.remove_tag(tag)
neko259
Added post admin page with tags edit capability
r566 self.last_edit_time = edit_time
self.save()
thread.last_edit_time = edit_time
thread.save()
neko259
Some more speedups to the post view
r625 def get_url(self, thread=None):
neko259
Added post url caching to cache post replies and id urls
r589 """
neko259
Optimized imports and added some docstrings to the post module
r622 Gets full url to the post.
neko259
Added post url caching to cache post replies and id urls
r589 """
cache_key = CACHE_KEY_POST_URL + str(self.id)
link = cache.get(cache_key)
if not link:
neko259
Some more speedups to the post view
r625 if not thread:
thread = self.get_thread()
opening_id = thread.get_opening_post_id()
neko259
Speed up thread loading
r614
if self.id != opening_id:
neko259
Style cleanup
r608 link = reverse('thread', kwargs={
neko259
Speed up thread loading
r614 'post_id': opening_id}) + '#' + str(self.id)
neko259
Added post url caching to cache post replies and id urls
r589 else:
link = reverse('thread', kwargs={'post_id': self.id})
cache.set(cache_key, link)
return link
neko259
Made getting post thread more generic and scalable
r617 def get_thread(self):
neko259
Optimized imports and added some docstrings to the post module
r622 """
Gets post's thread.
"""
neko259
Made getting post thread more generic and scalable
r617 return self.thread_new
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398
class Thread(models.Model):
class Meta:
neko259
Use cache for PPD value
r410 app_label = APP_LABEL_BOARDS
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398
tags = models.ManyToManyField('Tag')
bump_time = models.DateTimeField()
last_edit_time = models.DateTimeField()
replies = models.ManyToManyField('Post', symmetrical=False, null=True,
blank=True, related_name='tre+')
neko259
Fixed threads title in the browser title bar. Moving old threads to archive instead of deleting them.
r484 archived = models.BooleanField(default=False)
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398
def get_tags(self):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Gets a sorted tag list.
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398
return self.tags.order_by('name')
def bump(self):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Bumps (moves to up) thread if possible.
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398
if self.can_bump():
self.bump_time = timezone.now()
neko259
Added some logging
r639 logger.info('Bumped thread %d' % self.id)
neko259
Moved models to a separate module folder. Starting to split up models file
r384 def get_reply_count(self):
return self.replies.count()
def get_images_count(self):
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 return self.replies.filter(image_width__gt=0).count()
neko259
Moved models to a separate module folder. Starting to split up models file
r384
def can_bump(self):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Checks if the thread can be bumped by replying to it.
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Moved models to a separate module folder. Starting to split up models file
r384
neko259
Fixed threads title in the browser title bar. Moving old threads to archive instead of deleting them.
r484 if self.archived:
return False
neko259
Moved models to a separate module folder. Starting to split up models file
r384 post_count = self.get_reply_count()
neko259
Make thread not bumpable at bumplimit, not bumplimit + 1
r428 return post_count < settings.MAX_POSTS_PER_THREAD
neko259
Moved models to a separate module folder. Starting to split up models file
r384
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 def delete_with_posts(self):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Completely deletes thread and all its posts
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Moved models to a separate module folder. Starting to split up models file
r384
neko259
Fixed some issues based on feedback at linux.org.ru
r618 if self.replies.exists():
neko259
Fixed deleting old threads when reaching limit
r470 self.replies.all().delete()
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398
self.delete()
neko259
Moved models to a separate module folder. Starting to split up models file
r384
def get_last_replies(self):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Gets several last replies, not including opening post
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398
neko259
Moved models to a separate module folder. Starting to split up models file
r384 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,
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 reply_count - 1)
neko259
Fixed some issues based on feedback at linux.org.ru
r618 last_replies = self.replies.order_by(
neko259
Style cleanup
r608 'pub_time')[reply_count - reply_count_to_show:]
neko259
Moved models to a separate module folder. Starting to split up models file
r384
return last_replies
neko259
Rewriting views to class-based
r542 def get_skipped_replies_count(self):
neko259
Optimized imports and added some docstrings to the post module
r622 """
Gets number of posts between opening post and last replies.
"""
neko259
Rewriting views to class-based
r542 last_replies = self.get_last_replies()
return self.get_reply_count() - len(last_replies) - 1
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 def get_replies(self):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Gets sorted thread posts
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Moved models to a separate module folder. Starting to split up models file
r384
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 return self.replies.all().order_by('pub_time')
neko259
Moved models to a separate module folder. Starting to split up models file
r384
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 def add_tag(self, tag):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Connects thread to a tag and tag to a thread
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Moved models to a separate module folder. Starting to split up models file
r384
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 self.tags.add(tag)
tag.threads.add(self)
neko259
Fixed tag removal from thread and thread from tag
r576 def remove_tag(self, tag):
self.tags.remove(tag)
tag.threads.remove(self)
neko259
Fixed some issues with post model migration
r400 def get_opening_post(self):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Gets the first post of the thread
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Temp fix for the post cache problem
r595 opening_post = self.get_replies()[0]
neko259
Added cache for thread opening post
r593
return opening_post
neko259
Fixed some issues with post model migration
r400
neko259
Added cache for opening post id
r620 def get_opening_post_id(self):
neko259
Optimized imports and added some docstrings to the post module
r622 """
Gets ID of the first thread post.
"""
neko259
Added cache for opening post id
r620 cache_key = CACHE_KEY_OPENING_POST + str(self.id)
opening_post_id = cache.get(cache_key)
if not opening_post_id:
neko259
Optimized imports and added some docstrings to the post module
r622 opening_post_id = self.get_opening_post().id
neko259
Added cache for opening post id
r620 cache.set(cache_key, opening_post_id)
return opening_post_id
neko259
Split up post model into post and thread to normalise models. Still need some refactoring
r398 def __unicode__(self):
neko259
Moved delete view to class-based views
r552 return str(self.id)
neko259
Fixed RSS
r402
def get_pub_time(self):
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Optimized imports and added some docstrings to the post module
r622 Gets opening post's pub time because thread does not have its own one.
neko259
Small changes to the docstrings. Added some TODOs
r418 """
neko259
Small design changes. Count board speed since yesterday, not today
r411 return self.get_opening_post().pub_time