diff --git a/apps/forums/models.py b/apps/forums/models.py index fb5692ad7..083f65507 100644 --- a/apps/forums/models.py +++ b/apps/forums/models.py @@ -95,6 +95,31 @@ class Post(ModelBase): self.thread.forum.last_post = self self.thread.forum.save() + def delete(self, *args, **kwargs): + """Override delete method to update parent thread info.""" + + thread = self.thread + if thread.last_post and thread.last_post.id == self.id: + try: + thread.last_post = thread.post_set.all() \ + .order_by('-created')[1] + except IndexError: + # The thread has only one Post so let the delete cascade. + pass + thread.replies = thread.post_set.count() - 2 + thread.save() + + forum = thread.forum + if forum.last_post and forum.last_post.id == self.id: + try: + forum.last_post = Post.objects.filter(thread__forum=forum) \ + .order_by('-created')[1] + except IndexError: + forum.last_post = None + forum.save() + + super(Post, self).delete(*args, **kwargs) + @property def page(self): """Get the page of the thread on which this post is found.""" diff --git a/apps/forums/templates/confirm_post_delete.html b/apps/forums/templates/confirm_post_delete.html new file mode 100644 index 000000000..62aff599f --- /dev/null +++ b/apps/forums/templates/confirm_post_delete.html @@ -0,0 +1,26 @@ +{# vim: set ts=2 et sts=2 sw=2: #} +{% extends "common/base.html" %} +{# L10n: {t} is the title of the thread. {f} if the name of the forum. #} +{% set title = _('Delete Post | {t} | {f} | Forums')|f(t=thread.title, f=forum.name) %} +{% set crumbs = [(url('forums.forums'), _('Forums')), + (url('forums.threads', forum.slug), forum.name), + (url('forums.posts', forum.slug, thread.id), thread.title), + (None, _('Delete Post'))] %} + +{% block content %} +

{{ _('Are you sure you want to delete this post?') }}

+
+ +
{{ post.author }}
+ +
{{ datetimeformat(post.created, format='longdatetime') }}
+ +
{{ post.content_parsed }}
+ +
+ {{ csrf() }} + {{ _('Cancel') }} + +
+
+{% endblock %} diff --git a/apps/forums/templates/posts.html b/apps/forums/templates/posts.html index bec94546a..0a2e21e9d 100644 --- a/apps/forums/templates/posts.html +++ b/apps/forums/templates/posts.html @@ -51,7 +51,9 @@ {{ _('Edit') }} {% endif %} {% if has_perm('forums_forum.post_delete_forum', forum) %} - {{ _('Delete') }} + + {{ _('Delete') }} + {% endif %} diff --git a/apps/forums/tests/__init__.py b/apps/forums/tests/__init__.py index 4208b8d7e..dcd91b2df 100644 --- a/apps/forums/tests/__init__.py +++ b/apps/forums/tests/__init__.py @@ -20,7 +20,7 @@ class ForumTestCase(TestCase): installed. This will set them to the correct values.""" f1 = Forum.objects.filter()[0] - f1.last_post = Post.objects.get(pk=24) + f1.last_post = Post.objects.get(pk=25) f1.save() t1 = Thread.objects.get(pk=1) diff --git a/apps/forums/tests/test_models.py b/apps/forums/tests/test_models.py index acf1e511f..45b891c57 100644 --- a/apps/forums/tests/test_models.py +++ b/apps/forums/tests/test_models.py @@ -49,3 +49,37 @@ class ForumModelTestCase(ForumTestCase): eq_(1, p.page) p = Post.objects.get(pk=24) eq_(2, p.page) + + def test_last_post_updated(self): + """Adding/Deleting the last post in a thread and forum should + update the last_post field + """ + forum = Forum.objects.get(pk=1) + last_post = forum.last_post + thread = last_post.thread + + # add a new post, then check that last_post is updated + new_post = Post(thread=thread, content="test", author=last_post.author) + new_post.save() + forum = Forum.objects.get(pk=1) + thread = Thread.objects.get(pk=thread.id) + eq_(forum.last_post.id, new_post.id) + eq_(thread.last_post.id, new_post.id) + + # delete the new post, then check that last_post is updated + new_post.delete() + forum = Forum.objects.get(pk=1) + thread = Thread.objects.get(pk=thread.id) + eq_(forum.last_post.id, last_post.id) + eq_(thread.last_post.id, last_post.id) + + def test_delete_last_and_only_post_in_thread(self): + """Deleting the only post in a thread should delete the thread""" + forum = Forum.objects.get(pk=1) + thread = Thread(title="test", forum=forum, creator_id=118533) + thread.save() + post = Post(thread=thread, content="test", author=thread.creator) + post.save() + eq_(1, thread.post_set.count()) + post.delete() + eq_(0, Thread.objects.filter(pk=thread.id).count()) diff --git a/apps/forums/tests/test_templates.py b/apps/forums/tests/test_templates.py index c73e0abbe..0a5de6db2 100644 --- a/apps/forums/tests/test_templates.py +++ b/apps/forums/tests/test_templates.py @@ -66,7 +66,7 @@ class ForumsTemplateTestCase(ForumTestCase): doc = pq(response.content) last_post_link = doc('ol.forums div.last-post a:not(.username)')[0] href = last_post_link.attrib['href'] - eq_(href.split('#')[1], 'post-24') + eq_(href.split('#')[1], 'post-25') def test_edit_thread_403(self): """Editing a thread without permissions returns 403.""" diff --git a/apps/forums/views.py b/apps/forums/views.py index f45605276..0ee526b2e 100644 --- a/apps/forums/views.py +++ b/apps/forums/views.py @@ -1,3 +1,5 @@ +import logging + from django.contrib.auth.decorators import login_required from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 @@ -8,10 +10,12 @@ from authority.decorators import permission_required_or_403 from sumo.urlresolvers import reverse from sumo.utils import paginate -from .models import Forum, Thread +from .models import Forum, Thread, Post from .forms import ReplyForm, NewThreadForm import forums as constants +log = logging.getLogger('k.forums') + def forums(request): """ @@ -145,6 +149,7 @@ def new_thread(request, forum_slug): {'form': form, 'forum': forum}) + @require_POST @login_required @permission_required_or_403('forums_forum.thread_locked_forum', @@ -169,7 +174,7 @@ def lock_thread(request, forum_slug, thread_id): def sticky_thread(request, forum_slug, thread_id): """Mark/unmark a thread sticky.""" - thread = Thread.objects.get(pk=thread_id) + thread = get_object_or_404(Thread, pk=thread_id) thread.is_sticky = not thread.is_sticky thread.save() @@ -211,4 +216,26 @@ def edit_post(request, forum_slug, thread_id, post_id): def delete_post(request, forum_slug, thread_id, post_id): """Delete a post.""" - return jingo.render(request, 'bad_reply.html') + forum = get_object_or_404(Forum, slug=forum_slug) + thread = get_object_or_404(Thread, pk=thread_id) + post = get_object_or_404(Post, pk=post_id) + + if request.method == 'GET': + # Render the confirmation page + return jingo.render(request, 'confirm_post_delete.html', + {'forum': forum, 'thread': thread, + 'post': post}) + + # Handle confirm delete form POST + log.info("User %s is deleting post with id=%s" % (request.user, post.id)) + post.delete() + try: + Thread.objects.get(pk=thread_id) + goto = reverse('forums.posts', + kwargs={'forum_slug': forum_slug, + 'thread_id': thread_id}) + except Thread.DoesNotExist: + # The thread was deleted, go to the threads list page + goto = reverse('forums.threads', kwargs={'forum_slug': forum_slug}) + + return HttpResponseRedirect(goto) diff --git a/media/css/forums.css b/media/css/forums.css index 4af62dd85..51ce31ba0 100644 --- a/media/css/forums.css +++ b/media/css/forums.css @@ -161,7 +161,8 @@ ol.posts li div.post-actions { margin: 1em 0; } -ol.posts li div.post-actions a { +ol.posts li div.post-actions a, +ol.posts li div.post-actions form { display: inline; } @@ -287,3 +288,18 @@ form.new-thread div.form-widget label { form.new-thread div.form-widget div.forum-editor-tools { margin: 0 0 0 10em; } + +/* Delete Post Confirmation */ +div.post-to-delete label { + display:block; + font-weight:bold; + margin: 0.5em 0 0 0; +} + +div.post-to-delete input { + margin: 0 0 0 1em; +} + +div.post-to-delete form { + margin: 2em 0 0 0; +}