diff --git a/ietf/templates/wgchairs/manage_delegates.html b/ietf/templates/wgchairs/manage_delegates.html
new file mode 100644
index 000000000..8afd102f0
--- /dev/null
+++ b/ietf/templates/wgchairs/manage_delegates.html
@@ -0,0 +1,55 @@
+{% extends "wginfo/wg_base.html" %}
+
+{% block morecss %}
+{{ block.super }}
+.wg-chair-management ul {
+ list-style: none;
+}
+
+.wg-chair-management input {
+ border: 1px solid green;
+}
+{% endblock %}
+
+{% block wg_titledetail %}Delegates{% endblock %}
+
+{% block wg_content %}
+
+
Add new delegate
+{% if add_form.message %}
+
+ {{ add_form.message.value }}
+
+{% endif %}
+{% if can_add %}
+
+{% else %}
+
+You can only assign three delegates. Please remove delegates to add a new one.
+
+{% endif %}
+
+
Delegates
+{% if delegates %}
+
+{% else %}
+
+No delegates
+
+{% endif %}
+
+{% endblock %}
diff --git a/ietf/templates/wgchairs/notexistdelegate.html b/ietf/templates/wgchairs/notexistdelegate.html
new file mode 100644
index 000000000..3a7fa6482
--- /dev/null
+++ b/ietf/templates/wgchairs/notexistdelegate.html
@@ -0,0 +1,12 @@
+
+The delegate you are trying to designate does not have a personal user-id and password to log-on to the Datatracker.
+
+
+An email will be sent to the following address to inform that the person designated sould contact with the Secretariat
+to obtain their own user-id and password to the Datatracker.
+
+
{% ifequal selected "documents" %}
Documents{% else %}
Documents{% endifequal %} |
{% ifequal selected "charter" %}
Charter{% else %}
Charter{% endifequal %} |
+{% wgchairs_admin_options wg %}
{% if wg.clean_email_archive|startswith:"http:" or wg.clean_email_archive|startswith:"ftp:" %}
List Archive » |
{% endif %}
diff --git a/ietf/wgchairs/accounts.py b/ietf/wgchairs/accounts.py
index 4c519a288..95f45d147 100644
--- a/ietf/wgchairs/accounts.py
+++ b/ietf/wgchairs/accounts.py
@@ -22,7 +22,7 @@ def can_do_wg_workflow_in_document(user, document):
person = get_person_for_user(user)
if not person or not document.group:
return False
- return can_do_wg_wgorkflow_in_group(document.group)
+ return can_do_wg_workflow_in_group(document.group)
def can_manage_workflow_in_group(user, group):
diff --git a/ietf/wgchairs/forms.py b/ietf/wgchairs/forms.py
new file mode 100644
index 000000000..39903e73b
--- /dev/null
+++ b/ietf/wgchairs/forms.py
@@ -0,0 +1,179 @@
+from django import forms
+from django.conf import settings
+from django.core.mail import EmailMessage
+from django.template.loader import render_to_string
+
+from ietf.wgchairs.models import WGDelegate
+from ietf.wgchairs.accounts import get_person_for_user
+from ietf.idtracker.models import PersonOrOrgInfo
+
+
+class RelatedWGForm(forms.Form):
+
+ can_cancel = False
+
+ def __init__(self, *args, **kwargs):
+ self.wg = kwargs.pop('wg', None)
+ self.user = kwargs.pop('user', None)
+ self.message = {}
+ super(RelatedWGForm, self).__init__(*args, **kwargs)
+
+ def get_message(self):
+ return self.message
+
+ def set_message(self, msg_type, msg_value):
+ self.message = {'type': msg_type,
+ 'value': msg_value,
+ }
+
+
+class RemoveDelegateForm(RelatedWGForm):
+
+ delete = forms.MultipleChoiceField()
+
+ def __init__(self, *args, **kwargs):
+ super(RemoveDelegateForm, self).__init__(*args, **kwargs)
+ self.fields['delete'].choices = [(i.pk, i.pk) for i in self.wg.wgdelegate_set.all()]
+
+ def save(self):
+ delegates = self.cleaned_data.get('delete')
+ WGDelegate.objects.filter(pk__in=delegates).delete()
+ self.set_message('success', 'Delegates removed')
+
+
+class AddDelegateForm(RelatedWGForm):
+
+ email = forms.EmailField()
+ form_type = forms.CharField(widget=forms.HiddenInput, initial='single')
+
+ def __init__(self, *args, **kwargs):
+ super(AddDelegateForm, self).__init__(*args, **kwargs)
+ self.next_form = self
+
+ def get_next_form(self):
+ return self.next_form
+
+ def get_person(self, email):
+ persons = PersonOrOrgInfo.objects.filter(emailaddress__address=email, iesglogin__isnull=False).distinct()
+ if not persons:
+ raise PersonOrOrgInfo.DoesNotExist
+ if len(persons) > 1:
+ raise PersonOrOrgInfo.MultipleObjectsReturned
+ return persons[0]
+
+ def save(self):
+ email = self.cleaned_data.get('email')
+ try:
+ person = self.get_person(email)
+ except PersonOrOrgInfo.DoesNotExist:
+ self.next_form = NotExistDelegateForm(wg=self.wg, user=self.user, email=email)
+ self.next_form.set_message('doesnotexist', 'There is no user with this email allowed to login to the system')
+ return
+ except PersonOrOrgInfo.MultipleObjectsReturned:
+ self.next_form = MultipleDelegateForm(wg=self.wg, user=self.user, email=email)
+ self.next_form.set_message('multiple', 'There are multiple users with this email in the system')
+ return
+ self.create_delegate(person)
+
+ def create_delegate(self, person):
+ (delegate, created) = WGDelegate.objects.get_or_create(wg=self.wg,
+ person=person)
+ if not created:
+ self.set_message('error', 'The email belongs to a person who is already a delegate')
+ else:
+ self.next_form = AddDelegateForm(wg=self.wg, user=self.user)
+ self.next_form.set_message('success', 'A new delegate has been added')
+
+
+class MultipleDelegateForm(AddDelegateForm):
+
+ email = forms.EmailField(widget=forms.HiddenInput)
+ form_type = forms.CharField(widget=forms.HiddenInput, initial='multiple')
+ persons = forms.ChoiceField(widget=forms.RadioSelect, help_text='Please select one person from the list')
+ submit_msg = 'Designate as delegate'
+
+ def __init__(self, *args, **kwargs):
+ self.email = kwargs.pop('email', None)
+ super(MultipleDelegateForm, self).__init__(*args, **kwargs)
+ if not self.email:
+ self.email = self.data.get('email', None)
+ self.fields['email'].initial = self.email
+ self.fields['persons'].choices = [(i.pk, unicode(i)) for i in PersonOrOrgInfo.objects.filter(emailaddress__address=self.email, iesglogin__isnull=False).distinct().order_by('first_name')]
+
+ def save(self):
+ person_id = self.cleaned_data.get('persons')
+ person = PersonOrOrgInfo.objects.get(pk=person_id)
+ self.create_delegate(person)
+
+
+class NotExistDelegateForm(MultipleDelegateForm):
+
+ email = forms.EmailField(widget=forms.HiddenInput)
+ form_type = forms.CharField(widget=forms.HiddenInput, initial='notexist')
+ can_cancel = True
+ submit_msg = 'Send email to these addresses'
+
+ def __init__(self, *args, **kwargs):
+ super(NotExistDelegateForm, self).__init__(*args, **kwargs)
+ self.email_list = []
+
+ def get_email_list(self):
+ if self.email_list:
+ return self.email_list
+ email_list = [self.email]
+ email_list.append('IETF Secretariat
')
+ email_list += ['%s <%s>' % i.person.email() for i in self.wg.wgchair_set.all() if i.person.email()]
+ self.email_list = email_list
+ return email_list
+
+ def as_p(self):
+ email_list = self.get_email_list()
+ return render_to_string('wgchairs/notexistdelegate.html', {'email_list': email_list})
+
+ def send_email(self, email, template):
+ subject = 'WG Delegate needs system credentials'
+ persons = PersonOrOrgInfo.objects.filter(emailaddress__address=self.email).distinct()
+ body = render_to_string(template,
+ {'chair': get_person_for_user(self.user),
+ 'delegate_email': self.email,
+ 'delegate_persons': persons,
+ })
+ mail = EmailMessage(subject=subject,
+ body=body,
+ to=email,
+ from_email=settings.DEFAULT_FROM_EMAIL)
+ return mail
+
+ def send_email_to_delegate(self, email):
+ self.send_email(email, 'wgchairs/notexistsdelegate_delegate_email.txt')
+
+ def send_email_to_secretariat(self, email):
+ self.send_email(email, 'wgchairs/notexistsdelegate_secretariat_email.txt')
+
+ def send_email_to_wgchairs(self, email):
+ self.send_email(email, 'wgchairs/notexistsdelegate_wgchairs_email.txt')
+
+ def save(self):
+ self.next_form = AddDelegateForm(wg=self.wg, user=self.user)
+ if settings.DEBUG:
+ self.next_form.set_message('warning', 'Email was not sent cause tool is in DEBUG mode')
+ else:
+ email_list = self.get_email_list()
+ self.send_email_to_delegate([email_list[0]])
+ self.send_email_to_secretariat([email_list[1]])
+ self.send_email_to_wgchairs(email_list[2:])
+ self.next_form.set_message('success', 'Email sent successfully')
+
+
+def add_form_factory(request, wg, user):
+ if request.method != 'POST':
+ return AddDelegateForm(wg=wg, user=user)
+
+ if request.POST.get('form_type', None) == 'multiple':
+ return MultipleDelegateForm(wg=wg, user=user, data=request.POST.copy())
+ elif request.POST.get('form_type', None) == 'notexist':
+ return NotExistDelegateForm(wg=wg, user=user, data=request.POST.copy())
+ elif request.POST.get('form_type', None) == 'single':
+ return AddDelegateForm(wg=wg, user=user, data=request.POST.copy())
+
+ return AddDelegateForm(wg=wg, user=user)
diff --git a/ietf/wgchairs/templatetags/__init__.py b/ietf/wgchairs/templatetags/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/ietf/wgchairs/templatetags/wgchairs_tags.py b/ietf/wgchairs/templatetags/wgchairs_tags.py
new file mode 100644
index 000000000..abe633974
--- /dev/null
+++ b/ietf/wgchairs/templatetags/wgchairs_tags.py
@@ -0,0 +1,19 @@
+from django import template
+
+from ietf.wgchairs.accounts import (can_manage_workflow_in_group,
+ can_manage_delegates_in_group)
+
+
+register = template.Library()
+
+
+@register.inclusion_tag('wgchairs/wgchairs_admin_options.html', takes_context=True)
+def wgchairs_admin_options(context, wg):
+ request = context.get('request', None)
+ user = request and request.user
+ return {'user': user,
+ 'can_manage_delegates': can_manage_delegates_in_group(user, wg),
+ 'can_manage_workflow': can_manage_workflow_in_group(user, wg),
+ 'wg': wg,
+ 'selected': context.get('selected', None),
+ }
diff --git a/ietf/wgchairs/urls.py b/ietf/wgchairs/urls.py
new file mode 100644
index 000000000..916fa4ace
--- /dev/null
+++ b/ietf/wgchairs/urls.py
@@ -0,0 +1,8 @@
+# Copyright The IETF Trust 2008, All Rights Reserved
+
+from django.conf.urls.defaults import patterns, url
+
+urlpatterns = patterns('ietf.wgchairs.views',
+ url(r'^workflows/$', 'manage_workflow', name='manage_workflow'),
+ url(r'^delegates/$', 'manage_delegates', name='manage_delegates'),
+)
diff --git a/ietf/wgchairs/views.py b/ietf/wgchairs/views.py
new file mode 100644
index 000000000..7da34a3dd
--- /dev/null
+++ b/ietf/wgchairs/views.py
@@ -0,0 +1,38 @@
+from ietf.idtracker.models import IETFWG
+from django.shortcuts import get_object_or_404, render_to_response
+from django.template import RequestContext
+from django.http import HttpResponseForbidden
+
+from ietf.wgchairs.forms import RemoveDelegateForm, add_form_factory
+from ietf.wgchairs.accounts import can_manage_delegates_in_group
+
+
+def manage_delegates(request, acronym):
+ wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
+ user = request.user
+ if not can_manage_delegates_in_group(user, wg):
+ return HttpResponseForbidden('You have no permission to access this view')
+ delegates = wg.wgdelegate_set.all()
+ add_form = add_form_factory(request, wg, user)
+ if request.method == 'POST':
+ if request.POST.get('remove', None):
+ form = RemoveDelegateForm(wg=wg, data=request.POST.copy())
+ if form.is_valid():
+ form.save()
+ elif add_form.is_valid():
+ add_form.save()
+ add_form = add_form.get_next_form()
+ return render_to_response('wgchairs/manage_delegates.html',
+ {'wg': wg,
+ 'delegates': delegates,
+ 'selected': 'manage_delegates',
+ 'can_add': delegates.count() < 3,
+ 'add_form': add_form,
+ },
+ RequestContext(request))
+
+
+def manage_workflow(request, acronym):
+ wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
+ concluded = (wg.status_id != 1)
+ return render_to_response('wginfo/wg_charter.html', {'wg': wg, 'concluded': concluded, 'selected': 'manage_workflow'}, RequestContext(request))