models.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. from django.conf import settings
  2. from django.core.cache import cache
  3. from django.db import models
  4. from django.utils.translation import ugettext_lazy as _
  5. from mptt.models import MPTTModel,TreeForeignKey
  6. from misago.roles.models import Role
  7. class ForumManager(models.Manager):
  8. forums_tree = None
  9. def token_to_pk(self, token):
  10. self.populate_tree()
  11. try:
  12. return self.forums_tree[token].pk
  13. except KeyError:
  14. return 0
  15. def populate_tree(self, force=False):
  16. if not self.forums_tree:
  17. self.forums_tree = cache.get('forums_tree')
  18. if not self.forums_tree or force:
  19. self.forums_tree = {}
  20. for forum in Forum.objects.order_by('lft'):
  21. self.forums_tree[forum.pk] = forum
  22. if forum.token:
  23. self.forums_tree[forum.token] = forum
  24. cache.set('forums_tree', self.forums_tree)
  25. def forum_parents(self, forum, include_self=False):
  26. self.populate_tree()
  27. parents = []
  28. parent = self.forums_tree[forum]
  29. if include_self:
  30. parents.append(parent)
  31. while parent.level > 1:
  32. parent = self.forums_tree[parent.parent_id]
  33. parents.append(parent)
  34. return reversed(parents)
  35. def treelist(self, acl, parent=None, tracker=None):
  36. complete_list = []
  37. forums_list = []
  38. parents = {}
  39. if parent:
  40. queryset = Forum.objects.filter(pk__in=acl.known_forums).filter(lft__gt=parent.lft).filter(rght__lt=parent.rght).order_by('lft')
  41. else:
  42. queryset = Forum.objects.filter(pk__in=acl.known_forums).order_by('lft')
  43. for forum in queryset:
  44. forum.subforums = []
  45. forum.is_read = False
  46. if tracker:
  47. forum.is_read = tracker.is_read(forum)
  48. parents[forum.pk] = forum
  49. complete_list.append(forum)
  50. if forum.parent_id in parents:
  51. parents[forum.parent_id].subforums.append(forum)
  52. else:
  53. forums_list.append(forum)
  54. # Second iteration - sum up forum counters
  55. for forum in reversed(complete_list):
  56. if forum.parent_id in parents and parents[forum.parent_id].type != 'redirect':
  57. parents[forum.parent_id].threads += forum.threads
  58. parents[forum.parent_id].threads_delta += forum.threads_delta
  59. parents[forum.parent_id].posts += forum.posts
  60. parents[forum.parent_id].posts_delta += forum.posts_delta
  61. if acl.can_browse(forum.pk):
  62. # If forum is unread, make parent unread too
  63. if not forum.is_read:
  64. parents[forum.parent_id].is_read = False
  65. # Sum stats
  66. if forum.last_thread_date and (not parents[forum.parent_id].last_thread_date or forum.last_thread_date > parents[forum.parent_id].last_thread_date):
  67. parents[forum.parent_id].last_thread_id = forum.last_thread_id
  68. parents[forum.parent_id].last_thread_name = forum.last_thread_name
  69. parents[forum.parent_id].last_thread_slug = forum.last_thread_slug
  70. parents[forum.parent_id].last_thread_date = forum.last_thread_date
  71. parents[forum.parent_id].last_poster_id = forum.last_poster_id
  72. parents[forum.parent_id].last_poster_name = forum.last_poster_name
  73. parents[forum.parent_id].last_poster_slug = forum.last_poster_slug
  74. parents[forum.parent_id].last_poster_style = forum.last_poster_style
  75. return forums_list
  76. class Forum(MPTTModel):
  77. parent = TreeForeignKey('self',null=True,blank=True,related_name='children')
  78. type = models.CharField(max_length=12)
  79. token = models.CharField(max_length=255,null=True,blank=True)
  80. name = models.CharField(max_length=255)
  81. slug = models.SlugField(max_length=255)
  82. description = models.TextField(null=True,blank=True)
  83. description_preparsed = models.TextField(null=True,blank=True)
  84. threads = models.PositiveIntegerField(default=0)
  85. threads_delta = models.PositiveIntegerField(default=0)
  86. posts = models.PositiveIntegerField(default=0)
  87. posts_delta = models.IntegerField(default=0)
  88. redirects = models.PositiveIntegerField(default=0)
  89. redirects_delta = models.IntegerField(default=0)
  90. last_thread = models.ForeignKey('threads.Thread',related_name='+',null=True,blank=True,on_delete=models.SET_NULL)
  91. last_thread_name = models.CharField(max_length=255,null=True,blank=True)
  92. last_thread_slug = models.SlugField(max_length=255,null=True,blank=True)
  93. last_thread_date = models.DateTimeField(null=True,blank=True)
  94. last_poster = models.ForeignKey('users.User',related_name='+',null=True,blank=True,on_delete=models.SET_NULL)
  95. last_poster_name = models.CharField(max_length=255,null=True,blank=True)
  96. last_poster_slug = models.SlugField(max_length=255,null=True,blank=True)
  97. last_poster_style = models.CharField(max_length=255,null=True,blank=True)
  98. prune_start = models.PositiveIntegerField(default=0)
  99. prune_last = models.PositiveIntegerField(default=0)
  100. redirect = models.CharField(max_length=255,null=True,blank=True)
  101. template = models.CharField(max_length=255,null=True,blank=True)
  102. style = models.CharField(max_length=255,null=True,blank=True)
  103. closed = models.BooleanField(default=False)
  104. objects = ForumManager()
  105. def __unicode__(self):
  106. if self.token == 'root':
  107. return unicode(_('Root Category'))
  108. return unicode(self.name)
  109. def set_description(self, description):
  110. self.description = description.strip()
  111. self.description_preparsed = ''
  112. if self.description:
  113. import markdown
  114. self.description_preparsed = markdown.markdown(description,safe_mode='escape',output_format=settings.OUTPUT_FORMAT)
  115. def copy_permissions(self, target):
  116. if target.pk != self.pk:
  117. for role in Role.objects.all():
  118. perms = role.get_permissions()
  119. try:
  120. perms['forums'][self.pk] = perms['forums'][target.pk]
  121. role.set_permissions(perms)
  122. role.save(force_update=True)
  123. except KeyError:
  124. pass
  125. def move_content(self, target):
  126. pass
  127. def sync(self):
  128. self.threads = self.thread_set.filter(moderated=0).filter(deleted=0).count()
  129. self.posts = self.post_set.filter(moderated=0).filter(deleted=0).count()
  130. self.last_poster = None
  131. self.last_poster_name = None
  132. self.last_poster_slug = None
  133. self.last_poster_style = None
  134. self.last_thread = None
  135. self.last_thread_date = None
  136. self.last_thread_name = None
  137. self.last_thread_slug = None
  138. try:
  139. last_thread = self.thread_set.filter(moderated=0).filter(deleted=0).order_by('-last').all()[1:][0]
  140. self.last_poster_name = last_thread.last_poster_name
  141. self.last_poster_slug = last_thread.last_poster_slug
  142. self.last_poster_style = last_thread.last_poster_style
  143. if last_thread.last_poster:
  144. self.last_poster = last_thread.last_poster
  145. self.last_thread = last_thread
  146. self.last_thread_date = last_thread.start
  147. self.last_thread_name = last_thread.name
  148. self.last_thread_slug = last_thread.slug
  149. except (IndexError, AttributeError):
  150. pass
  151. def prune(self):
  152. pass