1 from django import forms
2 from django.contrib.auth.decorators import login_required
3 from django.shortcuts import render_to_response
4 from django.shortcuts import get_object_or_404
5 from django.template import RequestContext
6 from django.utils.translation import ugettext as _
7 from django.contrib.auth.models import User
8 from django.contrib.contenttypes.models import ContentType
9 from django.core.urlresolvers import reverse
10 from django.http import HttpResponseRedirect, HttpResponseForbidden
11 from django.views.generic.list_detail import object_detail, object_list
12 from threadedcomments.models import ThreadedComment
13 from threadedcomments.forms import ThreadedCommentForm
14 from threadedcomments.views import comment
15 from xerxes.influences.models import Character
16 from xerxes.influences.models import Influence
17 from xerxes.tools.forms import ContextModelForm
20 # A few comment form classes, to handle the various cases (staff/no staff,
21 # reply to public/private post)
23 # It is probably possible to reduce this mess a bit using metaclasses, but I
24 # didn't get this to work yet.
26 class InfluenceCommentForm(ThreadedCommentForm):
27 def __init__(self, *args, **kwargs):
28 super(InfluenceCommentForm, self).__init__(*args, **kwargs)
30 class Meta(ThreadedCommentForm.Meta):
31 exclude = ('markup', )
33 class AdminInfluenceCommentForm(ThreadedCommentForm):
34 def __init__(self, *args, **kwargs):
35 super(AdminInfluenceCommentForm, self).__init__(*args, **kwargs)
37 class Meta(ThreadedCommentForm.Meta):
38 fields = ThreadedCommentForm.Meta.fields + ('is_public',)
40 class AdminPrivateInfluenceCommentForm(ThreadedCommentForm):
41 def __init__(self, *args, **kwargs):
42 super(AdminPrivateInfluenceCommentForm, self).__init__(*args, **kwargs)
43 self.instance.is_public = False
45 def get_influence_comment_form(is_staff, reply_to):
46 """ Gets the form class that a user can use to reply to the given comment.
47 reply_to can be None, in which case the form class for a new comment is
49 allow_markup = allow_private = is_staff
51 allow_public = reply_to.is_public
54 return _get_influence_comment_form(allow_markup, allow_public, allow_private)
56 def _get_influence_comment_form(allow_markup, allow_public, allow_private):
57 """ Internal wrapper that selects the right form class depending on the
58 given options. Should not be called directly, call
59 get_influence_comment_form instead. """
60 if allow_markup and allow_public and allow_private:
61 return AdminInfluenceCommentForm
62 elif allow_markup and not allow_public and allow_private:
63 return AdminPrivateInfluenceCommentForm
64 elif not allow_markup and allow_public and not allow_private:
65 return InfluenceCommentForm
67 raise Exception("Unsupported configuration")
69 class InfluenceForm(ContextModelForm):
72 fields = ('character', 'contact', 'summary', 'description')
74 class CharacterForm(ContextModelForm):
80 def add_influence(request, character_id=None):
82 # Get the current user's characters
83 chars = request.user.character_set.all()
85 # If a character_id was specified in the url, or there is only one
86 # character, preselect it.
88 initial['character'] = character_id
89 elif (chars.count() == 1):
90 initial['character'] = chars[0].id
93 f = InfluenceForm(request=request, initial=initial)
95 # Only allow characters of the current user. Putting this here also
96 # ensures that a form will not validate when any other choice was
97 # selected (perhaps through URL crafting).
98 f.fields['character']._set_queryset(chars)
101 # The form was submitted, let's save it.
103 # Redirect to the just saved influence
104 return HttpResponseRedirect(reverse('influences_influence_detail', args=[influence.id]))
106 return render_to_response('influences/add_influence.html', {'form' : f}, RequestContext(request))
109 def add_character(request):
110 f = CharacterForm(request=request)
112 character = f.save(commit=False)
113 character.player = request.user
115 return HttpResponseRedirect(reverse('influences_character_detail', args=[character.id]))
117 return render_to_response('influences/add_character.html', {'form' : f}, RequestContext(request))
121 # Only show this player's characters and influences
122 characters = request.user.character_set.all()
123 influences = Influence.objects.filter(character__player=request.user)
124 return render_to_response('influences/index.html', {'characters' : characters, 'influences' : influences}, RequestContext(request))
127 # The views below are very similar to django's generic views (in fact,
128 # they used to be generic views before). However, since they all depend
129 # on the currently logged in user (for limiting the show list or
130 # performing access control), we won't actually use the generic views
134 def character_list(request):
135 # Only show this player's characters
136 os = request.user.character_set.all()
137 return render_to_response('influences/character_list.html', {'object_list' : os}, RequestContext(request))
140 def character_detail(request, object_id):
141 o = Character.objects.get(pk=object_id)
142 # Don't show other player's characters
143 if (o.player != request.user):
144 return HttpResponseForbidden("Forbidden -- Trying to view somebody else's character")
145 return render_to_response('influences/character_detail.html', {'object' : o}, RequestContext(request))
148 def influence_list(request):
149 # Only show this player's influences
150 os = Influence.objects.filter(character__player=request.user)
151 return render_to_response('influences/influence_list.html', {'object_list' : os}, RequestContext(request))
154 def influence_detail(request, object_id):
156 def quote_reply(comment):
157 return "\n".join(["> " + l for l in comment.comment.split("\n")])
159 o = Influence.objects.get(pk=object_id)
160 # Don't show other player's influences
161 if (o.character.player != request.user):
162 return HttpResponseForbidden("Forbidden -- Trying to view influences of somebody else's character")
164 # Show all comments to staff, but only public comments to other
166 if request.user.is_staff:
167 comments = ThreadedComment.objects.get_tree(o)
169 comments = ThreadedComment.public.get_tree(o)
171 # Annotate each comment with a proper reply form
172 for comment in comments:
173 initial = { 'comment' : quote_reply(comment) }
174 comment.reply_form = get_influence_comment_form(request.user.is_staff, comment)(initial=initial)
178 'comments' : comments,
179 'comment_form' : get_influence_comment_form(request.user.is_staff, None)
181 return render_to_response('influences/influence_detail.html', context, RequestContext(request))
184 def influence_comment(request, edit_id=None, *args, **kwargs):
185 # Add the content_type, since we don't put in in the url explicitly
186 kwargs['content_type'] = ContentType.objects.get_for_model(Influence).id
187 # Find the comment to which we're replying, so we can get the right form for it.
189 reply_to = get_object_or_404(ThreadedComment, id=edit_id)
192 # Find the right form class
193 kwargs['form_class'] = get_influence_comment_form(request.user.is_staff, reply_to)
194 return comment(request, edit_id=edit_id, *args, **kwargs)
196 # vim: set sts=4 sw=4 expandtab: