Initial version of forms and views for mailing list submissions.

The nonwg_lists/submit wizard is nearly done; it needs templates
and to figure out why submit from step 2 goes back to step 1 instead
of calling done.

 The req_list wizard is just started.  It needs to get the incoming
value of domain_name as an alternat version of dname, and be able to
get dname from GET args to handle the javascript redirect.  It also
needs all the workflow ("I'm allowed to create this list",
who-is-approver, etc.) and additional forms.
 - Legacy-Id: 122
This commit is contained in:
Bill Fenner 2007-05-10 22:01:36 +00:00
parent 95209614b5
commit 2739083fbe
5 changed files with 225 additions and 14 deletions
ietf
mailinglists
templates/mailinglists

106
ietf/mailinglists/forms.py Normal file
View file

@ -0,0 +1,106 @@
from django import newforms as forms
from models import NonWgMailingList, ImportedMailingList
from ietf.idtracker.models import PersonOrOrgInfo, GroupIETF
class NonWgStep1(forms.Form):
add_edit = forms.ChoiceField(choices=(
('add', 'Add a new entry'),
('edit', 'Modify an existing entry'),
('delete', 'Delete an existing entry'),
), widget=forms.RadioSelect)
list_id = forms.ChoiceField(required=False)
list_id_delete = forms.ChoiceField(required=False)
def add_edit_fields(self):
field = self['add_edit']
return field.as_widget(field.field.widget)
def __init__(self, *args, **kwargs):
super(NonWgStep1, self).__init__(*args, **kwargs)
choices=[('', '-- Select an item from the list below')] + NonWgMailingList.choices()
self.fields['list_id'].choices = choices
self.fields['list_id_delete'].choices = choices
def clean_list_id(self):
if self.clean_data.get('add_edit', None) == 'edit':
if not self.clean_data.get('list_id'):
raise forms.ValidationError, 'Please pick a mailing list to modify'
return self.clean_data['list_id']
def clean_list_id_delete(self):
if self.clean_data.get('add_edit', None) == 'delete':
if not self.clean_data.get('list_id_delete'):
raise forms.ValidationError, 'Please pick a mailing list to delete'
return self.clean_data['list_id_delete']
class ListReqStep1(forms.Form):
DOMAIN_CHOICES = (
('ietf.org', 'ietf.org'),
('iab.org', 'iab.org'),
('irtf.org', 'irtf.org'),
)
mail_type = forms.ChoiceField(choices=(
('newwg', 'Create new WG email list at ietf.org'),
('movewg', 'Move existing WG email list to ietf.org'),
('closewg', 'Close existing WG email list at ietf.org'),
('newnon', 'Create new non-WG email list at selected domain above'),
('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)
domain_name = forms.ChoiceField(choices=DOMAIN_CHOICES, required=False)
list_to_close = forms.ChoiceField(required=False)
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')
super(ListReqStep1, self).__init__(*args, **kwargs)
self.fields['group'].choices = [('', '-- Select Working Group')] + GroupIETF.choices()
self.fields['list_to_close'].choices = [('', '-- Select List To Close')] + ImportedMailingList.choices(dname)
self.fields['domain_name'].initial = dname
def clean_group(self):
if self.clean_data.get('mail_type', '').endswith('wg'):
if not self.clean_data.get('group'):
raise forms.ValidationError, 'Please pick a working group'
return self.clean_data['group']
def clean_list_to_close(self):
if self.clean_data.get('mail_type', '') == 'closenon':
if not self.clean_data.get('list_to_close'):
raise forms.ValidationError, 'Please pick a list to close'
return self.clean_data['list_to_close']
# multiwidget for separate scheme and rest for urls
# todo: can the clean return the "smart" value?
class UrlMultiWidget(forms.MultiWidget):
def decompress(self, value):
if value:
if '//' in value:
(scheme, rest) = value.split('//', 1)
scheme += '//'
else:
scheme = 'http://'
rest = value
return [scheme, rest]
else:
return ['', '']
def __init__(self, choices=(('http://', 'http://'), ('https://', 'https://')), attrs=None):
widgets = (forms.RadioSelect(choices=choices, attrs=attrs), forms.TextInput(attrs=attrs))
super(UrlMultiWidget, self).__init__(widgets, attrs)
def format_output(self, rendered_widgets):
return u'%s\n%s\n<br/>' % ( u'<br/>\n'.join(["%s" % w for w in rendered_widgets[0]]), rendered_widgets[1] )
class PickApprover(forms.Form):
"""
When instantiating, supply a list of person tags in approvers=
"""
approver = forms.ChoiceField(choices=(
('', '-- Pick an approver from the list below'),
))
def __init__(self, approvers, *args, **kwargs):
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 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}))
msg_to_ad = forms.CharField(label = 'Message to the Area Director', widget = forms.Textarea(attrs = {'rows': 5, 'cols': 50}))

View file

@ -2,12 +2,18 @@ from django.db import models
from ietf.idtracker.models import Acronym, Areas, PersonOrOrgInfo
class ImportedMailingList(models.Model):
group_acronym = models.ForeignKey(Acronym)
list_acronym = models.CharField(blank=True, maxlength=255)
list_name = models.CharField(blank=True, maxlength=255)
list_domain = models.CharField(blank=True, maxlength=25)
group_acronym = models.ForeignKey(Acronym, null=True)
acronym = models.CharField(maxlength=255, db_column='list_acronym')
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.list_name or self.group_acronym
return self.name or self.group_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]
choices = staticmethod(choices)
class Meta:
db_table = 'imported_mailing_list'
class Admin:
@ -72,22 +78,25 @@ class MailingList(models.Model):
class NonWgMailingList(models.Model):
id = models.CharField(primary_key=True, maxlength=35)
purpose = models.TextField(blank=True)
area_acronym = models.ForeignKey(Areas)
admin = models.TextField(blank=True)
list_url = models.CharField(maxlength=255)
s_name = models.CharField(blank=True, maxlength=255)
s_email = models.CharField(blank=True, maxlength=255)
area = models.ForeignKey(Areas, db_column='area_acronym_id')
admin = models.TextField("Administrator(s)' Email Address(es)", blank=True)
list_url = models.CharField("List URL", maxlength=255)
s_name = models.CharField("Submitter's Name", blank=True, maxlength=255)
s_email = models.CharField("Submitter's Email Address", blank=True, maxlength=255)
# Can be 0, 1, -1, or what looks like a person_or_org_tag, positive or neg.
# The values less than 1 don't get displayed on the list of lists.
status = models.IntegerField()
list_name = models.CharField(blank=True, maxlength=255)
subscribe_url = models.CharField(blank=True, maxlength=255)
subscribe_other = models.TextField(blank=True)
list_name = models.CharField("Mailing List Name", unique=True, maxlength=255)
subscribe_url = models.CharField("Subscribe URL", blank=True, maxlength=255)
subscribe_other = models.TextField("Subscribe Other", blank=True)
ds_name = models.CharField(blank=True, maxlength=255)
ds_email = models.CharField(blank=True, maxlength=255)
msg_to_ad = models.TextField(blank=True)
def __str__(self):
return self.list_name
def choices():
return [(list.id, list.list_name) for list in NonWgMailingList.objects.all().filter(status__gt=0)]
choices = staticmethod(choices)
class Meta:
db_table = 'none_wg_mailing_list'
ordering = ['list_name']

View file

@ -1,8 +1,15 @@
from django.conf.urls.defaults import *
from ietf.idtracker.models import Areas
from ietf.mailinglists import views
from ietf.mailinglists.models import NonWgMailingList
from ietf.mailinglists.forms import NonWgStep1
urlpatterns = patterns('django.views.generic.list_detail',
(r'^area_lists/$', 'object_list', { 'queryset': Areas.objects.filter(status=1).select_related().order_by('acronym.acronym'), 'template_name': 'mailinglists/areas_list.html' }),
(r'^nonwg_lists/$', 'object_list', { 'queryset': NonWgMailingList.objects.filter(status__gt=0) }),
)
urlpatterns += patterns('',
(r'^nonwg_lists/submit/$', views.non_wg_wizard),
(r'^request/$', views.list_req_wizard),
(r'^nonwg_lists/s2/$', views.non_wg_submit),
)

View file

@ -1 +1,72 @@
# Create your views here.
from forms import NonWgStep1, ListReqStep1, PickApprover, DeletionPickApprover, UrlMultiWidget
from models import NonWgMailingList
from ietf.idtracker.models import Areas
from django import newforms as forms
from django.shortcuts import render_to_response
from ietf.contrib import wizard, form_decorator
nonwg_fields = {
'id': None,
'status': None,
'ds_name': None,
'ds_email': None,
'msg_to_ad': None,
}
nonwg_widgets = {
'list_url': UrlMultiWidget(choices=(('http://', 'http://'), ('https://', 'https://'), ('mailto:', 'mailto:'))),
'subscribe_url': UrlMultiWidget(choices=(('n/a', 'Not Applicable'), ('http://', 'http://'), ('https://', 'https://'))),
}
nonwg_callback = form_decorator(fields=nonwg_fields, widgets=nonwg_widgets)
def gen_approval(approvers, parent):
class BoundApproval(parent):
_approvers = approvers
def __init__(self, *args, **kwargs):
super(BoundApproval, self).__init__(self._approvers, *args, **kwargs)
return BoundApproval
class NonWgWizard(wizard.Wizard):
def get_template(self):
return "mailinglists/nwg_wizard.html"
def hash_failed(self, step):
raise NotImplementedError("step %d hash failed" % step)
def process_step(self, request, form, step):
form.full_clean()
if step == 0:
if form.clean_data['add_edit'] == 'add':
self.form_list.append(forms.form_for_model(NonWgMailingList, formfield_callback=nonwg_callback))
elif form.clean_data['add_edit'] == 'edit':
self.form_list.append(forms.form_for_instance(NonWgMailingList.objects.get(pk=form.clean_data['list_id']), formfield_callback=nonwg_callback))
elif form.clean_data['add_edit'] == 'delete':
list = NonWgMailingList.objects.get(pk=form.clean_data['list_id_delete'])
self.form_list.append(gen_approval([ad.person_id for ad in list.area.areadirectors_set.all()], DeletionPickApprover))
if step == 1:
form0 = self.get_form(0, request.POST)
form0.full_clean()
add_edit = form0.clean_data['add_edit']
if add_edit == 'add' or add_edit == 'edit':
self.form_list.append(gen_approval([ad.person_id for ad in Areas.objects.get(area_acronym=form.clean_data['area']).areadirectors_set.all()], PickApprover))
super(NonWgWizard, self).process_step(request, form, step)
def non_wg_wizard(request):
wiz = NonWgWizard([ NonWgStep1 ])
return wiz(request)
class ListReqWizard(wizard.Wizard):
def get_template(self):
return "mailinglists/nwg_wizard.html"
def hash_failed(self, step):
raise NotImplementedError("step %d hash failed" % step)
def process_step(self, request, form, step):
form.full_clean()
super(ListReqWizard, self).process_step(request, form, step)
def list_req_wizard(request):
wiz = ListReqWizard([ ListReqStep1 ])
return wiz(request)
def non_wg_submit(request):
form = NonWgStep1()
return render_to_response('mailinglists/step1.html', { 'form': form })

View file

@ -0,0 +1,18 @@
{% extends "base.html" %}
{% block css %}
ul.errorlist { color: red; border: 1px solid red; }
{% endblock %}
{% block content %}
<form action="." method="POST">
FORM( {{ step }} ):<table> {{ form }} </table>
step_info : <input type="hidden" name="{{ step_field }}" value="{{ step }}" />
previous_fields: {{ previous_fields }}
<input type="submit">
</form>
{% endblock %}