Browse Source

Delete thread/reply

Ralfp 12 years ago
parent
commit
da9fc03d4a

+ 17 - 0
misago/apps/threads/delete.py

@@ -0,0 +1,17 @@
+from misago.apps.threadtype.delete import *
+from misago.apps.threads.mixins import TypeMixin
+
+class DeleteThreadView(DeleteThreadBaseView, TypeMixin):
+    pass
+
+
+class HideThreadView(HideThreadBaseView, TypeMixin):
+    pass
+
+
+class DeleteReplyView(DeleteReplyBaseView, TypeMixin):
+    pass
+
+
+class HideReplyView(HideReplyBaseView, TypeMixin):
+    pass

+ 4 - 4
misago/apps/threads/urls.py

@@ -22,13 +22,13 @@ urlpatterns = patterns('misago.apps.threads',
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/unwatch/email/$', 'jumps.UnwatchEmailThreadView', name="thread_unwatch_email"),
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/upvote/$', 'jumps.UpvotePostView', name="post_upvote"),
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/downvote/$', 'jumps.DownvotePostView', name="post_downvote"),
+    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/delete/$', 'delete.DeleteThreadView', name="thread_delete", kwargs={'mode': 'delete_thread'}),
+    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/hide/$', 'delete.HideThreadView', name="thread_hide", kwargs={'mode': 'hide_thread'}),
+    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/delete/$', 'delete.DeleteReplyView', name="post_delete", kwargs={'mode': 'delete_post'}),
+    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/hide/$', 'delete.HideReplyView', name="post_hide", kwargs={'mode': 'hide_post'}),
 )
 
 urlpatterns += patterns('misago.apps.errors',
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/delete/$', 'error_not_implemented', name="thread_delete", kwargs={'mode': 'delete_thread'}),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/hide/$', 'error_not_implemented', name="thread_hide", kwargs={'mode': 'hide_thread'}),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/delete/$', 'error_not_implemented', name="post_delete", kwargs={'mode': 'delete_post'}),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/hide/$', 'error_not_implemented', name="post_hide", kwargs={'mode': 'hide_post'}),
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/info/$', 'error_not_implemented', name="post_info"),
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/votes/$', 'error_not_implemented', name="post_votes"),
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/$', 'error_not_implemented', name="changelog"),

+ 142 - 0
misago/apps/threadtype/delete.py

@@ -0,0 +1,142 @@
+from django.core.urlresolvers import reverse
+from django.shortcuts import redirect
+from django.utils import timezone
+from django.utils.translation import ugettext as _
+from misago.acl.exceptions import ACLError403, ACLError404
+from misago.apps.errors import error403, error404
+from misago.messages import Message
+from misago.models import Forum, Thread, Post
+from misago.apps.threadtype.base import ViewBase
+
+class DeleteHideBaseView(ViewBase):
+    def _set_context(self):
+        self.thread = Thread.objects.get(pk=self.kwargs.get('thread'))
+        self.forum = self.thread.forum
+        self.proxy = Forum.objects.parents_aware_forum(self.forum)
+        if self.forum.level:
+            self.parents = Forum.objects.forum_parents(self.forum.pk)
+        self.check_forum_type()
+        self.request.acl.forums.allow_forum_view(self.forum)
+        self.request.acl.threads.allow_thread_view(self.request.user, self.thread)
+
+        if self.kwargs.get('post'):
+            self.post = self.thread.post_set.get(id=self.kwargs.get('post'))
+            self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.post)
+
+        self.set_context()
+
+    def __call__(self, request, **kwargs):
+        self.request = request
+        self.kwargs = kwargs
+        self.parents = []
+        try:
+            self._set_context()
+            self.delete()
+            self.message()
+            return self.response()
+        except (Forum.DoesNotExist, Thread.DoesNotExist, Post.DoesNotExist):
+            return error404(request)
+        except ACLError403 as e:
+            return error403(request, unicode(e))
+        except ACLError404 as e:
+            return error404(request, unicode(e))
+
+
+class DeleteThreadBaseView(DeleteHideBaseView):
+    def set_context(self):
+        self.request.acl.threads.allow_delete_thread(self.request.user, self.proxy,
+                                                     self.thread, self.thread.start_post, True)
+        # Assert we are not user trying to delete thread with replies
+        acl = self.request.acl.threads.get_role(self.thread.forum_id)
+        if not acl['can_delete_threads']:
+            if self.thread.post_set.exclude(user_id=self.request.user.id).count() > 0:
+                raise ACLError403(_("Somebody has already replied to this thread. You cannot delete it."))
+
+    def delete(self):
+        self.thread.delete()
+        self.forum.sync()
+        self.forum.save(force_update=True)
+
+    def message(self):
+        self.request.messages.set_flash(Message(_('Thread "%(thread)s" has been deleted.') % {'thread': self.thread.name}), 'success', 'threads')
+
+    def response(self):
+        return self.threads_list_redirect()
+
+
+class HideThreadBaseView(DeleteHideBaseView):
+    def set_context(self):
+        self.request.acl.threads.allow_delete_thread(self.request.user, self.proxy,
+                                                     self.thread, self.thread.start_post)
+        # Assert we are not user trying to delete thread with replies
+        acl = self.request.acl.threads.get_role(self.thread.forum_id)
+        if not acl['can_delete_threads']:
+            if self.thread.post_set.exclude(user_id=self.request.user.id).count() > 0:
+                raise ACLError403(_("Somebody has already replied to this thread. You cannot delete it."))
+
+    def delete(self):
+        self.thread.start_post.deleted = True
+        self.thread.start_post.save(force_update=True)
+        self.thread.last_post.set_checkpoint(self.request, 'deleted')
+        self.thread.last_post.save(force_update=True)
+        self.thread.sync()
+        self.thread.save(force_update=True)
+        self.forum.sync()
+        self.forum.save(force_update=True)
+
+    def message(self):
+        self.request.messages.set_flash(Message(_('Thread "%(thread)s" has been deleted.') % {'thread': self.thread.name}), 'success', 'threads')
+
+    def response(self):
+        if self.request.acl.threads.can_see_deleted_threads(self.thread.forum):
+            return redirect(reverse(self.type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}))
+        return self.threads_list_redirect()
+
+
+class DeleteReplyBaseView(DeleteHideBaseView):
+    def set_context(self):
+        self.request.acl.threads.allow_delete_post(self.request.user, self.forum,
+                                                   self.thread, self.post, True)
+        acl = self.request.acl.threads.get_role(self.thread.forum_id)
+        if not acl['can_delete_posts'] and self.thread.post_set.filter(id__gt=self.post.pk).count() > 0:
+            raise ACLError403(_("Somebody has already replied to this post, you cannot delete it."))
+
+    def delete(self):
+        self.post.delete()
+        self.thread.sync()
+        self.thread.save(force_update=True)
+        self.forum.sync()
+        self.forum.save(force_update=True)
+
+    def message(self):
+        self.request.messages.set_flash(Message(_("Selected Reply has been deleted.")), 'success', 'threads')
+
+    def response(self):
+        return redirect(reverse(self.type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}))
+
+
+class HideReplyBaseView(DeleteHideBaseView):
+    def set_context(self):
+        self.request.acl.threads.allow_delete_post(self.request.user, self.forum,
+                                                   self.thread, self.post)
+        acl = self.request.acl.threads.get_role(self.thread.forum_id)
+        if not acl['can_delete_posts'] and self.thread.post_set.filter(id__gt=self.post.pk).count() > 0:
+            raise ACLError403(_("Somebody has already replied to this post, you cannot delete it."))
+
+    def delete(self):
+        self.post.deleted = True
+        self.post.edit_date = timezone.now()
+        self.post.edit_user = self.request.user
+        self.post.edit_user_name = self.request.user.username
+        self.post.edit_user_slug = self.request.user.username_slug
+        self.post.save(force_update=True)
+        self.thread.sync()
+        self.thread.save(force_update=True)
+        self.forum.sync()
+        self.forum.save(force_update=True)
+
+    def message(self):
+        self.request.messages.set_flash(Message(_("Selected Reply has been deleted.")), 'success', 'threads_%s' % self.post.pk)
+
+    def response(self):
+        return self.redirect_to_post(self.post)

+ 2 - 1
misago/apps/threadtype/list/views.py

@@ -18,6 +18,7 @@ class ThreadsListBaseView(ViewBase):
         self.request.acl.forums.allow_forum_view(self.forum)
         if self.forum.level:
             self.parents = Forum.objects.forum_parents(self.forum.pk)
+        self.check_forum_type()
         if self.forum.lft + 1 != self.forum.rght:
             self.forum.subforums = Forum.objects.treelist(self.request.acl.forums, self.forum, tracker=ForumsTracker(self.request.user))
 
@@ -99,7 +100,7 @@ class ThreadsListBaseView(ViewBase):
                 response = self.handle_form()
                 if response:
                     return response
-        except Forum.DoesNotExist:
+        except (Forum.DoesNotExist, Thread.DoesNotExist):
             return error404(request)
         except ACLError403 as e:
             return error403(request, unicode(e))

+ 1 - 1
misago/apps/threadtype/thread/views.py

@@ -176,7 +176,7 @@ class ThreadBaseView(ViewBase):
                 response = self.handle_posts_form()
                 if response:
                     return response
-        except Forum.DoesNotExist:
+        except (Forum.DoesNotExist, Thread.DoesNotExist):
             return error404(request)
         except ACLError403 as e:
             return error403(request, unicode(e))