Merged branch/iola/statesync up to @5118 to trunk.
- Legacy-Id: 5147
This commit is contained in:
commit
1fbcd783f3
35
ietf/bin/email-sync-discrepancies
Executable file
35
ietf/bin/email-sync-discrepancies
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys, os
|
||||
import syslog
|
||||
|
||||
# boilerplate
|
||||
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
|
||||
sys.path = [ basedir ] + sys.path
|
||||
|
||||
from ietf import settings
|
||||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
|
||||
from optparse import OptionParser
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option("-t", "--to", dest="to",
|
||||
help="Email address to send report to", metavar="EMAIL")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
|
||||
syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_LOCAL0)
|
||||
|
||||
from ietf.sync.mails import email_discrepancies
|
||||
|
||||
receivers = ["iesg-secretary@ietf.org"]
|
||||
|
||||
if options.to:
|
||||
receivers = [options.to]
|
||||
|
||||
email_discrepancies(receivers)
|
||||
|
||||
syslog.syslog("Emailed sync discrepancies to %s" % receivers)
|
67
ietf/bin/iana-changes-updates
Executable file
67
ietf/bin/iana-changes-updates
Executable file
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os, sys, re, json, datetime, optparse
|
||||
import syslog
|
||||
|
||||
# boilerplate
|
||||
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
|
||||
sys.path = [ basedir ] + sys.path
|
||||
|
||||
from ietf import settings
|
||||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
|
||||
from optparse import OptionParser
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option("-f", "--from", dest="start",
|
||||
help="Start time, defaults to a little less than 23 hours ago", metavar="YYYY-MM-DD HH:MM:SS")
|
||||
parser.add_option("-t", "--to", dest="end",
|
||||
help="End time, defaults to 23 hours later than from", metavar="YYYY-MM-DD HH:MM:SS")
|
||||
parser.add_option("", "--no-email", dest="send_email", default=True, action="store_false",
|
||||
help="Skip sending emails")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
# compensate to avoid we ask for something that happened now and then
|
||||
# don't get it back because our request interval is slightly off
|
||||
CLOCK_SKEW_COMPENSATION = 5 # seconds
|
||||
|
||||
# actually the interface accepts 24 hours, but then we get into
|
||||
# trouble with daylights savings - meh
|
||||
MAX_INTERVAL_ACCEPTED_BY_IANA = datetime.timedelta(hours=23)
|
||||
|
||||
|
||||
start = datetime.datetime.now() - datetime.timedelta(hours=23) + datetime.timedelta(seconds=CLOCK_SKEW_COMPENSATION)
|
||||
if options.start:
|
||||
start = datetime.datetime.strptime(options.start, "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
end = start + datetime.timedelta(hours=23)
|
||||
if options.end:
|
||||
end = datetime.datetime.strptime(options.end, "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_LOCAL0)
|
||||
|
||||
|
||||
from ietf.sync.iana import *
|
||||
|
||||
syslog.syslog("Updating history log with new changes from IANA from %s, period %s - %s" % (CHANGES_URL, start, end))
|
||||
|
||||
t = start
|
||||
while t < end:
|
||||
# the IANA server doesn't allow us to fetch more than a certain
|
||||
# period, so loop over the requested period and make multiple
|
||||
# requests if necessary
|
||||
|
||||
text = fetch_changes_json(CHANGES_URL, t, min(end, t + MAX_INTERVAL_ACCEPTED_BY_IANA))
|
||||
changes = parse_changes_json(text)
|
||||
added_events, warnings = update_history_with_changes(changes, send_email=options.send_email)
|
||||
|
||||
for e in added_events:
|
||||
syslog.syslog("Added event for %s %s: %s" % (e.doc_id, e.time, e.desc))
|
||||
|
||||
for w in warnings:
|
||||
syslog.syslog("WARNING: %s" % w)
|
||||
|
||||
t += MAX_INTERVAL_ACCEPTED_BY_IANA
|
34
ietf/bin/iana-protocols-updates
Executable file
34
ietf/bin/iana-protocols-updates
Executable file
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os, sys, re, json, datetime
|
||||
import syslog
|
||||
|
||||
syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_LOCAL0)
|
||||
|
||||
# boilerplate
|
||||
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
|
||||
sys.path = [ basedir ] + sys.path
|
||||
|
||||
from ietf import settings
|
||||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
|
||||
from ietf.sync.iana import *
|
||||
|
||||
def chunks(l, n):
|
||||
"""Split list l up in chunks of max size n."""
|
||||
return (l[i:i+n] for i in xrange(0, len(l), n))
|
||||
|
||||
syslog.syslog("Updating history log with new RFC entries from IANA protocols page %s" % PROTOCOLS_URL)
|
||||
|
||||
# FIXME: this needs to be the date where this tool is first deployed
|
||||
rfc_must_published_later_than = datetime.datetime(2012, 11, 26, 0, 0, 0)
|
||||
|
||||
text = fetch_protocol_page(PROTOCOLS_URL)
|
||||
rfc_numbers = parse_protocol_page(text)
|
||||
for chunk in chunks(rfc_numbers, 100):
|
||||
updated = update_rfc_log_from_protocol_page(chunk, rfc_must_published_later_than)
|
||||
|
||||
for d in updated:
|
||||
syslog.syslog("Added history entry for %s" % d.display_name())
|
33
ietf/bin/iana-review-email
Executable file
33
ietf/bin/iana-review-email
Executable file
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os, sys, re, json, datetime, optparse
|
||||
import syslog
|
||||
|
||||
# boilerplate
|
||||
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
|
||||
sys.path = [ basedir ] + sys.path
|
||||
|
||||
from ietf import settings
|
||||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
|
||||
syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_LOCAL0)
|
||||
|
||||
from ietf.sync.iana import *
|
||||
from ietf.doc.models import Document
|
||||
|
||||
msg = sys.stdin.read()
|
||||
|
||||
doc_name, review_time, by, comment = parse_review_email(msg)
|
||||
|
||||
syslog.syslog(u"Read IANA review email for %s at %s by %s" % (doc_name, review_time, by))
|
||||
|
||||
if by.name == "(System)":
|
||||
syslog.syslog("WARNING: person responsible for email does not have a IANA role")
|
||||
|
||||
try:
|
||||
add_review_comment(doc_name, review_time, by, comment)
|
||||
except Document.DoesNotExist:
|
||||
syslog.syslog("ERROR: unknown document %s" % doc_name)
|
||||
|
42
ietf/bin/rfc-editor-index-updates
Executable file
42
ietf/bin/rfc-editor-index-updates
Executable file
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os, sys, re, json, datetime
|
||||
import syslog
|
||||
|
||||
syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_LOCAL0)
|
||||
|
||||
# boilerplate
|
||||
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
|
||||
sys.path = [ basedir ] + sys.path
|
||||
|
||||
from ietf import settings
|
||||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
|
||||
from optparse import OptionParser
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option("-d", dest="skip_date",
|
||||
help="To speed up processing skip RFCs published before this date (default is one year ago)", metavar="YYYY-MM-DD")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
skip_date = datetime.date.today() - datetime.timedelta(days=365)
|
||||
if options.skip_date:
|
||||
skip_date = datetime.datetime.strptime(options.skip_date, "%Y-%m-%d").date()
|
||||
|
||||
from ietf.sync.rfceditor import *
|
||||
|
||||
syslog.syslog("Updating document metadata from RFC index from %s" % QUEUE_URL)
|
||||
|
||||
response = fetch_index_xml(INDEX_URL)
|
||||
data = parse_index(response)
|
||||
|
||||
if len(data) < MIN_INDEX_RESULTS:
|
||||
syslog.syslog("Not enough results, only %s" % len(data))
|
||||
sys.exit(1)
|
||||
|
||||
changed = update_docs_from_rfc_index(data, skip_older_than_date=skip_date)
|
||||
for c in changed:
|
||||
syslog.syslog(c)
|
35
ietf/bin/rfc-editor-queue-updates
Executable file
35
ietf/bin/rfc-editor-queue-updates
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os, sys, re, json, datetime
|
||||
import syslog
|
||||
|
||||
syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_LOCAL0)
|
||||
|
||||
# boilerplate
|
||||
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
|
||||
sys.path = [ basedir ] + sys.path
|
||||
|
||||
from ietf import settings
|
||||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
|
||||
from ietf.sync.rfceditor import *
|
||||
|
||||
syslog.syslog("Updating RFC Editor queue states from %s" % QUEUE_URL)
|
||||
|
||||
response = fetch_queue_xml(QUEUE_URL)
|
||||
drafts, warnings = parse_queue(response)
|
||||
for w in warnings:
|
||||
syslog.syslog(u"WARNING: %s" % w)
|
||||
|
||||
if len(drafts) < MIN_QUEUE_RESULTS:
|
||||
syslog.syslog("Not enough results, only %s" % len(drafts))
|
||||
sys.exit(1)
|
||||
|
||||
changed, warnings = update_drafts_from_queue(drafts)
|
||||
for w in warnings:
|
||||
syslog.syslog(u"WARNING: %s" % w)
|
||||
|
||||
for c in changed:
|
||||
syslog.syslog(u"Updated %s" % c)
|
|
@ -142,6 +142,8 @@ class DocEventAdmin(admin.ModelAdmin):
|
|||
admin.site.register(DocEvent, DocEventAdmin)
|
||||
|
||||
admin.site.register(NewRevisionDocEvent, DocEventAdmin)
|
||||
admin.site.register(StateDocEvent, DocEventAdmin)
|
||||
admin.site.register(ConsensusDocEvent, DocEventAdmin)
|
||||
admin.site.register(BallotDocEvent, DocEventAdmin)
|
||||
admin.site.register(WriteupDocEvent, DocEventAdmin)
|
||||
admin.site.register(LastCallDocEvent, DocEventAdmin)
|
||||
|
|
|
@ -0,0 +1,377 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding model 'StateDocEvent'
|
||||
db.create_table('doc_statedocevent', (
|
||||
('docevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['doc.DocEvent'], unique=True, primary_key=True)),
|
||||
('state_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.StateType'])),
|
||||
('state', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.State'], null=True, blank=True)),
|
||||
))
|
||||
db.send_create_signal('doc', ['StateDocEvent'])
|
||||
|
||||
# Adding model 'ConsensusDocEvent'
|
||||
db.create_table('doc_consensusdocevent', (
|
||||
('docevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['doc.DocEvent'], unique=True, primary_key=True)),
|
||||
('consensus', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||
))
|
||||
db.send_create_signal('doc', ['ConsensusDocEvent'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'StateDocEvent'
|
||||
db.delete_table('doc_statedocevent')
|
||||
|
||||
# Deleting model 'ConsensusDocEvent'
|
||||
db.delete_table('doc_consensusdocevent')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'doc.ballotdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ballot_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.BallotType']"}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.ballotpositiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotPositionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['doc.BallotDocEvent']", 'null': 'True'}),
|
||||
'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'comment_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'discuss': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'discuss_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'pos': ('django.db.models.fields.related.ForeignKey', [], {'default': "'norecord'", 'to': "orm['name.BallotPositionName']"})
|
||||
},
|
||||
'doc.ballottype': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'BallotType'},
|
||||
'doc_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'positions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.BallotPositionName']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'question': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'doc.consensusdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'ConsensusDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'consensus': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.docalias': {
|
||||
'Meta': {'object_name': 'DocAlias'},
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
|
||||
},
|
||||
'doc.docevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'DocEvent'},
|
||||
'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'desc': ('django.db.models.fields.TextField', [], {}),
|
||||
'doc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'doc.dochistory': {
|
||||
'Meta': {'object_name': 'DocHistory'},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocHistoryAuthor']", 'blank': 'True'}),
|
||||
'doc': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['doc.Document']"}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
|
||||
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", 'symmetrical': 'False', 'through': "orm['doc.RelatedDocHistory']", 'blank': 'True'}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
|
||||
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.dochistoryauthor': {
|
||||
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocHistoryAuthor'},
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'doc.docreminder': {
|
||||
'Meta': {'object_name': 'DocReminder'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'due': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'event': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocEvent']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocReminderTypeName']"})
|
||||
},
|
||||
'doc.document': {
|
||||
'Meta': {'object_name': 'Document'},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
|
||||
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'reversely_related_document_set'", 'blank': 'True', 'through': "orm['doc.RelatedDocument']", 'to': "orm['doc.DocAlias']"}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
|
||||
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.documentauthor': {
|
||||
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'},
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1'})
|
||||
},
|
||||
'doc.initialreviewdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'InitialReviewDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.lastcalldocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'LastCallDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.newrevisiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'NewRevisionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16'})
|
||||
},
|
||||
'doc.relateddochistory': {
|
||||
'Meta': {'object_name': 'RelatedDocHistory'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
|
||||
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reversely_related_document_history_set'", 'to': "orm['doc.DocAlias']"})
|
||||
},
|
||||
'doc.relateddocument': {
|
||||
'Meta': {'object_name': 'RelatedDocument'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
|
||||
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocAlias']"})
|
||||
},
|
||||
'doc.state': {
|
||||
'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'previous_states'", 'symmetrical': 'False', 'to': "orm['doc.State']"}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'doc.statedocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'StateDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.State']", 'null': 'True', 'blank': 'True'}),
|
||||
'state_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"})
|
||||
},
|
||||
'doc.statetype': {
|
||||
'Meta': {'object_name': 'StateType'},
|
||||
'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.telechatdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'TelechatDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'returning_item': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'telechat_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.writeupdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'WriteupDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'text': ('django.db.models.fields.TextField', [], {'blank': 'True'})
|
||||
},
|
||||
'group.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}),
|
||||
'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
|
||||
'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}),
|
||||
'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'name.ballotpositionname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'BallotPositionName'},
|
||||
'blocking': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.docrelationshipname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocRelationshipName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.docremindertypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocReminderTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctagname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.groupstatename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.grouptypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.intendedstdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.stdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.streamname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StreamName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'person.email': {
|
||||
'Meta': {'object_name': 'Email'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}),
|
||||
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'person.person': {
|
||||
'Meta': {'object_name': 'Person'},
|
||||
'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['doc']
|
387
ietf/doc/migrations/0006_add_iana_rfc_editor_states.py
Normal file
387
ietf/doc/migrations/0006_add_iana_rfc_editor_states.py
Normal file
|
@ -0,0 +1,387 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
t = orm.StateType.objects.get_or_create(slug="draft-iana-action", label="IANA Action state")[0]
|
||||
orm.State.objects.get_or_create(type=t, slug='newdoc', name='New Document', desc="A new document has been received by IANA, but no actions have been taken", order=1)
|
||||
orm.State.objects.get_or_create(type=t, slug='inprog', name='In Progress', desc="IANA is currently processing the actions for this document", order=2)
|
||||
orm.State.objects.get_or_create(type=t, slug='waitauth', name='Waiting on Authors', desc="IANA is waiting on the document's authors to respond", order=3)
|
||||
orm.State.objects.get_or_create(type=t, slug='waitad', name='Waiting on ADs', desc="IANA is waiting on the IETF Area Directors to respond", order=4)
|
||||
orm.State.objects.get_or_create(type=t, slug='waitwgc', name='Waiting on WGC', desc="IANA is waiting on the IETF Working Group Chairs to respond", order=5)
|
||||
orm.State.objects.get_or_create(type=t, slug='waitrfc', name='Waiting on RFC Editor', desc="IANA has notified the RFC Editor that the actions have been completed", order=6)
|
||||
orm.State.objects.get_or_create(type=t, slug='rfcedack', name='RFC-Ed-Ack', desc="Request completed. The RFC Editor has acknowledged receipt of IANA's message that the actions have been completed", order=7)
|
||||
orm.State.objects.get_or_create(type=t, slug='onhold', name='On Hold', desc="IANA has suspended work on the document", order=8)
|
||||
orm.State.objects.get_or_create(type=t, slug='noic', name='No IC', desc="Request completed. There were no IANA actions for this document", order=9)
|
||||
|
||||
t = orm.StateType.objects.get_or_create(slug="draft-iana-review", label="IANA Review state")[0]
|
||||
orm.State.objects.get_or_create(type=t, slug="need-rev", name='IANA Review Needed', desc="Document has not yet been reviewed by IANA.", order=1)
|
||||
orm.State.objects.get_or_create(type=t, slug="ok-act", name='IANA OK - Actions Needed', desc="Document requires IANA actions, and the IANA Considerations section indicates the details of the actions correctly.", order=2)
|
||||
orm.State.objects.get_or_create(type=t, slug="ok-noact", name='IANA OK - No Actions Needed', desc="Document requires no IANA action, and the IANA Considerations section indicates this correctly.", order=3)
|
||||
orm.State.objects.get_or_create(type=t, slug="not-ok", name='IANA Not OK', desc="IANA has issues with the text of the IANA Considerations section of the document.", order=4)
|
||||
orm.State.objects.get_or_create(type=t, slug="changed", name='Version Changed - Review Needed', desc="Document revision has changed after review by IANA.", order=5)
|
||||
|
||||
# fixup RFC Editor states/tags
|
||||
orm.State.objects.filter(type="draft-rfceditor", slug="edit").update(desc="Awaiting editing or being edited")
|
||||
orm.State.objects.filter(type="draft-rfceditor", slug="iesg").update(desc="Awaiting IESG action")
|
||||
orm.State.objects.filter(type="draft-rfceditor", slug="isr-auth").update(desc="Independent submission awaiting author action, or in discussion between author and ISE")
|
||||
orm.State.objects.filter(type="draft-rfceditor", slug="iana-crd").update(slug="iana", desc="Document has been edited, but is holding for completion of IANA actions")
|
||||
orm.State.objects.get_or_create(type_id="draft-rfceditor", slug="auth48-done", defaults=dict(name="AUTH48-DONE", desc="Final approvals are complete"))
|
||||
|
||||
orm["name.DocTagName"].objects.get_or_create(slug="iana", name="IANA", desc="The document has IANA actions that are not yet completed.")
|
||||
for d in orm.Document.objects.filter(type="draft", tags="iana-crd"):
|
||||
d.tags.remove("iana-crd")
|
||||
d.tags.add("iana")
|
||||
|
||||
orm["name.DocTagName"].objects.filter(slug="iana-crd").delete()
|
||||
|
||||
def backwards(self, orm):
|
||||
"Write your backwards methods here."
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'doc.ballotdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ballot_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.BallotType']"}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.ballotpositiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotPositionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['doc.BallotDocEvent']", 'null': 'True'}),
|
||||
'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'comment_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'discuss': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'discuss_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'pos': ('django.db.models.fields.related.ForeignKey', [], {'default': "'norecord'", 'to': "orm['name.BallotPositionName']"})
|
||||
},
|
||||
'doc.ballottype': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'BallotType'},
|
||||
'doc_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'positions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.BallotPositionName']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'question': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'doc.consensusdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'ConsensusDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'consensus': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.docalias': {
|
||||
'Meta': {'object_name': 'DocAlias'},
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
|
||||
},
|
||||
'doc.docevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'DocEvent'},
|
||||
'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'desc': ('django.db.models.fields.TextField', [], {}),
|
||||
'doc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'doc.dochistory': {
|
||||
'Meta': {'object_name': 'DocHistory'},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocHistoryAuthor']", 'blank': 'True'}),
|
||||
'doc': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['doc.Document']"}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
|
||||
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", 'symmetrical': 'False', 'through': "orm['doc.RelatedDocHistory']", 'blank': 'True'}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
|
||||
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.dochistoryauthor': {
|
||||
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocHistoryAuthor'},
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'doc.docreminder': {
|
||||
'Meta': {'object_name': 'DocReminder'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'due': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'event': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocEvent']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocReminderTypeName']"})
|
||||
},
|
||||
'doc.document': {
|
||||
'Meta': {'object_name': 'Document'},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
|
||||
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'reversely_related_document_set'", 'blank': 'True', 'through': "orm['doc.RelatedDocument']", 'to': "orm['doc.DocAlias']"}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
|
||||
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.documentauthor': {
|
||||
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'},
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1'})
|
||||
},
|
||||
'doc.initialreviewdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'InitialReviewDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.lastcalldocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'LastCallDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.newrevisiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'NewRevisionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16'})
|
||||
},
|
||||
'doc.relateddochistory': {
|
||||
'Meta': {'object_name': 'RelatedDocHistory'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
|
||||
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reversely_related_document_history_set'", 'to': "orm['doc.DocAlias']"})
|
||||
},
|
||||
'doc.relateddocument': {
|
||||
'Meta': {'object_name': 'RelatedDocument'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
|
||||
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocAlias']"})
|
||||
},
|
||||
'doc.state': {
|
||||
'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'previous_states'", 'symmetrical': 'False', 'to': "orm['doc.State']"}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'doc.statedocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'StateDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.State']", 'null': 'True', 'blank': 'True'}),
|
||||
'state_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"})
|
||||
},
|
||||
'doc.statetype': {
|
||||
'Meta': {'object_name': 'StateType'},
|
||||
'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.telechatdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'TelechatDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'returning_item': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'telechat_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.writeupdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'WriteupDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'text': ('django.db.models.fields.TextField', [], {'blank': 'True'})
|
||||
},
|
||||
'group.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}),
|
||||
'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
|
||||
'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}),
|
||||
'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'name.ballotpositionname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'BallotPositionName'},
|
||||
'blocking': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.docrelationshipname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocRelationshipName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.docremindertypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocReminderTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctagname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.groupstatename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.grouptypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.intendedstdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.stdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.streamname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StreamName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'person.email': {
|
||||
'Meta': {'object_name': 'Email'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}),
|
||||
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'person.person': {
|
||||
'Meta': {'object_name': 'Person'},
|
||||
'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['doc']
|
374
ietf/doc/migrations/0007_fix_groups_of_alternate_stream_docs.py
Normal file
374
ietf/doc/migrations/0007_fix_groups_of_alternate_stream_docs.py
Normal file
|
@ -0,0 +1,374 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# IAB
|
||||
iab = orm["group.Group"].objects.get(acronym="iab")
|
||||
orm.Document.objects.filter(stream="iab").update(group=iab)
|
||||
|
||||
# IRTF
|
||||
rgs = {}
|
||||
for d in orm.Document.objects.filter(stream="irtf"):
|
||||
acronym = d.name.split("-")[2]
|
||||
if acronym not in rgs:
|
||||
try:
|
||||
rgs[acronym] = orm["group.Group"].objects.get(acronym=acronym, type="rg")
|
||||
except orm["group.Group"].DoesNotExist:
|
||||
rgs[acronym] = None
|
||||
|
||||
rg = rgs[acronym]
|
||||
if rg:
|
||||
d.group = rg
|
||||
d.save()
|
||||
|
||||
def backwards(self, orm):
|
||||
"Write your backwards methods here."
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'doc.ballotdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ballot_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.BallotType']"}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.ballotpositiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotPositionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['doc.BallotDocEvent']", 'null': 'True'}),
|
||||
'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'comment_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'discuss': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'discuss_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'pos': ('django.db.models.fields.related.ForeignKey', [], {'default': "'norecord'", 'to': "orm['name.BallotPositionName']"})
|
||||
},
|
||||
'doc.ballottype': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'BallotType'},
|
||||
'doc_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'positions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.BallotPositionName']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'question': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'doc.consensusdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'ConsensusDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'consensus': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.docalias': {
|
||||
'Meta': {'object_name': 'DocAlias'},
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
|
||||
},
|
||||
'doc.docevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'DocEvent'},
|
||||
'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'desc': ('django.db.models.fields.TextField', [], {}),
|
||||
'doc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'doc.dochistory': {
|
||||
'Meta': {'object_name': 'DocHistory'},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocHistoryAuthor']", 'blank': 'True'}),
|
||||
'doc': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['doc.Document']"}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
|
||||
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", 'symmetrical': 'False', 'through': "orm['doc.RelatedDocHistory']", 'blank': 'True'}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
|
||||
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.dochistoryauthor': {
|
||||
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocHistoryAuthor'},
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'doc.docreminder': {
|
||||
'Meta': {'object_name': 'DocReminder'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'due': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'event': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocEvent']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocReminderTypeName']"})
|
||||
},
|
||||
'doc.document': {
|
||||
'Meta': {'object_name': 'Document'},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
|
||||
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'reversely_related_document_set'", 'blank': 'True', 'through': "orm['doc.RelatedDocument']", 'to': "orm['doc.DocAlias']"}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
|
||||
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.documentauthor': {
|
||||
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'},
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1'})
|
||||
},
|
||||
'doc.initialreviewdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'InitialReviewDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.lastcalldocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'LastCallDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.newrevisiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'NewRevisionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16'})
|
||||
},
|
||||
'doc.relateddochistory': {
|
||||
'Meta': {'object_name': 'RelatedDocHistory'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
|
||||
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reversely_related_document_history_set'", 'to': "orm['doc.DocAlias']"})
|
||||
},
|
||||
'doc.relateddocument': {
|
||||
'Meta': {'object_name': 'RelatedDocument'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
|
||||
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocAlias']"})
|
||||
},
|
||||
'doc.state': {
|
||||
'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'previous_states'", 'blank': 'True', 'to': "orm['doc.State']"}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'doc.statedocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'StateDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.State']", 'null': 'True', 'blank': 'True'}),
|
||||
'state_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"})
|
||||
},
|
||||
'doc.statetype': {
|
||||
'Meta': {'object_name': 'StateType'},
|
||||
'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.telechatdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'TelechatDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'returning_item': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'telechat_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.writeupdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'WriteupDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'text': ('django.db.models.fields.TextField', [], {'blank': 'True'})
|
||||
},
|
||||
'group.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}),
|
||||
'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
|
||||
'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}),
|
||||
'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'name.ballotpositionname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'BallotPositionName'},
|
||||
'blocking': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.docrelationshipname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocRelationshipName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.docremindertypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocReminderTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctagname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.groupstatename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.grouptypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.intendedstdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.stdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.streamname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StreamName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'person.email': {
|
||||
'Meta': {'object_name': 'Email'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}),
|
||||
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'person.person': {
|
||||
'Meta': {'object_name': 'Person'},
|
||||
'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['doc']
|
377
ietf/doc/migrations/0008_auto__add_deletedevent.py
Normal file
377
ietf/doc/migrations/0008_auto__add_deletedevent.py
Normal file
|
@ -0,0 +1,377 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding model 'DeletedEvent'
|
||||
db.create_table('doc_deletedevent', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
|
||||
('json', self.gf('django.db.models.fields.TextField')()),
|
||||
('by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Person'])),
|
||||
('time', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
|
||||
))
|
||||
db.send_create_signal('doc', ['DeletedEvent'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'DeletedEvent'
|
||||
db.delete_table('doc_deletedevent')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'doc.ballotdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ballot_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.BallotType']"}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.ballotpositiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotPositionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['doc.BallotDocEvent']", 'null': 'True'}),
|
||||
'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'comment_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'discuss': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'discuss_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'pos': ('django.db.models.fields.related.ForeignKey', [], {'default': "'norecord'", 'to': "orm['name.BallotPositionName']"})
|
||||
},
|
||||
'doc.ballottype': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'BallotType'},
|
||||
'doc_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'positions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.BallotPositionName']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'question': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'doc.consensusdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'ConsensusDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'consensus': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.deletedevent': {
|
||||
'Meta': {'object_name': 'DeletedEvent'},
|
||||
'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'json': ('django.db.models.fields.TextField', [], {}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})
|
||||
},
|
||||
'doc.docalias': {
|
||||
'Meta': {'object_name': 'DocAlias'},
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
|
||||
},
|
||||
'doc.docevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'DocEvent'},
|
||||
'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'desc': ('django.db.models.fields.TextField', [], {}),
|
||||
'doc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'doc.dochistory': {
|
||||
'Meta': {'object_name': 'DocHistory'},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocHistoryAuthor']", 'blank': 'True'}),
|
||||
'doc': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['doc.Document']"}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
|
||||
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", 'symmetrical': 'False', 'through': "orm['doc.RelatedDocHistory']", 'blank': 'True'}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
|
||||
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.dochistoryauthor': {
|
||||
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocHistoryAuthor'},
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'doc.docreminder': {
|
||||
'Meta': {'object_name': 'DocReminder'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'due': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'event': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocEvent']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocReminderTypeName']"})
|
||||
},
|
||||
'doc.document': {
|
||||
'Meta': {'object_name': 'Document'},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
|
||||
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'reversely_related_document_set'", 'blank': 'True', 'through': "orm['doc.RelatedDocument']", 'to': "orm['doc.DocAlias']"}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
|
||||
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.documentauthor': {
|
||||
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'},
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1'})
|
||||
},
|
||||
'doc.initialreviewdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'InitialReviewDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.lastcalldocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'LastCallDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.newrevisiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'NewRevisionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16'})
|
||||
},
|
||||
'doc.relateddochistory': {
|
||||
'Meta': {'object_name': 'RelatedDocHistory'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
|
||||
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reversely_related_document_history_set'", 'to': "orm['doc.DocAlias']"})
|
||||
},
|
||||
'doc.relateddocument': {
|
||||
'Meta': {'object_name': 'RelatedDocument'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
|
||||
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocAlias']"})
|
||||
},
|
||||
'doc.state': {
|
||||
'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'previous_states'", 'blank': 'True', 'to': "orm['doc.State']"}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'doc.statedocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'StateDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.State']", 'null': 'True', 'blank': 'True'}),
|
||||
'state_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"})
|
||||
},
|
||||
'doc.statetype': {
|
||||
'Meta': {'object_name': 'StateType'},
|
||||
'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.telechatdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'TelechatDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'returning_item': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'telechat_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.writeupdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'WriteupDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'text': ('django.db.models.fields.TextField', [], {'blank': 'True'})
|
||||
},
|
||||
'group.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}),
|
||||
'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
|
||||
'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}),
|
||||
'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'name.ballotpositionname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'BallotPositionName'},
|
||||
'blocking': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.docrelationshipname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocRelationshipName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.docremindertypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocReminderTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctagname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.groupstatename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.grouptypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.intendedstdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.stdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.streamname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StreamName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'person.email': {
|
||||
'Meta': {'object_name': 'Email'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}),
|
||||
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'person.person': {
|
||||
'Meta': {'object_name': 'Person'},
|
||||
'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['doc']
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import models
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.group.models import *
|
||||
|
@ -26,7 +27,7 @@ class State(models.Model):
|
|||
desc = models.TextField(blank=True)
|
||||
order = models.IntegerField(default=0)
|
||||
|
||||
next_states = models.ManyToManyField('State', related_name="previous_states")
|
||||
next_states = models.ManyToManyField('State', related_name="previous_states", blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
@ -450,12 +451,15 @@ EVENT_TYPES = [
|
|||
|
||||
("deleted", "Deleted document"),
|
||||
|
||||
("changed_state", "Changed state"),
|
||||
|
||||
# misc draft/RFC events
|
||||
("changed_stream", "Changed document stream"),
|
||||
("expired_document", "Expired document"),
|
||||
("extended_expiry", "Extended expiry of document"),
|
||||
("requested_resurrect", "Requested resurrect"),
|
||||
("completed_resurrect", "Completed resurrect"),
|
||||
("changed_consensus", "Changed consensus"),
|
||||
("published_rfc", "Published RFC"),
|
||||
|
||||
# WG events
|
||||
|
@ -481,13 +485,21 @@ EVENT_TYPES = [
|
|||
("changed_last_call_text", "Changed last call text"),
|
||||
("requested_last_call", "Requested last call"),
|
||||
("sent_last_call", "Sent last call"),
|
||||
|
||||
|
||||
("scheduled_for_telechat", "Scheduled for telechat"),
|
||||
|
||||
("iesg_approved", "IESG approved document (no problem)"),
|
||||
("iesg_disapproved", "IESG disapproved document (do not publish)"),
|
||||
|
||||
("approved_in_minute", "Approved in minute"),
|
||||
|
||||
# IANA events
|
||||
("iana_review", "IANA review comment"),
|
||||
("rfc_in_iana_registry", "RFC is in IANA registry"),
|
||||
|
||||
# RFC Editor
|
||||
("rfc_editor_received_announcement", "Announcement was received by RFC Editor"),
|
||||
("requested_publication", "Publication at RFC Editor requested")
|
||||
]
|
||||
|
||||
class DocEvent(models.Model):
|
||||
|
@ -506,7 +518,14 @@ class DocEvent(models.Model):
|
|||
|
||||
class NewRevisionDocEvent(DocEvent):
|
||||
rev = models.CharField(max_length=16)
|
||||
|
||||
|
||||
class StateDocEvent(DocEvent):
|
||||
state_type = models.ForeignKey(StateType)
|
||||
state = models.ForeignKey(State, blank=True, null=True)
|
||||
|
||||
class ConsensusDocEvent(DocEvent):
|
||||
consensus = models.BooleanField()
|
||||
|
||||
# IESG events
|
||||
class BallotType(models.Model):
|
||||
doc_type = models.ForeignKey(DocTypeName, blank=True, null=True)
|
||||
|
@ -589,7 +608,7 @@ class BallotPositionDocEvent(DocEvent):
|
|||
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 WriteupDocEvent(DocEvent):
|
||||
text = models.TextField(blank=True)
|
||||
|
||||
|
@ -603,3 +622,14 @@ class TelechatDocEvent(DocEvent):
|
|||
# charter events
|
||||
class InitialReviewDocEvent(DocEvent):
|
||||
expires = models.DateTimeField(blank=True, null=True)
|
||||
|
||||
|
||||
# dumping store for removed events
|
||||
class DeletedEvent(models.Model):
|
||||
content_type = models.ForeignKey(ContentType)
|
||||
json = models.TextField(help_text="Deleted object in JSON format, with attribute names chosen to be suitable for passing into the relevant create method.")
|
||||
by = models.ForeignKey(Person)
|
||||
time = models.DateTimeField(default=datetime.datetime.now)
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s by %s %s" % (self.content_type, self.by, self.time)
|
||||
|
|
|
@ -19,7 +19,8 @@ def get_state_types(doc):
|
|||
res.append("draft-stream-%s" % doc.stream_id)
|
||||
|
||||
res.append("draft-iesg")
|
||||
res.append("draft-iana")
|
||||
res.append("draft-iana-review")
|
||||
res.append("draft-iana-action")
|
||||
res.append("draft-rfceditor")
|
||||
|
||||
return res
|
||||
|
@ -108,8 +109,6 @@ def augment_with_start_time(docs):
|
|||
if e.doc_id in seen:
|
||||
continue
|
||||
|
||||
print e.time, e.doc_id
|
||||
|
||||
docs_dict[e.doc_id].start_time = e.time
|
||||
seen.add(e.doc_id)
|
||||
|
||||
|
@ -167,11 +166,26 @@ def get_document_content(key, filename, split=True, markup=True):
|
|||
return raw_content
|
||||
|
||||
def log_state_changed(request, doc, by, new_description, old_description):
|
||||
from ietf.doc.models import DocEvent
|
||||
|
||||
e = DocEvent(doc=doc, by=by)
|
||||
e.type = "changed_document"
|
||||
e.desc = u"State changed to <b>%s</b> from %s" % (new_description, old_description)
|
||||
e.save()
|
||||
return e
|
||||
|
||||
def add_state_change_event(doc, by, prev_state, new_state, timestamp=None):
|
||||
"""Add doc event to explain that state change just happened."""
|
||||
if prev_state == new_state:
|
||||
return None
|
||||
|
||||
e = StateDocEvent(doc=doc, by=by)
|
||||
e.type = "changed_state"
|
||||
e.state_type = (prev_state or new_state).type
|
||||
e.state = new_state
|
||||
e.desc = "%s changed to <b>%s</b>" % (e.state_type.label, new_state.name)
|
||||
if prev_state:
|
||||
e.desc += " from %s" % prev_state.name
|
||||
if timestamp:
|
||||
e.time = timestamp
|
||||
e.save()
|
||||
return e
|
||||
|
||||
|
|
|
@ -24,6 +24,12 @@ class GroupInfo(models.Model):
|
|||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
def name_with_acronym(self):
|
||||
res = self.name
|
||||
if self.type_id in ("wg", "rg", "area"):
|
||||
res += " %s (%s)" % (self.type, self.acronym)
|
||||
return res
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
|
|
@ -34,11 +34,19 @@ def in_id_expire_freeze(when=None):
|
|||
return second_cut_off <= when < ietf_monday
|
||||
|
||||
def expirable_documents():
|
||||
# the general rule is that each active draft is expirable, unless
|
||||
# it's in a state where we shouldn't touch it
|
||||
|
||||
d = Document.objects.filter(states__type="draft", states__slug="active").exclude(tags="rfc-rev")
|
||||
# we need to get those that either don't have a state or have a
|
||||
# state >= 42 (AD watching), unfortunately that doesn't appear to
|
||||
# be possible to get to work directly in Django 1.1
|
||||
return itertools.chain(d.exclude(states__type="draft-iesg").distinct(), d.filter(states__type="draft-iesg", states__slug__in=("watching", "dead")).distinct())
|
||||
|
||||
nonexpirable_states = []
|
||||
# all IESG states except AD Watching and Dead block expiry
|
||||
nonexpirable_states += list(State.objects.filter(type="draft-iesg").exclude(slug__in=("watching", "dead")))
|
||||
# Sent to RFC Editor and RFC Published block expiry (the latter
|
||||
# shouldn't be possible for an active draft, though)
|
||||
nonexpirable_states += list(State.objects.filter(type__in=("draft-stream-iab", "draft-stream-irtf", "draft-stream-ise"), slug__in=("rfc-edit", "pub")))
|
||||
|
||||
return d.exclude(states__in=nonexpirable_states).distinct()
|
||||
|
||||
def get_soon_to_expire_ids(days):
|
||||
start_date = datetime.date.today() - datetime.timedelta(InternetDraft.DAYS_TO_EXPIRE - 1)
|
||||
|
|
|
@ -125,9 +125,9 @@ class IdWrapper:
|
|||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
s = self._draft.get_state("draft-rfceditor")
|
||||
if s:
|
||||
# extract possible extra states
|
||||
tags = self._draft.tags.filter(slug__in=("iana-crd", "ref", "missref"))
|
||||
return " ".join([s.name] + [t.slug.replace("-crd", "").upper() for t in tags])
|
||||
# extract possible extra annotations
|
||||
tags = self._draft.tags.filter(slug__in=("iana", "ref"))
|
||||
return "*".join([s.name] + [t.slug.upper() for t in tags])
|
||||
else:
|
||||
return None
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
from ietf.utils.mail import send_mail, send_mail_text
|
||||
from ietf.idtracker.models import *
|
||||
from ietf.ipr.search import iprs_from_docs
|
||||
from ietf.doc.models import WriteupDocEvent, BallotPositionDocEvent, LastCallDocEvent, DocAlias
|
||||
#from ietf.doc.models import *
|
||||
from ietf.doc.models import WriteupDocEvent, BallotPositionDocEvent, LastCallDocEvent, DocAlias, ConsensusDocEvent
|
||||
from ietf.person.models import Person
|
||||
from ietf.group.models import Group
|
||||
|
||||
|
@ -62,8 +63,26 @@ def email_stream_changed(request, doc, old_stream, new_stream, text=""):
|
|||
"idrfc/stream_changed_email.txt",
|
||||
dict(text=text,
|
||||
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
|
||||
|
||||
def email_pulled_from_rfc_queue(request, doc, comment, prev_state, next_state):
|
||||
send_mail(request, ["IANA <iana@iana.org>", "RFC Editor <rfc-editor@rfc-editor.org>"], None,
|
||||
"%s changed state from %s to %s" % (doc.name, prev_state.name, next_state.name),
|
||||
"idrfc/pulled_from_rfc_queue_email.txt",
|
||||
dict(doc=doc,
|
||||
prev_state=prev_state,
|
||||
next_state=next_state,
|
||||
comment=comment,
|
||||
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
|
||||
extra=extra_automation_headers(doc))
|
||||
|
||||
|
||||
def email_authors(request, doc, subject, text):
|
||||
to = [x.strip() for x in doc.author_list().split(',')]
|
||||
if not to:
|
||||
return
|
||||
|
||||
|
||||
send_mail_text(request, to, None, subject, text)
|
||||
|
||||
def html_to_text(html):
|
||||
return strip_tags(html.replace("<", "<").replace(">", ">").replace("&", "&").replace("<br>", "\n"))
|
||||
|
||||
|
@ -98,12 +117,15 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|||
|
||||
|
||||
def generate_ballot_writeup(request, doc):
|
||||
e = doc.latest_event(type="iana_review")
|
||||
iana = e.desc if e else ""
|
||||
|
||||
e = WriteupDocEvent()
|
||||
e.type = "changed_ballot_writeup_text"
|
||||
e.by = request.user.get_profile()
|
||||
e.doc = doc
|
||||
e.desc = u"Ballot writeup was generated"
|
||||
e.text = unicode(render_to_string("idrfc/ballot_writeup.txt"))
|
||||
e.text = unicode(render_to_string("idrfc/ballot_writeup.txt", {'iana': iana}))
|
||||
e.save()
|
||||
|
||||
return e
|
||||
|
@ -263,6 +285,30 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|||
generate_approval_mail = generate_approval_mailREDESIGN
|
||||
generate_approval_mail_rfc_editor = generate_approval_mail_rfc_editorREDESIGN
|
||||
|
||||
def generate_publication_request(request, doc):
|
||||
group_description = ""
|
||||
if doc.group and doc.group.acronym != "none":
|
||||
group_description = doc.group.name_with_acronym()
|
||||
|
||||
e = doc.latest_event(ConsensusDocEvent, type="changed_consensus")
|
||||
consensus = e.consensus if e else None
|
||||
|
||||
if doc.stream_id == "irtf":
|
||||
approving_body = "IRSG"
|
||||
consensus_body = doc.group.acronym.upper()
|
||||
else:
|
||||
approving_body = str(doc.stream)
|
||||
consensus_body = approving_body
|
||||
|
||||
return render_to_string("idrfc/publication_request.txt",
|
||||
dict(doc=doc,
|
||||
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
|
||||
group_description=group_description,
|
||||
approving_body=approving_body,
|
||||
consensus_body=consensus_body,
|
||||
consensus=consensus,
|
||||
)
|
||||
)
|
||||
|
||||
def send_last_call_request(request, doc, ballot):
|
||||
to = "iesg-secretary@ietf.org"
|
||||
|
@ -426,22 +472,6 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|||
generate_issue_ballot_mail = generate_issue_ballot_mailREDESIGN
|
||||
|
||||
def email_iana(request, doc, to, msg):
|
||||
# fix up message and send message to IANA for each in ballot set
|
||||
import email
|
||||
parsed_msg = email.message_from_string(msg.encode("utf-8"))
|
||||
|
||||
for i in doc.idinternal.ballot_set():
|
||||
extra = {}
|
||||
extra["Reply-To"] = "noreply@ietf.org"
|
||||
extra["X-IETF-Draft-string"] = i.document().filename
|
||||
extra["X-IETF-Draft-revision"] = i.document().revision_display()
|
||||
|
||||
send_mail_text(request, "To: IANA <%s>" % to,
|
||||
parsed_msg["From"], parsed_msg["Subject"],
|
||||
parsed_msg.get_payload(),
|
||||
extra=extra)
|
||||
|
||||
def email_ianaREDESIGN(request, doc, to, msg):
|
||||
# fix up message and send it with extra info on doc in headers
|
||||
import email
|
||||
parsed_msg = email.message_from_string(msg.encode("utf-8"))
|
||||
|
@ -456,8 +486,13 @@ def email_ianaREDESIGN(request, doc, to, msg):
|
|||
parsed_msg.get_payload(),
|
||||
extra=extra)
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
email_iana = email_ianaREDESIGN
|
||||
def extra_automation_headers(doc):
|
||||
extra = {}
|
||||
extra["Reply-To"] = "noreply@ietf.org"
|
||||
extra["X-IETF-Draft-string"] = doc.name
|
||||
extra["X-IETF-Draft-revision"] = doc.rev
|
||||
|
||||
return extra
|
||||
|
||||
def email_last_call_expired(doc):
|
||||
text = "IETF Last Call has ended, and the state has been changed to\n%s." % doc.idinternal.cur_state.state
|
||||
|
|
|
@ -1,293 +0,0 @@
|
|||
# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# * Neither the name of the Nokia Corporation and/or its
|
||||
# subsidiary(-ies) nor the names of its contributors may be used
|
||||
# to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from ietf import settings
|
||||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
from django import db
|
||||
|
||||
from xml.dom import pulldom, Node
|
||||
import re
|
||||
import urllib2
|
||||
from datetime import datetime
|
||||
import socket
|
||||
import sys
|
||||
|
||||
QUEUE_URL = "http://www.rfc-editor.org/queue2.xml"
|
||||
TABLE = "rfc_editor_queue_mirror"
|
||||
REF_TABLE = "rfc_editor_queue_mirror_refs"
|
||||
|
||||
log_data = ""
|
||||
def log(line):
|
||||
global log_data
|
||||
if __name__ == '__main__' and len(sys.argv) > 1:
|
||||
print line
|
||||
else:
|
||||
log_data += line + "\n"
|
||||
|
||||
def parse(response):
|
||||
def getChildText(parentNode, tagName):
|
||||
for node in parentNode.childNodes:
|
||||
if node.nodeType == Node.ELEMENT_NODE and node.localName == tagName:
|
||||
return node.firstChild.data
|
||||
return None
|
||||
|
||||
events = pulldom.parse(response)
|
||||
drafts = []
|
||||
refs = []
|
||||
for (event, node) in events:
|
||||
if event == pulldom.START_ELEMENT and node.tagName == "entry":
|
||||
events.expandNode(node)
|
||||
node.normalize()
|
||||
draft_name = getChildText(node, "draft").strip()
|
||||
draft_name = re.sub("(-\d\d)?(.txt){1,2}$", "", draft_name)
|
||||
date_received = getChildText(node, "date-received")
|
||||
|
||||
states = []
|
||||
for child in node.childNodes:
|
||||
if child.nodeType == Node.ELEMENT_NODE and child.localName == "state":
|
||||
states.append(child.firstChild.data)
|
||||
|
||||
has_refs = False
|
||||
for child in node.childNodes:
|
||||
if child.nodeType == Node.ELEMENT_NODE and child.localName == "normRef":
|
||||
ref_name = getChildText(child, "ref-name")
|
||||
ref_state = getChildText(child, "ref-state")
|
||||
in_queue = ref_state.startswith("IN-QUEUE")
|
||||
refs.append([draft_name, ref_name, in_queue, True])
|
||||
has_refs = True
|
||||
if has_refs and not "MISSREF" in states:
|
||||
states.append("REF")
|
||||
|
||||
if len(states) == 0:
|
||||
state = "?"
|
||||
else:
|
||||
state = " ".join(states)
|
||||
drafts.append([draft_name, date_received, state, stream])
|
||||
|
||||
elif event == pulldom.START_ELEMENT and node.tagName == "section":
|
||||
name = node.getAttribute('name')
|
||||
if name.startswith("IETF"):
|
||||
stream = 1
|
||||
elif name.startswith("IAB"):
|
||||
stream = 2
|
||||
elif name.startswith("IRTF"):
|
||||
stream = 3
|
||||
elif name.startswith("INDEPENDENT"):
|
||||
stream = 4
|
||||
else:
|
||||
stream = 0
|
||||
log("WARNING: unrecognized section "+name)
|
||||
return (drafts, refs)
|
||||
|
||||
# Find set of all normative references (whether direct or via some
|
||||
# other normative reference)
|
||||
def find_indirect_refs(drafts, refs):
|
||||
result = []
|
||||
draft_names = set()
|
||||
for draft in drafts:
|
||||
draft_names.add(draft[0])
|
||||
|
||||
def recurse(draft_name, ref_set, level):
|
||||
for (source, destination, in_queue, direct) in refs:
|
||||
if source == draft_name:
|
||||
if destination not in ref_set:
|
||||
ref_set.add(destination)
|
||||
recurse(destination, ref_set, level+1)
|
||||
if level == 0:
|
||||
# Remove self-reference
|
||||
ref_set.remove(draft_name)
|
||||
# Remove direct references
|
||||
for (source, destination, in_queue, direct) in refs:
|
||||
if source == draft_name:
|
||||
if destination in ref_set:
|
||||
ref_set.remove(destination)
|
||||
# The rest are indirect references
|
||||
for ref in ref_set:
|
||||
if draft_name != ref:
|
||||
result.append([draft_name, ref, ref in draft_names, False])
|
||||
|
||||
for draft_name in draft_names:
|
||||
recurse(draft_name, set([draft_name]), 0)
|
||||
return result
|
||||
|
||||
# Convert filenames to id_document_tags
|
||||
def find_document_ids(cursor, drafts, refs):
|
||||
draft_ids = {}
|
||||
drafts2 = []
|
||||
for draft in drafts:
|
||||
cursor.execute("SELECT id_document_tag FROM internet_drafts WHERE filename=%s", [draft[0]])
|
||||
row = cursor.fetchone()
|
||||
if not row:
|
||||
log("WARNING: cannot find id for "+draft[0])
|
||||
else:
|
||||
draft_ids[draft[0]] = row[0]
|
||||
drafts2.append([row[0]]+draft[1:])
|
||||
refs2 = []
|
||||
for ref in refs:
|
||||
if ref[0] in draft_ids:
|
||||
refs2.append([draft_ids[ref[0]]]+ref[1:])
|
||||
return (drafts2, refs2)
|
||||
|
||||
def parse_all(response):
|
||||
log("parsing...")
|
||||
(drafts, refs) = parse(response)
|
||||
log("got "+ str(len(drafts)) + " drafts and "+str(len(refs))+" direct refs")
|
||||
|
||||
indirect_refs = find_indirect_refs(drafts, refs)
|
||||
log("found " + str(len(indirect_refs)) + " indirect refs")
|
||||
refs.extend(indirect_refs)
|
||||
del(indirect_refs)
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES: # note: return before id lookup
|
||||
return (drafts, refs)
|
||||
|
||||
# convert filenames to id_document_tags
|
||||
log("connecting to database...")
|
||||
cursor = db.connection.cursor()
|
||||
log("finding id_document_tags...")
|
||||
(drafts, refs) = find_document_ids(cursor, drafts, refs)
|
||||
cursor.close()
|
||||
return (drafts, refs)
|
||||
|
||||
def insert_into_database(drafts, refs):
|
||||
log("connecting to database...")
|
||||
cursor = db.connection.cursor()
|
||||
log("removing old data...")
|
||||
cursor.execute("DELETE FROM "+TABLE)
|
||||
cursor.execute("DELETE FROM "+REF_TABLE)
|
||||
log("inserting new data...")
|
||||
cursor.executemany("INSERT INTO "+TABLE+" (id_document_tag, date_received, state, stream) VALUES (%s, %s, %s, %s)", drafts)
|
||||
cursor.execute("DELETE FROM "+REF_TABLE)
|
||||
cursor.executemany("INSERT INTO "+REF_TABLE+" (source, destination, in_queue, direct) VALUES (%s, %s, %s, %s)", refs)
|
||||
cursor.close()
|
||||
db.connection._commit()
|
||||
db.connection.close()
|
||||
|
||||
import django.db.transaction
|
||||
|
||||
def get_rfc_tag_mapping():
|
||||
"""Return dict with RFC Editor state name -> DocTagName"""
|
||||
from ietf.name.models import DocTagName
|
||||
from ietf.name.utils import name
|
||||
|
||||
return {
|
||||
'IANA': name(DocTagName, 'iana-crd', 'IANA coordination', "RFC-Editor/IANA Registration Coordination"),
|
||||
'REF': name(DocTagName, 'ref', 'Holding for references', "Holding for normative reference"),
|
||||
'MISSREF': name(DocTagName, 'missref', 'Missing references', "Awaiting missing normative reference"),
|
||||
}
|
||||
|
||||
def get_rfc_state_mapping():
|
||||
"""Return dict with RFC Editor state name -> State"""
|
||||
from ietf.doc.models import State, StateType
|
||||
t = StateType.objects.get(slug="draft-rfceditor")
|
||||
return {
|
||||
'AUTH': State.objects.get_or_create(type=t, slug='auth', name='AUTH', desc="Awaiting author action")[0],
|
||||
'AUTH48': State.objects.get_or_create(type=t, slug='auth48', name="AUTH48", desc="Awaiting final author approval")[0],
|
||||
'AUTH48-DONE': State.objects.get_or_create(type=t, slug='auth48done', name="AUTH48-DONE", desc="Final approvals are complete")[0],
|
||||
'EDIT': State.objects.get_or_create(type=t, slug='edit', name='EDIT', desc="Approved by the stream manager (e.g., IESG, IAB, IRSG, ISE), awaiting processing and publishing")[0],
|
||||
'IANA': State.objects.get_or_create(type=t, slug='iana-crd', name='IANA', desc="RFC-Editor/IANA Registration Coordination")[0],
|
||||
'IESG': State.objects.get_or_create(type=t, slug='iesg', name='IESG', desc="Holding for IESG action")[0],
|
||||
'ISR': State.objects.get_or_create(type=t, slug='isr', name='ISR', desc="Independent Submission Review by the ISE ")[0],
|
||||
'ISR-AUTH': State.objects.get_or_create(type=t, slug='isr-auth', name='ISR-AUTH', desc="Independent Submission awaiting author update, or in discussion between author and ISE")[0],
|
||||
'REF': State.objects.get_or_create(type=t, slug='ref', name='REF', desc="Holding for normative reference")[0],
|
||||
'RFC-EDITOR': State.objects.get_or_create(type=t, slug='rfc-edit', name='RFC-EDITOR', desc="Awaiting final RFC Editor review before AUTH48")[0],
|
||||
'TO': State.objects.get_or_create(type=t, slug='timeout', name='TO', desc="Time-out period during which the IESG reviews document for conflict/concurrence with other IETF working group work")[0],
|
||||
'MISSREF': State.objects.get_or_create(type=t, slug='missref', name='MISSREF', desc="Awaiting missing normative reference")[0],
|
||||
}
|
||||
|
||||
|
||||
@django.db.transaction.commit_on_success
|
||||
def insert_into_databaseREDESIGN(drafts, refs):
|
||||
from ietf.doc.models import Document
|
||||
from ietf.name.models import DocTagName
|
||||
|
||||
tags = get_rfc_tag_mapping()
|
||||
state_map = get_rfc_state_mapping()
|
||||
|
||||
rfc_editor_tags = tags.values()
|
||||
|
||||
log("removing old data...")
|
||||
for d in Document.objects.filter(states__type="draft-rfceditor").distinct():
|
||||
d.tags.remove(*rfc_editor_tags)
|
||||
d.unset_state("draft-rfceditor")
|
||||
|
||||
log("inserting new data...")
|
||||
|
||||
for name, date_received, state_info, stream_id in drafts:
|
||||
try:
|
||||
d = Document.objects.get(name=name)
|
||||
except Document.DoesNotExist:
|
||||
log("unknown document %s" % name)
|
||||
continue
|
||||
|
||||
state_list = state_info.split(" ")
|
||||
if state_list:
|
||||
state = state_list[0]
|
||||
# For now, ignore the '*R...' that's appeared for some states.
|
||||
# FIXME : see if we need to add some refinement for this.
|
||||
if '*' in state:
|
||||
state = state.split("*")[0]
|
||||
# first is state
|
||||
d.set_state(state_map[state])
|
||||
|
||||
# remainding are tags
|
||||
for x in state_list[1:]:
|
||||
d.tags.add(tags[x])
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
insert_into_database = insert_into_databaseREDESIGN
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
log("output from mirror_rfc_editor_queue.py:\n")
|
||||
log("time: "+str(datetime.now()))
|
||||
log("host: "+socket.gethostname())
|
||||
log("url: "+QUEUE_URL)
|
||||
|
||||
log("downloading...")
|
||||
socket.setdefaulttimeout(30)
|
||||
response = urllib2.urlopen(QUEUE_URL)
|
||||
|
||||
(drafts, refs) = parse_all(response)
|
||||
if len(drafts) < 10 or len(refs) < 10:
|
||||
raise Exception('not enough data')
|
||||
|
||||
insert_into_database(drafts, refs)
|
||||
|
||||
log("all done!")
|
||||
if log_data.find("WARNING") < 0:
|
||||
log_data = ""
|
||||
finally:
|
||||
if len(log_data) > 0:
|
||||
print log_data
|
|
@ -1,365 +0,0 @@
|
|||
# Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# * Neither the name of the Nokia Corporation and/or its
|
||||
# subsidiary(-ies) nor the names of its contributors may be used
|
||||
# to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from ietf import settings
|
||||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
from django import db
|
||||
|
||||
from xml.dom import pulldom, Node
|
||||
import re
|
||||
import urllib2
|
||||
from datetime import datetime, date, timedelta
|
||||
import socket
|
||||
import sys
|
||||
|
||||
INDEX_URL = "http://www.rfc-editor.org/rfc/rfc-index.xml"
|
||||
TABLE = "rfc_index_mirror"
|
||||
|
||||
log_data = ""
|
||||
def log(line):
|
||||
global log_data
|
||||
if __name__ == '__main__' and len(sys.argv) > 1:
|
||||
print line
|
||||
else:
|
||||
log_data += line + "\n"
|
||||
|
||||
# python before 2.7 doesn't have the total_seconds method on datetime.timedelta.
|
||||
def total_seconds(td):
|
||||
return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
|
||||
|
||||
def parse(response):
|
||||
def getChildText(parentNode, tagName):
|
||||
for node in parentNode.childNodes:
|
||||
if node.nodeType == Node.ELEMENT_NODE and node.localName == tagName:
|
||||
return node.firstChild.data
|
||||
return None
|
||||
|
||||
def getDocList(parentNode, tagName):
|
||||
l = []
|
||||
for u in parentNode.getElementsByTagName(tagName):
|
||||
for d in u.getElementsByTagName("doc-id"):
|
||||
l.append(d.firstChild.data)
|
||||
if len(l) == 0:
|
||||
return None
|
||||
else:
|
||||
return ",".join(l)
|
||||
|
||||
also_list = {}
|
||||
data = []
|
||||
events = pulldom.parse(response)
|
||||
for (event, node) in events:
|
||||
if event == pulldom.START_ELEMENT and node.tagName in ["bcp-entry", "fyi-entry", "std-entry"]:
|
||||
events.expandNode(node)
|
||||
node.normalize()
|
||||
bcpid = getChildText(node, "doc-id")
|
||||
doclist = getDocList(node, "is-also")
|
||||
if doclist:
|
||||
for docid in doclist.split(","):
|
||||
if docid in also_list:
|
||||
also_list[docid].append(bcpid)
|
||||
else:
|
||||
also_list[docid] = [bcpid]
|
||||
|
||||
elif event == pulldom.START_ELEMENT and node.tagName == "rfc-entry":
|
||||
events.expandNode(node)
|
||||
node.normalize()
|
||||
rfc_number = int(getChildText(node, "doc-id")[3:])
|
||||
title = getChildText(node, "title")
|
||||
|
||||
l = []
|
||||
for author in node.getElementsByTagName("author"):
|
||||
l.append(getChildText(author, "name"))
|
||||
authors = "; ".join(l)
|
||||
|
||||
d = node.getElementsByTagName("date")[0]
|
||||
year = int(getChildText(d, "year"))
|
||||
month = getChildText(d, "month")
|
||||
month = ["January","February","March","April","May","June","July","August","September","October","November","December"].index(month)+1
|
||||
rfc_published_date = ("%d-%02d-01" % (year, month))
|
||||
|
||||
current_status = getChildText(node, "current-status").title()
|
||||
|
||||
updates = getDocList(node, "updates")
|
||||
updated_by = getDocList(node, "updated-by")
|
||||
obsoletes = getDocList(node, "obsoletes")
|
||||
obsoleted_by = getDocList(node, "obsoleted-by")
|
||||
stream = getChildText(node, "stream")
|
||||
wg = getChildText(node, "wg_acronym")
|
||||
if wg and ((wg == "NON WORKING GROUP") or len(wg) > 15):
|
||||
wg = None
|
||||
|
||||
l = []
|
||||
for format in node.getElementsByTagName("format"):
|
||||
l.append(getChildText(format, "file-format"))
|
||||
file_formats = (",".join(l)).lower()
|
||||
|
||||
draft = getChildText(node, "draft")
|
||||
if draft and re.search("-\d\d$", draft):
|
||||
draft = draft[0:-3]
|
||||
|
||||
if len(node.getElementsByTagName("errata-url")) > 0:
|
||||
has_errata = 1
|
||||
else:
|
||||
has_errata = 0
|
||||
|
||||
data.append([rfc_number,title,authors,rfc_published_date,current_status,updates,updated_by,obsoletes,obsoleted_by,None,draft,has_errata,stream,wg,file_formats])
|
||||
|
||||
for d in data:
|
||||
k = "RFC%04d" % d[0]
|
||||
if k in also_list:
|
||||
d[9] = ",".join(also_list[k])
|
||||
return data
|
||||
|
||||
def insert_to_database(data):
|
||||
log("connecting to database...")
|
||||
cursor = db.connection.cursor()
|
||||
log("removing old data...")
|
||||
cursor.execute("DELETE FROM "+TABLE)
|
||||
log("inserting new data...")
|
||||
cursor.executemany("INSERT INTO "+TABLE+" (rfc_number, title, authors, rfc_published_date, current_status,updates,updated_by,obsoletes,obsoleted_by,also,draft,has_errata,stream,wg,file_formats) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", data)
|
||||
cursor.close()
|
||||
db.connection._commit()
|
||||
db.connection.close()
|
||||
|
||||
def get_std_level_mapping():
|
||||
from ietf.name.models import StdLevelName
|
||||
from ietf.name.utils import name
|
||||
return {
|
||||
"Standard": name(StdLevelName, "std", "Standard"),
|
||||
"Draft Standard": name(StdLevelName, "ds", "Draft Standard"),
|
||||
"Proposed Standard": name(StdLevelName, "ps", "Proposed Standard"),
|
||||
"Informational": name(StdLevelName, "inf", "Informational"),
|
||||
"Experimental": name(StdLevelName, "exp", "Experimental"),
|
||||
"Best Current Practice": name(StdLevelName, "bcp", "Best Current Practice"),
|
||||
"Historic": name(StdLevelName, "hist", "Historic"),
|
||||
"Unknown": name(StdLevelName, "unkn", "Unknown"),
|
||||
}
|
||||
|
||||
def get_stream_mapping():
|
||||
from ietf.name.models import StreamName
|
||||
from ietf.name.utils import name
|
||||
|
||||
return {
|
||||
"IETF": name(StreamName, "ietf", "IETF", desc="IETF stream", order=1),
|
||||
"INDEPENDENT": name(StreamName, "ise", "ISE", desc="Independent Submission Editor stream", order=2),
|
||||
"IRTF": name(StreamName, "irtf", "IRTF", desc="Independent Submission Editor stream", order=3),
|
||||
"IAB": name(StreamName, "iab", "IAB", desc="IAB stream", order=4),
|
||||
"Legacy": name(StreamName, "legacy", "Legacy", desc="Legacy stream", order=5),
|
||||
}
|
||||
|
||||
|
||||
import django.db.transaction
|
||||
|
||||
@django.db.transaction.commit_on_success
|
||||
def insert_to_databaseREDESIGN(data):
|
||||
from ietf.person.models import Person
|
||||
from ietf.doc.models import Document, DocAlias, DocEvent, RelatedDocument, State, save_document_in_history
|
||||
from ietf.group.models import Group
|
||||
from ietf.name.models import DocTagName, DocRelationshipName
|
||||
from ietf.name.utils import name
|
||||
|
||||
system = Person.objects.get(name="(System)")
|
||||
std_level_mapping = get_std_level_mapping()
|
||||
stream_mapping = get_stream_mapping()
|
||||
tag_has_errata = name(DocTagName, 'errata', "Has errata")
|
||||
relationship_obsoletes = name(DocRelationshipName, "obs", "Obsoletes")
|
||||
relationship_updates = name(DocRelationshipName, "updates", "Updates")
|
||||
|
||||
skip_older_than_date = (date.today() - timedelta(days=365)).strftime("%Y-%m-%d")
|
||||
|
||||
log("updating data...")
|
||||
for d in data:
|
||||
rfc_number, title, authors, rfc_published_date, current_status, updates, updated_by, obsoletes, obsoleted_by, also, draft, has_errata, stream, wg, file_formats = d
|
||||
|
||||
if rfc_published_date < skip_older_than_date:
|
||||
# speed up the process by skipping old entries
|
||||
continue
|
||||
|
||||
# we assume two things can happen: we get a new RFC, or an
|
||||
# attribute has been updated at the RFC Editor (RFC Editor
|
||||
# attributes currently take precedence over our local
|
||||
# attributes)
|
||||
|
||||
# make sure we got the document and alias
|
||||
created = False
|
||||
doc = None
|
||||
name = "rfc%s" % rfc_number
|
||||
a = DocAlias.objects.filter(name=name)
|
||||
if a:
|
||||
doc = a[0].document
|
||||
else:
|
||||
if draft:
|
||||
try:
|
||||
doc = Document.objects.get(name=draft)
|
||||
except Document.DoesNotExist:
|
||||
pass
|
||||
|
||||
if not doc:
|
||||
created = True
|
||||
log("created document %s" % name)
|
||||
doc = Document.objects.create(name=name)
|
||||
|
||||
# add alias
|
||||
DocAlias.objects.create(name=name, document=doc)
|
||||
if not created:
|
||||
created = True
|
||||
log("created alias %s to %s" % (name, doc.name))
|
||||
|
||||
|
||||
# check attributes
|
||||
changed_attributes = {}
|
||||
changed_states = []
|
||||
created_relations = []
|
||||
other_changes = False
|
||||
if title != doc.title:
|
||||
changed_attributes["title"] = title
|
||||
|
||||
if std_level_mapping[current_status] != doc.std_level:
|
||||
changed_attributes["std_level"] = std_level_mapping[current_status]
|
||||
|
||||
if doc.get_state_slug() != "rfc":
|
||||
changed_states.append(State.objects.get(type="draft", slug="rfc"))
|
||||
|
||||
if doc.stream != stream_mapping[stream]:
|
||||
changed_attributes["stream"] = stream_mapping[stream]
|
||||
|
||||
if not doc.group and wg:
|
||||
changed_attributes["group"] = Group.objects.get(acronym=wg)
|
||||
|
||||
if not doc.latest_event(type="published_rfc"):
|
||||
e = DocEvent(doc=doc, type="published_rfc")
|
||||
pubdate = datetime.strptime(rfc_published_date, "%Y-%m-%d")
|
||||
# unfortunately, pubdate doesn't include the correct day
|
||||
# at the moment because the data only has month/year, so
|
||||
# try to deduce it
|
||||
synthesized = datetime.now()
|
||||
if abs(pubdate - synthesized) > timedelta(days=60):
|
||||
synthesized = pubdate
|
||||
else:
|
||||
direction = -1 if total_seconds(pubdate - synthesized) < 0 else +1
|
||||
while synthesized.month != pubdate.month or synthesized.year != pubdate.year:
|
||||
synthesized += timedelta(days=direction)
|
||||
e.time = synthesized
|
||||
e.by = system
|
||||
e.desc = "RFC published"
|
||||
e.save()
|
||||
other_changes = True
|
||||
|
||||
if doc.get_state_slug("draft-iesg") == "rfcqueue":
|
||||
changed_states.append(State.objects.get(type="draft-iesg", slug="pub"))
|
||||
|
||||
def parse_relation_list(s):
|
||||
if not s:
|
||||
return []
|
||||
res = []
|
||||
for x in s.split(","):
|
||||
if x[:3] in ("NIC", "IEN", "STD", "RTR"):
|
||||
# try translating this to RFCs that we can handle
|
||||
# sensibly; otherwise we'll have to ignore them
|
||||
l = DocAlias.objects.filter(name__startswith="rfc", document__docalias__name=x.lower())
|
||||
else:
|
||||
l = DocAlias.objects.filter(name=x.lower())
|
||||
|
||||
for a in l:
|
||||
if a not in res:
|
||||
res.append(a)
|
||||
return res
|
||||
|
||||
for x in parse_relation_list(obsoletes):
|
||||
if not RelatedDocument.objects.filter(source=doc, target=x, relationship=relationship_obsoletes):
|
||||
created_relations.append(RelatedDocument(source=doc, target=x, relationship=relationship_obsoletes))
|
||||
|
||||
for x in parse_relation_list(updates):
|
||||
if not RelatedDocument.objects.filter(source=doc, target=x, relationship=relationship_updates):
|
||||
created_relations.append(RelatedDocument(source=doc, target=x, relationship=relationship_updates))
|
||||
|
||||
if also:
|
||||
for a in also.lower().split(","):
|
||||
if not DocAlias.objects.filter(name=a):
|
||||
DocAlias.objects.create(name=a, document=doc)
|
||||
other_changes = True
|
||||
|
||||
if has_errata:
|
||||
if not doc.tags.filter(pk=tag_has_errata.pk):
|
||||
changed_attributes["tags"] = list(doc.tags.all()) + [tag_has_errata]
|
||||
else:
|
||||
if doc.tags.filter(pk=tag_has_errata.pk):
|
||||
changed_attributes["tags"] = set(doc.tags.all()) - set([tag_has_errata])
|
||||
|
||||
if changed_attributes or changed_states or created_relations or other_changes:
|
||||
# apply changes
|
||||
save_document_in_history(doc)
|
||||
for k, v in changed_attributes.iteritems():
|
||||
setattr(doc, k, v)
|
||||
|
||||
for s in changed_states:
|
||||
doc.set_state(s)
|
||||
|
||||
for o in created_relations:
|
||||
o.save()
|
||||
|
||||
doc.time = datetime.now()
|
||||
doc.save()
|
||||
|
||||
if not created:
|
||||
log("%s changed" % name)
|
||||
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
insert_to_database = insert_to_databaseREDESIGN
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
log("output from mirror_rfc_index.py:\n")
|
||||
log("time: "+str(datetime.now()))
|
||||
log("host: "+socket.gethostname())
|
||||
log("url: "+INDEX_URL)
|
||||
|
||||
log("downloading...")
|
||||
socket.setdefaulttimeout(30)
|
||||
response = urllib2.urlopen(INDEX_URL)
|
||||
log("parsing...")
|
||||
data = parse(response)
|
||||
|
||||
log("got " + str(len(data)) + " entries")
|
||||
if len(data) < 5000:
|
||||
raise Exception('not enough data')
|
||||
|
||||
insert_to_database(data)
|
||||
|
||||
log("all done!")
|
||||
log_data = ""
|
||||
|
||||
finally:
|
||||
if len(log_data) > 0:
|
||||
print log_data
|
|
@ -119,7 +119,61 @@ class ChangeStateTestCase(django.test.TestCase):
|
|||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('.prev-state form input[name="state"]')), 1)
|
||||
|
||||
def test_pull_from_rfc_queue(self):
|
||||
draft = make_test_data()
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="rfcqueue"))
|
||||
|
||||
url = urlreverse('doc_change_state', kwargs=dict(name=draft.name))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
# change state
|
||||
mailbox_before = len(outbox)
|
||||
|
||||
r = self.client.post(url,
|
||||
dict(state=State.objects.get(type="draft-iesg", slug="review-e").pk,
|
||||
substate="",
|
||||
comment="Test comment"))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEquals(draft.get_state_slug("draft-iesg"), "review-e")
|
||||
self.assertEquals(len(outbox), mailbox_before + 2 + 1)
|
||||
self.assertTrue(draft.name in outbox[-1]['Subject'])
|
||||
self.assertTrue("changed state" in outbox[-1]['Subject'])
|
||||
self.assertTrue("is no longer" in str(outbox[-1]))
|
||||
self.assertTrue("Test comment" in str(outbox[-1]))
|
||||
|
||||
def test_change_iana_state(self):
|
||||
draft = make_test_data()
|
||||
|
||||
first_state = State.objects.get(type="draft-iana-review", slug="need-rev")
|
||||
next_state = State.objects.get(type="draft-iana-review", slug="ok-noact")
|
||||
draft.set_state(first_state)
|
||||
|
||||
url = urlreverse('doc_change_iana_state', kwargs=dict(name=draft.name, state_type="iana-review"))
|
||||
login_testing_unauthorized(self, "iana", url)
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('form select[name=state]')), 1)
|
||||
|
||||
# faulty post
|
||||
r = self.client.post(url, dict(state="foobarbaz"))
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(len(q('form ul.errorlist')) > 0)
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEquals(draft.get_state("draft-iana-review"), first_state)
|
||||
|
||||
# change state
|
||||
r = self.client.post(url, dict(state=next_state.pk))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEquals(draft.get_state("draft-iana-review"), next_state)
|
||||
|
||||
def test_request_last_call(self):
|
||||
draft = make_test_data()
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="ad-eval"))
|
||||
|
@ -202,7 +256,7 @@ class EditInfoTestCase(django.test.TestCase):
|
|||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEquals(draft.ad, new_ad)
|
||||
self.assertEquals(draft.note, "New note")
|
||||
self.assertTrue(not draft.latest_event(TelechatDocEvent, type="telechat_date"))
|
||||
self.assertTrue(not draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat"))
|
||||
self.assertEquals(draft.docevent_set.count(), events_before + 3)
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue(draft.name in outbox[-1]['Subject'])
|
||||
|
@ -221,14 +275,14 @@ class EditInfoTestCase(django.test.TestCase):
|
|||
)
|
||||
|
||||
# add to telechat
|
||||
self.assertTrue(not draft.latest_event(TelechatDocEvent, "scheduled_for_telechat"))
|
||||
self.assertTrue(not draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat"))
|
||||
data["telechat_date"] = TelechatDate.objects.active()[0].date.isoformat()
|
||||
r = self.client.post(url, data)
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue(draft.latest_event(TelechatDocEvent, "scheduled_for_telechat"))
|
||||
self.assertEquals(draft.latest_event(TelechatDocEvent, "scheduled_for_telechat").telechat_date, TelechatDate.objects.active()[0].date)
|
||||
self.assertTrue(draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat"))
|
||||
self.assertEqual(draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat").telechat_date, TelechatDate.objects.active()[0].date)
|
||||
|
||||
# change telechat
|
||||
data["telechat_date"] = TelechatDate.objects.active()[1].date.isoformat()
|
||||
|
@ -236,7 +290,7 @@ class EditInfoTestCase(django.test.TestCase):
|
|||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEquals(draft.latest_event(TelechatDocEvent, "scheduled_for_telechat").telechat_date, TelechatDate.objects.active()[1].date)
|
||||
self.assertEqual(draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat").telechat_date, TelechatDate.objects.active()[1].date)
|
||||
|
||||
# remove from agenda
|
||||
data["telechat_date"] = ""
|
||||
|
@ -244,7 +298,7 @@ class EditInfoTestCase(django.test.TestCase):
|
|||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue(not draft.latest_event(TelechatDocEvent, "scheduled_for_telechat").telechat_date)
|
||||
self.assertTrue(not draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat").telechat_date)
|
||||
|
||||
def test_start_iesg_process_on_draft(self):
|
||||
make_test_data()
|
||||
|
@ -311,6 +365,18 @@ class EditInfoTestCase(django.test.TestCase):
|
|||
self.assertEquals(events[-3].type, "started_iesg_process")
|
||||
self.assertEquals(len(outbox), mailbox_before)
|
||||
|
||||
def test_edit_consensus(self):
|
||||
draft = make_test_data()
|
||||
|
||||
url = urlreverse('doc_edit_consensus', kwargs=dict(name=draft.name))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
self.assertTrue(not draft.latest_event(ConsensusDocEvent, type="changed_consensus"))
|
||||
r = self.client.post(url, dict(consensus="Yes"))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
self.assertEqual(draft.latest_event(ConsensusDocEvent, type="changed_consensus").consensus, True)
|
||||
|
||||
|
||||
class ResurrectTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
@ -406,6 +472,16 @@ class AddCommentTestCase(django.test.TestCase):
|
|||
self.assertTrue("updated" in outbox[-1]['Subject'])
|
||||
self.assertTrue(draft.name in outbox[-1]['Subject'])
|
||||
|
||||
# Make sure we can also do it as IANA
|
||||
self.client.login(remote_user="iana")
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('form textarea[name=comment]')), 1)
|
||||
|
||||
|
||||
class EditPositionTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
|
@ -670,12 +746,21 @@ class BallotWriteupsTestCase(django.test.TestCase):
|
|||
url = urlreverse('doc_ballot_writeupnotes', kwargs=dict(name=draft.name))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
# add a IANA review note
|
||||
draft.set_state(State.objects.get(type="draft-iana-review", slug="not-ok"))
|
||||
DocEvent.objects.create(type="iana_review",
|
||||
doc=draft,
|
||||
by=Person.objects.get(user__username="iana"),
|
||||
desc="IANA does not approve of this document, it does not make sense.",
|
||||
)
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('textarea[name=ballot_writeup]')), 1)
|
||||
self.assertEquals(len(q('input[type=submit][value*="Save Ballot Writeup"]')), 1)
|
||||
self.assertTrue("IANA does not" in r.content)
|
||||
|
||||
# save
|
||||
r = self.client.post(url, dict(
|
||||
|
@ -869,6 +954,44 @@ class MakeLastCallTestCase(django.test.TestCase):
|
|||
self.assertTrue("Last Call" in outbox[-3]['Subject'])
|
||||
self.assertTrue("Last Call" in draft.message_set.order_by("-time")[0].subject)
|
||||
|
||||
class RequestPublicationTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
def test_request_publication(self):
|
||||
draft = make_test_data()
|
||||
draft.stream = StreamName.objects.get(slug="iab")
|
||||
draft.group = Group.objects.get(acronym="iab")
|
||||
draft.intended_std_level = IntendedStdLevelName.objects.get(slug="inf")
|
||||
draft.save()
|
||||
draft.set_state(State.objects.get(type="draft-stream-iab", slug="approved"))
|
||||
|
||||
url = urlreverse('doc_request_publication', kwargs=dict(name=draft.name))
|
||||
login_testing_unauthorized(self, "iabchair", url)
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
subject = q('input#id_subject')[0].get("value")
|
||||
self.assertTrue("Document Action" in subject)
|
||||
body = q('.request-publication #id_body').text()
|
||||
self.assertTrue("Informational" in body)
|
||||
self.assertTrue("IAB" in body)
|
||||
|
||||
# approve
|
||||
mailbox_before = len(outbox)
|
||||
|
||||
r = self.client.post(url, dict(subject=subject, body=body))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEquals(draft.get_state_slug("draft-stream-iab"), "rfc-edit")
|
||||
self.assertEquals(len(outbox), mailbox_before + 2)
|
||||
self.assertTrue("Document Action" in outbox[-2]['Subject'])
|
||||
self.assertTrue("Document Action" in draft.message_set.order_by("-time")[0].subject)
|
||||
# the IANA copy
|
||||
self.assertTrue("Document Action" in outbox[-1]['Subject'])
|
||||
|
||||
class ExpireIDsTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
|
@ -1099,341 +1222,6 @@ class ExpireLastCallTestCase(django.test.TestCase):
|
|||
self.assertEquals(draft.docevent_set.count(), events_before + 1)
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("Last Call Expired" in outbox[-1]["Subject"])
|
||||
|
||||
|
||||
|
||||
TEST_RFC_INDEX = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rfc-index xmlns="http://www.rfc-editor.org/rfc-index"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.rfc-editor.org/rfc-index
|
||||
http://www.rfc-editor.org/rfc-index.xsd">
|
||||
<bcp-entry>
|
||||
<doc-id>BCP0110</doc-id>
|
||||
<is-also>
|
||||
<doc-id>RFC4170</doc-id>
|
||||
</is-also>
|
||||
</bcp-entry>
|
||||
<bcp-entry>
|
||||
<doc-id>BCP0111</doc-id>
|
||||
<is-also>
|
||||
<doc-id>RFC4181</doc-id>
|
||||
<doc-id>RFC4841</doc-id>
|
||||
</is-also>
|
||||
</bcp-entry>
|
||||
<fyi-entry>
|
||||
<doc-id>FYI0038</doc-id>
|
||||
<is-also>
|
||||
<doc-id>RFC3098</doc-id>
|
||||
</is-also>
|
||||
</fyi-entry>
|
||||
<rfc-entry>
|
||||
<doc-id>RFC1938</doc-id>
|
||||
<title>A One-Time Password System</title>
|
||||
<author>
|
||||
<name>N. Haller</name>
|
||||
</author>
|
||||
<author>
|
||||
<name>C. Metz</name>
|
||||
</author>
|
||||
<date>
|
||||
<month>May</month>
|
||||
<year>1996</year>
|
||||
</date>
|
||||
<format>
|
||||
<file-format>ASCII</file-format>
|
||||
<char-count>44844</char-count>
|
||||
<page-count>18</page-count>
|
||||
</format>
|
||||
<keywords>
|
||||
<kw>OTP</kw>
|
||||
<kw>authentication</kw>
|
||||
<kw>S/KEY</kw>
|
||||
</keywords>
|
||||
<abstract><p>This document describes a one-time password authentication system (OTP). [STANDARDS-TRACK]</p></abstract>
|
||||
<obsoleted-by>
|
||||
<doc-id>RFC2289</doc-id>
|
||||
</obsoleted-by>
|
||||
<current-status>PROPOSED STANDARD</current-status>
|
||||
<publication-status>PROPOSED STANDARD</publication-status>
|
||||
<stream>Legacy</stream>
|
||||
</rfc-entry>
|
||||
<rfc-entry>
|
||||
<doc-id>RFC2289</doc-id>
|
||||
<title>A One-Time Password System</title>
|
||||
<author>
|
||||
<name>N. Haller</name>
|
||||
</author>
|
||||
<author>
|
||||
<name>C. Metz</name>
|
||||
</author>
|
||||
<author>
|
||||
<name>P. Nesser</name>
|
||||
</author>
|
||||
<author>
|
||||
<name>M. Straw</name>
|
||||
</author>
|
||||
<date>
|
||||
<month>February</month>
|
||||
<year>1998</year>
|
||||
</date>
|
||||
<format>
|
||||
<file-format>ASCII</file-format>
|
||||
<char-count>56495</char-count>
|
||||
<page-count>25</page-count>
|
||||
</format>
|
||||
<keywords>
|
||||
<kw>ONE-PASS</kw>
|
||||
<kw>authentication</kw>
|
||||
<kw>OTP</kw>
|
||||
<kw>replay</kw>
|
||||
<kw>attach</kw>
|
||||
</keywords>
|
||||
<abstract><p>This document describes a one-time password authentication system (OTP). The system provides authentication for system access (login) and other applications requiring authentication that is secure against passive attacks based on replaying captured reusable passwords. [STANDARDS- TRACK]</p></abstract>
|
||||
<obsoletes>
|
||||
<doc-id>RFC1938</doc-id>
|
||||
</obsoletes>
|
||||
<is-also>
|
||||
<doc-id>STD0061</doc-id>
|
||||
</is-also>
|
||||
<current-status>STANDARD</current-status>
|
||||
<publication-status>DRAFT STANDARD</publication-status>
|
||||
<stream>Legacy</stream>
|
||||
</rfc-entry>
|
||||
<rfc-entry>
|
||||
<doc-id>RFC3098</doc-id>
|
||||
<title>How to Advertise Responsibly Using E-Mail and Newsgroups or - how NOT to $$$$$ MAKE ENEMIES FAST! $$$$$</title>
|
||||
<author>
|
||||
<name>T. Gavin</name>
|
||||
</author>
|
||||
<author>
|
||||
<name>D. Eastlake 3rd</name>
|
||||
</author>
|
||||
<author>
|
||||
<name>S. Hambridge</name>
|
||||
</author>
|
||||
<date>
|
||||
<month>April</month>
|
||||
<year>2001</year>
|
||||
</date>
|
||||
<format>
|
||||
<file-format>ASCII</file-format>
|
||||
<char-count>64687</char-count>
|
||||
<page-count>28</page-count>
|
||||
</format>
|
||||
<keywords>
|
||||
<kw>internet</kw>
|
||||
<kw>marketing</kw>
|
||||
<kw>users</kw>
|
||||
<kw>service</kw>
|
||||
<kw>providers</kw>
|
||||
<kw>isps</kw>
|
||||
</keywords>
|
||||
<abstract><p>This memo offers useful suggestions for responsible advertising techniques that can be used via the internet in an environment where the advertiser, recipients, and the Internet Community can coexist in a productive and mutually respectful fashion. This memo provides information for the Internet community.</p></abstract>
|
||||
<draft>draft-ietf-run-adverts-02</draft>
|
||||
<is-also>
|
||||
<doc-id>FYI0038</doc-id>
|
||||
</is-also>
|
||||
<current-status>INFORMATIONAL</current-status>
|
||||
<publication-status>INFORMATIONAL</publication-status>
|
||||
<stream>Legacy</stream>
|
||||
</rfc-entry>
|
||||
<rfc-entry>
|
||||
<doc-id>RFC4170</doc-id>
|
||||
<title>Tunneling Multiplexed Compressed RTP (TCRTP)</title>
|
||||
<author>
|
||||
<name>B. Thompson</name>
|
||||
</author>
|
||||
<author>
|
||||
<name>T. Koren</name>
|
||||
</author>
|
||||
<author>
|
||||
<name>D. Wing</name>
|
||||
</author>
|
||||
<date>
|
||||
<month>November</month>
|
||||
<year>2005</year>
|
||||
</date>
|
||||
<format>
|
||||
<file-format>ASCII</file-format>
|
||||
<char-count>48990</char-count>
|
||||
<page-count>24</page-count>
|
||||
</format>
|
||||
<keywords>
|
||||
<kw>real-time transport protocol</kw>
|
||||
</keywords>
|
||||
<abstract><p>This document describes a method to improve the bandwidth utilization of RTP streams over network paths that carry multiple Real-time Transport Protocol (RTP) streams in parallel between two endpoints, as in voice trunking. The method combines standard protocols that provide compression, multiplexing, and tunneling over a network path for the purpose of reducing the bandwidth used when multiple RTP streams are carried over that path. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</p></abstract>
|
||||
<draft>draft-ietf-avt-tcrtp-08</draft>
|
||||
<is-also>
|
||||
<doc-id>BCP0110</doc-id>
|
||||
</is-also>
|
||||
<current-status>BEST CURRENT PRACTICE</current-status>
|
||||
<publication-status>BEST CURRENT PRACTICE</publication-status>
|
||||
<stream>IETF</stream>
|
||||
<area>rai</area>
|
||||
<wg_acronym>avt</wg_acronym>
|
||||
</rfc-entry>
|
||||
<rfc-entry>
|
||||
<doc-id>RFC4181</doc-id>
|
||||
<title>Guidelines for Authors and Reviewers of MIB Documents</title>
|
||||
<author>
|
||||
<name>C. Heard</name>
|
||||
<title>Editor</title>
|
||||
</author>
|
||||
<date>
|
||||
<month>September</month>
|
||||
<year>2005</year>
|
||||
</date>
|
||||
<format>
|
||||
<file-format>ASCII</file-format>
|
||||
<char-count>102521</char-count>
|
||||
<page-count>42</page-count>
|
||||
</format>
|
||||
<keywords>
|
||||
<kw>standards-track specifications</kw>
|
||||
<kw>management information base</kw>
|
||||
<kw>review</kw>
|
||||
</keywords>
|
||||
<abstract><p>This memo provides guidelines for authors and reviewers of IETF standards-track specifications containing MIB modules. Applicable portions may be used as a basis for reviews of other MIB documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</p></abstract>
|
||||
<draft>draft-ietf-ops-mib-review-guidelines-04</draft>
|
||||
<updated-by>
|
||||
<doc-id>RFC4841</doc-id>
|
||||
</updated-by>
|
||||
<is-also>
|
||||
<doc-id>BCP0111</doc-id>
|
||||
</is-also>
|
||||
<current-status>BEST CURRENT PRACTICE</current-status>
|
||||
<publication-status>BEST CURRENT PRACTICE</publication-status>
|
||||
<stream>IETF</stream>
|
||||
<area>rtg</area>
|
||||
<wg_acronym>ospf</wg_acronym>
|
||||
<errata-url>http://www.rfc-editor.org/errata_search.php?rfc=4181</errata-url>
|
||||
</rfc-entry>
|
||||
<rfc-entry>
|
||||
<doc-id>RFC4841</doc-id>
|
||||
<title>RFC 4181 Update to Recognize the IETF Trust</title>
|
||||
<author>
|
||||
<name>C. Heard</name>
|
||||
<title>Editor</title>
|
||||
</author>
|
||||
<date>
|
||||
<month>March</month>
|
||||
<year>2007</year>
|
||||
</date>
|
||||
<format>
|
||||
<file-format>ASCII</file-format>
|
||||
<char-count>4414</char-count>
|
||||
<page-count>3</page-count>
|
||||
</format>
|
||||
<keywords>
|
||||
<kw>management information base</kw>
|
||||
<kw> standards-track specifications</kw>
|
||||
<kw>mib review</kw>
|
||||
</keywords>
|
||||
<abstract><p>This document updates RFC 4181, "Guidelines for Authors and Reviewers of MIB Documents", to recognize the creation of the IETF Trust. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</p></abstract>
|
||||
<draft>draft-heard-rfc4181-update-00</draft>
|
||||
<updates>
|
||||
<doc-id>RFC4181</doc-id>
|
||||
</updates>
|
||||
<is-also>
|
||||
<doc-id>BCP0111</doc-id>
|
||||
</is-also>
|
||||
<current-status>BEST CURRENT PRACTICE</current-status>
|
||||
<publication-status>BEST CURRENT PRACTICE</publication-status>
|
||||
<stream>IETF</stream>
|
||||
<wg_acronym>NON WORKING GROUP</wg_acronym>
|
||||
</rfc-entry>
|
||||
<std-entry>
|
||||
<doc-id>STD0061</doc-id>
|
||||
<title>A One-Time Password System</title>
|
||||
<is-also>
|
||||
<doc-id>RFC2289</doc-id>
|
||||
</is-also>
|
||||
</std-entry>
|
||||
</rfc-index>
|
||||
'''
|
||||
|
||||
TEST_QUEUE = '''<rfc-editor-queue xmlns="http://www.rfc-editor.org/rfc-editor-queue">
|
||||
<section name="IETF STREAM: WORKING GROUP STANDARDS TRACK">
|
||||
<entry xml:id="draft-ietf-sipping-app-interaction-framework">
|
||||
<draft>draft-ietf-sipping-app-interaction-framework-05.txt</draft>
|
||||
<date-received>2005-10-17</date-received>
|
||||
<state>EDIT</state>
|
||||
<normRef>
|
||||
<ref-name>draft-ietf-sip-gruu</ref-name>
|
||||
<ref-state>IN-QUEUE</ref-state>
|
||||
</normRef>
|
||||
<authors>J. Rosenberg</authors>
|
||||
<title>
|
||||
A Framework for Application Interaction in the Session Initiation Protocol (SIP)
|
||||
</title>
|
||||
<bytes>94672</bytes>
|
||||
<source>Session Initiation Proposal Investigation</source>
|
||||
</entry>
|
||||
</section>
|
||||
<section name="IETF STREAM: NON-WORKING GROUP STANDARDS TRACK">
|
||||
<entry xml:id="draft-ietf-sip-gruu">
|
||||
<draft>draft-ietf-sip-gruu-15.txt</draft>
|
||||
<date-received>2007-10-15</date-received>
|
||||
<state>MISSREF</state>
|
||||
<normRef>
|
||||
<ref-name>draft-ietf-sip-outbound</ref-name>
|
||||
<ref-state>NOT-RECEIVED</ref-state>
|
||||
</normRef>
|
||||
<authors>J. Rosenberg</authors>
|
||||
<title>
|
||||
Obtaining and Using Globally Routable User Agent (UA) URIs (GRUU) in the Session Initiation Protocol (SIP)
|
||||
</title>
|
||||
<bytes>95501</bytes>
|
||||
<source>Session Initiation Protocol</source>
|
||||
</entry>
|
||||
</section>
|
||||
<section name="IETF STREAM: WORKING GROUP INFORMATIONAL/EXPERIMENTAL/BCP">
|
||||
</section>
|
||||
<section name="IETF STREAM: NON-WORKING GROUP INFORMATIONAL/EXPERIMENTAL/BCP">
|
||||
<entry xml:id="draft-thomson-beep-async">
|
||||
<draft>draft-thomson-beep-async-02.txt</draft>
|
||||
<date-received>2009-05-12</date-received>
|
||||
<state>EDIT</state>
|
||||
<state>IANA</state>
|
||||
<authors>M. Thomson</authors>
|
||||
<title>
|
||||
Asynchronous Channels for the Blocks Extensible Exchange Protocol (BEEP)
|
||||
</title>
|
||||
<bytes>17237</bytes>
|
||||
<source>IETF - NON WORKING GROUP</source>
|
||||
</entry>
|
||||
</section>
|
||||
<section name="IAB STREAM">
|
||||
</section>
|
||||
<section name="IRTF STREAM">
|
||||
</section>
|
||||
<section name="INDEPENDENT SUBMISSIONS">
|
||||
</section>
|
||||
</rfc-editor-queue>
|
||||
'''
|
||||
|
||||
class MirrorScriptTestCases(unittest.TestCase,RealDatabaseTest):
|
||||
|
||||
def setUp(self):
|
||||
self.setUpRealDatabase()
|
||||
def tearDown(self):
|
||||
self.tearDownRealDatabase()
|
||||
|
||||
def testRfcIndex(self):
|
||||
print " Testing rfc-index.xml parsing"
|
||||
from ietf.idrfc.mirror_rfc_index import parse
|
||||
data = parse(StringIO.StringIO(TEST_RFC_INDEX))
|
||||
self.assertEquals(len(data), 6)
|
||||
print "OK"
|
||||
|
||||
def testRfcEditorQueue(self):
|
||||
print " Testing queue2.xml parsing"
|
||||
from ietf.idrfc.mirror_rfc_editor_queue import parse_all
|
||||
(drafts,refs) = parse_all(StringIO.StringIO(TEST_QUEUE))
|
||||
self.assertEquals(len(drafts), 3)
|
||||
self.assertEquals(len(refs), 3)
|
||||
print "OK"
|
||||
|
||||
|
||||
class IndividualInfoFormsTestCase(django.test.TestCase):
|
||||
|
||||
|
|
|
@ -49,12 +49,13 @@ urlpatterns = patterns('',
|
|||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/(?P<ballot_id>[0-9]+)/emailposition/$', views_ballot.send_ballot_comment, name='doc_send_ballot_comment'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/(?P<ballot_id>[0-9]+)/$', views_doc.document_ballot, name="doc_ballot"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/$', views_doc.document_ballot, name="doc_ballot"),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/doc.json$', views_doc.document_debug),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/doc.json$', views_doc.document_json),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/ballotpopup/$', views_doc.ballot_for_popup),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot.tsv$', views_doc.ballot_tsv),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot.json$', views_doc.ballot_json),
|
||||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/$', views_edit.change_state, name='doc_change_state'), # IESG state
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/(?P<state_type>iana-action|iana-review)/$', views_edit.change_iana_state, name='doc_change_iana_state'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/info/$', views_edit.edit_info, name='doc_edit_info'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/requestresurrect/$', views_edit.request_resurrect, name='doc_request_resurrect'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/resurrect/$', views_edit.resurrect, name='doc_resurrect'),
|
||||
|
@ -66,6 +67,8 @@ urlpatterns = patterns('',
|
|||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/telechat/$', views_edit.telechat_date, name='doc_change_telechat_date'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/iesgnote/$', views_edit.edit_iesg_note, name='doc_change_iesg_note'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/ad/$', views_edit.edit_ad, name='doc_change_ad'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/consensus/$', views_edit.edit_consensus, name='doc_edit_consensus'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/requestpublication/$', views_edit.request_publication, name='doc_request_publication'),
|
||||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/clearballot/$', views_ballot.clear_ballot, name='doc_clear_ballot'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/deferballot/$', views_ballot.defer_ballot, name='doc_defer_ballot'),
|
||||
|
|
|
@ -2,6 +2,7 @@ from django.conf import settings
|
|||
|
||||
from ietf.idtracker.models import InternetDraft, DocumentComment, BallotInfo, IESGLogin
|
||||
from ietf.idrfc.mails import *
|
||||
from ietf.ietfauth.decorators import has_role
|
||||
|
||||
def add_document_comment(request, doc, text, ballot=None):
|
||||
if request:
|
||||
|
@ -175,3 +176,24 @@ def update_telechatREDESIGN(request, doc, by, new_telechat_date, new_returning_i
|
|||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
update_telechat = update_telechatREDESIGN
|
||||
|
||||
def can_edit_intended_std_level(doc, user):
|
||||
return user.is_authenticated() and (
|
||||
has_role(user, ["Secretariat", "Area Director"]) or
|
||||
doc.group.role_set.filter(name__in=("chair", "auth", "delegate"), person__user=user)
|
||||
)
|
||||
|
||||
def can_edit_consensus(doc, user):
|
||||
return user.is_authenticated() and (
|
||||
has_role(user, ["Secretariat", "Area Director"]) or
|
||||
doc.group.role_set.filter(name__in=("chair", "auth", "delegate"), person__user=user)
|
||||
)
|
||||
|
||||
def nice_consensus(consensus):
|
||||
mapping = {
|
||||
None: "Unknown",
|
||||
True: "Yes",
|
||||
False: "No"
|
||||
}
|
||||
return mapping[consensus]
|
||||
|
||||
|
|
|
@ -726,7 +726,7 @@ def ballot_writeupnotes(request, name):
|
|||
msg = generate_issue_ballot_mail(request, doc)
|
||||
send_mail_preformatted(request, msg)
|
||||
|
||||
email_iana(request, doc, 'drafts-eval@icann.org', msg)
|
||||
# email_iana(request, doc, 'drafts-eval@icann.org', msg)
|
||||
|
||||
doc.b_sent_date = date.today()
|
||||
doc.save()
|
||||
|
@ -807,8 +807,8 @@ def ballot_writeupnotesREDESIGN(request, name):
|
|||
|
||||
msg = generate_issue_ballot_mail(request, doc, ballot)
|
||||
send_mail_preformatted(request, msg)
|
||||
|
||||
email_iana(request, doc, 'drafts-eval@icann.org', msg)
|
||||
send_mail_preformatted(request, msg, extra=extra_automation_headers(doc),
|
||||
override={ "To": "IANA <drafts-eval@icann.org>" })
|
||||
|
||||
e = DocEvent(doc=doc, by=login)
|
||||
e.by = login
|
||||
|
@ -1043,7 +1043,8 @@ def approve_ballotREDESIGN(request, name):
|
|||
send_mail_preformatted(request, announcement)
|
||||
|
||||
if action == "to_announcement_list":
|
||||
email_iana(request, doc, "drafts-approval@icann.org", announcement)
|
||||
send_mail_preformatted(request, announcement, extra=extra_automation_headers(doc),
|
||||
override={ "To": "IANA <drafts-approval@icann.org>" })
|
||||
|
||||
msg = infer_message(announcement)
|
||||
msg.by = login
|
||||
|
@ -1068,62 +1069,10 @@ class MakeLastCallForm(forms.Form):
|
|||
|
||||
@group_required('Secretariat')
|
||||
def make_last_call(request, name):
|
||||
"""Make last call for Internet Draft, sending out announcement."""
|
||||
doc = get_object_or_404(InternetDraft, filename=name)
|
||||
if not doc.idinternal:
|
||||
raise Http404()
|
||||
|
||||
login = IESGLogin.objects.get(login_name=request.user.username)
|
||||
|
||||
ballot = doc.idinternal.ballot
|
||||
docs = [i.document() for i in doc.idinternal.ballot_set()]
|
||||
|
||||
announcement = ballot.last_call_text
|
||||
|
||||
if request.method == 'POST':
|
||||
form = MakeLastCallForm(request.POST)
|
||||
if form.is_valid():
|
||||
send_mail_preformatted(request, announcement)
|
||||
email_iana(request, doc, "drafts-lastcall@icann.org", announcement)
|
||||
|
||||
doc.idinternal.change_state(IDState.objects.get(document_state_id=IDState.IN_LAST_CALL), None)
|
||||
doc.idinternal.event_date = date.today()
|
||||
doc.idinternal.save()
|
||||
|
||||
idrfcutil_log_state_changed(request, doc, login)
|
||||
|
||||
doc.lc_sent_date = form.cleaned_data['last_call_sent_date']
|
||||
doc.lc_expiration_date = form.cleaned_data['last_call_expiration_date']
|
||||
doc.save()
|
||||
|
||||
comment = "Last call has been made for %s ballot and state has been changed to %s" % (doc.filename, doc.idinternal.cur_state.state)
|
||||
email_owner(request, doc, doc.idinternal.job_owner, login, comment)
|
||||
|
||||
return HttpResponseRedirect(doc.idinternal.get_absolute_url())
|
||||
else:
|
||||
initial = {}
|
||||
initial["last_call_sent_date"] = date.today()
|
||||
expire_days = 14
|
||||
if doc.group_id == Acronym.INDIVIDUAL_SUBMITTER:
|
||||
expire_days = 28
|
||||
|
||||
initial["last_call_expiration_date"] = date.today() + timedelta(days=expire_days)
|
||||
|
||||
form = MakeLastCallForm(initial=initial)
|
||||
|
||||
return render_to_response('idrfc/make_last_call.html',
|
||||
dict(doc=doc,
|
||||
docs=docs,
|
||||
form=form),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@group_required('Secretariat')
|
||||
def make_last_callREDESIGN(request, name):
|
||||
"""Make last call for Internet Draft, sending out announcement."""
|
||||
doc = get_object_or_404(Document, docalias__name=name)
|
||||
if not doc.get_state("draft-iesg"):
|
||||
raise Http404()
|
||||
raise Http404
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
|
@ -1136,7 +1085,8 @@ def make_last_callREDESIGN(request, name):
|
|||
form = MakeLastCallForm(request.POST)
|
||||
if form.is_valid():
|
||||
send_mail_preformatted(request, announcement)
|
||||
email_iana(request, doc, "drafts-lastcall@icann.org", announcement)
|
||||
send_mail_preformatted(request, announcement, extra=extra_automation_headers(doc),
|
||||
override={ "To": "IANA <drafts-lastcall@icann.org>" })
|
||||
|
||||
msg = infer_message(announcement)
|
||||
msg.by = login
|
||||
|
@ -1171,7 +1121,14 @@ def make_last_callREDESIGN(request, name):
|
|||
e.time = datetime.datetime.combine(form.cleaned_data['last_call_sent_date'], e.time.time())
|
||||
e.expires = form.cleaned_data['last_call_expiration_date']
|
||||
e.save()
|
||||
|
||||
|
||||
# update IANA Review state
|
||||
prev_state = doc.get_state("draft-iana-review")
|
||||
if not prev_state:
|
||||
next_state = State.objects.get(type="draft-iana-review", slug="need-rev")
|
||||
doc.set_state(next_state)
|
||||
add_state_change_event(doc, login, prev_state, next_state)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
else:
|
||||
initial = {}
|
||||
|
@ -1188,7 +1145,3 @@ def make_last_callREDESIGN(request, name):
|
|||
dict(doc=doc,
|
||||
form=form),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
make_last_call = make_last_callREDESIGN
|
||||
|
|
|
@ -46,6 +46,7 @@ from django.conf import settings
|
|||
from ietf.idtracker.models import InternetDraft, IDInternal, BallotInfo, DocumentComment
|
||||
from ietf.idtracker.templatetags.ietf_filters import format_textarea, fill
|
||||
from ietf.idrfc import markup_txt
|
||||
from ietf.idrfc.utils import *
|
||||
from ietf.idrfc.models import RfcIndex, DraftVersions
|
||||
from ietf.idrfc.idrfc_wrapper import BallotWrapper, IdWrapper, RfcWrapper
|
||||
from ietf.ietfworkflows.utils import get_full_info_for_draft
|
||||
|
@ -54,7 +55,6 @@ from ietf.doc.utils import *
|
|||
from ietf.utils.history import find_history_active_at
|
||||
from ietf.ietfauth.decorators import has_role
|
||||
|
||||
|
||||
def render_document_top(request, doc, tab, name):
|
||||
tabs = []
|
||||
tabs.append(("Document", "document", urlreverse("ietf.idrfc.views_doc.document_main", kwargs=dict(name=name)), True))
|
||||
|
@ -349,17 +349,51 @@ def document_ballot(request, name, ballot_id=None):
|
|||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def document_debug(request, name):
|
||||
r = re.compile("^rfc([1-9][0-9]*)$")
|
||||
m = r.match(name)
|
||||
if m:
|
||||
rfc_number = int(m.group(1))
|
||||
rfci = get_object_or_404(RfcIndex, rfc_number=rfc_number)
|
||||
doc = RfcWrapper(rfci)
|
||||
else:
|
||||
id = get_object_or_404(InternetDraft, filename=name)
|
||||
doc = IdWrapper(draft=id)
|
||||
return HttpResponse(doc.to_json(), mimetype='text/plain')
|
||||
def document_json(request, name):
|
||||
doc = get_object_or_404(Document, docalias__name=name)
|
||||
|
||||
def extract_name(s):
|
||||
return s.name if s else None
|
||||
|
||||
data = {}
|
||||
|
||||
data["name"] = doc.name
|
||||
data["rev"] = doc.rev
|
||||
data["time"] = doc.time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
data["group"] = None
|
||||
if doc.group:
|
||||
data["group"] = dict(
|
||||
name=doc.group.name,
|
||||
type=extract_name(doc.group.type),
|
||||
acronym=doc.group.acronym)
|
||||
data["expires"] = doc.expires.strftime("%Y-%m-%d %H:%M:%S") if doc.expires else None
|
||||
data["title"] = doc.title
|
||||
data["abstract"] = doc.abstract
|
||||
data["aliases"] = list(doc.docalias_set.values_list("name", flat=True))
|
||||
data["state"] = extract_name(doc.get_state())
|
||||
data["intended_std_level"] = extract_name(doc.intended_std_level)
|
||||
data["std_level"] = extract_name(doc.std_level)
|
||||
data["authors"] = [
|
||||
dict(name=e.person.name,
|
||||
email=e.address,
|
||||
affiliation=e.person.affiliation)
|
||||
for e in Email.objects.filter(documentauthor__document=doc).select_related("person").order_by("documentauthor__order")
|
||||
]
|
||||
data["shepherd"] = doc.shepherd.formatted_email() if doc.shepherd else None
|
||||
data["ad"] = doc.ad.role_email("ad").formatted_email() if doc.ad else None
|
||||
|
||||
if doc.type_id == "draft":
|
||||
data["iesg_state"] = extract_name(doc.get_state("draft-iesg"))
|
||||
data["rfceditor_state"] = extract_name(doc.get_state("draft-rfceditor"))
|
||||
data["iana_review_state"] = extract_name(doc.get_state("draft-iana-review"))
|
||||
data["iana_action_state"] = extract_name(doc.get_state("draft-iana-action"))
|
||||
|
||||
if doc.stream_id in ("ietf", "irtf", "iab"):
|
||||
e = doc.latest_event(ConsensusDocEvent, type="changed_consensus")
|
||||
data["consensus"] = e.consensus if e else None
|
||||
data["stream"] = extract_name(doc.stream)
|
||||
|
||||
return HttpResponse(json.dumps(data, indent=2), mimetype='text/plain')
|
||||
|
||||
def _get_html(key, filename, split=True):
|
||||
return get_document_content(key, filename, split=split, markup=True)
|
||||
|
@ -415,7 +449,16 @@ def document_main_idrfc(request, name, tab):
|
|||
info['is_rfc'] = False
|
||||
|
||||
info['conflict_reviews'] = [ rel.source for alias in id.docalias_set.all() for rel in alias.relateddocument_set.filter(relationship='conflrev') ]
|
||||
|
||||
info['rfc_editor_state'] = id.get_state("draft-rfceditor")
|
||||
info['iana_review_state'] = id.get_state("draft-iana-review")
|
||||
info['iana_action_state'] = id.get_state("draft-iana-action")
|
||||
info["consensus"] = None
|
||||
if id.stream_id in ("ietf", "irtf", "iab"):
|
||||
e = id.latest_event(ConsensusDocEvent, type="changed_consensus")
|
||||
info["consensus"] = nice_consensus(e and e.consensus)
|
||||
info["can_edit_consensus"] = can_edit_consensus(id, request.user)
|
||||
info["can_edit_intended_std_level"] = can_edit_intended_std_level(id, request.user)
|
||||
|
||||
(content1, content2) = _get_html(
|
||||
str(name)+","+str(id.revision)+",html",
|
||||
os.path.join(settings.INTERNET_DRAFT_PATH, name+"-"+id.revision+".txt"))
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import re, os
|
||||
from datetime import datetime, date, time, timedelta
|
||||
from django.http import HttpResponse, HttpResponseRedirect, Http404
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
|
||||
from django.shortcuts import render_to_response, get_object_or_404
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.template.loader import render_to_string
|
||||
|
@ -13,10 +13,10 @@ from django.utils.html import strip_tags
|
|||
from django.db.models import Max
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.utils.mail import send_mail_text
|
||||
from ietf.utils.mail import send_mail_text, send_mail_message
|
||||
from ietf.ietfauth.decorators import group_required
|
||||
from ietf.idtracker.templatetags.ietf_filters import in_group
|
||||
from ietf.ietfauth.decorators import has_role
|
||||
from ietf.ietfauth.decorators import has_role, role_required
|
||||
from ietf.idtracker.models import *
|
||||
from ietf.iesg.models import *
|
||||
from ietf.idrfc.mails import *
|
||||
|
@ -26,10 +26,13 @@ from ietf.idrfc.lastcall import request_last_call
|
|||
from ietf.ietfworkflows.models import Stream
|
||||
from ietf.ietfworkflows.utils import update_stream
|
||||
from ietf.ietfworkflows.streams import get_stream_from_draft
|
||||
from ietf.ietfworkflows.accounts import can_edit_state
|
||||
|
||||
from ietf.doc.models import *
|
||||
from ietf.doc.utils import *
|
||||
from ietf.name.models import IntendedStdLevelName, DocTagName, StreamName
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.message.models import Message
|
||||
|
||||
class ChangeStateForm(forms.Form):
|
||||
pass
|
||||
|
@ -58,20 +61,21 @@ def change_stateREDESIGN(request, name):
|
|||
if request.method == 'POST':
|
||||
form = ChangeStateForm(request.POST)
|
||||
if form.is_valid():
|
||||
state = form.cleaned_data['state']
|
||||
next_state = form.cleaned_data['state']
|
||||
prev_state = doc.get_state("draft-iesg")
|
||||
|
||||
tag = form.cleaned_data['substate']
|
||||
comment = form.cleaned_data['comment'].strip()
|
||||
prev = doc.get_state("draft-iesg")
|
||||
|
||||
# tag handling is a bit awkward since the UI still works
|
||||
# as if IESG tags are a substate
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
|
||||
if state != prev or tag != prev_tag:
|
||||
if next_state != prev_state or tag != prev_tag:
|
||||
save_document_in_history(doc)
|
||||
|
||||
doc.set_state(state)
|
||||
doc.set_state(next_state)
|
||||
|
||||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
@ -79,7 +83,7 @@ def change_stateREDESIGN(request, name):
|
|||
if tag:
|
||||
doc.tags.add(tag)
|
||||
|
||||
e = log_state_changed(request, doc, login, prev, prev_tag)
|
||||
e = log_state_changed(request, doc, login, prev_state, prev_tag)
|
||||
|
||||
if comment:
|
||||
c = DocEvent(type="added_comment")
|
||||
|
@ -96,7 +100,15 @@ def change_stateREDESIGN(request, name):
|
|||
email_state_changed(request, doc, e.desc)
|
||||
email_owner(request, doc, doc.ad, login, e.desc)
|
||||
|
||||
if state.slug == "lc-req":
|
||||
|
||||
if prev_state and prev_state.slug in ("ann", "rfcqueue") and next_state.slug not in ("rfcqueue", "pub"):
|
||||
email_pulled_from_rfc_queue(request, doc, comment, prev_state, next_state)
|
||||
|
||||
if next_state.slug in ("iesg-eva", "lc"):
|
||||
if not doc.get_state_slug("draft-iana-review"):
|
||||
doc.set_state(State.objects.get(type="draft-iana-review", slug="rev-need"))
|
||||
|
||||
if next_state.slug == "lc-req":
|
||||
request_last_call(request, doc)
|
||||
|
||||
return render_to_response('idrfc/last_call_requested.html',
|
||||
|
@ -129,6 +141,7 @@ def change_stateREDESIGN(request, name):
|
|||
return render_to_response('idrfc/change_stateREDESIGN.html',
|
||||
dict(form=form,
|
||||
doc=doc,
|
||||
state=state,
|
||||
prev_state=prev_state,
|
||||
next_states=next_states,
|
||||
to_iesg_eval=to_iesg_eval),
|
||||
|
@ -138,6 +151,52 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|||
change_state = change_stateREDESIGN
|
||||
ChangeStateForm = ChangeStateFormREDESIGN
|
||||
|
||||
class ChangeIanaStateForm(forms.Form):
|
||||
state = forms.ModelChoiceField(State.objects.all(), required=False)
|
||||
|
||||
def __init__(self, state_type, *args, **kwargs):
|
||||
super(self.__class__, self).__init__(*args, **kwargs)
|
||||
|
||||
choices = State.objects.filter(type=state_type).order_by("order").values_list("pk", "name")
|
||||
self.fields['state'].choices = [("", "-------")] + list(choices)
|
||||
|
||||
@role_required('Secretariat', 'IANA')
|
||||
def change_iana_state(request, name, state_type):
|
||||
"""Change IANA review state of Internet Draft. Normally, this is done via
|
||||
automatic sync, but this form allows one to set it manually."""
|
||||
doc = get_object_or_404(Document, docalias__name=name)
|
||||
|
||||
state_type = doc.type_id + "-" + state_type
|
||||
|
||||
prev_state = doc.get_state(state_type)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ChangeIanaStateForm(state_type, request.POST)
|
||||
if form.is_valid():
|
||||
next_state = form.cleaned_data['state']
|
||||
|
||||
if next_state != prev_state:
|
||||
save_document_in_history(doc)
|
||||
|
||||
doc.set_state(next_state)
|
||||
|
||||
e = add_state_change_event(doc, request.user.get_profile(), prev_state, next_state)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
|
||||
else:
|
||||
form = ChangeIanaStateForm(state_type, initial=dict(state=prev_state.pk if prev_state else None))
|
||||
|
||||
return render_to_response('idrfc/change_iana_state.html',
|
||||
dict(form=form,
|
||||
doc=doc),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
|
||||
class ChangeStreamForm(forms.Form):
|
||||
stream = forms.ModelChoiceField(StreamName.objects.exclude(slug="legacy"), required=False)
|
||||
comment = forms.CharField(widget=forms.Textarea, required=False)
|
||||
|
@ -197,13 +256,15 @@ class ChangeIntentionForm(forms.Form):
|
|||
intended_std_level = forms.ModelChoiceField(IntendedStdLevelName.objects.filter(used=True), empty_label="(None)", required=True, label="Intended RFC status")
|
||||
comment = forms.CharField(widget=forms.Textarea, required=False)
|
||||
|
||||
@group_required('Area_Director','Secretariat')
|
||||
def change_intention(request, name):
|
||||
"""Change the intended publication status of a Document of type 'draft' , notifying parties
|
||||
as necessary and logging the change as a comment."""
|
||||
doc = get_object_or_404(Document, docalias__name=name)
|
||||
if not doc.type_id=='draft':
|
||||
raise Http404()
|
||||
if doc.type_id != 'draft':
|
||||
raise Http404
|
||||
|
||||
if not can_edit_intended_std_level(doc, request.user):
|
||||
return HttpResponseForbidden("You do not have the necessary permissions to view this page")
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
|
@ -617,7 +678,7 @@ def add_comment(request, name):
|
|||
back_url=doc.idinternal.get_absolute_url()),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
@group_required('Area_Director', 'Secretariat', 'IANA')
|
||||
@group_required('Area_Director', 'Secretariat', 'IANA', 'RFC Editor')
|
||||
def add_commentREDESIGN(request, name):
|
||||
"""Add comment to history of document."""
|
||||
doc = get_object_or_404(Document, docalias__name=name)
|
||||
|
@ -827,3 +888,116 @@ def edit_ad(request, name):
|
|||
},
|
||||
context_instance = RequestContext(request))
|
||||
|
||||
class ConsensusForm(forms.Form):
|
||||
consensus = forms.ChoiceField(choices=(("", "Unknown"), ("Yes", "Yes"), ("No", "No")), required=True)
|
||||
|
||||
def edit_consensus(request, name):
|
||||
"""Change whether the draft is a consensus document or not."""
|
||||
|
||||
doc = get_object_or_404(Document, type="draft", name=name)
|
||||
|
||||
if not can_edit_consensus(doc, request.user):
|
||||
return HttpResponseForbidden("You do not have the necessary permissions to view this page")
|
||||
|
||||
e = doc.latest_event(ConsensusDocEvent, type="changed_consensus")
|
||||
prev_consensus = e and e.consensus
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ConsensusForm(request.POST)
|
||||
if form.is_valid():
|
||||
if form.cleaned_data["consensus"] != bool(prev_consensus):
|
||||
e = ConsensusDocEvent(doc=doc, type="changed_consensus", by=request.user.get_profile())
|
||||
e.consensus = form.cleaned_data["consensus"] == "Yes"
|
||||
|
||||
e.desc = "Changed consensus to <b>%s</b> from %s" % (nice_consensus(e.consensus),
|
||||
nice_consensus(prev_consensus))
|
||||
|
||||
e.save()
|
||||
|
||||
return HttpResponseRedirect(urlreverse('doc_view', kwargs={'name': doc.name}))
|
||||
|
||||
else:
|
||||
form = ConsensusForm(initial=dict(consensus=nice_consensus(prev_consensus).replace("Unknown", "")))
|
||||
|
||||
return render_to_response('idrfc/change_consensus.html',
|
||||
{'form': form,
|
||||
'doc': doc,
|
||||
},
|
||||
context_instance = RequestContext(request))
|
||||
|
||||
class PublicationForm(forms.Form):
|
||||
subject = forms.CharField(max_length=200, required=True)
|
||||
body = forms.CharField(widget=forms.Textarea, required=True)
|
||||
|
||||
def request_publication(request, name):
|
||||
"""Request publication by RFC Editor for a document which hasn't
|
||||
been through the IESG ballot process."""
|
||||
|
||||
doc = get_object_or_404(Document, type="draft", name=name, stream__in=("iab", "ise", "irtf"))
|
||||
|
||||
if not can_edit_state(request.user, doc):
|
||||
return HttpResponseForbidden("You do not have the necessary permissions to view this page")
|
||||
|
||||
m = Message()
|
||||
m.frm = request.user.get_profile().formatted_email()
|
||||
m.to = "RFC Editor <rfc-editor@rfc-editor.org>"
|
||||
m.by = request.user.get_profile()
|
||||
|
||||
next_state = State.objects.get(type="draft-stream-%s" % doc.stream.slug, slug="rfc-edit")
|
||||
|
||||
if request.method == 'POST' and not request.POST.get("reset"):
|
||||
form = PublicationForm(request.POST)
|
||||
if form.is_valid():
|
||||
m.subject = form.cleaned_data["subject"]
|
||||
m.body = form.cleaned_data["body"]
|
||||
m.save()
|
||||
|
||||
if doc.group.acronym != "none":
|
||||
m.related_groups = [doc.group]
|
||||
m.related_docs = [doc]
|
||||
|
||||
send_mail_message(request, m)
|
||||
|
||||
# IANA copy
|
||||
m.to = "IANA <drafts-approval@icann.org>"
|
||||
send_mail_message(request, m, extra=extra_automation_headers(doc))
|
||||
|
||||
e = DocEvent(doc=doc, type="requested_publication", by=request.user.get_profile())
|
||||
e.desc = "Sent request for publication to the RFC Editor"
|
||||
e.save()
|
||||
|
||||
# change state
|
||||
prev_state = doc.get_state(next_state.type)
|
||||
|
||||
doc.set_state(next_state)
|
||||
|
||||
e = add_state_change_event(doc, request.user.get_profile(), prev_state, next_state)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
||||
return HttpResponseRedirect(urlreverse('doc_view', kwargs={'name': doc.name}))
|
||||
|
||||
else:
|
||||
if doc.intended_std_level_id in ("std", "ds", "ps", "bcp"):
|
||||
action = "Protocol Action"
|
||||
else:
|
||||
action = "Document Action"
|
||||
|
||||
from ietf.idrfc.templatetags.mail_filters import std_level_prompt
|
||||
|
||||
subject = "%s: '%s' to %s (%s-%s.txt)" % (action, doc.title, std_level_prompt(doc), doc.name, doc.rev)
|
||||
|
||||
body = generate_publication_request(request, doc)
|
||||
|
||||
form = PublicationForm(initial=dict(subject=subject,
|
||||
body=body))
|
||||
|
||||
return render_to_response('idrfc/request_publication.html',
|
||||
dict(form=form,
|
||||
doc=doc,
|
||||
message=m,
|
||||
next_state=next_state,
|
||||
),
|
||||
context_instance = RequestContext(request))
|
||||
|
||||
|
|
|
@ -22,4 +22,4 @@
|
|||
# Test case for missing comment time (bug fixed in changeset 1733)
|
||||
200 /feed/comments/draft-ietf-msec-newtype-keyid/
|
||||
|
||||
200,heavy /sitemap-idtracker.xml
|
||||
#200,heavy /sitemap-idtracker.xml
|
||||
|
|
|
@ -54,7 +54,7 @@ from ietf.idrfc.utils import update_telechat
|
|||
from ietf.ietfauth.decorators import group_required
|
||||
from ietf.idtracker.templatetags.ietf_filters import in_group
|
||||
from ietf.ipr.models import IprDocAlias
|
||||
from ietf.doc.models import Document, TelechatDocEvent
|
||||
from ietf.doc.models import Document, TelechatDocEvent, LastCallDocEvent, ConsensusDocEvent
|
||||
from ietf.group.models import Group
|
||||
|
||||
def date_threshold():
|
||||
|
@ -139,7 +139,6 @@ def get_doc_section(id):
|
|||
|
||||
def get_doc_sectionREDESIGN(doc):
|
||||
if doc.type_id == 'draft':
|
||||
states = [16,17,18,19,20,21]
|
||||
if doc.intended_std_level_id in ["bcp", "ds", "ps", "std"]:
|
||||
s = "2"
|
||||
else:
|
||||
|
@ -152,7 +151,7 @@ def get_doc_sectionREDESIGN(doc):
|
|||
s = s + "3"
|
||||
else:
|
||||
s = s + "2"
|
||||
if not doc.get_state_slug=="rfc" and doc.get_state('draft-iesg').order not in states:
|
||||
if not doc.get_state_slug=="rfc" and doc.get_state_slug('draft-iesg') not in ("lc", "writeupw", "goaheadw", "iesg-eva", "defer"):
|
||||
s = s + "3"
|
||||
elif doc.returning_item():
|
||||
s = s + "2"
|
||||
|
@ -191,23 +190,36 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|||
get_doc_section = get_doc_sectionREDESIGN
|
||||
|
||||
def agenda_docs(date, next_agenda):
|
||||
from ietf.doc.models import TelechatDocEvent
|
||||
|
||||
matches = Document.objects.filter(docevent__telechatdocevent__telechat_date=date).distinct()
|
||||
matches = Document.objects.filter(docevent__telechatdocevent__telechat_date=date).select_related("stream").distinct()
|
||||
|
||||
docmatches = []
|
||||
|
||||
for m in matches:
|
||||
if m.latest_event(TelechatDocEvent, type="scheduled_for_telechat").telechat_date != date:
|
||||
for doc in matches:
|
||||
if doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat").telechat_date != date:
|
||||
continue
|
||||
|
||||
e = m.latest_event(type="started_iesg_process")
|
||||
m.balloting_started = e.time if e else datetime.datetime.min
|
||||
e = doc.latest_event(type="started_iesg_process")
|
||||
doc.balloting_started = e.time if e else datetime.datetime.min
|
||||
|
||||
if m.type_id=='conflrev':
|
||||
m.conflictdoc = m.relateddocument_set.get(relationship__slug='conflrev').target.document
|
||||
if doc.type_id == "draft":
|
||||
s = doc.get_state("draft-iana-review")
|
||||
if s and s.slug in ("not-ok", "changed", "need-rev"):
|
||||
doc.iana_review_state = str(s)
|
||||
|
||||
docmatches.append(m)
|
||||
if doc.get_state_slug("draft-iesg") == "lc":
|
||||
e = doc.latest_event(LastCallDocEvent, type="sent_last_call")
|
||||
if e:
|
||||
doc.lastcall_expires = e.expires
|
||||
|
||||
if doc.stream_id in ("ietf", "irtf", "iab"):
|
||||
doc.consensus = "Unknown"
|
||||
e = doc.latest_event(ConsensusDocEvent, type="changed_consensus")
|
||||
if e:
|
||||
doc.consensus = "Yes" if e.consensus else "No"
|
||||
elif doc.type_id=='conflrev':
|
||||
doc.conflictdoc = doc.relateddocument_set.get(relationship__slug='conflrev').target.document
|
||||
|
||||
docmatches.append(doc)
|
||||
|
||||
# Be careful to keep this the same as what's used in agenda_documents
|
||||
docmatches.sort(key=lambda d: d.balloting_started)
|
||||
|
@ -313,19 +325,37 @@ def _agenda_json(request, date=None):
|
|||
if defer:
|
||||
docinfo['defer-by'] = defer.by.name
|
||||
docinfo['defer-at'] = str(defer.time)
|
||||
if d.type_id == 'conflrev':
|
||||
td = d.relateddocument_set.get(relationship__slug='conflrev').target.document
|
||||
if doc.type_id == "draft":
|
||||
docinfo['intended-std-level'] = str(doc.intended_std_level)
|
||||
if doc.rfc_number():
|
||||
docinfo['rfc-number'] = doc.rfc_number()
|
||||
else:
|
||||
docinfo['rev'] = doc.rev
|
||||
|
||||
iana_state = doc.get_state("draft-iana-review")
|
||||
if iana_state.slug in ("not-ok", "changed", "need-rev"):
|
||||
docinfo['iana_review_state'] = str(iana_state)
|
||||
|
||||
if doc.get_state_slug("draft-iesg") == "lc":
|
||||
e = doc.latest_event(LastCallDocEvent, type="sent_last_call")
|
||||
if e:
|
||||
docinfo['lastcall_expires'] = e.expires
|
||||
|
||||
docinfo['consensus'] = None
|
||||
e = doc.latest_event(ConsensusDocEvent, type="changed_consensus")
|
||||
if e:
|
||||
docinfo['consensus'] = e.consensus
|
||||
elif doc.type_id == 'conflrev':
|
||||
td = doc.relateddocument_set.get(relationship__slug='conflrev').target.document
|
||||
docinfo['target-docname'] = td.canonical_name()
|
||||
docinfo['target-title'] = td.title
|
||||
docinfo['target-rev'] = td.rev
|
||||
docinfo['intended-std-level'] = str(td.intended_std_level)
|
||||
docinfo['stream'] = str(td.stream)
|
||||
else:
|
||||
docinfo['intended-std-level'] = str(d.intended_std_level)
|
||||
if d.rfc_number():
|
||||
docinfo['rfc-number'] = d.rfc_number()
|
||||
else:
|
||||
docinfo['rev'] = d.rev
|
||||
else:
|
||||
# XXX check this -- is there nothing to set for
|
||||
# all other documents here?
|
||||
pass
|
||||
data['sections'][s]['docs'] += [docinfo, ]
|
||||
|
||||
wgs = agenda_wg_actions(date)
|
||||
|
|
|
@ -89,6 +89,7 @@ def has_role(user, role_names):
|
|||
"Area Director": Q(person=person, name__in=("pre-ad", "ad"), group__type="area", group__state="active"),
|
||||
"Secretariat": Q(person=person, name="secr", group__acronym="secretariat"),
|
||||
"IANA": Q(person=person, name="auth", group__acronym="iana"),
|
||||
"RFC Editor": Q(person=person, name="auth", group__acronym="rfceditor"),
|
||||
"IAD": Q(person=person, name="admdir", group__acronym="ietf"),
|
||||
"IETF Chair": Q(person=person, name="chair", group__acronym="ietf"),
|
||||
"IAB Chair": Q(person=person, name="chair", group__acronym="iab"),
|
||||
|
|
|
@ -46,7 +46,7 @@ from django.utils.http import urlquote
|
|||
from django.utils import simplejson as json
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from ietf.ietfauth.forms import RegistrationForm, PasswordForm, RecoverPasswordForm
|
||||
from ietf.ietfauth.forms import RegistrationForm, PasswordForm, RecoverPasswordForm, TestEmailForm
|
||||
|
||||
def index(request):
|
||||
return render_to_response('registration/index.html', context_instance=RequestContext(request))
|
||||
|
|
|
@ -108,14 +108,6 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|||
|
||||
|
||||
def can_edit_state(user, draft):
|
||||
streamed = get_streamed_draft(draft)
|
||||
if not settings.USE_DB_REDESIGN_PROXY_CLASSES and (not streamed or not streamed.stream):
|
||||
person = get_person_for_user(user)
|
||||
if not person:
|
||||
return False
|
||||
return (is_secretariat(user) or
|
||||
is_wgchair(person) or
|
||||
is_wgdelegate(person))
|
||||
return (is_secretariat(user) or
|
||||
is_authorized_in_draft_stream(user, draft))
|
||||
|
||||
|
|
|
@ -74,6 +74,8 @@ def edit_actions(context, wrapper):
|
|||
|
||||
if can_edit_state(user, draft):
|
||||
actions.append(("Change stream state", urlreverse('edit_state', kwargs=dict(name=doc.draft_name))))
|
||||
if draft.stream_id in ("iab", "ise", "irtf"):
|
||||
actions.append(("Request publication", urlreverse('doc_request_publication', kwargs=dict(name=doc.draft_name))))
|
||||
|
||||
if can_manage_shepherd_of_a_document(user, draft):
|
||||
actions.append(("Change shepherd", urlreverse('doc_managing_shepherd', kwargs=dict(acronym=draft.group.acronym, name=draft.filename))))
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="iana-crd" model="name.doctagname">
|
||||
<object pk="iana" model="name.doctagname">
|
||||
<field type="CharField" name="name">IANA coordination</field>
|
||||
<field type="TextField" name="desc">RFC-Editor/IANA Registration Coordination</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
|
@ -325,36 +325,6 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="no" model="name.groupballotpositionname">
|
||||
<field type="CharField" name="name">No</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="yes" model="name.groupballotpositionname">
|
||||
<field type="CharField" name="name">Yes</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="abstain" model="name.groupballotpositionname">
|
||||
<field type="CharField" name="name">Abstain</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="block" model="name.groupballotpositionname">
|
||||
<field type="CharField" name="name">Block</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="norecord" model="name.groupballotpositionname">
|
||||
<field type="CharField" name="name">No record</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="bof" model="name.groupstatename">
|
||||
<field type="CharField" name="name">BOF</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
|
@ -751,8 +721,11 @@
|
|||
<object pk="draft-iesg" model="doc.statetype">
|
||||
<field type="CharField" name="label">IESG state</field>
|
||||
</object>
|
||||
<object pk="draft-iana" model="doc.statetype">
|
||||
<field type="CharField" name="label">IANA state</field>
|
||||
<object pk="draft-iana-action" model="doc.statetype">
|
||||
<field type="CharField" name="label">IANA Action state</field>
|
||||
</object>
|
||||
<object pk="draft-iana-review" model="doc.statetype">
|
||||
<field type="CharField" name="label">IANA Review state</field>
|
||||
</object>
|
||||
<object pk="draft-rfceditor" model="doc.statetype">
|
||||
<field type="CharField" name="label">RFC Editor state</field>
|
||||
|
@ -1003,6 +976,141 @@
|
|||
<field type="IntegerField" name="order">6</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="104" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-action</field>
|
||||
<field type="SlugField" name="slug">rfcedack</field>
|
||||
<field type="CharField" name="name">RFC-Ed-Ack</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">Request completed. The RFC Editor has acknowledged receipt of IANA's message that the actions have been completed</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="103" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-action</field>
|
||||
<field type="SlugField" name="slug">waitrfc</field>
|
||||
<field type="CharField" name="name">Waiting on RFC Editor</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">IANA has notified the RFC Editor that the actions have been completed</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="102" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-action</field>
|
||||
<field type="SlugField" name="slug">waitwgc</field>
|
||||
<field type="CharField" name="name">Waiting on WGC</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">IANA is waiting on the IETF Working Group Chairs to respond</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="101" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-action</field>
|
||||
<field type="SlugField" name="slug">waitad</field>
|
||||
<field type="CharField" name="name">Waiting on ADs</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">IANA is waiting on the IETF Area Directors to respond</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="100" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-action</field>
|
||||
<field type="SlugField" name="slug">waitauth</field>
|
||||
<field type="CharField" name="name">Waiting on Authors</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">IANA is waiting on the document's authors to respond</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="99" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-action</field>
|
||||
<field type="SlugField" name="slug">inprog</field>
|
||||
<field type="CharField" name="name">In Progress</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">IANA is currently processing the actions for this document</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="98" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-action</field>
|
||||
<field type="SlugField" name="slug">newdoc</field>
|
||||
<field type="CharField" name="name">New Document</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">A new document has been received by IANA, but no actions have been taken</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="105" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-action</field>
|
||||
<field type="SlugField" name="slug">onhold</field>
|
||||
<field type="CharField" name="name">On Hold</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">IANA has suspended work on the document</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="106" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-action</field>
|
||||
<field type="SlugField" name="slug">noic</field>
|
||||
<field type="CharField" name="name">No IC</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">Request completed. There were no IANA actions for this document</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="107" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-review</field>
|
||||
<field type="SlugField" name="slug">need-rev</field>
|
||||
<field type="CharField" name="name">IANA Review Needed</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="IntegerField" name="order">1</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="108" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-review</field>
|
||||
<field type="SlugField" name="slug">ok-act</field>
|
||||
<field type="CharField" name="name">IANA OK - Actions Needed</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">Document requires IANA actions, and the IANA Considerations section indicates the details of the actions correctly.</field>
|
||||
<field type="IntegerField" name="order">2</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="109" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-review</field>
|
||||
<field type="SlugField" name="slug">ok-noact</field>
|
||||
<field type="CharField" name="name">IANA OK - No Actions Needed</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">Document requires no IANA action, and the IANA Considerations section indicates this correctly.</field>
|
||||
<field type="IntegerField" name="order">3</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="110" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-review</field>
|
||||
<field type="SlugField" name="slug">not-ok</field>
|
||||
<field type="CharField" name="name">IANA Not OK</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">IANA has issues with the text of the IANA Considerations section of the document.</field>
|
||||
<field type="IntegerField" name="order">4</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="111" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iana-review</field>
|
||||
<field type="SlugField" name="slug">changed</field>
|
||||
<field type="CharField" name="name">Version Changed - Review Needed</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">Document revision has changed after review by IANA.</field>
|
||||
<field type="IntegerField" name="order">5</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="112" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-rfceditor</field>
|
||||
<field type="SlugField" name="slug">auth48-done</field>
|
||||
<field type="CharField" name="name">AUTH48-DONE</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">Final approvals are complete</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
|
||||
</object>
|
||||
<object pk="16" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iesg</field>
|
||||
<field type="SlugField" name="slug">pub-req</field>
|
||||
|
@ -1185,7 +1293,7 @@
|
|||
</object>
|
||||
<object pk="27" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-rfceditor</field>
|
||||
<field type="SlugField" name="slug">iana-crd</field>
|
||||
<field type="SlugField" name="slug">iana</field>
|
||||
<field type="CharField" name="name">IANA</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">RFC-Editor/IANA Registration Coordination</field>
|
||||
|
@ -1780,4 +1888,4 @@
|
|||
<field type="IntegerField" name="order">3</field>
|
||||
<field to="name.ballotpositionname" name="positions" rel="ManyToManyRel"><object pk="yes"></object><object pk="noobj"></object><object pk="block"></object><object pk="abstain"></object><object pk="norecord"></object></field>
|
||||
</object>
|
||||
</django-objects>
|
||||
</django-objects>
|
||||
|
|
|
@ -165,6 +165,7 @@ INSTALLED_APPS = (
|
|||
'ietf.ietfworkflows',
|
||||
'ietf.wgchairs',
|
||||
'ietf.wgcharter',
|
||||
'ietf.sync',
|
||||
'ietf.community',
|
||||
)
|
||||
|
||||
|
@ -250,7 +251,8 @@ else:
|
|||
IPR_EMAIL_TO = ['ietf-ipr@ietf.org', ]
|
||||
DOC_APPROVAL_EMAIL_CC = ["RFC Editor <rfc-editor@rfc-editor.org>", ]
|
||||
|
||||
|
||||
# Put real password in settings_local.py
|
||||
IANA_SYNC_PASSWORD = "secret"
|
||||
|
||||
# Liaison Statement Tool settings
|
||||
LIAISON_UNIVERSAL_FROM = 'Liaison Statement Management Tool <lsmt@' + IETF_DOMAIN + '>'
|
||||
|
|
|
@ -14,6 +14,7 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
|
||||
import debug
|
||||
|
||||
from ietf.group.models import Group
|
||||
from ietf.idtracker.models import InternetDraft, IETFWG
|
||||
from ietf.proceedings.models import Meeting
|
||||
from ietf.submit.models import IdSubmissionDetail, TempIdAuthors, Preapproval
|
||||
|
@ -226,27 +227,36 @@ class UploadForm(forms.Form):
|
|||
self.idnits_message = p.stdout.read()
|
||||
|
||||
def get_working_group(self):
|
||||
filename = self.draft.filename
|
||||
existing_draft = InternetDraft.objects.filter(filename=filename)
|
||||
name = self.draft.filename
|
||||
existing_draft = InternetDraft.objects.filter(filename=name)
|
||||
if existing_draft:
|
||||
group = existing_draft[0].group and existing_draft[0].group.ietfwg or None
|
||||
if group and group.pk != NONE_WG:
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES and group.type_id == "area":
|
||||
return None
|
||||
if group and group.pk != NONE_WG and group.type_id != "area":
|
||||
return group
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
if filename.startswith('draft-ietf-'):
|
||||
# Extra check for WG that contains dashes
|
||||
for group in IETFWG.objects.filter(group_acronym__acronym__contains='-'):
|
||||
if filename.startswith('draft-ietf-%s-' % group.group_acronym.acronym):
|
||||
return group
|
||||
group_acronym = filename.split('-')[2]
|
||||
if name.startswith('draft-ietf-') or name.startswith("draft-irtf-"):
|
||||
components = name.split("-")
|
||||
if len(components) < 3:
|
||||
raise forms.ValidationError("The draft name \"%s\" is missing a third part, please rename it")
|
||||
|
||||
if components[1] == "ietf":
|
||||
group_type = "wg"
|
||||
else:
|
||||
group_type = "rg"
|
||||
|
||||
# first check groups with dashes
|
||||
for g in Group.objects.filter(acronym__contains="-", type=group_type):
|
||||
if name.startswith('draft-%s-%s-' % (components[1], g.acronym)):
|
||||
return IETFWG().from_object(g)
|
||||
|
||||
try:
|
||||
return IETFWG.objects.get(group_acronym__acronym=group_acronym)
|
||||
except IETFWG.DoesNotExist:
|
||||
raise forms.ValidationError('There is no active group with acronym \'%s\', please rename your draft' % group_acronym)
|
||||
return IETFWG().from_object(Group.objects.get(acronym=components[2], type=group_type))
|
||||
except Group.DoesNotExist:
|
||||
raise forms.ValidationError('There is no active group with acronym \'%s\', please rename your draft' % components[2])
|
||||
elif name.startswith("draft-iab-"):
|
||||
return IETFWG().from_object(Group.objects.get(acronym="iab"))
|
||||
else:
|
||||
return None
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ from ietf.utils.mail import outbox
|
|||
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.group.models import Group, Role
|
||||
from ietf.doc.models import Document, BallotDocEvent, BallotPositionDocEvent
|
||||
from ietf.doc.models import *
|
||||
from ietf.submit.models import IdSubmissionDetail, Preapproval
|
||||
|
||||
class SubmitTestCase(django.test.TestCase):
|
||||
|
@ -75,7 +75,6 @@ class SubmitTestCase(django.test.TestCase):
|
|||
self.assertTrue(os.path.exists(os.path.join(self.staging_dir, u"%s-%s.txt" % (name, rev))))
|
||||
self.assertEquals(IdSubmissionDetail.objects.filter(filename=name).count(), 1)
|
||||
submission = IdSubmissionDetail.objects.get(filename=name)
|
||||
self.assertEquals(submission.group_acronym.acronym, "mars")
|
||||
self.assertEquals(submission.tempidauthors_set.count(), 1)
|
||||
self.assertTrue(re.search('\s+Summary:\s+0\s+errors|No nits found', submission.idnits_message))
|
||||
author = submission.tempidauthors_set.all()[0]
|
||||
|
@ -139,6 +138,7 @@ class SubmitTestCase(django.test.TestCase):
|
|||
draft = Document.objects.get(docalias__name=name)
|
||||
self.assertEquals(draft.rev, rev)
|
||||
new_revision = draft.latest_event()
|
||||
self.assertEquals(draft.group.acronym, "mars")
|
||||
self.assertEquals(new_revision.type, "new_revision")
|
||||
self.assertEquals(new_revision.by.name, "Test Name")
|
||||
self.assertTrue(not os.path.exists(os.path.join(self.staging_dir, u"%s-%s.txt" % (name, rev))))
|
||||
|
@ -161,6 +161,16 @@ class SubmitTestCase(django.test.TestCase):
|
|||
# submit new revision of existing -> supply submitter info -> confirm
|
||||
draft = make_test_data()
|
||||
|
||||
# pretend IANA reviewed it
|
||||
draft.set_state(State.objects.get(type="draft-iana-review", slug="not-ok"))
|
||||
|
||||
# pretend it was approved to check that we notify the RFC Editor
|
||||
e = DocEvent(type="iesg_approved", doc=draft)
|
||||
e.time = draft.time
|
||||
e.by = Person.objects.get(name="(System)")
|
||||
e.desc = "The IESG approved the document"
|
||||
e.save()
|
||||
|
||||
# make a discuss to see if the AD gets an email
|
||||
ballot_position = BallotPositionDocEvent()
|
||||
ballot_position.ballot = draft.latest_event(BallotDocEvent, type="created_ballot")
|
||||
|
@ -214,16 +224,17 @@ class SubmitTestCase(django.test.TestCase):
|
|||
|
||||
draft = Document.objects.get(docalias__name=name)
|
||||
self.assertEquals(draft.rev, rev)
|
||||
new_revision = draft.latest_event()
|
||||
self.assertEquals(new_revision.type, "new_revision")
|
||||
self.assertEquals(new_revision.by.name, "Test Name")
|
||||
self.assertEquals(draft.group.acronym, name.split("-")[2])
|
||||
self.assertEquals(draft.docevent_set.all()[1].type, "new_revision")
|
||||
self.assertEquals(draft.docevent_set.all()[1].by.name, "Test Name")
|
||||
self.assertTrue(not os.path.exists(os.path.join(self.repository_dir, "%s-%s.txt" % (name, old_rev))))
|
||||
self.assertTrue(os.path.exists(os.path.join(self.archive_dir, "%s-%s.txt" % (name, old_rev))))
|
||||
self.assertTrue(not os.path.exists(os.path.join(self.staging_dir, u"%s-%s.txt" % (name, rev))))
|
||||
self.assertTrue(os.path.exists(os.path.join(self.repository_dir, u"%s-%s.txt" % (name, rev))))
|
||||
self.assertEquals(draft.type_id, "draft")
|
||||
self.assertEquals(draft.stream_id, "ietf")
|
||||
self.assertEquals(draft.get_state("draft-stream-%s" % draft.stream_id).slug, "wg-doc")
|
||||
self.assertEquals(draft.get_state_slug("draft-stream-%s" % draft.stream_id), "wg-doc")
|
||||
self.assertEquals(draft.get_state_slug("draft-iana-review"), "changed")
|
||||
self.assertEquals(draft.authors.count(), 1)
|
||||
self.assertEquals(draft.authors.all()[0].get_name(), "Test Name")
|
||||
self.assertEquals(draft.authors.all()[0].address, "testname@example.com")
|
||||
|
@ -240,6 +251,38 @@ class SubmitTestCase(django.test.TestCase):
|
|||
self.assertTrue(name in unicode(outbox[-1]))
|
||||
self.assertTrue("mars" in unicode(outbox[-1]))
|
||||
|
||||
def test_submit_new_wg_with_dash(self):
|
||||
draft = make_test_data()
|
||||
|
||||
group = Group.objects.create(acronym="mars-special", name="Mars Special", type_id="wg", state_id="active")
|
||||
|
||||
name = "draft-ietf-%s-testing-tests" % group.acronym
|
||||
|
||||
self.do_submission(name, "00")
|
||||
|
||||
self.assertEquals(IdSubmissionDetail.objects.get(filename=name).group_acronym.acronym, group.acronym)
|
||||
|
||||
def test_submit_new_irtf(self):
|
||||
draft = make_test_data()
|
||||
|
||||
group = Group.objects.create(acronym="saturnrg", name="Saturn", type_id="rg", state_id="active")
|
||||
|
||||
name = "draft-irtf-%s-testing-tests" % group.acronym
|
||||
|
||||
self.do_submission(name, "00")
|
||||
|
||||
self.assertEquals(IdSubmissionDetail.objects.get(filename=name).group_acronym.acronym, group.acronym)
|
||||
self.assertEquals(IdSubmissionDetail.objects.get(filename=name).group_acronym.type_id, group.type_id)
|
||||
|
||||
def test_submit_new_iab(self):
|
||||
draft = make_test_data()
|
||||
|
||||
name = "draft-iab-testing-tests"
|
||||
|
||||
self.do_submission(name, "00")
|
||||
|
||||
self.assertEquals(IdSubmissionDetail.objects.get(filename=name).group_acronym.acronym, "iab")
|
||||
|
||||
def test_cancel_submission(self):
|
||||
# submit -> cancel
|
||||
draft = make_test_data()
|
||||
|
|
|
@ -17,6 +17,7 @@ from ietf.ietfauth.decorators import has_role
|
|||
|
||||
from ietf.doc.models import *
|
||||
from ietf.person.models import Person, Alias, Email
|
||||
from ietf.doc.utils import add_state_change_event
|
||||
from ietf.message.models import Message
|
||||
|
||||
# Some useful states
|
||||
|
@ -132,28 +133,34 @@ def perform_postREDESIGN(request, submission):
|
|||
draft.expires = datetime.datetime.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
|
||||
draft.save()
|
||||
|
||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00":
|
||||
# automatically set state "WG Document"
|
||||
draft.set_state(State.objects.get(type="draft-stream-%s" % draft.stream_id, slug="wg-doc"))
|
||||
|
||||
DocAlias.objects.get_or_create(name=submission.filename, document=draft)
|
||||
|
||||
update_authors(draft, submission)
|
||||
|
||||
# new revision event
|
||||
a = submission.tempidauthors_set.filter(author_order=0)
|
||||
if a:
|
||||
submitter = ensure_person_email_info_exists(a[0]).person
|
||||
else:
|
||||
submitter = system
|
||||
|
||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
DocAlias.objects.get_or_create(name=submission.filename, document=draft)
|
||||
|
||||
update_authors(draft, submission)
|
||||
|
||||
# new revision event
|
||||
e = NewRevisionDocEvent(type="new_revision", doc=draft, rev=draft.rev)
|
||||
e.time = draft.time #submission.submission_date
|
||||
e.by = submitter
|
||||
e.desc = "New revision available"
|
||||
e.save()
|
||||
|
||||
if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00":
|
||||
# automatically set state "WG Document"
|
||||
draft.set_state(State.objects.get(type="draft-stream-%s" % draft.stream_id, slug="wg-doc"))
|
||||
|
||||
if draft.get_state_slug("draft-iana-review") in ("ok-act", "ok-noact", "not-ok"):
|
||||
prev_state = draft.get_state("draft-iana-review")
|
||||
next_state = State.objects.get(type="draft-iana-review", slug="changed")
|
||||
draft.set_state(next_state)
|
||||
add_state_change_event(draft, submitter, prev_state, next_state)
|
||||
|
||||
# clean up old files
|
||||
if prev_rev != draft.rev:
|
||||
from ietf.idrfc.expire import move_draft_files_to_archive
|
||||
|
@ -177,8 +184,7 @@ def perform_postREDESIGN(request, submission):
|
|||
submission.status_id = POSTED
|
||||
|
||||
announce_to_lists(request, submission)
|
||||
if draft.get_state("draft-iesg") != None and not was_rfc:
|
||||
announce_new_version(request, submission, draft, state_change_msg)
|
||||
announce_new_version(request, submission, draft, state_change_msg)
|
||||
announce_to_authors(request, submission)
|
||||
|
||||
submission.save()
|
||||
|
@ -261,17 +267,29 @@ def announce_new_versionREDESIGN(request, submission, draft, state_change_msg):
|
|||
if draft.ad:
|
||||
to_email.append(draft.ad.role_email("ad").address)
|
||||
|
||||
if draft.stream_id == "iab":
|
||||
to_email.append("IAB Stream <iab-stream@iab.org>")
|
||||
elif draft.stream_id == "ise":
|
||||
to_email.append("Independent Submission Editor <rfc-ise@rfc-editor.org>")
|
||||
elif draft.stream_id == "irtf":
|
||||
to_email.append("IRSG <irsg@irtf.org>")
|
||||
|
||||
# if it has been sent to the RFC Editor, keep them in the loop
|
||||
if draft.get_state_slug("draft-iesg") in ("ann", "rfcqueue"):
|
||||
to_email.append("RFC Editor <rfc-editor@rfc-editor.org>")
|
||||
|
||||
active_ballot = draft.active_ballot()
|
||||
if active_ballot:
|
||||
for ad, pos in active_ballot.active_ad_positions().iteritems():
|
||||
if pos and pos.pos_id == "discuss":
|
||||
to_email.append(ad.role_email("ad").address)
|
||||
|
||||
subject = 'New Version Notification - %s-%s.txt' % (submission.filename, submission.revision)
|
||||
from_email = settings.IDSUBMIT_ANNOUNCE_FROM_EMAIL
|
||||
send_mail(request, to_email, from_email, subject, 'submit/announce_new_version.txt',
|
||||
{'submission': submission,
|
||||
'msg': state_change_msg})
|
||||
if to_email:
|
||||
subject = 'New Version Notification - %s-%s.txt' % (submission.filename, submission.revision)
|
||||
from_email = settings.IDSUBMIT_ANNOUNCE_FROM_EMAIL
|
||||
send_mail(request, to_email, from_email, subject, 'submit/announce_new_version.txt',
|
||||
{'submission': submission,
|
||||
'msg': state_change_msg})
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
announce_new_version = announce_new_versionREDESIGN
|
||||
|
@ -563,7 +581,7 @@ class DraftValidation(object):
|
|||
|
||||
def validate_wg(self):
|
||||
if self.wg and not self.wg.status_id == IETFWG.ACTIVE:
|
||||
self.add_warning('group', 'Working Group exists but is not an active WG')
|
||||
self.add_warning('group', 'Group exists but is not an active group')
|
||||
|
||||
def validate_abstract(self):
|
||||
if not self.draft.abstract:
|
||||
|
|
|
@ -117,7 +117,7 @@ def draft_status(request, submission_id, submission_hash=None, message=None):
|
|||
except Preapproval.DoesNotExist:
|
||||
preapproval = None
|
||||
|
||||
if detail.revision == '00' and detail.group_acronym and not preapproval:
|
||||
if detail.revision == '00' and detail.group_acronym and detail.group_acronym.type_id == "wg" and not preapproval:
|
||||
detail.status_id = INITIAL_VERSION_APPROVAL_REQUESTED
|
||||
detail.save()
|
||||
|
||||
|
|
0
ietf/sync/__init__.py
Normal file
0
ietf/sync/__init__.py
Normal file
37
ietf/sync/discrepancies.py
Normal file
37
ietf/sync/discrepancies.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
from ietf.doc.models import *
|
||||
|
||||
def find_discrepancies():
|
||||
res = []
|
||||
|
||||
title = "Drafts that have been sent to the RFC Editor but do not have an RFC Editor state"
|
||||
|
||||
docs = Document.objects.filter(states__in=list(State.objects.filter(type="draft-iesg", slug__in=("ann", "rfcqueue")))).exclude(states__in=list(State.objects.filter(type="draft-rfceditor")))
|
||||
|
||||
res.append((title, docs))
|
||||
|
||||
title = "Drafts that have the IANA Action state \"In Progress\" but do not have a \"IANA\" RFC-Editor state/tag"
|
||||
|
||||
docs = Document.objects.filter(states__in=list(State.objects.filter(type="draft-iana-action", slug__in=("inprog",)))).exclude(tags="iana").exclude(states__in=list(State.objects.filter(type="draft-rfceditor", slug="iana")))
|
||||
|
||||
res.append((title, docs))
|
||||
|
||||
title = "Drafts that have the IANA Action state \"Waiting on RFC Editor\" or \"RFC-Ed-Ack\" but are in the RFC Editor state \"IANA\"/tagged with \"IANA\""
|
||||
|
||||
docs = Document.objects.filter(states__in=list(State.objects.filter(type="draft-iana-action", slug__in=("waitrfc", "rfcedack")))).filter(models.Q(tags="iana") | models.Q(states__in=list(State.objects.filter(type="draft-rfceditor", slug="iana"))))
|
||||
|
||||
res.append((title, docs))
|
||||
|
||||
title = "Drafts that have a state other than \"RFC Ed Queue\", \"RFC Published\" or \"Sent to the RFC Editor\" and have an RFC Editor or IANA Action state"
|
||||
|
||||
docs = Document.objects.exclude(states__in=list(State.objects.filter(type="draft-iesg", slug__in=("rfcqueue", "pub"))) + list(State.objects.filter(type__in=("draft-stream-iab", "draft-stream-ise", "draft-stream-irtf"), slug="rfc-edit"))).filter(states__in=list(State.objects.filter(type__in=("draft-iana-action", "draft-rfceditor"))))
|
||||
|
||||
res.append((title, docs))
|
||||
|
||||
for _, docs in res:
|
||||
for d in docs:
|
||||
d.iesg_state = d.get_state("draft-iesg")
|
||||
d.rfc_state = d.get_state("draft-rfceditor")
|
||||
d.iana_action_state = d.get_state("draft-iana-action")
|
||||
|
||||
return res
|
||||
|
266
ietf/sync/iana.py
Normal file
266
ietf/sync/iana.py
Normal file
|
@ -0,0 +1,266 @@
|
|||
import re, urllib2, json, email, base64
|
||||
|
||||
from django.utils.http import urlquote
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.doc.models import *
|
||||
from ietf.doc.utils import add_state_change_event
|
||||
from ietf.person.models import *
|
||||
from ietf.idrfc.mails import email_owner, email_state_changed, email_authors
|
||||
from ietf.utils.timezone import *
|
||||
|
||||
PROTOCOLS_URL = "http://www.iana.org/protocols/"
|
||||
CHANGES_URL = "http://datatracker.dev.icann.org:8080/data-tracker/changes"
|
||||
|
||||
def fetch_protocol_page(url):
|
||||
f = urllib2.urlopen(PROTOCOLS_URL)
|
||||
text = f.read()
|
||||
f.close()
|
||||
return text
|
||||
|
||||
def parse_protocol_page(text):
|
||||
"""Parse IANA protocols page to extract referenced RFCs (as
|
||||
rfcXXXX document names)."""
|
||||
matches = re.findall('RFC [0-9]+', text)
|
||||
res = set()
|
||||
for m in matches:
|
||||
res.add("rfc" + m[len("RFC "):])
|
||||
|
||||
return list(res)
|
||||
|
||||
def update_rfc_log_from_protocol_page(rfc_names, rfc_must_published_later_than):
|
||||
"""Add notices to RFC history log that IANA is now referencing the RFC."""
|
||||
system = Person.objects.get(name="(System)")
|
||||
|
||||
updated = []
|
||||
|
||||
docs = Document.objects.filter(docalias__name__in=rfc_names).exclude(
|
||||
docevent__type="rfc_in_iana_registry").filter(
|
||||
# only take those that were published after cutoff since we
|
||||
# have a big bunch of old RFCs that we unfortunately don't have data for
|
||||
docevent__type="published_rfc", docevent__time__gte=rfc_must_published_later_than
|
||||
).distinct()
|
||||
|
||||
for d in docs:
|
||||
e = DocEvent(doc=d)
|
||||
e.by = system
|
||||
e.type = "rfc_in_iana_registry"
|
||||
e.desc = "IANA registries were updated to include %s" % d.display_name()
|
||||
e.save()
|
||||
|
||||
updated.append(d)
|
||||
|
||||
return updated
|
||||
|
||||
|
||||
|
||||
def fetch_changes_json(url, start, end):
|
||||
url += "?start=%s&end=%s" % (urlquote(local_timezone_to_utc(start).strftime("%Y-%m-%d %H:%M:%S")),
|
||||
urlquote(local_timezone_to_utc(end).strftime("%Y-%m-%d %H:%M:%S")))
|
||||
request = urllib2.Request(url)
|
||||
# HTTP basic auth
|
||||
username = "ietfsync"
|
||||
password = settings.IANA_SYNC_PASSWORD
|
||||
request.add_header("Authorization", "Basic %s" % base64.encodestring("%s:%s" % (username, password)).replace("\n", ""))
|
||||
f = urllib2.urlopen(request)
|
||||
text = f.read()
|
||||
f.close()
|
||||
return text
|
||||
|
||||
def parse_changes_json(text):
|
||||
response = json.loads(text)
|
||||
|
||||
if "error" in response:
|
||||
raise Exception("IANA server returned error: %s" % response["error"])
|
||||
|
||||
changes = response["changes"]
|
||||
|
||||
# do some rudimentary validation
|
||||
for i in changes:
|
||||
for f in ['doc', 'type', 'time']:
|
||||
if f not in i:
|
||||
raise Exception('Error in response: Field %s missing in input: %s - %s' % (f, json.dumps(i), json.dumps(changes)))
|
||||
|
||||
# a little bit of cleaning
|
||||
i["doc"] = i["doc"].strip()
|
||||
if i["doc"].startswith("http://www.ietf.org/internet-drafts/"):
|
||||
i["doc"] = i["doc"][len("http://www.ietf.org/internet-drafts/"):]
|
||||
|
||||
# make sure we process oldest entries first
|
||||
changes.sort(key=lambda c: c["time"])
|
||||
|
||||
return changes
|
||||
|
||||
def update_history_with_changes(changes, send_email=True):
|
||||
"""Take parsed changes from IANA and apply them. Note that we
|
||||
expect to get these chronologically sorted, otherwise the change
|
||||
descriptions generated may not be right."""
|
||||
|
||||
# build up state lookup
|
||||
states = {}
|
||||
|
||||
slookup = dict((s.slug, s)
|
||||
for s in State.objects.filter(type=StateType.objects.get(slug="draft-iana-action")))
|
||||
states["action"] = {
|
||||
"": slookup["newdoc"],
|
||||
"In Progress": slookup["inprog"],
|
||||
"Open": slookup["inprog"],
|
||||
"pre-approval In Progress": slookup["inprog"],
|
||||
"Waiting on Authors": slookup["waitauth"],
|
||||
"Author": slookup["waitauth"],
|
||||
"Waiting on ADs": slookup["waitad"],
|
||||
"Waiting on AD": slookup["waitad"],
|
||||
"AD": slookup["waitad"],
|
||||
"Waiting on WGC": slookup["waitwgc"],
|
||||
"WGC": slookup["waitwgc"],
|
||||
"Waiting on RFC-Editor": slookup["waitrfc"],
|
||||
"Waiting on RFC Editor": slookup["waitrfc"],
|
||||
"RFC-Editor": slookup["waitrfc"],
|
||||
"RFC-Ed-ACK": slookup["rfcedack"],
|
||||
"RFC-Editor-ACK": slookup["rfcedack"],
|
||||
"Completed": slookup["rfcedack"],
|
||||
"On Hold": slookup["onhold"],
|
||||
"No IC": slookup["noic"],
|
||||
}
|
||||
|
||||
slookup = dict((s.slug, s)
|
||||
for s in State.objects.filter(type=StateType.objects.get(slug="draft-iana-review")))
|
||||
states["review"] = {
|
||||
"IANA Review Needed": slookup["need-rev"],
|
||||
"IANA OK - Actions Needed": slookup["ok-act"],
|
||||
"IANA OK - No Actions Needed": slookup["ok-noact"],
|
||||
"IANA Not OK": slookup["not-ok"],
|
||||
"Version Changed - Review Needed": slookup["changed"],
|
||||
}
|
||||
|
||||
# so it turns out IANA has made a mistake and are including some
|
||||
# wrong states, we'll have to skip those
|
||||
wrong_action_states = ("Waiting on Reviewer", "Review Complete", "Last Call",
|
||||
"Last Call - Questions", "Evaluation", "Evaluation - Questions",
|
||||
"With Reviewer", "IESG Notification Received", "Watiing on Last Call",
|
||||
"IANA Comments Submitted", "Waiting on Last Call")
|
||||
|
||||
system = Person.objects.get(name="(System)")
|
||||
|
||||
added_events = []
|
||||
warnings = []
|
||||
|
||||
for c in changes:
|
||||
docname = c['doc']
|
||||
timestamp = datetime.datetime.strptime(c["time"], "%Y-%m-%d %H:%M:%S")
|
||||
timestamp = utc_to_local_timezone(timestamp) # timestamps are in UTC
|
||||
|
||||
if c['type'] in ("iana_state", "iana_review"):
|
||||
if c['type'] == "iana_state":
|
||||
kind = "action"
|
||||
|
||||
if c["state"] in wrong_action_states:
|
||||
warnings.append("Wrong action state '%s' encountered in changes from IANA" % c["state"])
|
||||
continue
|
||||
else:
|
||||
kind = "review"
|
||||
|
||||
if c["state"] not in states[kind]:
|
||||
warnings.append("Unknown IANA %s state %s (%s)" % (kind, c["state"], timestamp))
|
||||
continue
|
||||
|
||||
state = states[kind][c["state"]]
|
||||
state_type = "draft-iana-%s" % kind
|
||||
|
||||
e = StateDocEvent.objects.filter(type="changed_state", time=timestamp,
|
||||
state_type=state_type, state=state)
|
||||
if not e:
|
||||
try:
|
||||
doc = Document.objects.get(docalias__name=docname)
|
||||
except Document.DoesNotExist:
|
||||
warnings.append("Document %s not found" % docname)
|
||||
continue
|
||||
|
||||
# the naive way of extracting prev_state here means
|
||||
# that we assume these changes are cronologically
|
||||
# applied
|
||||
prev_state = doc.get_state(state_type)
|
||||
e = add_state_change_event(doc, system, prev_state, state, timestamp)
|
||||
|
||||
if e:
|
||||
added_events.append(e)
|
||||
|
||||
if not StateDocEvent.objects.filter(doc=doc, time__gt=timestamp, state_type=state_type):
|
||||
save_document_in_history(doc)
|
||||
doc.set_state(state)
|
||||
|
||||
if send_email:
|
||||
email_state_changed(None, doc, "IANA %s state changed to %s" % (kind, state.name))
|
||||
email_owner(None, doc, doc.ad, system, "IANA %s state changed to %s" % (kind, state.name))
|
||||
|
||||
if doc.time < timestamp:
|
||||
doc.time = timestamp
|
||||
doc.save()
|
||||
|
||||
return added_events, warnings
|
||||
|
||||
|
||||
def parse_review_email(text):
|
||||
msg = email.message_from_string(text)
|
||||
|
||||
# doc
|
||||
doc_name = ""
|
||||
m = re.search(r"<([^>]+)>", msg["Subject"])
|
||||
if m:
|
||||
doc_name = m.group(1).lower()
|
||||
if re.search(r"\.\w{3}$", doc_name): # strip off extension
|
||||
doc_name = doc_name[:-4]
|
||||
|
||||
if re.search(r"-\d{2}$", doc_name): # strip off revision
|
||||
doc_name = doc_name[:-3]
|
||||
|
||||
# date
|
||||
review_time = datetime.datetime.now()
|
||||
if "Date" in msg:
|
||||
review_time = email_time_to_local_timezone(msg["Date"])
|
||||
|
||||
# by
|
||||
by = None
|
||||
m = re.search(r"\"(.*)\"", msg["From"])
|
||||
if m:
|
||||
name = m.group(1).strip()
|
||||
if name.endswith(" via RT"):
|
||||
name = name[:-len(" via RT")]
|
||||
|
||||
try:
|
||||
by = Person.objects.get(alias__name=name, role__group__acronym="iana")
|
||||
except Person.DoesNotExist:
|
||||
pass
|
||||
|
||||
if not by:
|
||||
by = Person.objects.get(name="(System)")
|
||||
|
||||
# comment
|
||||
body = msg.get_payload().decode('quoted-printable').replace("\r", "")
|
||||
b = body.find("(BEGIN IANA LAST CALL COMMENTS)")
|
||||
e = body.find("(END IANA LAST CALL COMMENTS)")
|
||||
|
||||
comment = body[b + len("(BEGIN IANA LAST CALL COMMENTS)"):e].strip()
|
||||
|
||||
# strip leading IESG:
|
||||
if comment.startswith("IESG:"):
|
||||
comment = comment[len("IESG:"):].lstrip()
|
||||
|
||||
# strip ending Thanks, followed by signature
|
||||
m = re.compile(r"^Thanks,\n\n", re.MULTILINE).search(comment)
|
||||
if m:
|
||||
comment = comment[:m.start()].rstrip()
|
||||
|
||||
return doc_name, review_time, by, comment
|
||||
|
||||
def add_review_comment(doc_name, review_time, by, comment):
|
||||
try:
|
||||
e = DocEvent.objects.get(doc__name=doc_name, time=review_time, type="iana_review")
|
||||
except DocEvent.DoesNotExist:
|
||||
doc = Document.objects.get(name=doc_name)
|
||||
e = DocEvent(doc=doc, time=review_time, type="iana_review")
|
||||
|
||||
e.desc = comment
|
||||
e.by = by
|
||||
|
||||
e.save()
|
21
ietf/sync/mails.py
Normal file
21
ietf/sync/mails.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.utils.mail import send_mail
|
||||
|
||||
from ietf.sync.discrepancies import find_discrepancies
|
||||
|
||||
def email_discrepancies(receivers):
|
||||
sections = find_discrepancies()
|
||||
|
||||
send_mail(None,
|
||||
receivers,
|
||||
None,
|
||||
"Datatracker Sync Discrepancies Report",
|
||||
"sync/discrepancies_report.txt",
|
||||
dict(sections=sections,
|
||||
url=settings.IDTRACKER_BASE_URL + urlreverse("ietf.sync.views.discrepancies"),
|
||||
base_url=settings.IDTRACKER_BASE_URL,
|
||||
))
|
||||
|
||||
|
0
ietf/sync/models.py
Normal file
0
ietf/sync/models.py
Normal file
446
ietf/sync/rfceditor.py
Normal file
446
ietf/sync/rfceditor.py
Normal file
|
@ -0,0 +1,446 @@
|
|||
import re, urllib2, json, email, socket
|
||||
from xml.dom import pulldom, Node
|
||||
|
||||
from django.utils.http import urlquote
|
||||
|
||||
from ietf.utils.mail import send_mail_text
|
||||
|
||||
from ietf.doc.models import *
|
||||
from ietf.person.models import *
|
||||
from ietf.name.models import *
|
||||
from ietf.doc.utils import add_state_change_event
|
||||
|
||||
QUEUE_URL = "http://www.rfc-editor.org/queue2.xml"
|
||||
INDEX_URL = "http://www.rfc-editor.org/rfc/rfc-index.xml"
|
||||
|
||||
MIN_QUEUE_RESULTS = 10
|
||||
MIN_INDEX_RESULTS = 5000
|
||||
|
||||
# Python < 2.7 doesn't have the total_seconds method on datetime.timedelta.
|
||||
def total_seconds(td):
|
||||
return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
|
||||
|
||||
def get_child_text(parent_node, tag_name):
|
||||
for node in parent_node.childNodes:
|
||||
if node.nodeType == Node.ELEMENT_NODE and node.localName == tag_name:
|
||||
return node.firstChild.data
|
||||
return None
|
||||
|
||||
|
||||
def fetch_queue_xml(url):
|
||||
socket.setdefaulttimeout(30)
|
||||
return urllib2.urlopen(url)
|
||||
|
||||
def parse_queue(response):
|
||||
events = pulldom.parse(response)
|
||||
drafts = []
|
||||
warnings = []
|
||||
|
||||
for event, node in events:
|
||||
if event == pulldom.START_ELEMENT and node.tagName == "entry":
|
||||
events.expandNode(node)
|
||||
node.normalize()
|
||||
draft_name = get_child_text(node, "draft").strip()
|
||||
draft_name = re.sub("(-\d\d)?(.txt){1,2}$", "", draft_name)
|
||||
date_received = get_child_text(node, "date-received")
|
||||
|
||||
state = ""
|
||||
tags = []
|
||||
missref_generation = ""
|
||||
for child in node.childNodes:
|
||||
if child.nodeType == Node.ELEMENT_NODE and child.localName == "state":
|
||||
state = child.firstChild.data
|
||||
# state has some extra annotations encoded, parse
|
||||
# them out
|
||||
if '*R' in state:
|
||||
tags.append("ref")
|
||||
state = state.replace("*R", "")
|
||||
if '*A' in state:
|
||||
tags.append("iana")
|
||||
state = state.replace("*A", "")
|
||||
m = re.search(r"\(([0-9]+)G\)", state)
|
||||
if m:
|
||||
missref_generation = m.group(1)
|
||||
state = state.replace("(%sG)" % missref_generation, "")
|
||||
|
||||
# AUTH48 link
|
||||
auth48 = ""
|
||||
for child in node.childNodes:
|
||||
if child.nodeType == Node.ELEMENT_NODE and child.localName == "auth48-url":
|
||||
auth48 = child.firstChild.data
|
||||
|
||||
# cluster link (if it ever gets implemented)
|
||||
cluster = ""
|
||||
for child in node.childNodes:
|
||||
if child.nodeType == Node.ELEMENT_NODE and child.localName == "cluster-url":
|
||||
cluster = child.firstChild.data
|
||||
|
||||
refs = []
|
||||
for child in node.childNodes:
|
||||
if child.nodeType == Node.ELEMENT_NODE and child.localName == "normRef":
|
||||
ref_name = get_child_text(child, "ref-name")
|
||||
ref_state = get_child_text(child, "ref-state")
|
||||
in_queue = ref_state.startswith("IN-QUEUE")
|
||||
refs.append((ref_name, ref_state, in_queue))
|
||||
|
||||
drafts.append((draft_name, date_received, state, tags, missref_generation, stream, auth48, cluster, refs))
|
||||
|
||||
elif event == pulldom.START_ELEMENT and node.tagName == "section":
|
||||
name = node.getAttribute('name')
|
||||
if name.startswith("IETF"):
|
||||
stream = "ietf"
|
||||
elif name.startswith("IAB"):
|
||||
stream = "iab"
|
||||
elif name.startswith("IRTF"):
|
||||
stream = "irtf"
|
||||
elif name.startswith("INDEPENDENT"):
|
||||
stream = "ise"
|
||||
else:
|
||||
stream = None
|
||||
warnings.append("unrecognized section " + name)
|
||||
|
||||
return drafts, warnings
|
||||
|
||||
def update_drafts_from_queue(drafts):
|
||||
tag_mapping = {
|
||||
'IANA': DocTagName.objects.get(slug='iana'),
|
||||
'REF': DocTagName.objects.get(slug='ref')
|
||||
}
|
||||
|
||||
slookup = dict((s.slug, s)
|
||||
for s in State.objects.filter(type=StateType.objects.get(slug="draft-rfceditor")))
|
||||
state_mapping = {
|
||||
'AUTH': slookup['auth'],
|
||||
'AUTH48': slookup['auth48'],
|
||||
'AUTH48-DONE': slookup['auth48-done'],
|
||||
'EDIT': slookup['edit'],
|
||||
'IANA': slookup['iana'],
|
||||
'IESG': slookup['iesg'],
|
||||
'ISR': slookup['isr'],
|
||||
'ISR-AUTH': slookup['isr-auth'],
|
||||
'REF': slookup['ref'],
|
||||
'RFC-EDITOR': slookup['rfc-edit'],
|
||||
'TO': slookup['timeout'],
|
||||
'MISSREF': slookup['missref'],
|
||||
}
|
||||
|
||||
system = Person.objects.get(name="(System)")
|
||||
|
||||
warnings = []
|
||||
|
||||
names = [t[0] for t in drafts]
|
||||
|
||||
drafts_in_db = dict((d.name, d)
|
||||
for d in Document.objects.filter(type="draft", docalias__name__in=names))
|
||||
|
||||
changed = set()
|
||||
|
||||
for name, date_received, state, tags, missref_generation, stream, auth48, cluster, refs in drafts:
|
||||
if name not in drafts_in_db:
|
||||
warnings.append("unknown document %s" % name)
|
||||
continue
|
||||
|
||||
if not state or state not in state_mapping:
|
||||
warnings.append("unknown state '%s'" % state)
|
||||
continue
|
||||
|
||||
d = drafts_in_db[name]
|
||||
|
||||
prev_state = d.get_state("draft-rfceditor")
|
||||
next_state = state_mapping[state]
|
||||
|
||||
# check if we've noted it's been received
|
||||
if d.get_state_slug("draft-iesg") == "ann" and not prev_state and not d.latest_event(DocEvent, type="rfc_editor_received_announcement"):
|
||||
e = DocEvent(doc=d, by=system, type="rfc_editor_received_announcement")
|
||||
e.desc = "Announcement was received by RFC Editor"
|
||||
e.save()
|
||||
send_mail_text(None, "iesg-secretary@ietf.org", None,
|
||||
'%s in RFC Editor queue' % d.name,
|
||||
'The announcement for %s has been received by the RFC Editor.' % d.name)
|
||||
|
||||
|
||||
if prev_state != next_state:
|
||||
save_document_in_history(d)
|
||||
|
||||
d.set_state(next_state)
|
||||
|
||||
e = add_state_change_event(d, system, prev_state, next_state)
|
||||
|
||||
if auth48:
|
||||
e.desc = re.sub(r"(<b>.*</b>)", "<a href=\"%s\">\\1</a>" % auth48, e.desc)
|
||||
e.save()
|
||||
|
||||
changed.add(name)
|
||||
|
||||
t = DocTagName.objects.filter(slug__in=tags)
|
||||
if set(t) != set(d.tags.all()):
|
||||
d.tags = t
|
||||
changed.add(name)
|
||||
|
||||
|
||||
# remove tags and states for those not in the queue anymore
|
||||
for d in Document.objects.exclude(docalias__name__in=names).filter(states__type="draft-rfceditor").distinct():
|
||||
d.tags.remove(*tag_mapping.values())
|
||||
d.unset_state("draft-rfceditor")
|
||||
# we do not add a history entry here - most likely we already
|
||||
# have something that explains what happened
|
||||
changed.add(name)
|
||||
|
||||
return changed, warnings
|
||||
|
||||
|
||||
def fetch_index_xml(url):
|
||||
socket.setdefaulttimeout(30)
|
||||
return urllib2.urlopen(url)
|
||||
|
||||
def parse_index(response):
|
||||
def getDocList(parentNode, tagName):
|
||||
l = []
|
||||
for u in parentNode.getElementsByTagName(tagName):
|
||||
for d in u.getElementsByTagName("doc-id"):
|
||||
l.append(d.firstChild.data)
|
||||
return l
|
||||
|
||||
also_list = {}
|
||||
data = []
|
||||
events = pulldom.parse(response)
|
||||
for event, node in events:
|
||||
if event == pulldom.START_ELEMENT and node.tagName in ["bcp-entry", "fyi-entry", "std-entry"]:
|
||||
events.expandNode(node)
|
||||
node.normalize()
|
||||
bcpid = get_child_text(node, "doc-id")
|
||||
doclist = getDocList(node, "is-also")
|
||||
for docid in doclist:
|
||||
if docid in also_list:
|
||||
also_list[docid].append(bcpid)
|
||||
else:
|
||||
also_list[docid] = [bcpid]
|
||||
|
||||
elif event == pulldom.START_ELEMENT and node.tagName == "rfc-entry":
|
||||
events.expandNode(node)
|
||||
node.normalize()
|
||||
rfc_number = int(get_child_text(node, "doc-id")[3:])
|
||||
title = get_child_text(node, "title")
|
||||
|
||||
authors = []
|
||||
for author in node.getElementsByTagName("author"):
|
||||
authors.append(get_child_text(author, "name"))
|
||||
|
||||
d = node.getElementsByTagName("date")[0]
|
||||
year = int(get_child_text(d, "year"))
|
||||
month = get_child_text(d, "month")
|
||||
month = ["January","February","March","April","May","June","July","August","September","October","November","December"].index(month)+1
|
||||
rfc_published_date = datetime.date(year, month, 1)
|
||||
|
||||
current_status = get_child_text(node, "current-status").title()
|
||||
|
||||
updates = getDocList(node, "updates")
|
||||
updated_by = getDocList(node, "updated-by")
|
||||
obsoletes = getDocList(node, "obsoletes")
|
||||
obsoleted_by = getDocList(node, "obsoleted-by")
|
||||
stream = get_child_text(node, "stream")
|
||||
wg = get_child_text(node, "wg_acronym")
|
||||
if wg and ((wg == "NON WORKING GROUP") or len(wg) > 15):
|
||||
wg = None
|
||||
|
||||
l = []
|
||||
pages = ""
|
||||
for fmt in node.getElementsByTagName("format"):
|
||||
l.append(get_child_text(fmt, "file-format"))
|
||||
if get_child_text(fmt, "file-format") == "ASCII":
|
||||
pages = get_child_text(fmt, "page-count")
|
||||
file_formats = (",".join(l)).lower()
|
||||
|
||||
abstract = ""
|
||||
for abstract in node.getElementsByTagName("abstract"):
|
||||
abstract = get_child_text(abstract, "p")
|
||||
|
||||
draft = get_child_text(node, "draft")
|
||||
if draft and re.search("-\d\d$", draft):
|
||||
draft = draft[0:-3]
|
||||
|
||||
if len(node.getElementsByTagName("errata-url")) > 0:
|
||||
has_errata = 1
|
||||
else:
|
||||
has_errata = 0
|
||||
|
||||
data.append((rfc_number,title,authors,rfc_published_date,current_status,updates,updated_by,obsoletes,obsoleted_by,[],draft,has_errata,stream,wg,file_formats,pages,abstract))
|
||||
|
||||
for d in data:
|
||||
k = "RFC%04d" % d[0]
|
||||
if k in also_list:
|
||||
d[9].extend(also_list[k])
|
||||
return data
|
||||
|
||||
|
||||
def update_docs_from_rfc_index(data, skip_older_than_date=None):
|
||||
std_level_mapping = {
|
||||
"Standard": StdLevelName.objects.get(slug="std"),
|
||||
"Draft Standard": StdLevelName.objects.get(slug="ds"),
|
||||
"Proposed Standard": StdLevelName.objects.get(slug="ps"),
|
||||
"Informational": StdLevelName.objects.get(slug="inf"),
|
||||
"Experimental": StdLevelName.objects.get(slug="exp"),
|
||||
"Best Current Practice": StdLevelName.objects.get(slug="bcp"),
|
||||
"Historic": StdLevelName.objects.get(slug="hist"),
|
||||
"Unknown": StdLevelName.objects.get(slug="unkn"),
|
||||
}
|
||||
|
||||
stream_mapping = {
|
||||
"IETF": StreamName.objects.get(slug="ietf"),
|
||||
"INDEPENDENT": StreamName.objects.get(slug="ise"),
|
||||
"IRTF": StreamName.objects.get(slug="irtf"),
|
||||
"IAB": StreamName.objects.get(slug="iab"),
|
||||
"Legacy": StreamName.objects.get(slug="legacy"),
|
||||
}
|
||||
|
||||
tag_has_errata = DocTagName.objects.get(slug='errata')
|
||||
relationship_obsoletes = DocRelationshipName.objects.get(slug="obs")
|
||||
relationship_updates = DocRelationshipName.objects.get(slug="updates")
|
||||
|
||||
system = Person.objects.get(name="(System)")
|
||||
|
||||
results = []
|
||||
|
||||
for rfc_number, title, authors, rfc_published_date, current_status, updates, updated_by, obsoletes, obsoleted_by, also, draft, has_errata, stream, wg, file_formats, pages, abstract in data:
|
||||
|
||||
if skip_older_than_date and rfc_published_date < skip_older_than_date:
|
||||
# speed up the process by skipping old entries
|
||||
continue
|
||||
|
||||
# we assume two things can happen: we get a new RFC, or an
|
||||
# attribute has been updated at the RFC Editor (RFC Editor
|
||||
# attributes take precedence over our local attributes)
|
||||
|
||||
# make sure we got the document and alias
|
||||
created = False
|
||||
doc = None
|
||||
name = "rfc%s" % rfc_number
|
||||
a = DocAlias.objects.filter(name=name).select_related("document")
|
||||
if a:
|
||||
doc = a[0].document
|
||||
else:
|
||||
if draft:
|
||||
try:
|
||||
doc = Document.objects.get(name=draft)
|
||||
except Document.DoesNotExist:
|
||||
pass
|
||||
|
||||
if not doc:
|
||||
results.append("created document %s" % name)
|
||||
doc = Document.objects.get_or_create(name=name)[0]
|
||||
|
||||
# add alias
|
||||
DocAlias.objects.get_or_create(name=name, document=doc)
|
||||
results.append("created alias %s to %s" % (name, doc.name))
|
||||
created = True
|
||||
|
||||
|
||||
# check attributes
|
||||
changed_attributes = {}
|
||||
changed_states = []
|
||||
created_relations = []
|
||||
other_changes = False
|
||||
if title != doc.title:
|
||||
changed_attributes["title"] = title
|
||||
|
||||
if abstract and abstract != doc.abstract:
|
||||
changed_attributes["abstract"] = abstract
|
||||
|
||||
if pages and int(pages) != doc.pages:
|
||||
changed_attributes["pages"] = int(pages)
|
||||
|
||||
if std_level_mapping[current_status] != doc.std_level:
|
||||
changed_attributes["std_level"] = std_level_mapping[current_status]
|
||||
|
||||
if doc.get_state_slug() != "rfc":
|
||||
changed_states.append(State.objects.get(type="draft", slug="rfc"))
|
||||
|
||||
if doc.stream != stream_mapping[stream]:
|
||||
changed_attributes["stream"] = stream_mapping[stream]
|
||||
|
||||
if not doc.group and wg:
|
||||
changed_attributes["group"] = Group.objects.get(acronym=wg)
|
||||
|
||||
if not doc.latest_event(type="published_rfc"):
|
||||
e = DocEvent(doc=doc, type="published_rfc")
|
||||
# unfortunately, rfc_published_date doesn't include the correct day
|
||||
# at the moment because the data only has month/year, so
|
||||
# try to deduce it
|
||||
d = datetime.datetime.combine(rfc_published_date, datetime.time())
|
||||
synthesized = datetime.datetime.now()
|
||||
if abs(d - synthesized) > datetime.timedelta(days=60):
|
||||
synthesized = d
|
||||
else:
|
||||
direction = -1 if total_seconds(d - synthesized) < 0 else +1
|
||||
while synthesized.month != d.month or synthesized.year != d.year:
|
||||
synthesized += datetime.timedelta(days=direction)
|
||||
e.time = synthesized
|
||||
e.by = system
|
||||
e.desc = "RFC published"
|
||||
e.save()
|
||||
other_changes = True
|
||||
|
||||
results.append("Added RFC published event: %s" % e.time.strftime("%Y-%m-%d"))
|
||||
|
||||
for t in ("draft-iesg", "draft-stream-iab", "draft-stream-irtf", "draft-stream-ise"):
|
||||
slug = doc.get_state_slug(t)
|
||||
if slug and slug != "pub":
|
||||
changed_states.append(State.objects.get(type=t, slug="pub"))
|
||||
|
||||
def parse_relation_list(l):
|
||||
res = []
|
||||
for x in l:
|
||||
if x[:3] in ("NIC", "IEN", "STD", "RTR"):
|
||||
# try translating this to RFCs that we can handle
|
||||
# sensibly; otherwise we'll have to ignore them
|
||||
l = DocAlias.objects.filter(name__startswith="rfc", document__docalias__name=x.lower())
|
||||
else:
|
||||
l = DocAlias.objects.filter(name=x.lower())
|
||||
|
||||
for a in l:
|
||||
if a not in res:
|
||||
res.append(a)
|
||||
return res
|
||||
|
||||
for x in parse_relation_list(obsoletes):
|
||||
if not RelatedDocument.objects.filter(source=doc, target=x, relationship=relationship_obsoletes):
|
||||
created_relations.append(RelatedDocument(source=doc, target=x, relationship=relationship_obsoletes))
|
||||
|
||||
for x in parse_relation_list(updates):
|
||||
if not RelatedDocument.objects.filter(source=doc, target=x, relationship=relationship_updates):
|
||||
created_relations.append(RelatedDocument(source=doc, target=x, relationship=relationship_updates))
|
||||
|
||||
if also:
|
||||
for a in also:
|
||||
a = a.lower()
|
||||
if not DocAlias.objects.filter(name=a):
|
||||
DocAlias.objects.create(name=a, document=doc)
|
||||
other_changes = True
|
||||
results.append("Created alias %s to %s" % (a, doc.name))
|
||||
|
||||
if has_errata:
|
||||
if not doc.tags.filter(pk=tag_has_errata.pk):
|
||||
changed_attributes["tags"] = list(doc.tags.all()) + [tag_has_errata]
|
||||
else:
|
||||
if doc.tags.filter(pk=tag_has_errata.pk):
|
||||
changed_attributes["tags"] = set(doc.tags.all()) - set([tag_has_errata])
|
||||
|
||||
if changed_attributes or changed_states or created_relations or other_changes:
|
||||
# apply changes
|
||||
save_document_in_history(doc)
|
||||
for k, v in changed_attributes.iteritems():
|
||||
setattr(doc, k, v)
|
||||
results.append("Changed %s to %s on %s" % (k, v, doc.name))
|
||||
|
||||
for s in changed_states:
|
||||
doc.set_state(s)
|
||||
results.append("Set state %s on %s" % (s, doc.name))
|
||||
|
||||
for o in created_relations:
|
||||
o.save()
|
||||
results.append("Created %s" % o)
|
||||
|
||||
doc.time = datetime.datetime.now()
|
||||
doc.save()
|
||||
|
||||
return results
|
446
ietf/sync/tests.py
Normal file
446
ietf/sync/tests.py
Normal file
|
@ -0,0 +1,446 @@
|
|||
import unittest, re, json, datetime, StringIO
|
||||
import django.test
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
|
||||
from ietf.utils.mail import outbox
|
||||
from ietf.utils.test_data import make_test_data
|
||||
from ietf.utils.test_utils import login_testing_unauthorized
|
||||
|
||||
from ietf.doc.models import *
|
||||
from ietf.doc.utils import add_state_change_event
|
||||
from ietf.person.models import *
|
||||
|
||||
from ietf.sync import iana, rfceditor
|
||||
|
||||
from pyquery import PyQuery
|
||||
|
||||
class IANASyncTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
def test_protocol_page_sync(self):
|
||||
draft = make_test_data()
|
||||
DocAlias.objects.create(name="rfc1234", document=draft)
|
||||
DocEvent.objects.create(doc=draft, type="published_rfc", by=Person.objects.get(name="(System)"))
|
||||
|
||||
rfc_names = iana.parse_protocol_page('<html><a href="/go/rfc1234/">RFC 1234</a></html>')
|
||||
self.assertEqual(len(rfc_names), 1)
|
||||
self.assertEqual(rfc_names[0], "rfc1234")
|
||||
|
||||
iana.update_rfc_log_from_protocol_page(rfc_names, datetime.datetime.now() - datetime.timedelta(days=1))
|
||||
self.assertEqual(DocEvent.objects.filter(doc=draft, type="rfc_in_iana_registry").count(), 1)
|
||||
|
||||
# make sure it doesn't create duplicates
|
||||
iana.update_rfc_log_from_protocol_page(rfc_names, datetime.datetime.now() - datetime.timedelta(days=1))
|
||||
self.assertEqual(DocEvent.objects.filter(doc=draft, type="rfc_in_iana_registry").count(), 1)
|
||||
|
||||
def test_changes_sync(self):
|
||||
draft = make_test_data()
|
||||
|
||||
data = json.dumps({
|
||||
"changes": [
|
||||
{
|
||||
"time": "2011-10-09 12:00:01",
|
||||
"doc": draft.name,
|
||||
"state": "IANA Not OK",
|
||||
"type": "iana_review",
|
||||
},
|
||||
{
|
||||
"time": "2011-10-09 12:00:00",
|
||||
"doc": draft.name,
|
||||
"state": "Waiting on RFC-Editor",
|
||||
"type": "iana_state",
|
||||
},
|
||||
{
|
||||
"time": "2011-10-09 11:00:00",
|
||||
"doc": draft.name,
|
||||
"state": "In Progress",
|
||||
"type": "iana_state",
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
changes = iana.parse_changes_json(data)
|
||||
# check sorting
|
||||
self.assertEqual(changes[0]["time"], "2011-10-09 11:00:00")
|
||||
|
||||
mailbox_before = len(outbox)
|
||||
added_events, warnings = iana.update_history_with_changes(changes)
|
||||
|
||||
self.assertEqual(len(added_events), 3)
|
||||
self.assertEqual(len(warnings), 0)
|
||||
self.assertEqual(draft.get_state_slug("draft-iana-review"), "not-ok")
|
||||
self.assertEqual(draft.get_state_slug("draft-iana-action"), "waitrfc")
|
||||
e = draft.latest_event(StateDocEvent, type="changed_state", state_type="draft-iana-action")
|
||||
self.assertEqual(e.desc, "IANA Action state changed to <b>Waiting on RFC Editor</b> from In Progress")
|
||||
# self.assertEqual(e.time, datetime.datetime(2011, 10, 9, 5, 0)) # check timezone handling
|
||||
self.assertEqual(len(outbox), mailbox_before + 3 * 2)
|
||||
|
||||
# make sure it doesn't create duplicates
|
||||
added_events, warnings = iana.update_history_with_changes(changes)
|
||||
self.assertEqual(len(added_events), 0)
|
||||
self.assertEqual(len(warnings), 0)
|
||||
|
||||
def test_changes_sync_errors(self):
|
||||
draft = make_test_data()
|
||||
|
||||
# missing "type"
|
||||
data = json.dumps({
|
||||
"changes": [
|
||||
{
|
||||
"time": "2011-10-09 12:00:01",
|
||||
"doc": draft.name,
|
||||
"state": "IANA Not OK",
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
self.assertRaises(Exception, iana.parse_changes_json, data)
|
||||
|
||||
# error response
|
||||
data = json.dumps({
|
||||
"error": "I am in error."
|
||||
})
|
||||
|
||||
self.assertRaises(Exception, iana.parse_changes_json, data)
|
||||
|
||||
# missing document from database
|
||||
data = json.dumps({
|
||||
"changes": [
|
||||
{
|
||||
"time": "2011-10-09 12:00:01",
|
||||
"doc": "draft-this-does-not-exist",
|
||||
"state": "IANA Not OK",
|
||||
"type": "iana_review",
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
changes = iana.parse_changes_json(data)
|
||||
added_events, warnings = iana.update_history_with_changes(changes)
|
||||
self.assertEqual(len(added_events), 0)
|
||||
self.assertEqual(len(warnings), 1)
|
||||
|
||||
def test_iana_review_mail(self):
|
||||
draft = make_test_data()
|
||||
|
||||
msg = """From: "%(person)s via RT" <drafts-lastcall@iana.org>
|
||||
Date: Thu, 10 May 2012 12:00:00 +0000
|
||||
Subject: [IANA #12345] Last Call: <%(draft)s-%(rev)s.txt> (Long text) to Informational RFC
|
||||
(BEGIN IANA LAST CALL COMMENTS)
|
||||
|
||||
IESG:
|
||||
|
||||
IANA has reviewed %(draft)s-%(rev)s, which is=20
|
||||
currently in Last Call, and has the following comments:
|
||||
|
||||
IANA understands that, upon approval of this document, there are no=20
|
||||
IANA Actions that need completion.
|
||||
|
||||
Thanks,
|
||||
|
||||
%(person)s
|
||||
IANA Fake Test Person
|
||||
ICANN
|
||||
|
||||
(END IANA LAST CALL COMMENTS)
|
||||
"""
|
||||
|
||||
msg = msg % dict(person=Person.objects.get(user__username="iana").name,
|
||||
draft=draft.name,
|
||||
rev=draft.rev)
|
||||
|
||||
doc_name, review_time, by, comment = iana.parse_review_email(msg)
|
||||
|
||||
self.assertEqual(doc_name, draft.name)
|
||||
# self.assertEqual(review_time, datetime.datetime(2012, 5, 10, 5, 0, 0))
|
||||
self.assertEqual(by, Person.objects.get(user__username="iana"))
|
||||
self.assertTrue("there are no IANA Actions" in comment.replace("\n", ""))
|
||||
|
||||
iana.add_review_comment(doc_name, review_time, by, comment)
|
||||
|
||||
e = draft.latest_event(type="iana_review")
|
||||
self.assertTrue(e)
|
||||
self.assertEqual(e.desc, comment)
|
||||
self.assertEqual(e.by, by)
|
||||
|
||||
# make sure it doesn't create duplicates
|
||||
iana.add_review_comment(doc_name, review_time, by, comment)
|
||||
self.assertEqual(DocEvent.objects.filter(doc=draft, type="iana_review").count(), 1)
|
||||
|
||||
|
||||
class RFCSyncTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
def test_rfc_index(self):
|
||||
doc = make_test_data()
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug="rfcqueue"))
|
||||
# it's a bit strange to have this set when draft-iesg is set
|
||||
# too, but for testing purposes ...
|
||||
doc.set_state(State.objects.get(type="draft-stream-ise", slug="rfc-edit"))
|
||||
|
||||
updated_doc = Document.objects.create(name="draft-ietf-something")
|
||||
DocAlias.objects.create(name=updated_doc.name, document=updated_doc)
|
||||
DocAlias.objects.create(name="rfc123", document=updated_doc)
|
||||
|
||||
today = datetime.date.today()
|
||||
|
||||
t = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rfc-index xmlns="http://www.rfc-editor.org/rfc-index"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.rfc-editor.org/rfc-index
|
||||
http://www.rfc-editor.org/rfc-index.xsd">
|
||||
<bcp-entry>
|
||||
<doc-id>BCP0001</doc-id>
|
||||
<is-also>
|
||||
<doc-id>RFC1234</doc-id>
|
||||
<doc-id>RFC2345</doc-id>
|
||||
</is-also>
|
||||
</bcp-entry>
|
||||
<fyi-entry>
|
||||
<doc-id>FYI0001</doc-id>
|
||||
<is-also>
|
||||
<doc-id>RFC1234</doc-id>
|
||||
</is-also>
|
||||
</fyi-entry>
|
||||
<std-entry>
|
||||
<doc-id>STD0001</doc-id>
|
||||
<title>Test</title>
|
||||
<is-also>
|
||||
<doc-id>RFC1234</doc-id>
|
||||
</is-also>
|
||||
</std-entry>
|
||||
<rfc-entry>
|
||||
<doc-id>RFC1234</doc-id>
|
||||
<title>A Testing RFC</title>
|
||||
<author>
|
||||
<name>A. Irector</name>
|
||||
</author>
|
||||
<date>
|
||||
<month>%(month)s</month>
|
||||
<year>%(year)s</year>
|
||||
</date>
|
||||
<format>
|
||||
<file-format>ASCII</file-format>
|
||||
<char-count>12345</char-count>
|
||||
<page-count>42</page-count>
|
||||
</format>
|
||||
<keywords>
|
||||
<kw>test</kw>
|
||||
</keywords>
|
||||
<abstract><p>This is some interesting text.</p></abstract>
|
||||
<draft>%(name)s-%(rev)s</draft>
|
||||
<updates>
|
||||
<doc-id>RFC123</doc-id>
|
||||
</updates>
|
||||
<is-also>
|
||||
<doc-id>BCP0001</doc-id>
|
||||
</is-also>
|
||||
<current-status>PROPOSED STANDARD</current-status>
|
||||
<publication-status>PROPOSED STANDARD</publication-status>
|
||||
<stream>IETF</stream>
|
||||
<area>%(area)s</area>
|
||||
<wg_acronym>%(group)s</wg_acronym>
|
||||
<errata-url>http://www.rfc-editor.org/errata_search.php?rfc=1234</errata-url>
|
||||
</rfc-entry>
|
||||
</rfc-index>''' % dict(year=today.strftime("%Y"),
|
||||
month=today.strftime("%B"),
|
||||
name=doc.name,
|
||||
rev=doc.rev,
|
||||
area=doc.group.parent.acronym,
|
||||
group=doc.group.acronym)
|
||||
|
||||
data = rfceditor.parse_index(StringIO.StringIO(t))
|
||||
self.assertEqual(len(data), 1)
|
||||
|
||||
rfc_number, title, authors, rfc_published_date, current_status, updates, updated_by, obsoletes, obsoleted_by, also, draft, has_errata, stream, wg, file_formats, pages, abstract = data[0]
|
||||
|
||||
# currently, we only check what we actually use
|
||||
self.assertEqual(rfc_number, 1234)
|
||||
self.assertEqual(title, "A Testing RFC")
|
||||
self.assertEqual(rfc_published_date.year, today.year)
|
||||
self.assertEqual(rfc_published_date.month, today.month)
|
||||
self.assertEqual(current_status, "Proposed Standard")
|
||||
self.assertEqual(updates, ["RFC123"])
|
||||
self.assertEqual(set(also), set(["BCP0001", "FYI0001", "STD0001"]))
|
||||
self.assertEqual(draft, doc.name)
|
||||
self.assertEqual(wg, doc.group.acronym)
|
||||
self.assertEqual(has_errata, True)
|
||||
self.assertEqual(stream, "IETF")
|
||||
self.assertEqual(pages, "42")
|
||||
self.assertEqual(abstract, "This is some interesting text.")
|
||||
|
||||
|
||||
mailbox_before = len(outbox)
|
||||
|
||||
changed = rfceditor.update_docs_from_rfc_index(data, today - datetime.timedelta(days=30))
|
||||
|
||||
doc = Document.objects.get(name=doc.name)
|
||||
|
||||
self.assertEqual(doc.docevent_set.all()[0].type, "published_rfc")
|
||||
self.assertEqual(doc.docevent_set.all()[0].time.date(), today)
|
||||
self.assertTrue("errata" in doc.tags.all().values_list("slug", flat=True))
|
||||
self.assertTrue(DocAlias.objects.filter(name="rfc1234", document=doc))
|
||||
self.assertTrue(DocAlias.objects.filter(name="bcp0001", document=doc))
|
||||
self.assertTrue(DocAlias.objects.filter(name="fyi0001", document=doc))
|
||||
self.assertTrue(DocAlias.objects.filter(name="std0001", document=doc))
|
||||
self.assertTrue(RelatedDocument.objects.filter(source=doc, target__name="rfc123", relationship="updates"))
|
||||
self.assertEqual(doc.title, "A Testing RFC")
|
||||
self.assertEqual(doc.abstract, "This is some interesting text.")
|
||||
self.assertEqual(doc.get_state_slug(), "rfc")
|
||||
self.assertEqual(doc.get_state_slug("draft-iesg"), "pub")
|
||||
self.assertEqual(doc.get_state_slug("draft-stream-ise"), "pub")
|
||||
self.assertEqual(doc.std_level_id, "ps")
|
||||
self.assertEqual(doc.pages, 42)
|
||||
|
||||
# make sure we can apply it again with no changes
|
||||
changed = rfceditor.update_docs_from_rfc_index(data, today - datetime.timedelta(days=30))
|
||||
self.assertEquals(len(changed), 0)
|
||||
|
||||
|
||||
def test_rfc_queue(self):
|
||||
draft = make_test_data()
|
||||
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="ann"))
|
||||
|
||||
t = '''<rfc-editor-queue xmlns="http://www.rfc-editor.org/rfc-editor-queue">
|
||||
<section name="IETF STREAM: WORKING GROUP STANDARDS TRACK">
|
||||
<entry xml:id="%(name)s">
|
||||
<draft>%(name)s-%(rev)s.txt</draft>
|
||||
<date-received>2010-09-08</date-received>
|
||||
<state>EDIT*R*A(1G)</state>
|
||||
<auth48-url>http://www.rfc-editor.org/auth48/rfc1234</auth48-url>
|
||||
<normRef>
|
||||
<ref-name>%(ref)s</ref-name>
|
||||
<ref-state>IN-QUEUE</ref-state>
|
||||
</normRef>
|
||||
<authors>A. Author</authors>
|
||||
<title>
|
||||
%(title)s
|
||||
</title>
|
||||
<bytes>10000000</bytes>
|
||||
<source>%(group)s</source>
|
||||
</entry>
|
||||
</section>
|
||||
</rfc-editor-queue>''' % dict(name=draft.name,
|
||||
rev=draft.rev,
|
||||
title=draft.title,
|
||||
group=draft.group.name,
|
||||
ref="draft-ietf-test")
|
||||
|
||||
drafts, warnings = rfceditor.parse_queue(StringIO.StringIO(t))
|
||||
self.assertEqual(len(drafts), 1)
|
||||
self.assertEqual(len(warnings), 0)
|
||||
|
||||
draft_name, date_received, state, tags, missref_generation, stream, auth48, cluster, refs = drafts[0]
|
||||
|
||||
# currently, we only check what we actually use
|
||||
self.assertEqual(draft_name, draft.name)
|
||||
self.assertEqual(state, "EDIT")
|
||||
self.assertEqual(set(tags), set(["iana", "ref"]))
|
||||
self.assertEqual(auth48, "http://www.rfc-editor.org/auth48/rfc1234")
|
||||
|
||||
|
||||
mailbox_before = len(outbox)
|
||||
|
||||
changed, warnings = rfceditor.update_drafts_from_queue(drafts)
|
||||
self.assertEqual(len(changed), 1)
|
||||
self.assertEqual(len(warnings), 0)
|
||||
|
||||
self.assertEqual(draft.get_state_slug("draft-rfceditor"), "edit")
|
||||
self.assertEqual(set(draft.tags.all()), set(DocTagName.objects.filter(slug__in=("iana", "ref"))))
|
||||
self.assertEqual(draft.docevent_set.all()[0].type, "changed_state")
|
||||
self.assertEqual(draft.docevent_set.all()[1].type, "rfc_editor_received_announcement")
|
||||
|
||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("RFC Editor queue" in outbox[-1]["Subject"])
|
||||
|
||||
# make sure we can apply it again with no changes
|
||||
changed, warnings = rfceditor.update_drafts_from_queue(drafts)
|
||||
self.assertEquals(len(changed), 0)
|
||||
self.assertEquals(len(warnings), 0)
|
||||
|
||||
class DiscrepanciesTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
def test_discrepancies(self):
|
||||
make_test_data()
|
||||
|
||||
# draft approved but no RFC Editor state
|
||||
doc = Document.objects.create(name="draft-ietf-test1", type_id="draft")
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug="ann"))
|
||||
|
||||
r = self.client.get(urlreverse("ietf.sync.views.discrepancies"))
|
||||
self.assertTrue(doc.name in r.content)
|
||||
|
||||
# draft with IANA state "In Progress" but RFC Editor state not IANA
|
||||
doc = Document.objects.create(name="draft-ietf-test2", type_id="draft")
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug="rfcqueue"))
|
||||
doc.set_state(State.objects.get(type="draft-iana-action", slug="inprog"))
|
||||
doc.set_state(State.objects.get(type="draft-rfceditor", slug="auth"))
|
||||
|
||||
r = self.client.get(urlreverse("ietf.sync.views.discrepancies"))
|
||||
self.assertTrue(doc.name in r.content)
|
||||
|
||||
# draft with IANA state "Waiting on RFC Editor" or "RFC-Ed-Ack"
|
||||
# but RFC Editor state is IANA
|
||||
doc = Document.objects.create(name="draft-ietf-test3", type_id="draft")
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug="rfcqueue"))
|
||||
doc.set_state(State.objects.get(type="draft-iana-action", slug="waitrfc"))
|
||||
doc.set_state(State.objects.get(type="draft-rfceditor", slug="iana"))
|
||||
|
||||
r = self.client.get(urlreverse("ietf.sync.views.discrepancies"))
|
||||
self.assertTrue(doc.name in r.content)
|
||||
|
||||
# draft with state other than "RFC Ed Queue" or "RFC Published"
|
||||
# that are in RFC Editor or IANA queues
|
||||
doc = Document.objects.create(name="draft-ietf-test4", type_id="draft")
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug="ann"))
|
||||
doc.set_state(State.objects.get(type="draft-rfceditor", slug="auth"))
|
||||
|
||||
r = self.client.get(urlreverse("ietf.sync.views.discrepancies"))
|
||||
self.assertTrue(doc.name in r.content)
|
||||
|
||||
class RFCEditorUndoTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
def test_rfceditor_undo(self):
|
||||
draft = make_test_data()
|
||||
|
||||
e1 = add_state_change_event(draft, Person.objects.get(name="(System)"), None,
|
||||
State.objects.get(type="draft-rfceditor", slug="auth"))
|
||||
e1.desc = "First"
|
||||
e1.save()
|
||||
|
||||
e2 = add_state_change_event(draft, Person.objects.get(name="(System)"), None,
|
||||
State.objects.get(type="draft-rfceditor", slug="edit"))
|
||||
e2.desc = "Second"
|
||||
e2.save()
|
||||
|
||||
url = urlreverse('ietf.sync.views.rfceditor_undo')
|
||||
login_testing_unauthorized(self, "rfc", url)
|
||||
|
||||
# get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertTrue(e2.doc_id in r.content)
|
||||
|
||||
# delete e2
|
||||
deleted_before = DeletedEvent.objects.count()
|
||||
|
||||
r = self.client.post(url, dict(event=e2.id))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
self.assertEquals(StateDocEvent.objects.filter(id=e2.id).count(), 0)
|
||||
self.assertEquals(draft.get_state("draft-rfceditor").slug, "auth")
|
||||
self.assertEquals(DeletedEvent.objects.count(), deleted_before + 1)
|
||||
|
||||
# delete e1
|
||||
r = self.client.post(url, dict(event=e1.id))
|
||||
self.assertEquals(draft.get_state("draft-rfceditor"), None)
|
||||
|
||||
# let's just test we can recover
|
||||
e = DeletedEvent.objects.all().order_by("-time")[0]
|
||||
|
||||
e.content_type.model_class().objects.create(**json.loads(e.json))
|
||||
self.assertTrue(StateDocEvent.objects.filter(desc="First", doc=draft))
|
8
ietf/sync/urls.py
Normal file
8
ietf/sync/urls.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^discrepancies/$', 'ietf.sync.views.discrepancies'),
|
||||
url(r'^(?P<org>\w+)/notify/(?P<notification>\w+)/$', 'ietf.sync.views.notify'),
|
||||
url(r'^rfceditor/undo/', 'ietf.sync.views.rfceditor_undo')
|
||||
)
|
||||
|
146
ietf/sync/views.py
Normal file
146
ietf/sync/views.py
Normal file
|
@ -0,0 +1,146 @@
|
|||
import subprocess, os, json
|
||||
|
||||
from django.http import HttpResponse, HttpResponseForbidden, HttpResponseServerError, HttpResponseRedirect
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
from django.template.loader import render_to_string
|
||||
from django.conf import settings
|
||||
from django import forms
|
||||
from django.db.models import Q
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from ietf.ietfauth.decorators import role_required, has_role
|
||||
from ietf.doc.models import *
|
||||
from ietf.sync import iana, rfceditor
|
||||
from ietf.sync.discrepancies import find_discrepancies
|
||||
from ietf.utils.serialize import object_as_shallow_dict
|
||||
|
||||
SYNC_BIN_PATH = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../bin"))
|
||||
|
||||
#@role_required('Secretariat', 'IANA', 'RFC Editor')
|
||||
def discrepancies(request):
|
||||
sections = find_discrepancies()
|
||||
|
||||
return render_to_response("sync/discrepancies.html",
|
||||
dict(sections=sections),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def notify(request, org, notification):
|
||||
"""Notify that something has changed at another site to trigger a
|
||||
run of one of the sync scripts."""
|
||||
|
||||
known_orgs = {
|
||||
"iana": "IANA",
|
||||
"rfceditor": "RFC Editor",
|
||||
}
|
||||
|
||||
if org not in known_orgs:
|
||||
raise Http404
|
||||
|
||||
# handle auth, to make it easier for the other end, you can send
|
||||
# the username/password as POST parameters instead of having to
|
||||
# visit the login page
|
||||
user = request.user
|
||||
|
||||
username = request.POST.get("username") or request.GET.get("username")
|
||||
password = request.POST.get("password") or request.GET.get("password")
|
||||
|
||||
if username != None and password != None:
|
||||
if settings.SERVER_MODE == "production" and not request.is_secure():
|
||||
return HttpResponseForbidden("You must use HTTPS when sending username/password")
|
||||
|
||||
if not user.is_authenticated():
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
return HttpResponse("Invalid username/password")
|
||||
|
||||
if not user.check_password(password):
|
||||
return HttpResponse("Invalid username/password")
|
||||
|
||||
if not has_role(user, ("Secretariat", known_orgs[org])):
|
||||
return HttpResponseForbidden("You do not have the necessary permissions to view this page")
|
||||
|
||||
known_notifications = {
|
||||
"protocols": "an added reference to an RFC at <a href=\"%s\">the IANA protocols page</a>" % iana.PROTOCOLS_URL,
|
||||
"changes": "new changes at <a href=\"%s\">the changes JSON dump</a>" % iana.CHANGES_URL,
|
||||
"queue": "new changes to <a href=\"%s\">queue2.xml</a>" % rfceditor.QUEUE_URL,
|
||||
"index": "new changes to <a href=\"%s\">rfc-index.xml</a>" % rfceditor.INDEX_URL,
|
||||
}
|
||||
|
||||
if notification not in known_notifications:
|
||||
raise Http404
|
||||
|
||||
if request.method == "POST":
|
||||
def runscript(name):
|
||||
p = subprocess.Popen(["python", os.path.join(SYNC_BIN_PATH, name)],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
out, _ = p.communicate()
|
||||
return (p.returncode, out)
|
||||
|
||||
if notification == "protocols":
|
||||
failed, out = runscript("iana-protocols-updates")
|
||||
|
||||
if notification == "changes":
|
||||
failed, out = runscript("iana-changes-updates")
|
||||
|
||||
if notification == "queue":
|
||||
failed, out = runscript("rfc-editor-queue-updates")
|
||||
|
||||
if notification == "index":
|
||||
failed, out = runscript("rfc-editor-index-updates")
|
||||
|
||||
if failed:
|
||||
return HttpResponseServerError("FAIL\n\n" + out, content_type="text/plain")
|
||||
else:
|
||||
return HttpResponse("OK", content_type="text/plain")
|
||||
|
||||
return render_to_response('sync/notify.html',
|
||||
dict(org=known_orgs[org],
|
||||
notification=notification,
|
||||
help_text=known_notifications[notification],
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
@role_required('Secretariat', 'RFC Editor')
|
||||
def rfceditor_undo(request):
|
||||
"""Undo a DocEvent."""
|
||||
events = StateDocEvent.objects.filter(state_type="draft-rfceditor",
|
||||
time__gte=datetime.datetime.now() - datetime.timedelta(weeks=1)
|
||||
).order_by("-time", "-id")
|
||||
|
||||
if request.method == "POST":
|
||||
try:
|
||||
eid = int(request.POST.get("event", ""))
|
||||
except ValueError:
|
||||
return HttpResponse("Could not parse event id")
|
||||
|
||||
try:
|
||||
e = events.get(id=eid)
|
||||
except StateDocEvent.DoesNotExist:
|
||||
return HttpResponse("Event does not exist")
|
||||
|
||||
doc = e.doc
|
||||
|
||||
# possibly reset the state of the document
|
||||
all_events = StateDocEvent.objects.filter(doc=doc, state_type="draft-rfceditor").order_by("-time", "-id")
|
||||
if all_events and all_events[0] == e:
|
||||
if len(all_events) > 1:
|
||||
doc.set_state(all_events[1].state)
|
||||
else:
|
||||
doc.unset_state("draft-rfceditor")
|
||||
|
||||
dump = DeletedEvent()
|
||||
dump.content_type = ContentType.objects.get_for_model(type(e))
|
||||
dump.json = json.dumps(object_as_shallow_dict(e), indent=2)
|
||||
dump.by = request.user.person
|
||||
dump.save()
|
||||
|
||||
e.delete()
|
||||
|
||||
return HttpResponseRedirect(urlreverse("ietf.sync.views.rfceditor_undo"))
|
||||
|
||||
return render_to_response('sync/rfceditor_undo.html',
|
||||
dict(events=events,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
|
@ -44,14 +44,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<li><a href="{% url ietf.iesg.views.agenda_documents %}">Next Telechat</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.discusses %}">Discusses</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.working_group_actions %}">Working Groups</a></li>
|
||||
{# FIXME: wgcharter <li><a href="{% url wg_search_by_area name=user|ad_area %}">Working Groups</a></li> #}
|
||||
{% endif %}
|
||||
{% if user|in_group:"Secretariat" %}
|
||||
<li class="sect first">Secretariat</li>
|
||||
<li><a href="{% url ietf.iesg.views.telechat_dates %}">Telechat Dates</a></li>
|
||||
<li><a href="/admin/iesg/telechatagendaitem/">Management Items</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.working_group_actions %}">Working Groups</a></li>
|
||||
{# FIXME: wgcharter <li><a href="{% url wg_search_in_process %}">Working Groups</a></li> #}
|
||||
<li><a href="{% url ietf.sync.views.discrepancies %}">Sync discrepancies</a>
|
||||
{% endif %}
|
||||
{% if user %}
|
||||
{% get_user_managed_streams user as stream_list %}
|
||||
|
@ -62,6 +61,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if user|has_role:"IANA" %}
|
||||
<li class="sect first">IANA</li>
|
||||
<li><a href="{% url ietf.sync.views.discrepancies %}">Sync discrepancies</a></li>
|
||||
{% endif %}
|
||||
{% if user|has_role:"RFC Editor" %}
|
||||
<li class="sect first">RFC Editor</li>
|
||||
<li><a href="{% url ietf.sync.views.discrepancies %}">Sync discrepancies</a></li>
|
||||
{% endif %}
|
||||
<li class="sect{% if not user|in_group:"Area_Director,Secretariat" %} first{% endif %}">Working Groups</li>
|
||||
|
||||
<li style="padding-bottom:0;"><div id="wgs" class="yuimenu"><div class="bd" style="border:0;">
|
||||
|
|
|
@ -45,6 +45,8 @@ IESG Note
|
|||
(Insert IESG Note here or remove section)
|
||||
|
||||
IANA Note
|
||||
|
||||
{% if iana %}
|
||||
{% load ietf_filters %}{% filter wordwrap:"68"|indent:2 %}{{ iana }}{% endfilter %}
|
||||
{% endif %}
|
||||
(Insert IANA Note here or remove section)
|
||||
{% endautoescape%}
|
||||
|
|
21
ietf/templates/idrfc/change_consensus.html
Normal file
21
ietf/templates/idrfc/change_consensus.html
Normal file
|
@ -0,0 +1,21 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Change whether {{ doc.name }}-{{ doc.rev }} is the result of a consensus process{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Change whether {{ doc.name }}-{{ doc.rev }} is the result of a consensus process</h1>
|
||||
|
||||
<form action="" method="POST">
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="actions">
|
||||
<a href="{% url doc_view name=doc.name %}">Back</a>
|
||||
<input type="submit" value="Submit"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
24
ietf/templates/idrfc/change_iana_state.html
Normal file
24
ietf/templates/idrfc/change_iana_state.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Change IANA state of {{ doc }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
form table .actions { text-align: right; padding-top: 1em; }
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Change IANA state of {{ doc }}</h1>
|
||||
|
||||
<form action="" method="post">
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
<tr>
|
||||
<td colspan="2" class="actions">
|
||||
<a href="{{ doc.get_absolute_url }}">Back</a>
|
||||
<input type="submit" value="Save"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
|
@ -3,9 +3,9 @@
|
|||
{% block title %}Change state of {{ doc }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
form.change-state select {
|
||||
width: 22em;
|
||||
}
|
||||
form.change-state select { width: 22em; }
|
||||
form.change-state #id_comment { width: 30em; }
|
||||
form.change-state .cancel-pub-note { width: 30em; color: #a00; }
|
||||
form.change-state .actions {
|
||||
text-align: right;
|
||||
padding-top: 10px;
|
||||
|
@ -29,6 +29,14 @@ form.change-state .actions {
|
|||
<form class="change-state" action="" method="post">
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
{% if state and state.slug == "rfcqueue" %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="cancel-pub-note">Note: if you pull the draft out of the
|
||||
{{ state.name }} state, the RFC Editor and IANA will be notified
|
||||
by email with this comment so they can update their queues.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td colspan="2" class="actions">
|
||||
<a href="{{ doc.get_absolute_url }}">Back</a>
|
||||
|
|
|
@ -57,12 +57,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% with info.conflict_reviews as r %}{% if r %}<tr><td>IETF Conflict Review:</td><td> {% filter urlize_ietf_docs %}{{ r|join:","}}{% endfilter %}</td></tr>{% endif %} {% endwith %}
|
||||
|
||||
<tr><td>Intended RFC status:</td><td>
|
||||
{% with user|in_group:"Area_Director,Secretariat" as add_link %}
|
||||
{% if add_link %}<a class="editlink" href="{% url doc_change_intended_status name=doc.draft_name %}">{% endif %}
|
||||
<a{% if info.can_edit_intended_std_level %} class="editlink" href="{% url doc_change_intended_status name=doc.draft_name %}"{% endif %}>
|
||||
{{ doc.underlying_document.intended_std_level|default:"(None)" }}
|
||||
{% if add_link %}</a>{% endif %}
|
||||
{% endwith %}
|
||||
</td></tr>
|
||||
</a>
|
||||
</td></tr>
|
||||
|
||||
<tr><td>Other versions:</td>
|
||||
{% ifequal doc.draft_status "Active" %}
|
||||
|
@ -119,6 +117,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% endif %}
|
||||
<tr><td>Document shepherd:</td><td>{{ stream_info.shepherd|default:"" }}</td></tr>
|
||||
|
||||
{% if info.consensus %}
|
||||
<tr><td>Consensus:</td><td><a title="Whether the document is the result of a community consensus process as defined in RFC 5741" {% if info.can_edit_consensus %}class="editlink" href="{% url doc_edit_consensus name=doc.draft_name %}"{% endif %}>{{ info.consensus }}</a></td></tr>
|
||||
{% endif %}
|
||||
|
||||
<tr><td colspan='2'><hr size='1' noshade /></td></tr>
|
||||
|
||||
|
||||
|
@ -128,7 +130,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% else %}
|
||||
{{ doc.friendly_state|safe }}
|
||||
{% endif %}
|
||||
{% if doc.rfc_editor_state %}<br />RFC Editor State: <a href="http://www.rfc-editor.org/queue2.html#{{doc.draft_name}}">{{ doc.rfc_editor_state|escape }}</a>{% endif %}
|
||||
{% if info.iana_review_state %}<br />IANA Review State: <a class="editlink" {% if user|in_group:"Secretariat,IANA" %}href="{% url doc_change_iana_state name=doc.draft_name state_type="iana-review" %}"{% endif %}>{{ info.iana_review_state.name|escape }}</a>{% endif %}
|
||||
{% if info.iana_action_state %}<br />IANA Action State: <a class="editlink" {% if user|in_group:"Secretariat,IANA" %}href="{% url doc_change_iana_state name=doc.draft_name state_type="iana-action" %}"{% endif %}>{{ info.iana_action_state.name|escape }}</a>{% endif %}
|
||||
{% if info.rfc_editor_state %}<br />RFC Editor State: <a href="http://www.rfc-editor.org/queue2.html#{{ doc.draft_name }}">{{ info.rfc_editor_state|escape }}</a>{% endif %}
|
||||
{% ifequal doc.draft_status "Expired" %}
|
||||
{% if doc.resurrect_requested_by %}(resurrect requested by {{ doc.resurrect_requested_by }}){% endif %}
|
||||
{% endifequal %}
|
||||
|
|
|
@ -42,7 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% include "idrfc/doc_diffs.html" %}
|
||||
{% endif %}
|
||||
<h2 style="margin-top:1em;">Document history</h2>
|
||||
{% if user|in_group:"Area_Director,Secretariat,IANA" and doc.in_ietf_process %}
|
||||
{% if user|in_group:"Area_Director,Secretariat,IANA,RFC Editor" and doc.in_ietf_process %}
|
||||
<div style="margin-bottom:8px" id="history_actions">
|
||||
<span id="doc_add_comment_button" class="yui-button yui-link-button" style="margin-left:2px;"><span class="first-child"><a href="{% url doc_add_comment name=doc.draft_name %}">Add comment</a></span></span>
|
||||
</div>
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
|
||||
{% if doc.rev %}
|
||||
<div class="markup_draft">
|
||||
{{ content|safe|linebreaksbr|keep_spacing|sanitize_html|safe }}
|
||||
{{ content|safe|keep_spacing|sanitize_html|wordwrap:80|safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
{% endif %}
|
||||
|
||||
<h2>Document history</h2>
|
||||
{% if user|has_role:"Area Director,Secretariat,IANA" %}
|
||||
{% if user|has_role:"Area Director,Secretariat,IANA,RFC Editor" %}
|
||||
<div class="history-actions">
|
||||
<a href="{% url doc_add_comment name=doc.name %}">Add comment</a>
|
||||
</div>
|
||||
|
|
|
@ -22,7 +22,7 @@ with no "Discuss" positions, are needed for approval.
|
|||
|
||||
DISCUSSES AND COMMENTS
|
||||
======================
|
||||
{% filter wordwrap:79 %}{% for pos in ad_feedback %}{{ pos.ad.get_name }}:
|
||||
{% filter wordwrap:79 %}{% for pos in ad_feedback %}{{ pos.ad }}:
|
||||
|
||||
{% if pos.discuss %}Discuss [{{ pos.discuss_time|date:"Y-m-d" }}]:
|
||||
{{ pos.discuss }}
|
||||
|
|
20
ietf/templates/idrfc/publication_request.txt
Normal file
20
ietf/templates/idrfc/publication_request.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% load mail_filters %}{% autoescape off %}{% filter wordwrap:73 %}
|
||||
The {{ approving_body }} has approved the following document in the {{ doc.stream }} stream:
|
||||
|
||||
- "{{ doc.title }}" ({{ doc.name }}) as {{ doc|std_level_prompt }}.{% if group_description %}
|
||||
|
||||
This document is the product of the {{ group_description }}.{% endif %}{% endfilter %}
|
||||
|
||||
URL: {{ doc_url }}
|
||||
|
||||
{% filter wordwrap:73 %}{% if consensus != None %}The document {% if consensus %}represents{% else %}does not necessarily represent{% endif%} the consensus of the {{ consensus_body }}.
|
||||
|
||||
{% endif %}No IANA allocation in the document requires IETF Consensus or Standards Action.{% endfilter %}
|
||||
|
||||
|
||||
[OPTIONAL: Include summary of related discussion of this document in an IETF WG or in the IESG.]
|
||||
|
||||
[OPTIONAL: Include statement of the purpose of publishing this document, its intended audience, its merits and significance.]
|
||||
|
||||
[OPTIONAL: Include suggested names and contact information for one or more competent and independent potential reviewers for the document (this can speed the review and approval process).]
|
||||
{% endautoescape %}
|
9
ietf/templates/idrfc/pulled_from_rfc_queue_email.txt
Normal file
9
ietf/templates/idrfc/pulled_from_rfc_queue_email.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
{% autoescape off %}{{ doc.name }} is no longer in the {{ prev_state.name }} state.
|
||||
|
||||
{% if comment %}Explanation:
|
||||
|
||||
{{ comment }}
|
||||
{% endif %}
|
||||
|
||||
URL: {{ url }}
|
||||
{% endautoescape %}
|
37
ietf/templates/idrfc/request_publication.html
Normal file
37
ietf/templates/idrfc/request_publication.html
Normal file
|
@ -0,0 +1,37 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Request publication for {{ doc }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
form.request-publication #id_subject,
|
||||
form.request-publication #id_body { width: 50em; }
|
||||
|
||||
form.request-publication #id_body { height: 30em; }
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Request publication for {{ doc }}</h1>
|
||||
|
||||
<p>Send a publication request to the RFC Editor for {{ doc }} and move
|
||||
it to the <em>{{ next_state.name }}</em> stream state.</p>
|
||||
|
||||
<p>Please edit the message and remove any parts in brackets you do not
|
||||
fill in. For independent submissions, see the <a
|
||||
href="http://www.rfc-editor.org/indsubs.html">guidelines</a>.</p>
|
||||
|
||||
<form class="request-publication" action="" method="POST">
|
||||
<table>
|
||||
<tr><td>From:</td> <td>{{ message.frm }}</td></tr>
|
||||
<tr><td>To:</td> <td>{{ message.to }}</td></tr>
|
||||
<tr><td>Subject:</td> <td>{{ form.subject }} {{ form.subject.errors }}</td></tr>
|
||||
<tr><td style="vertical-align: top">Message:</td> <td>{{ form.body }} {{ form.body.errors }}</td></tr>
|
||||
<tr class="actions"><td></td>
|
||||
<td>
|
||||
<a href="{% url doc_view name=doc.name %}">Back</a>
|
||||
<input name="reset" type="submit" value="Reset"/>
|
||||
<input type="submit" value="Send request to the RFC Editor"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #}
|
|||
table.agenda-doc { margin-left: 30px; margin-top:0.5em; margin-bottom: 0.5em; width: 95%; }
|
||||
table.agenda-doc > tbody > tr { vertical-align:top; }
|
||||
div.agenda-wg { margin-left: 30px; margin-top:0.5em; margin-bottom: 0.5em; width: 95%; }
|
||||
.agenda .stream { padding-left: 0.5em; }
|
||||
{% endblock morecss %}
|
||||
|
||||
{% block pagehead %}
|
||||
|
|
|
@ -71,6 +71,8 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved.
|
|||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<span class="stream">{% if doc.obj.stream %} - {{ doc.obj.stream }} stream{% endif %}</span>
|
||||
|
||||
<br/>{{ doc.obj.title|escape }} ({{ doc.obj.intended_std_level }})
|
||||
|
||||
|
||||
|
@ -97,6 +99,19 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved.
|
|||
<br/>Was deferred by {{defer.by}} on {{defer.time|date:"Y-m-d"}}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% if doc.obj.iana_review_state %}
|
||||
<br/>IANA Review: {{ doc.obj.iana_review_state }}
|
||||
{% endif %}
|
||||
|
||||
{% if doc.obj.consensus %}
|
||||
<br/>Consensus: {{ doc.obj.consensus }}
|
||||
{% endif %}
|
||||
|
||||
{% if doc.obj.lastcall_expires %}
|
||||
<br/>Last call expires: {{ doc.obj.lastcall_expires|date:"Y-m-d" }}
|
||||
{% endif %}
|
||||
|
||||
</td><td style="padding-left:20px; width: 50px;">
|
||||
{% ballot_icon doc.obj %}
|
||||
</td></tr></tbody></table>
|
||||
|
|
|
@ -39,10 +39,13 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved.
|
|||
{{ title2 }}
|
||||
{% endif %}{{ title3 }}
|
||||
{% for doc in section_docs %}{% with doc.obj.rfc_number as rfc_number %}
|
||||
o {{doc.obj.canonical_name}}{% if not rfc_number %}-{{doc.obj.rev}}{% endif %}{% endwith %}
|
||||
o {{doc.obj.canonical_name}}{% if not rfc_number %}-{{doc.obj.rev}}{% endif %}{% endwith %}{% if doc.obj.stream %} - {{ doc.obj.stream }} stream{% endif %}
|
||||
{% filter wordwrap:"68"|indent|indent %}{{ doc.obj.title }} ({{ doc.obj.intended_std_level }}){% endfilter %}
|
||||
{% if doc.obj.note %}{# note: note is not escaped #} {% filter wordwrap:"68"|indent|indent %}Note: {{ doc.obj.note|striptags }}{% endfilter %}
|
||||
{% endif %} Token: {{ doc.obj.ad }}
|
||||
{% endif %} Token: {{ doc.obj.ad }}{% if doc.obj.iana_review_state %}
|
||||
IANA Review: {{ doc.obj.iana_review_state }}{% endif %}{% if doc.obj.consensus %}
|
||||
Consensus: {{ doc.obj.consensus }}{% endif %}{% if doc.obj.lastcall_expires %}
|
||||
Last call expires: {{ doc.obj.lastcall_expires|date:"Y-m-d" }}{% endif %}
|
||||
{% with doc.obj.active_defer_event as defer %}{% if defer %} Was deferred by {{defer.by}} on {{defer.time|date:"Y-m-d"}}{% endif %}{% endwith %}
|
||||
{% empty %}
|
||||
NONE
|
||||
|
|
|
@ -7,7 +7,7 @@ Filename: {{ submission.filename }}
|
|||
Revision: {{ submission.revision }}
|
||||
Title: {{ submission.id_document_name }}
|
||||
Creation date: {{ submission.creation_date|date:"Y-m-d" }}
|
||||
WG ID: {{ wg }}
|
||||
Group: {{ wg }}
|
||||
Number of pages: {{ submission.txt_page_count }}
|
||||
URL: http://www.ietf.org/internet-drafts/{{ submission.filename }}-{{ submission.revision }}.txt
|
||||
Status: http://datatracker.ietf.org/doc/{{ submission.filename }}
|
||||
|
|
|
@ -93,7 +93,7 @@ table.ietf-table span.field-error { display: block; color: red; }
|
|||
{% show_submission_files detail %}
|
||||
</td></tr>
|
||||
<tr><th>Submission date</th><td>{{ detail.submission_date }}</td></tr>
|
||||
<tr{% if validation.warnings.group %} class="warning"{% endif %}><th>WG</th><td>{{ validation.wg|default:"Individual Submission" }}
|
||||
<tr{% if validation.warnings.group %} class="warning"{% endif %}><th>Group</th><td>{{ validation.wg|default:"Individual Submission" }}
|
||||
{% if validation.warnings.group %}
|
||||
<div class="warn_message">The secretariat will be notified that the working group is not active</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -149,7 +149,7 @@ returned to the submitter.
|
|||
</td>
|
||||
</tr>
|
||||
<tr{% if validation.warnings.revision %} class="warning"{% endif %}><th>Revision</th><td>{{ detail.revision }}<div class="warn_message">{{ validation.warnings.revision }}{% if validation.warnings.revision %}<br /><a class="twopages_trigger" href="#">[View error]</a>{% endif %}</div></td></tr>
|
||||
<tr{% if validation.warnings.group %} class="warning"{% endif %}><th>WG</th><td>{{ validation.wg|default:"Individual Submission" }}<div class="warn_message">{{ validation.warnings.group }}</div></td></tr>
|
||||
<tr{% if validation.warnings.group %} class="warning"{% endif %}><th>Group</th><td>{{ validation.wg|default:"Individual Submission" }}<div class="warn_message">{{ validation.warnings.group }}</div></td></tr>
|
||||
<tr{% if validation.warnings.creation_date %} class="warning"{% endif %}><th>Document date</th><td>{{ detail.creation_date }}<div class="warn_message">{{ validation.warnings.creation_date }}</div></td></tr>
|
||||
<tr><th>Submission date</th><td>{{ detail.submission_date }}</td></tr>
|
||||
<tr{% if validation.warnings.title %} class="warning"{% endif %}><th>Title</th><td>{{ detail.id_document_name|default:"" }}<div class="warn_message">{{ validation.warnings.title }}</div></td></tr>
|
||||
|
|
|
@ -9,7 +9,7 @@ I-D Submission Tool URL:
|
|||
File name : {{ draft.filename }}
|
||||
Version : {{ draft.revision }}
|
||||
Submission date : {{ draft.submission_date }}
|
||||
WG : {{ draft.group_acronym|default:"Individual Submission" }} {% if form.validation.warnings.group %}*Please note that this WG is not an active one*{% endif %}
|
||||
Group : {{ draft.group_acronym|default:"Individual Submission" }} {% if form.validation.warnings.group %}*Please note that this group is not an active one*{% endif %}
|
||||
|
||||
Title : {{ draft.id_document_name }}
|
||||
Document date : {{ draft.creation_date }}
|
||||
|
|
|
@ -9,7 +9,7 @@ To approve the draft, go to this URL (note: you need to login to be able to appr
|
|||
File name : {{ draft.filename }}
|
||||
Version : {{ draft.revision }}
|
||||
Submission date : {{ draft.submission_date }}
|
||||
WG : {{ draft.group_acronym|default:"Individual Submission" }}
|
||||
Group : {{ draft.group_acronym|default:"Individual Submission" }}
|
||||
|
||||
Title : {{ draft.id_document_name }}
|
||||
Document date : {{ draft.creation_date }}
|
||||
|
|
37
ietf/templates/sync/discrepancies.html
Normal file
37
ietf/templates/sync/discrepancies.html
Normal file
|
@ -0,0 +1,37 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Sync discrepancies{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
table.discrepancies td { padding-right: 0.2em; }
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Sync discrepancies</h1>
|
||||
|
||||
{% for title, docs in sections %}
|
||||
<h3>{{ title }}</h3>
|
||||
|
||||
{% if docs %}
|
||||
<table class="discrepancies">
|
||||
<tr>
|
||||
<td>Draft Name</td>
|
||||
<td>IESG state</td>
|
||||
<td>RFC Editor state</td>
|
||||
<td>IANA Action state</td>
|
||||
</tr>
|
||||
{% for d in docs %}
|
||||
<tr id="d{{ d.pk }}">
|
||||
<td><a href="{{ d.get_absolute_url }}">{{ d.name }}</a></td>
|
||||
<td>{{ d.iesg_state|default:"-" }}</td>
|
||||
<td>{{ d.rfc_state|default:"-" }}</td>
|
||||
<td>{{ d.iana_action_state|default:"-" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>None found.</p>
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endblock %}
|
18
ietf/templates/sync/discrepancies_report.txt
Normal file
18
ietf/templates/sync/discrepancies_report.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
{% autoescape off %}
|
||||
This is an automated report of current Datatracker sync discrepancies,
|
||||
also available at:
|
||||
|
||||
{{ url }}
|
||||
{% for title, docs in sections %}
|
||||
|
||||
{{ title|wordwrap:73 }}
|
||||
{% if docs %}{% for d in docs %}
|
||||
{{ d.name }}
|
||||
IESG: {{ d.iesg_state|default:"-" }}
|
||||
RFC Ed: {{ d.rfc_state|default:"-" }}
|
||||
IANA: {{ d.iana_action_state|default:"-" }}
|
||||
{{ base_url }}{{ d.get_absolute_url }}
|
||||
{% endfor %}{% else %}
|
||||
None found.
|
||||
{% endif %}{% endfor %}
|
||||
{% endautoescape %}
|
13
ietf/templates/sync/notify.html
Normal file
13
ietf/templates/sync/notify.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Trigger {{ notification }} sync for {{ org }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Trigger {{ notification }} sync for {{ org }}</h1>
|
||||
|
||||
<p>Update the Datatracker with {{ help_text|safe }} at {{ org }}.</p>
|
||||
|
||||
<form class="sync-form" method="post">
|
||||
<input type="submit" value="Trigger {{ notification }} sync"/>
|
||||
</form>
|
||||
{% endblock %}
|
29
ietf/templates/sync/rfceditor_undo.html
Normal file
29
ietf/templates/sync/rfceditor_undo.html
Normal file
|
@ -0,0 +1,29 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Undo RFC Editor state events{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Undo RFC Editor state events</h1>
|
||||
|
||||
<table class="ietf-table">
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Document</th>
|
||||
<th>Text</th>
|
||||
<th>Undo</th>
|
||||
</tr>
|
||||
{% for e in events %}
|
||||
<tr class="{% if forloop.counter|divisibleby:2 %}evenrow{% else %}oddrow{% endif %}">
|
||||
<td>{{ e.time|date:"Y-m-d H:i:s"}}</td>
|
||||
<td><a href="{% url doc_history e.doc_id %}">{{ e.doc_id }}</a></td>
|
||||
<td>{{ e.desc|safe }}</td>
|
||||
<td>
|
||||
<form method="post">
|
||||
<input type="hidden" name="event" value="{{ e.id }}"/>
|
||||
<input type="submit" value="Remove"/>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
|
@ -68,6 +68,7 @@ urlpatterns = patterns('',
|
|||
(r'^submit/', include('ietf.submit.urls')),
|
||||
(r'^(?P<path>public)/', include('ietf.redirects.urls')),
|
||||
(r'^wg/', include('ietf.wginfo.urls')),
|
||||
(r'^sync/', include('ietf.sync.urls')),
|
||||
|
||||
# Google webmaster tools verification url
|
||||
(r'^googlea30ad1dacffb5e5b.html', 'django.views.generic.simple.direct_to_template', { 'template': 'googlea30ad1dacffb5e5b.html' }),
|
||||
|
|
|
@ -26,7 +26,7 @@ test_mode = False
|
|||
outbox = []
|
||||
|
||||
def empty_outbox():
|
||||
outbox[:] = []
|
||||
outbox[:] = []
|
||||
|
||||
def add_headers(msg):
|
||||
if not(msg.has_key('Message-ID')):
|
||||
|
@ -187,16 +187,34 @@ def send_mail_mime(request, to, frm, subject, msg, cc=None, extra=None, toUser=F
|
|||
msg['X-Tracker-Bcc']=bcc
|
||||
copy_email(msg, copy_to)
|
||||
|
||||
def send_mail_preformatted(request, preformatted):
|
||||
def send_mail_preformatted(request, preformatted, extra={}, override={}):
|
||||
"""Parse preformatted string containing mail with From:, To:, ...,
|
||||
and send it through the standard IETF mail interface (inserting
|
||||
extra headers as needed)."""
|
||||
msg = message_from_string(preformatted.encode("utf-8"))
|
||||
extra = copy.copy(msg)
|
||||
for key in ['To', 'From', 'Subject', ]:
|
||||
del extra[key]
|
||||
send_mail_text(request, msg['To'], msg["From"], msg["Subject"], msg.get_payload(), extra=extra)
|
||||
|
||||
def send_mail_message(request, message):
|
||||
for k, v in override.iteritems():
|
||||
if k in msg:
|
||||
del msg[k]
|
||||
msg[k] = v
|
||||
|
||||
headers = copy.copy(msg)
|
||||
for key in ['To', 'From', 'Subject']:
|
||||
del headers[key]
|
||||
for k, v in extra.iteritems():
|
||||
if k in headers:
|
||||
del headers[k]
|
||||
headers[k] = v
|
||||
|
||||
send_mail_text(request, msg['To'], msg["From"], msg["Subject"], msg.get_payload(), extra=headers)
|
||||
|
||||
def send_mail_message(request, message, extra={}):
|
||||
"""Send a Message object."""
|
||||
# note that this doesn't handle MIME messages at the moment
|
||||
send_mail_text(request, message.to, message.frm, message.subject, message.body, cc=message.cc, bcc=message.bcc, extra={ 'Reply-to': message.reply_to })
|
||||
|
||||
e = extra.copy()
|
||||
if message.reply_to:
|
||||
e['Reply-to'] = message.reply_to
|
||||
|
||||
send_mail_text(request, message.to, message.frm, message.subject,
|
||||
message.body, cc=message.cc, bcc=message.bcc, extra=e)
|
||||
|
|
23
ietf/utils/serialize.py
Normal file
23
ietf/utils/serialize.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from django.db import models
|
||||
|
||||
def object_as_shallow_dict(obj):
|
||||
"""Turn a Django model object into a dict suitable for passing to
|
||||
create and for serializing to JSON."""
|
||||
|
||||
d = {}
|
||||
for f in obj._meta.fields:
|
||||
n = f.name
|
||||
if isinstance(f, models.ForeignKey):
|
||||
n = f.name + "_id"
|
||||
|
||||
v = getattr(obj, n)
|
||||
if isinstance(f, models.ManyToManyField):
|
||||
v = list(v.values_list("pk", flat=True))
|
||||
elif isinstance(f, models.DateTimeField):
|
||||
v = v.strftime('%Y-%m-%d %H:%M:%S')
|
||||
elif isinstance(f, models.DateField):
|
||||
v = v.strftime('%Y-%m-%d')
|
||||
|
||||
d[n] = v
|
||||
|
||||
return d
|
|
@ -114,6 +114,22 @@ def make_test_data():
|
|||
ascii="(System)",
|
||||
address="",
|
||||
)
|
||||
|
||||
# IANA and RFC Editor groups
|
||||
iana = Group.objects.create(
|
||||
name="IANA",
|
||||
acronym="iana",
|
||||
state_id="active",
|
||||
type_id="ietf",
|
||||
parent=None,
|
||||
)
|
||||
rfc_editor = Group.objects.create(
|
||||
name="RFC Editor",
|
||||
acronym="rfceditor",
|
||||
state_id="active",
|
||||
type_id="ietf",
|
||||
parent=None,
|
||||
)
|
||||
|
||||
if system_person.id != 0: # work around bug in Django
|
||||
Person.objects.filter(id=system_person.id).update(id=0)
|
||||
|
@ -248,6 +264,42 @@ def make_test_data():
|
|||
email=email,
|
||||
)
|
||||
|
||||
# IANA user
|
||||
u = User.objects.create(username="iana")
|
||||
p = Person.objects.create(
|
||||
name="Ina Iana",
|
||||
ascii="Ina Iana",
|
||||
user=u)
|
||||
Alias.objects.create(
|
||||
name=p.name,
|
||||
person=p)
|
||||
email = Email.objects.create(
|
||||
address="iana@ia.na",
|
||||
person=p)
|
||||
Role.objects.create(
|
||||
name_id="auth",
|
||||
group=iana,
|
||||
email=email,
|
||||
person=p,
|
||||
)
|
||||
|
||||
# RFC Editor user
|
||||
u = User.objects.create(username="rfc")
|
||||
p = Person.objects.create(
|
||||
name="Rfc Editor",
|
||||
ascii="Rfc Editor",
|
||||
user=u)
|
||||
email = Email.objects.create(
|
||||
address="rfc@edit.or",
|
||||
person=p)
|
||||
Role.objects.create(
|
||||
name_id="auth",
|
||||
group=rfc_editor,
|
||||
email=email,
|
||||
person=p,
|
||||
)
|
||||
|
||||
|
||||
# draft
|
||||
draft = Document.objects.create(
|
||||
name="draft-ietf-mars-test",
|
||||
|
|
|
@ -112,7 +112,7 @@ class SimpleUrlTestCase(TestCase,RealDatabaseTest):
|
|||
self.ref_prefix = os.environ.get("IETFDB_REF_PREFIX", "")
|
||||
if self.ref_prefix.endswith("/"):
|
||||
self.ref_prefix = self.ref_prefix[:-1]
|
||||
self.skip_heavy_tests = os.environ.get("IETFDB_SKIP_HEAVY", False)
|
||||
self.skip_heavy_tests = os.environ.get("IETFDB_SKIP_HEAVY", True)
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownRealDatabase()
|
||||
|
|
37
ietf/utils/timezone.py
Normal file
37
ietf/utils/timezone.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
import pytz
|
||||
import email.utils
|
||||
import datetime
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
def local_timezone_to_utc(d):
|
||||
"""Takes a naive datetime in the local timezone and returns a
|
||||
naive datetime with the corresponding UTC time."""
|
||||
local_timezone = pytz.timezone(settings.TIME_ZONE)
|
||||
|
||||
d = local_timezone.localize(d).astimezone(pytz.utc)
|
||||
|
||||
return d.replace(tzinfo=None)
|
||||
|
||||
def utc_to_local_timezone(d):
|
||||
"""Takes a naive datetime UTC and returns a naive datetime in the
|
||||
local time zone."""
|
||||
local_timezone = pytz.timezone(settings.TIME_ZONE)
|
||||
|
||||
d = local_timezone.normalize(d.replace(tzinfo=pytz.utc).astimezone(local_timezone))
|
||||
|
||||
return d.replace(tzinfo=None)
|
||||
|
||||
def email_time_to_local_timezone(date_string):
|
||||
"""Takes a time string from an email and returns a naive datetime
|
||||
in the local time zone."""
|
||||
|
||||
t = email.utils.parsedate_tz(date_string)
|
||||
d = datetime.datetime(*t[:6])
|
||||
|
||||
if t[7] != None:
|
||||
d += datetime.timedelta(seconds=t[9])
|
||||
|
||||
return utc_to_local_timezone(d)
|
||||
|
||||
|
204
magic.py
204
magic.py
|
@ -1,204 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
'''
|
||||
Python bindings for libmagic
|
||||
'''
|
||||
|
||||
import ctypes
|
||||
|
||||
from ctypes import *
|
||||
from ctypes.util import find_library
|
||||
|
||||
def _init():
|
||||
"""
|
||||
Loads the shared library through ctypes and returns a library
|
||||
L{ctypes.CDLL} instance
|
||||
"""
|
||||
return ctypes.cdll.LoadLibrary(find_library('magic'))
|
||||
|
||||
_libraries = {}
|
||||
_libraries['magic'] = _init()
|
||||
|
||||
# Flag constants for open and setflags
|
||||
MAGIC_NONE = NONE = 0
|
||||
MAGIC_DEBUG = DEBUG = 1
|
||||
MAGIC_SYMLINK = SYMLINK = 2
|
||||
MAGIC_COMPRESS = COMPRESS = 4
|
||||
MAGIC_DEVICES = DEVICES = 8
|
||||
MAGIC_MIME_TYPE = MIME_TYPE = 16
|
||||
MAGIC_CONTINUE = CONTINUE = 32
|
||||
MAGIC_CHECK = CHECK = 64
|
||||
MAGIC_PRESERVE_ATIME = PRESERVE_ATIME = 128
|
||||
MAGIC_RAW = RAW = 256
|
||||
MAGIC_ERROR = ERROR = 512
|
||||
MAGIC_MIME_ENCODING = MIME_ENCODING = 1024
|
||||
MAGIC_MIME = MIME = 1040
|
||||
MAGIC_APPLE = APPLE = 2048
|
||||
|
||||
MAGIC_NO_CHECK_COMPRESS = NO_CHECK_COMPRESS = 4096
|
||||
MAGIC_NO_CHECK_TAR = NO_CHECK_TAR = 8192
|
||||
MAGIC_NO_CHECK_SOFT = NO_CHECK_SOFT = 16384
|
||||
MAGIC_NO_CHECK_APPTYPE = NO_CHECK_APPTYPE = 32768
|
||||
MAGIC_NO_CHECK_ELF = NO_CHECK_ELF = 65536
|
||||
MAGIC_NO_CHECK_TEXT = NO_CHECK_TEXT = 131072
|
||||
MAGIC_NO_CHECK_CDF = NO_CHECK_CDF = 262144
|
||||
MAGIC_NO_CHECK_TOKENS = NO_CHECK_TOKENS = 1048576
|
||||
MAGIC_NO_CHECK_ENCODING = NO_CHECK_ENCODING = 2097152
|
||||
|
||||
MAGIC_NO_CHECK_BUILTIN = NO_CHECK_BUILTIN = 4173824
|
||||
|
||||
class magic_set(Structure):
|
||||
pass
|
||||
magic_set._fields_ = []
|
||||
magic_t = POINTER(magic_set)
|
||||
|
||||
_open = _libraries['magic'].magic_open
|
||||
_open.restype = magic_t
|
||||
_open.argtypes = [c_int]
|
||||
|
||||
_close = _libraries['magic'].magic_close
|
||||
_close.restype = None
|
||||
_close.argtypes = [magic_t]
|
||||
|
||||
_file = _libraries['magic'].magic_file
|
||||
_file.restype = c_char_p
|
||||
_file.argtypes = [magic_t, c_char_p]
|
||||
|
||||
_descriptor = _libraries['magic'].magic_descriptor
|
||||
_descriptor.restype = c_char_p
|
||||
_descriptor.argtypes = [magic_t, c_int]
|
||||
|
||||
_buffer = _libraries['magic'].magic_buffer
|
||||
_buffer.restype = c_char_p
|
||||
_buffer.argtypes = [magic_t, c_void_p, c_size_t]
|
||||
|
||||
_error = _libraries['magic'].magic_error
|
||||
_error.restype = c_char_p
|
||||
_error.argtypes = [magic_t]
|
||||
|
||||
_setflags = _libraries['magic'].magic_setflags
|
||||
_setflags.restype = c_int
|
||||
_setflags.argtypes = [magic_t, c_int]
|
||||
|
||||
_load = _libraries['magic'].magic_load
|
||||
_load.restype = c_int
|
||||
_load.argtypes = [magic_t, c_char_p]
|
||||
|
||||
_compile = _libraries['magic'].magic_compile
|
||||
_compile.restype = c_int
|
||||
_compile.argtypes = [magic_t, c_char_p]
|
||||
|
||||
_check = _libraries['magic'].magic_check
|
||||
_check.restype = c_int
|
||||
_check.argtypes = [magic_t, c_char_p]
|
||||
|
||||
_list = _libraries['magic'].magic_list
|
||||
_list.restype = c_int
|
||||
_list.argtypes = [magic_t, c_char_p]
|
||||
|
||||
_errno = _libraries['magic'].magic_errno
|
||||
_errno.restype = c_int
|
||||
_errno.argtypes = [magic_t]
|
||||
|
||||
class Magic(object):
|
||||
def __init__(self, ms):
|
||||
self._magic_t = ms
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Closes the magic database and deallocates any resources used.
|
||||
"""
|
||||
_close(self._magic_t)
|
||||
|
||||
def file(self, file):
|
||||
"""
|
||||
Returns a textual description of the contents of the argument passed
|
||||
as a filename or None if an error occurred and the MAGIC_ERROR flag
|
||||
is set. A call to errno() will return the numeric error code.
|
||||
"""
|
||||
return _file(self._magic_t, file)
|
||||
|
||||
def descriptor(self, fd):
|
||||
"""
|
||||
Like the file method, but the argument is a file descriptor.
|
||||
"""
|
||||
return _descriptor(self._magic_t, fd)
|
||||
|
||||
def buffer(self, buf):
|
||||
"""
|
||||
Returns a textual description of the contents of the argument passed
|
||||
as a buffer or None if an error occurred and the MAGIC_ERROR flag
|
||||
is set. A call to errno() will return the numeric error code.
|
||||
"""
|
||||
return _buffer(self._magic_t, buf, len(buf))
|
||||
|
||||
def error(self):
|
||||
"""
|
||||
Returns a textual explanation of the last error or None
|
||||
if there was no error.
|
||||
"""
|
||||
return _error(self._magic_t)
|
||||
|
||||
def setflags(self, flags):
|
||||
"""
|
||||
Set flags on the magic object which determine how magic checking behaves;
|
||||
a bitwise OR of the flags described in libmagic(3), but without the MAGIC_
|
||||
prefix.
|
||||
|
||||
Returns -1 on systems that don't support utime(2) or utimes(2)
|
||||
when PRESERVE_ATIME is set.
|
||||
"""
|
||||
return _setflags(self._magic_t, flags)
|
||||
|
||||
def load(self, file=None):
|
||||
"""
|
||||
Must be called to load entries in the colon separated list of database files
|
||||
passed as argument or the default database file if no argument before
|
||||
any magic queries can be performed.
|
||||
|
||||
Returns 0 on success and -1 on failure.
|
||||
"""
|
||||
return _load(self._magic_t, file)
|
||||
|
||||
def compile(self, dbs):
|
||||
"""
|
||||
Compile entries in the colon separated list of database files
|
||||
passed as argument or the default database file if no argument.
|
||||
Returns 0 on success and -1 on failure.
|
||||
The compiled files created are named from the basename(1) of each file
|
||||
argument with ".mgc" appended to it.
|
||||
"""
|
||||
return _compile(self._magic_t, dbs)
|
||||
|
||||
def check(self, dbs):
|
||||
"""
|
||||
Check the validity of entries in the colon separated list of
|
||||
database files passed as argument or the default database file
|
||||
if no argument.
|
||||
Returns 0 on success and -1 on failure.
|
||||
"""
|
||||
return _check(self._magic_t, dbs)
|
||||
|
||||
def list(self, dbs):
|
||||
"""
|
||||
Check the validity of entries in the colon separated list of
|
||||
database files passed as argument or the default database file
|
||||
if no argument.
|
||||
Returns 0 on success and -1 on failure.
|
||||
"""
|
||||
return _list(self._magic_t, dbs)
|
||||
|
||||
def errno(self):
|
||||
"""
|
||||
Returns a numeric error code. If return value is 0, an internal
|
||||
magic error occurred. If return value is non-zero, the value is
|
||||
an OS error code. Use the errno module or os.strerror() can be used
|
||||
to provide detailed error information.
|
||||
"""
|
||||
return _errno(self._magic_t)
|
||||
|
||||
def open(flags):
|
||||
"""
|
||||
Returns a magic object on success and None on failure.
|
||||
Flags argument as for setflags.
|
||||
"""
|
||||
return Magic(_open(flags))
|
Loading…
Reference in a new issue