diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 8f2b76864..fedc7ed46 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -141,9 +141,10 @@ def agenda_infoREDESIGN(num=None): ads = [] meeting_time = datetime.datetime.combine(meeting.date, datetime.time(0, 0, 0)) - from redesign.group.models import Group, find_group_history_active_at + from redesign.group.models import Group + from ietf.utils.history import find_history_active_at for g in Group.objects.filter(type="area").order_by("acronym"): - history = find_group_history_active_at(g, meeting_time) + history = find_history_active_at(g, meeting_time) if history: if history.state_id == "active": ads.extend(IESGHistory().from_role(x) for x in history.rolehistory_set.filter(name="ad")) diff --git a/ietf/utils/history.py b/ietf/utils/history.py new file mode 100644 index 000000000..e0b790044 --- /dev/null +++ b/ietf/utils/history.py @@ -0,0 +1,22 @@ +def find_history_active_at(obj, time): + """Assumes obj has a corresponding history object (e.g. obj could + be Person with a corresponding PersonHistory model), then returns + the history object active at time, or None if the object itself + was active at the time. + + For this to work, the history model must use + related_name="history_set" for the foreign key connecting to the + live model, both models must have a "time" DateTimeField and a + history object must be saved with a copy of the old values and + time when the time field changes. + """ + if obj.time <= time: + return None + + histories = obj.history_set.order_by('-time') + + for h in histories: + if h.time <= time: + return h + + return None diff --git a/redesign/doc/models.py b/redesign/doc/models.py index 4ee0db63a..550abe3b4 100644 --- a/redesign/doc/models.py +++ b/redesign/doc/models.py @@ -137,7 +137,7 @@ class DocHistoryAuthor(models.Model): ordering = ["document", "order"] class DocHistory(DocumentInfo): - doc = models.ForeignKey(Document) # ID of the Document this relates to + doc = models.ForeignKey(Document, related_name="history_set") # Django 1.2 won't let us define these in the base class, so we have # to repeat them related = models.ManyToManyField('DocAlias', through=RelatedDocHistory, blank=True) diff --git a/redesign/doc/proxy.py b/redesign/doc/proxy.py index ca36ae527..e61c7199f 100644 --- a/redesign/doc/proxy.py +++ b/redesign/doc/proxy.py @@ -349,7 +349,7 @@ class InternetDraft(Document): #prev_state = models.ForeignKey(IDState, db_column='prev_state', related_name='docs_prev') @property def prev_state(self): - ds = self.dochistory_set.exclude(iesg_state=self.iesg_state).order_by('-time')[:1] + ds = self.history_set.exclude(iesg_state=self.iesg_state).order_by('-time')[:1] return IDState().from_object(ds[0].iesg_state) if ds else None #assigned_to = models.CharField(blank=True, max_length=25) # unused @@ -403,7 +403,7 @@ class InternetDraft(Document): #prev_sub_state = BrokenForeignKey(IDSubState, related_name='docs_prev', null=True, blank=True, null_values=(0, -1)) @property def prev_sub_state(self): - ds = self.dochistory_set.all().order_by('-time')[:1] + ds = self.history_set.all().order_by('-time')[:1] substates = ds[0].tags.filter(slug__in=['extpty', 'need-rev', 'ad-f-up', 'point']) if ds else None return IDSubState().from_object(substates[0]) if substates else None @property diff --git a/redesign/group/models.py b/redesign/group/models.py index 645de8726..6d506f203 100644 --- a/redesign/group/models.py +++ b/redesign/group/models.py @@ -39,7 +39,7 @@ class Group(GroupInfo): # to a group. The group acronym must be unique and is the invariant used # to select group history from this table. class GroupHistory(GroupInfo): - group = models.ForeignKey('Group', related_name='group_history') + group = models.ForeignKey(Group, related_name='history_set') charter = models.ForeignKey('doc.Document', related_name='chartered_group_history_set', blank=True, null=True) class Meta: @@ -91,24 +91,13 @@ class Role(models.Model): class RoleHistory(models.Model): + # RoleHistory doesn't have a time field as it's not supposed to be + # used on its own - there should always be a GroupHistory + # accompanying a change in roles, so lookup the appropriate + # GroupHistory instead name = models.ForeignKey(RoleName) group = models.ForeignKey(GroupHistory) email = models.ForeignKey(Email, help_text="Email address used by person for this role") auth = models.CharField(max_length=255, blank=True) # unused? def __unicode__(self): return u"%s is %s in %s" % (self.email.get_name(), self.name.name, self.group.acronym) - - -def find_group_history_active_at(group, time): - """Return the GroupHistory object active at time, or None if the - group itself was active at the time.""" - if group.time <= time: - return None - - histories = group.group_history.order_by('-time') - - for h in histories: - if h.time <= time: - return h - - return None diff --git a/redesign/importing/import-roles.py b/redesign/importing/import-roles.py index a2c696f76..743cc41b5 100755 --- a/redesign/importing/import-roles.py +++ b/redesign/importing/import-roles.py @@ -19,6 +19,7 @@ from redesign.importing.utils import get_or_create_email from ietf.idtracker.models import IESGLogin, AreaDirector, PersonOrOrgInfo, WGChair, WGEditor, WGSecretary, WGTechAdvisor, ChairsHistory, Role as OldRole, Acronym, IRTFChair from ietf.proceedings.models import IESGHistory +from ietf.utils.history import * # assumptions: @@ -195,7 +196,7 @@ for o in IESGHistory.objects.all().order_by('meeting__start_date', 'pk'): emails_for_time[key].append(email) - history = find_group_history_active_at(area, meeting_time) + history = find_history_active_at(area, meeting_time) if (history and history.rolehistory_set.filter(email__person=email.person) or not history and area.role_set.filter(email__person=email.person)): continue