From rjsparks@nostrum.com:

-  Fixed layout issue on schedule editing page in Chrome
  -  Fixed errant display of text in unscheduled group bar
     on the schedule editing page
  -  Changed the instruction text on the special requests
     field of the session request form

From rcross@amsl.com:
  - Improved scheduling of non-session items
  - Fixed issue with layout of the new notifications page
  - Fixed crash on notifications page
 - Legacy-Id: 7644
This commit is contained in:
Robert Sparks 2014-04-25 14:44:40 +00:00
commit b8cfbf18e5
10 changed files with 86 additions and 56 deletions

View file

@ -88,7 +88,7 @@ class MainTestCase(TestCase):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
q = PyQuery(response.content)
self.assertEqual(q('#id_notification_list').html(),'ames,mars')
self.assertEqual(q('#id_notification_list').html(),'ames, mars')
# test that only changes since last notification show up
mars_group = Group.objects.get(acronym='mars')

View file

@ -14,7 +14,6 @@ from django.utils.functional import curry
from ietf.utils.mail import send_mail
from ietf.meeting.models import Meeting, Session, Room, TimeSlot, ScheduledSession, Schedule
from ietf.meeting.helpers import get_schedule
from ietf.group.models import Group, GroupEvent
from ietf.person.models import Person
from ietf.secr.meetings.blue_sheets import create_blue_sheets
@ -83,7 +82,7 @@ def build_timeslots(meeting,room=None):
location=room,
duration=t.duration)
def build_nonsession(meeting):
def build_nonsession(meeting,schedule):
'''
This function takes a meeting object and creates non-session records
for a new meeting, based on the last meeting
@ -91,11 +90,10 @@ def build_nonsession(meeting):
last_meeting = get_last_meeting(meeting)
if not last_meeting:
return None
delta = meeting.date - last_meeting.date
system = Person.objects.get(name='(system)')
schedule = get_schedule(meeting)
for slot in TimeSlot.objects.filter(meeting=last_meeting,type__in=('break','reg','other','plenary')):
new_time = slot.time + delta
session = None
@ -118,13 +116,36 @@ def build_nonsession(meeting):
if session:
ScheduledSession.objects.create(schedule=schedule,session=session,timeslot=ts)
def check_nonsession(meeting,schedule):
'''
Ensure non-session timeslots exist and have appropriate ScheduledSession objects
for the specified schedule.
'''
slots = TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other','plenary'))
if not slots:
build_nonsession(meeting,schedule)
return None
scheduledsessions = slots.filter(type='plenary').first().scheduledsession_set.all()
if not scheduledsessions.filter(schedule=schedule):
source = scheduledsessions.first().schedule
copy_scheduledsessions(slots,source,schedule)
def copy_scheduledsessions(slots,source,target):
'''
Copy scheduledsession objects from source schedule to target schedule. Slots is
a queryset of slots
'''
for ss in ScheduledSession.objects.filter(schedule=source,timeslot__in=slots):
ScheduledSession.objects.create(schedule=target,session=ss.session,timeslot=ss.timeslot)
def get_last_meeting(meeting):
last_number = int(meeting.number) - 1
try:
return Meeting.objects.get(number=last_number)
except Meeting.DoesNotExist:
return None
def is_combined(session,meeting,schedule=None):
'''
Check to see if this session is using two combined timeslots
@ -162,7 +183,7 @@ def send_notifications(meeting, groups, person):
# easier to populate template from timeslot perspective. assuming one-to-one timeslot-session
count = 0
session_info = ''
data = [ (s,get_timeslot(s)) for s in sessions ]
data = [ (s,get_timeslot(s)) for s in sessions if get_timeslot(s)]
for s,t in data:
count += 1
session_info += session_info_template.format(group.acronym,
@ -189,7 +210,7 @@ def send_notifications(meeting, groups, person):
template,
context,
cc=cc_list)
# create sent_notification event
GroupEvent.objects.create(group=group,time=now,type='sent_notification',
by=person,desc='sent scheduled notification for %s' % meeting)
@ -392,10 +413,8 @@ def non_session(request, meeting_id, schedule_name):
'''
meeting = get_object_or_404(Meeting, number=meeting_id)
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
# if the Break/Registration records don't exist yet (new meeting) create them
if not TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other')):
build_nonsession(meeting)
check_nonsession(meeting,schedule)
slots = TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other','plenary')).order_by('-type__name','time')
@ -419,7 +438,7 @@ def non_session(request, meeting_id, schedule_name):
time=new_time,
duration=duration,
show_location=form.cleaned_data['show_location'])
# create a dummy Session object to hold materials
# NOTE: we're setting group to none here, but the set_room page will force user
# to pick a legitimate group
@ -432,14 +451,14 @@ def non_session(request, meeting_id, schedule_name):
requested_by=Person.objects.get(name='(system)'),
status_id='sched')
session.save()
# create association
ScheduledSession.objects.create(timeslot=timeslot,
session=session,
schedule=meeting.agenda)
schedule=schedule)
messages.success(request, 'Non-Sessions updated successfully')
return redirect('meetings_non_session', meeting_id=meeting_id, schedule_name=schedule.name)
return redirect('meetings_non_session', meeting_id=meeting_id, schedule_name=schedule_name)
else:
form = NonSessionForm(initial={'show_location':True})
@ -456,19 +475,22 @@ def non_session(request, meeting_id, schedule_name):
def non_session_delete(request, meeting_id, schedule_name, slot_id):
'''
This function deletes the non-session TimeSlot. For "other" and "plenary" timeslot types
we need to delete the corresponding Session object as well. Check for uploaded material
first.
This function deletes the non-session TimeSlot. For "other" and "plenary" timeslot
types we need to delete the corresponding Session object as well. Check for uploaded
material first. ScheduledSession objects get deleted as well.
'''
meeting = get_object_or_404(Meeting, number=meeting_id)
# schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
slot = get_object_or_404(TimeSlot, id=slot_id)
if slot.type_id in ('other','plenary'):
session = get_session(slot,schedule=schedule)
if session and session.materials.exclude(states__slug='deleted'):
messages.error(request, 'Materials have already been uploaded for "%s". You must delete those before deleting the timeslot.' % slot.name)
return redirect('meetings_non_session', meeting_id=meeting_id, schedule_name=schedule_name)
scheduledsessions = slot.scheduledsession_set.filter(schedule__meeting=meeting)
session_objects = [ x.session for x in scheduledsessions ]
for session in session_objects:
if session.materials.exclude(states__slug='deleted'):
messages.error(request, 'Materials have already been uploaded for "%s". You must delete those before deleting the timeslot.' % slot.name)
return redirect('meetings_non_session', meeting_id=meeting_id, schedule_name=schedule_name)
else:
slot.sessions.all().delete()
Session.objects.filter(pk__in=[ x.pk for x in session_objects ]).delete()
slot.delete()
messages.success(request, 'Non-Session timeslot deleted successfully')
@ -480,6 +502,7 @@ def non_session_edit(request, meeting_id, schedule_name, slot_id):
'''
meeting = get_object_or_404(Meeting, number=meeting_id)
slot = get_object_or_404(TimeSlot, id=slot_id)
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
session = get_session(slot,schedule=schedule)
if request.method == 'POST':
@ -517,6 +540,7 @@ def non_session_edit(request, meeting_id, schedule_name, slot_id):
return render_to_response('meetings/non_session_edit.html', {
'meeting': meeting,
'form': form,
'schedule': schedule,
'slot': slot},
RequestContext(request, {}),
)
@ -585,7 +609,7 @@ def rooms(request, meeting_id, schedule_name):
'''
meeting = get_object_or_404(Meeting, number=meeting_id)
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
# if no rooms exist yet (new meeting) formset extra=10
first_time = not bool(meeting.room_set.all())
extra = 10 if first_time else 0
@ -630,7 +654,7 @@ def schedule(request, meeting_id, schedule_name, acronym):
meeting = get_object_or_404(Meeting, number=meeting_id)
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
group = get_object_or_404(Group, acronym=acronym)
sessions = Session.objects.filter(meeting=meeting,group=group,status__in=('schedw','apprw','appr','sched','canceled'))
legacy_session = get_initial_session(sessions)
now = datetime.datetime.now()
@ -742,13 +766,13 @@ def select(request, meeting_id, schedule_name):
'''
meeting = get_object_or_404(Meeting, number=meeting_id)
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
return render_to_response('meetings/select.html', {
'meeting': meeting,
'schedule': schedule},
RequestContext(request, {}),
)
def select_group(request, meeting_id, schedule_name):
'''
In this view the user can select the group to schedule. Only those groups that have
@ -758,7 +782,7 @@ def select_group(request, meeting_id, schedule_name):
'''
meeting = get_object_or_404(Meeting, number=meeting_id)
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
if request.method == 'POST':
group = request.POST.get('group',None)
if group:
@ -864,7 +888,7 @@ def times_edit(request, meeting_id, schedule_name, time):
'''
meeting = get_object_or_404(Meeting, number=meeting_id)
schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
parts = [ int(x) for x in time.split(':') ]
dtime = datetime.datetime(*parts)
timeslots = TimeSlot.objects.filter(meeting=meeting,time=dtime)
@ -880,10 +904,10 @@ def times_edit(request, meeting_id, schedule_name, time):
time = form.cleaned_data['time']
duration = form.cleaned_data['duration']
name = form.cleaned_data['name']
t = meeting.date + datetime.timedelta(days=int(day))
new_time = datetime.datetime(t.year,t.month,t.day,time.hour,time.minute)
for timeslot in timeslots:
timeslot.time = new_time
timeslot.duration = duration
@ -918,7 +942,7 @@ def times_delete(request, meeting_id, schedule_name, time):
meeting. There is one timeslot for each room.
'''
meeting = get_object_or_404(Meeting, number=meeting_id)
parts = [ int(x) for x in time.split(':') ]
dtime = datetime.datetime(*parts)
@ -955,7 +979,7 @@ def view(request, meeting_id):
'''
meeting = get_object_or_404(Meeting, number=meeting_id)
return render_to_response('meetings/view.html', {
'meeting': meeting},
RequestContext(request, {}),

View file

@ -57,7 +57,7 @@
</td>
</tr>
<tr class="bg1">
<td valign="top">Special Requests:<br />&nbsp;<br />i.e. Meetecho, WebEx (please state which, and the reason needed), restrictions on meeting times / days, etc.</td>
<td valign="top">Special Requests:<br />&nbsp;<br />i.e. restrictions on meeting times / days, etc.</td>
<td>{{ form.comments.errors }}{{ form.comments }}</td>
</tr>
</table>

View file

@ -19,7 +19,7 @@
<form id="id_notification_form" action="." method="post">{% csrf_token %}
<p>Send email notifications to all groups that have been scheduled since the last
notification went out on {{ last_notice.time|date:"Y-m-d" }}:</p>
<p id="id_notification_list">{% if not groups %}(none){% endif %}{% for group in groups %}{{ group.acronym }}{% if not forloop.last %},{% endif %}{% endfor %}<p>
<p id="id_notification_list">{% if not groups %}(none){% endif %}{% for group in groups %}{{ group.acronym }}{% if not forloop.last %}, {% endif %}{% endfor %}<p>
<input type="submit" value="Send Now" name="submit" onclick="return window.confirm('Are you sure you want to send notifications?');">
</form>

View file

@ -4,22 +4,22 @@
{% block extrahead %}{{ block.super }}
<script type="text/javascript" src="{{ SECR_STATIC_URL }}js/utils.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$.ajaxSetup ({
cache: false
$.ajaxSetup ({
cache: false
});
$("select[id$='day']").change(function(){
var loadUrl = "/meetings/ajax/get-times/";
var loadUrl = "/secr/meetings/ajax/get-times/";
var url = window.location.pathname;
var parts = url.split("/");
var id = this.id;
var new_id = id.replace('day','time');
var sel = "#"+new_id;
var day = $(this).val();
loadUrl = loadUrl+parts[2]+"/"+day+"/";
loadUrl = loadUrl+parts[3]+"/"+day+"/";
$.getJSON(loadUrl,function(data) {
$(sel+" option").remove();
$.each(data,function(i,item) {
@ -27,10 +27,10 @@
});
});
});
});
</script>
{% endblock %}
@ -46,11 +46,11 @@
<div class="module">
<h2>Requested Information</h2>
{% if show_request %}
{% include "includes/sessions_request_view.html" %}
{% endif %}
<div class="inline-group">
<h2>Sessions</h2>
@ -66,7 +66,7 @@
</div> <!-- inline-related -->
{% endfor %}
</div> <!-- inline-group -->
<div class="button-group">
<ul>
<li><button type="submit" name="submit" value="Save">Save</button></li>
@ -74,9 +74,9 @@
<li><button type="button" onclick="window.location='{% url "meetings_select_group" meeting_id=meeting.number schedule_name=schedule.name %}'">Back</button></li>
</ul>
</div> <!-- button-group -->
</form>
</div> <!-- module -->
{% endblock %}

View file

@ -15,7 +15,7 @@
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>";
var url = window.location.pathname;
var parts = url.split("/");
var loadUrl = "/proceedings/ajax/generate-proceedings/" + parts[2] + "/";
var loadUrl = "/secr/proceedings/ajax/generate-proceedings/" + parts[2] + "/";
$("#private-functions").html(ajax_load).load(loadUrl);
});

View file

@ -249,7 +249,7 @@ promiselist.push(ss_promise);
</th>
{% for day in time_slices %}
{% for slot in date_slices|lookup:day %}
<td id="{{r.domid}}_{{day}}_{{slot.0|date:'Hi'}}" class="day_{{day}} agenda-column-{{day}}-{{slot.0|date:'Hi'}} agenda_slot agenda_slot_unavailable" capacity="{{r.capacity}}" ></td>
<td id="{{r.dom_id}}_{{day}}_{{slot.0|date:'Hi'}}" class="day_{{day}} agenda-column-{{day}}-{{slot.0|date:'Hi'}} agenda_slot agenda_slot_unavailable" capacity="{{r.capacity}}" ></td>
{% endfor %}
<td class="day_{{day}} spacer {{day|date:'Y-m-d'}}-spacer"></td>
{% endfor %}

View file

@ -141,7 +141,7 @@ promiselist.push(ts_promise);
</th>
{% for day in time_slices %}
{% for slot in date_slices|lookup:day %}
<td slot_time="{{day}} {{slot.0|date:'H:i:s'}}" slot_duration="{{slot.2}}" slot_room="{{r.pk}}" id="{{r.domid}}_{{day}}_{{slot.0|date:'Hi'}}" class="day_{{day}} agenda-column-{{day}}-{{slot.0|date:'Hi'}} agenda_slot {% cycle 'agenda_slot_alt' '' %} agenda_slot_unavailable" ></td>
<td slot_time="{{day}} {{slot.0|date:'H:i:s'}}" slot_duration="{{slot.2}}" slot_room="{{r.pk}}" id="{{r.dom_id}}_{{day}}_{{slot.0|date:'Hi'}}" class="day_{{day}} agenda-column-{{day}}-{{slot.0|date:'Hi'}} agenda_slot {% cycle 'agenda_slot_alt' '' %} agenda_slot_unavailable" ></td>
{% endfor %}
<td class="day_{{day}} spacer {{day|date:'Y-m-d'}}-spacer"></td>
{% endfor %}

View file

@ -701,6 +701,10 @@ table.actual_conflic3 {
background-repeat: no-repeat;
}
td.ourconflicts, td.theirconflicts {
white-space:nowrap;
}
/* ::-webkit-scrollbar{ */
/* width:3px; */
/* } */

View file

@ -1123,7 +1123,9 @@ Session.prototype.event_template = function() {
if(this.responsible_ad != undefined) {
area_mark = this.responsible_ad.area_mark;
if(area_mark == undefined) {
area_mark = "ad:" + this.responsible_ad.href;
// This doesn't seem to do the right thing
// area_mark = "ad:" + this.responsible_ad.href;
area_mark = "";
}
}