Skip to content

Commit e5943f8

Browse files
committed
Add support for displaying constraint hints when scheduling a task and
for displaying violated constraints in the new schedule editor, with the old of a new field, ConstraintName.editor_label. Add support for displaying room capacity violations. Add support for selecting a session and displaying information about it similar to the existing scheduling editor. Add support for sorting unassigned sessions. Clean up markup and styles a bit, and fix some bugs. Expand HTML-based test and add JS test that exercises the Javascript-based functionality. Switch to using Chrome driver instead of PhantomJS since the HTML engine in PhantomJS is apparently too old to support the constructs in the new schema editor. Add a workaround for LiveServerTestCase clashing with IetfTestRunner fixture loading. - Legacy-Id: 17519
1 parent 5faccf5 commit e5943f8

14 files changed

Lines changed: 902 additions & 250 deletions

docker/Dockerfile

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ RUN apt-get install -qy \
5454
build-essential \
5555
bzip2 \
5656
ca-certificates \
57+
chromium-driver \
5758
colordiff \
5859
gawk \
5960
gcc \
@@ -139,15 +140,6 @@ RUN wget -q https://bootstrap.pypa.io/get-pip.py && python get-pip.py && rm get-
139140
RUN pip install certifi
140141
RUN pip install virtualenv
141142

142-
# Phantomjs
143-
WORKDIR /usr/local
144-
145-
RUN wget -qN https://tools.ietf.org/tar/phantomjs-1.9.8-linux-x86_64.tar.bz2
146-
RUN tar xjf phantomjs-1.9.8-linux-x86_64.tar.bz2
147-
148-
WORKDIR /usr/local/bin
149-
RUN ln -s /usr/local/phantomjs-1.9.8-linux-x86_64/bin/phantomjs .
150-
151143
# idnits and dependencies
152144
ADD https://tools.ietf.org/tools/idnits/idnits /usr/local/bin/
153145
RUN chmod +rx /usr/local/bin/idnits

ietf/meeting/test_data.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright The IETF Trust 2013-2019, All Rights Reserved
1+
# Copyright The IETF Trust 2013-2020, All Rights Reserved
22
# -*- coding: utf-8 -*-
33

44

@@ -101,11 +101,11 @@ def make_meeting_test_data(meeting=None):
101101
# slots
102102
session_date = meeting.date + datetime.timedelta(days=1)
103103
slot1 = TimeSlot.objects.create(meeting=meeting, type_id='regular', location=room,
104-
duration=datetime.timedelta(minutes=30),
104+
duration=datetime.timedelta(minutes=60),
105105
time=datetime.datetime.combine(session_date, datetime.time(9, 30)))
106106
slot2 = TimeSlot.objects.create(meeting=meeting, type_id='regular', location=room,
107-
duration=datetime.timedelta(minutes=30),
108-
time=datetime.datetime.combine(session_date, datetime.time(10, 30)))
107+
duration=datetime.timedelta(minutes=60),
108+
time=datetime.datetime.combine(session_date, datetime.time(10, 50)))
109109
breakfast_slot = TimeSlot.objects.create(meeting=meeting, type_id="lead", location=breakfast_room,
110110
duration=datetime.timedelta(minutes=90),
111111
time=datetime.datetime.combine(session_date, datetime.time(7,0)))
@@ -118,7 +118,7 @@ def make_meeting_test_data(meeting=None):
118118
# mars WG
119119
mars = Group.objects.get(acronym='mars')
120120
mars_session = Session.objects.create(meeting=meeting, group=mars,
121-
attendees=10, requested_duration=datetime.timedelta(minutes=20),
121+
attendees=10, requested_duration=datetime.timedelta(minutes=50),
122122
type_id='regular')
123123
SchedulingEvent.objects.create(session=mars_session, status_id='schedw', by=system_person)
124124
SchedTimeSessAssignment.objects.create(timeslot=slot1, session=mars_session, schedule=schedule)
@@ -127,7 +127,7 @@ def make_meeting_test_data(meeting=None):
127127
# ames WG
128128
ames_session = Session.objects.create(meeting=meeting, group=Group.objects.get(acronym="ames"),
129129
attendees=10,
130-
requested_duration=datetime.timedelta(minutes=20),
130+
requested_duration=datetime.timedelta(minutes=60),
131131
type_id='regular')
132132
SchedulingEvent.objects.create(session=ames_session, status_id='schedw', by=system_person)
133133
SchedTimeSessAssignment.objects.create(timeslot=slot2, session=ames_session, schedule=schedule)
@@ -136,7 +136,7 @@ def make_meeting_test_data(meeting=None):
136136
# IESG breakfast
137137
iesg_session = Session.objects.create(meeting=meeting, group=Group.objects.get(acronym="iesg"),
138138
name="IESG Breakfast", attendees=25,
139-
requested_duration=datetime.timedelta(minutes=20),
139+
requested_duration=datetime.timedelta(minutes=60),
140140
type_id="lead")
141141
SchedulingEvent.objects.create(session=iesg_session, status_id='schedw', by=system_person)
142142
SchedTimeSessAssignment.objects.create(timeslot=breakfast_slot, session=iesg_session, schedule=schedule)

ietf/meeting/tests_js.py

Lines changed: 189 additions & 50 deletions
Large diffs are not rendered by default.

ietf/meeting/tests_views.py

Lines changed: 76 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from ietf.meeting.helpers import send_interim_approval_request
3535
from ietf.meeting.helpers import send_interim_cancellation_notice
3636
from ietf.meeting.helpers import send_interim_minutes_reminder, populate_important_dates, update_important_dates
37-
from ietf.meeting.models import Session, TimeSlot, Meeting, SchedTimeSessAssignment, Schedule, SessionPresentation, SlideSubmission, SchedulingEvent, Room
37+
from ietf.meeting.models import Session, TimeSlot, Meeting, SchedTimeSessAssignment, Schedule, SessionPresentation, SlideSubmission, SchedulingEvent, Room, Constraint, ConstraintName
3838
from ietf.meeting.test_data import make_meeting_test_data, make_interim_meeting
3939
from ietf.meeting.utils import finalize, condition_slide_order
4040
from ietf.meeting.utils import add_event_info_to_session_qs
@@ -921,29 +921,86 @@ def test_edit_meeting_schedule(self):
921921

922922
self.client.login(username="secretary", password="secretary+password")
923923

924-
# check we have the grid and everything set up
924+
s1 = Session.objects.filter(meeting=meeting, type='regular').first()
925+
s2 = Session.objects.filter(meeting=meeting, type='regular').exclude(group=s1.group).first()
926+
s1.comments = "Hello world!"
927+
s1.attendees = 1234
928+
s1.save()
929+
930+
Constraint.objects.create(
931+
meeting=meeting,
932+
source=s1.group,
933+
target=s2.group,
934+
name=ConstraintName.objects.get(slug="conflict"),
935+
)
936+
937+
p = Person.objects.all().first()
938+
939+
Constraint.objects.create(
940+
meeting=meeting,
941+
source=s1.group,
942+
person=p,
943+
name=ConstraintName.objects.get(slug="bethere"),
944+
)
945+
946+
Constraint.objects.create(
947+
meeting=meeting,
948+
source=s2.group,
949+
person=p,
950+
name=ConstraintName.objects.get(slug="bethere"),
951+
)
952+
953+
# check we have the grid and everything set up as a baseline -
954+
# the Javascript tests check that the Javascript can work with
955+
# it
925956
url = urlreverse("ietf.meeting.views.edit_meeting_schedule", kwargs=dict(num=meeting.number))
926957
r = self.client.get(url)
927958
q = PyQuery(r.content)
928959

929960
room = Room.objects.get(meeting=meeting, session_types='regular')
930-
self.assertTrue(q("h5:contains(\"{}\")".format(room.name)))
931-
self.assertTrue(q("h5:contains(\"{}\")".format(room.capacity)))
961+
self.assertTrue(q(".room-name:contains(\"{}\")".format(room.name)))
962+
self.assertTrue(q(".room-name:contains(\"{}\")".format(room.capacity)))
932963

933964
timeslots = TimeSlot.objects.filter(meeting=meeting, type='regular')
934-
self.assertTrue(q("div.timeslot[data-timeslot=\"{}\"]".format(timeslots[0].pk)))
965+
self.assertTrue(q("#timeslot{}".format(timeslots[0].pk)))
935966

936-
sessions = Session.objects.filter(meeting=meeting, type='regular')
937-
for s in sessions:
938-
self.assertIn(s.group.acronym, q("#session{}".format(s.pk)).text())
967+
for s in [s1, s2]:
968+
e = q("#session{}".format(s.pk))
939969

940-
self.assertIn("You can't edit this schedule", r.content)
970+
# info in the movable entity
971+
self.assertIn(s.group.acronym, e.find(".session-label").text())
972+
if s.comments:
973+
self.assertTrue(e.find(".comments"))
974+
if s.attendees is not None:
975+
self.assertIn(str(s.attendees), e.find(".attendees").text())
976+
self.assertTrue(e.hasClass("parent-{}".format(s.group.parent.acronym)))
977+
978+
# session info for the panel
979+
self.assertIn(str(s.requested_duration.total_seconds() / 60.0 / 60), e.find(".session-info label").text())
980+
981+
event = SchedulingEvent.objects.filter(session=s).order_by("id").first()
982+
if event:
983+
self.assertTrue(e.find("div:contains(\"{}\")".format(event.by.plain_name())))
984+
985+
if s.comments:
986+
self.assertIn(s.comments, e.find(".comments").text())
987+
988+
# constraints
989+
constraints = e.find(".constraints > span")
990+
s_other = s2 if s == s1 else s1
991+
self.assertEqual(len(constraints), 2)
992+
self.assertEqual(constraints.eq(0).attr("data-sessions"), str(s_other.pk))
993+
self.assertEqual(constraints.eq(1).attr("data-sessions"), str(s_other.pk))
994+
self.assertEqual(constraints.find(".encircled").text(), "1")
995+
self.assertEqual(constraints.find(".fa-user-o").parent().text(), "1") # 1 person in the constraint
996+
997+
self.assertTrue(q("em:contains(\"You can't edit this schedule\")"))
941998

942999
# can't change anything
9431000
r = self.client.post(url, {
9441001
'action': 'assign',
9451002
'timeslot': timeslots[0].pk,
946-
'session': sessions[0].pk,
1003+
'session': s1.pk,
9471004
})
9481005
self.assertEqual(r.status_code, 403)
9491006

@@ -953,35 +1010,36 @@ def test_edit_meeting_schedule(self):
9531010

9541011
url = urlreverse("ietf.meeting.views.edit_meeting_schedule", kwargs=dict(num=meeting.number, owner=meeting.schedule.owner_email(), name=meeting.schedule.name))
9551012
r = self.client.get(url)
956-
self.assertNotIn("You can't edit this schedule", r.content)
1013+
q = PyQuery(r.content)
1014+
self.assertTrue(not q("em:contains(\"You can't edit this schedule\")"))
9571015

958-
SchedTimeSessAssignment.objects.filter(session=sessions[0]).delete()
1016+
SchedTimeSessAssignment.objects.filter(session=s1).delete()
9591017

9601018
# assign
9611019
r = self.client.post(url, {
9621020
'action': 'assign',
9631021
'timeslot': timeslots[0].pk,
964-
'session': sessions[0].pk,
1022+
'session': s1.pk,
9651023
})
9661024
self.assertEqual(r.content, "OK")
967-
self.assertEqual(SchedTimeSessAssignment.objects.get(schedule=meeting.schedule, session=sessions[0]).timeslot, timeslots[0])
1025+
self.assertEqual(SchedTimeSessAssignment.objects.get(schedule=meeting.schedule, session=s1).timeslot, timeslots[0])
9681026

9691027
# move assignment
9701028
r = self.client.post(url, {
9711029
'action': 'assign',
9721030
'timeslot': timeslots[1].pk,
973-
'session': sessions[0].pk,
1031+
'session': s1.pk,
9741032
})
9751033
self.assertEqual(r.content, "OK")
976-
self.assertEqual(SchedTimeSessAssignment.objects.get(schedule=meeting.schedule, session=sessions[0]).timeslot, timeslots[1])
1034+
self.assertEqual(SchedTimeSessAssignment.objects.get(schedule=meeting.schedule, session=s1).timeslot, timeslots[1])
9771035

9781036
# unassign
9791037
r = self.client.post(url, {
9801038
'action': 'unassign',
981-
'session': sessions[0].pk,
1039+
'session': s1.pk,
9821040
})
9831041
self.assertEqual(r.content, "OK")
984-
self.assertEqual(list(SchedTimeSessAssignment.objects.filter(schedule=meeting.schedule, session=sessions[0])), [])
1042+
self.assertEqual(list(SchedTimeSessAssignment.objects.filter(schedule=meeting.schedule, session=s1)), [])
9851043

9861044

9871045
def test_copy_meeting_schedule(self):

0 commit comments

Comments
 (0)