diff --git a/ietf/idtracker/models.py b/ietf/idtracker/models.py index c91eabfd2..c546e833b 100644 --- a/ietf/idtracker/models.py +++ b/ietf/idtracker/models.py @@ -1147,9 +1147,10 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES: AcronymOld = Acronym IESGLoginOld = IESGLogin IETFWGOld = IETFWG + IRTFOld = IRTF from redesign.doc.proxy import InternetDraft, IDInternal, BallotInfo, Rfc from redesign.name.proxy import IDState, IDSubState - from redesign.group.proxy import Area, Acronym, IETFWG + from redesign.group.proxy import Area, Acronym, IETFWG, IRTF from redesign.person.proxy import IESGLogin diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py index ffc27d6ee..9636e7de6 100644 --- a/ietf/meeting/models.py +++ b/ietf/meeting/models.py @@ -1,6 +1,6 @@ # old meeting models can be found in ../proceedings/models.py -import pytz +import pytz, datetime from django.db import models from timedeltafield import TimedeltaField @@ -8,7 +8,7 @@ from timedeltafield import TimedeltaField from redesign.group.models import Group from redesign.person.models import Person from redesign.doc.models import Document -from redesign.name.models import TimeSlotTypeName, SessionStatusName, ConstraintName +from redesign.name.models import MeetingTypeName, TimeSlotTypeName, SessionStatusName, ConstraintName countries = pytz.country_names.items() countries.sort(lambda x,y: cmp(x[1], y[1])) @@ -17,9 +17,10 @@ timezones = [(name, name) for name in pytz.common_timezones] timezones.sort() class Meeting(models.Model): - # Number is not an integer any more, in order to be able to accomodate - # interim meetings (and other variations?) + # number is either the number for IETF meetings, or some other + # identifier for interim meetings/IESG retreats/liaison summits/... number = models.CharField(max_length=64) + type = models.ForeignKey(MeetingTypeName) # Date is useful when generating a set of timeslot for this meeting, but # is not used to determine date for timeslot instances thereafter, as # they have their own datetime field. @@ -37,11 +38,10 @@ class Meeting(models.Model): def __str__(self): return "IETF-%s" % (self.number) + def time_zone_offset(self): + return pytz.timezone(self.time_zone).localize(datetime.datetime.combine(self.date, datetime.time(0, 0))).strftime("%z") def get_meeting_date (self,offset): return self.date + datetime.timedelta(days=offset) - # cut-off dates (draft submission cut-of, wg agenda cut-off, minutes - # submission cut-off), and more, are probably methods of this class, - # rather than fields on a Proceedings class. @classmethod def get_first_cut_off(cls): @@ -60,6 +60,13 @@ class Meeting(models.Model): date = cls.objects.all().order_by('-date')[0].date return date + datetime.timedelta(days=-date.weekday(), weeks=1) + # the various dates are currently computed + def get_submission_start_date(self): + return self.date + datetime.timedelta(days=-90) + def get_submission_cut_off_date(self): + return self.date + datetime.timedelta(days=33) + def get_submission_correction_date(self): + return self.date + datetime.timedelta(days=59) class Room(models.Model): meeting = models.ForeignKey(Meeting) @@ -82,8 +89,10 @@ class TimeSlot(models.Model): time = models.DateTimeField() duration = TimedeltaField() location = models.ForeignKey(Room, blank=True, null=True) - show_location = models.BooleanField(default=True) + show_location = models.BooleanField(default=True, help_text="Show location in agenda") materials = models.ManyToManyField(Document, blank=True) + session = models.ForeignKey('Session', null=True, blank=True, help_text=u"Scheduled group session, if any") + modified = models.DateTimeField(default=datetime.datetime.now) def __unicode__(self): location = self.get_location() @@ -120,7 +129,6 @@ class Constraint(models.Model): class Session(models.Model): meeting = models.ForeignKey(Meeting) - timeslot = models.ForeignKey(TimeSlot, null=True, blank=True) # Null until session has been scheduled group = models.ForeignKey(Group) # The group type determines the session type. BOFs also need to be added as a group. attendees = models.IntegerField(null=True, blank=True) agenda_note = models.CharField(blank=True, max_length=255) @@ -132,16 +140,15 @@ class Session(models.Model): # status = models.ForeignKey(SessionStatusName) scheduled = models.DateTimeField(null=True, blank=True) - modified = models.DateTimeField(null=True, blank=True) + modified = models.DateTimeField(default=datetime.datetime.now) # contains the materials while the session is being requested, - # when it is scheduled, timeslot.materials should be used (FIXME: ask Henrik) + # when it is scheduled, timeslot.materials should be used materials = models.ManyToManyField(Document, blank=True) def __unicode__(self): - return u"%s: %s %s" % (self.meeting, self.group.acronym, self.timeslot.time.strftime("%H%M") if self.timeslot else "(unscheduled)") - -# Agendas, Minutes and Slides are all mapped to Document. + timeslots = self.timeslot_set.order_by('time') + return u"%s: %s %s" % (self.meeting, self.group.acronym, timeslots[0].time.strftime("%H%M") if timeslots else "(unscheduled)") # IESG history is extracted from GroupHistory, rather than hand coded in a # separate table. diff --git a/ietf/meeting/proxy.py b/ietf/meeting/proxy.py index d5d087c56..65ffc5ecd 100644 --- a/ietf/meeting/proxy.py +++ b/ietf/meeting/proxy.py @@ -39,15 +39,12 @@ class MeetingProxy(Meeting): def get_meeting_date (self,offset): return self.start_date + datetime.timedelta(days=offset) def num(self): - return self.meeting_num + return self.number @property def meeting_venue(self): return MeetingVenueProxy().from_object(self) - class Meta: - proxy = True - @classmethod def get_first_cut_off(cls): start_date = cls.objects.all().order_by('-date')[0].start_date @@ -65,6 +62,60 @@ class MeetingProxy(Meeting): start_date = cls.objects.all().order_by('-date')[0].start_date return start_date + datetime.timedelta(days=-start_date.weekday(), weeks=1) + class Meta: + proxy = True + +class ProceedingProxy(Meeting): + objects = TranslatingManager(dict(meeting_num="number")) + + #meeting_num = models.ForeignKey(Meeting, db_column='meeting_num', unique=True, primary_key=True) + @property + def meeting_num(self): + return MeetingProxy().from_object(self) + @property + def meeting_num_id(self): + return self.number + #dir_name = models.CharField(blank=True, max_length=25) + @property + def dir_name(self): + return self.number + #sub_begin_date = models.DateField(null=True, blank=True) + @property + def sub_begin_date(self): + return self.get_submission_start_date() + #sub_cut_off_date = models.DateField(null=True, blank=True) + @property + def sub_cut_off_date(self): + return self.get_submission_cut_off_date() + #frozen = models.IntegerField(null=True, blank=True) + #c_sub_cut_off_date = models.DateField(null=True, blank=True) + @property + def c_sub_cut_off_date(self): + return self.get_submission_correction_date() + #pr_from_date = models.DateField(null=True, blank=True) + #pr_to_date = models.DateField(null=True, blank=True) + def __str__(self): + return "IETF %s" % (self.meeting_num_id) + class Meta: + proxy = True + +class SwitchesProxy(Meeting): + def from_object(self, base): + for f in base._meta.fields: + setattr(self, f.name, getattr(base, f.name)) + return self + + #name = models.CharField(max_length=100) + #val = models.IntegerField(null=True, blank=True) + #updated_date = models.DateField(null=True, blank=True) + #updated_time = models.TimeField(null=True, blank=True) + def updated(self): + from django.db.models import Max + return max(self.timeslot_set.aggregate(Max('modified'))["modified__max"], + self.session_set.aggregate(Max('modified'))["modified__max"]) + class Meta: + proxy = True + class MeetingVenueProxy(Meeting): objects = TranslatingManager(dict(meeting_num="number")) @@ -191,58 +242,100 @@ class WgMeetingSessionProxy(TimeSlot): # because some previous sessions are now really time slots, to # make the illusion complete we thus have to forward all the # session stuff to the real session - objects = TranslatingManager(dict(group_acronym_id="session__group")) + objects = TranslatingManager(dict(group_acronym_id="session__group", + status__id=lambda v: ("state", {4: "sched"}[v]))) def from_object(self, base): for f in base._meta.fields: setattr(self, f.name, getattr(base, f.name)) return self - def get_session(self): - if not hasattr(self, "_session_cache"): - s = self.session_set.all() - self._session_cache = s[0] if s else None - - return self._session_cache - - #session_id = models.AutoField(primary_key=True) - @property - def session_id(self): - return self.id + #session_id = models.AutoField(primary_key=True) # same name #meeting = models.ForeignKey(Meeting, db_column='meeting_num') # same name #group_acronym_id = models.IntegerField() @property def group_acronym_id(self): - s = self.get_session() - return s.group_id if s else -1 + return self.session.group_id if self.session else -1 #irtf = models.NullBooleanField() + @property + def irtf(self): + return 1 if self.session and self.session.group and self.session.group.type == "rg" else 0 #num_session = models.IntegerField() + @property + def num_session(self): + return 1 if self.session else 0 #length_session1 = models.CharField(blank=True, max_length=100) + @property + def length_session1(self): + if not self.session: + return "0" + + secs = self.session.requested_duration.seconds + if secs == 0: + return "0" + return str((secs / 60 - 30) / 30) #length_session2 = models.CharField(blank=True, max_length=100) + @property + def length_session2(self): + return "0" #length_session3 = models.CharField(blank=True, max_length=100) + @property + def length_session3(self): + return "0" + + def conflicting_group_acronyms(self, level): + if not self.session: + return "" + + conflicts = Constraint.objects.filter(meeting=self.meeting_id, + target=self.session.group, + name=level) + return " ".join(c.source.acronym for c in conflicts) + #conflict1 = models.CharField(blank=True, max_length=255) + @property + def conflict1(self): + return self.conflicting_group_acronyms("conflict") #conflict2 = models.CharField(blank=True, max_length=255) + @property + def conflict2(self): + return self.conflicting_group_acronyms("conflic2") #conflict3 = models.CharField(blank=True, max_length=255) + @property + def conflict3(self): + return self.conflicting_group_acronyms("conflic3") #conflict_other = models.TextField(blank=True) + @property + def conflict_other(self): + return "" #special_req = models.TextField(blank=True) + @property + def special_req(self): + return self.session.comments if self.session else "" #number_attendee = models.IntegerField(null=True, blank=True) @property def number_attendee(self): - return self.get_session().attendees if self.get_session() else 0 + return self.session.attendees if self.session else 0 #approval_ad = models.IntegerField(null=True, blank=True) #status = models.ForeignKey(SessionStatus, null=True, blank=True) # same name #ts_status_id = models.IntegerField(null=True, blank=True) #requested_date = models.DateField(null=True, blank=True) + @property + def requested_date(self): + return self.session.requested.date() if self.session else None #approved_date = models.DateField(null=True, blank=True) #requested_by = BrokenForeignKey(PersonOrOrgInfo, db_column='requested_by', null=True, null_values=(0, 888888)) + @property + def requested_by(self): + return self.session.requested_by if self.session else None #scheduled_date = models.DateField(null=True, blank=True) @property def scheduled_date(self): - return self.get_session().scheduled.date() if self.get_session() else "" + return self.session.scheduled.date() if self.session else "" #last_modified_date = models.DateField(null=True, blank=True) @property def last_modified_date(self): - return self.get_session().modified.date() if self.get_session() else "" + return self.session.modified.date() if self.session else "" #ad_comments = models.TextField(blank=True,null=True) #sched_room_id1 = models.ForeignKey(MeetingRoom, db_column='sched_room_id1', null=True, blank=True, related_name='here1') #sched_time_id1 = BrokenForeignKey(MeetingTime, db_column='sched_time_id1', null=True, blank=True, related_name='now1') @@ -256,7 +349,7 @@ class WgMeetingSessionProxy(TimeSlot): #special_agenda_note = models.CharField(blank=True, max_length=255) @property def special_agenda_note(self): - return self.get_session().agenda_note if self.get_session() else "" + return self.session.agenda_note if self.session else "" #combined_room_id1 = models.ForeignKey(MeetingRoom, db_column='combined_room_id1', null=True, blank=True, related_name='here4') #combined_time_id1 = models.ForeignKey(MeetingTime, db_column='combined_time_id1', null=True, blank=True, related_name='now4') #combined_room_id2 = models.ForeignKey(MeetingRoom, db_column='combined_room_id2', null=True, blank=True, related_name='here5') @@ -285,41 +378,21 @@ class WgMeetingSessionProxy(TimeSlot): filename = docs[0].external_url return "%s/minutes/%s" % (self.meeting.number, filename) def slides(self,interimvar=0): - """ - Get all slides of this session. - """ - # FIXME - irtfvar = 0 - if self.irtf: - irtfvar = self.group_acronym_id - if interimvar == 0: - try: - if self.interim: - interimvar = 1 - except AttributeError: - interimvar = 0 - slides = Slide.objects.filter(meeting=self.meeting,group_acronym_id=self.group_acronym_id,irtf=irtfvar,interim=interimvar).order_by("order_num") - return slides - def interim_meeting (self): - # FIXME - if self.minute_file(1): - return True - elif self.agenda_file(1): - return True - elif self.slides(1): - return True - else: - return False - def length_session1_desc (self): - if self.requested_duration.seconds == 60 * 60: - return "1 hour" - else: - return "%.1f hours" % (float(self.requested_duration.seconds) / (60 * 60)) - def length_session2_desc (self): + return SlideProxy.objects.filter(timeslot=self).order_by("order") + def interim_meeting(self): + return False + def length_session1_desc(self): + l = self.length_session1 + return { "0": "", "1": "1 hour", "2": "1.5 hours", "3": "2 hours", "4": "2.5 hours"}[l] + def length_session2_desc(self): return "" - def length_session3_desc (self): + def length_session3_desc(self): return "" + @property + def ordinality(self): + return 1 + @property def room_id(self): class Dummy: pass @@ -329,51 +402,53 @@ class WgMeetingSessionProxy(TimeSlot): # from ResolveAcronym: def acronym(self): - s = self.get_session() - if not s: + if not self.session: if self.type_id == "plenary": + if "Operations and Administration" in self.name: + return "plenaryw" + if "Technical" in self.name: + return "plenaryt" for m in self.materials.filter(type="agenda"): if "plenaryw" in m.name: return "plenaryw" if "plenaryt" in m.name: return "plenaryt" - return "" + return "%s" % self.pk if hasattr(self, "interim"): - return "i" + s.group.acronym + return "i" + self.session.group.acronym else: - return s.group.acronym + return self.session.group.acronym def acronym_lower(self): return self.acronym().lower() def acronym_name(self): - s = self.get_session() - if not s: + if not self.session: return self.name if hasattr(self, "interim"): - return s.group.name + " (interim)" + return self.session.group.name + " (interim)" else: - return s.group.name + return self.session.group.name def area(self): - s = self.get_session() - if not s: + if not self.session: return "" - return s.group.parent.acronym + return self.session.group.parent.acronym def area_name(self): - s = self.get_session() - if not s: + if self.type_id == "plenary": + return "Plenary Sessions" + elif self.type_id == "other": + return "Training" + elif not self.session: return "" - return s.group.parent.name + return self.session.group.parent.name def isWG(self): - s = self.get_session() - if not s or not s.group: + if not self.session or not self.session.group: return False - if s.group.type_id == "wg" and s.group.state_id != "bof": + if self.session.group.type_id == "wg" and self.session.group.state_id != "bof": return True def group_type_str(self): - s = self.get_session() - if not s or not s.group: + if not self.session or not self.session.group: return "" - if s.group and s.group.type_id == "wg": - if s.group.state_id == "bof": + if self.session.group and self.session.group.type_id == "wg": + if self.session.group.state_id == "bof": return "BOF" else: return "WG" @@ -383,3 +458,43 @@ class WgMeetingSessionProxy(TimeSlot): class Meta: proxy = True +class SlideProxy(Document): + objects = TranslatingManager(dict(), always_filter=dict(type="slides")) + + SLIDE_TYPE_CHOICES=( + ('1', '(converted) HTML'), + ('2', 'PDF'), + ('3', 'Text'), + ('4', 'PowerPoint -2003 (PPT)'), + ('5', 'Microsoft Word'), + ('6', 'PowerPoint 2007- (PPTX)'), + ) + #meeting = models.ForeignKey(Meeting, db_column='meeting_num') + @property + def meeting_id(self): + return self.name.split("-")[1] + #group_acronym_id = models.IntegerField(null=True, blank=True) + #slide_num = models.IntegerField(null=True, blank=True) + @property + def slide_name(self): + return int(self.name.split("-")[3]) + #slide_type_id = models.IntegerField(choices=SLIDE_TYPE_CHOICES) + #slide_name = models.CharField(blank=True, max_length=255) + @property + def slide_name(self): + return self.title + #irtf = models.IntegerField() + #interim = models.BooleanField() + #order_num = models.IntegerField(null=True, blank=True) + @property + def order_num(self): + return self.order + #in_q = models.IntegerField(null=True, blank=True) + def acronym(): + return self.name.split("-")[2] + def __str__(self): + return "IETF%d: %s slides (%s)" % (self.meeting_id, self.acronym(), self.slide_name) + def file_loc(self): + return "%s/slides/%s" % (self.meeting_id, self.external_url) + class Meta: + proxy = True diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index a2fb1fcf5..9c3b3b53f 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -19,7 +19,7 @@ from django.template.loader import render_to_string from django.conf import settings from django.utils.decorators import decorator_from_middleware from django.middleware.gzip import GZipMiddleware -from django.db.models import Count +from django.db.models import Count, Max from ietf.idtracker.models import InternetDraft from ietf.idrfc.idrfc_wrapper import IdWrapper from ietf.utils.pipe import pipe @@ -42,19 +42,38 @@ def show_html_materials(request, meeting_num=None): if now > begin_date: sub_began = 1 # List of WG sessions and Plenary sessions - queryset_list = WgMeetingSession.objects.filter(Q(meeting=meeting_num, group_acronym_id__gte = -2, status__id=4), Q(irtf__isnull=True) | Q(irtf=0)) - queryset_irtf = WgMeetingSession.objects.filter(meeting=meeting_num, group_acronym_id__gte = -2, status__id=4, irtf__gt=0) - queryset_interim = [] - queryset_training = [] - for item in list(WgMeetingSession.objects.filter(meeting=meeting_num)): - if item.interim_meeting(): - item.interim=1 - queryset_interim.append(item) - if item.group_acronym_id < -2: - if item.slides(): - queryset_training.append(item) - cache_version = WgProceedingsActivities.objects.aggregate(Count('id')) - return object_list(request,queryset=queryset_list, template_name="meeting/list.html",allow_empty=True, extra_context={'meeting_num':meeting_num,'irtf_list':queryset_irtf, 'interim_list':queryset_interim, 'training_list':queryset_training, 'begin_date':begin_date, 'cut_off_date':cut_off_date, 'cor_cut_off_date':cor_cut_off_date,'sub_began':sub_began,'cache_version':cache_version}) + if settings.USE_DB_REDESIGN_PROXY_CLASSES: + queryset_list = [] + queryset_irtf = [] + queryset_interim = [] # currently ignored, have no way of handling interim here + queryset_training = [] + for item in WgMeetingSession.objects.filter(meeting=meeting_num): + if item.type_id in ("session", "plenary"): + if item.session and item.session.group and item.session.group.type_id == "rg": + queryset_irtf.append(item) + else: + queryset_list.append(item) + else: + if item.type_id == "other" and item.slides(): + queryset_training.append(item) + from redesign.doc.models import Document + cache_version = Document.objects.filter(timeslot__meeting__number=meeting_num).aggregate(Max('time'))["time__max"] + else: + queryset_list = WgMeetingSession.objects.filter(Q(meeting=meeting_num, group_acronym_id__gte = -2, status__id=4), Q(irtf__isnull=True) | Q(irtf=0)) + queryset_irtf = WgMeetingSession.objects.filter(meeting=meeting_num, group_acronym_id__gte = -2, status__id=4, irtf__gt=0) + queryset_interim = [] + queryset_training = [] + for item in list(WgMeetingSession.objects.filter(meeting=meeting_num)): + if item.interim_meeting(): + item.interim=1 + queryset_interim.append(item) + if item.group_acronym_id < -2: + if item.slides(): + queryset_training.append(item) + cache_version = WgProceedingsActivities.objects.aggregate(Count('id')) + return render_to_response("meeting/list.html", + {'meeting_num':meeting_num,'object_list': queryset_list, 'irtf_list':queryset_irtf, 'interim_list':queryset_interim, 'training_list':queryset_training, 'begin_date':begin_date, 'cut_off_date':cut_off_date, 'cor_cut_off_date':cor_cut_off_date,'sub_began':sub_began,'cache_version':cache_version}, + context_instance=RequestContext(request)) def current_materials(request): meeting = Meeting.objects.order_by('-meeting_num')[0] @@ -83,7 +102,7 @@ def agenda_info(num=None): for n in meetings: try: timeslots = MeetingTime.objects.select_related().filter(meeting=n).order_by("day_id", "time_desc") - update = Switches.objects.get(id=1) # FIXME + update = Switches.objects.get(id=1) meeting= Meeting.objects.get(meeting_num=n) venue = MeetingVenue.objects.get(meeting_num=n) break @@ -91,7 +110,7 @@ def agenda_info(num=None): continue else: raise Http404("No meeting information for meeting %s available" % num) - ads = list(IESGHistory.objects.select_related().filter(meeting=n)) # FIXME + ads = list(IESGHistory.objects.select_related().filter(meeting=n)) if not ads: ads = list(IESGHistory.objects.select_related().filter(meeting=str(int(n)-1))) ads.sort(key=(lambda item: item.area.area_acronym.acronym)) @@ -117,12 +136,12 @@ def agenda_infoREDESIGN(num=None): time_seen.add(t.time) timeslots.append(t) - update = Switches.objects.get(id=1) # FIXME + update = Switches().from_object(meeting) venue = meeting.meeting_venue - ads = list(IESGHistory.objects.select_related().filter(meeting=meeting.number)) # FIXME + ads = list(IESGHistory.objects.select_related().filter(meeting=int(meeting.number))) if not ads: - ads = list(IESGHistory.objects.select_related().filter(meeting=str(int(meeting.number)-1))) + ads = list(IESGHistory.objects.select_related().filter(meeting=int(meeting.number)-1)) ads.sort(key=(lambda item: item.area.area_acronym.acronym)) from redesign.doc.models import Document @@ -153,8 +172,6 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES: def html_agenda(request, num=None): timeslots, update, meeting, venue, ads, plenaryw_agenda, plenaryt_agenda = agenda_info(num) - #timeslots = timeslots[:10] - groups_meeting = []; for slot in timeslots: for session in slot.sessions(): @@ -397,7 +414,7 @@ def ical_agenda(request, num=None): if session.area() == '' or session.area().find('plenary') > 0 or (session.area().lower() in include): filter.append(session.acronym()) - return HttpResponse(render_to_string("meeting/agenda.ics", + return HttpResponse(render_to_string("meeting/agendaREDESIGN.ics" if settings.USE_DB_REDESIGN_PROXY_CLASSES else "meeting/agenda.ics", {"filter":set(filter), "timeslots":timeslots, "update":update, "meeting":meeting, "venue":venue, "ads":ads, "plenaryw_agenda":plenaryw_agenda, "plenaryt_agenda":plenaryt_agenda, "now":now}, diff --git a/ietf/proceedings/admin.py b/ietf/proceedings/admin.py index b747497ad..5c2cd2a4a 100644 --- a/ietf/proceedings/admin.py +++ b/ietf/proceedings/admin.py @@ -59,7 +59,8 @@ admin.site.register(SessionName, SessionNameAdmin) class SlideAdmin(admin.ModelAdmin): list_filter = ['meeting', ] pass -admin.site.register(Slide, SlideAdmin) +if not settings.USE_DB_REDESIGN_PROXY_CLASSES: + admin.site.register(Slide, SlideAdmin) class SwitchesAdmin(admin.ModelAdmin): pass diff --git a/ietf/proceedings/models.py b/ietf/proceedings/models.py index 889f0a88e..8be95333c 100644 --- a/ietf/proceedings/models.py +++ b/ietf/proceedings/models.py @@ -587,10 +587,13 @@ class MeetingHour(models.Model): if settings.USE_DB_REDESIGN_PROXY_CLASSES: MeetingOld = Meeting + ProceedingOld = Proceeding MeetingVenueOld = MeetingVenue MeetingTimeOld = MeetingTime WgMeetingSessionOld = WgMeetingSession - from ietf.meeting.proxy import MeetingProxy as Meeting, MeetingVenueProxy as MeetingVenue, MeetingTimeProxy as MeetingTime, WgMeetingSessionProxy as WgMeetingSession + SlideOld = Slide + SwitchesOld = Switches + from ietf.meeting.proxy import MeetingProxy as Meeting, ProceedingProxy as Proceeding, MeetingVenueProxy as MeetingVenue, MeetingTimeProxy as MeetingTime, WgMeetingSessionProxy as WgMeetingSession, SlideProxy as Slide, SwitchesProxy as Switches # changes done by convert-096.py:changed maxlength to max_length # removed core diff --git a/ietf/templates/meeting/agendaREDESIGN.ics b/ietf/templates/meeting/agendaREDESIGN.ics new file mode 100644 index 000000000..0585f07a9 --- /dev/null +++ b/ietf/templates/meeting/agendaREDESIGN.ics @@ -0,0 +1,35 @@ +{% load humanize %}{% autoescape off %}{% load ietf_filters %}BEGIN:VCALENDAR +VERSION:2.0 +METHOD:PUBLISH +{% if meeting.time_zone %}BEGIN:VTIMEZONE +TZID:{{meeting.time_zone}} +BEGIN:STANDARD +TZOFFSETFROM:{{meeting.time_zone_offset}} +TZOFFSETTO:{{meeting.time_zone_offset}} +TZNAME:{{meeting.time_zone}} +DTSTART:19700101T000000 +END:STANDARD +END:VTIMEZONE +{% endif %}{% for slot in timeslots %}{% ifchanged %}{% if slot.session_name and slot.break_info %}BEGIN:VEVENT +UID:ietf-{{meeting.num}}-break-{{slot.time_id}} +SUMMARY:{{slot.break_info.name}} +{% if venue.break_area_name and slot.break_info.show_break_location %}LOCATION:{{venue.break_area_name}} +{% endif %}STATUS:TENTATIVE +CLASS:PUBLIC +DTSTART{% if meeting.time_zone %};TZID="{{meeting.time_zone}}"{%endif%}:{{ slot.meeting_date|date:"Ymd" }}T{{slot.break_info.time_desc|slice:":4"}}00 +DTEND{% if meeting.time_zone %};TZID="{{meeting.time_zone}}"{%endif%}:{{ slot.meeting_date|date:"Ymd" }}T{{slot.break_info.time_desc|slice:"5:9"}}00 +DTSTAMP:{{ now|date:"Ymd" }}T{{ now|date:"His" }}Z +END:VEVENT +{% endif %}{% endifchanged %}{% for session in slot.sessions %}{%for f in filter%}{%ifequal f session.acronym%}BEGIN:VEVENT +UID:ietf-{{meeting.num}}-{{session.acronym}}-{{session.ordinality}} +SUMMARY:{% if session.area %}{% ifnotequal session.area "1plenary" %}{{session.acronym|upper}} - {% endifnotequal %}{% endif %}{{session.acronym_name}} +LOCATION:{{session.room_id.room_name}} +STATUS:TENTATIVE +CLASS:PUBLIC +DTSTART{% if meeting.time_zone %};TZID="{{meeting.time_zone}}"{%endif%}:{{ slot.meeting_date|date:"Ymd" }}T{{slot.time_desc|slice:":4"}}00 +DTEND{% if meeting.time_zone %};TZID="{{meeting.time_zone}}"{%endif%}:{{ slot.meeting_date|date:"Ymd" }}T{{slot.time_desc|slice:"5:9"}}00 +DTSTAMP:{{ now|date:"Ymd" }}T{{ now|date:"His" }}Z +{% if session.description %}DESCRIPTION: + {{ session.description|escapejs }} +{% endif %}END:VEVENT +{%endifequal%}{%endfor%}{% endfor %}{% endfor %}END:VCALENDAR{% endautoescape %} diff --git a/redesign/doc/models.py b/redesign/doc/models.py index 2f3d8cc84..48883efaa 100644 --- a/redesign/doc/models.py +++ b/redesign/doc/models.py @@ -29,6 +29,7 @@ class DocumentInfo(models.Model): abstract = models.TextField() rev = models.CharField(verbose_name="revision", max_length=16, blank=True) pages = models.IntegerField(blank=True, null=True) + order = models.IntegerField(default=1) intended_std_level = models.ForeignKey(IntendedStdLevelName, blank=True, null=True) std_level = models.ForeignKey(StdLevelName, blank=True, null=True) ad = models.ForeignKey(Person, verbose_name="area director", related_name='ad_%(class)s_set', blank=True, null=True) diff --git a/redesign/group/proxy.py b/redesign/group/proxy.py index ca71ef58b..e28793c1b 100644 --- a/redesign/group/proxy.py +++ b/redesign/group/proxy.py @@ -119,6 +119,11 @@ class IETFWG(Group): return { "active": 1, "dormant": 2, "conclude": 3 }[self.state_id] #area_director = models.ForeignKey(AreaDirector, null=True) #meeting_scheduled = models.CharField(blank=True, max_length=3) + @property + def meeting_scheduled(self): + from meeting.models import Meeting + latest_meeting = Meeting.objects.order_by('-date')[0] + return "YES" if self.session_set.filter(meeting=latest_meeting) else "NO" #email_address = models.CharField(blank=True, max_length=60) @property def email_address(self): diff --git a/redesign/importing/import-meetings.py b/redesign/importing/import-meetings.py index a666fea75..12a56aa9d 100755 --- a/redesign/importing/import-meetings.py +++ b/redesign/importing/import-meetings.py @@ -15,7 +15,7 @@ from django.template.defaultfilters import slugify from ietf.idtracker.models import AreaDirector, IETFWG, Acronym, IRTF from ietf.meeting.models import * -from ietf.proceedings.models import Meeting as MeetingOld, MeetingVenue, MeetingRoom, NonSession, WgMeetingSession, WgAgenda +from ietf.proceedings.models import Meeting as MeetingOld, MeetingVenue, MeetingRoom, NonSession, WgMeetingSession, WgAgenda, Minute, Slide from redesign.person.models import * from redesign.doc.models import Document, DocAlias from redesign.importing.utils import get_or_create_email, old_person_to_person @@ -23,12 +23,14 @@ from redesign.name.models import * from redesign.name.utils import name -# imports Meeting, MeetingVenue, MeetingRoom, NonSession, WgMeetingSession, WgAgenda +# imports Meeting, MeetingVenue, MeetingRoom, NonSession, WgMeetingSession, WgAgenda, Minute, Slide # assumptions: # - persons have been imported # - groups have been imported +ietf_meeting = name(MeetingTypeName, "ietf", "IETF") +interim_meeting = name(MeetingTypeName, "interim", "Interim") session_status_mapping = { 1: name(SessionStatusName, "schedw", "Waiting for Scheduling"), @@ -47,9 +49,15 @@ registration_slot = name(TimeSlotTypeName, "reg", "Registration") plenary_slot = name(TimeSlotTypeName, "plenary", "Plenary") other_slot = name(TimeSlotTypeName, "other", "Other") -conflict_constraint = name(ConstraintName, "conflict", "Conflicts with") +conflict_constraints = { + 1: name(ConstraintName, "conflict", "Conflicts with"), + 2: name(ConstraintName, "conflic2", "Conflicts with (secondary)"), + 3: name(ConstraintName, "conflic3", "Conflicts with (tertiary)"), + } agenda_doctype = name(DocTypeName, "agenda", "Agenda") +minutes_doctype = name(DocTypeName, "minutes", "Minutes") +slides_doctype = name(DocTypeName, "slides", "Slides") system_person = Person.objects.get(name="(System)") obviously_bogus_date = datetime.date(1970, 1, 1) @@ -63,6 +71,7 @@ for o in MeetingOld.objects.all(): m = Meeting(number="%s" % o.meeting_num) m.pk = o.pk + m.type = ietf_meeting m.date = o.start_date m.city = o.city @@ -141,22 +150,6 @@ def parse_time_desc(o): return (datetime.datetime.combine(d, start_time), datetime.datetime.combine(d, end_time)) -def get_or_create_session_timeslot(meeting_time, room): - meeting = Meeting.objects.get(number=s.meeting_id) - starts, ends = parse_time_desc(meeting_time) - - try: - slot = TimeSlot.objects.get(meeting=meeting, time=starts, location=room) - except TimeSlot.DoesNotExist: - slot = TimeSlot(meeting=meeting, time=starts, location=room) - - slot.type = session_slot - slot.name = meeting_time.session_name.session_name if meeting_time.session_name_id else "Unknown" - slot.duration = ends - starts - slot.save() - - return slot - requested_length_mapping = { None: 0, # assume NULL to mean nothing particular requested "1": 60 * 60, @@ -165,42 +158,53 @@ requested_length_mapping = { "4": 150 * 60, } -def import_materials_for_timeslot(timeslot, session=None, wg_meeting_session=None): +def import_materials(wg_meeting_session, timeslot=None, session=None): if timeslot: meeting = timeslot.meeting materials = timeslot.materials else: meeting = session.meeting materials = session.materials - - if wg_meeting_session: + + def import_material_kind(kind, doctype): # import agendas irtf = 0 if wg_meeting_session.irtf: irtf = wg_meeting_session.group_acronym_id - agendas = WgAgenda.objects.filter(meeting=wg_meeting_session.meeting_id, - group_acronym_id=wg_meeting_session.group_acronym_id, - irtf=irtf) + found = kind.objects.filter(meeting=wg_meeting_session.meeting_id, + group_acronym_id=wg_meeting_session.group_acronym_id, + irtf=irtf, + interim=0) - for o in agendas: + for o in found: if session: acronym = session.group.acronym else: - acronym = os.path.splitext(o.filename)[0].lower() - rev = "01" - name = ("agenda-%s-%s-%s" % (meeting.number, acronym, rev)) + acronym = wg_meeting_session.acronym() + name = "%s-%s-%s" % (doctype.slug, meeting.number, acronym) + if kind == Slide: + name += "-%s" % o.slide_num try: - d = Document.objects.get(type=agenda_doctype, docalias__name=name) + d = Document.objects.get(type=doctype, docalias__name=name) except Document.DoesNotExist: - d = Document(type=agenda_doctype, name=name) + d = Document(type=doctype, name=name) if session: session_name = session.group.acronym.upper() else: session_name = timeslot.name - d.title = u"Agenda for %s at %s" % (session_name, meeting) - d.external_url = o.filename # save filenames for now as they don't appear to be quite regular + + if kind == Slide: + d.title = o.slide_name + l = o.file_loc() + d.external_url = l[l.find("slides/") + len("slides/"):] + d.order = o.order_num or 1 + else: + d.title = u"%s for %s at %s" % (doctype.name, session_name, meeting) + d.external_url = o.filename # save filenames for now as they don't appear to be quite regular + d.rev = "01" + d.group = session.group if session else None d.save() @@ -208,7 +212,11 @@ def import_materials_for_timeslot(timeslot, session=None, wg_meeting_session=Non materials.add(d) -for o in WgMeetingSession.objects.all().order_by("pk").filter(pk=1699): + import_material_kind(WgAgenda, agenda_doctype) + import_material_kind(Minute, minutes_doctype) + import_material_kind(Slide, slides_doctype) + +for o in WgMeetingSession.objects.all().order_by("pk"): # num_session is unfortunately not quite reliable, seems to be # right for 1 or 2 but not 3 and it's sometimes null sessions = o.num_session or 1 @@ -217,22 +225,35 @@ for o in WgMeetingSession.objects.all().order_by("pk").filter(pk=1699): print "importing WgMeetingSession", o.pk, "subsessions", sessions - print o.sched_time_id1, o.sched_time_id2, o.sched_time_id3 - for i in range(1, 1 + sessions): pk = o.pk + (i - 1) * 10000 # move extra session out of the way try: s = Session.objects.get(pk=pk) except: s = Session(pk=pk) - s.meeting = Meeting.objects.get(number=o.meeting_id) - sched_time_id = getattr(o, "sched_time_id%s" % i) - if sched_time_id: - room = Room.objects.get(pk=getattr(o, "sched_room_id%s_id" % i)) - s.timeslot = get_or_create_session_timeslot(sched_time_id, room) - else: - s.timeslot = None + + def get_timeslot(attr): + meeting_time = getattr(o, attr) + if not meeting_time: + return None + room = Room.objects.get(pk=getattr(o, attr.replace("time", "room") + "_id")) + + starts, ends = parse_time_desc(meeting_time) + + slots = TimeSlot.objects.filter(meeting=s.meeting, time=starts, location=room).filter(models.Q(session=s) | models.Q(session=None)) + if slots: + slot = slots[0] + else: + slot = TimeSlot(meeting=s.meeting, time=starts, location=room) + + slot.type = session_slot + slot.name = meeting_time.session_name.session_name if meeting_time.session_name_id else "Unknown" + slot.duration = ends - starts + + return slot + + timeslot = get_timeslot("sched_time_id%s" % i) if o.irtf: s.group = Group.objects.get(acronym=IRTF.objects.get(pk=o.group_acronym_id).acronym.lower()) else: @@ -241,22 +262,24 @@ for o in WgMeetingSession.objects.all().order_by("pk").filter(pk=1699): # this wasn't actually a WG session, but rather a tutorial # or similar, don't create a session but instead modify # the time slot appropriately - if not s.timeslot: + if not timeslot: print "IGNORING unscheduled non-WG-session", acronym.name continue - if sched_time_id.session_name_id: - s.timeslot.name = sched_time_id.session_name.session_name + meeting_time = getattr(o, "sched_time_id%s" % i) + if meeting_time.session_name_id: + timeslot.name = meeting_time.session_name.session_name else: - s.timeslot.name = acronym.name + timeslot.name = acronym.name - if "Plenary" in s.timeslot.name: - s.timeslot.type = plenary_slot + if "Plenary" in timeslot.name: + timeslot.type = plenary_slot else: - s.timeslot.type = other_slot - s.timeslot.save() + timeslot.type = other_slot + timeslot.modified = o.last_modified_date + timeslot.save() - import_materials_for_timeslot(s.timeslot, wg_meeting_session=o) + import_materials(o, timeslot=timeslot) continue @@ -266,14 +289,12 @@ for o in WgMeetingSession.objects.all().order_by("pk").filter(pk=1699): s.requested = o.requested_date or obviously_bogus_date s.requested_by = old_person_to_person(o.requested_by) if o.requested_by else system_person s.requested_duration = requested_length_mapping[getattr(o, "length_session%s" % i)] - comments = [] - special_req = (o.special_req or "").strip() - if special_req: - comments.append(u"Special requests:\n" + special_req) + s.comments = (o.special_req or "").strip() conflict_other = (o.conflict_other or "").strip() if conflict_other: - comments.append(u"Other conflicts:\n" + conflict_other) - s.comments = u"\n\n".join(comments) + if s.comments: + s.comments += " " + s.comments += u"(other conflicts: %s)" % conflict_other s.status = session_status_mapping[o.status_id or 5] s.scheduled = o.scheduled_date @@ -281,8 +302,24 @@ for o in WgMeetingSession.objects.all().order_by("pk").filter(pk=1699): s.save() - import_materials_for_timeslot(s.timeslot, session=s, wg_meeting_session=o) + if timeslot: + timeslot.session = s + timeslot.modified = s.modified + timeslot.save() + + import_materials(o, timeslot=timeslot, session=s) + # some sessions have been scheduled over multiple time slots + if i < 3: + timeslot = get_timeslot("combined_time_id%s" % i) + if timeslot: + timeslot.session = s + timeslot.modified = s.modified + timeslot.save() + import_materials(o, timeslot=timeslot, session=s) + + + for i in (1, 2, 3): conflict = (getattr(o, "conflict%s" % i) or "").replace(",", " ").lower() conflicting_groups = [g for g in conflict.split() if g] for target in Group.objects.filter(acronym__in=conflicting_groups): @@ -290,7 +327,7 @@ for o in WgMeetingSession.objects.all().order_by("pk").filter(pk=1699): meeting=s.meeting, source=target, target=s.group, - name=conflict_constraint) + name=conflict_constraints[i]) # missing following fields from old: ts_status_id (= third session diff --git a/redesign/name/models.py b/redesign/name/models.py index 62997a9ff..ed1803c1d 100644 --- a/redesign/name/models.py +++ b/redesign/name/models.py @@ -62,8 +62,10 @@ class IntendedStdLevelName(NameModel): Practice, Historic, ...""" class BallotPositionName(NameModel): """ Yes, NoObjection, Abstain, Discuss, Recuse """ +class MeetingTypeName(NameModel): + """IETF, Interim""" class SessionStatusName(NameModel): - """ Waiting for Approval, Approved, Waiting for Scheduling, Scheduled, Cancelled, Disapproved""" + """Waiting for Approval, Approved, Waiting for Scheduling, Scheduled, Cancelled, Disapproved""" class TimeSlotTypeName(NameModel): """Session, Break, Registration""" class ConstraintName(NameModel):