Skip to content

Commit f9b3e2e

Browse files
committed
Merged in ^/branch/iola/meeting-improvement-r18382@18466. This provides a beta-level snapshot of the new schedule editor work. All known issues should be fixed, but there might be adjustments needed after experience with using the new edit view.
- Legacy-Id: 18467
2 parents 6927f16 + 72665a3 commit f9b3e2e

51 files changed

Lines changed: 2313 additions & 419 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ietf/bin/create-break-sessions

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ for meeting in Meeting.objects.filter(type="ietf").order_by("date"):
3333
for schedule in meeting.schedule_set.all():
3434
print " Checking for missing Break and Reg sessions in %s" % schedule
3535
for timeslot in meeting.timeslot_set.all():
36-
if timeslot.type_id == 'break':
37-
assignment, created = ScheduleTimeslotSSessionAssignment.objects.get_or_create(timeslot=timeslot, session=brk, schedule=schedule)
36+
if timeslot.type_id == 'break' and not (schedule.base and SchedTimeSessAssignment.objects.filter(timeslot=timeslot, session=brk, schedule=schedule.base).exists()):
37+
assignment, created = SchedTimeSessAssignment.objects.get_or_create(timeslot=timeslot, session=brk, schedule=schedule)
3838
if created:
3939
print " Added %s break assignment" % timeslot
40-
if timeslot.type_id == 'reg':
41-
assignment, created = ScheduleTimeslotSSessionAssignment.objects.get_or_create(timeslot=timeslot, session=reg, schedule=schedule)
40+
if timeslot.type_id == 'reg' and not (schedule.base and SchedTimeSessAssignment.objects.filter(timeslot=timeslot, session=reg, schedule=schedule.base).exists()):
41+
assignment, created = SchedTimeSessAssignment.objects.get_or_create(timeslot=timeslot, session=reg, schedule=schedule)
4242
if created:
4343
print " Added %s registration assignment" % timeslot

ietf/meeting/admin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ class SchedulingEventAdmin(admin.ModelAdmin):
138138

139139
class ScheduleAdmin(admin.ModelAdmin):
140140
list_display = ["name", "meeting", "owner", "visible", "public", "badness"]
141-
list_filter = ["meeting", ]
142-
raw_id_fields = ["meeting", "owner", ]
141+
list_filter = ["meeting"]
142+
raw_id_fields = ["meeting", "owner", "origin", "base"]
143143
search_fields = ["meeting__number", "name", "owner__name"]
144144
ordering = ["-meeting", "name"]
145145

ietf/meeting/helpers.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,6 @@ def get_schedule(meeting, name=None):
151151
schedule = get_object_or_404(meeting.schedule_set, name=name)
152152
return schedule
153153

154-
def get_schedule_by_id(meeting, schedid):
155-
if schedid is None:
156-
schedule = meeting.schedule
157-
else:
158-
schedule = get_object_or_404(meeting.schedule_set, id=int(schedid))
159-
return schedule
160-
161154
# seems this belongs in ietf/person/utils.py?
162155
def get_person_by_email(email):
163156
# email == None may actually match people who haven't set an email!
@@ -229,10 +222,15 @@ def preprocess_assignments_for_agenda(assignments_queryset, meeting, extra_prefe
229222
parents = Group.objects.filter(pk__in=parent_id_set)
230223
parent_replacements = find_history_replacements_active_at(parents, meeting_time)
231224

225+
timeslot_by_session_pk = {a.session_id: a.timeslot for a in assignments}
226+
232227
for a in assignments:
233228
if a.session and a.session.historic_group and a.session.historic_group.parent_id:
234229
a.session.historic_group.historic_parent = parent_replacements.get(a.session.historic_group.parent_id)
235230

231+
if a.session.current_status == 'resched':
232+
a.session.rescheduled_to = timeslot_by_session_pk.get(a.session.tombstone_for_id)
233+
236234
for d in a.session.prefetched_active_materials:
237235
# make sure these are precomputed with the meeting instead
238236
# of having to look it up
@@ -440,6 +438,11 @@ def get_announcement_initial(meeting, is_change=False):
440438
type = group.type.slug.upper()
441439
if group.type.slug == 'wg' and group.state.slug == 'bof':
442440
type = 'BOF'
441+
442+
assignments = SchedTimeSessAssignment.objects.filter(
443+
schedule__in=[meeting.schedule, meeting.schedule.base if meeting.schedule else None]
444+
).order_by('timeslot__time')
445+
443446
initial['subject'] = '{name} ({acronym}) {type} {desc} Meeting: {date}{change}'.format(
444447
name=group.name,
445448
acronym=group.acronym,

ietf/meeting/management/commands/create_dummy_meeting.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,11 @@ def handle(self, *args, **options):
8585
date=datetime.date(2019, 11, 16),
8686
days=7,
8787
)
88-
schedule = Schedule.objects.create(meeting=m, name='Empty-Schedule', owner_id=1,
89-
visible=True, public=True)
88+
base_schedule = Schedule.objects.create(meeting=m, name='base', owner_id=1,
89+
visible=True, public=True)
90+
91+
schedule = Schedule.objects.create(meeting=m, name='first1', owner_id=1,
92+
visible=True, public=True, base=base_schedule)
9093
m.schedule = schedule
9194
m.save()
9295

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright The IETF Trust 2020, All Rights Reserved
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('meeting', '0032_auto_20200824_1642'),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name='session',
16+
name='tombstone_for',
17+
field=models.ForeignKey(blank=True, help_text='This session is the tombstone for a session that was rescheduled', null=True, on_delete=django.db.models.deletion.CASCADE, to='meeting.Session'),
18+
),
19+
]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Generated by Django 2.0.13 on 2020-07-01 02:45
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('meeting', '0033_session_tombstone_for'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='schedule',
15+
name='notes',
16+
field=models.TextField(blank=True),
17+
),
18+
migrations.AlterField(
19+
model_name='schedule',
20+
name='public',
21+
field=models.BooleanField(default=True, help_text='Allow others to see this agenda.'),
22+
),
23+
migrations.AlterField(
24+
model_name='schedule',
25+
name='visible',
26+
field=models.BooleanField(default=True, help_text='Show in the list of possible agendas for the meeting.', verbose_name='Show in agenda list'),
27+
),
28+
]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Generated by Django 2.0.13 on 2020-08-04 06:22
2+
3+
from django.db import migrations
4+
import django.db.models.deletion
5+
import ietf.utils.models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('meeting', '0034_schedule_notes'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='schedule',
17+
name='origin',
18+
field=ietf.utils.models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='meeting.Schedule'),
19+
),
20+
]
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Generated by Django 2.0.13 on 2020-08-07 09:30
2+
3+
from django.db import migrations
4+
import django.db.models.deletion
5+
import ietf.utils.models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('meeting', '0035_add_session_origin'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='schedule',
17+
name='base',
18+
field=ietf.utils.models.ForeignKey(blank=True, help_text='Sessions scheduled in the base show up in this schedule.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='derivedschedule_set', to='meeting.Schedule'),
19+
),
20+
migrations.AlterField(
21+
model_name='schedule',
22+
name='origin',
23+
field=ietf.utils.models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='meeting.Schedule'),
24+
),
25+
]

ietf/meeting/models.py

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,9 @@ def updated(self):
298298
min_time = datetime.datetime(1970, 1, 1, 0, 0, 0) # should be Meeting.modified, but we don't have that
299299
timeslots_updated = self.timeslot_set.aggregate(Max('modified'))["modified__max"] or min_time
300300
sessions_updated = self.session_set.aggregate(Max('modified'))["modified__max"] or min_time
301-
assignments_updated = (self.schedule.assignments.aggregate(Max('modified'))["modified__max"] or min_time) if self.schedule else min_time
301+
assignments_updated = min_time
302+
if self.schedule:
303+
assignments_updated = SchedTimeSessAssignment.objects.filter(schedule__in=[self.schedule, self.schedule.base if self.schedule else None]).aggregate(Max('modified'))["modified__max"] or min_time
302304
ts = max(timeslots_updated, sessions_updated, assignments_updated)
303305
tz = pytz.timezone(settings.PRODUCTION_TIMEZONE)
304306
ts = tz.localize(ts)
@@ -457,7 +459,7 @@ class TimeSlot(models.Model):
457459
@property
458460
def session(self):
459461
if not hasattr(self, "_session_cache"):
460-
self._session_cache = self.sessions.filter(timeslotassignments__schedule=self.meeting.schedule).first()
462+
self._session_cache = self.sessions.filter(timeslotassignments__schedule__in=[self.meeting.schedule, self.meeting.schedule.base if self.meeting else None]).first()
461463
return self._session_cache
462464

463465
@property
@@ -637,10 +639,14 @@ class Schedule(models.Model):
637639
meeting = ForeignKey(Meeting, null=True, related_name='schedule_set')
638640
name = models.CharField(max_length=16, blank=False, help_text="Letters, numbers and -:_ allowed.", validators=[RegexValidator(r'^[A-Za-z0-9-:_]*$')])
639641
owner = ForeignKey(Person)
640-
visible = models.BooleanField(default=True, help_text="Make this agenda available to those who know about it.")
641-
public = models.BooleanField(default=True, help_text="Make this agenda publically available.")
642+
visible = models.BooleanField("Show in agenda list", default=True, help_text="Show in the list of possible agendas for the meeting.")
643+
public = models.BooleanField(default=True, help_text="Allow others to see this agenda.")
642644
badness = models.IntegerField(null=True, blank=True)
643-
# considering copiedFrom = ForeignKey('Schedule', blank=True, null=True)
645+
notes = models.TextField(blank=True)
646+
origin = ForeignKey('Schedule', blank=True, null=True, on_delete=models.SET_NULL, related_name="+")
647+
base = ForeignKey('Schedule', blank=True, null=True, on_delete=models.SET_NULL,
648+
help_text="Sessions scheduled in the base schedule show up in this schedule too.", related_name="derivedschedule_set",
649+
limit_choices_to={'base': None}) # prevent the inheritance from being more than one layer deep (no recursion)
644650

645651
def __str__(self):
646652
return u"%s:%s(%s)" % (self.meeting, self.name, self.owner)
@@ -667,20 +673,6 @@ def owner_email(self):
667673
else:
668674
return "noemail"
669675

670-
@property
671-
def visible_token(self):
672-
if self.visible:
673-
return "visible"
674-
else:
675-
return "hidden"
676-
677-
@property
678-
def public_token(self):
679-
if self.public:
680-
return "public"
681-
else:
682-
return "private"
683-
684676
@property
685677
def is_official(self):
686678
return (self.meeting.schedule == self)
@@ -952,6 +944,8 @@ class Session(models.Model):
952944
modified = models.DateTimeField(auto_now=True)
953945
remote_instructions = models.CharField(blank=True,max_length=1024)
954946

947+
tombstone_for = models.ForeignKey('Session', blank=True, null=True, help_text="This session is the tombstone for a session that was rescheduled", on_delete=models.CASCADE)
948+
955949
materials = models.ManyToManyField(Document, through=SessionPresentation, blank=True)
956950
resources = models.ManyToManyField(ResourceAssociation, blank=True)
957951

@@ -1093,7 +1087,7 @@ def __str__(self):
10931087
ss0name = "(%s)" % SessionStatusName.objects.get(slug=status_id).name
10941088
else:
10951089
ss0name = "(unscheduled)"
1096-
ss = self.timeslotassignments.filter(schedule=self.meeting.schedule).order_by('timeslot__time')
1090+
ss = self.timeslotassignments.filter(schedule__in=[self.meeting.schedule, self.meeting.schedule.base if self.meeting.schedule else None]).order_by('timeslot__time')
10971091
if ss:
10981092
ss0name = ','.join(x.timeslot.time.strftime("%a-%H%M") for x in ss)
10991093
return "%s: %s %s %s" % (self.meeting, self.group.acronym, self.name, ss0name)
@@ -1126,11 +1120,8 @@ def constraints(self):
11261120
def reverse_constraints(self):
11271121
return Constraint.objects.filter(target=self.group, meeting=self.meeting).order_by('name__name')
11281122

1129-
def timeslotassignment_for_schedule(self, schedule):
1130-
return self.timeslotassignments.filter(schedule=schedule).first()
1131-
11321123
def official_timeslotassignment(self):
1133-
return self.timeslotassignment_for_schedule(self.meeting.schedule)
1124+
return self.timeslotassignments.filter(schedule__in=[self.meeting.schedule, self.meeting.schedule.base if self.meeting.schedule else None]).first()
11341125

11351126
def constraints_dict(self, host_scheme):
11361127
constraint_list = []

ietf/meeting/test_data.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@ def make_meeting_test_data(meeting=None, create_interims=False):
7878

7979
if not meeting:
8080
meeting = Meeting.objects.get(number="72", type="ietf")
81-
schedule = Schedule.objects.create(meeting=meeting, owner=plainman, name="test-schedule", visible=True, public=True)
82-
unofficial_schedule = Schedule.objects.create(meeting=meeting, owner=plainman, name="test-unofficial-schedule", visible=True, public=True)
81+
base_schedule = Schedule.objects.create(meeting=meeting, owner=plainman, name="base", visible=True, public=True)
82+
schedule = Schedule.objects.create(meeting=meeting, owner=plainman, name="test-schedule", visible=True, public=True, base=base_schedule)
83+
unofficial_schedule = Schedule.objects.create(meeting=meeting, owner=plainman, name="test-unofficial-schedule", visible=True, public=True, base=base_schedule)
8384

8485
# test room
8586
pname = RoomResourceName.objects.create(name='projector',slug='proj')
@@ -148,15 +149,15 @@ def make_meeting_test_data(meeting=None, create_interims=False):
148149
requested_duration=datetime.timedelta(minutes=480),
149150
type_id="reg")
150151
SchedulingEvent.objects.create(session=reg_session, status_id='schedw', by=system_person)
151-
SchedTimeSessAssignment.objects.create(timeslot=reg_slot, session=reg_session, schedule=schedule)
152+
SchedTimeSessAssignment.objects.create(timeslot=reg_slot, session=reg_session, schedule=base_schedule)
152153

153154
# Break
154155
break_session = Session.objects.create(meeting=meeting, group=Group.objects.get(acronym="secretariat"),
155156
name="Morning Break", attendees=250,
156157
requested_duration=datetime.timedelta(minutes=30),
157158
type_id="break")
158159
SchedulingEvent.objects.create(session=break_session, status_id='schedw', by=system_person)
159-
SchedTimeSessAssignment.objects.create(timeslot=break_slot, session=break_session, schedule=schedule)
160+
SchedTimeSessAssignment.objects.create(timeslot=break_slot, session=break_session, schedule=base_schedule)
160161

161162
meeting.schedule = schedule
162163
meeting.save()

0 commit comments

Comments
 (0)