|
|
import os
|
|
|
import re
|
|
|
from django.db import models
|
|
|
from django.utils import timezone
|
|
|
import time
|
|
|
|
|
|
from neboard import settings
|
|
|
|
|
|
import thumbs
|
|
|
|
|
|
NO_PARENT = -1
|
|
|
NO_IP = '0.0.0.0'
|
|
|
UNKNOWN_UA = ''
|
|
|
|
|
|
|
|
|
def update_image_filename(instance, filename):
|
|
|
"""Get unique image filename"""
|
|
|
|
|
|
path = 'images/'
|
|
|
new_name = str(int(time.mktime(time.gmtime()))) + '_' + filename
|
|
|
return os.path.join(path, new_name)
|
|
|
|
|
|
|
|
|
class PostManager(models.Manager):
|
|
|
def create_post(self, title, text, image=None, parent_id=NO_PARENT,
|
|
|
ip=NO_IP, tags=None):
|
|
|
post = self.create(title=title,
|
|
|
text=text,
|
|
|
pub_time=timezone.now(),
|
|
|
parent=parent_id,
|
|
|
image=image,
|
|
|
poster_ip=ip,
|
|
|
poster_user_agent=UNKNOWN_UA,
|
|
|
last_edit_time=timezone.now())
|
|
|
|
|
|
if tags:
|
|
|
for tag in tags:
|
|
|
post.tags.add(tag)
|
|
|
|
|
|
if parent_id != NO_PARENT:
|
|
|
parent = self.get(id=parent_id)
|
|
|
parent.last_edit_time=timezone.now()
|
|
|
parent.save()
|
|
|
else:
|
|
|
self._delete_old_threads()
|
|
|
|
|
|
return post
|
|
|
|
|
|
def delete_post(self, post):
|
|
|
children = self.filter(parent=post.id)
|
|
|
for child in children:
|
|
|
self.delete_post(child)
|
|
|
post.delete()
|
|
|
|
|
|
def delete_posts_by_ip(self, ip):
|
|
|
posts = self.filter(poster_ip=ip)
|
|
|
for post in posts:
|
|
|
self.delete_post(post)
|
|
|
|
|
|
def get_threads(self, tag=None):
|
|
|
if tag:
|
|
|
threads = self.filter(parent=NO_PARENT, tags=tag)
|
|
|
else:
|
|
|
threads = self.filter(parent=NO_PARENT)
|
|
|
threads = list(threads.order_by('-last_edit_time'))
|
|
|
|
|
|
return threads
|
|
|
|
|
|
def get_thread(self, opening_post_id):
|
|
|
opening_post = self.get(id=opening_post_id)
|
|
|
|
|
|
if opening_post.parent == NO_PARENT:
|
|
|
replies = self.filter(parent=opening_post_id)
|
|
|
|
|
|
thread = [opening_post]
|
|
|
thread.extend(replies)
|
|
|
|
|
|
return thread
|
|
|
|
|
|
def exists(self, post_id):
|
|
|
posts = self.filter(id=post_id)
|
|
|
|
|
|
return len(posts) > 0
|
|
|
|
|
|
def _delete_old_threads(self):
|
|
|
"""
|
|
|
Preserves maximum thread count. If there are too many threads,
|
|
|
delete the old ones.
|
|
|
"""
|
|
|
|
|
|
# TODO Try to find a better way to get the active thread count.
|
|
|
|
|
|
# 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
|
|
|
old_threads = threads[-num_threads_to_delete:]
|
|
|
|
|
|
for thread in old_threads:
|
|
|
self.delete_post(thread)
|
|
|
|
|
|
|
|
|
class TagManager(models.Manager):
|
|
|
def get_not_empty_tags(self):
|
|
|
all_tags = self.all().order_by('name')
|
|
|
tags = []
|
|
|
for tag in all_tags:
|
|
|
if not tag.is_empty():
|
|
|
tags.append(tag)
|
|
|
|
|
|
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)
|
|
|
# TODO Connect the tag to its posts to check the number of threads for
|
|
|
# the tag.
|
|
|
|
|
|
def __unicode__(self):
|
|
|
return self.name
|
|
|
|
|
|
def is_empty(self):
|
|
|
return self.get_post_count() == 0
|
|
|
|
|
|
def get_post_count(self):
|
|
|
posts_with_tag = Post.objects.get_threads(tag=self)
|
|
|
return len(posts_with_tag)
|
|
|
|
|
|
|
|
|
class Post(models.Model):
|
|
|
"""A post is a message."""
|
|
|
|
|
|
objects = PostManager()
|
|
|
|
|
|
title = models.CharField(max_length=50)
|
|
|
pub_time = models.DateTimeField()
|
|
|
text = models.TextField()
|
|
|
image = thumbs.ImageWithThumbsField(upload_to=update_image_filename,
|
|
|
blank=True, sizes=((200, 150),))
|
|
|
poster_ip = models.IPAddressField()
|
|
|
poster_user_agent = models.TextField()
|
|
|
parent = models.BigIntegerField()
|
|
|
tags = models.ManyToManyField(Tag)
|
|
|
last_edit_time = models.DateTimeField()
|
|
|
|
|
|
def __unicode__(self):
|
|
|
return self.title + ' (' + self.text + ')'
|
|
|
|
|
|
def _get_replies(self):
|
|
|
return Post.objects.filter(parent=self.id)
|
|
|
|
|
|
def get_reply_count(self):
|
|
|
return len(self._get_replies())
|
|
|
|
|
|
def get_images_count(self):
|
|
|
images_count = 1 if self.image else 0
|
|
|
for reply in self._get_replies():
|
|
|
if reply.image:
|
|
|
images_count += 1
|
|
|
|
|
|
return images_count
|
|
|
|
|
|
def get_gets_count(self):
|
|
|
gets_count = 1 if self.is_get() else 0
|
|
|
for reply in self._get_replies():
|
|
|
if reply.is_get():
|
|
|
gets_count += 1
|
|
|
|
|
|
return gets_count
|
|
|
|
|
|
def is_get(self):
|
|
|
"""If the post has pretty id (1, 1000, 77777), than it is called GET"""
|
|
|
|
|
|
# TODO Make a better algorithm for describing gets
|
|
|
return self.id == 1 or self.id % 10 == 0
|
|
|
|
|
|
def get_parsed_text(self):
|
|
|
text = self.text
|
|
|
|
|
|
# TODO Implement parsing
|
|
|
# Make //text colored
|
|
|
# Make >>12 links to posts
|
|
|
|
|
|
return text
|
|
|
|
|
|
|
|
|
class Admin(models.Model):
|
|
|
"""
|
|
|
Model for admin users
|
|
|
"""
|
|
|
name = models.CharField(max_length=100)
|
|
|
password = models.CharField(max_length=100)
|
|
|
|
|
|
def __unicode__(self):
|
|
|
return self.name + '/' + '*' * len(self.password)
|
|
|
|
|
|
|