212 lines
9.1 KiB
Python
212 lines
9.1 KiB
Python
# Copyright The IETF Trust 2007, All Rights Reserved
|
|
|
|
from django.db import models
|
|
from redesign.group.models import *
|
|
from redesign.name.models import *
|
|
from redesign.person.models import Email
|
|
from redesign.util import admin_link
|
|
|
|
|
|
class RelatedDoc(models.Model):
|
|
relationship = models.ForeignKey(DocRelationshipName)
|
|
doc_alias = models.ForeignKey('DocAlias')
|
|
def __unicode__(self):
|
|
return "%s %s" % (self.relationship.name, self.doc_alias.name)
|
|
source = admin_link("related_document_set")
|
|
target = admin_link("doc_alias__document")
|
|
|
|
class DocumentInfo(models.Model):
|
|
"""Any kind of document. Draft, RFC, Charter, IPR Statement, Liaison Statement"""
|
|
time = models.DateTimeField() # should probably have auto_now=True
|
|
# Document related
|
|
type = models.ForeignKey(DocTypeName, blank=True, null=True) # Draft, Agenda, Minutes, Charter, Discuss, Guideline, Email, Review, Issue, Wiki, External ...
|
|
title = models.CharField(max_length=255)
|
|
# State
|
|
state = models.ForeignKey(DocStateName, blank=True, null=True) # Active/Expired/RFC/Replaced/Withdrawn
|
|
tags = models.ManyToManyField(DocInfoTagName, blank=True, null=True) # Revised ID Needed, ExternalParty, AD Followup, ...
|
|
stream = models.ForeignKey(DocStreamName, blank=True, null=True) # IETF, IAB, IRTF, Independent Submission
|
|
group = models.ForeignKey(Group, blank=True, null=True) # WG, RG, IAB, IESG, Edu, Tools
|
|
wg_state = models.ForeignKey(WgDocStateName, blank=True, null=True) # Not/Candidate/Active/Parked/LastCall/WriteUp/Submitted/Dead
|
|
iesg_state = models.ForeignKey(IesgDocStateName, blank=True, null=True) #
|
|
iana_state = models.ForeignKey(IanaDocStateName, blank=True, null=True)
|
|
rfc_state = models.ForeignKey(RfcDocStateName, blank=True, null=True)
|
|
# Other
|
|
abstract = models.TextField()
|
|
rev = models.CharField(max_length=16)
|
|
pages = models.IntegerField(blank=True, null=True)
|
|
intended_std_level = models.ForeignKey(IntendedStatusName, blank=True, null=True)
|
|
std_level = models.ForeignKey(StdStatusName, blank=True, null=True)
|
|
authors = models.ManyToManyField(Email, blank=True, null=True)
|
|
related = models.ManyToManyField(RelatedDoc, related_name='related_%(class)s_set', blank=True)
|
|
ad = models.ForeignKey(Email, related_name='ad_%(class)s_set', blank=True, null=True)
|
|
shepherd = models.ForeignKey(Email, related_name='shepherd_%(class)s_set', blank=True, null=True)
|
|
notify = models.CharField(max_length=255, blank=True)
|
|
external_url = models.URLField(blank=True) # Should be set for documents with type 'External'.
|
|
note = models.TextField(blank=True)
|
|
internal_comments = models.TextField(blank=True)
|
|
|
|
class Meta:
|
|
abstract = True
|
|
def author_list(self):
|
|
return ", ".join(email.address for email in self.authors.all())
|
|
def latest_event(self, **filter_args):
|
|
e = self.event_set.filter(**filter_args).order_by('-time')[:1]
|
|
if e:
|
|
return e[0]
|
|
else:
|
|
return None
|
|
|
|
class Document(DocumentInfo):
|
|
name = models.CharField(max_length=255, primary_key=True) # immutable
|
|
def __unicode__(self):
|
|
return self.name
|
|
def values(self):
|
|
try:
|
|
fields = dict([(field.name, getattr(self, field.name))
|
|
for field in self._meta.fields
|
|
if field is not self._meta.pk])
|
|
except:
|
|
for field in self._meta.fields:
|
|
print "* %24s"%field.name,
|
|
print getattr(self, field.name)
|
|
raise
|
|
many2many = dict([(field.name, getattr(self, field.name).all())
|
|
for field in self._meta.many_to_many ])
|
|
return fields, many2many
|
|
|
|
def save_with_history(self, force_insert=False, force_update=False):
|
|
fields, many2many = self.values()
|
|
fields["doc"] = self
|
|
try:
|
|
snap = DocHistory.objects.get(**dict((k,v) for k,v in fields.items() if k != 'time'))
|
|
# FIXME: what if there are two with the same set of values
|
|
# at different points in time?
|
|
if snap.time > fields["time"]:
|
|
snap.time = fields["time"]
|
|
snap.save()
|
|
except DocHistory.DoesNotExist:
|
|
snap = DocHistory(**fields)
|
|
snap.save()
|
|
for m in many2many:
|
|
#print "m2m:", m, many2many[m]
|
|
rel = getattr(snap, m)
|
|
for item in many2many[m]:
|
|
rel.add(item)
|
|
except DocHistory.MultipleObjectsReturned:
|
|
list = DocHistory.objects.filter(**dict((k,v) for k,v in fields.items() if k != 'time'))
|
|
list.delete()
|
|
snap = DocHistory(**fields)
|
|
snap.save()
|
|
print "Deleted list:", snap
|
|
super(Document, self).save(force_insert, force_update)
|
|
|
|
class DocHistory(DocumentInfo):
|
|
doc = models.ForeignKey(Document) # ID of the Document this relates to
|
|
def __unicode__(self):
|
|
return unicode(self.doc.name)
|
|
|
|
class DocAlias(models.Model):
|
|
"""This is used for documents that may appear under multiple names,
|
|
and in particular for RFCs, which for continuity still keep the
|
|
same immutable Document.name, in the tables, but will be referred
|
|
to by RFC number, primarily, after achieving RFC status.
|
|
"""
|
|
document = models.ForeignKey(Document)
|
|
name = models.CharField(max_length=255)
|
|
def __unicode__(self):
|
|
return "%s-->%s" % (self.name, self.document.name)
|
|
document_link = admin_link("document")
|
|
class Meta:
|
|
verbose_name_plural="Aliases"
|
|
|
|
class SendQueue(models.Model):
|
|
time = models.DateTimeField() # Scheduled at this time
|
|
agent = models.ForeignKey(Email) # Scheduled by this person
|
|
comment = models.TextField()
|
|
#
|
|
msg = models.ForeignKey('Message')
|
|
to = models.ForeignKey(Email, related_name='to_messages')
|
|
cc = models.ManyToManyField(Email, related_name='cc_messages')
|
|
send = models.DateTimeField() # Send message at this time
|
|
|
|
# class Ballot(models.Model): # A collection of ballot positions
|
|
# """A collection of ballot positions, and the actions taken during the
|
|
# lifetime of the ballot.
|
|
|
|
# The actual ballot positions are found by searching Messages for
|
|
# BallotPositions for this document between the dates indicated by
|
|
# self.initiated.time and (self.closed.time or now)
|
|
# """
|
|
# initiated = models.ForeignKey(Message, related_name="initiated_ballots")
|
|
# deferred = models.ForeignKey(Message, null=True, blank=True, related_name="deferred_ballots")
|
|
# last_call = models.ForeignKey(Message, null=True, blank=True, related_name="lastcalled_ballots")
|
|
# closed = models.ForeignKey(Message, null=True, blank=True, related_name="closed_ballots")
|
|
# announced = models.ForeignKey(Message, null=True, blank=True, related_name="announced_ballots")
|
|
|
|
|
|
EVENT_TYPES = [
|
|
# misc document events
|
|
("new_revision", "Added new revision"),
|
|
("document_changed", "Changed document"),
|
|
("tombstone_added", "Added tombstone"),
|
|
("requested_resurrect", "Requested resurrect"),
|
|
|
|
# IESG events
|
|
("sent_ballot_announcement", "Sent ballot announcement"),
|
|
("deferred_ballot", "Deferred ballot"),
|
|
("approved_ballot", "Approved ballot"),
|
|
("changed_ballot_position", "Changed ballot position"),
|
|
("changed_ballot_approval_text", "Changed ballot approval text"),
|
|
("changed_ballot_writeup_text", "Changed ballot writeup text"),
|
|
|
|
("changed_last_call_text", "Changed last call text"),
|
|
("sent_last_call", "Sent last call"),
|
|
|
|
("scheduled_for_telechat", "Scheduled for telechat"),
|
|
|
|
("resolved_to_do_not_publish", "Resolved to 'do not publish'"),
|
|
("resolved_to_no_problem", "Resolved to 'no problem'"),
|
|
|
|
("approved_in_minute", "Approved in minute"),
|
|
]
|
|
|
|
class Event(models.Model):
|
|
"""An occurrence in connection with a document."""
|
|
time = models.DateTimeField()
|
|
type = models.CharField(max_length=50, choices=EVENT_TYPES)
|
|
by = models.ForeignKey(Email, blank=True, null=True)
|
|
doc = models.ForeignKey('doc.Document')
|
|
desc = models.TextField()
|
|
|
|
def __unicode__(self):
|
|
return u"%s %s at %s" % (self.by.get_name(), self.get_type_display().lower(), self.time)
|
|
|
|
class Meta:
|
|
ordering = ['-time']
|
|
|
|
class Message(Event):
|
|
subj = models.CharField(max_length=255)
|
|
body = models.TextField()
|
|
|
|
class Text(Event):
|
|
content = models.TextField(blank=True)
|
|
|
|
# IESG events
|
|
class BallotPosition(Event):
|
|
ad = models.ForeignKey(Email)
|
|
pos = models.ForeignKey(BallotPositionName, verbose_name="position", default="norec")
|
|
discuss = models.TextField(help_text="Discuss text if position is discuss", blank=True)
|
|
discuss_time = models.DateTimeField(help_text="Time discuss text was written", blank=True, null=True)
|
|
comment = models.TextField(help_text="Optional comment", blank=True)
|
|
comment_time = models.DateTimeField(help_text="Time optional comment was written", blank=True, null=True)
|
|
|
|
class Expiration(Event):
|
|
expires = models.DateTimeField()
|
|
|
|
class Telechat(Event):
|
|
telechat_date = models.DateField()
|
|
returning_item = models.BooleanField(default=False)
|
|
|
|
|
|
|