thread.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. from django.shortcuts import get_object_or_404
  2. from django.utils.translation import ugettext as _
  3. from misago.acl import add_acl
  4. from misago.categories.models import PRIVATE_THREADS_ROOT, THREADS_ROOT, Category
  5. from misago.core.shortcuts import validate_slug
  6. from misago.core.viewmodel import ViewModel as BaseViewModel
  7. from misago.readtracker.threadstracker import make_read_aware
  8. from misago.threads.models import Poll, Thread
  9. from misago.threads.participants import make_participants_aware
  10. from misago.threads.permissions import (
  11. allow_see_private_thread, allow_see_thread, allow_use_private_threads)
  12. from misago.threads.serializers import PrivateThreadSerializer, ThreadSerializer
  13. from misago.threads.subscriptions import make_subscription_aware
  14. from misago.threads.threadtypes import trees_map
  15. BASE_RELATIONS = [
  16. 'category',
  17. 'poll',
  18. 'starter',
  19. 'starter__rank',
  20. 'starter__ban_cache',
  21. 'starter__online_tracker',
  22. ]
  23. class ViewModel(BaseViewModel):
  24. def __init__(
  25. self,
  26. request,
  27. pk,
  28. slug=None,
  29. path_aware=False,
  30. read_aware=False,
  31. subscription_aware=False,
  32. poll_votes_aware=False
  33. ):
  34. model = self.get_thread(request, pk, slug)
  35. if path_aware:
  36. model.path = self.get_thread_path(model.category)
  37. add_acl(request.user, model.category)
  38. add_acl(request.user, model)
  39. if read_aware:
  40. make_read_aware(request.user, model)
  41. if subscription_aware:
  42. make_subscription_aware(request.user, model)
  43. self._model = model
  44. try:
  45. self._poll = model.poll
  46. add_acl(request.user, self._poll)
  47. if poll_votes_aware:
  48. self._poll.make_choices_votes_aware(request.user)
  49. except Poll.DoesNotExist:
  50. self._poll = None
  51. @property
  52. def poll(self):
  53. return self._poll
  54. def get_thread(self, request, pk, slug=None):
  55. raise NotImplementedError(
  56. 'Thread view model has to implement get_thread(request, pk, slug=None)'
  57. )
  58. def get_thread_path(self, category):
  59. thread_path = []
  60. if category.level:
  61. categories = Category.objects.filter(
  62. tree_id=category.tree_id, lft__lte=category.lft, rght__gte=category.rght
  63. ).order_by('level')
  64. thread_path = list(categories)
  65. else:
  66. thread_path = [category]
  67. thread_path[0].name = self.get_root_name()
  68. return thread_path
  69. def get_root_name(self):
  70. raise NotImplementedError("Thread view model has to implement get_root_name()")
  71. def get_frontend_context(self):
  72. raise NotImplementedError("Thread view model has to implement get_frontend_context()")
  73. def get_template_context(self):
  74. return {
  75. 'thread': self._model,
  76. 'poll': self._poll,
  77. 'category': self._model.category,
  78. 'breadcrumbs': self._model.path,
  79. }
  80. class ForumThread(ViewModel):
  81. def get_thread(self, request, pk, slug=None):
  82. thread = get_object_or_404(
  83. Thread.objects.select_related(*BASE_RELATIONS),
  84. pk=pk,
  85. category__tree_id=trees_map.get_tree_id_for_root(THREADS_ROOT),
  86. )
  87. allow_see_thread(request.user, thread)
  88. if slug:
  89. validate_slug(thread, slug)
  90. return thread
  91. def get_root_name(self):
  92. return _("Threads")
  93. def get_frontend_context(self):
  94. return ThreadSerializer(self._model).data
  95. class PrivateThread(ViewModel):
  96. def get_thread(self, request, pk, slug=None):
  97. allow_use_private_threads(request.user)
  98. thread = get_object_or_404(
  99. Thread.objects.select_related(*BASE_RELATIONS),
  100. pk=pk,
  101. category__tree_id=trees_map.get_tree_id_for_root(PRIVATE_THREADS_ROOT),
  102. )
  103. make_participants_aware(request.user, thread)
  104. allow_see_private_thread(request.user, thread)
  105. if slug:
  106. validate_slug(thread, slug)
  107. return thread
  108. def get_root_name(self):
  109. return _("Private threads")
  110. def get_frontend_context(self):
  111. return PrivateThreadSerializer(self._model).data