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:
parent
6aad0f2ef8
commit
230f6cfae7
155
ietf/name/migrations/0004_add_rolename_member.py
Normal file
155
ietf/name/migrations/0004_add_rolename_member.py
Normal 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
0
ietf/nomcom/__init__.py
Normal file
97
ietf/nomcom/forms.py
Normal file
97
ietf/nomcom/forms.py
Normal 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
3
ietf/nomcom/models.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
16
ietf/nomcom/tests.py
Normal file
16
ietf/nomcom/tests.py
Normal 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
7
ietf/nomcom/urls.py
Normal 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
0
ietf/nomcom/views.py
Normal file
18
ietf/templates/nomcom/manage_group.html
Normal file
18
ietf/templates/nomcom/manage_group.html
Normal 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 %}
|
57
ietf/templates/nomcom/manage_group_review.html
Normal file
57
ietf/templates/nomcom/manage_group_review.html
Normal 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 %}
|
|
@ -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
20
ietf/utils/fields.py
Normal 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
|
Loading…
Reference in a new issue