##// END OF EJS Templates
Separate settings to limit first posting from the session or every post
Separate settings to limit first posting from the session or every post

File last commit:

r1591:af1d8bd1 default
r1607:c825aebd default
Show More
tag.py
149 lines | 4.4 KiB | text/x-python | PythonLexer
import hashlib
from boards.models.attachment import FILE_TYPES_IMAGE
from django.template.loader import render_to_string
from django.db import models
from django.db.models import Count
from django.core.urlresolvers import reverse
from boards.models import Attachment
from boards.models.base import Viewable
from boards.models.thread import STATUS_ACTIVE, STATUS_BUMPLIMIT, STATUS_ARCHIVE
from boards.utils import cached_result
import boards
__author__ = 'neko259'
RELATED_TAGS_COUNT = 5
class TagManager(models.Manager):
def get_not_empty_tags(self):
"""
Gets tags that have non-archived threads.
"""
return self.annotate(num_threads=Count('thread_tags')).filter(num_threads__gt=0)\
.order_by('-required', 'name')
def get_tag_url_list(self, tags: list) -> str:
"""
Gets a comma-separated list of tag links.
"""
return ', '.join([tag.get_view() for tag in tags])
class Tag(models.Model, Viewable):
"""
A tag is a text node assigned to the thread. The tag serves as a board
section. There can be multiple tags for each thread
"""
objects = TagManager()
class Meta:
app_label = 'boards'
ordering = ('name',)
name = models.CharField(max_length=100, db_index=True, unique=True)
required = models.BooleanField(default=False, db_index=True)
description = models.TextField(blank=True)
parent = models.ForeignKey('Tag', null=True, blank=True,
related_name='children')
def __str__(self):
return self.name
def is_empty(self) -> bool:
"""
Checks if the tag has some threads.
"""
return self.get_thread_count() == 0
def get_thread_count(self, status=None) -> int:
threads = self.get_threads()
if status is not None:
threads = threads.filter(status=status)
return threads.count()
def get_active_thread_count(self) -> int:
return self.get_thread_count(status=STATUS_ACTIVE)
def get_bumplimit_thread_count(self) -> int:
return self.get_thread_count(status=STATUS_BUMPLIMIT)
def get_archived_thread_count(self) -> int:
return self.get_thread_count(status=STATUS_ARCHIVE)
def get_absolute_url(self):
return reverse('tag', kwargs={'tag_name': self.name})
def get_threads(self):
return self.thread_tags.order_by('-bump_time')
def is_required(self):
return self.required
def get_view(self):
link = '<a class="tag" href="{}">{}</a>'.format(
self.get_absolute_url(), self.name)
if self.is_required():
link = '<b>{}</b>'.format(link)
return link
def get_search_view(self, *args, **kwargs):
return render_to_string('boards/tag.html', {
'tag': self,
})
@cached_result()
def get_post_count(self):
return self.get_threads().aggregate(num_posts=Count('multi_replies'))['num_posts']
def get_description(self):
return self.description
def get_random_image_post(self, status=[STATUS_ACTIVE, STATUS_BUMPLIMIT]):
posts = boards.models.Post.objects.filter(attachments__mimetype__in=FILE_TYPES_IMAGE)\
.annotate(images_count=Count(
'attachments')).filter(images_count__gt=0, threads__tags__in=[self])
if status is not None:
posts = posts.filter(thread__status__in=status)
return posts.order_by('?').first()
def get_first_letter(self):
return self.name and self.name[0] or ''
def get_related_tags(self):
return set(Tag.objects.filter(thread_tags__in=self.get_threads()).exclude(
id=self.id).order_by('?')[:RELATED_TAGS_COUNT])
@cached_result()
def get_color(self):
"""
Gets color hashed from the tag name.
"""
return hashlib.md5(self.name.encode()).hexdigest()[:6]
def get_parent(self):
return self.parent
def get_all_parents(self):
parents = list()
parent = self.get_parent()
if parent and parent not in parents:
parents.insert(0, parent)
parents = parent.get_all_parents() + parents
return parents
def get_children(self):
return self.children
def get_images(self):
return Attachment.objects.filter(
attachment_posts__thread__tags__in=[self]).filter(
mimetype__in=FILE_TYPES_IMAGE).order_by('-attachment_posts__pub_time')