Great leaps towards completing the mailing list request tool.

- Legacy-Id: 259
This commit is contained in:
Bill Fenner 2007-06-08 15:30:34 +00:00
parent a99d598cc0
commit 3cd72bc1fe
9 changed files with 225 additions and 59 deletions

View file

@ -43,17 +43,27 @@ class ListReqStep1(forms.Form):
('movenon', 'Move existing non-WG email list to selected domain above'),
('closenon', 'Close existing non-WG email list at selected domain above'),
), widget=forms.RadioSelect)
group = forms.ChoiceField(required=False)
#group = forms.ChoiceField(required=False)
group = forms.ModelChoiceField(queryset=IETFWG.objects.all().select_related().order_by('acronym.acronym'), required=False, empty_label="-- Select Working Group")
domain_name = forms.ChoiceField(choices=DOMAIN_CHOICES, required=False)
list_to_close = forms.ChoiceField(required=False)
list_to_close = forms.ModelChoiceField(queryset=ImportedMailingList.objects.all(), required=False, empty_label="-- Select List To Close")
def mail_type_fields(self):
field = self['mail_type']
return field.as_widget(field.field.widget)
def __init__(self, *args, **kwargs):
dname = kwargs.get('dname', 'ietf.org')
dname = 'ietf.org'
if args:
dn = 'domain_name'
if kwargs.has_key('prefix'):
dn = kwargs['prefix'] + '-' + dn
dname = args[0][dn]
dname = kwargs.get('dname', dname)
super(ListReqStep1, self).__init__(*args, **kwargs)
self.fields['group'].choices = [('', '-- Select Working Group')] + IETFWG.choices()
self.fields['list_to_close'].choices = [('', '-- Select List To Close')] + ImportedMailingList.choices(dname)
#self.fields['group'].choices = [('', '-- Select Working Group')] + IETFWG.choices()
#self.fields['list_to_close'].choices = [('', '-- Select List To Close')] + ImportedMailingList.choices(dname)
#XXX This doesn't work yet. Maybe switch back to choices.
self.fields['list_to_close'].queryset = ImportedMailingList.choices(dname)
print "dname %s list_to_close values: %s" % (dname, self.fields['list_to_close'].queryset)
self.fields['domain_name'].initial = dname
def clean_group(self):
group = self.clean_data['group']
@ -61,15 +71,13 @@ class ListReqStep1(forms.Form):
if action.endswith('wg'):
if not self.clean_data.get('group'):
raise forms.ValidationError, 'Please pick a working group'
group_name = Acronym.objects.get(pk=group).acronym
#group_list_exists = ImportedMailingList.objects.filter(acronym=group_name).count()
group_list_exists = ImportedMailingList.objects.filter(group_acronym=group).count()
if action.startswith('close'):
if group_list_exists == 0:
raise forms.ValidationError, 'The %s mailing list does not exist.' % group_name
raise forms.ValidationError, 'The %s mailing list does not exist.' % group
else:
if group_list_exists:
raise forms.ValidationError, 'The %s mailing list already exists.' % group_name
raise forms.ValidationError, 'The %s mailing list already exists.' % group
return self.clean_data['group']
def clean_list_to_close(self):
if self.clean_data.get('mail_type', '') == 'closenon':
@ -126,6 +134,21 @@ class PickApprover(forms.Form):
super(PickApprover, self).__init__(*args, **kwargs)
self.fields['approver'].choices = [('', '-- Pick an approver from the list below')] + [(person.person_or_org_tag, str(person)) for person in PersonOrOrgInfo.objects.filter(pk__in=approvers)]
class ListApprover(forms.Form):
"""
When instantiating, supply a list of AreaDirector, WGChair and/or Role
objects (or other objects with a person_id and appropriate str value).
"""
approver = forms.ChoiceField(choices=(
('', '-- Pick an approver from the list below'),
))
def __init__(self, approvers, requestor=None, *args, **kwargs):
super(ListApprover, self).__init__(*args, **kwargs)
self.fields['approver'].choices = [('', '-- Pick an approver from the list below')] + [(item.person_id, str(item)) for item in approvers]
if requestor:
self.fields['approver'].initial = requestor.person_id
self.fields['approver'].widget = forms.widgets.HiddenInput()
class DeletionPickApprover(PickApprover):
ds_name = forms.CharField(label = 'Enter your name', widget = forms.TextInput(attrs = {'size': 45}))
ds_email = forms.EmailField(label = 'Enter your email', widget = forms.TextInput(attrs = {'size': 45}))
@ -143,9 +166,11 @@ class ListReqAuthorized(forms.Form):
raise forms.ValidationError, 'You must assert that you are authorized to perform this action.'
return self.clean_data['authorized']
# subclass pickapprover here too?
class ListReqClose(forms.Form):
pass
requestor = forms.CharField(label = "Requestor's full name", widget = forms.TextInput(attrs = {'size': 55}))
requestor_email = forms.EmailField(label = "Requestor's email address", widget = forms.TextInput(attrs = {'size': 55}))
#mlist_name: with a widget that just displays the value as text
reason_to_delete = forms.CharField(label = 'Reason for closing list', widget = forms.Textarea(attrs = {'rows': 4, 'cols': 60}))
class AdminRequestor(forms.MultiWidget):
def decompress(self, value):
@ -169,7 +194,8 @@ class AdminRequestor(forms.MultiWidget):
# this is used.
key = name.replace('admins', 'requestor_email')
try:
return data[key] + "\n" + rest
ret = data[key] + "\r\n" + rest
return ret.strip()
except KeyError:
return rest
else:

View file

@ -10,12 +10,13 @@ class ImportedMailingList(models.Model):
name = models.CharField(blank=True, maxlength=255, db_column='list_name')
domain = models.CharField(blank=True, maxlength=25, db_column='list_domain')
def __str__(self):
return self.name or self.group_acronym
return self.acronym or self.group_acronym.acronym
def choices(dname):
objects = ImportedMailingList.objects.all().filter(domain__icontains=dname).exclude(acronym__iendswith='announce')
if dname == "ietf.org":
objects = objects.exclude(acronym__istartswith='ietf').exclude(acronym__icontains='iesg')
return [(list.acronym, list.acronym) for list in objects]
return objects
#return [(list.acronym, list.acronym) for list in objects]
choices = staticmethod(choices)
class Meta:
db_table = 'imported_mailing_list'
@ -24,7 +25,9 @@ class ImportedMailingList(models.Model):
class Domain(models.Model):
domain = models.CharField("Mailing List Domain Name", maxlength=100)
approvers = models.ManyToManyField(Role)
approvers = models.ManyToManyField(Role, filter_interface=models.HORIZONTAL)
def __str__(self):
return self.domain
class Admin:
pass
@ -34,6 +37,14 @@ class MailingList(models.Model):
(2, 'Approval'),
(3, 'Confirm+Approval'),
)
MAILTYPE_MAP = {
'newwg': 1,
'movewg': 2,
'closewg': 5,
'newnon': 4,
'movenon': 3,
'closenon': 6,
}
MAILTYPE_CHOICES = (
(1, 'Create new WG email list at ietf.org'),
(2, 'Move existing WG email list to ietf.org'),
@ -87,7 +98,7 @@ class MailingList(models.Model):
if self.mailing_list_id is None:
generate = True
while generate:
self.mailing_list_id = ''.join([random.choice('0123456789abcdefghijklmnopqrstuvwxyz') for i in range(35)])
self.mailing_list_id = ''.join([random.choice('0123456789abcdefghijklmnopqrstuvwxyz') for i in range(25)])
try:
MailingList.objects.get(pk=self.mailing_list_id)
except MailingList.DoesNotExist:
@ -110,7 +121,7 @@ class NonWgMailingList(models.Model):
list_url = models.CharField("List URL", maxlength=255)
admin = models.TextField("Administrator(s)' Email Address(es)", blank=True)
purpose = models.TextField(blank=True)
area = models.ForeignKey(Area, db_column='area_acronym_id', null=True)
area = models.ForeignKey(Area, db_column='area_acronym_id')
subscribe_url = models.CharField("Subscribe URL", blank=True, maxlength=255)
subscribe_other = models.TextField("Subscribe Other", blank=True)
# Can be 0, 1, -1, or what looks like a person_or_org_tag, positive or neg.

View file

@ -1,6 +1,6 @@
from forms import NonWgStep1, ListReqStep1, PickApprover, DeletionPickApprover, UrlMultiWidget, Preview, ListReqAuthorized, ListReqClose, MultiEmailField, AdminRequestor, ApprovalComment
from models import NonWgMailingList, MailingList
from ietf.idtracker.models import Area, PersonOrOrgInfo
from forms import NonWgStep1, ListReqStep1, PickApprover, DeletionPickApprover, UrlMultiWidget, Preview, ListReqAuthorized, ListReqClose, MultiEmailField, AdminRequestor, ApprovalComment, ListApprover
from models import NonWgMailingList, MailingList, Domain
from ietf.idtracker.models import Area, PersonOrOrgInfo, AreaDirector, WGChair
from django import newforms as forms
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
@ -145,7 +145,6 @@ list_fields = {
'add_comment': None,
'mail_type': None,
'mail_cat': None,
'domain_name': None,
'admins': MultiEmailField(label='List Administrator(s)', widget=AdminRequestor(attrs={'cols': 41, 'rows': 4})),
'initial': MultiEmailField(label='Initial list member(s)', widget=forms.Textarea(attrs={'cols': 41, 'rows': 4}), required=False),
}
@ -160,6 +159,7 @@ list_widgets = {
'post_who': forms.Select(choices=(('1', 'List members only'), ('0', 'Open'))),
'post_admin': forms.Select(choices=(('0', 'No'), ('1', 'Yes'))),
'archive_private': forms.Select(choices=(('0', 'No'), ('1', 'Yes'))),
'domain_name': forms.HiddenInput(),
}
list_attrs = {
@ -177,7 +177,18 @@ list_attrs = {
list_callback = form_decorator(fields=list_fields, widgets=list_widgets, attrs=list_attrs)
def gen_list_approval(approvers, requestor, parent):
class ListApproval(parent):
_approvers = approvers
_requestor = requestor
def __init__(self, *args, **kwargs):
super(ListApproval, self).__init__(self._approvers, self._requestor, *args, **kwargs)
return ListApproval
class ListReqWizard(wizard.Wizard):
clean_forms = []
main_step = 1
requestor_is_approver = False
def get_template(self):
templates = []
#if self.step > 0:
@ -190,6 +201,12 @@ class ListReqWizard(wizard.Wizard):
templates.append("mailinglists/list_wizard.html")
print templates
return templates
def render_template(self, *args, **kwargs):
#self.extra_context['clean_forms'] = self.clean_forms
if self.step > self.main_step:
self.extra_context['main_form'] = self.clean_forms[self.main_step]
self.extra_context['requestor_is_approver'] = self.requestor_is_approver
return super(ListReqWizard, self).render_template(*args, **kwargs)
# want to implement parse_params to get domain for list
def process_step(self, request, form, step):
form.full_clean()
@ -197,15 +214,60 @@ class ListReqWizard(wizard.Wizard):
self.clean_forms = [ form ]
else:
self.clean_forms.append(form)
form0 = self.clean_forms[0]
needs_auth = form0.clean_data['mail_type'].endswith('non') and form0.clean_data['domain_name'] != 'ietf.org'
if step == 0:
if form.clean_data['mail_type'].endswith('non') and form.clean_data['domain_name'] != 'ietf.org':
self.main_step = 1
if needs_auth:
self.form_list.append(ListReqAuthorized)
self.main_step = 2
if form.clean_data['mail_type'].startswith('close'):
self.form_list.append(ListReqClose)
if form.clean_data['mail_type'] == 'closewg':
self.initial[self.main_step] = {'mlist_name': form.clean_data['group']}
else:
self.initial[self.main_step] = {'mlist_name': form.clean_data['list_to_close']}
else:
self.form_list.append(forms.form_for_model(MailingList, formfield_callback=list_callback))
#XXX not quite
if form.clean_data['mail_type'].endswith('wg'):
self.initial[self.main_step] = {'mlist_name': form.clean_data['group']}
else:
self.initial[self.main_step] = {}
if form.clean_data['mail_type'].endswith('wg'):
self.initial[self.main_step].update({'domain_name': 'ietf.org'})
else:
self.initial[self.main_step].update({'domain_name': form.clean_data['domain_name']})
if step == self.main_step:
approvers = mlist_approvers(form0.clean_data['mail_type'], form0.clean_data['domain_name'], form0.clean_data['group'])
main_form = self.clean_forms[self.main_step]
requestor_email = main_form.clean_data['requestor_email']
requestor_person = None
for a in approvers:
if requestor_email == a.person.email()[1]:
requestor_person = a
self.requestor_is_approver = True
self.form_list.append(gen_list_approval(approvers, requestor_person, ListApprover))
super(ListReqWizard, self).process_step(request, form, step)
def done(self, request, form_list):
list = MailingList(**self.clean_forms[self.main_step].clean_data)
list.mailing_list_id = None # make sure that we create a new row
list.auth_person_id = int(self.clean_forms[self.main_step + 1].clean_data['approver'])
list.mail_type = MailingList.MAILTYPE_MAP[self.clean_forms[0].clean_data['mail_type']]
list.approved = 0
list.save()
approver_email = list.auth_person.email()
send_mail_subj(request, [ approver_email ], None, 'mailinglists/list_wizard_subject.txt', 'mailinglists/list_wizard_done_email.txt', {'list': list, 'forms': self.clean_forms, 'requestor_is_approver': self.requestor_is_approver})
return render_to_response('mailinglists/list_wizard_done.html', {'list': list, 'forms': self.clean_forms, 'requestor_is_approver': self.requestor_is_approver}, context_instance=RequestContext(request) )
def mlist_approvers(mail_type, domain_name, group):
approvers = []
if domain_name == 'ietf.org':
approvers += AreaDirector.objects.filter(area__status=Area.ACTIVE)
if mail_type.endswith('wg'):
approvers += WGChair.objects.filter(group_acronym=group)
domain = Domain.objects.get(domain=domain_name)
approvers += domain.approvers.all()
return approvers
def list_req_wizard(request):
wiz = ListReqWizard([ ListReqStep1 ])

View file

@ -1,39 +1,5 @@
{% extends "mailinglists/list_wizard_base.html" %}
{% block mlcontent %}
<table bgcolor="#88AED2" cellspacing="1" border="0" width="594">
<tr><td>
<table bgcolor="#f3f8fd" cellpadding="3" cellspacing="0" border="0" width="100%">
<tr>
<td colspan="2"><img src="/images/ietf_topleft.gif" border="0"><img src="/images/blue_title.gif" border="0"></td>
</tr>
<tr><td colspan="2">
<img src="/images/mail_title.gif" border="0">
</td></tr>
<tr><td colspan="2" valign="top">
<img src="/images/t_un.gif" border="0">
</td></tr>
</table>
<form action="." method="POST">
<h2>Step {{ step|add:"1" }}:</h2>
<table bgcolor="f3f8fd" cellpadding="3" cellspacing="0" border="0" width="100%">
{% block mlform %}
{{ form }}
</table>
<input type="hidden" name="{{ step_field }}" value="{{ step }}" />
{{ previous_fields }}
<input type="submit" value="Next">
</form>
<!--
clean_forms: {{ clean_forms|escape }}
-->
</td></tr>
</table>
{% endblock %}

View file

@ -0,0 +1,32 @@
{% extends "mailinglists/list_wizard_base.html" %}
{% block mlform %}
<tr>
<th colspan=2>Preview</th>
</tr>
<tr>
<th>{{ main_form.requestor.label }}</th>
<td>{{ main_form.requestor.field.data|escape }}</td>
</tr>
<tr>
<th>{{ main_form.requestor_email.label }}</th>
<td>{{ main_form.requestor_email.field.data|escape }}</td>
</tr>
<tr>
<th>{{ main_form.mlist_name.label }}</th>
<td>{{ main_form.mlist_name.field.data|escape }}@{{ main_form.domain_name }}</td>
</tr>
<tr>
<th>{{ main_form.requestor_email.label }}</th>
<td>{{ main_form.requestor_email.field.data|escape }}</td>
</tr>
<!-- make sure we have all the fields -->
{% for field in main_form %}
<tr>
<th>{{ field.label }}</th>
<td>{{ field.data|escape|linebreaksbr }}</td>
</tr>
{% endfor %}
<!-- must figure out whether this is an approver or a hidden field -->
{{ form }}
{% endblock %}

View file

@ -17,9 +17,43 @@ ul.errorlist { color: red; border: 1px solid red; }
<img src="/images/nwg/t_un1.gif" border="0">
<!-- form step {{ step }} -->
<br>
{% block mlcontent %}
<table bgcolor="#88AED2" cellspacing="1" border="0" width="594">
<tr><td>
<table bgcolor="#f3f8fd" cellpadding="3" cellspacing="0" border="0" width="100%">
<tr>
<td colspan="2"><img src="/images/ietf_topleft.gif" border="0"><img src="/images/blue_title.gif" border="0"></td>
</tr>
<tr><td colspan="2">
<img src="/images/mail_title.gif" border="0">
</td></tr>
<tr><td colspan="2" valign="top">
<img src="/images/t_un.gif" border="0">
</td></tr>
</table>
<form action="." method="POST">
<h2>Step {{ step|add:"1" }}:</h2>
<table bgcolor="f3f8fd" cellpadding="3" cellspacing="0" border="0" width="100%">
{% block mlform %}
form goes here
{% endblock %}
</table>
<input type="hidden" name="{{ step_field }}" value="{{ step }}" />
{{ previous_fields }}
<input type="submit" value="Next">
</form>
<!--
clean_forms: {{ clean_forms|escape }}
-->
</td></tr>
</table>
</blockquote>
{% endblock %}

View file

@ -0,0 +1,25 @@
{% extends "mailinglists/list_approval_base.html" %}
{% block innercontent %}
{% if requestor_is_approver %}
An email has been sent to you so you can confirm this request.<br>
Please note that after your request has been approved by you,<br>
{% else %}
Your request to {% filter escape %}{% include "mailinglists/list_type_message2.txt" %}{% endfilter %}
has been sent to<br>
{{ list.auth_person }} for approval.<br>
Please note that after your request has been approved by <br>
{{ list.auth_person }},
{% endif %}
{% ifequal req "delete" %}
your list will be closed within two business days.<br>
{% else %}
your list will be created and the archives <br>
will be tested.<br>
You will receive a welcome E-mail containing your administrator's<br>
password within two business days.<br>
For security reasons we suggest that you change this password.<br>
Please remember to forward this changed password to any other list<br>
admins. <br>
{% endifequal %}
{% endblock %}

View file

@ -0,0 +1,9 @@
{% filter wordwrap:"72" %}
The Secretariat has received a request from {{ list.requestor }}
to {% include "mailinglists/list_type_message2.txt" %}
Please use the following URL to review and approve or deny this request:
https://datatracker.ietf.org{% url ietf.mailinglists.views.list_approve list.mailing_list_id %}
{% endfilter %}
{# gotta set req for list_summary to work #}
{% include "mailinglists/list_summary.txt" %}

View file

@ -0,0 +1 @@
{% filter title %}Request to {% include "mailinglists/list_type_message2.txt %}{% endfilter %}