thread.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. from django.core.urlresolvers import reverse
  2. from django.db import models
  3. from django.dispatch import receiver
  4. from misago.conf import settings
  5. from misago.core.shortcuts import paginate
  6. from misago.core.utils import slugify
  7. __all__ = ['Thread']
  8. class Thread(models.Model):
  9. forum = models.ForeignKey('misago_forums.Forum')
  10. label = models.ForeignKey('misago_threads.Label',
  11. null=True, blank=True,
  12. on_delete=models.SET_NULL)
  13. title = models.CharField(max_length=255)
  14. slug = models.CharField(max_length=255)
  15. replies = models.PositiveIntegerField(default=0, db_index=True)
  16. has_reported_posts = models.BooleanField(default=False)
  17. has_moderated_posts = models.BooleanField(default=False)
  18. has_hidden_posts = models.BooleanField(default=False)
  19. has_events = models.BooleanField(default=False)
  20. started_on = models.DateTimeField(db_index=True)
  21. first_post = models.ForeignKey('misago_threads.Post', related_name='+',
  22. null=True, blank=True,
  23. on_delete=models.SET_NULL)
  24. starter = models.ForeignKey(settings.AUTH_USER_MODEL,
  25. null=True, blank=True,
  26. on_delete=models.SET_NULL)
  27. starter_name = models.CharField(max_length=255)
  28. starter_slug = models.CharField(max_length=255)
  29. last_post_on = models.DateTimeField(db_index=True)
  30. last_post = models.ForeignKey('misago_threads.Post', related_name='+',
  31. null=True, blank=True,
  32. on_delete=models.SET_NULL)
  33. last_poster = models.ForeignKey(settings.AUTH_USER_MODEL,
  34. related_name='last_poster_set',
  35. null=True, blank=True,
  36. on_delete=models.SET_NULL)
  37. last_poster_name = models.CharField(max_length=255, null=True, blank=True)
  38. last_poster_slug = models.CharField(max_length=255, null=True, blank=True)
  39. is_pinned = models.BooleanField(default=False, db_index=True)
  40. is_poll = models.BooleanField(default=False)
  41. is_moderated = models.BooleanField(default=False, db_index=True)
  42. is_hidden = models.BooleanField(default=False)
  43. is_closed = models.BooleanField(default=False)
  44. class Meta:
  45. index_together = [
  46. ['forum', 'id'],
  47. ['forum', 'last_post_on'],
  48. ['forum', 'replies'],
  49. ]
  50. def __unicode__(self):
  51. return self.title
  52. def delete(self, *args, **kwargs):
  53. from misago.threads.signals import delete_thread
  54. delete_thread.send(sender=self)
  55. super(Thread, self).delete(*args, **kwargs)
  56. def merge(self, other_thread):
  57. if self.pk == other_thread.pk:
  58. raise ValueError("thread can't be merged with itself")
  59. from misago.threads.signals import merge_thread
  60. merge_thread.send(sender=self, other_thread=other_thread)
  61. def move(self, new_forum):
  62. from misago.threads.signals import move_thread
  63. self.forum = new_forum
  64. move_thread.send(sender=self)
  65. def synchronize(self):
  66. self.replies = self.post_set.filter(is_moderated=False).count()
  67. if self.replies > 0:
  68. self.replies -= 1
  69. reported_post_qs = self.post_set.filter(is_reported=True)[:1]
  70. self.has_reported_posts = reported_post_qs.exists()
  71. moderated_post_qs = self.post_set.filter(is_moderated=True)[:1]
  72. self.has_moderated_posts = moderated_post_qs.exists()
  73. hidden_post_qs = self.post_set.filter(is_hidden=True)[:1]
  74. self.has_hidden_posts = hidden_post_qs.exists()
  75. self.has_events = self.event_set.exists()
  76. first_post = self.post_set.order_by('id')[:1][0]
  77. self.set_first_post(first_post)
  78. self.is_moderated = first_post.is_moderated
  79. self.is_hidden = first_post.is_hidden
  80. last_post_qs = self.post_set.filter(is_moderated=False).order_by('-id')
  81. last_post = last_post_qs[:1]
  82. if last_post:
  83. self.set_last_post(last_post[0])
  84. else:
  85. self.set_last_post(first_post)
  86. @property
  87. def link_prefix(self):
  88. if self.forum.special_role == 'private_threads':
  89. return 'private_thread'
  90. else:
  91. return 'thread'
  92. def get_url_name(self, suffix=None):
  93. link = 'misago:%s' % self.link_prefix
  94. if suffix:
  95. link = '%s_%s' % (link, suffix)
  96. return link
  97. def get_url(self, suffix=None):
  98. return reverse(self.get_url_name(suffix), kwargs={
  99. 'thread_slug': self.slug,
  100. 'thread_id': self.id
  101. })
  102. def get_absolute_url(self):
  103. return self.get_url()
  104. def get_new_reply_url(self):
  105. return self.get_url('new')
  106. def get_last_reply_url(self):
  107. return self.get_url('last')
  108. def set_title(self, title):
  109. self.title = title
  110. self.slug = slugify(title)
  111. def set_first_post(self, post):
  112. self.started_on = post.posted_on
  113. self.first_post = post
  114. self.starter = post.poster
  115. self.starter_name = post.poster_name
  116. if post.poster:
  117. self.starter_slug = post.poster.slug
  118. else:
  119. self.starter_slug = slugify(post.poster_name)
  120. self.is_moderated = post.is_moderated
  121. self.is_hidden = post.is_hidden
  122. def set_last_post(self, post):
  123. self.last_post_on = post.posted_on
  124. self.last_post = post
  125. self.last_poster = post.poster
  126. self.last_poster_name = post.poster_name
  127. if post.poster:
  128. self.last_poster_slug = post.poster.slug
  129. else:
  130. self.last_poster_slug = slugify(post.poster_name)