Skip to content

Commit 91b3212

Browse files
committed
Merged in changes from the conversion branch
- Legacy-Id: 3188
2 parents 03bed41 + 4cff739 commit 91b3212

30 files changed

Lines changed: 4206 additions & 0 deletions

redesign/__init__.py

Whitespace-only changes.

redesign/doc/__init__.py

Whitespace-only changes.

redesign/doc/admin.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from django.contrib import admin
2+
from models import *
3+
from person.models import *
4+
5+
class DocumentAdmin(admin.ModelAdmin):
6+
list_display = ['name', 'rev', 'state', 'group', 'pages', 'intended_std_level', 'author_list', 'time']
7+
search_fields = ['name']
8+
raw_id_fields = ['authors', 'related', 'group', 'shepherd', 'ad']
9+
admin.site.register(Document, DocumentAdmin)
10+
11+
class DocHistoryAdmin(admin.ModelAdmin):
12+
list_display = ['doc', 'rev', 'state', 'group', 'pages', 'intended_std_level', 'author_list', 'time']
13+
search_fields = ['doc__name']
14+
ordering = ['time', 'doc', 'rev']
15+
raw_id_fields = ['doc', 'authors', 'related', 'group', 'shepherd', 'ad']
16+
admin.site.register(DocHistory, DocHistoryAdmin)
17+
18+
class DocAliasAdmin(admin.ModelAdmin):
19+
list_display = [ 'name', 'document_link', ]
20+
search_fields = [ 'name', 'document__name', ]
21+
raw_id_fields = ['document']
22+
admin.site.register(DocAlias, DocAliasAdmin)
23+
24+
25+
# events
26+
27+
class DocEventAdmin(admin.ModelAdmin):
28+
list_display = ["doc", "type", "by_raw", "time"]
29+
raw_id_fields = ["doc", "by"]
30+
31+
def by_raw(self, instance):
32+
return instance.by_id
33+
by_raw.short_description = "By"
34+
35+
admin.site.register(DocEvent, DocEventAdmin)
36+
37+
admin.site.register(NewRevisionDocEvent, DocEventAdmin)
38+
admin.site.register(WriteupDocEvent, DocEventAdmin)
39+
admin.site.register(StatusDateDocEvent, DocEventAdmin)
40+
admin.site.register(LastCallDocEvent, DocEventAdmin)
41+
admin.site.register(TelechatDocEvent, DocEventAdmin)
42+
43+
class BallotPositionDocEventAdmin(DocEventAdmin):
44+
raw_id_fields = ["doc", "by", "ad"]
45+
46+
admin.site.register(BallotPositionDocEvent, BallotPositionDocEventAdmin)
47+

redesign/doc/models.py

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
# Copyright The IETF Trust 2007, All Rights Reserved
2+
3+
from django.db import models
4+
from django.core.urlresolvers import reverse as urlreverse
5+
6+
from redesign.group.models import *
7+
from redesign.name.models import *
8+
from redesign.person.models import Email, Person
9+
from redesign.util import admin_link
10+
11+
import datetime
12+
13+
class DocumentInfo(models.Model):
14+
"""Any kind of document. Draft, RFC, Charter, IPR Statement, Liaison Statement"""
15+
time = models.DateTimeField(default=datetime.datetime.now) # should probably have auto_now=True
16+
# Document related
17+
type = models.ForeignKey(DocTypeName, blank=True, null=True) # Draft, Agenda, Minutes, Charter, Discuss, Guideline, Email, Review, Issue, Wiki, External ...
18+
title = models.CharField(max_length=255)
19+
# State
20+
state = models.ForeignKey(DocStateName, blank=True, null=True) # Active/Expired/RFC/Replaced/Withdrawn
21+
tags = models.ManyToManyField(DocInfoTagName, blank=True, null=True) # Revised ID Needed, ExternalParty, AD Followup, ...
22+
stream = models.ForeignKey(DocStreamName, blank=True, null=True) # IETF, IAB, IRTF, Independent Submission
23+
group = models.ForeignKey(Group, blank=True, null=True) # WG, RG, IAB, IESG, Edu, Tools
24+
wg_state = models.ForeignKey(WgDocStateName, verbose_name="WG state", blank=True, null=True) # Not/Candidate/Active/Parked/LastCall/WriteUp/Submitted/Dead
25+
iesg_state = models.ForeignKey(IesgDocStateName, verbose_name="IESG state", blank=True, null=True) #
26+
iana_state = models.ForeignKey(IanaDocStateName, verbose_name="IANA state", blank=True, null=True)
27+
rfc_state = models.ForeignKey(RfcDocStateName, verbose_name="RFC state", blank=True, null=True)
28+
# Other
29+
abstract = models.TextField()
30+
rev = models.CharField(verbose_name="revision", max_length=16, blank=True)
31+
pages = models.IntegerField(blank=True, null=True)
32+
intended_std_level = models.ForeignKey(IntendedStdLevelName, blank=True, null=True)
33+
std_level = models.ForeignKey(StdLevelName, blank=True, null=True)
34+
ad = models.ForeignKey(Person, verbose_name="area director", related_name='ad_%(class)s_set', blank=True, null=True)
35+
shepherd = models.ForeignKey(Person, related_name='shepherd_%(class)s_set', blank=True, null=True)
36+
notify = models.CharField(max_length=255, blank=True)
37+
external_url = models.URLField(blank=True) # Should be set for documents with type 'External'.
38+
note = models.TextField(blank=True)
39+
internal_comments = models.TextField(blank=True)
40+
41+
class Meta:
42+
abstract = True
43+
def author_list(self):
44+
return ", ".join(email.address for email in self.authors.all())
45+
46+
class RelatedDocument(models.Model):
47+
source = models.ForeignKey('Document')
48+
target = models.ForeignKey('DocAlias')
49+
relationship = models.ForeignKey(DocRelationshipName)
50+
def action(self):
51+
return self.relationship.name
52+
def inverse_action():
53+
infinitive = self.relationship.name[:-1]
54+
return u"%sd by" % infinitive
55+
def __unicode__(self):
56+
return u"%s %s %s" % (self.source.name, self.relationship.name.lower(), self.target.name)
57+
58+
class DocumentAuthor(models.Model):
59+
document = models.ForeignKey('Document')
60+
author = models.ForeignKey(Email, help_text="Email address used by author for submission")
61+
order = models.IntegerField(default=1)
62+
63+
def __unicode__(self):
64+
return u"%s %s (%s)" % (self.document.name, self.author.get_name(), self.order)
65+
66+
class Meta:
67+
ordering = ["document", "order"]
68+
69+
class Document(DocumentInfo):
70+
name = models.CharField(max_length=255, primary_key=True) # immutable
71+
related = models.ManyToManyField('DocAlias', through=RelatedDocument, blank=True, related_name="reversely_related_document_set")
72+
authors = models.ManyToManyField(Email, through=DocumentAuthor, blank=True)
73+
74+
def __unicode__(self):
75+
return self.name
76+
77+
def get_absolute_url(self):
78+
name = self.name
79+
if self.state == "rfc":
80+
aliases = self.docalias_set.filter(name__startswith="rfc")
81+
if aliases:
82+
name = aliases[0].name
83+
return urlreverse('doc_view', kwargs={ 'name': name })
84+
85+
def file_tag(self):
86+
return u"<%s>" % self.filename_with_rev()
87+
88+
def filename_with_rev(self):
89+
# FIXME: compensate for tombstones?
90+
return u"%s-%s.txt" % (self.name, self.rev)
91+
92+
def latest_event(self, *args, **filter_args):
93+
"""Get latest event of optional Python type and with filter
94+
arguments, e.g. d.latest_event(type="xyz") returns an DocEvent
95+
while d.latest_event(WriteupDocEvent, type="xyz") returns a
96+
WriteupDocEvent event."""
97+
model = args[0] if args else DocEvent
98+
e = model.objects.filter(doc=self).filter(**filter_args).order_by('-time', '-id')[:1]
99+
return e[0] if e else None
100+
101+
def canonical_name(self):
102+
name = self.name
103+
if self.type_id == "draft" and self.state_id == "rfc":
104+
a = self.docalias_set.filter(name__startswith="rfc")
105+
if a:
106+
name = a[0].name
107+
return name
108+
109+
110+
class RelatedDocHistory(models.Model):
111+
source = models.ForeignKey('DocHistory')
112+
target = models.ForeignKey('DocAlias', related_name="reversely_related_document_history_set")
113+
relationship = models.ForeignKey(DocRelationshipName)
114+
def __unicode__(self):
115+
return u"%s %s %s" % (self.source.doc.name, self.relationship.name.lower(), self.target.name)
116+
117+
class DocHistoryAuthor(models.Model):
118+
document = models.ForeignKey('DocHistory')
119+
author = models.ForeignKey(Email)
120+
order = models.IntegerField()
121+
122+
def __unicode__(self):
123+
return u"%s %s (%s)" % (self.document.doc.name, self.author.get_name(), self.order)
124+
125+
class Meta:
126+
ordering = ["document", "order"]
127+
128+
class DocHistory(DocumentInfo):
129+
doc = models.ForeignKey(Document) # ID of the Document this relates to
130+
# Django 1.2 won't let us define these in the base class, so we have
131+
# to repeat them
132+
related = models.ManyToManyField('DocAlias', through=RelatedDocHistory, blank=True)
133+
authors = models.ManyToManyField(Email, through=DocHistoryAuthor, blank=True)
134+
def __unicode__(self):
135+
return unicode(self.doc.name)
136+
137+
def save_document_in_history(doc):
138+
def get_model_fields_as_dict(obj):
139+
return dict((field.name, getattr(obj, field.name))
140+
for field in obj._meta.fields
141+
if field is not obj._meta.pk)
142+
143+
# copy fields
144+
fields = get_model_fields_as_dict(doc)
145+
fields["doc"] = doc
146+
147+
dochist = DocHistory(**fields)
148+
dochist.save()
149+
150+
# copy many to many
151+
for field in doc._meta.many_to_many:
152+
if not field.rel.through:
153+
# just add the attributes
154+
rel = getattr(dochist, field.name)
155+
for item in getattr(doc, field.name).all():
156+
rel.add(item)
157+
158+
# copy remaining tricky many to many
159+
def transfer_fields(obj, HistModel):
160+
mfields = get_model_fields_as_dict(item)
161+
# map doc -> dochist
162+
for k, v in mfields.iteritems():
163+
if v == doc:
164+
mfields[k] = dochist
165+
HistModel.objects.create(**mfields)
166+
167+
for item in RelatedDocument.objects.filter(source=doc):
168+
transfer_fields(item, RelatedDocHistory)
169+
170+
for item in DocumentAuthor.objects.filter(document=doc):
171+
transfer_fields(item, DocHistoryAuthor)
172+
173+
return dochist
174+
175+
class DocAlias(models.Model):
176+
"""This is used for documents that may appear under multiple names,
177+
and in particular for RFCs, which for continuity still keep the
178+
same immutable Document.name, in the tables, but will be referred
179+
to by RFC number, primarily, after achieving RFC status.
180+
"""
181+
document = models.ForeignKey(Document)
182+
name = models.CharField(max_length=255, db_index=True)
183+
def __unicode__(self):
184+
return "%s-->%s" % (self.name, self.document.name)
185+
document_link = admin_link("document")
186+
class Meta:
187+
verbose_name = "document alias"
188+
verbose_name_plural = "document aliases"
189+
190+
191+
EVENT_TYPES = [
192+
# core events
193+
("new_revision", "Added new revision"),
194+
("changed_document", "Changed document metadata"),
195+
196+
# misc document events
197+
("added_comment", "Added comment"),
198+
("expired_document", "Expired document"),
199+
("requested_resurrect", "Requested resurrect"),
200+
("completed_resurrect", "Completed resurrect"),
201+
("published_rfc", "Published RFC"),
202+
203+
# IESG events
204+
("started_iesg_process", "Started IESG process on document"),
205+
206+
("sent_ballot_announcement", "Sent ballot announcement"),
207+
("changed_ballot_position", "Changed ballot position"),
208+
209+
("changed_ballot_approval_text", "Changed ballot approval text"),
210+
("changed_ballot_writeup_text", "Changed ballot writeup text"),
211+
212+
("changed_last_call_text", "Changed last call text"),
213+
("requested_last_call", "Requested last call"),
214+
("sent_last_call", "Sent last call"),
215+
216+
("changed_status_date", "Changed status date"),
217+
218+
("scheduled_for_telechat", "Scheduled for telechat"),
219+
220+
("iesg_approved", "IESG approved document (no problem)"),
221+
("iesg_disapproved", "IESG disapproved document (do not publish)"),
222+
223+
("approved_in_minute", "Approved in minute"),
224+
]
225+
226+
class DocEvent(models.Model):
227+
"""An occurrence for a document, used for tracking who, when and what."""
228+
time = models.DateTimeField(default=datetime.datetime.now, help_text="When the event happened")
229+
type = models.CharField(max_length=50, choices=EVENT_TYPES)
230+
by = models.ForeignKey(Person)
231+
doc = models.ForeignKey('doc.Document')
232+
desc = models.TextField()
233+
234+
def __unicode__(self):
235+
return u"%s %s at %s" % (self.by.name, self.get_type_display().lower(), self.time)
236+
237+
class Meta:
238+
ordering = ['-time', '-id']
239+
240+
class NewRevisionDocEvent(DocEvent):
241+
rev = models.CharField(max_length=16)
242+
243+
# IESG events
244+
class BallotPositionDocEvent(DocEvent):
245+
ad = models.ForeignKey(Person)
246+
pos = models.ForeignKey(BallotPositionName, verbose_name="position", default="norecord")
247+
discuss = models.TextField(help_text="Discuss text if position is discuss", blank=True)
248+
discuss_time = models.DateTimeField(help_text="Time discuss text was written", blank=True, null=True)
249+
comment = models.TextField(help_text="Optional comment", blank=True)
250+
comment_time = models.DateTimeField(help_text="Time optional comment was written", blank=True, null=True)
251+
252+
class WriteupDocEvent(DocEvent):
253+
text = models.TextField(blank=True)
254+
255+
class StatusDateDocEvent(DocEvent):
256+
date = models.DateField(blank=True, null=True)
257+
258+
class LastCallDocEvent(DocEvent):
259+
expires = models.DateTimeField(blank=True, null=True)
260+
261+
class TelechatDocEvent(DocEvent):
262+
telechat_date = models.DateField(blank=True, null=True)
263+
returning_item = models.BooleanField(default=False)
264+

0 commit comments

Comments
 (0)