##// END OF EJS Templates
Moving neboard to python3 support (no python2 for now until we figure out how...
Moving neboard to python3 support (no python2 for now until we figure out how to make them both work)

File last commit:

r718:056bdb08 default
r765:bb8477db default
Show More
thread.py
187 lines | 5.2 KiB | text/x-python | PythonLexer
import logging
from django.db.models import Count
from django.utils import timezone
from django.core.cache import cache
from django.db import models
from boards import settings
__author__ = 'neko259'
logger = logging.getLogger(__name__)
CACHE_KEY_OPENING_POST = 'opening_post_id'
class ThreadManager(models.Manager):
def process_oldest_threads(self):
"""
Preserves maximum thread count. If there are too many threads,
archive or delete the old ones.
"""
threads = Thread.objects.filter(archived=False).order_by('-bump_time')
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:]
for thread in old_threads:
if settings.ARCHIVE_THREADS:
self._archive_thread(thread)
else:
thread.delete()
logger.info('Processed %d old threads' % num_threads_to_delete)
def _archive_thread(self, thread):
thread.archived = True
thread.last_edit_time = timezone.now()
thread.save(update_fields=['archived', 'last_edit_time'])
class Thread(models.Model):
objects = ThreadManager()
class Meta:
app_label = 'boards'
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+')
archived = models.BooleanField(default=False)
def get_tags(self):
"""
Gets a sorted tag list.
"""
return self.tags.order_by('name')
def bump(self):
"""
Bumps (moves to up) thread if possible.
"""
if self.can_bump():
self.bump_time = timezone.now()
logger.info('Bumped thread %d' % self.id)
def get_reply_count(self):
return self.replies.count()
def get_images_count(self):
# TODO Use sum
total_count = 0
for post_with_image in self.replies.annotate(images_count=Count(
'images')):
total_count += post_with_image.images_count
return total_count
def can_bump(self):
"""
Checks if the thread can be bumped by replying to it.
"""
if self.archived:
return False
post_count = self.get_reply_count()
return post_count < settings.MAX_POSTS_PER_THREAD
def get_last_replies(self):
"""
Gets several last replies, not including opening post
"""
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 - 1)
replies = self.get_replies()
last_replies = replies[reply_count - reply_count_to_show:]
return last_replies
def get_skipped_replies_count(self):
"""
Gets number of posts between opening post and last replies.
"""
reply_count = self.get_reply_count()
last_replies_count = min(settings.LAST_REPLIES_COUNT,
reply_count - 1)
return reply_count - last_replies_count - 1
def get_replies(self, view_fields_only=False):
"""
Gets sorted thread posts
"""
query = self.replies.order_by('pub_time').prefetch_related('images')
if view_fields_only:
query = query.defer('poster_user_agent', 'text_markup_type')
return query.all()
def get_replies_with_images(self, view_fields_only=False):
return self.get_replies(view_fields_only).annotate(images_count=Count(
'images')).filter(images_count__gt=0)
def add_tag(self, tag):
"""
Connects thread to a tag and tag to a thread
"""
self.tags.add(tag)
tag.threads.add(self)
def remove_tag(self, tag):
self.tags.remove(tag)
tag.threads.remove(self)
def get_opening_post(self, only_id=False):
"""
Gets the first post of the thread
"""
query = self.replies.order_by('pub_time')
if only_id:
query = query.only('id')
opening_post = query.first()
return opening_post
def get_opening_post_id(self):
"""
Gets ID of the first thread post.
"""
cache_key = CACHE_KEY_OPENING_POST + str(self.id)
opening_post_id = cache.get(cache_key)
if not opening_post_id:
opening_post_id = self.get_opening_post(only_id=True).id
cache.set(cache_key, opening_post_id)
return opening_post_id
def __unicode__(self):
return str(self.id)
def get_pub_time(self):
"""
Gets opening post's pub time because thread does not have its own one.
"""
return self.get_opening_post().pub_time
def delete(self, using=None):
if self.replies.exists():
self.replies.all().delete()
super(Thread, self).delete(using)