Mercurial > public > sg101
changeset 107:e94398f5e027
Forums: implemented post delete feature.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Tue, 22 Sep 2009 03:36:39 +0000 |
parents | cb72577785df |
children | 80ab249d1adc |
files | gpp/forums/models.py gpp/forums/urls.py gpp/forums/views.py gpp/templates/forums/display_post.html gpp/templates/forums/topic.html media/js/forums.js |
diffstat | 6 files changed, 130 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/gpp/forums/models.py Sat Sep 19 21:49:56 2009 +0000 +++ b/gpp/forums/models.py Tue Sep 22 03:36:39 2009 +0000 @@ -108,6 +108,18 @@ else: self.last_post = None + def last_post_pre_delete(self): + """ + Call this function prior to deleting the last post in the forum. + A new last post will be found, if one exists. + This is to avoid the Django cascading delete issue. + """ + try: + self.last_post = \ + Post.objects.filter(topic__forum=self).exclude(pk=self.last_post.pk).latest() + except Post.DoesNotExist: + self.last_post = None + class Topic(models.Model): """ @@ -168,6 +180,18 @@ super(Topic, self).save(*args, **kwargs) + def last_post_pre_delete(self): + """ + Call this function prior to deleting the last post in the topic. + A new last post will be found, if one exists. + This is to avoid the Django cascading delete issue. + """ + try: + self.last_post = \ + Post.objects.filter(topic=self).exclude(pk=self.last_post.pk).latest() + except Post.DoesNotExist: + self.last_post = None + class Post(models.Model): """ @@ -183,6 +207,7 @@ class Meta: ordering = ('creation_date', ) + get_latest_by = 'creation_date' @models.permalink def get_absolute_url(self):
--- a/gpp/forums/urls.py Sat Sep 19 21:49:56 2009 +0000 +++ b/gpp/forums/urls.py Tue Sep 22 03:36:39 2009 +0000 @@ -7,6 +7,7 @@ url(r'^$', 'index', name='forums-index'), url(r'^new-topic-success/(?P<tid>\d+)$', 'new_topic_thanks', name='forums-new_topic_thanks'), url(r'^topic/(?P<id>\d+)/$', 'topic_index', name='forums-topic_index'), + url(r'^delete-post/$', 'delete_post', name='forums-delete_post'), url(r'^edit/(?P<id>\d+)/$', 'edit_post', name='forums-edit_post'), url(r'^flag-post/$', 'flag_post', name='forums-flag_post'), url(r'^forum/(?P<slug>[\w\d-]+)/$', 'forum_index', name='forums-forum_index'),
--- a/gpp/forums/views.py Sat Sep 19 21:49:56 2009 +0000 +++ b/gpp/forums/views.py Tue Sep 22 03:36:39 2009 +0000 @@ -67,7 +67,7 @@ if not forum.category.can_access(request.user): return HttpResponseForbidden() - topics = forum.topics.select_related('last_post', 'last_post__user') + topics = forum.topics.select_related('user', 'last_post', 'last_post__user') paginator = create_topic_paginator(topics) page_num = int(request.GET.get('page', 1)) try: @@ -267,3 +267,79 @@ 'can_moderate': True, }, context_instance=RequestContext(request)) + + +@require_POST +def delete_post(request): + """ + This view function allows superusers and forum moderators to delete posts. + This function is the target of AJAX calls from the client. + """ + if not request.user.is_authenticated(): + return HttpResponseForbidden('Please login to delete a post.') + + id = request.POST.get('id') + if id is None: + return HttpResponseBadRequest('No post id') + + post = get_object_or_404(Post.objects.select_related(), pk=id) + + can_delete = request.user.is_superuser or \ + request.user in post.topic.forum.moderators.all() + + if not can_delete: + return HttpResponseForbidden("You don't have permission to delete that post.") + + if post.topic.post_count == 1 and post == post.topic.last_post: + _delete_topic(post.topic) + else: + _delete_post(post) + + return HttpResponse("The post has been deleted.") + + +def _delete_post(post): + """ + Internal function to delete a single post object. + Decrements the post author's post count. + Adjusts the parent topic and forum's last_post as needed. + """ + # Adjust post creator's post count + profile = post.user.get_profile() + if profile.forum_post_count > 0: + profile.forum_post_count -= 1 + profile.save() + + # If this post is the last_post in a topic, we need to update + # both the topic and parent forum's last post fields. If we don't + # the cascading delete will delete them also! + + topic = post.topic + if topic.last_post == post: + topic.last_post_pre_delete() + topic.save() + + forum = topic.forum + if forum.last_post == post: + forum.last_post_pre_delete() + forum.save() + + # Should be safe to delete the post now: + post.delete() + + +def _delete_topic(topic): + """ + Internal function to delete an entire topic. + Deletes the topic and all posts contained within. + Adjusts the parent forum's last_post as needed. + Note that we don't bother adjusting all the users' + post counts as that doesn't seem to be worth the effort. + """ + if topic.forum.last_post.topic == topic: + topic.forum.last_post_pre_delete() + topic.forum.save() + + # It should be safe to just delete the topic now. This will + # automatically delete all posts in the topic. + topic.delete()
--- a/gpp/templates/forums/display_post.html Sat Sep 19 21:49:56 2009 +0000 +++ b/gpp/templates/forums/display_post.html Tue Sep 22 03:36:39 2009 +0000 @@ -1,6 +1,6 @@ {% load avatar_tags %} {% load forum_tags %} -<tr class="forum-post {% cycle 'odd' 'even' %}"> +<tr class="forum-post {% cycle 'odd' 'even' %}" id="post-{{ post.id }}"> <td class="forum-post-author"> <a name="p{{ post.id }}"></a> <a href="{% url bio-view_profile username=post.user.username %}" title="View Profile for {{ post.user.username }}">{{ post.user.username }}</a><br /> @@ -28,7 +28,8 @@ title="Flag this post as spam, abuse, or a violation of site rules."> <img src="{{ MEDIA_URL }}icons/flag_red.png" alt="Flag" /></a> {% if can_moderate %} - <a href=""><img src="{{ MEDIA_URL }}icons/cross.png" alt="Delete post" title="Delete post" /></a> + <a href="#" class="post-delete" id="dp-{{ post.id }}" + title="Delete this post"><img src="{{ MEDIA_URL }}icons/cross.png" alt="Delete post" /></a> {% endif %} </div> </td>
--- a/gpp/templates/forums/topic.html Sat Sep 19 21:49:56 2009 +0000 +++ b/gpp/templates/forums/topic.html Tue Sep 22 03:36:39 2009 +0000 @@ -1,6 +1,6 @@ {% extends 'base.html' %} {% block title %}Forums: {{ topic.name }}{% endblock %} -{% block custom_js %}{% if last_page %}{{ form.media }}{% endif %}{% endblock %} +{% block custom_js %}{{ form.media }}{% endblock %} {% block content %} <h2>Forums: {{ topic.name }}</h2>
--- a/media/js/forums.js Sat Sep 19 21:49:56 2009 +0000 +++ b/media/js/forums.js Tue Sep 22 03:36:39 2009 +0000 @@ -33,7 +33,7 @@ }); $('a.post-flag').click(function () { var id = this.id; - if (id.match(/fp-(\d)/)) { + if (id.match(/fp-(\d+)/)) { id = RegExp.$1; if (confirm('Only flag a post if you feel it is spam, abuse, violates site rules, ' + 'or is not appropriate. ' + @@ -55,5 +55,27 @@ } return false; }); + $('a.post-delete').click(function () { + var id = this.id; + if (id.match(/dp-(\d+)/)) { + id = RegExp.$1; + if (confirm('Are you sure you want to delete this post?')) { + $.ajax({ + url: '/forums/delete-post/', + type: 'POST', + data: {id: id}, + dataType: 'text', + success: function (response, textStatus) { + alert(response); + $('#post-' + id).fadeOut(3000); + }, + error: function (xhr, textStatus, ex) { + alert('Oops, an error occurred: ' + xhr.statusText + ' - ' + xhr.responseText); + } + }); + } + } + return false; + }); $('#id_body').markItUp(mySettings); });