generic.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. """
  2. Module with basic views for use by inheriting actions
  3. """
  4. from django.db.transaction import atomic
  5. from django.shortcuts import redirect, render
  6. from django.views.generic import View
  7. from misago.acl import add_acl
  8. from misago.core.shortcuts import get_object_or_404, paginate, validate_slug
  9. from misago.forums.lists import get_forums_list, get_forum_path
  10. from misago.forums.models import Forum
  11. from misago.forums.permissions import allow_see_forum, allow_browse_forum
  12. from misago.threads.forms.posting import EditorFormset, START, REPLY, EDIT
  13. from misago.threads.models import Thread, Post
  14. from misago.threads.permissions import allow_see_thread, allow_start_thread
  15. class ForumMixin(object):
  16. """
  17. Mixin for getting forums
  18. """
  19. def get_forum(self, request, lock=False, **kwargs):
  20. forum = self.fetch_forum(request, lock, **kwargs)
  21. self.check_forum_permissions(request, forum)
  22. if kwargs.get('forum_slug'):
  23. validate_slug(forum, kwargs.get('forum_slug'))
  24. return forum
  25. def fetch_forum(self, request, lock=False, **kwargs):
  26. queryset = Forum.objects
  27. if lock:
  28. queryset = queryset.select_for_update()
  29. return get_object_or_404(
  30. queryset, id=kwargs.get('forum_id'), role='forum')
  31. def check_forum_permissions(self, request, forum):
  32. add_acl(request.user, forum)
  33. allow_see_forum(request.user, forum)
  34. allow_browse_forum(request.user, forum)
  35. class ThreadMixin(object):
  36. """
  37. Mixin for getting thread
  38. """
  39. def get_thread(self, request, lock=False, **kwargs):
  40. thread = self.fetch_thread(request, lock, **kwargs)
  41. self.check_thread_permissions(request, thread)
  42. if kwargs.get('thread_slug'):
  43. validate_slug(thread, kwargs.get('thread_slug'))
  44. return thread
  45. def fetch_thread(self, request, lock=False, **kwargs):
  46. queryset = Thread.objects
  47. if lock:
  48. queryset = queryset.select_for_update()
  49. return get_object_or_404(queryset, id=kwargs.get('thread_id'))
  50. def check_thread_permissions(self, request, thread):
  51. add_acl(request.user, thread)
  52. allow_see_thread(request.user, thread)
  53. class ViewBase(ForumMixin, View):
  54. templates_dir = ''
  55. template = ''
  56. def final_template(self):
  57. return '%s/%s' % (self.templates_dir, self.template)
  58. def process_context(self, request, context):
  59. """
  60. Simple hook for extending and manipulating template context.
  61. """
  62. return context
  63. def render(self, request, context=None, template=None):
  64. context = self.process_context(request, context or {})
  65. template = template or self.final_template()
  66. return render(request, template, context)
  67. class ForumView(ViewBase):
  68. """
  69. Basic view for threads lists
  70. """
  71. template = 'list.html'
  72. def get_threads(self, request, forum, **kwargs):
  73. return forum.thread_set
  74. def dispatch(self, request, *args, **kwargs):
  75. forum = self.get_forum(request, **kwargs)
  76. forum.subforums = get_forums_list(request.user, forum)
  77. threads = self.get_threads(request, forum, **kwargs)
  78. return self.render(request, {
  79. 'forum': forum,
  80. 'path': get_forum_path(forum),
  81. })
  82. class ThreadView(ViewBase):
  83. """
  84. Basic view for threads
  85. """
  86. def fetch_thread(self, request, **kwargs):
  87. pass
  88. def dispatch(self, request, *args, **kwargs):
  89. thread = self.fetch_thread(request, **kwargs)
  90. class PostView(ViewBase):
  91. """
  92. Basic view for posts
  93. """
  94. def fetch_post(self, request, **kwargs):
  95. pass
  96. def dispatch(self, request, *args, **kwargs):
  97. post = self.fetch_post(request, **kwargs)
  98. class EditorView(ViewBase):
  99. """
  100. Basic view for starting/replying/editing
  101. """
  102. template = 'editor.html'
  103. def find_mode(self, request, *args, **kwargs):
  104. """
  105. First step: guess from request what kind of view we are
  106. """
  107. is_post = request.method == 'POST'
  108. if 'forum_id' in kwargs:
  109. mode = START
  110. user = request.user
  111. forum = self.get_forum(request, lock=is_post, **kwargs)
  112. thread = Thread(forum=forum, starter=user, last_poster=user)
  113. post = Post(forum=forum, thread=thread, poster=user)
  114. quote = Post(0)
  115. elif 'thread_id' in kwargs:
  116. thread = self.get_thread(request, lock=is_post, **kwargs)
  117. forum = thread.forum
  118. return mode, forum, thread, post, quote
  119. def allow_mode(self, user, mode, forum, thread, post, quote):
  120. """
  121. Second step: check start/reply/edit permissions
  122. """
  123. if mode == START:
  124. self.allow_start(user, forum)
  125. if mode == REPLY:
  126. self.allow_reply(user, forum, thread, quote)
  127. if mode == EDIT:
  128. self.allow_edit(user, forum, thread, post)
  129. def allow_start(self, user, forum):
  130. allow_start_thread(user, forum)
  131. def allow_reply(self, user, forum, thread, quote):
  132. raise NotImplementedError()
  133. def allow_edit(self, user, forum, thread, post):
  134. raise NotImplementedError()
  135. def dispatch(self, request, *args, **kwargs):
  136. if request.method == 'POST':
  137. with atomic():
  138. return self.real_dispatch(request, *args, **kwargs)
  139. else:
  140. return self.real_dispatch(request, *args, **kwargs)
  141. def real_dispatch(self, request, *args, **kwargs):
  142. mode_context = self.find_mode(request, *args, **kwargs)
  143. self.allow_mode(request.user, *mode_context)
  144. mode, forum, thread, post, quote = mode_context
  145. formset = EditorFormset(request=request,
  146. mode=mode,
  147. user=request.user,
  148. forum=forum,
  149. thread=thread,
  150. post=post,
  151. quote=quote)
  152. if request.method == 'POST':
  153. if 'submit' in request.POST and formset.is_valid():
  154. formset.save()
  155. return redirect('misago:index')
  156. else:
  157. formset.update()
  158. return self.render(request, {
  159. 'mode': mode,
  160. 'formset': formset,
  161. 'forms': formset.get_forms_list(),
  162. 'main_forms': formset.get_main_forms(),
  163. 'supporting_forms': formset.get_supporting_forms(),
  164. 'forum': forum,
  165. 'path': get_forum_path(forum),
  166. 'thread': thread,
  167. 'post': post,
  168. 'quote': quote
  169. })