thread.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. from django.shortcuts import get_object_or_404
  2. from django.utils.translation import gettext as _
  3. from misago.acl import add_acl
  4. from misago.categories.models import THREADS_ROOT_NAME, 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 ..models import Poll, Thread
  9. from ..permissions.threads import allow_see_thread
  10. from ..serializers import ThreadSerializer
  11. from ..subscriptions import make_subscription_aware
  12. from ..threadtypes import trees_map
  13. __all__ = ['ForumThread', 'PrivateThread']
  14. BASE_RELATIONS = (
  15. 'category',
  16. 'poll',
  17. 'starter',
  18. 'starter__rank',
  19. 'starter__ban_cache',
  20. 'starter__online_tracker'
  21. )
  22. class ViewModel(BaseViewModel):
  23. def __init__(self, request, pk, slug=None, read_aware=False,
  24. subscription_aware=False, poll_votes_aware=False, select_for_update=False):
  25. model = self.get_thread(request, pk, slug, select_for_update)
  26. model.path = self.get_thread_path(model.category)
  27. add_acl(request.user, model.category)
  28. add_acl(request.user, model)
  29. if read_aware:
  30. make_read_aware(request.user, model)
  31. if subscription_aware:
  32. make_subscription_aware(request.user, model)
  33. self._model = model
  34. try:
  35. self._poll = model.poll
  36. add_acl(request.user, self._poll)
  37. if poll_votes_aware:
  38. self._poll.make_choices_votes_aware(request.user)
  39. except Poll.DoesNotExist:
  40. self._poll = None
  41. @property
  42. def poll(self):
  43. return self._poll
  44. def get_thread(self, request, pk, slug=None, select_for_update=False):
  45. raise NotImplementedError('Thread view model has to implement get_thread(request, pk, slug=None)')
  46. def get_thread_path(self, category):
  47. thread_path = []
  48. if category.level:
  49. categories = Category.objects.filter(
  50. tree_id=category.tree_id,
  51. lft__lte=category.lft,
  52. rght__gte=category.rght
  53. ).order_by('level')
  54. thread_path = list(categories)
  55. else:
  56. thread_path = [category]
  57. thread_path[0].name = self.get_root_name()
  58. return thread_path
  59. def get_root_name(self):
  60. raise NotImplementedError('Thread view model has to implement get_root_name()')
  61. def get_frontend_context(self):
  62. return ThreadSerializer(self._model).data
  63. def get_template_context(self):
  64. return {
  65. 'thread': self._model,
  66. 'poll': self._poll,
  67. 'category': self._model.category,
  68. 'breadcrumbs': self._model.path
  69. }
  70. class ForumThread(ViewModel):
  71. def get_thread(self, request, pk, slug=None, select_for_update=False):
  72. if select_for_update:
  73. queryset = Thread.objects.select_for_update()
  74. else:
  75. queryset = Thread.objects.select_related(*BASE_RELATIONS)
  76. thread = get_object_or_404(
  77. queryset,
  78. pk=pk,
  79. category__tree_id=trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)
  80. )
  81. allow_see_thread(request.user, thread)
  82. if slug:
  83. validate_slug(thread, slug)
  84. return thread
  85. def get_root_name(self):
  86. return _("Threads")
  87. class PrivateThread(ViewModel):
  88. pass