diff --git a/ietf/doc/views_draft.py b/ietf/doc/views_draft.py index b57b43d75..ef46b1632 100644 --- a/ietf/doc/views_draft.py +++ b/ietf/doc/views_draft.py @@ -29,7 +29,7 @@ from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, user_is_p from ietf.ietfauth.utils import role_required from ietf.message.models import Message from ietf.name.models import IntendedStdLevelName, DocTagName, StreamName -from ietf.person.fields import EmailsField +from ietf.person.fields import AutocompletedEmailField from ietf.person.models import Person, Email from ietf.secr.lib.template import jsonapi from ietf.utils.mail import send_mail, send_mail_message @@ -1043,7 +1043,7 @@ def edit_shepherd_writeup(request, name): context_instance=RequestContext(request)) class ShepherdForm(forms.Form): - shepherd = EmailsField(label="Shepherd", required=False, max_entries=1) + shepherd = AutocompletedEmailField(required=False) def edit_shepherd(request, name): """Change the shepherd for a Document""" @@ -1060,7 +1060,7 @@ def edit_shepherd(request, name): if form.is_valid(): save_document_in_history(doc) - doc.shepherd = form.cleaned_data['shepherd'].first() + doc.shepherd = form.cleaned_data['shepherd'] doc.save() login = request.user.person diff --git a/ietf/group/edit.py b/ietf/group/edit.py index 7944feaae..173597cc7 100644 --- a/ietf/group/edit.py +++ b/ietf/group/edit.py @@ -19,7 +19,7 @@ from ietf.group.models import ( Group, Role, GroupEvent, GroupHistory, GroupStat from ietf.group.utils import save_group_in_history, can_manage_group_type from ietf.group.utils import get_group_or_404 from ietf.ietfauth.utils import has_role -from ietf.person.fields import EmailsField +from ietf.person.fields import AutocompletedEmailsField from ietf.person.models import Person, Email from ietf.group.mails import email_iesg_secretary_re_charter @@ -29,10 +29,10 @@ class GroupForm(forms.Form): name = forms.CharField(max_length=255, label="Name", required=True) acronym = forms.CharField(max_length=10, label="Acronym", required=True) state = forms.ModelChoiceField(GroupStateName.objects.all(), label="State", required=True) - chairs = EmailsField(label="Chairs", required=False) - secretaries = EmailsField(label="Secretaries", required=False) - techadv = EmailsField(label="Technical Advisors", required=False) - delegates = EmailsField(label="Delegates", required=False, help_text=mark_safe("Chairs can delegate the authority to update the state of group documents - max %s persons at a given time" % MAX_GROUP_DELEGATES), max_entries=MAX_GROUP_DELEGATES) + chairs = AutocompletedEmailsField(label="Chairs", required=False) + secretaries = AutocompletedEmailsField(label="Secretaries", required=False) + techadv = AutocompletedEmailsField(label="Technical Advisors", required=False) + delegates = AutocompletedEmailsField(label="Delegates", required=False, help_text=mark_safe("Chairs can delegate the authority to update the state of group documents - max %s persons at a given time" % MAX_GROUP_DELEGATES), max_entries=MAX_GROUP_DELEGATES) ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'), label="Shepherding AD", empty_label="(None)", required=False) parent = forms.ModelChoiceField(Group.objects.filter(state="active").order_by('name'), empty_label="(None)", required=False) list_email = forms.CharField(max_length=64, required=False) diff --git a/ietf/group/views_stream.py b/ietf/group/views_stream.py index 53299e9e9..783c282d8 100644 --- a/ietf/group/views_stream.py +++ b/ietf/group/views_stream.py @@ -10,7 +10,7 @@ from ietf.group.models import Group, GroupEvent, Role from ietf.group.utils import save_group_in_history from ietf.ietfauth.utils import has_role from ietf.name.models import StreamName -from ietf.person.fields import EmailsField +from ietf.person.fields import AutocompletedEmailsField from ietf.person.models import Email import debug # pyflakes:ignore @@ -31,7 +31,7 @@ def stream_documents(request, acronym): return render_to_response('group/stream_documents.html', {'stream':stream, 'docs':docs, 'meta':meta }, context_instance=RequestContext(request)) class StreamEditForm(forms.Form): - delegates = EmailsField(label="Delegates", required=False) + delegates = AutocompletedEmailsField(label="Delegates", required=False) def stream_edit(request, acronym): group = get_object_or_404(Group, acronym=acronym) diff --git a/ietf/person/fields.py b/ietf/person/fields.py index e161889c6..a4c2681b5 100644 --- a/ietf/person/fields.py +++ b/ietf/person/fields.py @@ -13,7 +13,7 @@ def json_emails(emails): emails = Email.objects.filter(address__in=[x.strip() for x in emails.split(",") if x.strip()]).select_related("person") return json.dumps([{"id": e.address + "", "name": escape(u"%s <%s>" % (e.person.name, e.address))} for e in emails]) -class EmailsField(forms.CharField): +class AutocompletedEmailsField(forms.CharField): """Multi-select field using jquery.tokeninput.js. Since the API of tokeninput" is asymmetric, we have to pass it a JSON representation on the way out and parse the ids coming back as a @@ -25,7 +25,7 @@ class EmailsField(forms.CharField): self.max_entries = max_entries self.only_users = only_users - super(EmailsField, self).__init__(*args, **kwargs) + super(AutocompletedEmailsField, self).__init__(*args, **kwargs) self.widget.attrs["class"] = "tokenized-field" self.widget.attrs["data-hint-text"] = hint_text @@ -41,6 +41,8 @@ class EmailsField(forms.CharField): if isinstance(value, basestring): addresses = self.parse_tokenized_value(value) value = Email.objects.filter(address__in=addresses).select_related("person") + if isinstance(value, Email): + value = [value] self.widget.attrs["data-pre"] = json_emails(value) # doing this in the constructor is difficult because the URL @@ -52,7 +54,7 @@ class EmailsField(forms.CharField): return ",".join(e.address for e in value) def clean(self, value): - value = super(EmailsField, self).clean(value) + value = super(AutocompletedEmailsField, self).clean(value) addresses = self.parse_tokenized_value(value) emails = Email.objects.filter(address__in=addresses).exclude(person=None).select_related("person") @@ -70,3 +72,12 @@ class EmailsField(forms.CharField): return emails +class AutocompletedEmailField(AutocompletedEmailsField): + """Version of AutocompletedEmailsField specialized to a single Email.""" + + def __init__(self, *args, **kwargs): + kwargs["max_entries"] = 1 + super(AutocompletedEmailField, self).__init__(*args, **kwargs) + + def clean(self, value): + return super(AutocompletedEmailField, self).clean(value).first() diff --git a/ietf/secr/drafts/forms.py b/ietf/secr/drafts/forms.py index f8cdcfcfb..cc34554ee 100644 --- a/ietf/secr/drafts/forms.py +++ b/ietf/secr/drafts/forms.py @@ -8,7 +8,7 @@ from ietf.doc.models import Document, DocAlias, State from ietf.name.models import IntendedStdLevelName, DocRelationshipName from ietf.group.models import Group from ietf.person.models import Person, Email -from ietf.person.fields import EmailsField +from ietf.person.fields import AutocompletedEmailField from ietf.secr.groups.forms import get_person @@ -132,7 +132,7 @@ class EditModelForm(forms.ModelForm): iesg_state = forms.ModelChoiceField(queryset=State.objects.filter(type='draft-iesg'),required=False) group = GroupModelChoiceField(required=True) review_by_rfc_editor = forms.BooleanField(required=False) - shepherd = EmailsField(required=False, max_entries=1) + shepherd = AutocompletedEmailField(required=False) class Meta: model = Document @@ -190,9 +190,6 @@ class EditModelForm(forms.ModelForm): raise forms.ValidationError("ERROR: Draft does not exist") return name - def clean_shepherd(self): - return self.cleaned_data["shepherd"].first() - def clean(self): super(EditModelForm, self).clean() cleaned_data = self.cleaned_data diff --git a/ietf/secr/sreq/forms.py b/ietf/secr/sreq/forms.py index 5698a34d4..db399bb1f 100644 --- a/ietf/secr/sreq/forms.py +++ b/ietf/secr/sreq/forms.py @@ -2,7 +2,7 @@ from django import forms from ietf.group.models import Group from ietf.meeting.models import ResourceAssociation -from ietf.person.fields import EmailsField +from ietf.person.fields import AutocompletedEmailsField # ------------------------------------------------- @@ -67,7 +67,7 @@ class SessionForm(forms.Form): wg_selector3 = forms.ChoiceField(choices=WG_CHOICES,required=False) third_session = forms.BooleanField(required=False) resources = forms.MultipleChoiceField(choices=[(x.pk,x.desc) for x in ResourceAssociation.objects.all()], widget=forms.CheckboxSelectMultiple,required=False) - bethere = EmailsField(label="Must be present", required=False) + bethere = AutocompletedEmailsField(label="Must be present", required=False) def __init__(self, *args, **kwargs): super(SessionForm, self).__init__(*args, **kwargs)