changelog.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import difflib
  2. from django.core.urlresolvers import reverse
  3. from django.shortcuts import redirect
  4. from django.template import RequestContext
  5. from django.utils.translation import ugettext as _
  6. from misago.acl.utils import ACLError403, ACLError404
  7. from misago.forums.models import Forum
  8. from misago.markdown import post_markdown
  9. from misago.messages import Message
  10. from misago.threads.models import Thread, Post, Change
  11. from misago.threads.views.base import BaseView
  12. from misago.views import error403, error404
  13. from misago.utils import make_pagination, slugify
  14. class ChangelogBaseView(BaseView):
  15. def fetch_target(self, kwargs):
  16. self.thread = Thread.objects.get(pk=kwargs['thread'])
  17. self.forum = self.thread.forum
  18. self.proxy = Forum.objects.parents_aware_forum(self.forum)
  19. self.request.acl.forums.allow_forum_view(self.forum)
  20. self.request.acl.threads.allow_thread_view(self.request.user, self.thread)
  21. self.parents = Forum.objects.forum_parents(self.forum.pk, True)
  22. self.post = Post.objects.select_related('user').get(pk=kwargs['post'], thread=self.thread.pk)
  23. self.post.thread = self.thread
  24. self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.post)
  25. self.request.acl.threads.allow_changelog_view(self.request.user, self.forum, self.post)
  26. def dispatch(self, request, **kwargs):
  27. raise NotImplementedError('ChangelogBaseView cannot be called directly. Did you forget to define custom "dispatch" method?')
  28. def __call__(self, request, **kwargs):
  29. self.request = request
  30. self.forum = None
  31. self.thread = None
  32. self.post = None
  33. try:
  34. self.fetch_target(kwargs)
  35. if not request.user.is_authenticated():
  36. raise ACLError403(_("Guest, you have to sign-in in order to see posts changelogs."))
  37. except (Forum.DoesNotExist, Thread.DoesNotExist, Post.DoesNotExist, Change.DoesNotExist):
  38. return error404(self.request)
  39. except ACLError403 as e:
  40. return error403(request, e.message)
  41. except ACLError404 as e:
  42. return error404(request, e.message)
  43. return self.dispatch(request, **kwargs)
  44. class ChangelogView(ChangelogBaseView):
  45. def dispatch(self, request, **kwargs):
  46. return request.theme.render_to_response('threads/changelog.html',
  47. {
  48. 'forum': self.forum,
  49. 'parents': self.parents,
  50. 'thread': self.thread,
  51. 'post': self.post,
  52. 'edits': self.post.change_set.prefetch_related('user').order_by('-id')
  53. },
  54. context_instance=RequestContext(request))
  55. class ChangelogDiffView(ChangelogBaseView):
  56. def fetch_target(self, kwargs):
  57. super(ChangelogDiffView, self).fetch_target(kwargs)
  58. self.change = self.post.change_set.get(pk=kwargs['change'])
  59. def dispatch(self, request, **kwargs):
  60. try:
  61. next = self.post.change_set.filter(id__gt=self.change.pk)[:1][0]
  62. except IndexError:
  63. next = None
  64. try:
  65. prev = self.post.change_set.filter(id__lt=self.change.pk).order_by('-id')[:1][0]
  66. except IndexError:
  67. prev = None
  68. self.forum.closed = self.proxy.closed
  69. return request.theme.render_to_response('threads/changelog_diff.html',
  70. {
  71. 'forum': self.forum,
  72. 'parents': self.parents,
  73. 'thread': self.thread,
  74. 'post': self.post,
  75. 'change': self.change,
  76. 'next': next,
  77. 'prev': prev,
  78. 'message': request.messages.get_message('changelog'),
  79. 'l': 1,
  80. 'diff': difflib.ndiff(self.change.post_content.splitlines(), self.post.post.splitlines()),
  81. },
  82. context_instance=RequestContext(request))
  83. class ChangelogRevertView(ChangelogDiffView):
  84. def fetch_target(self, kwargs):
  85. super(ChangelogDiffView, self).fetch_target(kwargs)
  86. self.change = self.post.change_set.get(pk=kwargs['change'])
  87. self.request.acl.threads.allow_revert(self.proxy, self.thread)
  88. def dispatch(self, request, **kwargs):
  89. if ((not self.change.thread_name_old or self.thread.name == self.change.thread_name_old)
  90. and (self.change.post_content == self.post.post)):
  91. request.messages.set_flash(Message(_("No changes to revert.")), 'error', 'changelog')
  92. return redirect(reverse('changelog_diff', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'post': self.post.pk, 'change': self.change.pk}))
  93. if self.change.thread_name_old and self.change.thread_name_old != self.thread.name:
  94. self.thread.name = self.change.thread_name_old
  95. self.thread.slug = slugify(self.change.thread_name_old)
  96. self.thread.save(force_update=True)
  97. if self.forum.last_thread_id == self.thread.pk:
  98. self.forum.last_thread_name = self.change.thread_name_old
  99. self.forum.last_thread_slug = slugify(self.change.thread_name_old)
  100. self.forum.save(force_update=True)
  101. if self.change.post_content != self.post.post:
  102. self.post.post = self.change.post_content
  103. self.post.post_preparsed = post_markdown(request, self.change.post_content)
  104. self.post.save(force_update=True)
  105. request.messages.set_flash(Message(_("Post has been reverted previous state.")), 'success', 'threads_%s' % self.post.pk)
  106. pagination = make_pagination(0, request.acl.threads.filter_posts(self.request, self.thread, self.thread.post_set).filter(id__lte=self.post.pk).count(), self.request.settings.posts_per_page)
  107. if pagination['total'] > 1:
  108. return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'page': pagination['total']}) + ('#post-%s' % self.post.pk))
  109. return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % self.post.pk))