123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- from django.db import models
- from django.db.models import F
- from django.utils import timezone
- from django.utils.translation import ugettext_lazy as _
- from misago.forums.signals import move_forum_content
- from misago.threads.signals import move_thread, merge_thread, move_post, merge_post
- from misago.users.signals import delete_user_content, rename_user
- from misago.utils import slugify, ugettext_lazy
- from misago.watcher.models import ThreadWatch
- class ThreadManager(models.Manager):
- def filter_stats(self, start, end):
- return self.filter(start__gte=start).filter(start__lte=end)
- class Thread(models.Model):
- forum = models.ForeignKey('forums.Forum')
- weight = models.PositiveIntegerField(default=0)
- type = models.PositiveIntegerField(default=0)
- name = models.CharField(max_length=255)
- slug = models.SlugField(max_length=255)
- replies = models.PositiveIntegerField(default=0)
- replies_reported = models.PositiveIntegerField(default=0)
- replies_moderated = models.PositiveIntegerField(default=0)
- replies_deleted = models.PositiveIntegerField(default=0)
- merges = models.PositiveIntegerField(default=0)
- score = models.PositiveIntegerField(default=30)
- upvotes = models.PositiveIntegerField(default=0)
- downvotes = models.PositiveIntegerField(default=0)
- start = models.DateTimeField()
- start_post = models.ForeignKey('Post', related_name='+', null=True, blank=True, on_delete=models.SET_NULL)
- start_poster = models.ForeignKey('users.User', null=True, blank=True, on_delete=models.SET_NULL)
- start_poster_name = models.CharField(max_length=255)
- start_poster_slug = models.SlugField(max_length=255)
- start_poster_style = models.CharField(max_length=255, null=True, blank=True)
- last = models.DateTimeField()
- last_post = models.ForeignKey('Post', related_name='+', null=True, blank=True, on_delete=models.SET_NULL)
- last_poster = models.ForeignKey('users.User', related_name='+', null=True, blank=True, on_delete=models.SET_NULL)
- last_poster_name = models.CharField(max_length=255, null=True, blank=True)
- last_poster_slug = models.SlugField(max_length=255, null=True, blank=True)
- last_poster_style = models.CharField(max_length=255, null=True, blank=True)
- moderated = models.BooleanField(default=False)
- deleted = models.BooleanField(default=False)
- closed = models.BooleanField(default=False)
- objects = ThreadManager()
- statistics_name = _('New Threads')
- def get_date(self):
- return self.start
- def move_to(self, move_to):
- move_thread.send(sender=self, move_to=move_to)
- self.forum = move_to
- def merge_with(self, thread, merge):
- merge_thread.send(sender=self, new_thread=thread, merge=merge)
- def sync(self):
- # Counters
- self.replies = self.post_set.filter(moderated=False).count() - 1
- if self.replies < 0:
- self.replies = 0
- self.replies_reported = self.post_set.filter(reported=True).count()
- self.replies_moderated = self.post_set.filter(moderated=True).count()
- self.replies_deleted = self.post_set.filter(deleted=True).count()
- # First post
- start_post = self.post_set.order_by('merge', 'id')[0:][0]
- self.start = start_post.date
- self.start_post = start_post
- self.start_poster = start_post.user
- self.start_poster_name = start_post.user_name
- self.start_poster_slug = slugify(start_post.user_name)
- self.start_poster_style = start_post.user.rank.style if start_post.user else ''
- self.upvotes = start_post.upvotes
- self.downvotes = start_post.downvotes
- # Last visible post
- if self.replies > 0:
- last_post = self.post_set.order_by('-merge', '-id').filter(moderated=False)[0:][0]
- else:
- last_post = start_post
- self.last = last_post.date
- self.last_post = last_post
- self.last_poster = last_post.user
- self.last_poster_name = last_post.user_name
- self.last_poster_slug = slugify(last_post.user_name)
- self.last_poster_style = last_post.user.rank.style if last_post.user else ''
- # Flags
- self.moderated = start_post.moderated
- self.deleted = start_post.deleted
- self.merges = last_post.merge
-
- def email_watchers(self, request, post):
- from misago.acl.builder import get_acl
- from misago.acl.utils import ACLError403, ACLError404
-
- for watch in ThreadWatch.objects.filter(thread=self).filter(email=True).filter(last_read__gte=self.previous_last):
- user = watch.user
- if user.pk != request.user.pk:
- try:
- acl = get_acl(request, user)
- acl.forums.allow_forum_view(self.forum)
- acl.threads.allow_thread_view(user, self)
- acl.threads.allow_post_view(user, self, post)
- if not user.is_ignoring(request.user):
- user.email_user(
- request,
- 'post_notification',
- _('New reply in thread "%(thread)s"') % {'thread': self.name},
- {'author': request.user, 'post': post, 'thread': self}
- )
- except (ACLError403, ACLError404):
- pass
- class PostManager(models.Manager):
- def filter_stats(self, start, end):
- return self.filter(date__gte=start).filter(date__lte=end)
- class Post(models.Model):
- forum = models.ForeignKey('forums.Forum')
- thread = models.ForeignKey(Thread)
- merge = models.PositiveIntegerField(default=0)
- user = models.ForeignKey('users.User', null=True, blank=True, on_delete=models.SET_NULL)
- user_name = models.CharField(max_length=255)
- ip = models.GenericIPAddressField()
- agent = models.CharField(max_length=255)
- post = models.TextField()
- post_preparsed = models.TextField()
- upvotes = models.PositiveIntegerField(default=0)
- downvotes = models.PositiveIntegerField(default=0)
- mentions = models.ManyToManyField('users.User', related_name="mention_set")
- checkpoints = models.BooleanField(default=False)
- date = models.DateTimeField()
- edits = models.PositiveIntegerField(default=0)
- edit_date = models.DateTimeField(null=True, blank=True)
- edit_reason = models.CharField(max_length=255, null=True, blank=True)
- edit_user = models.ForeignKey('users.User', related_name='+', null=True, blank=True, on_delete=models.SET_NULL)
- edit_user_name = models.CharField(max_length=255, null=True, blank=True)
- edit_user_slug = models.SlugField(max_length=255, null=True, blank=True)
- reported = models.BooleanField(default=False)
- moderated = models.BooleanField(default=False)
- deleted = models.BooleanField(default=False)
- protected = models.BooleanField(default=False)
- objects = PostManager()
- statistics_name = _('New Posts')
- def get_date(self):
- return self.date
- def move_to(self, thread):
- move_post.send(sender=self, move_to=thread)
- self.thread = thread
- self.forum = thread.forum
-
- def merge_with(self, post):
- post.post = '%s\n- - -\n%s' % (post.post, self.post)
- merge_post.send(sender=self, new_post=post)
- def set_checkpoint(self, request, action):
- if request.user.is_authenticated():
- self.checkpoints = True
- self.checkpoint_set.create(
- forum=self.forum,
- thread=self.thread,
- post=self,
- action=action,
- user=request.user,
- user_name=request.user.username,
- user_slug=request.user.username_slug,
- date=timezone.now(),
- ip=request.session.get_ip(request),
- agent=request.META.get('HTTP_USER_AGENT'),
- )
-
- def notify_mentioned(self, request, users):
- from misago.acl.builder import get_acl
- from misago.acl.utils import ACLError403, ACLError404
-
- mentioned = self.mentions.all()
- for slug, user in users.items():
- if user.pk != request.user.pk and user not in mentioned:
- self.mentions.add(user)
- try:
- acl = get_acl(request, user)
- acl.forums.allow_forum_view(self.forum)
- acl.threads.allow_thread_view(user, self.thread)
- acl.threads.allow_post_view(user, self.thread, self)
- if not user.is_ignoring(request.user):
- alert = user.alert(ugettext_lazy("%(username)s has mentioned you in his reply in thread %(thread)s").message)
- alert.profile('username', request.user)
- alert.post('thread', self.thread, self)
- alert.save_all()
- except (ACLError403, ACLError404):
- pass
- class Karma(models.Model):
- forum = models.ForeignKey('forums.Forum')
- thread = models.ForeignKey(Thread)
- post = models.ForeignKey(Post)
- user = models.ForeignKey('users.User', null=True, blank=True, on_delete=models.SET_NULL)
- user_name = models.CharField(max_length=255)
- user_slug = models.CharField(max_length=255)
- date = models.DateTimeField()
- ip = models.GenericIPAddressField()
- agent = models.CharField(max_length=255)
- score = models.IntegerField(default=0)
-
- class Change(models.Model):
- forum = models.ForeignKey('forums.Forum')
- thread = models.ForeignKey(Thread)
- post = models.ForeignKey(Post)
- user = models.ForeignKey('users.User', null=True, blank=True, on_delete=models.SET_NULL)
- user_name = models.CharField(max_length=255)
- user_slug = models.CharField(max_length=255)
- date = models.DateTimeField()
- ip = models.GenericIPAddressField()
- agent = models.CharField(max_length=255)
- reason = models.CharField(max_length=255, null=True, blank=True)
- thread_name_new = models.CharField(max_length=255, null=True, blank=True)
- thread_name_old = models.CharField(max_length=255, null=True, blank=True)
- post_content = models.TextField()
- size = models.IntegerField(default=0)
- change = models.IntegerField(default=0)
- class Checkpoint(models.Model):
- forum = models.ForeignKey('forums.Forum')
- thread = models.ForeignKey(Thread)
- post = models.ForeignKey(Post)
- action = models.CharField(max_length=255)
- user = models.ForeignKey('users.User', null=True, blank=True, on_delete=models.SET_NULL)
- user_name = models.CharField(max_length=255)
- user_slug = models.CharField(max_length=255)
- date = models.DateTimeField()
- ip = models.GenericIPAddressField()
- agent = models.CharField(max_length=255)
- """
- Signals
- """
- def rename_user_handler(sender, **kwargs):
- Thread.objects.filter(start_poster=sender).update(
- start_poster_name=sender.username,
- start_poster_slug=sender.username_slug,
- )
- Thread.objects.filter(last_poster=sender).update(
- last_poster_name=sender.username,
- last_poster_slug=sender.username_slug,
- )
- Post.objects.filter(user=sender).update(
- user_name=sender.username,
- )
- Post.objects.filter(edit_user=sender).update(
- edit_user_name=sender.username,
- edit_user_slug=sender.username_slug,
- )
- Karma.objects.filter(user=sender).update(
- user_name=sender.username,
- user_slug=sender.username_slug,
- )
- Change.objects.filter(user=sender).update(
- user_name=sender.username,
- user_slug=sender.username_slug,
- )
- Checkpoint.objects.filter(user=sender).update(
- user_name=sender.username,
- user_slug=sender.username_slug,
- )
- rename_user.connect(rename_user_handler, dispatch_uid="rename_user_threads")
- def delete_user_content_handler(sender, **kwargs):
- for thread in Thread.objects.filter(start_poster=sender):
- thread.delete()
- threads = []
- prev_posts = []
- for post in sender.post_set.filter(checkpoints=True):
- threads.append(post.thread_id)
- prev_post = Post.objects.filter(thread=post.thread_id).exclude(merge__gt=post.merge).exclude(user=sender).order_by('merge', '-id')[:1][0]
- post.checkpoint_set.update(post=prev_post)
- if not prev_post.pk in prev_posts:
- prev_posts.append(prev_post.pk)
- sender.post_set.all().delete()
- Post.objects.filter(id__in=prev_posts).update(checkpoints=True)
- for post in sender.post_set.distinct().values('thread_id').iterator():
- if not post['thread_id'] in threads:
- threads.append(post['thread_id'])
- for post in Post.objects.filter(user=sender):
- post.delete()
- for thread in Thread.objects.filter(id__in=threads):
- thread.sync()
- thread.save(force_update=True)
- delete_user_content.connect(delete_user_content_handler, dispatch_uid="delete_user_threads_posts")
- def move_forum_content_handler(sender, **kwargs):
- Thread.objects.filter(forum=sender).update(forum=kwargs['move_to'])
- Post.objects.filter(forum=sender).update(forum=kwargs['move_to'])
- Karma.objects.filter(forum=sender).update(forum=kwargs['move_to'])
- Change.objects.filter(forum=sender).update(forum=kwargs['move_to'])
- Checkpoint.objects.filter(forum=sender).update(forum=kwargs['move_to'])
- move_forum_content.connect(move_forum_content_handler, dispatch_uid="move_forum_threads_posts")
- def move_thread_handler(sender, **kwargs):
- Post.objects.filter(forum=sender.forum_pk).update(forum=kwargs['move_to'])
- Karma.objects.filter(forum=sender.forum_pk).update(forum=kwargs['move_to'])
- Change.objects.filter(forum=sender.forum_pk).update(forum=kwargs['move_to'])
- Checkpoint.objects.filter(forum=sender.forum_pk).update(forum=kwargs['move_to'])
- move_thread.connect(move_thread_handler, dispatch_uid="move_thread")
- def merge_thread_handler(sender, **kwargs):
- Post.objects.filter(thread=sender).update(thread=kwargs['new_thread'], merge=F('merge') + kwargs['merge'])
- Karma.objects.filter(thread=sender).update(thread=kwargs['new_thread'])
- Change.objects.filter(thread=sender).update(thread=kwargs['new_thread'])
- Checkpoint.objects.filter(thread=sender).delete()
- merge_thread.connect(merge_thread_handler, dispatch_uid="merge_threads")
- def move_posts_handler(sender, **kwargs):
- Change.objects.filter(post=sender).update(forum=kwargs['move_to'].forum, thread=kwargs['move_to'])
- Karma.objects.filter(post=sender).update(forum=kwargs['move_to'].forum, thread=kwargs['move_to'])
- if sender.checkpoints:
- prev_post = Post.objects.filter(thread=sender.thread_id).filter(merge__lte=sender.merge).exclude(id=sender.pk).order_by('merge', '-id')[:1][0]
- Checkpoint.objects.filter(post=sender).update(post=prev_post)
- prev_post.checkpoints = True
- prev_post.save(force_update=True)
- sender.checkpoints = False
- move_post.connect(move_posts_handler, dispatch_uid="move_posts")
- def merge_posts_handler(sender, **kwargs):
- Change.objects.filter(post=sender).update(post=kwargs['new_post'])
- Checkpoint.objects.filter(post=sender).update(post=kwargs['new_post'])
- Karma.objects.filter(post=sender).update(post=kwargs['new_post'])
- if sender.checkpoints:
- kwargs['new_post'].checkpoints = True
- kwargs['new_post'].upvotes += self.upvotes
- kwargs['new_post'].downvotes += self.downvotes
- kwargs['new_post'].score += self.score
- merge_post.connect(merge_posts_handler, dispatch_uid="merge_posts")
|