From 435a62554852c2863d2247c04df4342e002576fc Mon Sep 17 00:00:00 2001
From: Matthijs Kooijman
Date: Wed, 29 Oct 2008 11:31:19 +0100
Subject: [PATCH] Improve influence comment handling.
This adds a number of form classes for commenting, which allow to choose
between public or private comments and can prevent the choice of markup.
Using a wrapper function, the right class can be selected depending on
the logged in user and the comment to reply to.
Each comment to display is annotated with the reply form to reply to it,
so we no longer need changes in threaded_comments to support quoted
replies.
Additionally, a new view is added that handles the selection of the
right form class when saving a comment.
---
influences/views.py | 77 ++++++++++++++++++-
.../influences/influence_detail_block.html | 6 +-
urls.py | 2 +
3 files changed, 80 insertions(+), 5 deletions(-)
diff --git a/influences/views.py b/influences/views.py
index 2dbd5c9..ca1a1e1 100644
--- a/influences/views.py
+++ b/influences/views.py
@@ -1,19 +1,70 @@
+from django import forms
from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.utils.translation import ugettext as _
from django.contrib.auth.models import User
+from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.views.generic.list_detail import object_detail, object_list
from threadedcomments.models import ThreadedComment
from threadedcomments.forms import ThreadedCommentForm
+from threadedcomments.views import comment
from xerxes.influences.models import Character
from xerxes.influences.models import Influence
from xerxes.tools.forms import ContextModelForm
-
+#
+# A few comment form classes, to handle the various cases (staff/no staff,
+# reply to public/private post)
+#
+# It is probably possible to reduce this mess a bit using metaclasses, but I
+# didn't get this to work yet.
+#
+class InfluenceCommentForm(ThreadedCommentForm):
+ def __init__(self, *args, **kwargs):
+ super(InfluenceCommentForm, self).__init__(*args, **kwargs)
+
+ class Meta(ThreadedCommentForm.Meta):
+ exclude = ('markup', )
+
+class AdminInfluenceCommentForm(ThreadedCommentForm):
+ def __init__(self, *args, **kwargs):
+ super(AdminInfluenceCommentForm, self).__init__(*args, **kwargs)
+
+ class Meta(ThreadedCommentForm.Meta):
+ fields = ThreadedCommentForm.Meta.fields + ('is_public',)
+
+class AdminPrivateInfluenceCommentForm(ThreadedCommentForm):
+ def __init__(self, *args, **kwargs):
+ super(AdminPrivateInfluenceCommentForm, self).__init__(*args, **kwargs)
+ self.instance.is_public = False
+
+def get_influence_comment_form(is_staff, reply_to):
+ """ Gets the form class that a user can use to reply to the given comment.
+ reply_to can be None, in which case the form class for a new comment is
+ returned. """
+ allow_markup = allow_private = is_staff
+ if reply_to:
+ allow_public = reply_to.is_public
+ else:
+ allow_public = True
+ return _get_influence_comment_form(allow_markup, allow_public, allow_private)
+
+def _get_influence_comment_form(allow_markup, allow_public, allow_private):
+ """ Internal wrapper that selects the right form class depending on the
+ given options. Should not be called directly, call
+ get_influence_comment_form instead. """
+ if allow_markup and allow_public and allow_private:
+ return AdminInfluenceCommentForm
+ elif allow_markup and not allow_public and allow_private:
+ return AdminPrivateInfluenceCommentForm
+ elif not allow_markup and allow_public and not allow_private:
+ return InfluenceCommentForm
+ else:
+ raise Exception("Unsupported configuration")
class InfluenceForm(ContextModelForm):
class Meta:
@@ -101,6 +152,10 @@ def influence_list(request):
@login_required
def influence_detail(request, object_id):
+
+ def quote_reply(comment):
+ return "\n".join(["> " + l for l in comment.comment.split("\n")])
+
o = Influence.objects.get(pk=object_id)
# Don't show other player's influences
if (o.character.player != request.user):
@@ -112,12 +167,30 @@ def influence_detail(request, object_id):
comments = ThreadedComment.objects.get_tree(o)
else:
comments = ThreadedComment.public.get_tree(o)
+
+ # Annotate each comment with a proper reply form
+ for comment in comments:
+ initial = { 'comment' : quote_reply(comment) }
+ comment.reply_form = get_influence_comment_form(request.user.is_staff, comment)(initial=initial)
context = {
'object' : o,
'comments' : comments,
- 'comment_form' : ThreadedCommentForm(),
+ 'comment_form' : get_influence_comment_form(request.user.is_staff, None)
}
return render_to_response('influences/influence_detail.html', context, RequestContext(request))
+@login_required
+def influence_comment(request, edit_id=None, *args, **kwargs):
+ # Add the content_type, since we don't put in in the url explicitly
+ kwargs['content_type'] = ContentType.objects.get_for_model(Influence).id
+ # Find the comment to which we're replying, so we can get the right form for it.
+ if edit_id:
+ reply_to = get_object_or_404(ThreadedComment, id=edit_id)
+ else:
+ reply_to = None
+ # Find the right form class
+ kwargs['form_class'] = get_influence_comment_form(request.user.is_staff, reply_to)
+ return comment(request, edit_id=edit_id, *args, **kwargs)
+
# vim: set sts=4 sw=4 expandtab:
diff --git a/templates/influences/influence_detail_block.html b/templates/influences/influence_detail_block.html
index ea6603d..d60ac14 100644
--- a/templates/influences/influence_detail_block.html
+++ b/templates/influences/influence_detail_block.html
@@ -33,10 +33,10 @@
{% trans "Add comment" %}
-