posting.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. from django.core.urlresolvers import reverse
  2. from django.shortcuts import redirect
  3. from django.template import RequestContext
  4. from django.utils import timezone
  5. from django.utils.translation import ugettext as _
  6. from misago.acl.utils import ACLError403, ACLError404
  7. from misago.forms import FormLayout
  8. from misago.forums.models import Forum
  9. from misago.markdown import post_markdown
  10. from misago.messages import Message
  11. from misago.threads.forms import PostForm
  12. from misago.threads.models import Thread, Post
  13. from misago.threads.views.base import BaseView
  14. from misago.views import error403, error404
  15. from misago.utils import make_pagination, slugify, ugettext_lazy
  16. class PostingView(BaseView):
  17. def fetch_target(self, kwargs):
  18. if self.mode == 'new_thread':
  19. self.fetch_forum(kwargs)
  20. if self.mode in ('edit_thread', 'new_post', 'new_post_quick'):
  21. self.fetch_thread(kwargs)
  22. def fetch_forum(self, kwargs):
  23. self.forum = Forum.objects.get(pk=kwargs['forum'], type='forum')
  24. self.request.acl.forums.allow_forum_view(self.forum)
  25. self.request.acl.threads.allow_new_threads(self.forum)
  26. self.parents = Forum.objects.forum_parents(self.forum.pk, True)
  27. def fetch_thread(self, kwargs):
  28. self.thread = Thread.objects.get(pk=kwargs['thread'])
  29. self.forum = self.thread.forum
  30. self.request.acl.forums.allow_forum_view(self.forum)
  31. self.request.acl.threads.allow_thread_view(self.request.user, self.thread)
  32. self.request.acl.threads.allow_reply(self.thread)
  33. self.parents = Forum.objects.forum_parents(self.forum.pk, True)
  34. if kwargs.get('quote'):
  35. self.quote = Post.objects.select_related('user').get(pk=kwargs['quote'], thread=self.thread.pk)
  36. self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.quote)
  37. def get_form(self, bound=False):
  38. if bound:
  39. return PostForm(self.request.POST,request=self.request,mode=self.mode)
  40. if self.quote:
  41. quote_post = []
  42. if self.quote.user:
  43. quote_post.append('@%s' % self.quote.user.username)
  44. else:
  45. quote_post.append('@%s' % self.quote.user_name)
  46. for line in self.quote.post.splitlines():
  47. quote_post.append('> %s' % line)
  48. quote_post.append('\n')
  49. return PostForm(request=self.request,mode=self.mode,initial={'post': '\n'.join(quote_post)})
  50. return PostForm(request=self.request,mode=self.mode)
  51. def __call__(self, request, **kwargs):
  52. self.request = request
  53. self.forum = None
  54. self.thread = None
  55. self.quote = None
  56. self.post = None
  57. self.parents = None
  58. self.mode = kwargs.get('mode')
  59. if self.request.POST.get('quick_reply') and self.mode == 'new_post':
  60. self.mode = 'new_post_quick'
  61. try:
  62. self.fetch_target(kwargs)
  63. if not request.user.is_authenticated():
  64. raise ACLError403(_("Guest, you have to sign-in to post."))
  65. except (Forum.DoesNotExist, Thread.DoesNotExist, Post.DoesNotExist):
  66. return error404(self.request)
  67. except ACLError403 as e:
  68. return error403(request, e.message)
  69. except ACLError404 as e:
  70. return error404(request, e.message)
  71. message = request.messages.get_message('threads')
  72. if request.method == 'POST':
  73. form = self.get_form(True)
  74. if form.is_valid():
  75. now = timezone.now()
  76. moderation = False
  77. if not request.acl.threads.acl[self.forum.pk]['can_approve']:
  78. if self.mode == 'new_thread' and request.acl.threads.acl[self.forum.pk]['can_start_threads'] == 1:
  79. moderation = True
  80. if self.mode in ['new_post', 'new_post_quick'] and request.acl.threads.acl[self.forum.pk]['can_write_posts'] == 1:
  81. moderation = True
  82. # Get or create new thread
  83. if self.mode in ['new_thread']:
  84. thread = Thread.objects.create(
  85. forum=self.forum,
  86. name=form.cleaned_data['thread_name'],
  87. slug=slugify(form.cleaned_data['thread_name']),
  88. start=now,
  89. last=now,
  90. moderated=moderation,
  91. score=request.settings['thread_ranking_initial_score'],
  92. )
  93. if moderation:
  94. thread.replies_moderated += 1
  95. else:
  96. thread = self.thread
  97. # Create new message
  98. post = Post.objects.create(
  99. forum=self.forum,
  100. thread=thread,
  101. merge=thread.merges,
  102. user=request.user,
  103. user_name=request.user.username,
  104. ip=request.session.get_ip(request),
  105. agent=request.META.get('HTTP_USER_AGENT'),
  106. post=form.cleaned_data['post'],
  107. post_preparsed=post_markdown(request, form.cleaned_data['post']),
  108. date=now,
  109. moderated=moderation,
  110. )
  111. if self.mode == 'new_thread':
  112. thread.start_post = post
  113. thread.start_poster = request.user
  114. thread.start_poster_name = request.user.username
  115. thread.start_poster_slug = request.user.username_slug
  116. if request.user.rank and request.user.rank.style:
  117. thread.start_poster_style = request.user.rank.style
  118. if self.mode in ['new_post', 'new_post_quick']:
  119. if moderation:
  120. thread.replies_moderated += 1
  121. else:
  122. thread.replies += 1
  123. if thread.last_poster_id != request.user.pk:
  124. thread.score += request.settings['thread_ranking_reply_score']
  125. # Notify quoted poster of reply?
  126. if self.quote and self.quote.user_id and self.quote.user_id != request.user.pk:
  127. alert = self.quote.user.alert(ugettext_lazy("%(username)s has replied to your post in thread %(thread)s").message)
  128. alert.profile('username', request.user)
  129. alert.post('thread', self.thread, post)
  130. alert.save_all()
  131. if (self.request.settings.thread_length > 0
  132. and not thread.closed
  133. and thread.replies >= self.request.settings.thread_length):
  134. thread.closed = True
  135. post.set_checkpoint(self.request, 'limit')
  136. if not moderation:
  137. thread.last = now
  138. thread.last_post = post
  139. thread.last_poster = request.user
  140. thread.last_poster_name = request.user.username
  141. thread.last_poster_slug = request.user.username_slug
  142. if request.user.rank and request.user.rank.style:
  143. thread.last_poster_style = request.user.rank.style
  144. thread.save(force_update=True)
  145. # Update forum and monitor
  146. if not moderation:
  147. if self.mode == 'new_thread':
  148. self.request.monitor['threads'] = int(self.request.monitor['threads']) + 1
  149. self.forum.threads += 1
  150. self.forum.threads_delta += 1
  151. if self.mode in ['new_thread', 'new_post', 'new_post_quick']:
  152. self.request.monitor['posts'] = int(self.request.monitor['posts']) + 1
  153. self.forum.posts += 1
  154. self.forum.posts_delta += 1
  155. self.forum.last_thread = thread
  156. self.forum.last_thread_name = thread.name
  157. self.forum.last_thread_slug = thread.slug
  158. self.forum.last_thread_date = thread.last
  159. self.forum.last_poster = thread.last_poster
  160. self.forum.last_poster_name = thread.last_poster_name
  161. self.forum.last_poster_slug = thread.last_poster_slug
  162. self.forum.last_poster_style = thread.last_poster_style
  163. self.forum.save(force_update=True)
  164. # Update user
  165. if not moderation:
  166. if self.mode == 'new_thread':
  167. request.user.threads += 1
  168. request.user.posts += 1
  169. request.user.last_post = thread.last
  170. request.user.save(force_update=True)
  171. if self.mode == 'new_thread':
  172. if moderation:
  173. request.messages.set_flash(Message(_("New thread has been posted. It will be hidden from other members until moderator reviews it.")), 'success', 'threads')
  174. else:
  175. request.messages.set_flash(Message(_("New thread has been posted.")), 'success', 'threads')
  176. return redirect(reverse('thread', kwargs={'thread': thread.pk, 'slug': thread.slug}) + ('#post-%s' % post.pk))
  177. if self.mode in ['new_post', 'new_post_quick']:
  178. if moderation:
  179. request.messages.set_flash(Message(_("Your reply has been posted. It will be hidden from other members until moderator reviews it.")), 'success', 'threads_%s' % post.pk)
  180. else:
  181. request.messages.set_flash(Message(_("Your reply has been posted.")), 'success', 'threads_%s' % post.pk)
  182. pagination = make_pagination(0, self.request.acl.threads.filter_posts(self.request, self.thread, self.thread.post_set).count(), self.request.settings.posts_per_page)
  183. if pagination['total'] > 1:
  184. return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'page': pagination['total']}) + ('#post-%s' % post.pk))
  185. return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % post.pk))
  186. message = Message(form.non_field_errors()[0], 'error')
  187. else:
  188. form = self.get_form()
  189. return request.theme.render_to_response('threads/posting.html',
  190. {
  191. 'mode': self.mode,
  192. 'forum': self.forum,
  193. 'thread': self.thread,
  194. 'post': self.post,
  195. 'quote': self.quote,
  196. 'parents': self.parents,
  197. 'message': message,
  198. 'form': FormLayout(form),
  199. },
  200. context_instance=RequestContext(request));