Add support for series request. Javascript tweaks

- Legacy-Id: 11028
This commit is contained in:
Ryan Cross 2016-03-30 00:02:28 +00:00
parent b85df63a4f
commit 7238fd9148
7 changed files with 164 additions and 22 deletions

View file

@ -3,6 +3,7 @@ import re
from django import forms
from django.core.validators import ValidationError
from django.forms import BaseFormSet
from django.forms.fields import Field
from django.utils.encoding import force_text
from django.utils import six
@ -110,6 +111,27 @@ class GroupModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.acronym
'''
class BaseSessionFormSet(BaseFormSet):
def save_new_objects(self, commit=True):
self.new_objects = []
for form in self.extra_forms:
if not form.has_changed():
continue
# If someone has marked an add form for deletion, don't save the
# object.
if self.can_delete and self._should_delete_form(form):
continue
self.new_objects.append(self.save_new(form, commit=commit))
if not commit:
self.saved_forms.append(form)
return self.new_objects
def save(self,commit=True):
#return self.save_existing_objects(commit) + self.save_new_objects(commit)
return self.save_new_objects(commit)
'''
# -------------------------------------------------
# Forms
# -------------------------------------------------
@ -140,10 +162,16 @@ class InterimRequestForm(forms.Form):
self.fields['group'].queryset = queryset
# if there's only one possibility make it the default
if len(queryset) == 1:
self.fields['group'].initial = queryset[0]
class InterimSessionForm(forms.Form):
date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Date', required=True)
time = forms.TimeField()
utc_time = forms.TimeField()
duration = DurationField()
end_time = forms.TimeField()
remote_instructions = forms.CharField(max_length=1024,required=False)
agenda = forms.CharField(required=False,widget=forms.Textarea)
agenda_note = forms.CharField(max_length=255,required=False)

View file

@ -18,7 +18,7 @@ from ietf.doc.models import Document
from ietf.group.models import Group
from ietf.ietfauth.utils import has_role, user_is_person
from ietf.person.models import Person
from ietf.meeting.models import Meeting
from ietf.meeting.models import Meeting, Schedule
from ietf.utils.history import find_history_active_at, find_history_replacements_active_at
from ietf.utils.pipe import pipe
@ -285,6 +285,35 @@ def session_constraint_expire(request,session):
if key is not None and cache.has_key(key):
cache.delete(key)
def get_earliest_session(session_formset):
'''Return earliest InterimSessionForm from formset'''
earliest = session_formset[0]
if len(session_formset) == 1:
return earliest
for form in session_formset[1:]:
date = form.cleaned_data.get('date')
if date and date < earliest.cleaned_data.get('date'):
earliest = form
return earliest
def get_next_interim_number(group,date):
sequence = Meeting.objects.filter(number__startswith='interim-%s-%s' % (date.year,group.acronym)).count() + 1
return 'interim-%s-%s-%s' % (date.year,group.acronym,sequence)
def create_interim_meeting(request_form,session_form):
'''Create an Interim meeting, given an InterimRequestForm and InterimSessionForm'''
group = request_form.cleaned_data.get('group')
date = session_form.cleaned_data.get('date')
number = get_next_interim_number(group,date)
city = session_form.cleaned_data.get('city')
country = session_form.cleaned_data.get('country')
timezone = session_form.cleaned_data.get('timezone')
if not request_form.cleaned_data.get('face_to_face'):
timezone = 'UTC'
meeting = Meeting.objects.create(number=number,type_id='interim',date=date,city=city,
country=country,time_zone=timezone)
schedule = Schedule.objects.create(meeting=meeting, owner=request_form.person, visible=True, public=True)
meeting.agenda = schedule
meeting.save()
return meeting

View file

@ -381,6 +381,48 @@ class InterimTests(TestCase):
len(q("#id_group option")) -1 ) # -1 for options placeholder
def test_interim_request_single(self):
make_meeting_test_data()
group = Group.objects.get(acronym='mars')
date = datetime.date.today() + datetime.timedelta(days=30)
time = datetime.datetime.now().time().replace(microsecond=0,second=0)
dt = datetime.datetime.combine(date, time)
duration = datetime.timedelta(hours=3)
remote_instructions = 'Use webex'
agenda = 'Intro. Slides. Discuss.'
agenda_note = 'On second level'
self.client.login(username="secretary", password="secretary+password")
data = {'group':group.pk,
'meeting_type':'single',
'form-0-date':date.strftime("%Y-%m-%d"),
'form-0-time':time.strftime('%H:%M'),
'form-0-duration':'03:00:00',
'form-0-city':'',
'form-0-country':'',
'form-0-timezone':'',
'form-0-remote_instructions':remote_instructions,
'form-0-agenda':agenda,
'form-0-agenda_note':agenda_note,
'form-TOTAL_FORMS':1,
'form-INITIAL_FORMS':0}
r = self.client.post(urlreverse("ietf.meeting.views.interim_request"),data)
self.assertRedirects(r,urlreverse('ietf.meeting.views.upcoming'))
meeting = Meeting.objects.order_by('id').last()
self.assertEqual(meeting.type_id,'interim')
self.assertEqual(meeting.date,date)
self.assertEqual(meeting.number,'interim-%s-%s-%s' % (date.year,group.acronym,1))
self.assertEqual(meeting.city,'')
self.assertEqual(meeting.country,'')
self.assertEqual(meeting.time_zone,'UTC')
self.assertEqual(meeting.agenda_note,agenda_note)
session = meeting.session_set.first()
self.assertEqual(session.remote_instructions,remote_instructions)
timeslot = session.official_timeslotassignment().timeslot
self.assertEqual(timeslot.time,dt)
self.assertEqual(timeslot.duration,duration)
def test_interim_request_single_f2f(self):
make_meeting_test_data()
group = Group.objects.get(acronym='mars')
date = datetime.date.today() + datetime.timedelta(days=30)

View file

@ -35,7 +35,8 @@ from ietf.meeting.helpers import get_modified_from_assignments
from ietf.meeting.helpers import get_wg_list, find_ads_for_meeting
from ietf.meeting.helpers import get_meeting, get_schedule, agenda_permissions, get_meetings
from ietf.meeting.helpers import preprocess_assignments_for_agenda, read_agenda_file
from ietf.meeting.helpers import convert_draft_to_pdf, get_next_interim_number
from ietf.meeting.helpers import convert_draft_to_pdf, get_earliest_session
from ietf.meeting.helpers import create_interim_meeting
from ietf.utils.pipe import pipe
from ietf.utils.pdf import pdf_pages
@ -897,22 +898,20 @@ def interim_request(request):
if request.method == 'POST':
form = InterimRequestForm(request, data=request.POST)
formset = SessionFormset(data=request.POST)
person = request.user.person
if form.is_valid() and formset.is_valid():
group = form.cleaned_data.get('group')
meeting_type = form.cleaned_data.get('meeting_type')
# pre create meeting
if meeting_type in ('single','multi-day'):
date = sorted([ f.cleaned_data.get('date') for f in formset.forms])[0]
number = get_next_interim_number(group,date)
city = formset.forms[0].cleaned_data.get('city')
country = formset.forms[0].cleaned_data.get('country')
timezone = formset.forms[0].cleaned_data.get('timezone')
meeting = Meeting.objects.create(number=number,type_id='interim',date=date,city=city,
country=country,time_zone=timezone)
schedule = Schedule.objects.create(meeting=meeting, owner=person, visible=True, public=True)
meeting.agenda = schedule
meeting.save()
meeting = create_interim_meeting(request_form=form,session_form=get_earliest_session(formset))
for f in formset.forms:
# TODO: create meetings if type == series
if not f.has_changed():
continue
if meeting_type == 'series':
meeting = create_interim_meeting(form,f)
f.save(request,group,meeting)
return redirect(upcoming)
else:
@ -935,7 +934,7 @@ def ical_upcoming(request):
def upcoming(request):
'''List of upcoming meetings'''
today = datetime.datetime.today()
meetings = Meeting.objects.filter(date__gt=today)
meetings = Meeting.objects.filter(date__gte=today).order_by('date')
# extract groups hierarchy
seen = set()

View file

@ -466,3 +466,7 @@ form.navbar-form input.form-control.input-sm { width: 141px; }
#interim-request-form .fieldset.template {
display: none;
}
#interim-request-form .time-field {
width: 100px;
}

View file

@ -2,12 +2,18 @@
var interimRequest = {
// functions for Interim Meeting Request
init : function() {
// get elements
interimRequest.form = $(this);
//interimRequest.sessionTemplate = interimRequest.form.find('.fieldset.template');
interimRequest.addButton = $('#add_session');
interimRequest.faceToFace = $('#id_face_to_face');
// bind functions
$('.select2-field').select2();
$('#add_session').click(interimRequest.addSession);
$('#id_face_to_face').change(interimRequest.toggleLocation);
$('#id_face_to_face').each(interimRequest.toggleLocation);
$('input[name="meeting_type"]').change(interimRequest.checkAddButton);
// init
interimRequest.faceToFace.each(interimRequest.toggleLocation);
interimRequest.checkAddButton();
},
addSession : function() {
@ -16,6 +22,7 @@ var interimRequest = {
var el = template.clone(true);
var totalField = $('#id_form-TOTAL_FORMS');
var total = +totalField.val();
var meeting_type = $('input[name="meeting_type"]:checked').val();
el.find(':input').each(function() {
var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
@ -38,6 +45,27 @@ var interimRequest = {
el.find(".select2-field").each(function () {
setupSelect2Field($(this));
});
if(interimRequest.faceToFace.prop('checked')){
var first_session = $(".fieldset:first");
el.find("input[name$='city']").val(first_session.find("input[name$='city']").val());
el.find("select[name$='country']").val(first_session.find("select[name$='country']").val());
el.find("select[name$='timezone']").val(first_session.find("select[name$='timezone']").val());
}
if(meeting_type == 'multi-day'){
el.find(".location").prop('disabled', true);
}
},
checkAddButton : function() {
var meeting_type = $('input[name="meeting_type"]:checked').val();
if(meeting_type == 'single'){
interimRequest.addButton.hide();
} else {
interimRequest.addButton.show();
}
},
toggleLocation : function() {

View file

@ -63,9 +63,16 @@
<label for="session" class="col-md-2 control-label">Session</label>
<div class="">
<div class="form-inline">
<div class="col-md-3">{% render_field form.date class="form-control" %}</div>
<div class="col-md-3">{% render_field form.time class="form-control" placeholder="time" %}</div>
<div class="col-md-3">{% render_field form.duration class="form-control" placeholder="duration" %}</div>
<div class="col-md-9">
{% render_field form.date class="form-control" %}
<div>
{% render_field form.time class="form-control time-field" placeholder="time" %}
<p class="help-block">Time</p>
</div>
{% render_field form.utc_time class="form-control time-field computed" disabled="disabled" placeholder="UTC time" %}
{% render_field form.duration class="form-control time-field" placeholder="duration" %}
{% render_field form.end_time class="form-control time-field computed" placeholder="end time" disabled="disabled" %}
</div>
</div>
</div>
</div>
@ -87,14 +94,19 @@
</div> <!-- fieldset -->
{% endfor %}
<div class="row">
<button id="add_session" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true">Add Session</button>
</div>
<div class="form-group">
<div class="col-md-10">
<button id="add_session" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span>Add Session</button>
</div>
</div>
<div class="form-group"
{% buttons %}
<button type="submit" class="btn btn-primary">Submit</button>
<a class="btn btn-default pull-right" href="{% url "ietf.meeting.views.upcoming" %}">Back</a>
{% endbuttons %}
</div>
</form>
{% endblock %}