Add models for new meeting schema and an importer, clean up person

import slightly
 - Legacy-Id: 3282
This commit is contained in:
Ole Laursen 2011-08-04 11:17:29 +00:00
parent 5aa189afdd
commit 0e576f4352
8 changed files with 668 additions and 49 deletions

View file

@ -1,3 +1,139 @@
# Copyright The IETF Trust 2007, All Rights Reserved
# old meeting models can be found in ../proceedings/models.py
import pytz
from django.db import models
from timedeltafield import TimedeltaField
from redesign.group.models import Group
from redesign.person.models import Person
from redesign.name.models import TimeSlotTypeName, SessionStatusName, ConstraintName
countries = pytz.country_names.items()
countries.sort(lambda x,y: cmp(x[1], y[1]))
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 = models.CharField(max_length=64)
# 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.
date = models.DateField()
city = models.CharField(blank=True, max_length=255)
country = models.CharField(blank=True, max_length=2, choices=countries)
# We can't derive time-zone from country, as there are some that have
# more than one timezone, and the pytz module doesn't provide timezone
# lookup information for all relevant city/country combinations.
time_zone = models.CharField(blank=True, max_length=255, choices=timezones)
venue_name = models.CharField(blank=True, max_length=255)
venue_addr = models.TextField(blank=True)
break_area = models.CharField(blank=True, max_length=255)
reg_area = models.CharField(blank=True, max_length=255)
def __str__(self):
return "IETF-%s" % (self.number)
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):
date = cls.objects.all().order_by('-date')[0].date
offset = datetime.timedelta(days=settings.FIRST_CUTOFF_DAYS)
return date - offset
@classmethod
def get_second_cut_off(cls):
date = cls.objects.all().order_by('-date')[0].date
offset = datetime.timedelta(days=settings.SECOND_CUTOFF_DAYS)
return date - offset
@classmethod
def get_ietf_monday(cls):
date = cls.objects.all().order_by('-date')[0].date
return date + datetime.timedelta(days=-date.weekday(), weeks=1)
class Room(models.Model):
meeting = models.ForeignKey(Meeting)
name = models.CharField(max_length=255)
def __unicode__(self):
return self.name
class TimeSlot(models.Model):
"""
Everything that would appear on the meeting agenda of a meeting is mapped
to a time slot, including breaks (i.e., also NonSession+NonSessionRef.
Sessions are connected to TimeSlots during scheduling.
A template function to populate a meeting with an appropriate set of TimeSlots
is probably also needed.
"""
meeting = models.ForeignKey(Meeting)
type = models.ForeignKey(TimeSlotTypeName)
name = models.CharField(max_length=255)
time = models.DateTimeField()
duration = TimedeltaField()
location = models.ForeignKey(Room, blank=True, null=True)
show_location = models.BooleanField(default=True)
def __unicode__(self):
location = self.get_location()
if not location:
location = "(no location)"
return u"%s: %s-%s %s, %s" % (self.meeting.number, self.time.strftime("%m-%d %H:%M"), (self.time + self.duration).strftime("%H:%M"), self.name, location)
def get_location(self):
location = self.location
if location:
location = location.name
elif self.type_id == "reg":
location = self.meeting.reg_area
elif self.type_id == "break":
location = self.meeting.break_area
if not self.show_location:
location = ""
return location
class Constraint(models.Model):
"""Specifies a constraint on the scheduling between source and
target, e.g. some kind of conflict."""
meeting = models.ForeignKey(Meeting)
source = models.ForeignKey(Group, related_name="constraint_source_set")
target = models.ForeignKey(Group, related_name="constraint_target_set")
name = models.ForeignKey(ConstraintName)
def __unicode__(self):
return u"%s %s %s" % (self.source, self.name.lower(), self.target)
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)
#
requested = models.DateTimeField()
requested_by = models.ForeignKey(Person)
requested_duration = TimedeltaField()
comments = models.TextField()
#
status = models.ForeignKey(SessionStatusName)
scheduled = models.DateTimeField(null=True, blank=True)
modified = models.DateTimeField(null=True, blank=True)
# Agendas, Minutes and Slides are all mapped to Document.
# IESG history is extracted from GroupHistory, rather than hand coded in a
# separate table.
# Meeting models can be found under ../proceedings/

View file

@ -0,0 +1,191 @@
# -*- coding: iso-8859-1 -*-
# $Id: TimedeltaField.py 1787 2011-04-20 07:09:57Z tguettler $
# $HeadURL: svn+ssh://svnserver/svn/djangotools/trunk/dbfields/TimedeltaField.py $
# from http://djangosnippets.org/snippets/1060/ with some fixes
# Python
import datetime
# Django
from django import forms
from django.db import models
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
#Djangotools
#from djangotools.utils.southutils import add_introspection_rules_from_baseclass
SECS_PER_DAY=3600*24
class TimedeltaField(models.Field):
u'''
Store Python's datetime.timedelta in an integer column.
Most database systems only support 32 bit integers by default.
'''
__metaclass__ = models.SubfieldBase
empty_strings_allowed = False
def __init__(self, *args, **kwargs):
super(TimedeltaField, self).__init__(*args, **kwargs)
def to_python(self, value):
if (value is None) or isinstance(value, datetime.timedelta):
return value
try:
# else try to convert to int (e.g. from string)
value = int(value)
except (TypeError, ValueError):
raise exceptions.ValidationError(
_("This value must be an integer or a datetime.timedelta."))
return datetime.timedelta(seconds=value)
def get_internal_type(self):
return 'IntegerField'
def get_db_prep_lookup(self, lookup_type, value, connection=None, prepared=False):
raise NotImplementedError() # SQL WHERE
def get_db_prep_save(self, value, connection=None, prepared=False):
if (value is None) or isinstance(value, int):
return value
return SECS_PER_DAY*value.days+value.seconds
def formfield(self, *args, **kwargs):
defaults={'form_class': TimedeltaFormField}
defaults.update(kwargs)
return super(TimedeltaField, self).formfield(*args, **defaults)
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
return self.get_db_prep_value(value)
#South Plugin registrieren
#add_introspection_rules_from_baseclass(TimedeltaField, ["^djangotools\.dbfields\.TimedeltaField"])
class TimedeltaFormField(forms.Field):
default_error_messages = {
'invalid': _(u'Enter a whole number.'),
}
def __init__(self, *args, **kwargs):
defaults={'widget': TimedeltaWidget}
defaults.update(kwargs)
super(TimedeltaFormField, self).__init__(*args, **defaults)
def clean(self, value):
# value comes from Timedelta.Widget.value_from_datadict(): tuple of strings
super(TimedeltaFormField, self).clean(value)
assert len(value)==len(self.widget.inputs), (value, self.widget.inputs)
i=0
for value, multiply in zip(value, self.widget.multiply):
try:
i+=int(value)*multiply
except ValueError, TypeError:
raise forms.ValidationError(self.error_messages['invalid'])
return i
class TimedeltaWidget(forms.Widget):
INPUTS=['days', 'hours', 'minutes', 'seconds']
MULTIPLY=[60*60*24, 60*60, 60, 1]
def __init__(self, attrs=None):
self.widgets=[]
if not attrs:
attrs={}
inputs=attrs.get('inputs', self.INPUTS)
multiply=[]
for input in inputs:
assert input in self.INPUTS, (input, self.INPUT)
self.widgets.append(forms.TextInput(attrs=attrs))
multiply.append(self.MULTIPLY[self.INPUTS.index(input)])
self.inputs=inputs
self.multiply=multiply
super(TimedeltaWidget, self).__init__(attrs)
def render(self, name, value, attrs):
if value is None:
values=[0 for i in self.inputs]
elif isinstance(value, datetime.timedelta):
values=split_seconds(value.days*SECS_PER_DAY+value.seconds, self.inputs, self.multiply)
elif isinstance(value, int):
# initial data from model
values=split_seconds(value, self.inputs, self.multiply)
else:
assert isinstance(value, tuple), (value, type(value))
assert len(value)==len(self.inputs), (value, self.inputs)
values=value
id=attrs.pop('id')
assert not attrs, attrs
rendered=[]
for input, widget, val in zip(self.inputs, self.widgets, values):
rendered.append(u'%s %s' % (_(input), widget.render('%s_%s' % (name, input), val)))
return mark_safe('<div id="%s">%s</div>' % (id, ' '.join(rendered)))
def value_from_datadict(self, data, files, name):
# Don't throw ValidationError here, just return a tuple of strings.
ret=[]
for input, multi in zip(self.inputs, self.multiply):
ret.append(data.get('%s_%s' % (name, input), 0))
return tuple(ret)
def _has_changed(self, initial_value, data_value):
# data_value comes from value_from_datadict(): A tuple of strings.
if initial_value is None:
return bool(set(data_value)!=set([u'0']))
assert isinstance(initial_value, datetime.timedelta), initial_value
initial=tuple([unicode(i) for i in split_seconds(initial_value.days*SECS_PER_DAY+initial_value.seconds, self.inputs, self.multiply)])
assert len(initial)==len(data_value), (initial, data_value)
return bool(initial!=data_value)
def main():
assert split_seconds(1000000)==[11, 13, 46, 40]
field=TimedeltaField()
td=datetime.timedelta(days=10, seconds=11)
s=field.get_db_prep_save(td)
assert isinstance(s, int), (s, type(s))
td_again=field.to_python(s)
assert td==td_again, (td, td_again)
td=datetime.timedelta(seconds=11)
s=field.get_db_prep_save(td)
td_again=field.to_python(s)
assert td==td_again, (td, td_again)
field=TimedeltaFormField()
assert field.widget._has_changed(datetime.timedelta(seconds=0), (u'0', u'0', u'0', u'0',)) is False
assert field.widget._has_changed(None, (u'0', u'0', u'0', u'0',)) is False
assert field.widget._has_changed(None, (u'0', u'0')) is False
assert field.widget._has_changed(datetime.timedelta(days=1, hours=2, minutes=3, seconds=4), (u'1', u'2', u'3', u'4',)) is False
for secs, soll, kwargs in [
(100, [0, 0, 1, 40], dict()),
(100, ['0days', '0hours', '1minutes', '40seconds'], dict(with_unit=True)),
(100, ['1minutes', '40seconds'], dict(with_unit=True, remove_leading_zeros=True)),
(100000, ['1days', '3hours'], dict(inputs=['days', 'hours'], with_unit=True, remove_leading_zeros=True)),
]:
ist=split_seconds(secs, **kwargs)
if ist!=soll:
raise Exception('geg=%s soll=%s ist=%s kwargs=%s' % (secs, soll, ist, kwargs))
print "unittest OK"
def split_seconds(secs, inputs=TimedeltaWidget.INPUTS, multiply=TimedeltaWidget.MULTIPLY,
with_unit=False, remove_leading_zeros=False):
ret=[]
assert len(inputs)<=len(multiply), (inputs, multiply)
for input, multi in zip(inputs, multiply):
count, secs = divmod(secs, multi)
if remove_leading_zeros and not ret and not count:
continue
if with_unit:
ret.append('%s%s' % (count, input))
else:
ret.append(count)
return ret
if __name__=='__main__':
main()

View file

@ -0,0 +1,273 @@
#!/usr/bin/python
import sys, os, re, datetime, pytz
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
sys.path = [ basedir ] + sys.path
from ietf import settings
settings.USE_DB_REDESIGN_PROXY_CLASSES = False
from django.core import management
management.setup_environ(settings)
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
from redesign.person.models import *
from redesign.importing.utils import get_or_create_email, old_person_to_person
from redesign.name.utils import name
# imports Meeting, MeetingVenue, MeetingRoom, NonSession, WgMeetingSession
# assumptions:
# - persons have been imported
# - groups have been imported
session_status_mapping = {
1: name(SessionStatusName, "schedw", "Waiting for Scheduling"),
2: name(SessionStatusName, "apprw", "Waiting for Approval"),
3: name(SessionStatusName, "appr", "Approved"),
4: name(SessionStatusName, "sched", "Scheduled"),
5: name(SessionStatusName, "canceled", "Canceled"),
6: name(SessionStatusName, "disappr", "Disapproved"),
}
session_status_mapping[0] = session_status_mapping[1] # assume broken statuses of 0 are actually cancelled
session_slot = name(TimeSlotTypeName, "session", "Session")
break_slot = name(TimeSlotTypeName, "break", "Break")
registration_slot = name(TimeSlotTypeName, "reg", "Registration")
other_slot = name(TimeSlotTypeName, "other", "Other")
conflict_constraint = name(ConstraintName, "conflict", "Conflicts with")
system_person = Person.objects.get(name="(System)")
obviously_bogus_date = datetime.date(1970, 1, 1)
for o in MeetingOld.objects.all():
print "importing Meeting", o.pk
try:
m = Meeting.objects.get(number=o.meeting_num)
except:
m = Meeting(number="%s" % o.meeting_num)
m.pk = o.pk
m.date = o.start_date
m.city = o.city
# convert country to code
country_code = None
for k, v in pytz.country_names.iteritems():
if v == o.country:
country_code = k
break
if not country_code:
country_fallbacks = {
'USA': 'US'
}
country_code = country_fallbacks.get(o.country)
if country_code:
m.country = country_code
else:
print "unknown country", o.country
time_zone_lookup = {
("IE", "Dublin"): "Europe/Dublin",
("FR", "Paris"): "Europe/Paris",
("CA", "Vancouver"): "America/Vancouver",
("CZ", "Prague"): "Europe/Prague",
("US", "Chicago"): "America/Chicago",
("US", "Anaheim"): "America/Los_Angeles",
("NL", "Maastricht"): "Europe/Amsterdam",
("CN", "Beijing"): "Asia/Shanghai",
("JP", "Hiroshima"): "Asia/Tokyo",
("SE", "Stockholm"): "Europe/Stockholm",
("US", "San Francisco"): "America/Los_Angeles",
("US", "Minneapolis"): "America/Menominee",
}
m.time_zone = time_zone_lookup.get((m.country, m.city), "")
if not m.time_zone:
print "unknown time zone for", m.get_country_display(), m.city
m.venue_name = "" # no source for that in the old DB?
m.venue_addr = "" # no source for that in the old DB?
try:
venue = o.meetingvenue_set.get()
m.break_area = venue.break_area_name
m.reg_area = venue.reg_area_name
except MeetingVenue.DoesNotExist:
pass
# missing following semi-used fields from old Meeting: end_date,
# ack, agenda_html/agenda_text, future_meeting
m.save()
for o in MeetingRoom.objects.all():
print "importing MeetingRoom", o.pk
try:
r = Room.objects.get(pk=o.pk)
except Room.DoesNotExist:
r = Room(pk=o.pk)
r.meeting = Meeting.objects.get(number="%s" % o.meeting_id)
r.name = o.room_name
r.save()
def parse_time_desc(o):
t = o.time_desc.replace(' ', '')
start_time = datetime.time(int(t[0:2]), int(t[2:4]))
end_time = datetime.time(int(t[5:7]), int(t[7:9]))
d = o.meeting.start_date + datetime.timedelta(days=o.day_id)
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,
"2": 90 * 60,
"3": 120 * 60,
"4": 150 * 60,
}
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
if o.sched_time_id3:
sessions = 3
print "importing WgMeetingSession", o.pk, "subsessions", sessions
for i in range(1, 1 + sessions):
try:
s = Session.objects.get(pk=o.pk + (i - 1) * 10000)
except:
s = Session(pk=o.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
if o.irtf:
s.group = Group.objects.get(acronym=IRTF.objects.get(pk=o.group_acronym_id).acronym.lower())
else:
acronym = Acronym.objects.get(pk=o.group_acronym_id)
if o.group_acronym_id < 0:
# 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:
print "IGNORING unscheduled non-WG-session", acronym.name
continue
s.timeslot.name = acronym.name
s.timeslot.type = other_slot
s.timeslot.save()
continue
s.group = Group.objects.get(acronym=acronym.acronym)
s.attendees = o.number_attendee
s.agenda_note = (o.special_agenda_note or "").strip()
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)
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)
s.status = session_status_mapping[o.status_id or 5]
s.scheduled = o.scheduled_date
s.modified = o.last_modified_date
s.save()
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):
Constraint.objects.get_or_create(
meeting=s.meeting,
source=target,
target=s.group,
name=conflict_constraint)
# missing following fields from old: ts_status_id (= third session
# status id, third session required AD approval),
# combined_room_id1/2, combined_time_id1/2
for o in NonSession.objects.all().order_by('pk').select_related("meeting"):
print "importing NonSession", o.pk
if o.time_desc in ("", "0"):
print "IGNORING non-scheduled NonSession", o.non_session_ref.name
continue
meeting = Meeting.objects.get(number=o.meeting_id)
# some non-sessions are scheduled every day, but only if there's a
# session nearby, figure out which days this corresponds to
days = set()
if o.day_id == None:
t = datetime.time(int(o.time_desc[-4:][0:2]), int(o.time_desc[-4:][2:4]))
for s in TimeSlot.objects.filter(meeting=meeting):
if s.time.time() == t:
days.add((s.time.date() - meeting.date).days)
else:
days.add(o.day_id)
for day in days:
o.day_id = day
starts, ends = parse_time_desc(o)
name = o.non_session_ref.name
try:
slot = TimeSlot.objects.get(meeting=meeting, time=starts, name=name)
except TimeSlot.DoesNotExist:
slot = TimeSlot(meeting=meeting, time=starts, name=name)
slot.location = None
if o.non_session_ref_id == 1:
slot.type = registration_slot
else:
slot.type = break_slot
slot.duration = ends - starts
slot.show_location = o.show_break_location
slot.save()

View file

@ -11,16 +11,20 @@ settings.USE_DB_REDESIGN_PROXY_CLASSES = False
from django.core import management
management.setup_environ(settings)
from ietf.idtracker.models import AreaDirector, IETFWG
from ietf.idtracker.models import AreaDirector, IETFWG, PersonOrOrgInfo, IDAuthor
from redesign.person.models import *
from redesign.importing.utils import get_or_create_email
from redesign.importing.utils import clean_email_address, get_or_create_email
# creates system person and email
# imports AreaDirector persons that are connected to an IETFWG
# imports AreaDirector persons that are connected to an IETFWG,
# persons from IDAuthor, announcement originators from Announcements,
# requesters from WgMeetingSession
# should probably also import the old person/email tables
# should probably import
# PersonOrOrgInfo/PostalAddress/EmailAddress/PhoneNumber fully
# make sure special system user/email is created
print "creating (System) person and email"
try:
system_person = Person.objects.get(name="(System)")
@ -48,7 +52,39 @@ system_email = Email.objects.get_or_create(
defaults=dict(active=True, person=system_person)
)
# AreaDirector from IETFWG persons
for o in AreaDirector.objects.filter(ietfwg__in=IETFWG.objects.all()).exclude(area=None).distinct().order_by("pk").iterator():
print "importing AreaDirector (from IETFWG) persons", o.pk
get_or_create_email(o, create_fake=False)
# WgMeetingSession persons
for o in PersonOrOrgInfo.objects.filter(wgmeetingsession__pk__gte=1).distinct().order_by("pk").iterator():
print "importing WgMeetingSession persons", o.pk, o.first_name.encode('utf-8'), o.last_name.encode('utf-8')
get_or_create_email(o, create_fake=False)
# Announcement persons
for o in PersonOrOrgInfo.objects.filter(announcement__announcement_id__gte=1).order_by("pk").distinct():
print "importing Announcement originator", o.pk, o.first_name.encode('utf-8'), o.last_name.encode('utf-8')
email = get_or_create_email(o, create_fake=False)
# IDAuthor persons
for o in IDAuthor.objects.all().order_by('id').select_related('person').iterator():
print "importing IDAuthor", o.id, o.person_id, o.person.first_name.encode('utf-8'), o.person.last_name.encode('utf-8')
email = get_or_create_email(o, create_fake=True)
# we may also need to import email address used specifically for
# the document
addr = clean_email_address(o.email() or "")
if addr and addr.lower() != email.address.lower():
try:
e = Email.objects.get(address=addr)
if e.person != email.person or e.active != False:
e.person = email.person
e.active = False
e.save()
except Email.DoesNotExist:
Email.objects.create(address=addr, person=email.person, active=False)

View file

@ -15,24 +15,19 @@ from redesign.person.models import *
from redesign.group.models import *
from redesign.name.models import *
from redesign.name.utils import name
from redesign.importing.utils import old_person_to_email, clean_email_address, get_or_create_email
from redesign.importing.utils import get_or_create_email
from ietf.idtracker.models import IESGLogin, AreaDirector, IDAuthor, PersonOrOrgInfo, WGChair, WGEditor, WGSecretary, WGTechAdvisor, ChairsHistory, Role as OldRole, Acronym, IRTFChair
from ietf.idtracker.models import IESGLogin, AreaDirector, PersonOrOrgInfo, WGChair, WGEditor, WGSecretary, WGTechAdvisor, ChairsHistory, Role as OldRole, Acronym, IRTFChair
# assumptions:
# - persons have been imported
# - groups have been imported
# PersonOrOrgInfo/PostalAddress/EmailAddress/PhoneNumber are not
# imported, although some information is retrieved from those
# imports IESGLogin, AreaDirector, WGEditor, WGChair, IRTFChair,
# WGSecretary, WGTechAdvisor, NomCom chairs from ChairsHistory,
#
# also imports persons from IDAuthor, announcement originators from
# Announcements
# FIXME: should probably import Role
# FIXME: should probably import Role, LegacyWgPassword, LegacyLiaisonUser
area_director_role = name(RoleName, "ad", "Area Director")
inactive_area_director_role = name(RoleName, "ex-ad", "Ex-Area Director", desc="Inactive Area Director")
@ -176,29 +171,3 @@ for o in AreaDirector.objects.all():
Role.objects.get_or_create(name=role_type, group=area, email=email)
# Announcement persons
for o in PersonOrOrgInfo.objects.filter(announcement__announcement_id__gte=1).distinct():
print "importing Announcement originator", o.person_or_org_tag, o.first_name.encode('utf-8'), o.last_name.encode('utf-8')
o.person = o # satisfy the get_or_create_email interface
email = get_or_create_email(o, create_fake=False)
# IDAuthor persons
for o in IDAuthor.objects.all().order_by('id').select_related('person').iterator():
print "importing IDAuthor", o.id, o.person_id, o.person.first_name.encode('utf-8'), o.person.last_name.encode('utf-8')
email = get_or_create_email(o, create_fake=True)
# we may also need to import email address used specifically for
# the document
addr = clean_email_address(o.email() or "")
if addr and addr.lower() != email.address.lower():
try:
e = Email.objects.get(address=addr)
if e.person != email.person or e.active != False:
e.person = email.person
e.active = False
e.save()
except Email.DoesNotExist:
Email.objects.create(address=addr, person=email.person, active=False)

View file

@ -11,7 +11,10 @@ def clean_email_address(addr):
return addr
def old_person_to_person(person):
return Person.objects.get(id=person.pk)
try:
return Person.objects.get(id=person.pk)
except Person.DoesNotExist:
return Person.objects.get(alias__name=u"%s %s" % (person.first_name, person.last_name))
def old_person_to_email(person):
hardcoded_emails = { 'Dinara Suleymanova': "dinaras@ietf.org" }
@ -19,25 +22,27 @@ def old_person_to_email(person):
return clean_email_address(person.email()[1] or hardcoded_emails.get("%s %s" % (person.first_name, person.last_name)) or "")
def get_or_create_email(o, create_fake):
# take person on o and get or create new Email and Person objects
email = old_person_to_email(o.person)
# take o.person (or o) and get or create new Email and Person objects
person = o.person if hasattr(o, "person") else o
email = old_person_to_email(person)
if not email:
if create_fake:
email = u"unknown-email-%s-%s" % (o.person.first_name, o.person.last_name)
print ("USING FAKE EMAIL %s for %s %s %s" % (email, o.person.pk, o.person.first_name, o.person.last_name)).encode('utf-8')
email = u"unknown-email-%s-%s" % (person.first_name, person.last_name)
print ("USING FAKE EMAIL %s for %s %s %s" % (email, person.pk, person.first_name, person.last_name)).encode('utf-8')
else:
print ("NO EMAIL FOR %s %s %s %s %s" % (o.__class__, o.pk, o.person.pk, o.person.first_name, o.person.last_name)).encode('utf-8')
print ("NO EMAIL FOR %s %s %s %s %s" % (o.__class__, o.pk, person.pk, person.first_name, person.last_name)).encode('utf-8')
return None
e, _ = Email.objects.select_related("person").get_or_create(address=email)
if not e.person:
n = u"%s %s" % (o.person.first_name, o.person.last_name)
n = u"%s %s" % (person.first_name, person.last_name)
asciified = unaccent.asciify(n)
aliases = Alias.objects.filter(name__in=(n, asciified))
if aliases:
p = aliases[0].person
else:
p = Person.objects.create(id=o.person.pk, name=n, ascii=asciified)
p = Person.objects.create(id=person.pk, name=n, ascii=asciified)
# FIXME: fill in address?
Alias.objects.create(name=n, person=p)

View file

@ -21,3 +21,6 @@ admin.site.register(DocInfoTagName, NameAdmin)
admin.site.register(StdLevelName, NameAdmin)
admin.site.register(IntendedStdLevelName, NameAdmin)
admin.site.register(BallotPositionName, NameAdmin)
admin.site.register(SessionStatusName, NameAdmin)
admin.site.register(TimeSlotTypeName, NameAdmin)
admin.site.register(ConstraintName, NameAdmin)

View file

@ -62,6 +62,12 @@ class IntendedStdLevelName(NameModel):
Practice, Historic, ..."""
class BallotPositionName(NameModel):
""" Yes, NoObjection, Abstain, Discuss, Recuse """
class SessionStatusName(NameModel):
""" Waiting for Approval, Approved, Waiting for Scheduling, Scheduled, Cancelled, Disapproved"""
class TimeSlotTypeName(NameModel):
"""Session, Break, Registration"""
class ConstraintName(NameModel):
"""Conflict"""
def get_next_iesg_states(iesg_state):