Skip to content

Commit 029b477

Browse files
committed
resolve several bugs with scheduling code
- Legacy-Id: 7618
1 parent 2ff7900 commit 029b477

5 files changed

Lines changed: 77 additions & 52 deletions

File tree

ietf/secr/meetings/tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def test_notifications(self):
8585
response = self.client.get(url, REMOTE_USER=SECR_USER)
8686
self.assertEqual(response.status_code, 200)
8787
q = PyQuery(response.content)
88-
self.assertEqual(q('#id_notification_list').html(),'ames,mars')
88+
self.assertEqual(q('#id_notification_list').html(),'ames, mars')
8989

9090
# test that only changes since last notification show up
9191
mars_group = Group.objects.get(acronym='mars')
@@ -193,4 +193,4 @@ def test_meetings_select_group(self):
193193
self.assertEqual(len(q("#id_scheduled_sessions")),1)
194194

195195
# def test_meetings_schedule():
196-
196+

ietf/secr/meetings/views.py

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,18 @@ def build_timeslots(meeting,room=None):
8787
# ScheduledSession.objects.create(schedule=schedule,timeslot=t)
8888
#meeting.create_all_timeslots();
8989

90-
def build_nonsession(meeting):
90+
def build_nonsession(meeting,schedule):
9191
'''
9292
This function takes a meeting object and creates non-session records
9393
for a new meeting, based on the last meeting
9494
'''
9595
last_meeting = get_last_meeting(meeting)
9696
if not last_meeting:
9797
return None
98-
98+
9999
delta = meeting.date - last_meeting.date
100100
system = Person.objects.get(name='(system)')
101-
schedule = get_schedule(meeting)
102-
101+
103102
for slot in TimeSlot.objects.filter(meeting=last_meeting,type__in=('break','reg','other','plenary')):
104103
new_time = slot.time + delta
105104
session = None
@@ -122,13 +121,36 @@ def build_nonsession(meeting):
122121
if session:
123122
ScheduledSession.objects.create(schedule=schedule,session=session,timeslot=ts)
124123

124+
def check_nonsession(meeting,schedule):
125+
'''
126+
Ensure non-session timeslots exist and have appropriate ScheduledSession objects
127+
for the specified schedule.
128+
'''
129+
slots = TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other','plenary'))
130+
if not slots:
131+
build_nonsession(meeting,schedule)
132+
return None
133+
134+
scheduledsessions = slots.filter(type='plenary').first().scheduledsession_set.all()
135+
if not scheduledsessions.filter(schedule=schedule):
136+
source = scheduledsessions.first().schedule
137+
copy_scheduledsessions(slots,source,schedule)
138+
139+
def copy_scheduledsessions(slots,source,target):
140+
'''
141+
Copy scheduledsession objects from source schedule to target schedule. Slots is
142+
a queryset of slots
143+
'''
144+
for ss in ScheduledSession.objects.filter(schedule=source,timeslot__in=slots):
145+
ScheduledSession.objects.create(schedule=target,session=ss.session,timeslot=ss.timeslot)
146+
125147
def get_last_meeting(meeting):
126148
last_number = int(meeting.number) - 1
127149
try:
128150
return Meeting.objects.get(number=last_number)
129151
except Meeting.DoesNotExist:
130152
return None
131-
153+
132154
def is_combined(session,meeting,schedule=None):
133155
'''
134156
Check to see if this session is using two combined timeslots
@@ -178,7 +200,7 @@ def send_notifications(meeting, groups, person):
178200
# easier to populate template from timeslot perspective. assuming one-to-one timeslot-session
179201
count = 0
180202
session_info = ''
181-
data = [ (s,get_timeslot(s)) for s in sessions ]
203+
data = [ (s,get_timeslot(s)) for s in sessions if get_timeslot(s)]
182204
for s,t in data:
183205
count += 1
184206
session_info += session_info_template.format(group.acronym,
@@ -205,7 +227,7 @@ def send_notifications(meeting, groups, person):
205227
template,
206228
context,
207229
cc=cc_list)
208-
230+
209231
# create sent_notification event
210232
GroupEvent.objects.create(group=group,time=now,type='sent_notification',
211233
by=person,desc='sent scheduled notification for %s' % meeting)
@@ -408,10 +430,8 @@ def non_session(request, meeting_id, schedule_name):
408430
'''
409431
meeting = get_object_or_404(Meeting, number=meeting_id)
410432
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
411-
412-
# if the Break/Registration records don't exist yet (new meeting) create them
413-
if not TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other')):
414-
build_nonsession(meeting)
433+
434+
check_nonsession(meeting,schedule)
415435

416436
slots = TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other','plenary')).order_by('-type__name','time')
417437

@@ -435,7 +455,7 @@ def non_session(request, meeting_id, schedule_name):
435455
time=new_time,
436456
duration=duration,
437457
show_location=form.cleaned_data['show_location'])
438-
458+
439459
# create a dummy Session object to hold materials
440460
# NOTE: we're setting group to none here, but the set_room page will force user
441461
# to pick a legitimate group
@@ -448,14 +468,14 @@ def non_session(request, meeting_id, schedule_name):
448468
requested_by=Person.objects.get(name='(system)'),
449469
status_id='sched')
450470
session.save()
451-
471+
452472
# create association
453473
ScheduledSession.objects.create(timeslot=timeslot,
454474
session=session,
455-
schedule=meeting.agenda)
475+
schedule=schedule)
456476

457477
messages.success(request, 'Non-Sessions updated successfully')
458-
return redirect('meetings_non_session', meeting_id=meeting_id, schedule_name=schedule.name)
478+
return redirect('meetings_non_session', meeting_id=meeting_id, schedule_name=schedule_name)
459479
else:
460480
form = NonSessionForm(initial={'show_location':True})
461481

@@ -472,19 +492,22 @@ def non_session(request, meeting_id, schedule_name):
472492

473493
def non_session_delete(request, meeting_id, schedule_name, slot_id):
474494
'''
475-
This function deletes the non-session TimeSlot. For "other" and "plenary" timeslot types
476-
we need to delete the corresponding Session object as well. Check for uploaded material
477-
first.
495+
This function deletes the non-session TimeSlot. For "other" and "plenary" timeslot
496+
types we need to delete the corresponding Session object as well. Check for uploaded
497+
material first. ScheduledSession objects get deleted as well.
478498
'''
499+
meeting = get_object_or_404(Meeting, number=meeting_id)
500+
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
479501
slot = get_object_or_404(TimeSlot, id=slot_id)
480502
if slot.type_id in ('other','plenary'):
481-
session = get_session(slot,schedule=schedule)
482-
if session and session.materials.exclude(states__slug='deleted'):
483-
messages.error(request, 'Materials have already been uploaded for "%s". You must delete those before deleting the timeslot.' % slot.name)
484-
return redirect('meetings_non_session', meeting_id=meeting_id, schedule_name=schedule_name)
485-
503+
scheduledsessions = slot.scheduledsession_set.filter(schedule__meeting=meeting)
504+
session_objects = [ x.session for x in scheduledsessions ]
505+
for session in session_objects:
506+
if session.materials.exclude(states__slug='deleted'):
507+
messages.error(request, 'Materials have already been uploaded for "%s". You must delete those before deleting the timeslot.' % slot.name)
508+
return redirect('meetings_non_session', meeting_id=meeting_id, schedule_name=schedule_name)
486509
else:
487-
slot.sessions.all().delete()
510+
Session.objects.filter(pk__in=[ x.pk for x in session_objects ]).delete()
488511
slot.delete()
489512

490513
messages.success(request, 'Non-Session timeslot deleted successfully')
@@ -496,6 +519,7 @@ def non_session_edit(request, meeting_id, schedule_name, slot_id):
496519
'''
497520
meeting = get_object_or_404(Meeting, number=meeting_id)
498521
slot = get_object_or_404(TimeSlot, id=slot_id)
522+
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
499523
session = get_session(slot,schedule=schedule)
500524

501525
if request.method == 'POST':
@@ -533,6 +557,7 @@ def non_session_edit(request, meeting_id, schedule_name, slot_id):
533557
return render_to_response('meetings/non_session_edit.html', {
534558
'meeting': meeting,
535559
'form': form,
560+
'schedule': schedule,
536561
'slot': slot},
537562
RequestContext(request, {}),
538563
)
@@ -601,7 +626,7 @@ def rooms(request, meeting_id, schedule_name):
601626
'''
602627
meeting = get_object_or_404(Meeting, number=meeting_id)
603628
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
604-
629+
605630
# if no rooms exist yet (new meeting) formset extra=10
606631
first_time = not bool(meeting.room_set.all())
607632
extra = 10 if first_time else 0
@@ -646,7 +671,7 @@ def schedule(request, meeting_id, schedule_name, acronym):
646671
meeting = get_object_or_404(Meeting, number=meeting_id)
647672
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
648673
group = get_object_or_404(Group, acronym=acronym)
649-
674+
650675
sessions = Session.objects.filter(meeting=meeting,group=group,status__in=('schedw','apprw','appr','sched','canceled'))
651676
legacy_session = get_initial_session(sessions)
652677
session_conflicts = session_conflicts_as_string(group, meeting)
@@ -759,13 +784,13 @@ def select(request, meeting_id, schedule_name):
759784
'''
760785
meeting = get_object_or_404(Meeting, number=meeting_id)
761786
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
762-
787+
763788
return render_to_response('meetings/select.html', {
764789
'meeting': meeting,
765790
'schedule': schedule},
766791
RequestContext(request, {}),
767792
)
768-
793+
769794
def select_group(request, meeting_id, schedule_name):
770795
'''
771796
In this view the user can select the group to schedule. Only those groups that have
@@ -775,7 +800,7 @@ def select_group(request, meeting_id, schedule_name):
775800
'''
776801
meeting = get_object_or_404(Meeting, number=meeting_id)
777802
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
778-
803+
779804
if request.method == 'POST':
780805
group = request.POST.get('group',None)
781806
if group:
@@ -882,7 +907,7 @@ def times_edit(request, meeting_id, schedule_name, time):
882907
'''
883908
meeting = get_object_or_404(Meeting, number=meeting_id)
884909
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
885-
910+
886911
parts = [ int(x) for x in time.split(':') ]
887912
dtime = datetime.datetime(*parts)
888913
timeslots = TimeSlot.objects.filter(meeting=meeting,time=dtime)
@@ -898,10 +923,10 @@ def times_edit(request, meeting_id, schedule_name, time):
898923
time = form.cleaned_data['time']
899924
duration = form.cleaned_data['duration']
900925
name = form.cleaned_data['name']
901-
926+
902927
t = meeting.date + datetime.timedelta(days=int(day))
903928
new_time = datetime.datetime(t.year,t.month,t.day,time.hour,time.minute)
904-
929+
905930
for timeslot in timeslots:
906931
timeslot.time = new_time
907932
timeslot.duration = duration
@@ -937,7 +962,7 @@ def times_delete(request, meeting_id, schedule_name, time):
937962
'''
938963
meeting = get_object_or_404(Meeting, number=meeting_id)
939964
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
940-
965+
941966
parts = [ int(x) for x in time.split(':') ]
942967
dtime = datetime.datetime(*parts)
943968

@@ -981,7 +1006,7 @@ def view(request, meeting_id):
9811006
9821007
'''
9831008
meeting = get_object_or_404(Meeting, number=meeting_id)
984-
1009+
9851010
return render_to_response('meetings/view.html', {
9861011
'meeting': meeting},
9871012
RequestContext(request, {}),

ietf/secr/templates/meetings/notifications.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ <h2>IETF {{ meeting.number }} - Send Notifications</h2>
1919
<form id="id_notification_form" action="." method="post">{% csrf_token %}
2020
<p>Send email notifications to all groups that have been scheduled since the last
2121
notification went out on {{ last_notice.time|date:"Y-m-d" }}:</p>
22-
<p id="id_notification_list">{% if not groups %}(none){% endif %}{% for group in groups %}{{ group.acronym }}{% if not forloop.last %},{% endif %}{% endfor %}<p>
22+
<p id="id_notification_list">{% if not groups %}(none){% endif %}{% for group in groups %}{{ group.acronym }}{% if not forloop.last %}, {% endif %}{% endfor %}<p>
2323
<input type="submit" value="Send Now" name="submit" onclick="return window.confirm('Are you sure you want to send notifications?');">
2424
</form>
2525

ietf/secr/templates/meetings/schedule.html

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,33 @@
44

55
{% block extrahead %}{{ block.super }}
66
<script type="text/javascript" src="{{ SECR_STATIC_URL }}js/utils.js"></script>
7-
7+
88
<script type="text/javascript">
99
$(document).ready(function() {
10-
$.ajaxSetup ({
11-
cache: false
10+
$.ajaxSetup ({
11+
cache: false
1212
});
13-
13+
1414
$("select[id$='day']").change(function(){
15-
var loadUrl = "/meetings/ajax/get-times/";
15+
var loadUrl = "/secr/meetings/ajax/get-times/";
1616
var url = window.location.pathname;
1717
var parts = url.split("/");
1818
var id = this.id;
1919
var new_id = id.replace('day','time');
2020
var sel = "#"+new_id;
2121
var day = $(this).val();
22-
loadUrl = loadUrl+parts[2]+"/"+day+"/";
22+
loadUrl = loadUrl+parts[3]+"/"+day+"/";
2323
$.getJSON(loadUrl,function(data) {
2424
$(sel+" option").remove();
2525
$.each(data,function(i,item) {
2626
$(sel).append('<option value="'+item.id+'">'+item.value+'</option>');
2727
});
2828
});
2929
});
30-
31-
30+
31+
3232
});
33-
33+
3434
</script>
3535
{% endblock %}
3636

@@ -46,11 +46,11 @@
4646

4747
<div class="module">
4848
<h2>Requested Information</h2>
49-
49+
5050
{% if show_request %}
5151
{% include "includes/sessions_request_view.html" %}
5252
{% endif %}
53-
53+
5454
<div class="inline-group">
5555
<h2>Sessions</h2>
5656

@@ -66,17 +66,17 @@ <h3><b>Session:</b>&nbsp; #{{ forloop.counter }}{% if form.session_object.status
6666
</div> <!-- inline-related -->
6767
{% endfor %}
6868
</div> <!-- inline-group -->
69-
69+
7070
<div class="button-group">
7171
<ul>
7272
<li><button type="submit" name="submit" value="Save">Save</button></li>
7373
<li><button type="button" onclick="if (window.confirm('This group will be permanently removed from the agenda and scheduling tool')) { window.location='{% url "meetings_remove_session" meeting_id=meeting.number acronym=group.acronym %}' };">Remove this group from agenda</button></li>
7474
<li><button type="button" onclick="window.location='{% url "meetings_select_group" meeting_id=meeting.number schedule_name=schedule.name %}'">Back</button></li>
7575
</ul>
7676
</div> <!-- button-group -->
77-
77+
7878
</form>
79-
79+
8080
</div> <!-- module -->
8181

8282
{% endblock %}

ietf/secr/templates/proceedings/select.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
var ajax_load = "<p><h4 align='center'>Generating Proceedings. This may take a few minutes.</h3><img class='loading' src='{{ SECR_STATIC_URL }}img/ajax-loader.gif' alt='loading...' /></p>";
1616
var url = window.location.pathname;
1717
var parts = url.split("/");
18-
var loadUrl = "/proceedings/ajax/generate-proceedings/" + parts[2] + "/";
18+
var loadUrl = "/secr/proceedings/ajax/generate-proceedings/" + parts[2] + "/";
1919
$("#private-functions").html(ajax_load).load(loadUrl);
2020
});
2121

0 commit comments

Comments
 (0)