Skip to content

Commit a39fa7f

Browse files
committed
New branch from trunk @ r18382 for meeting improvements, with iola/meeting-improvement-r17835 merged in
- Legacy-Id: 18385
2 parents bc75565 + 5ea3051 commit a39fa7f

Some content is hidden

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

44 files changed

+2201
-407
lines changed

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: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from tempfile import mkstemp
1010

1111
from django.http import HttpRequest, Http404
12-
from django.db.models import Max, Q, Prefetch
12+
from django.db.models import F, Max, Q, Prefetch
1313
from django.conf import settings
1414
from django.core.cache import cache
1515
from django.urls import reverse
@@ -150,13 +150,6 @@ def get_schedule(meeting, name=None):
150150
schedule = get_object_or_404(meeting.schedule_set, name=name)
151151
return schedule
152152

153-
def get_schedule_by_id(meeting, schedid):
154-
if schedid is None:
155-
schedule = meeting.schedule
156-
else:
157-
schedule = get_object_or_404(meeting.schedule_set, id=int(schedid))
158-
return schedule
159-
160153
# seems this belongs in ietf/person/utils.py?
161154
def get_person_by_email(email):
162155
# email == None may actually match people who haven't set an email!
@@ -171,13 +164,17 @@ def get_schedule_by_name(meeting, owner, name):
171164
return meeting.schedule_set.filter(name = name).first()
172165

173166
def preprocess_assignments_for_agenda(assignments_queryset, meeting, extra_prefetches=()):
174-
assignments_queryset = assignments_queryset.select_related(
175-
"timeslot", "timeslot__location", "timeslot__type",
176-
).prefetch_related(
167+
assignments_queryset = assignments_queryset.prefetch_related(
168+
'timeslot', 'timeslot__type', 'timeslot__meeting',
169+
'timeslot__location', 'timeslot__location__floorplan', 'timeslot__location__urlresource_set',
177170
Prefetch(
178171
"session",
179172
queryset=add_event_info_to_session_qs(Session.objects.all().prefetch_related(
180173
'group', 'group__charter', 'group__charter__group',
174+
Prefetch('materials',
175+
queryset=Document.objects.exclude(states__type=F("type"), states__slug='deleted').order_by('sessionpresentation__order').prefetch_related('states'),
176+
to_attr='prefetched_active_materials'
177+
)
181178
))
182179
),
183180
*extra_prefetches
@@ -218,10 +215,21 @@ def preprocess_assignments_for_agenda(assignments_queryset, meeting, extra_prefe
218215
parents = Group.objects.filter(pk__in=parent_id_set)
219216
parent_replacements = find_history_replacements_active_at(parents, meeting_time)
220217

218+
timeslot_by_session_pk = {a.session_id: a.timeslot for a in assignments}
219+
221220
for a in assignments:
222221
if a.session and a.session.historic_group and a.session.historic_group.parent_id:
223222
a.session.historic_group.historic_parent = parent_replacements.get(a.session.historic_group.parent_id)
224223

224+
if a.session.current_status == 'resched':
225+
a.session.rescheduled_to = timeslot_by_session_pk.get(a.session.tombstone_for_id)
226+
227+
for d in a.session.prefetched_active_materials:
228+
# make sure these are precomputed with the meeting instead
229+
# of having to look it up
230+
d.get_href(meeting=meeting)
231+
d.get_versionless_href(meeting=meeting)
232+
225233
return assignments
226234

227235
def read_session_file(type, num, doc):
@@ -423,6 +431,11 @@ def get_announcement_initial(meeting, is_change=False):
423431
type = group.type.slug.upper()
424432
if group.type.slug == 'wg' and group.state.slug == 'bof':
425433
type = 'BOF'
434+
435+
assignments = SchedTimeSessAssignment.objects.filter(
436+
schedule__in=[meeting.schedule, meeting.schedule.base if meeting.schedule else None]
437+
).order_by('timeslot__time')
438+
426439
initial['subject'] = '{name} ({acronym}) {type} {desc} Meeting: {date}{change}'.format(
427440
name=group.name,
428441
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', '0030_allow_empty_joint_with_sessions'),
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', '0031_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', '0032_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', '0033_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: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,9 @@ def updated(self):
297297
min_time = datetime.datetime(1970, 1, 1, 0, 0, 0) # should be Meeting.modified, but we don't have that
298298
timeslots_updated = self.timeslot_set.aggregate(Max('modified'))["modified__max"] or min_time
299299
sessions_updated = self.session_set.aggregate(Max('modified'))["modified__max"] or min_time
300-
assignments_updated = (self.schedule.assignments.aggregate(Max('modified'))["modified__max"] or min_time) if self.schedule else min_time
300+
assignments_updated = min_time
301+
if self.schedule:
302+
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
301303
ts = max(timeslots_updated, sessions_updated, assignments_updated)
302304
tz = pytz.timezone(settings.PRODUCTION_TIMEZONE)
303305
ts = tz.localize(ts)
@@ -397,14 +399,14 @@ def functional_display_name(self):
397399
return self.functional_name
398400
# audio stream support
399401
def audio_stream_url(self):
400-
urlresource = self.urlresource_set.filter(name_id='audiostream').first()
401-
return urlresource.url if urlresource else None
402+
urlresources = [ur for ur in self.urlresource_set.all() if ur.name_id == 'audiostream']
403+
return urlresources[0].url if urlresources else None
402404
def video_stream_url(self):
403-
urlresource = self.urlresource_set.filter(name_id__in=['meetecho', ]).first()
404-
return urlresource.url if urlresource else None
405+
urlresources = [ur for ur in self.urlresource_set.all() if ur.name_id in ['meetecho']]
406+
return urlresources[0].url if urlresources else None
405407
def webex_url(self):
406-
urlresource = self.urlresource_set.filter(name_id__in=['webex', ]).first()
407-
return urlresource.url if urlresource else None
408+
urlresources = [ur for ur in self.urlresource_set.all() if ur.name_id in ['webex']]
409+
return urlresources[0].url if urlresources else None
408410
#
409411
class Meta:
410412
ordering = ["-id"]
@@ -456,7 +458,7 @@ class TimeSlot(models.Model):
456458
@property
457459
def session(self):
458460
if not hasattr(self, "_session_cache"):
459-
self._session_cache = self.sessions.filter(timeslotassignments__schedule=self.meeting.schedule).first()
461+
self._session_cache = self.sessions.filter(timeslotassignments__schedule__in=[self.meeting.schedule, self.meeting.schedule.base if self.meeting else None]).first()
460462
return self._session_cache
461463

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

636642
def __str__(self):
637643
return u"%s:%s(%s)" % (self.meeting, self.name, self.owner)
@@ -658,20 +664,6 @@ def owner_email(self):
658664
else:
659665
return "noemail"
660666

661-
@property
662-
def visible_token(self):
663-
if self.visible:
664-
return "visible"
665-
else:
666-
return "hidden"
667-
668-
@property
669-
def public_token(self):
670-
if self.public:
671-
return "public"
672-
else:
673-
return "private"
674-
675667
@property
676668
def is_official(self):
677669
return (self.meeting.schedule == self)
@@ -943,6 +935,8 @@ class Session(models.Model):
943935
modified = models.DateTimeField(auto_now=True)
944936
remote_instructions = models.CharField(blank=True,max_length=1024)
945937

938+
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)
939+
946940
materials = models.ManyToManyField(Document, through=SessionPresentation, blank=True)
947941
resources = models.ManyToManyField(ResourceAssociation, blank=True)
948942

@@ -1084,7 +1078,7 @@ def __str__(self):
10841078
ss0name = "(%s)" % SessionStatusName.objects.get(slug=status_id).name
10851079
else:
10861080
ss0name = "(unscheduled)"
1087-
ss = self.timeslotassignments.filter(schedule=self.meeting.schedule).order_by('timeslot__time')
1081+
ss = self.timeslotassignments.filter(schedule__in=[self.meeting.schedule, self.meeting.schedule.base if self.meeting.schedule else None]).order_by('timeslot__time')
10881082
if ss:
10891083
ss0name = ','.join(x.timeslot.time.strftime("%a-%H%M") for x in ss)
10901084
return "%s: %s %s %s" % (self.meeting, self.group.acronym, self.name, ss0name)
@@ -1117,11 +1111,8 @@ def constraints(self):
11171111
def reverse_constraints(self):
11181112
return Constraint.objects.filter(target=self.group, meeting=self.meeting).order_by('name__name')
11191113

1120-
def timeslotassignment_for_schedule(self, schedule):
1121-
return self.timeslotassignments.filter(schedule=schedule).first()
1122-
11231114
def official_timeslotassignment(self):
1124-
return self.timeslotassignment_for_schedule(self.meeting.schedule)
1115+
return self.timeslotassignments.filter(schedule__in=[self.meeting.schedule, self.meeting.schedule.base if self.meeting.schedule else None]).first()
11251116

11261117
def constraints_dict(self, host_scheme):
11271118
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)