add pending and detail views and tests.

- Legacy-Id: 11125
This commit is contained in:
Ryan Cross 2016-04-20 23:57:52 +00:00
parent 8f8e4df650
commit be6e536769
11 changed files with 522 additions and 122 deletions

View file

@ -3,18 +3,19 @@ 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
from ietf.group.models import Group
from ietf.ietfauth.utils import has_role
from ietf.meeting.models import Meeting, Schedule, TimeSlot, Session, SchedTimeSessAssignment, countries, timezones
from ietf.meeting.models import Session, countries, timezones
from ietf.meeting.helpers import assign_interim_session
from ietf.utils.fields import DatepickerDateField
# need to insert empty option for use in ChoiceField
countries.insert(0, ('', '-'*9 ))
#countries.insert(0, ('', '-'*9 ))
countries.insert(0, ('', ''))
timezones.insert(0, ('', '-'*9 ))
# -------------------------------------------------
@ -138,7 +139,7 @@ class BaseSessionFormSet(BaseFormSet):
class InterimRequestForm(forms.Form):
group = GroupModelChoiceField(queryset = Group.objects.filter(type__in=('wg','rg'),state='active').order_by('acronym'))
face_to_face = forms.BooleanField(required=False)
in_person = forms.BooleanField(required=False)
meeting_type = forms.ChoiceField(choices=(("single", "Single"), ("multi-day", "Multi-Day"), ('series','Series')), required=False, initial='single', widget=forms.RadioSelect)
approved = forms.BooleanField(required=False)
@ -160,7 +161,8 @@ class InterimRequestForm(forms.Form):
queryset = Group.objects.filter(type="rg", state="active").order_by('acronym')
elif has_role(self.user, "WG Chair"):
queryset = Group.objects.filter(type="wg", state="active", role__person=self.person, role__name="chair").distinct().order_by('acronym')
elif has_role(self.user, "RG Chair"):
queryset = Group.objects.filter(type="rg", state="active", role__person=self.person, role__name="chair").distinct().order_by('acronym')
self.fields['group'].queryset = queryset
# if there's only one possibility make it the default
@ -168,10 +170,11 @@ class InterimRequestForm(forms.Form):
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()
# unset: date,time,duration
date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Date', required=False)
time = forms.TimeField(required=False)
time_utc = forms.TimeField(required=False)
duration = DurationField()
duration = DurationField(required=False)
end_time = forms.TimeField(required=False)
end_time_utc = forms.TimeField(required=False)
remote_instructions = forms.CharField(max_length=1024,required=False)
@ -196,17 +199,16 @@ class InterimSessionForm(forms.Form):
time = self.cleaned_data.get('time')
duration = self.cleaned_data.get('duration')
remote_instructions = self.cleaned_data.get('remote_instructions')
slot = TimeSlot.objects.create(meeting=meeting, type_id="session", duration=duration,
time=datetime.datetime.combine(date, time))
time=datetime.datetime.combine(date, time)
session = Session.objects.create(meeting=meeting,
group=group,
requested_by=person,
requested_duration=duration,
status_id='apprw',
type_id='session',
remote_instructions=remote_instructions,
agenda_note=agenda_note,)
SchedTimeSessAssignment.objects.create(timeslot=slot, session=session, schedule=meeting.agenda)
assign_interim_session(session,time)
if agenda:
self._save_agenda(agenda)

View file

@ -17,8 +17,9 @@ import debug # pyflakes:ignore
from ietf.doc.models import Document
from ietf.group.models import Group
from ietf.ietfauth.utils import has_role, user_is_person
from ietf.liaisons.utils import get_person_for_user
from ietf.person.models import Person
from ietf.meeting.models import Meeting, Schedule
from ietf.meeting.models import Meeting, Schedule, TimeSlot, SchedTimeSessAssignment
from ietf.utils.history import find_history_active_at, find_history_replacements_active_at
from ietf.utils.pipe import pipe
@ -285,6 +286,10 @@ def session_constraint_expire(request,session):
if key is not None and cache.has_key(key):
cache.delete(key)
# -------------------------------------------------
# Interim Meeting Helpers
# -------------------------------------------------
def get_earliest_session(session_formset):
'''Return earliest InterimSessionForm from formset'''
earliest = session_formset[0]
@ -300,20 +305,79 @@ 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')
def create_interim_meeting(group,date,city='',country='',timezone='UTC',person=None):
'''Helper function to create interim meeting and associated schedule'''
if not person:
person = Person.objects.get(name="(System)")
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)
schedule = Schedule.objects.create(meeting=meeting, owner=person, visible=True, public=True)
meeting.agenda = schedule
meeting.save()
return meeting
def create_interim_meeting_from_forms(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')
city = session_form.cleaned_data.get('city')
country = session_form.cleaned_data.get('country')
timezone = session_form.cleaned_data.get('timezone')
person = request_form.person
return create_interim_meeting(group=group,date=date,city=city,country=country,timezone=timezone,person=person)
def assign_interim_session(session,time):
'''Helper function to create a timeslot and assign the interim session'''
slot = TimeSlot.objects.create(meeting=session.meeting, type_id="session",
duration=session.requested_duration, time=time)
SchedTimeSessAssignment.objects.create(timeslot=slot, session=session, schedule=session.meeting.agenda)
def can_approve_interim_request(meeting,user):
'''Returns True if the user has permissions to approve an interim meeting request'''
if meeting.type.slug != 'interim':
return False
if has_role(user, 'Secretariat'):
return True
person = get_person_for_user(user)
session = meeting.session_set.first()
if not session:
return False
group = session.group
if group.type.slug == 'wg' and group.parent.role_set.filter(name='ad',person=person):
return True
if group.type.slug == 'rg' and group.parent.role_set.filter(name='chair',person=person):
return True
return False
def can_edit_interim_request(meeting,user):
'''Returns True if the user can edit the interim meeting request'''
if can_approve_interim_request(meeting,user):
return True
return False
def can_request_interim_meeting(user):
if has_role(user, ('Secretariat','Area Director','WG Chair','IRTF Chair', 'RG Chair')):
return True
return False
def can_view_interim_request(meeting,user):
'''Returns True if the user can see the pending interim request in the pending interim view'''
if meeting.type.slug != 'interim':
return False
if has_role(user, 'Secretariat'):
return True
person = get_person_for_user(user)
session = meeting.session_set.first()
if not session:
return False
group = session.group
if has_role(user, 'Area Director') and group.type.slug == 'wg':
return True
if has_role(user, 'IRTF Chair') and group.type.slug == 'rg':
return True
if group.role_set.filter(name='chair',person=person):
return True
return False

View file

@ -3,10 +3,21 @@ import datetime
from ietf.doc.models import Document, State
from ietf.group.models import Group
from ietf.meeting.models import Meeting, Room, TimeSlot, Session, Schedule, SchedTimeSessAssignment, ResourceAssociation, SessionPresentation
from ietf.meeting.helpers import create_interim_meeting, assign_interim_session
from ietf.name.models import RoomResourceName
from ietf.person.models import Person
from ietf.utils.test_data import make_test_data
def make_interim_meeting(group,date,status='sched'):
system_person = Person.objects.get(name="(System)")
time = datetime.datetime.combine(date, datetime.time(9))
meeting = create_interim_meeting(group=group,date=date)
session = Session.objects.create(meeting=meeting, group=group,
attendees=10, requested_by=system_person,
requested_duration=20, status_id=status,
scheduled=datetime.datetime.now(),type_id="session")
assign_interim_session(session,time)
return meeting
def make_meeting_test_data():
if not Group.objects.filter(acronym='mars'):
@ -79,29 +90,13 @@ def make_meeting_test_data():
# Future Interim Meetings
date = datetime.date.today() + datetime.timedelta(days=365)
mars_meeting = Meeting.objects.create(
number="interim-%s-mars-1" % date.year,
type_id='interim',
date=date,
city="New York",
country="US",
)
mars_session = Session.objects.create(meeting=mars_meeting, group=mars,
attendees=10, requested_by=system_person,
requested_duration=20, status_id="sched",
scheduled=datetime.datetime.now(),type_id="session")
date2 = datetime.date.today() + datetime.timedelta(days=1000)
ames = Group.objects.get(acronym="ames")
ames_meeting = Meeting.objects.create(
number="interim-%s-ames-1" % date.year,
type_id='interim',
date=date,
city="New York",
country="US",
)
ames_session = Session.objects.create(meeting=ames_meeting, group=ames,
attendees=10, requested_by=system_person,
requested_duration=20, status_id="canceled",
scheduled=datetime.datetime.now(),type_id="session")
make_interim_meeting(group=mars,date=date,status='sched')
make_interim_meeting(group=mars,date=date2,status='apprw')
make_interim_meeting(group=ames,date=date,status='canceled')
make_interim_meeting(group=ames,date=date2,status='apprw')
return meeting

View file

@ -5,11 +5,13 @@ import urlparse
from django.core.urlresolvers import reverse as urlreverse
from django.conf import settings
from django.contrib.auth.models import User
from pyquery import PyQuery
from ietf.doc.models import Document
from ietf.group.models import Group
from ietf.meeting.helpers import can_approve_interim_request, can_view_interim_request
from ietf.meeting.models import Session, TimeSlot, Meeting
from ietf.meeting.test_data import make_meeting_test_data
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
@ -332,6 +334,10 @@ class EditTests(TestCase):
self.assertTrue(mars_slot.slot_to_the_right)
self.assertTrue(mars_scheduled.slot_to_the_right)
# -------------------------------------------------
# Interim Meeting Tests
# -------------------------------------------------
class InterimTests(TestCase):
def test_upcoming(self):
make_meeting_test_data()
@ -354,20 +360,30 @@ class InterimTests(TestCase):
def test_interim_request_permissions(self):
'''Ensure only authorized users see link to request interim meeting'''
# test unauthorized
make_meeting_test_data()
# test unauthorized not logged in
upcoming_url = urlreverse("ietf.meeting.views.upcoming")
request_url = urlreverse("ietf.meeting.views.interim_request")
r = self.client.get(upcoming_url)
self.assertNotContains(r,'Request new interim meeting')
# test unauthorized user
login_testing_unauthorized(self,"plain",request_url)
r = self.client.get(upcoming_url)
self.assertNotContains(r,'Request new interim meeting')
r = self.client.get(request_url)
self.assertRedirects(r, '/accounts/login/?next=/meeting/interim/request/')
self.assertEqual(r.status_code, 403)
self.client.logout()
# test authorized
self.client.login(username="secretary", password="secretary+password")
r = self.client.get(upcoming_url)
self.assertContains(r,'Request new interim meeting')
r = self.client.get(request_url)
self.assertEqual(r.status_code, 200)
for username in ('secretary','ad','marschairman','irtf-chair','irgchairman'):
self.client.login(username=username, password= username + "+password")
r = self.client.get(upcoming_url)
self.assertContains(r,'Request new interim meeting')
r = self.client.get(request_url)
self.assertEqual(r.status_code, 200)
self.client.logout()
def test_interim_request_options(self):
make_meeting_test_data()
@ -398,7 +414,7 @@ class InterimTests(TestCase):
'form-0-duration':'03:00:00',
'form-0-city':'',
'form-0-country':'',
'form-0-timezone':'',
'form-0-timezone':'UTC',
'form-0-remote_instructions':remote_instructions,
'form-0-agenda':agenda,
'form-0-agenda_note':agenda_note,
@ -415,9 +431,9 @@ class InterimTests(TestCase):
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)
self.assertEqual(session.agenda_note,agenda_note)
timeslot = session.official_timeslotassignment().timeslot
self.assertEqual(timeslot.time,dt)
self.assertEqual(timeslot.duration,duration)
@ -460,9 +476,9 @@ class InterimTests(TestCase):
self.assertEqual(meeting.city,city)
self.assertEqual(meeting.country,country)
self.assertEqual(meeting.time_zone,timezone)
self.assertEqual(meeting.agenda_note,agenda_note)
session = meeting.session_set.first()
self.assertEqual(session.remote_instructions,remote_instructions)
self.assertEqual(session.agenda_note,agenda_note)
timeslot = session.official_timeslotassignment().timeslot
self.assertEqual(timeslot.time,dt)
self.assertEqual(timeslot.duration,duration)
@ -516,11 +532,97 @@ class InterimTests(TestCase):
self.assertEqual(meeting.city,city)
self.assertEqual(meeting.country,country)
self.assertEqual(meeting.time_zone,timezone)
self.assertEqual(meeting.agenda_note,agenda_note)
self.assertEqual(meeting.session_set.count(),2)
for session in meeting.session_set.all():
self.assertEqual(session.remote_instructions,remote_instructions)
timeslot = session.official_timeslotassignment().timeslot
self.assertEqual(timeslot.time,dt2)
self.assertEqual(timeslot.duration,duration)
# first sesstion
session = meeting.session_set.all()[0]
self.assertEqual(session.remote_instructions,remote_instructions)
timeslot = session.official_timeslotassignment().timeslot
self.assertEqual(timeslot.time,dt)
self.assertEqual(timeslot.duration,duration)
self.assertEqual(session.agenda_note,agenda_note)
# second sesstion
session = meeting.session_set.all()[1]
self.assertEqual(session.remote_instructions,remote_instructions)
timeslot = session.official_timeslotassignment().timeslot
self.assertEqual(timeslot.time,dt2)
self.assertEqual(timeslot.duration,duration)
self.assertEqual(session.agenda_note,agenda_note)
def test_interim_pending(self):
make_meeting_test_data()
url = urlreverse('ietf.meeting.views.interim_pending')
count = Meeting.objects.filter(type='interim',session__status='apprw').distinct().count()
# unpriviledged user
login_testing_unauthorized(self,"plain",url)
r = self.client.get(url)
self.assertEqual(r.status_code, 403)
# secretariat
login_testing_unauthorized(self,"secretary",url)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q("#pending-interim-meetings-table tr"))-1, count)
self.client.logout()
def test_can_approve_interim_request(self):
make_meeting_test_data()
# unprivileged user
user = User.objects.get(username='plain')
group = Group.objects.get(acronym='mars')
meeting = Meeting.objects.filter(type='interim',session__status='apprw',session__group=group).first()
self.assertFalse(can_approve_interim_request(meeting=meeting,user=user))
# Secretariat
user = User.objects.get(username='secretary')
self.assertTrue(can_approve_interim_request(meeting=meeting,user=user))
# related AD
user = User.objects.get(username='ad')
self.assertTrue(can_approve_interim_request(meeting=meeting,user=user))
# other AD
user = User.objects.get(username='ops-ad')
self.assertFalse(can_approve_interim_request(meeting=meeting,user=user))
# WG Chair
user = User.objects.get(username='marschairman')
self.assertFalse(can_approve_interim_request(meeting=meeting,user=user))
def test_can_view_interim_request(self):
make_meeting_test_data()
# unprivileged user
user = User.objects.get(username='plain')
group = Group.objects.get(acronym='mars')
meeting = Meeting.objects.filter(type='interim',session__status='apprw',session__group=group).first()
self.assertFalse(can_view_interim_request(meeting=meeting,user=user))
# Secretariat
user = User.objects.get(username='secretary')
self.assertTrue(can_view_interim_request(meeting=meeting,user=user))
# related AD
user = User.objects.get(username='ad')
self.assertTrue(can_view_interim_request(meeting=meeting,user=user))
# other AD
user = User.objects.get(username='ops-ad')
self.assertTrue(can_view_interim_request(meeting=meeting,user=user))
# WG Chair
user = User.objects.get(username='marschairman')
self.assertTrue(can_view_interim_request(meeting=meeting,user=user))
# Other WG Chair
user = User.objects.get(username='ameschairman')
self.assertFalse(can_view_interim_request(meeting=meeting,user=user))
def test_interim_request_details(self):
make_meeting_test_data()
meeting = Meeting.objects.filter(type='interim',session__status='apprw',session__group__acronym='mars').first()
url = urlreverse('ietf.meeting.views.interim_request_details',kwargs={'number':meeting.number})
login_testing_unauthorized(self,"secretary",url)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
def test_interim_request_details_permissions(self):
make_meeting_test_data()
meeting = Meeting.objects.filter(type='interim',session__status='apprw',session__group__acronym='mars').first()
url = urlreverse('ietf.meeting.views.interim_request_details',kwargs={'number':meeting.number})
# unprivileged user
login_testing_unauthorized(self,"plain",url)
r = self.client.get(url)
self.assertEqual(r.status_code, 403)

View file

@ -68,7 +68,9 @@ urlpatterns = [
url(r'^(?P<num>\d+)/', include(type_ietf_only_patterns)),
url(r'^upcoming/$', views.upcoming),
url(r'^upcoming.ics/$', views.ical_upcoming),
url(r'^interim/request/(?P<number>[A-Za-z0-9._+-]+)/$', views.interim_request_details),
url(r'^interim/request/$', views.interim_request),
url(r'^interim/pending/$', views.interim_pending),
url(r'^$', views.current_materials),
]

View file

@ -14,7 +14,7 @@ import pytz
import debug # pyflakes:ignore
from django import forms
from django.shortcuts import render, redirect
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
from django.contrib import messages
from django.core.urlresolvers import reverse
@ -37,19 +37,14 @@ 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_earliest_session
from ietf.meeting.helpers import create_interim_meeting
from ietf.meeting.helpers import create_interim_meeting_from_forms
from ietf.meeting.helpers import can_view_interim_request, can_approve_interim_request
from ietf.meeting.helpers import can_request_interim_meeting
from ietf.utils.pipe import pipe
from ietf.utils.pdf import pdf_pages
from .forms import InterimRequestForm, InterimSessionForm
# -------------------------------------------------
# Helper Functions
# -------------------------------------------------
def can_request_interim_meeting(user):
if has_role(user, ('Secretariat','Area Director','WG Chair','IRTF Chair')):
return True
return False
# -------------------------------------------------
# View Functions
@ -907,8 +902,20 @@ def ajax_get_utc(request):
utc = utc_dt.strftime('%H:%M')
context_data = {'timezone':timezone,'time':time,'utc':utc}
return HttpResponse(json.dumps(context_data),content_type='application/json')
@role_required('Area Director','Secretariat','IRTF Chair','WG Chair','RG Chair')
def interim_pending(request):
'''View which shows interim meeting requests pending approval'''
meetings = Meeting.objects.filter(type='interim',session__status='apprw')
meetings = [ m for m in meetings if can_view_interim_request(m,request.user)]
for meeting in meetings:
if can_approve_interim_request(meeting,request.user):
meeting.can_approve = True
@role_required('Area Director','Secretariat','IRTF Chair','WG Chair')
return render(request, "meeting/interim_pending.html", {"meetings":meetings})
@role_required('Area Director','Secretariat','IRTF Chair','WG Chair', 'RG Chair')
def interim_request(request):
'''View for requesting an interim meeting'''
SessionFormset = formset_factory(InterimSessionForm, extra=2)
@ -916,20 +923,22 @@ def interim_request(request):
if request.method == 'POST':
form = InterimRequestForm(request, data=request.POST)
formset = SessionFormset(data=request.POST)
person = request.user.person
#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'):
meeting = create_interim_meeting(request_form=form,session_form=get_earliest_session(formset))
meeting = create_interim_meeting_from_forms(
request_form=form,
session_form=get_earliest_session(formset))
for f in formset.forms:
if not f.has_changed():
continue
if meeting_type == 'series':
meeting = create_interim_meeting(form,f)
meeting = create_interim_meeting_from_forms(form,f)
f.save(request,group,meeting)
return redirect(upcoming)
else:
@ -940,6 +949,21 @@ def interim_request(request):
return render(request, "meeting/interim_request.html", {"form":form, "formset":formset})
@role_required('Area Director','Secretariat','IRTF Chair','WG Chair', 'RG Chair')
def interim_request_details(request, number):
'''View details of an interim meeting reqeust'''
meeting = get_object_or_404(Meeting,number=number)
sessions = meeting.session_set.all()
can_edit = can_view_interim_request(meeting,request.user)
can_approve = can_approve_interim_request(meeting,request.user)
return render(request, "meeting/interim_request_details.html",{
"meeting":meeting,
"sessions":sessions,
"can_edit":can_edit,
"can_approve":can_approve,
})
def ical_upcoming(request):
'''ICAL upcoming meetings'''
today = datetime.datetime.today()

View file

@ -5,22 +5,26 @@ var interimRequest = {
// get elements
interimRequest.form = $(this);
interimRequest.addButton = $('#add_session');
interimRequest.faceToFace = $('#id_face_to_face');
interimRequest.inPerson = $('#id_in_person');
// bind functions
$('.select2-field').select2();
$('#add_session').click(interimRequest.addSession);
interimRequest.addButton.click(interimRequest.addSession);
$('.btn-delete').click(interimRequest.deleteSession);
$('#id_face_to_face').change(interimRequest.toggleLocation);
$('input[name="meeting_type"]').change(interimRequest.checkAddButton);
interimRequest.inPerson.change(interimRequest.toggleLocation);
//$('input[name="meeting_type"]').change(interimRequest.checkAddButton);
$('input[name="meeting_type"]').change(interimRequest.meetingTypeChanged);
$('input[name$="-duration"]').blur(interimRequest.calculateEndTime);
$('input[name$="-time"]').blur(interimRequest.calculateEndTime);
//$('input[name$="-time"]').blur(interimRequest.setUTC);
$('input[name$="-time"]').blur(interimRequest.updateInfo);
$('input[name$="-end_time"]').change(interimRequest.updateInfo);
$('select[name$="-timezone"]').change(interimRequest.timezoneChange);
//interimRequest.form.submit(interimRequest.onSubmit);
// init
interimRequest.faceToFace.each(interimRequest.toggleLocation);
interimRequest.inPerson.each(interimRequest.toggleLocation);
interimRequest.checkAddButton();
interimRequest.checkHelpText();
//interimRequest.showRequired();
},
addSession : function() {
@ -53,13 +57,13 @@ var interimRequest = {
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());
//}
// copy field contents
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());
el.find("input[name$='remote_instructions']").val(first_session.find("input[name$='remote_instructions']").val());
if(meeting_type == 'multi-day'){
el.find(".location").prop('disabled', true);
}
@ -67,6 +71,15 @@ var interimRequest = {
$('.btn-delete').removeClass("hidden");
},
onSubmit : function() {
// must remove required attribute from non visible fields
var template = $(this).find(".template");
//template.find('input,textarea,select').filter('[required]').prop('required',false);
var x = template.find('input,textarea,select')
alert(x.length);
return true;
},
updateInfo : function() {
//var url = liaisonForm.form.data("ajaxInfoUrl");
//alert('called update');
@ -124,6 +137,30 @@ var interimRequest = {
interimRequest.addButton.show();
}
},
checkHelpText : function() {
var meeting_type = $('input[name="meeting_type"]:checked').val();
if(meeting_type == 'single'){
$('.meeting-type-help').hide();
} else if(meeting_type == 'multi-day') {
$('.meeting-type-help').hide();
$('.mth-multi').show();
} else if(meeting_type == 'series') {
$('.meeting-type-help').hide();
$('.mth-series').show();
}
},
checkInPerson : function() {
var meeting_type = $('input[name="meeting_type"]:checked').val();
if(meeting_type == 'series'){
interimRequest.inPerson.prop('disabled', true);
interimRequest.inPerson.prop('checked', false);
interimRequest.toggleLocation();
} else {
interimRequest.inPerson.prop('disabled', false);
}
},
get_formatted_time : function (d) {
// returns time from Date object as HH:MM
@ -151,6 +188,12 @@ var interimRequest = {
return interimRequest.pad(hours) + ":" + interimRequest.pad(minutes);
},
meetingTypeChanged : function () {
interimRequest.checkAddButton();
interimRequest.checkInPerson();
interimRequest.checkHelpText();
},
pad : function(str) {
// zero pads string 00
if(str.length == 1){
@ -169,6 +212,12 @@ var interimRequest = {
//alert(utc.attr("id"));
},
showRequired : function() {
// add a required class on labels on forms that should have
// explicit requirement asterisks
//$("form.show-required").find("input[required],select[required],textarea[required]").closest(".form-group").find("label").first().addClass("required");
},
timezoneChange : function() {
//alert("tz change");
var fieldset = $(this).parents(".fieldset");

View file

@ -0,0 +1,62 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %}
{% load staticfiles bootstrap3 widget_tweaks %}
{% block title %}Interim Pending{% endblock %}
{% block pagehead %}
<link rel="stylesheet" href="{% static 'select2/select2.css' %}">
<link rel="stylesheet" href="{% static 'select2-bootstrap-css/select2-bootstrap.min.css' %}">
{% endblock %}
{% block content %}
{% origin %}
<h1>Pending Interim Meetings</h1>
{% if meetings %}
<table id="pending-interim-meetings-table" class="table table-condensed table-striped">
<thead>
<tr>
<th>Date</th>
<th>Group</th>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody>
{% for meeting in meetings %}
{% if meeting.type.slug == 'interim' %}
<tr id="row-{{ forloop.counter }}-{{ meeting.session_set.all.0.group.acronym }}">
{% else %}
<tr id="row-{{ forloop.counter }}-ietf">
{% endif %}
<td>{{ meeting.date }}</td>
{% if meeting.type.slug == 'interim' %}
<td>{{ meeting.session_set.all.0.group.acronym }}</td>
{% else %}
<td>ietf</td>
{% endif %}
<td>
{% if meeting.type.slug == "interim" %}
<a href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">{{ meeting.number }}{% if meeting.session_set.all.0.status.slug == "canceled" %} -- CANCELLED --{% endif %}</a>
{% else %}
<a href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">IETF - {{ meeting.number }}</a>
{% endif %}
</td>
<td>{% if meeting.can_approve %}<span class="label label-warning">can approve</span>{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<h3>No pending interim meetings</h3>
{% endif %}
{% endblock %}
{% block js %}
<script src="{% static 'select2/select2.min.js' %}"></script>
<script src="{% static 'ietf/js/meeting-interim-request.js' %}"></script>
{% endblock %}

View file

@ -22,61 +22,69 @@
<div class="form-group form-inline">
<div class="col-md-offset-2">
<div class="col-md-2">
<!-- <div class="checkbox"> -->
<label class="checkbox-inline">{% render_field form.face_to_face %}<strong>Face to Face</strong></label>
<!-- </div> -->
<div class="col-md-2">
<label class="checkbox-inline">{% render_field form.in_person %}<strong>In Person</strong></label>
</div>
<div class="col-md-2">
<label class="checkbox-inline">{% render_field form.approved %}<strong>Preapproved by AD</strong></label>
</div>
<div class="col-md-2 radio-inline"><strong>Meeting Type:</strong></div>
<label class="radio-inline">
<input type="radio" value="single" checked="checked" name="meeting_type">Single
</label>
<label class="radio-inline">
<input type="radio" value="multi-day" name="meeting_type">Multi-Day
</label>
<label class="radio-inline">
<input type="radio" value="series" name="meeting_type">Series
</label>
</div> <!-- col-md-offset-2 -->
</div> <!-- form-group form-inline -->
<div class="form-group meeting-type-help mth-multi">
<div class="col-md-offset-2">
<div class="col-md-10">
<p class="help-block">Use Multi-Day to request one meeting with sessions over multiple days.</p>
</div>
</div>
<div class="col-md-2">
<!-- <div class="checkbox"> -->
<label class="checkbox-inline">{% render_field form.approved %}<strong>Approved</strong></label>
<!-- </div> -->
</div>
<!-- <div id="meeting-type-options"> -->
<div class="col-md-2 radio-inline"><strong>Meeting Type:</strong></div>
<label class="radio-inline">
<input type="radio" value="single" checked="checked" name="meeting_type">Single
</label>
<label class="radio-inline">
<input type="radio" value="multi-day" name="meeting_type">Multi-Day
</label>
<label class="radio-inline">
<input type="radio" value="series" name="meeting_type">Series
</label>
<!-- </div> -->
</div>
</div>
<div class="form-group meeting-type-help mth-series">
<div class="col-md-offset-2">
<div class="col-md-10">
<p class="help-block">Use Series to request a number of separate meetings. In Person series is not supported.</p>
</div>
</div>
</div>
{{ formset.management_form }}
{% for form in formset %}
<div class="fieldset{% if forloop.last %} template{% endif %}" >
<div class="form-group">
<label for="face-to_face" class="col-md-2 control-label">Location</label>
<label for="id_form-{{ forloop.counter0 }}-city" class="col-md-2 control-label">Location</label>
<div class="col-md-10 form-inline">
{% render_field form.city class="form-control location" placeholder="City" %}
{% render_field form.country class="form-control location" %}
{% render_field form.country class="form-control location" placeholder="Country" %}
{% render_field form.timezone class="form-control" %}
</div>
</div>
<div class="form-group">
<label for="id_date" class="col-md-2 control-label">Date</label>
<label for="id_form-{{ forloop.counter0 }}-date" class="col-md-2 control-label required">Date</label>
<div class="col-md-2">{% render_field form.date class="form-control" %}</div>
</div>
<div class="form-group">
<label for="id_time" class="col-md-2 control-label">Start Time</label>
<label for="id_form-{{ forloop.counter0 }}-time" class="col-md-2 control-label required">Start Time</label>
<div class="col-md-3 form-inline">
{% render_field form.time class="form-control time-field" placeholder="HH:MM" %}
{% render_field form.time_utc class="form-control time-field computed" disabled="disabled" placeholder="UTC" %}
</div>
<label for="id_end_time" class="col-md-2 control-label">End Time</label>
<label for="id_form-{{ forloop.counter0 }}-end_time" class="col-md-2 control-label">End Time</label>
<div class="col-md-4 form-inline">
{% render_field form.end_time class="form-control time-field computed" placeholder="HH:MM" disabled="disabled" %}
{% render_field form.end_time_utc class="form-control time-field computed" disabled="disabled" placeholder="UTC" %}
@ -84,7 +92,7 @@
</div>
<div class="form-group">
<label for="id_duration" class="col-md-2 control-label">Duration</label>
<label for="id_duration" class="col-md-2 control-label required">Duration</label>
<div class="col-md-2">{% render_field form.duration class="form-control time-field" placeholder="HH:MM" %}</div>
</div>

View file

@ -0,0 +1,59 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %}
{% load staticfiles bootstrap3 widget_tweaks %}
{% block title %}Interim Request Details{% endblock %}
{% block pagehead %}
<link rel="stylesheet" href="{% static 'select2/select2.css' %}">
<link rel="stylesheet" href="{% static 'select2-bootstrap-css/select2-bootstrap.min.css' %}">
{% endblock %}
{% block content %}
{% origin %}
<h1>Interim Meeting Request Details</h1>
<dl class="dl-horizontal">
<dt>Group</dt>
<dd>{{ sessions.0.group.acronym }}
<dt>Requested By</dt>
<dd>{{ sessions.0.requested_by }}
<dt>City</dt>
<dd>{{ meeting.city }}</dd>
<dt>Country</dt>
<dd>{{ meeting.country }}</dd>
<dt>Timezone</dt>
<dd>{{ meeting.time_zone }}</dd>
{% for session in sessions %}
<dt>Date</dt>
<dd>{{ session.official_timeslotassignment.timeslot.time|date:"Y-m-d" }}
<dt>Start Time</dt>
<dd>{{ session.official_timeslotassignment.timeslot.time|date:"H:i" }}
<dt>Duration</dt>
<dd>{{ session.requested_duration }}
<dt>Remote Instructions</dt>
<dd>{{ session.remote_instructions }}
<dt>Agenda Note</dt>
<dd>{{ session.agenda_note }}</dd>
{% endfor %}
</dl>
<form method="post">
{% csrf_token %}
{% if can_edit %}
<a class="btn btn-default" href="">Edit</a>
{% endif %}
{% if can_approve %}
<input class="btn btn-default" type="submit" value="Approve" name='approved' />
{% endif %}
{% if can_edit %}
<input class="btn btn-default" type="submit" value="Cancel" name='cancel' />
{% endif %}
</form>
{% endblock %}
{% block js %}
<script src="{% static 'select2/select2.min.js' %}"></script>
<script src="{% static 'ietf/js/meeting-interim-request.js' %}"></script>
{% endblock %}

View file

@ -89,6 +89,12 @@ def make_immutable_base_data():
area = create_group(name="Far Future", acronym="farfut", type_id="area", parent=ietf)
create_person(area, "ad", name="Areað Irector", username="ad", email_address="aread@ietf.org")
# second area
opsarea = create_group(name="Operations", acronym="ops", type_id="area", parent=ietf)
create_person(opsarea, "ad")
sops = create_group(name="Server Operations", acronym="sops", type_id="wg", parent=opsarea)
create_person(sops, "chair", name="Sops Chairman", username="sopschairman")
# create a bunch of ads for swarm tests
for i in range(1, 10):
u = User.objects.create(username="ad%s" % i)
@ -116,6 +122,7 @@ def make_immutable_base_data():
def make_test_data():
area = Group.objects.get(acronym="farfut")
ad = Person.objects.get(user__username="ad")
irtf = Group.objects.get(acronym='irtf')
# mars WG
group = Group.objects.create(
@ -166,6 +173,30 @@ def make_test_data():
group.charter = charter
group.save()
# irg RG
irg_rg = Group.objects.create(
name="Internet Research Group",
acronym="irg",
state_id="active",
type_id="rg",
parent=irtf,
list_email="irg-rg@ietf.org",
)
#charter = Document.objects.create(
# name="charter-ietf-" + group.acronym,
# type_id="charter",
# title=group.name,
# group=group,
# rev="00",
# )
#charter.set_state(State.objects.get(used=True, slug="infrev", type="charter"))
#DocAlias.objects.create(
# name=charter.name,
# document=charter
# )
#group.charter = charter
#group.save()
# plain IETF'er
u = User.objects.create(username="plain")
u.set_password("plain+password")
@ -187,6 +218,8 @@ def make_test_data():
ames_wg.role_set.get_or_create(name_id='ad',person=ad,email=ad.role_email('ad'))
ames_wg.save()
create_person(irg_rg, "chair", name="Irg Chair Man", username="irgchairman")
# old draft
old_draft = Document.objects.create(
name="draft-foo-mars-test",