models.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. from django.db import models
  2. from django.utils import timezone
  3. from django.utils.translation import ugettext_lazy as _
  4. from misago.forums.signals import move_forum_content
  5. from misago.users.signals import delete_user_content, rename_user
  6. from misago.utils import slugify
  7. class ThreadManager(models.Manager):
  8. def filter_stats(self, start, end):
  9. return self.filter(start__gte=start).filter(start__lte=end)
  10. class Thread(models.Model):
  11. forum = models.ForeignKey('forums.Forum')
  12. weight = models.PositiveIntegerField(default=0, db_index=True)
  13. type = models.PositiveIntegerField(default=0)
  14. name = models.CharField(max_length=255)
  15. slug = models.SlugField(max_length=255)
  16. replies = models.PositiveIntegerField(default=0)
  17. replies_reported = models.PositiveIntegerField(default=0)
  18. replies_moderated = models.PositiveIntegerField(default=0)
  19. replies_deleted = models.PositiveIntegerField(default=0)
  20. merges = models.PositiveIntegerField(default=0, db_index=True)
  21. score = models.PositiveIntegerField(default=30, db_index=True)
  22. upvotes = models.PositiveIntegerField(default=0)
  23. downvotes = models.PositiveIntegerField(default=0)
  24. start = models.DateTimeField(db_index=True)
  25. start_post = models.ForeignKey('Post', related_name='+', null=True, blank=True, on_delete=models.SET_NULL)
  26. start_poster = models.ForeignKey('users.User', null=True, blank=True)
  27. start_poster_name = models.CharField(max_length=255)
  28. start_poster_slug = models.SlugField(max_length=255)
  29. start_poster_style = models.CharField(max_length=255, null=True, blank=True)
  30. last = models.DateTimeField(db_index=True)
  31. last_post = models.ForeignKey('Post', related_name='+', null=True, blank=True, on_delete=models.SET_NULL)
  32. last_poster = models.ForeignKey('users.User', related_name='+', null=True, blank=True)
  33. last_poster_name = models.CharField(max_length=255, null=True, blank=True)
  34. last_poster_slug = models.SlugField(max_length=255, null=True, blank=True)
  35. last_poster_style = models.CharField(max_length=255, null=True, blank=True)
  36. moderated = models.BooleanField(default=False, db_index=True)
  37. deleted = models.BooleanField(default=False, db_index=True)
  38. closed = models.BooleanField(default=False)
  39. objects = ThreadManager()
  40. statistics_name = _('New Threads')
  41. def get_date(self):
  42. return self.start
  43. def sync(self):
  44. # Counters
  45. self.replies = self.post_set.filter(moderated=False).filter(deleted=False).count() - 1
  46. if self.replies < 0:
  47. self.replies = 0
  48. self.replies_reported = self.post_set.filter(reported=True).count()
  49. self.replies_moderated = self.post_set.filter(moderated=True).count()
  50. self.replies_deleted = self.post_set.filter(deleted=True).count()
  51. # First post
  52. start_post = self.post_set.order_by('merge', 'id')[0:][0]
  53. self.start = start_post.date
  54. self.start_post = start_post
  55. self.start_poster = start_post.user
  56. self.start_poster_name = start_post.user_name
  57. self.start_poster_slug = slugify(start_post.user_name)
  58. self.start_poster_style = start_post.user.rank.style if start_post.user else ''
  59. self.upvotes = start_post.upvotes
  60. self.downvotes = start_post.downvotes
  61. # Last post
  62. if self.replies > 0:
  63. last_post = self.post_set.order_by('-merge', '-id').filter(moderated=False).filter(deleted=False)[0:][0]
  64. else:
  65. last_post = start_post
  66. self.last = last_post.date
  67. self.last_post = last_post
  68. self.last_poster = last_post.user
  69. self.last_poster_name = last_post.user_name
  70. self.last_poster_slug = slugify(last_post.user_name)
  71. self.last_poster_style = last_post.user.rank.style if last_post.user else ''
  72. # Flags
  73. self.moderated = start_post.moderated
  74. self.deleted = start_post.deleted
  75. self.merges = last_post.merge
  76. class PostManager(models.Manager):
  77. def filter_stats(self, start, end):
  78. return self.filter(date__gte=start).filter(date__lte=end)
  79. class Post(models.Model):
  80. forum = models.ForeignKey('forums.Forum')
  81. thread = models.ForeignKey(Thread)
  82. merge = models.PositiveIntegerField(default=0, db_index=True)
  83. user = models.ForeignKey('users.User', null=True, blank=True)
  84. user_name = models.CharField(max_length=255)
  85. ip = models.GenericIPAddressField()
  86. agent = models.CharField(max_length=255)
  87. post = models.TextField()
  88. post_preparsed = models.TextField()
  89. upvotes = models.PositiveIntegerField(default=0)
  90. downvotes = models.PositiveIntegerField(default=0)
  91. checkpoints = models.BooleanField(default=False, db_index=True)
  92. date = models.DateTimeField()
  93. edits = models.PositiveIntegerField(default=0)
  94. edit_date = models.DateTimeField(null=True, blank=True)
  95. edit_reason = models.CharField(max_length=255, null=True, blank=True)
  96. edit_user = models.ForeignKey('users.User', related_name='+', null=True)
  97. edit_user_name = models.CharField(max_length=255, null=True, blank=True)
  98. edit_user_slug = models.SlugField(max_length=255, null=True, blank=True)
  99. reported = models.BooleanField(default=False)
  100. moderated = models.BooleanField(default=False, db_index=True)
  101. deleted = models.BooleanField(default=False, db_index=True)
  102. protected = models.BooleanField(default=False)
  103. objects = PostManager()
  104. statistics_name = _('New Posts')
  105. def get_date(self):
  106. return self.date
  107. def set_checkpoint(self, request, action):
  108. if request.user.is_authenticated():
  109. self.checkpoints = True
  110. self.checkpoint_set.create(
  111. forum=self.forum,
  112. thread=self.thread,
  113. post=self,
  114. action=action,
  115. user=request.user,
  116. user_name=request.user.username,
  117. user_slug=request.user.username_slug,
  118. date=timezone.now(),
  119. ip=request.session.get_ip(request),
  120. agent=request.META.get('HTTP_USER_AGENT'),
  121. )
  122. class Change(models.Model):
  123. forum = models.ForeignKey('forums.Forum')
  124. thread = models.ForeignKey(Thread)
  125. post = models.ForeignKey(Post)
  126. user = models.ForeignKey('users.User', null=True, blank=True)
  127. user_name = models.CharField(max_length=255)
  128. user_slug = models.CharField(max_length=255)
  129. date = models.DateTimeField()
  130. ip = models.GenericIPAddressField()
  131. agent = models.CharField(max_length=255)
  132. reason = models.CharField(max_length=255, null=True, blank=True)
  133. thread_name_new = models.CharField(max_length=255, null=True, blank=True)
  134. thread_name_old = models.CharField(max_length=255, null=True, blank=True)
  135. post_content = models.TextField()
  136. size = models.IntegerField(default=0)
  137. change = models.IntegerField(default=0)
  138. class Checkpoint(models.Model):
  139. forum = models.ForeignKey('forums.Forum')
  140. thread = models.ForeignKey(Thread)
  141. post = models.ForeignKey(Post)
  142. action = models.CharField(max_length=255)
  143. user = models.ForeignKey('users.User', null=True, blank=True)
  144. user_name = models.CharField(max_length=255)
  145. user_slug = models.CharField(max_length=255)
  146. date = models.DateTimeField()
  147. ip = models.GenericIPAddressField()
  148. agent = models.CharField(max_length=255)
  149. """
  150. Signals
  151. """
  152. def rename_user_handler(sender, **kwargs):
  153. Thread.objects.filter(start_poster=sender).update(
  154. start_poster_name=sender.username,
  155. start_poster_slug=sender.username_slug,
  156. )
  157. Thread.objects.filter(last_poster=sender).update(
  158. last_poster_name=sender.username,
  159. last_poster_slug=sender.username_slug,
  160. )
  161. Post.objects.filter(user=sender).update(
  162. user_name=sender.username,
  163. )
  164. Post.objects.filter(edit_user=sender).update(
  165. edit_user_name=sender.username,
  166. edit_user_slug=sender.username_slug,
  167. )
  168. Change.objects.filter(user=sender).update(
  169. user_name=sender.username,
  170. user_slug=sender.username_slug,
  171. )
  172. Checkpoint.objects.filter(user=sender).update(
  173. user_name=sender.username,
  174. user_slug=sender.username_slug,
  175. )
  176. rename_user.connect(rename_user_handler, dispatch_uid="rename_user_threads")
  177. def delete_user_content_handler(sender, **kwargs):
  178. Thread.objects.filter(start_poster=sender).delete()
  179. threads = []
  180. prev_posts = []
  181. for post in sender.post_set.filter(checkpoints=True):
  182. threads.append(post.thread_id)
  183. prev_post = Post.objects.filter(thread=post.thread_id).exclude(user=sender).order_by('-id')[:1][0]
  184. post.checkpoint_set.update(post=prev_post)
  185. if not prev_post.pk in prev_posts:
  186. prev_posts.append(prev_post.pk)
  187. sender.post_set.all().delete()
  188. Post.objects.filter(id__in=prev_posts).update(checkpoints=True)
  189. for post in sender.post_set.distinct().values('thread_id').iterator():
  190. if not post['thread_id'] in threads:
  191. threads.append(post['thread_id'])
  192. Post.objects.filter(user=sender).delete()
  193. for thread in Thread.objects.filter(id__in=threads):
  194. thread.sync()
  195. thread.save(force_update=True)
  196. delete_user_content.connect(delete_user_content_handler, dispatch_uid="delete_user_threads_posts")
  197. def move_forum_content_handler(sender, **kwargs):
  198. Thread.objects.filter(forum=sender).update(forum=kwargs['move_to'])
  199. Post.objects.filter(forum=sender).update(forum=kwargs['move_to'])
  200. Change.objects.filter(forum=sender).update(forum=kwargs['move_to'])
  201. Checkpoint.objects.filter(forum=sender).update(forum=kwargs['move_to'])
  202. move_forum_content.connect(move_forum_content_handler, dispatch_uid="move_forum_threads_posts")