damned-lies r1214 - in trunk: . people stats teams templates/people templates/teams



Author: claudep
Date: Fri Dec 12 20:56:07 2008
New Revision: 1214
URL: http://svn.gnome.org/viewvc/damned-lies?rev=1214&view=rev

Log:
2008-12-12  Claude Paroz  <claude 2xlibre net>

	* people/forms.py: Form to enable a person to join a team as translator.
	* people/urls.py:
	* people/views.py: Replace generic view for 'person' to be able to handle
	team membership form.
	* stats/models.py: Typo in comment.
	* teams/forms.py: Form to edit membership status.
	* teams/models.py: Enrich team API with membership functions. Add new Role
	class to store membership info.
	* teams/views.py: Prepare team membership content and handle form post
	(change membership).
	* templates/people/person_detail.html: Add team membership and join form.
	* templates/teams/team_detail.html: Add team membership display and form.

Added:
   trunk/people/forms.py
   trunk/people/views.py
   trunk/teams/forms.py
Modified:
   trunk/ChangeLog
   trunk/people/urls.py
   trunk/stats/models.py
   trunk/teams/models.py
   trunk/teams/views.py
   trunk/templates/people/person_detail.html
   trunk/templates/teams/team_detail.html

Added: trunk/people/forms.py
==============================================================================
--- (empty file)
+++ trunk/people/forms.py	Fri Dec 12 20:56:07 2008
@@ -0,0 +1,7 @@
+from django import forms
+from teams.models import Team
+
+class JoinTeamForm(forms.Form):
+    def __init__(self, *args, **kwargs):
+        super(JoinTeamForm, self).__init__(*args, **kwargs)
+        self.fields['teams'] = forms.ModelChoiceField(queryset=Team.objects.all())

Modified: trunk/people/urls.py
==============================================================================
--- trunk/people/urls.py	(original)
+++ trunk/people/urls.py	Fri Dec 12 20:56:07 2008
@@ -1,7 +1,6 @@
 from django.conf.urls.defaults import *
 from people.models import Person
 
-
 info_dict_list = {
     'queryset': Person.objects.all(),
     'template_object_name': 'person',
@@ -9,15 +8,10 @@
         'pageSection': "teams"
     }
 }
-
-info_dict_detail = dict(
-    info_dict_list,
-    slug_field = 'username'
-)
     
-urlpatterns = patterns('django.views.generic.list_detail',
-    url(r'^$', 'object_list', dict(info_dict_list), 'persons'),                    
-    url(r'(?P<object_id>\d+)/$', 'object_detail', dict(info_dict_detail), 'person'),
+urlpatterns = patterns('',
+    url(r'^$', 'django.views.generic.list_detail.object_list', dict(info_dict_list), 'persons'),                    
+    url(r'(?P<object_id>\d+)/$', 'people.views.person_detail_from_id', name='person'),
     # equivalent to the previous, but using username instead of user pk
-    url(r'(?P<slug>\w+)/$', 'object_detail', dict(info_dict_detail), 'person'),
+    url(r'(?P<slug>\w+)/$', 'people.views.person_detail_from_username', name='person'),
 )

Added: trunk/people/views.py
==============================================================================
--- (empty file)
+++ trunk/people/views.py	Fri Dec 12 20:56:07 2008
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2008 Claude Paroz <claude 2xlibre net>.
+#
+# This file is part of Damned Lies.
+#
+# Damned Lies is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# Damned Lies is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Damned Lies; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+from django.shortcuts import render_to_response, get_object_or_404
+from django.template import RequestContext
+from people.models import Person
+from teams.models import Role
+from people.forms import JoinTeamForm
+
+def person_detail_from_username(request, slug):
+    person = get_object_or_404(Person, username=slug)
+    return person_detail(request, person)
+
+def person_detail_from_id(request, object_id):
+    person = get_object_or_404(Person, pk=object_id)
+    return person_detail(request, person)
+
+def person_detail(request, person):
+    if request.method == 'POST':
+        form = JoinTeamForm(request.POST)
+        if form.is_valid():
+            if request.user.username == person.username:
+                team = form.cleaned_data['teams']
+                new_role = Role(team=team, person=person) # role default to translator
+                new_role.save()
+            else:
+                messages.append("Sorry, you're not allowed to modify this user.")
+    else:
+        form = JoinTeamForm()
+    context = {
+        'pageSection': "teams",
+        'person': person,
+        'form': form
+    }
+    return render_to_response('people/person_detail.html', context, context_instance=RequestContext(request))
+

Modified: trunk/stats/models.py
==============================================================================
--- trunk/stats/models.py	(original)
+++ trunk/stats/models.py	Fri Dec 12 20:56:07 2008
@@ -475,7 +475,7 @@
     description = models.TextField(null=True, blank=True)
     dtype = models.CharField(max_length=5, choices=DOMAIN_TYPE_CHOICES, default='ui')
     directory = models.CharField(max_length=50)
-    # The pot_method is a command who chould produce a potfile in the po directory of
+    # The pot_method is a command who should produce a potfile in the po directory of
     # the domain, named <potbase()>.pot (e.g. /po/gnucash.pot). If blank, method is 
     # intltool for UI and gnome-doc-utils for DOC
     pot_method = models.CharField(max_length=50, null=True, blank=True)

Added: trunk/teams/forms.py
==============================================================================
--- (empty file)
+++ trunk/teams/forms.py	Fri Dec 12 20:56:07 2008
@@ -0,0 +1,20 @@
+from django import forms
+from teams.models import Team, ROLE_CHOICES
+
+class EditMemberRoleForm(forms.Form):
+
+    def __init__(self, roles, *args, **kwargs):
+        super(EditMemberRoleForm, self).__init__(*args, **kwargs)
+        choices = list(ROLE_CHOICES)
+        choices.append(('remove','Remove From Team'))
+        for role in roles:
+            self.fields[str(role.pk)] = forms.ChoiceField(choices=choices,
+                                                 label = role.person.name,
+                                                 initial=role.role)
+        self.fields['form_type'] = forms.CharField(widget=forms.HiddenInput,
+                                                   initial=roles[0].role)
+    
+    def get_fields(self):
+        for key, field in self.fields.items():
+            if key not in ('form_type',):
+                yield self[key]

Modified: trunk/teams/models.py
==============================================================================
--- trunk/teams/models.py	(original)
+++ trunk/teams/models.py	Fri Dec 12 20:56:07 2008
@@ -30,6 +30,7 @@
     description = models.TextField()
     # Don't confuse this relation with the 'groups' one
     coordinator = models.ForeignKey(Person, related_name='coordinates_teams')
+    members = models.ManyToManyField(Person, through='Role', related_name='teams')
     webpage_url = models.URLField(null=True, blank=True)
     mailing_list = models.EmailField(null=True, blank=True)
     mailing_list_subscribe = models.URLField(null=True, blank=True)
@@ -50,6 +51,19 @@
     
     def get_languages(self):
         return self.language_set.all()
+    
+    def get_members_by_role(self, role):
+        members = Person.objects.filter(role__team=self, role__role=role)
+        return members
+        
+    def get_commiters(self):
+        return self.get_members_by_role('commiter')
+
+    def get_reviewers(self):
+        return self.get_members_by_role('reviewer')
+
+    def get_translators(self):
+        return self.get_members_by_role('translator')
 
 class FakeTeam(object):
     """ This is a class replacing a Team object when a language
@@ -70,3 +84,22 @@
     def get_languages(self):
         return (self.language,)
 
+
+ROLE_CHOICES = (
+    ('translator', 'Translator'),
+    ('reviewer', 'Reviewer'),
+    ('commiter', 'Commiter'),
+)
+
+class Role(models.Model):
+    """ This is the intermediary class between Person and Team to attribute
+        roles to Team members. """
+    
+    team = models.ForeignKey(Team)
+    person = models.ForeignKey(Person)
+    role = models.CharField(max_length=15, choices=ROLE_CHOICES, default='translator')
+
+    class Meta:
+        db_table = 'role'
+        unique_together = ('team', 'person')
+

Modified: trunk/teams/views.py
==============================================================================
--- trunk/teams/views.py	(original)
+++ trunk/teams/views.py	Fri Dec 12 20:56:07 2008
@@ -19,10 +19,12 @@
 # along with Damned Lies; if not, write to the Free Software Foundation, Inc.,
 # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
+from django.utils.translation import ugettext_lazy as _
 from django.shortcuts import render_to_response, get_object_or_404
 from django.template import RequestContext
 from common import utils
-from teams.models import Team, FakeTeam
+from teams.models import Team, FakeTeam, Role
+from teams.forms import EditMemberRoleForm
 from languages.models import Language
 
 def teams(request):
@@ -40,10 +42,52 @@
     except:
         lang = get_object_or_404(Language, locale=team_slug)
         team = FakeTeam(lang)
-    
+    mem_groups = ( {'title': _("Commiters"),
+                'members': team.get_commiters(),
+                'form': None,
+                'no_member': _("No commiters")
+               },
+               {'title': _("Reviewers"),
+                'members': team.get_reviewers(),
+                'form': None,
+                'no_member': _("No reviewers")
+               },
+               {'title': _("Translators"),
+                'members': team.get_translators(),
+                'form': None,
+                'no_member': _("No translators")
+               },
+    )
+
+    if request.user.is_authenticated() and request.user == team.coordinator:
+        if request.method == 'POST':
+            form_type = request.POST['form_type']
+            roles = Role.objects.filter(team=team, role=form_type)
+            form = EditMemberRoleForm(roles, request.POST)
+            if form.is_valid():
+                for key, field in form.fields.items():
+                    form_value = form.cleaned_data[key]
+                    if field.initial != form_value:
+                        role = Role.objects.get(pk=key)
+                        if form_value == "remove":
+                            role.delete()
+                        else:
+                            role.role = form_value
+                            role.save()
+        # Create forms for template
+        commit_roles = Role.objects.filter(team=team, role='commiter')
+        if commit_roles:
+            mem_groups[0]['form'] = EditMemberRoleForm(commit_roles)
+        review_roles = Role.objects.filter(team=team, role='reviewer')
+        if review_roles:
+            mem_groups[1]['form'] = EditMemberRoleForm(review_roles)
+        translate_roles = Role.objects.filter(team=team, role='translator')
+        if translate_roles:
+            mem_groups[2]['form'] = EditMemberRoleForm(translate_roles)
     context = {
         'pageSection': 'teams',
-        'team': team
+        'team': team,
+        'mem_groups': mem_groups
     }
     return render_to_response('teams/team_detail.html', context, context_instance=RequestContext(request))
        

Modified: trunk/templates/people/person_detail.html
==============================================================================
--- trunk/templates/people/person_detail.html	(original)
+++ trunk/templates/people/person_detail.html	Fri Dec 12 20:56:07 2008
@@ -1,5 +1,6 @@
 {% extends "base.html" %}
 {% load i18n %}
+{% load stats_extras %}
 
 {% block title %}{% trans "GNOME Contributor" %}{% endblock %}
 
@@ -9,5 +10,28 @@
   {% with 1 as printroles %}
   {% include "person_base.html" %}
   {% endwith %}
+
+  <div class="maintainer">
+  {% if person.role_set.all %}
+    <h2>{% trans "Team membership" %}</h2>
+    <ul>
+    {% for role in person.role_set.all %}
+      {% with role.role as role_name %}
+      <li>{% blocktrans with role.team|linked_with:role.team.description|safe as team_name %}Member of {{ team_name }} team ({{ role_name }}){% endblocktrans %}
+      </li>
+      {% endwith %}
+    {% endfor %}
+    </ul>
+  {% endif %}
+    
+  {% if user.is_authenticated %}
+    {% ifequal user.username person.username %}
+      <form action="#" method="POST">
+      <p><em>{% trans "I would like to join the following team as 'translator':" %}</em><br />
+       {{ form.teams }}  <input type="submit" value="{% trans "Join" %}">
+      </form>
+    {% endifequal %}
+  {% endif %}
+  </div>
 </div>
 {% endblock %}

Modified: trunk/templates/teams/team_detail.html
==============================================================================
--- trunk/templates/teams/team_detail.html	(original)
+++ trunk/templates/teams/team_detail.html	Fri Dec 12 20:56:07 2008
@@ -55,5 +55,31 @@
 </table>
 {% endfor %}
 
+<h2>{% trans "Team membership" %}</h2>
+{% for group in mem_groups %}
+    <h3>{{ group.title }}</h3>
+    {% if group.form %}
+        <form action="#" method="POST">
+        <ul>
+        {% for field in group.form.get_fields %}
+          <li>{{ field.label }} {{ field }}</li>
+        {% endfor %}
+        </ul>
+        {{ group.form.form_type }}
+        <input type="submit" value="Apply modifications">
+        </form>
+    {% else %}
+      {% if not group.members %}
+          <p><em>{{ group.no_member }}</em></p>
+      {% else %}
+        <ul>
+        {% for member in group.members %}
+          <li><a href="{{ member.get_absolute_url }}">{{ member.name }}</a></li>
+        {% endfor %}
+        </ul>
+      {% endif %}
+    {% endif %}
+{% endfor %}
+
 </div>
 {% endblock %}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]