From: Matthijs Kooijman Date: Fri, 16 Jan 2009 21:27:55 +0000 (+0100) Subject: Merge branch 'production' X-Git-Url: https://git.stderr.nl/gitweb?p=matthijs%2Fprojects%2Fxerxes.git;a=commitdiff_plain;h=31b568b8f923b0d146c6090527f0c41fa4b6c7b9;hp=a43581110039bf9697b88791812b7c380a707a5a Merge branch 'production' * production: Allow Influence.todo to be blank. --- diff --git a/influences/admin.py b/influences/admin.py index 8abe6cc..487b237 100644 --- a/influences/admin.py +++ b/influences/admin.py @@ -18,9 +18,9 @@ class CharacterAdmin(admin.ModelAdmin): admin.site.register(Character, CharacterAdmin) class InfluenceAdmin(admin.ModelAdmin): - list_filter=('character', 'status', 'longterm', 'todo') - search_fields=('character', 'summary', 'description', 'contact') - list_display=('character', 'contact', 'summary', 'longterm', 'status') + list_filter=('initiator', 'status', 'longterm', 'todo') + search_fields=('initiator', 'summary', 'description', 'contact') + list_display=('initiator', 'summary', 'longterm', 'status') class Media: js = ('base/js/yahoo-dom-event.js', 'base/js/logger-debug.js') diff --git a/influences/forms.py b/influences/forms.py index 7db7517..8ced120 100644 --- a/influences/forms.py +++ b/influences/forms.py @@ -67,7 +67,7 @@ def _get_influence_comment_form(allow_markup, allow_public, allow_private): class InfluenceForm(ContextModelForm): class Meta: model = Influence - fields = ('character', 'contact', 'summary', 'description') + fields = ('initiator', 'summary', 'other_characters', 'other_contacts', 'description') class CharacterForm(ContextModelForm): class Meta: diff --git a/influences/models.py b/influences/models.py index 6464e68..8f243f5 100644 --- a/influences/models.py +++ b/influences/models.py @@ -5,6 +5,7 @@ from django.utils.text import normalize_newlines from django.utils.translation import ugettext_lazy as _ from threadedcomments.models import ThreadedComment from xerxes.tools.text import rewrap +from string import strip # Create your models here. class Character(models.Model): @@ -12,11 +13,18 @@ class Character(models.Model): ('N', _('New')), ('A', _('Approved')), ) + TYPE_CHOICES = ( + ('P', _('Player')), + ('N', _('NPC')), + ('C', _('Contact')), + ) created = models.DateField(auto_now_add=1, verbose_name = _("Creation time")) modified = models.DateField(auto_now=1, verbose_name = _("Modification time")) name = models.CharField(max_length=255, verbose_name = _("Name")) status = models.CharField(max_length=2, choices=STATUS_CHOICES, default='N', verbose_name = _("Status")) player = models.ForeignKey(User, verbose_name = _("Player")) + contacts = models.ManyToManyField('self') + type = models.CharField(max_length=2, choices=TYPE_CHOICES, verbose_name=_("Type")) def __unicode__(self): return self.name @@ -38,8 +46,9 @@ class Influence(models.Model): created = models.DateField(auto_now_add=1, verbose_name = _("Creation time")) modified = models.DateField(auto_now=1, verbose_name = _("Modification time")) - character = models.ForeignKey(Character, verbose_name = _("Character")) - contact = models.CharField(max_length=255, verbose_name = _("Contact Name")) + initiator = models.ForeignKey(Character, verbose_name = _("Initiator"), related_name='initiated_influences') + other_contacts = models.CharField(max_length=255, blank = True, verbose_name = _("Other Contacts")) + other_characters = models.ManyToManyField(Character, blank = True, verbose_name = _("Involved characters"), related_name='influences_involved_in') summary = models.CharField(max_length=255, verbose_name = _("Summary")) description = models.TextField(verbose_name = _("Description")) todo = models.TextField(blank=True, verbose_name = _("Todo")) @@ -85,6 +94,31 @@ class Influence(models.Model): prefix=prefix) return comments + @property + def involved(self): + """ Returns the Characters and contacts (strings) involved """ + chars = list(self.other_characters.all()) + if (self.other_contacts): + chars.extend(map(strip,self.other_contacts.split(','))) + return chars + + @property + def related_players(self): + """ Returns all players to this Influence (ie, the players of the + initiator or involved characters). Returns a dict where the + players (User objects) are keys and a list of Character objects + for which this player is related is the value. + """ + players = {self.initiator.player : [self.initiator]} + for char in self.other_characters.all(): + # Add this character to the player's list of characters for + # this Influence, creating a new list if this is the first + # character. + chars = players.get(char.player, []) + chars.append(char) + players[char.player] = chars + return players + class Meta: verbose_name = _("Influence") verbose_name_plural = _("Influences") diff --git a/influences/views.py b/influences/views.py index 7f7b262..e741605 100644 --- a/influences/views.py +++ b/influences/views.py @@ -24,9 +24,9 @@ def add_influence(request, character_id=None): # If a character_id was specified in the url, or there is only one # character, preselect it. if (character_id): - initial['character'] = character_id + initial['initiator'] = character_id elif (chars.count() == 1): - initial['character'] = chars[0].id + initial['initiator'] = chars[0].id f = InfluenceForm(request=request, initial=initial) @@ -34,7 +34,7 @@ def add_influence(request, character_id=None): # Only allow characters of the current user. Putting this here also # ensures that a form will not validate when any other choice was # selected (perhaps through URL crafting). - f.fields['character']._set_queryset(chars) + f.fields['initiator']._set_queryset(chars) if (f.is_valid()): # The form was submitted, let's save it. @@ -59,7 +59,7 @@ def add_character(request): def index(request): # Only show this player's characters and influences characters = request.user.character_set.all() - influences = Influence.objects.filter(character__player=request.user) + influences = Influence.objects.filter(initiator__player=request.user) return render_to_response('influences/index.html', {'characters' : characters, 'influences' : influences}, RequestContext(request)) # @@ -86,7 +86,7 @@ def character_detail(request, object_id): @login_required def influence_list(request): # Only show this player's influences - os = Influence.objects.filter(character__player=request.user) + os = Influence.objects.filter(initiator__player=request.user) return render_to_response('influences/influence_list.html', {'object_list' : os}, RequestContext(request)) def influence_comment_preview(request, context_processors, extra_context, **kwargs): @@ -101,8 +101,8 @@ def influence_detail(request, object_id): o = Influence.objects.get(pk=object_id) # Don't show other player's influences - if (not request.user.is_staff and o.character.player != request.user): - return HttpResponseForbidden("Forbidden -- Trying to view influences of somebody else's character") + if (not request.user.is_staff and not request.user in o.related_players): + return HttpResponseForbidden("Forbidden -- Trying to view influences you are not involved in.") # Show all comments to staff, but only public comments to other # users diff --git a/settings.py b/settings.py index 4848651..5ed30bf 100644 --- a/settings.py +++ b/settings.py @@ -117,6 +117,8 @@ AUTH_PROFILE_MODULE = 'base.UserProfile' # Max length for comments, in characters. DEFAULT_MAX_COMMENT_LENGTH = 3000 +INTERNAL_IPS = ('127.0.0.1') + # Import local settings, that are specific to this installation. These # can override any settings specified here. try: diff --git a/templates/influences/influence_detail.html b/templates/influences/influence_detail.html index 61547ea..5c50b67 100644 --- a/templates/influences/influence_detail.html +++ b/templates/influences/influence_detail.html @@ -1,17 +1,32 @@ {% extends "base/base.html" %} {% load i18n %} +{% load list %} +{% load misc %} {% block content %}

{{ object.summary }}

- - + +{% if object.involved %} + +{% endif %} {% if object.longterm %} {% endif %}
{% trans "Contact" %}:{{ object.contact }}
{% trans "Character" %}:{{ object.character }}
{% trans "Iniator" %}:{{ object.initiator }}
{% trans "Involved" %}: +{{ object.involved|list_or_value }}
{% trans "Long term" %}:{{ object.longterm|yesno|capfirst }}

{{ object.description }}

- +{# Show all related players, except for the current user #} +{% with object.related_players|remove_item:user as players %} + {% if players %} + {% trans "Note: This influence (and its comments) can also be viewed by:" %} + + {% endif %} +{% endwith %}

{% trans "Comments" %}

{% block comments %} {% include "influences/influence_comments_block.html" %} diff --git a/tools/templatetags/list.py b/tools/templatetags/list.py new file mode 100644 index 0000000..70ce860 --- /dev/null +++ b/tools/templatetags/list.py @@ -0,0 +1,54 @@ +from django import template +from django.template.defaultfilters import unordered_list +from django.utils.safestring import mark_safe +from django.utils.encoding import force_unicode +from django.utils.translation import ugettext as _ + +""" + Template tags and filters for working with lists. +""" + +register = template.Library() + +@register.filter(name='list_or_value') +def list_or_value(list, autoescape=None): + """ + Turn a list into a simple string or unordered list. + + If the list is empty, returns an empty string. + If the list contains one element, returns just that element. + If the list contains more elements, return an ordered list with + those elements (Just like the builtin unordered_list, but with the +