view only accessible by the secretariat that allows to assign the email of the members and the chair of the NomCom

See #904
 - Legacy-Id: 5066
This commit is contained in:
Emilio Jiménez 2012-11-20 00:40:57 +00:00
parent 6aad0f2ef8
commit 230f6cfae7
11 changed files with 374 additions and 0 deletions

View file

@ -0,0 +1,155 @@
# encoding: utf-8
from south.v2 import DataMigration
from name.models import RoleName
class Migration(DataMigration):
def forwards(self, orm):
RoleName(slug='member', name='Member', used=True).save()
def backwards(self, orm):
pass
models = {
'name.ballotpositionname': {
'Meta': {'ordering': "['order']", 'object_name': 'BallotPositionName'},
'blocking': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.constraintname': {
'Meta': {'ordering': "['order']", 'object_name': 'ConstraintName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.docrelationshipname': {
'Meta': {'ordering': "['order']", 'object_name': 'DocRelationshipName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.docremindertypename': {
'Meta': {'ordering': "['order']", 'object_name': 'DocReminderTypeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.doctagname': {
'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.doctypename': {
'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.groupballotpositionname': {
'Meta': {'ordering': "['order']", 'object_name': 'GroupBallotPositionName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.groupstatename': {
'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.grouptypename': {
'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.intendedstdlevelname': {
'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.liaisonstatementpurposename': {
'Meta': {'ordering': "['order']", 'object_name': 'LiaisonStatementPurposeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.meetingtypename': {
'Meta': {'ordering': "['order']", 'object_name': 'MeetingTypeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.rolename': {
'Meta': {'ordering': "['order']", 'object_name': 'RoleName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.sessionstatusname': {
'Meta': {'ordering': "['order']", 'object_name': 'SessionStatusName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.stdlevelname': {
'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.streamname': {
'Meta': {'ordering': "['order']", 'object_name': 'StreamName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.timeslottypename': {
'Meta': {'ordering': "['order']", 'object_name': 'TimeSlotTypeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
}
}
complete_apps = ['name']

0
ietf/nomcom/__init__.py Normal file
View file

97
ietf/nomcom/forms.py Normal file
View file

@ -0,0 +1,97 @@
from django import forms
from django.contrib.formtools.preview import FormPreview
from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.core.urlresolvers import reverse
from ietf.ietfauth.decorators import has_role
from ietf.utils import fields as custom_fields
from ietf.group.models import Group, Role
from ietf.name.models import RoleName
from ietf.person.models import Email
class ManageGroupForm(forms.Form):
chair = forms.EmailField(label="Chair email", required=False,
widget=forms.TextInput(attrs={'size': '40'}))
members = custom_fields.MultiEmailField(label="Members email", required=False)
def __init__(self, *args, **kwargs):
super(ManageGroupForm, self).__init__(*args, **kwargs)
class ManageGroupFormPreview(FormPreview):
form_template = 'nomcom/manage_group.html'
preview_template = 'nomcom/manage_group_review.html'
def preview_get(self, request):
if not has_role(request.user, "Secretariat"):
return HttpResponseForbidden("Must be a secretariat")
return super(ManageGroupFormPreview, self).preview_get(request)
def parse_params(self, *args, **kwargs):
group_acronym = kwargs['acronym']
group = Group.objects.get(acronym=group_acronym)
chairs = group.role_set.filter(name__slug='chair')
members = group.role_set.filter(name__slug='member')
if chairs:
self.form.base_fields['chair'].initial = chairs[0].email.address
if members:
self.form.base_fields['members'].initial = ',\r\n'.join([role.email.address for role in members])
self.state['group'] = group
def process_preview(self, request, form, context):
chair_email = form.cleaned_data['chair']
members_email = form.cleaned_data['members'].replace('\r\n', '').replace(' ', '').split(',')
members_info = []
emails_not_found = []
try:
chair_email_obj = Email.objects.get(address=chair_email)
chair_person = chair_email_obj.person
except Email.DoesNotExist:
chair_person = None
chair_email_obj = None
chair_info = {'email': chair_email,
'email_obj': chair_email_obj,
'person': chair_person}
for email in members_email:
try:
email_obj = Email.objects.get(address=email)
person = email_obj.person
except Email.DoesNotExist:
person = None
if person:
members_info.append({'email': email,
'email_obj': email_obj,
'person': person})
else:
emails_not_found.append(email)
self.state.update({'chair_info': chair_info,
'members_info': members_info,
'emails_not_found': emails_not_found})
def done(self, request, cleaned_data):
group = self.state['group']
chair_info = self.state['chair_info']
members_info = self.state['members_info']
members_email = [member['email'] for member in self.state['members_info']]
members_excluded = group.role_set.filter(name__slug='member').exclude(email__address__in=members_email)
members_excluded.delete()
for member in members_info:
Role.objects.get_or_create(name=RoleName.objects.get(slug="member"),
group=group,
person=member['person'],
email=member['email_obj'])
chair_exclude = group.role_set.filter(name__slug='chair').exclude(email__address=chair_info['email'])
chair_exclude.delete()
if chair_info['email_obj'] and chair_info['person']:
Role.objects.get_or_create(name=RoleName.objects.get(slug="chair"),
group=group,
person=chair_info['person'],
email=chair_info['email_obj'])
return HttpResponseRedirect(reverse('manage_group', kwargs={'acronym': group.acronym}))

3
ietf/nomcom/models.py Normal file
View file

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

16
ietf/nomcom/tests.py Normal file
View file

@ -0,0 +1,16 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

7
ietf/nomcom/urls.py Normal file
View file

@ -0,0 +1,7 @@
from django.conf.urls.defaults import patterns, url
from ietf.nomcom.forms import ManageGroupForm, ManageGroupFormPreview
urlpatterns = patterns('ietf.nocom.views',
url(r'^group/(?P<acronym>[\w.@+-]+)/$', ManageGroupFormPreview(ManageGroupForm), name='manage_group'),
)

0
ietf/nomcom/views.py Normal file
View file

View file

@ -0,0 +1,18 @@
{% extends "base.html" %}
{% block title %}Manage group {{ state.group.acronym }}{% endblock %}
{% block content %}
<h1>Manage group {{ state.group.acronym }}</h1>
{% if form.errors %}<h3>Please correct the following errors</h3>{% endif %}
<form action="" method="post">{% csrf_token %}
<table>
{{ form }}
</table>
<input type="hidden" name="{{ stage_field }}" value="1" />
<p><input type="submit" value="Preview" /></p>
</form>
{% endblock %}

View file

@ -0,0 +1,57 @@
{% extends "base.html" %}
{% block title %}Preview group {{ state.group.acronym }} {% endblock %}
{% block content %}
<h1>Preview group {{ state.group.acronym }}</h1>
<h2>Chair info </h2>
{% if state.chair_info.person.name %}
<ul>
<li><strong>Email:</strong> {{ state.chair_info.email }}</li>
<li><strong>Person name:</strong> {{ state.chair_info.person.name }}</li>
</ul>
{% else %}
email {{ state.chair_info.email }} not found
{% endif %}
{% if state.members_info %}
<h2>Members info </h2>
<ul>
{% for member in state.members_info %}
<li><strong>Email:</strong> {{ member.email }}. <strong>Person Name</strong>: {{ member.person.name }}</li>
{% endfor %}
</ul>
{% endif %}
{% if state.emails_not_found %}
<h2>Members not found </h2>
<ul>
{% for email in state.emails_not_found %}
<li>{{ email }}</li>
{% endfor %}
</ul>
{% endif %}
<table>
<form action="" method="post">{% csrf_token %}
{% for field in form %}{{ field.as_hidden }}
{% endfor %}
<input type="hidden" name="{{ stage_field }}" value="2" />
<input type="hidden" name="{{ hash_field }}" value="{{ hash_value }}" />
<p><input type="submit" value="Submit" /></p>
</form>
<h1>Or edit it again</h1>
<form action="" method="post">{% csrf_token %}
<table>
{{ form }}
</table>
<input type="hidden" name="{{ stage_field }}" value="1" />
<p><input type="submit" value="Preview" /></p>
</form>
{% endblock %}

View file

@ -66,6 +66,7 @@ urlpatterns = patterns('',
(r'^submit/', include('ietf.submit.urls')),
(r'^streams/', include('ietf.ietfworkflows.urls')),
(r'^community/', include('ietf.community.urls')),
(r'^nocom/', include('ietf.nomcom.urls')),
(r'^$', 'ietf.idrfc.views.main'),
(r'^admin/doc/', include('django.contrib.admindocs.urls')),

20
ietf/utils/fields.py Normal file
View file

@ -0,0 +1,20 @@
from django import forms
from django.forms.util import ValidationError
from django.core.validators import email_re
class MultiEmailField(forms.CharField):
widget = forms.widgets.Textarea
def clean(self, value):
super(MultiEmailField, self).clean(value)
if value:
emails = map(unicode.strip, value.split(','))
else:
return value
for email in emails:
if not email_re.match(email):
raise ValidationError("This is not a valid comma separated email list.")
return value