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'^submit/', include('ietf.submit.urls')),
|
||||||
(r'^streams/', include('ietf.ietfworkflows.urls')),
|
(r'^streams/', include('ietf.ietfworkflows.urls')),
|
||||||
(r'^community/', include('ietf.community.urls')),
|
(r'^community/', include('ietf.community.urls')),
|
||||||
|
(r'^nocom/', include('ietf.nomcom.urls')),
|
||||||
|
|
||||||
(r'^$', 'ietf.idrfc.views.main'),
|
(r'^$', 'ietf.idrfc.views.main'),
|
||||||
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
(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