From 6e45e5e17be94ca1199839d122e91160f4c564a0 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 16 Jan 2013 14:15:18 +0000 Subject: [PATCH 01/38] Remove .related many to many relationship, it's not really useful since we always have to restrict on the relationship type anyway, instead add two helpers for doing the necessary queries (in both directions) - Legacy-Id: 5205 --- ietf/doc/admin.py | 2 +- ietf/doc/models.py | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ietf/doc/admin.py b/ietf/doc/admin.py index 63a457ac1..430de7b0f 100644 --- a/ietf/doc/admin.py +++ b/ietf/doc/admin.py @@ -93,7 +93,7 @@ class DocumentAdmin(admin.ModelAdmin): list_display = ['name', 'rev', 'group', 'pages', 'intended_std_level', 'author_list', 'time'] search_fields = ['name'] list_filter = ['type'] - raw_id_fields = ['authors', 'related', 'group', 'shepherd', 'ad'] + raw_id_fields = ['authors', 'group', 'shepherd', 'ad'] inlines = [DocAliasInline, DocAuthorInline, RelatedDocumentInline, ] form = DocumentForm diff --git a/ietf/doc/models.py b/ietf/doc/models.py index a300a7de5..3335400b9 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -4,6 +4,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 django.utils.html import mark_safe from ietf.group.models import * from ietf.name.models import * @@ -168,7 +169,7 @@ class DocumentAuthor(models.Model): class Document(DocumentInfo): name = models.CharField(max_length=255, primary_key=True) # immutable - related = models.ManyToManyField('DocAlias', through=RelatedDocument, blank=True, related_name="reversely_related_document_set") + #related = models.ManyToManyField('DocAlias', through=RelatedDocument, blank=True, related_name="reversely_related_document_set") authors = models.ManyToManyField(Email, through=DocumentAuthor, blank=True) def __unicode__(self): @@ -231,6 +232,14 @@ class Document(DocumentInfo): name = name.upper() return name + def related_that(self, relationship): + """Return the documents that are source of relationship targeting self.""" + return Document.objects.filter(relateddocument__target__document=self, relateddocument__relationship=relationship) + + def related_that_doc(self, relationship): + """Return the doc aliases that are target of relationship originating from self.""" + return DocAlias.objects.filter(relateddocument__source=self, relateddocument__relationship=relationship) + #TODO can/should this be a function instead of a property? Currently a view uses it as a property @property def telechat_date(self): @@ -285,9 +294,6 @@ class Document(DocumentInfo): qs = self.docalias_set.filter(name__startswith='rfc') return qs[0].name[3:] if qs else None - def replaced_by(self): - return [ rel.source for alias in self.docalias_set.all() for rel in alias.relateddocument_set.filter(relationship='replaces') ] - def friendly_state(self): """ Return a concise text description of the document's current state """ if self.type_id=='draft': @@ -306,11 +312,12 @@ class Document(DocumentInfo): iesg_state_summary = iesg_state_summary + "::"+"::".join(tag.name for tag in iesg_substate) if self.get_state_slug() == "rfc": - return "RFC %d" % (urlreverse('doc_view', args=['rfc%d' % self.rfc_number]), self.rfc_number) + n = self.rfc_number() + return "RFC %s" % (urlreverse('doc_view', kwargs=dict(name='rfc%s' % n)), n) elif self.get_state_slug() == "repl": - rs = self.replaced_by() + rs = self.related_that("replaces") if rs: - return "Replaced by "+", ".join("%s" % (urlreverse('doc_view', args=[name]),name) for name in rs) + return mark_safe("Replaced by " + ", ".join("%s" % (urlreverse('doc_view', args=[name]), name) for name in rs)) else: return "Replaced" elif self.get_state_slug() == "active": From e8daf2fbdf59d8983b5586732faebbe23494fada Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 16 Jan 2013 14:17:07 +0000 Subject: [PATCH 02/38] Add migration for transforming the .desc on the new_revision events into something more akin to what is actually shown in the history page - Legacy-Id: 5206 --- .../0009_cleanup_new_revision_docevents.py | 351 ++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 ietf/doc/migrations/0009_cleanup_new_revision_docevents.py diff --git a/ietf/doc/migrations/0009_cleanup_new_revision_docevents.py b/ietf/doc/migrations/0009_cleanup_new_revision_docevents.py new file mode 100644 index 000000000..4d069781c --- /dev/null +++ b/ietf/doc/migrations/0009_cleanup_new_revision_docevents.py @@ -0,0 +1,351 @@ +# 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): + for e in orm.NewRevisionDocEvent.objects.filter(type="new_revision").iterator(): + # fix the format + if (e.doc_id.startswith("draft-") or e.doc_id.startswith("charter-")) and e.desc in ("Added new revision", "New revision available"): + desc = "New version available: %s-%s.txt" % (e.doc_id, e.rev) + orm.DocEvent.objects.filter(id=e.docevent_ptr_id).update(desc=desc) + + + 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.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.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'] From 4624f4a31cb59dae402fe39ee755bc92bacbd5eb Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 16 Jan 2013 14:20:20 +0000 Subject: [PATCH 03/38] Add migration for blanking IESG notes that just consist of "RFC XXXX", these have been superfluous for some time - Legacy-Id: 5207 --- .../0010_cleanup_rfc_number_notes.py | 353 ++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 ietf/doc/migrations/0010_cleanup_rfc_number_notes.py diff --git a/ietf/doc/migrations/0010_cleanup_rfc_number_notes.py b/ietf/doc/migrations/0010_cleanup_rfc_number_notes.py new file mode 100644 index 000000000..720f9f518 --- /dev/null +++ b/ietf/doc/migrations/0010_cleanup_rfc_number_notes.py @@ -0,0 +1,353 @@ +# encoding: utf-8 +import datetime, re +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + # whack obsolete RFC 1234 notes (obsolete now that we got RFC alias links set up properly) + for d in orm.Document.objects.filter(type="draft").exclude(note="").iterator(): + if re.match("^RFC\s*\d+$", d.note): + # there are a couple that match without a + # corresponding RFC DocAlias, but upon manual + # inspection these all turn out to be mistakes in the + # note (most are off-by-one in the RFC number) + note = re.sub("^RFC\s*\d+$", "", d.note).strip() + orm.Document.objects.filter(name=d.name).update(note=note) + + 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.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'}), + '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.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'] From d56c6753efab51a3d9c3fdd7eee36711dbd6be47 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 16 Jan 2013 14:32:59 +0000 Subject: [PATCH 04/38] Grant stream chairs access to changing the stream on a draft - Legacy-Id: 5208 --- ietf/idrfc/views_edit.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ietf/idrfc/views_edit.py b/ietf/idrfc/views_edit.py index 1e4ecb5e6..46748e8a2 100644 --- a/ietf/idrfc/views_edit.py +++ b/ietf/idrfc/views_edit.py @@ -12,6 +12,7 @@ from django import forms from django.utils.html import strip_tags from django.db.models import Max from django.conf import settings +from django.contrib.auth.decorators import login_required from ietf.utils.mail import send_mail_text, send_mail_message from ietf.ietfauth.decorators import group_required @@ -201,7 +202,7 @@ class ChangeStreamForm(forms.Form): stream = forms.ModelChoiceField(StreamName.objects.exclude(slug="legacy"), required=False) comment = forms.CharField(widget=forms.Textarea, required=False) -@group_required('Area_Director','Secretariat') +@login_required def change_stream(request, name): """Change the stream of a Document of type 'draft' , notifying parties as necessary and logging the change as a comment.""" @@ -209,6 +210,13 @@ def change_stream(request, name): if not doc.type_id=='draft': raise Http404() + if not (has_role(request.user, ("Area Director", "Secretariat")) or + (request.user.is_authenticated() and + Role.objects.filter(name="chair", + group__acronym__in=StreamName.objects.values_list("slug", flat=True), + person__user=request.user))): + return HttpResponseForbidden("You do not have permission to view this page") + login = request.user.get_profile() if request.method == 'POST': @@ -224,7 +232,7 @@ def change_stream(request, name): doc.stream = new_stream e = DocEvent(doc=doc,by=login,type='changed_document') - e.desc = u"Stream changed to %s from %s"% (new_stream,old_stream) + e.desc = u"Stream changed to %s from %s"% (new_stream, old_stream or "None") e.save() email_desc = e.desc From 8f6a26ba22ded4701a9d9a3538960dc065a7cf30 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 16 Jan 2013 14:35:13 +0000 Subject: [PATCH 05/38] Hack the format_history_text filter to be less weird, using the same formatting for snippets and full text, also link up legacy ballot set events - Legacy-Id: 5209 --- ietf/idtracker/templatetags/ietf_filters.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ietf/idtracker/templatetags/ietf_filters.py b/ietf/idtracker/templatetags/ietf_filters.py index f48a30a8a..ea2d32b7d 100644 --- a/ietf/idtracker/templatetags/ietf_filters.py +++ b/ietf/idtracker/templatetags/ietf_filters.py @@ -4,7 +4,8 @@ import textwrap from django import template from django.conf import settings from django.utils.html import escape, fix_ampersands -from django.template.defaultfilters import linebreaksbr, wordwrap, stringfilter, urlize, truncatewords_html +from django.utils.text import truncate_html_words +from django.template.defaultfilters import linebreaksbr, wordwrap, stringfilter, urlize from django.template import resolve_variable from django.utils.safestring import mark_safe, SafeData from django.utils import simplejson @@ -460,9 +461,14 @@ def ad_area(user): @register.filter def format_history_text(text): """Run history text through some cleaning and add ellipsis if it's too long.""" - full = mark_safe(sanitize_html(keep_spacing(linebreaksbr(urlize(mark_safe(text)))))) - snippet = truncatewords_html(format_textarea(text), 25) - if snippet[-3:] == "...": + full = mark_safe(text) + + if text.startswith("This was part of a ballot set with:"): + full = urlize_ietf_docs(full) + + full = mark_safe(sanitize_html(keep_spacing(linebreaksbr(urlize(full))))) + snippet = truncate_html_words(full, 25) + if snippet != full: return mark_safe(u'
%s[show all]
' % (snippet, full)) return full From 99a14b3ede53b12a153010003c59777e1e185da3 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 16 Jan 2013 14:36:02 +0000 Subject: [PATCH 06/38] Move the decoraters + utilities to new ietfauth/utils.py file - Legacy-Id: 5210 --- ietf/ietfauth/decorators.py | 87 +-------------------------- ietf/ietfauth/utils.py | 116 ++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 84 deletions(-) create mode 100644 ietf/ietfauth/utils.py diff --git a/ietf/ietfauth/decorators.py b/ietf/ietfauth/decorators.py index 973362c5b..a30cbb01b 100644 --- a/ietf/ietfauth/decorators.py +++ b/ietf/ietfauth/decorators.py @@ -30,87 +30,6 @@ # (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 django.utils.http import urlquote -from django.conf import settings -from django.db.models import Q -from django.http import HttpResponseRedirect, HttpResponseForbidden -from django.contrib.auth import REDIRECT_FIELD_NAME - -def passes_test_decorator(test_func, message): - """ - Decorator creator that creates a decorator for checking that user - passes the test, redirecting to login or returning a 403 - error. The test function should be on the form fn(user) -> - true/false. - """ - def decorate(view_func): - def inner(request, *args, **kwargs): - if not request.user.is_authenticated(): - return HttpResponseRedirect('%s?%s=%s' % (settings.LOGIN_URL, REDIRECT_FIELD_NAME, urlquote(request.get_full_path()))) - elif test_func(request.user): - return view_func(request, *args, **kwargs) - else: - return HttpResponseForbidden(message) - return inner - return decorate - -def group_required(*group_names): - """Decorator for views that checks that the user is logged in, - and belongs to (at least) one of the listed groups.""" - return passes_test_decorator(lambda u: u.groups.filter(name__in=group_names), - "Restricted to group%s %s" % ("s" if len(group_names) != 1 else "", ",".join(group_names))) - - -def has_role(user, role_names): - """Determines whether user has any of the given standard roles - given. Role names must be a list or, in case of a single value, a - string.""" - if isinstance(role_names, str) or isinstance(role_names, unicode): - role_names = [ role_names ] - - if not user or not user.is_authenticated(): - return False - - if not hasattr(user, "roles_check_cache"): - user.roles_check_cache = {} - - key = frozenset(role_names) - if key not in user.roles_check_cache: - - from ietf.person.models import Person - from ietf.group.models import Role - - try: - person = user.get_profile() - except Person.DoesNotExist: - return False - - role_qs = { - "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"), - "WG Chair": Q(person=person,name="chair", group__type="wg", group__state="active"), - "WG Secretary": Q(person=person,name="secr", group__type="wg", group__state="active"), - } - - filter_expr = Q() - for r in role_names: - filter_expr |= role_qs[r] - - user.roles_check_cache[key] = bool(Role.objects.filter(filter_expr)[:1]) - - return user.roles_check_cache[key] - -def role_required(*role_names): - """View decorator for checking that the user is logged in and - has one of the listed roles.""" - return passes_test_decorator(lambda u: has_role(u, role_names), - "Restricted to role%s %s" % ("s" if len(role_names) != 1 else "", ", ".join(role_names))) - -if settings.USE_DB_REDESIGN_PROXY_CLASSES: - # overwrite group_required - group_required = lambda *group_names: role_required(*[n.replace("Area_Director", "Area Director") for n in group_names]) +# REDESIGN: backwards compatibility, to be deleted +from ietf.ietfauth.utils import role_required, has_role, passes_test_decorator +group_required = lambda *group_names: role_required(*[n.replace("Area_Director", "Area Director") for n in group_names]) diff --git a/ietf/ietfauth/utils.py b/ietf/ietfauth/utils.py new file mode 100644 index 000000000..678e1a1f5 --- /dev/null +++ b/ietf/ietfauth/utils.py @@ -0,0 +1,116 @@ +# various authentication and authorization utilities + +from django.utils.http import urlquote +from django.conf import settings +from django.db.models import Q +from django.http import HttpResponseRedirect, HttpResponseForbidden +from django.contrib.auth import REDIRECT_FIELD_NAME + +from ietf.doc.models import Document +from ietf.person.models import Person +from ietf.group.models import Role + +def user_is_person(user, person): + """Test whether user is associated with person.""" + if not user.is_authenticated() or not person: + return False + + if person.user_id == None: + return False + + return person.user_id == user.id + +def has_role(user, role_names): + """Determines whether user has any of the given standard roles + given. Role names must be a list or, in case of a single value, a + string.""" + if isinstance(role_names, str) or isinstance(role_names, unicode): + role_names = [ role_names ] + + if not user or not user.is_authenticated(): + return False + + # use cache to avoid checking the same permissions again and again + if not hasattr(user, "roles_check_cache"): + user.roles_check_cache = {} + + key = frozenset(role_names) + if key not in user.roles_check_cache: + try: + person = user.get_profile() + except Person.DoesNotExist: + return False + + role_qs = { + "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"), + "WG Chair": Q(person=person,name="chair", group__type="wg", group__state="active"), + "WG Secretary": Q(person=person,name="secr", group__type="wg", group__state="active"), + } + + filter_expr = Q() + for r in role_names: + filter_expr |= role_qs[r] + + user.roles_check_cache[key] = bool(Role.objects.filter(filter_expr)[:1]) + + return user.roles_check_cache[key] + + +# convenient decorator + +def passes_test_decorator(test_func, message): + """Decorator creator that creates a decorator for checking that + user passes the test, redirecting to login or returning a 403 + error. The test function should be on the form fn(user) -> + true/false.""" + def decorate(view_func): + def inner(request, *args, **kwargs): + if not request.user.is_authenticated(): + return HttpResponseRedirect('%s?%s=%s' % (settings.LOGIN_URL, REDIRECT_FIELD_NAME, urlquote(request.get_full_path()))) + elif test_func(request.user): + return view_func(request, *args, **kwargs) + else: + return HttpResponseForbidden(message) + return inner + return decorate + +def role_required(*role_names): + """View decorator for checking that the user is logged in and + has one of the listed roles.""" + return passes_test_decorator(lambda u: has_role(u, role_names), + "Restricted to role%s %s" % ("s" if len(role_names) != 1 else "", ", ".join(role_names))) + +# specific permissions + +def is_authorized_in_doc_stream(user, doc): + """Return whether user is authorized to perform stream duties on + document.""" + if has_role(user, ["Secretariat"]): + return True + + if not doc.stream or not user.is_authenticated(): + return False + + # must be authorized in the stream or group + + group_req = None + + if doc.stream.slug == "ietf": + if not doc.group.type == "individ": + group_req = Q(group=doc.group) + elif doc.stream.slug == "irtf": + group_req = Q(group__acronym=doc.stream.slug) | Q(group=doc.group) + elif doc.stream.slug in ("iab", "ise"): + group_req = Q(group__acronym=doc.stream.slug) + + if not group_req: + return False + + return bool(Role.objects.filter(Q(name__in=("chair", "delegate", "auth"), person__user=user) & group_req)) + From 9e3891791aa42334709cf24dfbea13aab8ed497c Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 16 Jan 2013 14:36:49 +0000 Subject: [PATCH 07/38] Add simple helper to Email to identify invalid email addresses (from legacy author entries) - Legacy-Id: 5211 --- ietf/person/models.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ietf/person/models.py b/ietf/person/models.py index cababcda8..69386ed51 100644 --- a/ietf/person/models.py +++ b/ietf/person/models.py @@ -111,4 +111,7 @@ class Email(models.Model): return u'"%s" <%s>' % (self.person.plain_name(), self.address) else: return self.address - + + def invalid_address(self): + # we have some legacy authors with unknown email addresses + return self.address.startswith("unknown-email") and "@" not in self.address From f85ce040a66732976de999a88c72b52a91d864f9 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 16 Jan 2013 14:37:50 +0000 Subject: [PATCH 08/38] Use new new_revision .desc format for when drafts are submitted - Legacy-Id: 5212 --- ietf/submit/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/submit/utils.py b/ietf/submit/utils.py index 9cf574946..d611a5ff3 100644 --- a/ietf/submit/utils.py +++ b/ietf/submit/utils.py @@ -148,7 +148,7 @@ def perform_postREDESIGN(request, submission): 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.desc = "New version available: %s-%s.txt" % (draft.name, draft.rev) e.save() if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00": From 321f646dabef31fbb9d5827ca1dfa640ff848cdb Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 16 Jan 2013 14:41:11 +0000 Subject: [PATCH 09/38] Improve the looks of the button class by adding extra contrast and a linear gradient. Currently the gradient is only visible in fairly recent browsers. - Legacy-Id: 5213 --- static/css/base2.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/static/css/base2.css b/static/css/base2.css index 239fb20e7..8cdd710cb 100644 --- a/static/css/base2.css +++ b/static/css/base2.css @@ -206,6 +206,6 @@ table.milestones .doc { display: block; padding-left: 1em; } .stream-state .milestone { display: inline-block; font-size: smaller; background-color: #d5dde6; padding: 0 0.2em; margin-left: 0.3em; } -.button { display: inline-block; font-weight: normal; background: #eee; border: 1px solid #bbb; border-radius: 3px; color: #333; padding: 2px 8px; text-align: center; text-decoration: none; outline: none; transition-duration: 0.2s; cursor: pointer } -.button:hover { background: #ddd; color: #222; } -.button:active { background: #ccc; color: #000; } +.button { display: inline-block; font-weight: normal; background: #eee; background: linear-gradient(#fff, #ddd); border: 1px solid #666; border-radius: 3px; color: #222; padding: 4px 12px; text-align: center; text-decoration: none; outline: none; transition-duration: 0.2s; cursor: pointer; margin-right: 0.3em; } +.button:hover { background: #ddd; background: linear-gradient(#eee, #ccc); color: #111; } +.button:active { background: #ccc; background: linear-gradient(#ddd, #bbb); color: #000; } From aa70cffe7330de296328148298f941da7131cfbe Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 16 Jan 2013 14:57:01 +0000 Subject: [PATCH 10/38] Rewrite draft and RFC tabs in terms of the new schema, porting write-up and history tabs as well - Legacy-Id: 5214 --- ietf/doc/utils.py | 40 ++- ietf/idrfc/markup_txt.py | 5 +- ietf/idrfc/utils.py | 14 +- ietf/idrfc/views_doc.py | 330 +++++++++++++++--- ietf/idrfc/views_edit.py | 6 +- ietf/ietfworkflows/urls.py | 1 + ietf/templates/idrfc/document_charter.html | 18 +- .../idrfc/document_conflict_review.html | 4 +- ietf/templates/idrfc/document_draft.html | 269 ++++++++++++++ ietf/templates/idrfc/document_history.html | 5 +- ietf/templates/idrfc/document_rfc.html | 92 +++++ ietf/templates/idrfc/document_writeup.html | 12 +- static/css/doc.css | 42 ++- 13 files changed, 750 insertions(+), 88 deletions(-) create mode 100644 ietf/templates/idrfc/document_draft.html create mode 100644 ietf/templates/idrfc/document_rfc.html diff --git a/ietf/doc/utils.py b/ietf/doc/utils.py index 7f4fbe3c5..4046f91ad 100644 --- a/ietf/doc/utils.py +++ b/ietf/doc/utils.py @@ -1,4 +1,4 @@ -import os +import os, re, urllib from django.conf import settings # Should this move from idrfc to doc? @@ -145,6 +145,37 @@ def augment_events_with_revision(doc, events): e.rev = cur_rev +def add_links_in_new_revision_events(doc, events, diff_revisions): + """Add direct .txt links and diff links to new_revision events.""" + prev = None + + diff_urls = dict(((name, revision), url) for name, revision, time, url in diff_revisions) + + for e in sorted(events, key=lambda e: (e.time, e.id)): + if not e.type == "new_revision": + continue + + if not (e.doc.name, e.rev) in diff_urls: + continue + + full_url = diff_url = diff_urls[(e.doc.name, e.rev)] + + if doc.type_id in "draft": # work around special diff url for drafts + full_url = "http://tools.ietf.org/id/" + diff_url + ".txt" + + # build links + links = r'\1' % full_url + if prev: + links += "" + + if prev != None: + links += ' (diff from previous)' % (settings.RFCDIFF_PREFIX, urllib.quote(diff_url, safe="~"), urllib.quote(prev, safe="~")) + + # replace the bold filename part + e.desc = re.sub(r"(.+-[0-9][0-9].txt)", links, e.desc) + + prev = diff_url + def get_document_content(key, filename, split=True, markup=True): f = None @@ -153,15 +184,12 @@ def get_document_content(key, filename, split=True, markup=True): raw_content = f.read() except IOError: error = "Error; cannot read ("+key+")" - if split: - return (error, "") - else: - return error + return error finally: if f: f.close() if markup: - return markup_txt.markup(raw_content,split) + return markup_txt.markup(raw_content, split) else: return raw_content diff --git a/ietf/idrfc/markup_txt.py b/ietf/idrfc/markup_txt.py index b4bb5d6f0..3094ba98b 100644 --- a/ietf/idrfc/markup_txt.py +++ b/ietf/idrfc/markup_txt.py @@ -66,7 +66,8 @@ def markup(content, split=True): if split: n = content.find("\n", 5000) content1 = "
"+content[:n+1]+"
\n" - content2 = "
"+content[n+1:]+"
\n" - return (content1, content2) + return content1 + #content2 = "
"+content[n+1:]+"
\n" + #return (content1, content2) else: return "
" + content + "
\n" diff --git a/ietf/idrfc/utils.py b/ietf/idrfc/utils.py index 318880493..4388bf893 100644 --- a/ietf/idrfc/utils.py +++ b/ietf/idrfc/utils.py @@ -2,7 +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 +from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream def add_document_comment(request, doc, text, ballot=None): if request: @@ -177,17 +177,13 @@ 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): +def can_edit_intended_std_level(user, doc): 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) - ) + has_role(user, ["Secretariat", "Area Director"]) or is_authorized_in_doc_stream(user, doc)) -def can_edit_consensus(doc, user): +def can_edit_consensus(user, doc): 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) - ) + has_role(user, ["Secretariat", "Area Director"]) or is_authorized_in_doc_stream(user, doc)) def nice_consensus(consensus): mapping = { diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index 6ee158ec6..14898ea1a 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -30,7 +30,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import re, os, datetime +import re, os, datetime, urllib from django.http import HttpResponse, Http404 from django.shortcuts import render_to_response, get_object_or_404, redirect @@ -53,7 +53,7 @@ from ietf.ietfworkflows.utils import get_full_info_for_draft from ietf.doc.models import * from ietf.doc.utils import * from ietf.utils.history import find_history_active_at -from ietf.ietfauth.decorators import has_role +from ietf.ietfauth.utils import user_is_person, has_role, role_required, is_authorized_in_doc_stream def render_document_top(request, doc, tab, name): tabs = [] @@ -72,7 +72,6 @@ def render_document_top(request, doc, tab, name): tabs.append(("History", "history", urlreverse("ietf.idrfc.views_doc.document_history", kwargs=dict(name=doc.name)), True)) - name = doc.canonical_name() if name.startswith("rfc"): name = "RFC %s" % name[3:] else: @@ -86,11 +85,13 @@ def render_document_top(request, doc, tab, name): def document_main(request, name, rev=None): - if name.lower().startswith("draft") or name.lower().startswith("rfc"): + if "old" in request.GET and (name.lower().startswith("draft") or name.lower().startswith("rfc")): if rev != None: # no support for old revisions at the moment raise Http404() return document_main_idrfc(request, name, tab="document") + # generic part + doc = get_object_or_404(Document, docalias__name=name) group = doc.group if doc.type_id == 'conflrev': @@ -128,18 +129,246 @@ def document_main(request, name, rev=None): top = render_document_top(request, doc, "document", name) - telechat = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat") - if telechat and not telechat.telechat_date: + if telechat and (not telechat.telechat_date or telechat.telechat_date < datetime.date.today()): telechat = None - if telechat and telechat.telechat_date < datetime.date.today(): - telechat = None + # specific document types + + if doc.type_id == "draft": + filename = "%s-%s.txt" % (doc.name, doc.rev) + + split_content = not request.GET.get('include_text') + if request.COOKIES.get("full_draft", "") == "on": + split = False + + iesg_state = doc.get_state("draft-iesg") + + can_edit = has_role(request.user, ("Area Director", "Secretariat")) + stream_slugs = StreamName.objects.values_list("slug", flat=True) + can_change_stream = bool(can_edit or (request.user.is_authenticated() and + Role.objects.filter(name__in=("chair", "auth"), + group__acronym__in=stream_slugs, + person__user=request.user))) + can_edit_iana_state = has_role(request.user, ("Secretariat", "IANA")) + + if name.startswith("rfc"): + # RFC tab + + rfc_number = name[3:] + filename = name + ".txt" + + content = get_document_content(filename, os.path.join(settings.RFC_PATH, filename), + split_content, markup=True) + + draft_name = doc.name if doc.name.startswith("draft") else None + + def prettify_std_name(n): + if re.match(r"(rfc|bcp|fyi)[0-9]{4}", n): + return n[:3].upper() + " " + n[3:] + else: + return n + + aliases = [prettify_std_name(a.name) for a in doc.docalias_set.filter( + models.Q(name__startswith="fyi") | + models.Q(name__startswith="std"))] + + # file types + base_path = os.path.join(settings.RFC_PATH, name + ".") + possible_types = ["txt", "pdf", "ps"] + found_types = [t for t in possible_types if os.path.exists(base_path + t)] + + base = "http://www.rfc-editor.org/rfc/" + + file_urls = [] + for t in found_types: + label = "plain text" if t == "txt" else t + file_urls.append((label, base + name + "." + t)) + + if "pdf" not in found_types and "txt" in found_types: + file_urls.append(("pdf", base + "pdfrfc/" + name + ".txt.pdf")) + + if "txt" in found_types: + file_urls.append(("html", "http://tools.ietf.org/html/" + name)) + + if not found_types: + content = "This RFC is not currently available online." + split_content = False + elif "txt" not in found_types: + content = "This RFC is not available in plain text format." + split_content = False + + return render_to_response("idrfc/document_rfc.html", + dict(doc=doc, + top=top, + name=name, + content=content, + split_content=split_content, + rfc_number=rfc_number, + updates=[prettify_std_name(d.name) for d in doc.related_that_doc("updates")], + updated_by=[prettify_std_name(d.canonical_name()) for d in doc.related_that("updates")], + obsoletes=[prettify_std_name(d.name) for d in doc.related_that_doc("obs")], + obsoleted_by=[prettify_std_name(d.canonical_name()) for d in doc.related_that("obs")], + draft_name=draft_name, + aliases=aliases, + has_errata=doc.tags.filter(slug="errata"), + published=doc.latest_event(type="published_rfc"), + file_urls=file_urls, + # can_edit=can_edit, + # can_change_stream=can_change_stream, + # can_edit_stream_info=can_edit_stream_info, + # telechat=telechat, + # ballot_summary=ballot_summary, + # iesg_state=iesg_state, + ), + context_instance=RequestContext(request)) + + content = get_document_content(filename, os.path.join(settings.INTERNET_DRAFT_PATH, filename), + split_content, markup=True) + + # ballot + ballot_summary = None + if iesg_state and iesg_state.slug in ("lc", "writeupw", "goaheadw", "iesg-eva", "defer"): + active_ballot = doc.active_ballot() + if active_ballot: + ballot_summary = needed_ballot_positions(doc, active_ballot.active_ad_positions().values()) + + # submission + submission = "" + if group.type_id == "individ": + if doc.stream_id and doc.stream_id != "ietf": + submission = doc.stream.name + else: + submission = "individual" + elif group.type_id == "area" and doc.stream_id == "ietf": + submission = "individual in %s area" % group.acronym + else: + submission = "%s %s" % (group.acronym, group.type) + if group.type_id == "wg": + submission = "%s" % (urlreverse("wg_docs", kwargs=dict(acronym=doc.group.acronym)), submission) + if doc.get_state_slug("draft-stream-%s" % doc.stream_id) == "c-adopt": + submission = "candidate for %s" % submission + + # resurrection + resurrected_by = None + if doc.get_state_slug() == "expired": + e = doc.latest_event(type__in=("requested_resurrect", "completed_resurrect")) + if e and e.type == "requested_resurrect": + resurrected_by = e.by + + # file types + base_path = os.path.join(settings.INTERNET_DRAFT_PATH, doc.name + "-" + doc.rev + ".") + possible_types = ["pdf", "xml", "ps"] + found_types = ["txt"] + [t for t in possible_types if os.path.exists(base_path + t)] + + tools_base = "http://tools.ietf.org/" + + if doc.get_state_slug() == "active": + base = "http://www.ietf.org/id/" + else: + base = tools_base + "id/" + + file_urls = [] + for t in found_types: + label = "plain text" if t == "txt" else t + file_urls.append((label, base + doc.name + "-" + doc.rev + "." + t)) + + if "pdf" not in found_types: + file_urls.append(("pdf", tools_base + "pdf/" + doc.name + "-" + doc.rev + ".pdf")) + file_urls.append(("html", tools_base + "html/" + doc.name + "-" + doc.rev)) + + # stream info + stream_state = None + if doc.stream: + stream_state = doc.get_state("draft-stream-%s" % doc.stream_id) + stream_tags = get_tags_for_stream_id(doc.stream_id) + + shepherd_writeup = doc.latest_event(WriteupDocEvent, type="changed_protocol_writeup") + + can_edit_stream_info = is_authorized_in_doc_stream(request.user, doc) + can_edit_shepherd_writeup = can_edit_stream_info or user_is_person(request.user, doc.shepherd) or has_role(request.user, ["Area Director"]) + + consensus = None + if doc.stream_id in ("ietf", "irtf", "iab"): + e = doc.latest_event(ConsensusDocEvent, type="changed_consensus") + consensus = nice_consensus(e and e.consensus) + + # mailing list search archive + search_archive = "www.ietf.org/mail-archive/web/" + if doc.stream_id == "ietf" and group.type_id == "wg" and group.list_archive: + search_archive = group.list_archive + + search_archive = urllib.quote(search_archive, safe="~") + + # conflict reviews + conflict_reviews = [d.name for d in doc.related_that("conflrev")] + + # remaining actions + actions = [] + + if ((not doc.stream_id or doc.stream_id in ("ietf", "irtf")) and group.type_id == "individ" and + (Role.objects.filter(person__user=request.user, name__in=("chair", "delegate"), group__type__in=("wg",), group__state="active") + or has_role(request.user, "Secretariat"))): + actions.append(("Adopt in Group", urlreverse('edit_adopt', kwargs=dict(name=doc.name)))) + + if doc.get_state_slug() == "expired" and not resurrected_by and can_edit: + actions.append(("Request Resurrect", urlreverse('doc_request_resurrect', kwargs=dict(name=doc.name)))) + + if doc.get_state_slug() == "expired" and has_role(request.user, ("Secretariat",)): + actions.append(("Resurrect", urlreverse('doc_resurrect', kwargs=dict(name=doc.name)))) + + if doc.get_state_slug() != "expired" and doc.stream_id in ("ise", "irtf") and has_role(request.user, ("Secretariat",)) and not conflict_reviews: + label = "Begin IETF Conflict Review" + if not doc.intended_std_level: + label += " (note that intended status is not set)" + actions.append((label, urlreverse('conflict_review_start', kwargs=dict(name=doc.name)))) + + if doc.get_state_slug() != "expired" and doc.stream_id in ("ietf",) and can_edit and not iesg_state: + actions.append(("Begin IESG Processing", urlreverse('doc_edit_info', kwargs=dict(name=doc.name)) + "?new=1")) + + return render_to_response("idrfc/document_draft.html", + dict(doc=doc, + top=top, + name=name, + content=content, + split_content=split_content, + revisions=revisions, + snapshot=snapshot, + can_edit=can_edit, + can_change_stream=can_change_stream, + can_edit_stream_info=can_edit_stream_info, + can_edit_shepherd_writeup=can_edit_shepherd_writeup, + can_edit_intended_std_level=can_edit_intended_std_level(request.user, doc), + can_edit_consensus=can_edit_consensus(request.user, doc), + can_edit_iana_state=can_edit_iana_state, + telechat=telechat, + ballot_summary=ballot_summary, + group=group, + submission=submission, + resurrected_by=resurrected_by, + replaces=[d.name for d in doc.related_that_doc("replaces")], + replaced_by=[d.name for d in doc.related_that("replaces")], + conflict_reviews=conflict_reviews, + file_urls=file_urls, + stream_state=stream_state, + stream_tags=stream_tags, + milestones=doc.groupmilestone_set.filter(state="active"), + consensus=consensus, + iesg_state=iesg_state, + rfc_editor_state=doc.get_state("draft-rfceditor"), + iana_review_state=doc.get_state("draft-iana-review"), + iana_action_state=doc.get_state("draft-iana-action"), + shepherd_writeup=shepherd_writeup, + search_archive=search_archive, + actions=actions, + ), + context_instance=RequestContext(request)) + if doc.type_id == "charter": filename = "%s-%s.txt" % (doc.canonical_name(), doc.rev) - content = _get_html(filename, os.path.join(settings.CHARTER_PATH, filename), split=False) + content = get_document_content(filename, os.path.join(settings.CHARTER_PATH, filename), split=False, markup=True) ballot_summary = None if doc.get_state_slug() in ("intrev", "iesgrev"): @@ -179,7 +408,7 @@ def document_main(request, name, rev=None): # This could move to a template content = "A conflict review response has not yet been proposed." else: - content = _get_html(filename, pathname, split=False) + content = get_document_content(filename, pathname, split=False, markup=True) ballot_summary = None if doc.get_state_slug() in ("iesgeval"): @@ -198,15 +427,10 @@ def document_main(request, name, rev=None): ), context_instance=RequestContext(request)) - raise Http404() + raise Http404 def document_history(request, name): - # todo: remove need for specific handling of drafts by porting the - # two event text hacks - if name.lower().startswith("draft") or name.lower().startswith("rfc"): - return document_main_idrfc(request, name, "history") - doc = get_object_or_404(Document, docalias__name=name) top = render_document_top(request, doc, "history", name) @@ -241,6 +465,7 @@ def document_history(request, name): events = doc.docevent_set.all().order_by("-time", "-id").select_related("by") augment_events_with_revision(doc, events) + add_links_in_new_revision_events(doc, events, diff_revisions) return render_to_response("idrfc/document_history.html", dict(doc=doc, @@ -251,38 +476,61 @@ def document_history(request, name): context_instance=RequestContext(request)) def document_writeup(request, name): - if name.lower().startswith("draft") or name.lower().startswith("rfc"): - # todo: migrate idrfc to pattern below - return document_main_idrfc(request, name, "writeup") - doc = get_object_or_404(Document, docalias__name=name) top = render_document_top(request, doc, "writeup", name) - writeups = [] - if doc.type_id == "charter": - e = doc.latest_event(WriteupDocEvent, type="changed_review_announcement") - writeups.append(("WG Review Announcement", - e.text if e else "", - urlreverse("ietf.wgcharter.views.announcement_text", kwargs=dict(name=doc.name, ann="review")))) + def text_from_writeup(event_type): + e = doc.latest_event(WriteupDocEvent, type=event_type) + if e: + return e.text + else: + return "" - e = doc.latest_event(WriteupDocEvent, type="changed_action_announcement") - writeups.append(("WG Action Announcement", - e.text if e else "", - urlreverse("ietf.wgcharter.views.announcement_text", kwargs=dict(name=doc.name, ann="action")))) + sections = [] + if doc.type_id == "draft": + writeups = [] + sections.append(("Approval Announcement", + "Draft of message to be sent after approval:", + writeups)) + + writeups.append(("Announcement", + text_from_writeup("changed_ballot_approval_text"), + urlreverse("doc_ballot_approvaltext", kwargs=dict(name=doc.name)))) + + writeups.append(("Ballot Text", + text_from_writeup("changed_ballot_writeup_text"), + urlreverse("doc_ballot_writeupnotes", kwargs=dict(name=doc.name)))) + + elif doc.type_id == "charter": + sections.append(("WG Review Announcement", + "", + [("WG Review Announcement", + text_from_writeup("changed_review_announcement"), + urlreverse("ietf.wgcharter.views.announcement_text", kwargs=dict(name=doc.name, ann="review")))] + )) + + sections.append(("WG Action Announcement", + "", + [("WG Action Announcement", + text_from_writeup("changed_action_announcement"), + urlreverse("ietf.wgcharter.views.announcement_text", kwargs=dict(name=doc.name, ann="action")))] + )) if doc.latest_event(BallotDocEvent, type="created_ballot"): - e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text") - writeups.append(("Ballot Announcement", - e.text if e else "", - urlreverse("ietf.wgcharter.views.ballot_writeupnotes", kwargs=dict(name=doc.name)))) + sections.append(("Ballot Announcement", + "", + [("Ballot Announcement", + text_from_writeup("changed_ballot_writeup_text"), + urlreverse("ietf.wgcharter.views.ballot_writeupnotes", kwargs=dict(name=doc.name)))] + )) - if not writeups: + if not sections: raise Http404() return render_to_response("idrfc/document_writeup.html", dict(doc=doc, top=top, - writeups=writeups, + sections=sections, can_edit=has_role(request.user, ("Area Director", "Secretariat")), ), context_instance=RequestContext(request)) @@ -404,9 +652,11 @@ def document_json(request, name): 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) + # FIXME + return get_document_content(key, filename, split=split, markup=True), "" def include_text(request): + # FIXME include_text = request.GET.get( 'include_text' ) if "full_draft" in request.COOKIES: if request.COOKIES["full_draft"] == "on": @@ -414,6 +664,7 @@ def include_text(request): return include_text def document_main_rfc(request, rfc_number, tab): + # FIXME rfci = get_object_or_404(RfcIndex, rfc_number=rfc_number, states__type="draft", states__slug="rfc") rfci.viewing_as_rfc = True doc = RfcWrapper(rfci) @@ -445,6 +696,7 @@ def document_main_rfc(request, rfc_number, tab): @decorator_from_middleware(GZipMiddleware) def document_main_idrfc(request, name, tab): + # FIXME r = re.compile("^rfc([1-9][0-9]*)$") m = r.match(name) if m: @@ -464,8 +716,8 @@ def document_main_idrfc(request, name, tab): 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) + info["can_edit_consensus"] = can_edit_consensus(request.user, id) + info["can_edit_intended_std_level"] = can_edit_intended_std_level(request.user, id) (content1, content2) = _get_html( str(name)+","+str(id.revision)+",html", diff --git a/ietf/idrfc/views_edit.py b/ietf/idrfc/views_edit.py index 46748e8a2..acbb80440 100644 --- a/ietf/idrfc/views_edit.py +++ b/ietf/idrfc/views_edit.py @@ -204,7 +204,7 @@ class ChangeStreamForm(forms.Form): @login_required def change_stream(request, name): - """Change the stream of a Document of type 'draft' , notifying parties as necessary + """Change the stream 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': @@ -271,7 +271,7 @@ def change_intention(request, name): if doc.type_id != 'draft': raise Http404 - if not can_edit_intended_std_level(doc, request.user): + if not can_edit_intended_std_level(request.user, doc): return HttpResponseForbidden("You do not have the necessary permissions to view this page") login = request.user.get_profile() @@ -904,7 +904,7 @@ def edit_consensus(request, name): doc = get_object_or_404(Document, type="draft", name=name) - if not can_edit_consensus(doc, request.user): + if not can_edit_consensus(request.user, doc): return HttpResponseForbidden("You do not have the necessary permissions to view this page") e = doc.latest_event(ConsensusDocEvent, type="changed_consensus") diff --git a/ietf/ietfworkflows/urls.py b/ietf/ietfworkflows/urls.py index ae339e45c..af7a885d4 100644 --- a/ietf/ietfworkflows/urls.py +++ b/ietf/ietfworkflows/urls.py @@ -6,6 +6,7 @@ from django.views.generic.simple import redirect_to urlpatterns = patterns('ietf.ietfworkflows.views', url(r'^(?P[^/]+)/history/$', 'stream_history', name='stream_history'), url(r'^(?P[^/]+)/edit/adopt/$', 'edit_adopt', name='edit_adopt'), + # FIXME: the name edit_state is far too generic url(r'^(?P[^/]+)/edit/state/$', 'edit_state', name='edit_state'), url(r'^(?P[^/]+)/edit/stream/$', redirect_to, { 'url': '/doc/%(name)s/edit/info/'}) , url(r'^delegates/(?P[^/]+)/$', 'stream_delegates', name='stream_delegates'), diff --git a/ietf/templates/idrfc/document_charter.html b/ietf/templates/idrfc/document_charter.html index 5070cc851..627f41d07 100644 --- a/ietf/templates/idrfc/document_charter.html +++ b/ietf/templates/idrfc/document_charter.html @@ -1,6 +1,4 @@ -{% extends "idrfc/doc_main.html" %} -{% comment extends "base.html" %} -{% endcomment %} +{% extends "base.html" %} {% load ietf_filters %} @@ -99,24 +97,24 @@
-
+ -
+
{% if not snapshot and user|has_role:"Area Director,Secretariat" %} {% if chartering %} - {% url charter_startstop_process name=doc.name option='abandon' as abandon_url %}{% if abandon_url %}Abandon Effort{% endif %} + {% url charter_startstop_process name=doc.name option='abandon' as abandon_url %}{% if abandon_url %}Abandon Effort{% endif %} {% if request.user|has_role:"Secretariat" %} - {% url charter_approve name=doc.name as approve_url %}{% if approve_url %}Approve Charter{% endif %} + {% url charter_approve name=doc.name as approve_url %}{% if approve_url %}Approve Charter{% endif %} {% endif %} {% else %} {% if group.state_id == "proposed" or group.state_id == "bof" %} - {% url charter_submit name=doc.name option='initcharter' as start_url %}{% if start_url %}Start Chartering{% endif %} + {% url charter_submit name=doc.name option='initcharter' as start_url %}{% if start_url %}Start Chartering{% endif %} {% else %} - {% url charter_submit name=doc.name option='recharter' as recharter_url %}{% if recharter_url %}Recharter{% endif %} + {% url charter_submit name=doc.name option='recharter' as recharter_url %}{% if recharter_url %}Recharter{% endif %} {% endif %} {% endif %} @@ -134,7 +132,7 @@ {% if doc.rev != "" %} -
+
{{ content|safe|keep_spacing|sanitize_html|wordwrap:80|safe }}
{% endif %} diff --git a/ietf/templates/idrfc/document_conflict_review.html b/ietf/templates/idrfc/document_conflict_review.html index 0cb182033..cdcfcddba 100644 --- a/ietf/templates/idrfc/document_conflict_review.html +++ b/ietf/templates/idrfc/document_conflict_review.html @@ -1,4 +1,4 @@ -{% extends "idrfc/doc_main.html" %} +{% extends "base.html" %} {% load ietf_filters %} @@ -107,7 +107,7 @@ {% if doc.rev %} -
+
{{ content|fill:"80"|safe|linebreaksbr|keep_spacing|sanitize_html|safe }}
{% endif %} diff --git a/ietf/templates/idrfc/document_draft.html b/ietf/templates/idrfc/document_draft.html new file mode 100644 index 000000000..73838437f --- /dev/null +++ b/ietf/templates/idrfc/document_draft.html @@ -0,0 +1,269 @@ +{% extends "base.html" %} + +{% load ietf_filters %} + +{% block title %}{{ name }}-{{ doc.rev }}{% endblock %} + +{% block pagehead %} + + +{% endblock %} + +{% block content %} +{{ top|safe }} + +{% comment %} +
+ Snapshots: + + {% for rev in revisions %} + {{ rev }} + {% endfor %} + +
+{% endcomment %} + +
+
+ {{ doc.get_state }} {% if not doc.get_state_slug == "rfc" %}Internet-Draft{% endif %} + ({{ submission|safe }}) + + {% if resurrected_by %}- resurrect requested by {{ resurrected_by }}{% endif %} +
+ + + + + + + + + + + + + {% if replaces %} + + + + + {% endif %} + + {% if replaced_by %} + + + + + {% endif %} + + {% if conflict_reviews %} + + + + + {% endif %} + + + + + + + + + + + + + + + + + + + {% if consensus %} + + + + + {% endif %} + + + + + + + {# the shepherd write up page only works for WGs at the moment ... #} + {% if group.type_id == "wg" %} + {% if shepherd_writeup or can_edit_shepherd_writeup %} + + + + + {% endif %} + {% endif %} + + + + + + + + + + + + + + {% if iesg_state %} + {% if doc.note or can_edit %} + + + + + {% endif %} + {% endif %} + + + + + + + +
Document Stream: + {{ doc.stream|default:"No stream defined" }}
Last updated:{{ doc.time|date:"Y-m-d" }}
Replaces:{{ replaces|join:", "|urlize_ietf_docs }}
Replaced by:{{ replaced_by|join:", "|urlize_ietf_docs }}
IETF Conflict Review:{{ conflict_reviews|join:", "|urlize_ietf_docs }}
Intended RFC status: + + {{ doc.intended_std_level|default:"(None)" }} +
Other versions: + {% if doc.get_state_slug != "active" %}(expired, archived):{% endif %} + {% for label, url in file_urls %}{{ label}}{% if not forloop.last%}, {% endif %}{% endfor %} +

{{ doc.stream }} State: + + {{ stream_state|default:"(None)" }} + + + {% if stream_tags %}
{% for tag in tags %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endif %} + + {% for m in milestones %} + {{ m.due|date:"M Y" }} + {% endfor %} +
Consensus: + + {{ consensus }} + +
Document shepherd: + {# the shepherd edit page only works for WGs at the moment ... #} + + {{ doc.shepherd|default:"(None)" }} + +
Shepherd Write-Up: + + {% if shepherd_writeup %}Last changed {{ shepherd_writeup.time|date:"Y-m-d"}}{% else %}(None){% endif %} + +

IESG State: + + {{ doc.friendly_state|safe }} + + {% if iana_review_state %} +
IANA Review State: + {{ iana_review_state }} +
+ {% endif %} + + {% if iana_review_state %} +
IANA Action State: + {{ iana_action_state }} +
+ {% endif %} + + {% if rfc_editor_state %} +
+ RFC Editor State: + {{ rfc_editor_state }}
+ {% endif %} + + + + {% if ballot_summary %}
({{ ballot_summary }})
{% endif %} +
Responsible AD: + + {{ doc.ad|default:"(None)" }} + +
IESG Note: + + {{ doc.note|default:"(None)"|format_textarea|safe }} + +
Send notices to: + + {{ doc.notify|default:"No addresses provided"}} + +

+ + + + {% if can_edit and iesg_state %} + + {% endif %} + + {% if actions %} +
+ {% for label, url in actions %}{{ label }} {% endfor %} +
+ {% endif %} +
+ +{% if doc.get_state_slug == "active" %} + +
+{{ content|safe }} +
+ +{% if split_content %} +

[include full document text]

+{% endif %} + +{% else %} + +

This Internet-Draft is no longer active. Unofficial copies of old Internet-Drafts can be found here:
+http://tools.ietf.org/id/{{ doc.name }}

+ +

Abstract

+ +

{{ doc.abstract|escape }}

+ +

Authors

+ +

+ {% for author in doc.documentauthor_set.all %} + {{ author.author.person }} {% if not author.author.invalid_address %}<{{ author.author.address }}>{% endif %} + {% if not forloop.last %}
{% endif %}{% endfor %} +

+ +

(Note: The e-mail addresses provided for the authors of this Internet-Draft may no longer be valid)

+ +{% endif %} + +{% endblock %} + diff --git a/ietf/templates/idrfc/document_history.html b/ietf/templates/idrfc/document_history.html index 283689a63..43442c227 100644 --- a/ietf/templates/idrfc/document_history.html +++ b/ietf/templates/idrfc/document_history.html @@ -6,13 +6,14 @@ {% block pagehead %} + {% endblock %} {% block content %} {{ top|safe }} {% if diff_revisions and diff_revisions|length > 1 %} -
+

Diffs

@@ -55,7 +56,7 @@

Document history

{% if user|has_role:"Area Director,Secretariat,IANA,RFC Editor" %} {% endif %} diff --git a/ietf/templates/idrfc/document_rfc.html b/ietf/templates/idrfc/document_rfc.html new file mode 100644 index 000000000..03ddcf659 --- /dev/null +++ b/ietf/templates/idrfc/document_rfc.html @@ -0,0 +1,92 @@ +{% extends "base.html" %} + +{% load ietf_filters %} + +{% block title %}RFC {{ rfc_number }}{% endblock %} + +{% block pagehead %} + + +{% endblock %} + +{% block content %} +{{ top|safe }} + +
+ + + + + + + + + + + + {% comment %} +{% if doc.in_ietf_process %} + + + + +{% if doc.ietf_process.iesg_note %}{% endif %} +{% if user|in_group:"Area_Director,Secretariat" %} + +{% endif %}{# if user|in_group:... #} + +{% endif %} + {% endcomment %} + + + + + + + +
Document type: + RFC - {{ doc.std_level }} {% if doc.stream %}({{ doc.stream.name }} stream){% endif %} + + {% if obsoleted_by %}
Obsoleted by {{ obsoleted_by|join:", "|urlize_ietf_docs }}{% endif %} + {% if updated_by %}
Updated by {{ updated_by|join:", "|urlize_ietf_docs }}{% endif %} + {% if obsoletes %}
Obsoletes {{ obsoletes|join:", "|urlize_ietf_docs }}{% endif %} + {% if updates %}
Updates {{ updates|join:", "|urlize_ietf_docs }}{% endif %} + {% if aliases %}
Also Known As {{ aliases|join:", "|urlize_ietf_docs }}{% endif %} + {% if draft_name %}
Was {{ draft_name }}{% endif %} + {% if has_errata %}
Errata{% endif %} +
Published:{% if published %}{{ published.time|date:"F Y" }}{% else %}Unknown{% endif %}
* This information refers to IESG processing after the RFC was initially published
State: +{{ doc.friendly_state|safe }} (IESG: {{ doc.ietf_process.state}}) +{% if doc.ietf_process.telechat_date %}
On agenda of {{ doc.ietf_process.telechat_date }} IESG telechat {% if doc.ietf_process.telechat_returning_item %} (returning item){%endif%}{%endif%} +
Intended status:{% if doc.in_ietf_process %}{{ doc.ietf_process.intended_maturity_level|default:"-" }}{% else %}-{%endif%}
Responsible AD:{{ doc.ietf_process.ad_name|default:"-"|escape }}
IESG Note:{{ doc.ietf_process.iesg_note|escape }}
Send notices to:{{ doc.ietf_process.state_change_notice_to}}
Other versions: + {% if file_urls %} + {% for label, url in file_urls %}{{ label}}{% if not forloop.last%}, {% endif %}{% endfor %} + {% else %} + (not online) + {% endif %} +

+ + + + {% if can_edit and iesg_state %} + + {% endif %} +
+ + +
+{{ content|safe }} +
+ +{% if split_content %} +

[include full document text]

+{% endif %} + +{% endblock %} + diff --git a/ietf/templates/idrfc/document_writeup.html b/ietf/templates/idrfc/document_writeup.html index f1deda666..aae69b4c9 100644 --- a/ietf/templates/idrfc/document_writeup.html +++ b/ietf/templates/idrfc/document_writeup.html @@ -9,16 +9,20 @@ {% block content %} {{ top|safe }} -{% for title, text, url in writeups %} -
+{% for title, subtitle, writeups in sections %}

{{ title }}

-{% if can_edit %}{% if text %}Edit{% else %}Generate{% endif %} {{ title }}{% endif %} +{% if subtitle %}

{{ subtitle|safe }}

{% endif %} + +{% for name, text, url in writeups %} +
+{% if can_edit %}{% if text %}Edit{% else %}Generate{% endif %} {{ name }}{% endif %}
 {{ text }}
 
-{% endfor%} +{% endfor %} +{% endfor %} {% endblock content %} diff --git a/static/css/doc.css b/static/css/doc.css index 8d1e4211e..6bf76cd8e 100644 --- a/static/css/doc.css +++ b/static/css/doc.css @@ -3,26 +3,46 @@ #metatable tr { vertical-align: top; } #metatable tr:first-child td:first-child { width: 15em; } -.markup_draft pre { line-height: 1.2em; margin: 0; } -.m_hdr, .m_ftr { color: #808080; } -.m_ftr { border-bottom: 1px solid #a0a0a0; } -.m_h { font-family: arial; font-weight:bold;} +.document-markup pre { line-height: 1.2em; margin: 0; } +.document-markup .m_hdr, .m_ftr { color: #808080; } +.document-markup .m_ftr { border-bottom: 1px solid #a0a0a0; } +.document-markup .m_h { font-family: arial; font-weight:bold;} .snapshots { margin: 0.5em 0; } .snapshots .revisions a:last-child { font-weight: bold; } -.metabox .actions a { display: inline-block; margin-right: 0.4em; } +.metabox .links { margin-bottom: 0.2em; } +.metabox .actions { margin-top: 0.5em; } .metabox .ballot-summary { font-style: italic; } .metabox .telechat { margin-top: 0.2em; } -.diffTool { padding: 8px 4px; margin: 8px 0;} -.diffTool h2 { margin-top:0;margin-bottom:4px; } -.diffTool label { display: inline-block; width: 3em; padding: 0 0.5em; } -.diffTool form { margin: 0; } +.diff-tool { padding: 8px 4px; margin: 8px 0;} +.diff-tool h2 { margin-top:0;margin-bottom:4px; } +.diff-tool label { display: inline-block; width: 3em; padding: 0 0.5em; } +.diff-tool form { margin: 0; } .history-actions { margin-bottom: 1em; padding-left: 1px; } -.writeup pre.editable { background-color: #efefff; min-height: 3em; } -.writeup a.edit { float: right; } +.writeup pre.editable { background-color: #efefff; min-height: 3em; padding: 4px; } +.writeup a.edit { float: right; margin: 4px; } + +a.editlink { + background-image: url("/images/pencil.png"); + background-size: 10px; + background-position: right top; + background-attachment: scroll; + background-repeat: no-repeat; + padding-right: 12px; +} + +a.editlink:link {text-decoration:none; color:inherit;} +a.editlink:visited {text-decoration:none; color:inherit;} +a.editlink:hover {text-decoration:underline;} +a.editlink:active {text-decoration:underline;} + + h3 a.edit { font-weight: normal; font-size: 13px; display: inline-block; margin-left: 0.5em;} + +h4 { margin-bottom: 0; } +h4 + p { margin-top: 0; max-width: 400px; } From 9ca9eb350dc05d3e00d7b2965a4beadfca0b6108 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 17 Jan 2013 11:19:53 +0000 Subject: [PATCH 11/38] Fix two bugs in RFC Editor syncing: make sure documents we don't know beforehand get a "draft" type and make sure individually submitted drafts get the type="individ" group instead of NULL - Legacy-Id: 5282 --- ietf/sync/rfceditor.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ietf/sync/rfceditor.py b/ietf/sync/rfceditor.py index ccb7f9032..c725f4726 100644 --- a/ietf/sync/rfceditor.py +++ b/ietf/sync/rfceditor.py @@ -327,7 +327,7 @@ def update_docs_from_rfc_index(data, skip_older_than_date=None): if not doc: results.append("created document %s" % name) - doc = Document.objects.get_or_create(name=name)[0] + doc = Document.objects.create(name=name, type=DocTypeName.objects.get(slug="draft")) # add alias DocAlias.objects.get_or_create(name=name, document=doc) @@ -358,8 +358,11 @@ def update_docs_from_rfc_index(data, skip_older_than_date=None): 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.group: # if we have no group assigned, check if RFC Editor has a suggestion + if wg: + changed_attributes["group"] = Group.objects.get(acronym=wg) + else: + changed_attributes["group"] = Group.objects.get(type="individ") if not doc.latest_event(type="published_rfc"): e = DocEvent(doc=doc, type="published_rfc") From 0454f5e414a539be88ca2fd5da7245459a5b1121 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 17 Jan 2013 12:45:25 +0000 Subject: [PATCH 12/38] Make the CSS-styled button feel a bit nicer to use by flattening the active state, also introduce some temporary styles until browsers catch up with the standard syntax - Legacy-Id: 5283 --- static/css/base2.css | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/static/css/base2.css b/static/css/base2.css index 8cdd710cb..5b15d3322 100644 --- a/static/css/base2.css +++ b/static/css/base2.css @@ -206,6 +206,12 @@ table.milestones .doc { display: block; padding-left: 1em; } .stream-state .milestone { display: inline-block; font-size: smaller; background-color: #d5dde6; padding: 0 0.2em; margin-left: 0.3em; } -.button { display: inline-block; font-weight: normal; background: #eee; background: linear-gradient(#fff, #ddd); border: 1px solid #666; border-radius: 3px; color: #222; padding: 4px 12px; text-align: center; text-decoration: none; outline: none; transition-duration: 0.2s; cursor: pointer; margin-right: 0.3em; } -.button:hover { background: #ddd; background: linear-gradient(#eee, #ccc); color: #111; } -.button:active { background: #ccc; background: linear-gradient(#ddd, #bbb); color: #000; } +.button { + display: inline-block; padding: 4px 12px; margin-right: 0.3em; + color: #222; font-weight: normal; text-align: center; text-decoration: none; outline: none; cursor: pointer; + background: #eee; background: linear-gradient(#fff, #ddd); background: -webkit-linear-gradient(#fff, #ddd); background: -moz-linear-gradient(#fff, #ddd); + border: 1px solid #666; border-radius: 3px; + transition-duration: 0.2s; +} +.button:hover { color: #111; background: #ddd; background: linear-gradient(#eee, #ccc); background: -webkit-linear-gradient(#eee, #ccc); background: -moz-linear-gradient(#eee, #ccc); } +.button:active { color: #000; background: #ccc; } From a6a0596be64590fa1146a7420cf8486b7881ad65 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 17 Jan 2013 13:00:36 +0000 Subject: [PATCH 13/38] Add migration for fixing 1) a dummy RFC entry, 2) three stand-alone RFCs that didn't get their doc.type set, 3) a big bunch of historic stand-alone RFCs that have doc.group=None - set these to the individual submission "none" group for the time being so the view code doesn't have to deal with a special case. In some cases this is wrong since there actually was a WG associated but unfortunately fixing them properly requires detective work (probably parsing the RFCs) and in at least some cases recreating historic WGs. In case someone ends up doing this, the documents to check can still be found with Document.objects.filter(name__startswith="rfc", group__type="individ") since there are almost no new RFCs that didn't went through the I-D process. - Legacy-Id: 5284 --- .../migrations/0011_fixup_broken_rfc_docs.py | 379 ++++++++++++++++++ 1 file changed, 379 insertions(+) create mode 100644 ietf/doc/migrations/0011_fixup_broken_rfc_docs.py diff --git a/ietf/doc/migrations/0011_fixup_broken_rfc_docs.py b/ietf/doc/migrations/0011_fixup_broken_rfc_docs.py new file mode 100644 index 000000000..1d8f17bee --- /dev/null +++ b/ietf/doc/migrations/0011_fixup_broken_rfc_docs.py @@ -0,0 +1,379 @@ +# 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): + # first get rid of unconnected redundant RFCs + for d in orm.Document.objects.filter(name__startswith="rfc"): + if d.docalias_set.count() == 0 and orm.DocAlias.objects.filter(name=d.name): + d.delete() # this doc is unreachable + + # fix up some standalone RFCs that didn't get type="draft" set + orm.Document.objects.filter(name__startswith="rfc", type=None).update(type="draft") + + # fix RFCs with group=None, set them to the individual + # submitter "none" group - this may in some historic cases be + # wrong, but in many of those cases we don't have a group to + # connect the document to anyway (a later history fixing round + # can find these documents as + # Document.objects.filter(name__startswith="rfc", group__type="individ")) + orm.Document.objects.filter(name__startswith="rfc", group=None).update(group=orm["group.Group"].objects.get(type="individ")) + + + 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.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'}), + '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'] From c0ecb787611e4088fb2fd89b9901ac2b621c87e1 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 17 Jan 2013 13:28:42 +0000 Subject: [PATCH 14/38] Merge the I-D and RFC views by showing I-D information on RFCs too. I-Ds that have been published as RFCs redirect to the RFC URL. Also support alias URLs so e.g. /doc/bcpXXXX redirects to /doc/rfcXXXX. - Legacy-Id: 5285 --- ietf/doc/utils.py | 7 + ietf/idrfc/views_doc.py | 143 +++++++++----------- ietf/idtracker/templatetags/ietf_filters.py | 2 + ietf/templates/idrfc/document_draft.html | 117 ++++++++-------- ietf/templates/idrfc/document_rfc.html | 92 ------------- static/css/doc.css | 4 +- 6 files changed, 141 insertions(+), 224 deletions(-) delete mode 100644 ietf/templates/idrfc/document_rfc.html diff --git a/ietf/doc/utils.py b/ietf/doc/utils.py index 4046f91ad..655a9e6a8 100644 --- a/ietf/doc/utils.py +++ b/ietf/doc/utils.py @@ -217,3 +217,10 @@ def add_state_change_event(doc, by, prev_state, new_state, timestamp=None): e.save() return e + +def prettify_std_name(n): + if re.match(r"(rfc|bcp|fyi|std)[0-9]{4}", n): + return n[:3].upper() + " " + n[3:] + else: + return n + diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index 14898ea1a..b248297a9 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -53,7 +53,7 @@ from ietf.ietfworkflows.utils import get_full_info_for_draft from ietf.doc.models import * from ietf.doc.utils import * from ietf.utils.history import find_history_active_at -from ietf.ietfauth.utils import user_is_person, has_role, role_required, is_authorized_in_doc_stream +from ietf.ietfauth.utils import * def render_document_top(request, doc, tab, name): tabs = [] @@ -89,13 +89,20 @@ def document_main(request, name, rev=None): if rev != None: # no support for old revisions at the moment raise Http404() return document_main_idrfc(request, name, tab="document") - # generic part doc = get_object_or_404(Document, docalias__name=name) + + # take care of possible redirections + aliases = DocAlias.objects.filter(document=doc).values_list("name", flat=True) + if doc.type_id == "draft" and not name.startswith("rfc"): + for a in aliases: + if a.startswith("rfc"): + return redirect("doc_view", name=a) + group = doc.group if doc.type_id == 'conflrev': - conflictdoc = doc.relateddocument_set.get(relationship__slug='conflrev').target.document + conflictdoc = doc.related_that_doc('conflrev').get().document revisions = [] for h in doc.history_set.order_by("time", "id"): @@ -135,10 +142,7 @@ def document_main(request, name, rev=None): # specific document types - if doc.type_id == "draft": - filename = "%s-%s.txt" % (doc.name, doc.rev) - split_content = not request.GET.get('include_text') if request.COOKIES.get("full_draft", "") == "on": split = False @@ -153,27 +157,24 @@ def document_main(request, name, rev=None): person__user=request.user))) can_edit_iana_state = has_role(request.user, ("Secretariat", "IANA")) - if name.startswith("rfc"): - # RFC tab + rfc_number = name[3:] if name.startswith("") else None + draft_name = None + for a in aliases: + if a.startswith("draft"): + draft_name = a - rfc_number = name[3:] + rfc_aliases = [prettify_std_name(a) for a in aliases + if a.startswith("fyi") or a.startswith("std") or a.startswith("bcp")] + + latest_revision = None + + if doc.get_state_slug() == "rfc": + # content filename = name + ".txt" content = get_document_content(filename, os.path.join(settings.RFC_PATH, filename), split_content, markup=True) - draft_name = doc.name if doc.name.startswith("draft") else None - - def prettify_std_name(n): - if re.match(r"(rfc|bcp|fyi)[0-9]{4}", n): - return n[:3].upper() + " " + n[3:] - else: - return n - - aliases = [prettify_std_name(a.name) for a in doc.docalias_set.filter( - models.Q(name__startswith="fyi") | - models.Q(name__startswith="std"))] - # file types base_path = os.path.join(settings.RFC_PATH, name + ".") possible_types = ["txt", "pdf", "ps"] @@ -198,34 +199,35 @@ def document_main(request, name, rev=None): elif "txt" not in found_types: content = "This RFC is not available in plain text format." split_content = False + else: + filename = "%s-%s.txt" % (draft_name, doc.rev) - return render_to_response("idrfc/document_rfc.html", - dict(doc=doc, - top=top, - name=name, - content=content, - split_content=split_content, - rfc_number=rfc_number, - updates=[prettify_std_name(d.name) for d in doc.related_that_doc("updates")], - updated_by=[prettify_std_name(d.canonical_name()) for d in doc.related_that("updates")], - obsoletes=[prettify_std_name(d.name) for d in doc.related_that_doc("obs")], - obsoleted_by=[prettify_std_name(d.canonical_name()) for d in doc.related_that("obs")], - draft_name=draft_name, - aliases=aliases, - has_errata=doc.tags.filter(slug="errata"), - published=doc.latest_event(type="published_rfc"), - file_urls=file_urls, - # can_edit=can_edit, - # can_change_stream=can_change_stream, - # can_edit_stream_info=can_edit_stream_info, - # telechat=telechat, - # ballot_summary=ballot_summary, - # iesg_state=iesg_state, - ), - context_instance=RequestContext(request)) + content = get_document_content(filename, os.path.join(settings.INTERNET_DRAFT_PATH, filename), + split_content, markup=True) - content = get_document_content(filename, os.path.join(settings.INTERNET_DRAFT_PATH, filename), - split_content, markup=True) + # file types + base_path = os.path.join(settings.INTERNET_DRAFT_PATH, doc.name + "-" + doc.rev + ".") + possible_types = ["pdf", "xml", "ps"] + found_types = ["txt"] + [t for t in possible_types if os.path.exists(base_path + t)] + + tools_base = "http://tools.ietf.org/" + + if doc.get_state_slug() == "active": + base = "http://www.ietf.org/id/" + else: + base = tools_base + "id/" + + file_urls = [] + for t in found_types: + label = "plain text" if t == "txt" else t + file_urls.append((label, base + doc.name + "-" + doc.rev + "." + t)) + + if "pdf" not in found_types: + file_urls.append(("pdf", tools_base + "pdf/" + doc.name + "-" + doc.rev + ".pdf")) + file_urls.append(("html", tools_base + "html/" + doc.name + "-" + doc.rev)) + + # latest revision + latest_revision = doc.latest_event(NewRevisionDocEvent, type="new_revision") # ballot ballot_summary = None @@ -237,17 +239,14 @@ def document_main(request, name, rev=None): # submission submission = "" if group.type_id == "individ": - if doc.stream_id and doc.stream_id != "ietf": - submission = doc.stream.name - else: - submission = "individual" + submission = "individual" elif group.type_id == "area" and doc.stream_id == "ietf": submission = "individual in %s area" % group.acronym - else: + elif group.type_id in ("rg", "wg"): submission = "%s %s" % (group.acronym, group.type) if group.type_id == "wg": submission = "%s" % (urlreverse("wg_docs", kwargs=dict(acronym=doc.group.acronym)), submission) - if doc.get_state_slug("draft-stream-%s" % doc.stream_id) == "c-adopt": + if doc.stream_id and doc.get_state_slug("draft-stream-%s" % doc.stream_id) == "c-adopt": submission = "candidate for %s" % submission # resurrection @@ -257,32 +256,11 @@ def document_main(request, name, rev=None): if e and e.type == "requested_resurrect": resurrected_by = e.by - # file types - base_path = os.path.join(settings.INTERNET_DRAFT_PATH, doc.name + "-" + doc.rev + ".") - possible_types = ["pdf", "xml", "ps"] - found_types = ["txt"] + [t for t in possible_types if os.path.exists(base_path + t)] - - tools_base = "http://tools.ietf.org/" - - if doc.get_state_slug() == "active": - base = "http://www.ietf.org/id/" - else: - base = tools_base + "id/" - - file_urls = [] - for t in found_types: - label = "plain text" if t == "txt" else t - file_urls.append((label, base + doc.name + "-" + doc.rev + "." + t)) - - if "pdf" not in found_types: - file_urls.append(("pdf", tools_base + "pdf/" + doc.name + "-" + doc.rev + ".pdf")) - file_urls.append(("html", tools_base + "html/" + doc.name + "-" + doc.rev)) - # stream info stream_state = None if doc.stream: stream_state = doc.get_state("draft-stream-%s" % doc.stream_id) - stream_tags = get_tags_for_stream_id(doc.stream_id) + stream_tags = doc.tags.filter(slug__in=get_tags_for_stream_id(doc.stream_id)) shepherd_writeup = doc.latest_event(WriteupDocEvent, type="changed_protocol_writeup") @@ -329,12 +307,15 @@ def document_main(request, name, rev=None): return render_to_response("idrfc/document_draft.html", dict(doc=doc, + group=group, top=top, name=name, content=content, split_content=split_content, revisions=revisions, snapshot=snapshot, + latest_revision=latest_revision, + can_edit=can_edit, can_change_stream=can_change_stream, can_edit_stream_info=can_edit_stream_info, @@ -342,14 +323,24 @@ def document_main(request, name, rev=None): can_edit_intended_std_level=can_edit_intended_std_level(request.user, doc), can_edit_consensus=can_edit_consensus(request.user, doc), can_edit_iana_state=can_edit_iana_state, + + rfc_number=rfc_number, + draft_name=draft_name, telechat=telechat, ballot_summary=ballot_summary, - group=group, submission=submission, resurrected_by=resurrected_by, + replaces=[d.name for d in doc.related_that_doc("replaces")], replaced_by=[d.name for d in doc.related_that("replaces")], + updates=[prettify_std_name(d.name) for d in doc.related_that_doc("updates")], + updated_by=[prettify_std_name(d.canonical_name()) for d in doc.related_that("updates")], + obsoletes=[prettify_std_name(d.name) for d in doc.related_that_doc("obs")], + obsoleted_by=[prettify_std_name(d.canonical_name()) for d in doc.related_that("obs")], conflict_reviews=conflict_reviews, + rfc_aliases=rfc_aliases, + has_errata=doc.tags.filter(slug="errata"), + published=doc.latest_event(type="published_rfc"), file_urls=file_urls, stream_state=stream_state, stream_tags=stream_tags, diff --git a/ietf/idtracker/templatetags/ietf_filters.py b/ietf/idtracker/templatetags/ietf_filters.py index ea2d32b7d..0a8ae5a4d 100644 --- a/ietf/idtracker/templatetags/ietf_filters.py +++ b/ietf/idtracker/templatetags/ietf_filters.py @@ -221,12 +221,14 @@ def urlize_ietf_docs(string, autoescape=None): """ if autoescape and not isinstance(string, SafeData): string = escape(string) + print string string = re.sub("(?)(RFC ?)0{0,3}(\d+)", "\\1\\2", string) string = re.sub("(?)(BCP ?)0{0,3}(\d+)", "\\1\\2", string) string = re.sub("(?)(STD ?)0{0,3}(\d+)", "\\1\\2", string) string = re.sub("(?)(FYI ?)0{0,3}(\d+)", "\\1\\2", string) string = re.sub("(?)(draft-[-0-9a-zA-Z._+]+)", "\\1", string) string = re.sub("(?)(conflict-review-[-0-9a-zA-Z._+]+)", "\\1", string) + print string return mark_safe(string) urlize_ietf_docs.is_safe = True urlize_ietf_docs.needs_autoescape = True diff --git a/ietf/templates/idrfc/document_draft.html b/ietf/templates/idrfc/document_draft.html index 73838437f..b33f964da 100644 --- a/ietf/templates/idrfc/document_draft.html +++ b/ietf/templates/idrfc/document_draft.html @@ -2,60 +2,83 @@ {% load ietf_filters %} -{% block title %}{{ name }}-{{ doc.rev }}{% endblock %} +{% block title %}{% if doc.get_state_slug == "rfc" %}RFC {{ rfc_number }}{% else %}{{ name }}-{{ doc.rev }}{% endif %}{% endblock %} {% block pagehead %} - + {% endblock %} {% block content %} {{ top|safe }} -{% comment %} -
- Snapshots: - - {% for rev in revisions %} - {{ rev }} - {% endfor %} - -
-{% endcomment %} -
-
- {{ doc.get_state }} {% if not doc.get_state_slug == "rfc" %}Internet-Draft{% endif %} - ({{ submission|safe }}) - - {% if resurrected_by %}- resurrect requested by {{ resurrected_by }}{% endif %} -
- - - + + + + + + + - + - {% if replaces %} + {% if doc.get_state_slug != "rfc" %} - - + + {% endif %} - {% if replaced_by %} - - + + - {% endif %} {% if conflict_reviews %} @@ -64,22 +87,6 @@ {% endif %} - - - - - - - - - - @@ -89,11 +96,13 @@ {{ stream_state|default:"(None)" }} - {% if stream_tags %}
{% for tag in tags %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endif %} - {% for m in milestones %} - {{ m.due|date:"M Y" }} + {{ m.due|date:"M Y" }} {% endfor %} + + {% if stream_tags %} +
{% for tag in stream_tags %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}
+ {% endif %} @@ -113,7 +122,7 @@ @@ -210,9 +219,9 @@ -{% if doc.get_state_slug == "active" %} +{% if doc.get_state_slug == "active" or doc.get_state_slug == "rfc" %}
{{ content|safe }} diff --git a/ietf/templates/idrfc/document_rfc.html b/ietf/templates/idrfc/document_rfc.html deleted file mode 100644 index 03ddcf659..000000000 --- a/ietf/templates/idrfc/document_rfc.html +++ /dev/null @@ -1,92 +0,0 @@ -{% extends "base.html" %} - -{% load ietf_filters %} - -{% block title %}RFC {{ rfc_number }}{% endblock %} - -{% block pagehead %} - - -{% endblock %} - -{% block content %} -{{ top|safe }} - -
-
Document Stream: - {{ doc.stream|default:"No stream defined" }}Document type: + {% if doc.get_state_slug == "rfc" %} + RFC - {{ doc.std_level }} + ({% if published %}{{ published.time|date:"F Y" }}{% else %}publication date unknown{% endif %}{% if has_errata %}; Errata{% endif %}) + + {% if obsoleted_by %}
Obsoleted by {{ obsoleted_by|join:", "|urlize_ietf_docs }}
{% endif %} + {% if updated_by %}
Updated by {{ updated_by|join:", "|urlize_ietf_docs }}
{% endif %} + {% if obsoletes %}
Obsoletes {{ obsoletes|join:", "|urlize_ietf_docs }}
{% endif %} + {% if updates %}
Updates {{ updates|join:", "|urlize_ietf_docs }}
{% endif %} + {% if rfc_aliases %}
Also Known As {{ rfc_aliases|join:", "|urlize_ietf_docs }}
{% endif %} + {% if draft_name %}
Was {{ draft_name }} {% if submission %}({{ submission|safe }}){% endif %}
{% endif %} + {% else %} + {{ doc.get_state }} Internet-Draft {% if submission %}({{ submission|safe }}){% endif %} + + {% if resurrected_by %}- resurrect requested by {{ resurrected_by }}{% endif %} + {% endif %} + + + {% if replaces %}
Replaces: {{ replaces|join:", "|urlize_ietf_docs }}
{% endif %} + {% if replaced_by %}
Replaced by: {{ replaced_by|join:", "|urlize_ietf_docs }}
{% endif %} +
Document stream: + + {{ doc.stream|default:"No stream defined" }} + +
Last updated:{{ doc.time|date:"Y-m-d" }} + {{ doc.time|date:"Y-m-d" }} + {% if latest_revision and latest_revision.time.date != doc.time.date %} + (latest revision {{ latest_revision.time|date:"Y-m-d" }}) + {% endif %} +
Replaces:{{ replaces|join:", "|urlize_ietf_docs }}Intended RFC status: + + {{ doc.intended_std_level|default:"Unknown" }} +
Replaced by:{{ replaced_by|join:", "|urlize_ietf_docs }}Other versions: + {% if doc.get_state_slug != "active" and doc.get_state_slug != "rfc" %}(expired, archived):{% endif %} + {% if file_urls %} + {% for label, url in file_urls %}{{ label}}{% if not forloop.last%}, {% endif %}{% endfor %} + {% else %} + (not online) + {% endif %} +
Intended RFC status: - - {{ doc.intended_std_level|default:"(None)" }} -
Other versions: - {% if doc.get_state_slug != "active" %}(expired, archived):{% endif %} - {% for label, url in file_urls %}{{ label}}{% if not forloop.last%}, {% endif %}{% endfor %} -

{# the shepherd edit page only works for WGs at the moment ... #} - {{ doc.shepherd|default:"(None)" }} + {{ doc.shepherd|default:"No shepherd assigned" }}
- - - - - - - - - - - {% comment %} -{% if doc.in_ietf_process %} - - - - -{% if doc.ietf_process.iesg_note %}{% endif %} -{% if user|in_group:"Area_Director,Secretariat" %} - -{% endif %}{# if user|in_group:... #} - -{% endif %} - {% endcomment %} - - - - - - - -
Document type: - RFC - {{ doc.std_level }} {% if doc.stream %}({{ doc.stream.name }} stream){% endif %} - - {% if obsoleted_by %}
Obsoleted by {{ obsoleted_by|join:", "|urlize_ietf_docs }}{% endif %} - {% if updated_by %}
Updated by {{ updated_by|join:", "|urlize_ietf_docs }}{% endif %} - {% if obsoletes %}
Obsoletes {{ obsoletes|join:", "|urlize_ietf_docs }}{% endif %} - {% if updates %}
Updates {{ updates|join:", "|urlize_ietf_docs }}{% endif %} - {% if aliases %}
Also Known As {{ aliases|join:", "|urlize_ietf_docs }}{% endif %} - {% if draft_name %}
Was {{ draft_name }}{% endif %} - {% if has_errata %}
Errata{% endif %} -
Published:{% if published %}{{ published.time|date:"F Y" }}{% else %}Unknown{% endif %}
* This information refers to IESG processing after the RFC was initially published
State: -{{ doc.friendly_state|safe }} (IESG: {{ doc.ietf_process.state}}) -{% if doc.ietf_process.telechat_date %}
On agenda of {{ doc.ietf_process.telechat_date }} IESG telechat {% if doc.ietf_process.telechat_returning_item %} (returning item){%endif%}{%endif%} -
Intended status:{% if doc.in_ietf_process %}{{ doc.ietf_process.intended_maturity_level|default:"-" }}{% else %}-{%endif%}
Responsible AD:{{ doc.ietf_process.ad_name|default:"-"|escape }}
IESG Note:{{ doc.ietf_process.iesg_note|escape }}
Send notices to:{{ doc.ietf_process.state_change_notice_to}}
Other versions: - {% if file_urls %} - {% for label, url in file_urls %}{{ label}}{% if not forloop.last%}, {% endif %}{% endfor %} - {% else %} - (not online) - {% endif %} -

- - - - {% if can_edit and iesg_state %} - - {% endif %} -
- - -
-{{ content|safe }} -
- -{% if split_content %} -

[include full document text]

-{% endif %} - -{% endblock %} - diff --git a/static/css/doc.css b/static/css/doc.css index 6bf76cd8e..deaa737d9 100644 --- a/static/css/doc.css +++ b/static/css/doc.css @@ -3,6 +3,8 @@ #metatable tr { vertical-align: top; } #metatable tr:first-child td:first-child { width: 15em; } +.stream-tags { font-style: italic; } + .document-markup pre { line-height: 1.2em; margin: 0; } .document-markup .m_hdr, .m_ftr { color: #808080; } .document-markup .m_ftr { border-bottom: 1px solid #a0a0a0; } @@ -40,8 +42,6 @@ a.editlink:visited {text-decoration:none; color:inherit;} a.editlink:hover {text-decoration:underline;} a.editlink:active {text-decoration:underline;} - - h3 a.edit { font-weight: normal; font-size: 13px; display: inline-block; margin-left: 0.5em;} h4 { margin-bottom: 0; } From 5efcc5fbef5dab0269bf06911ecd1d2960cd135e Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 17 Jan 2013 15:39:57 +0000 Subject: [PATCH 15/38] Fix revision augmentation so events after RFC publication gets a "RFC" designation - Legacy-Id: 5286 --- ietf/doc/utils.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ietf/doc/utils.py b/ietf/doc/utils.py index 655a9e6a8..9e1966ac7 100644 --- a/ietf/doc/utils.py +++ b/ietf/doc/utils.py @@ -130,9 +130,12 @@ def augment_events_with_revision(doc, events): event_revisions = list(NewRevisionDocEvent.objects.filter(doc=doc).order_by('time', 'id').values('id', 'rev', 'time')) - cur_rev = doc.rev - if doc.get_state_slug() == "rfc": - cur_rev = "RFC" + if doc.type_id == "draft" and doc.get_state_slug() == "rfc": + # add fake "RFC" revision + e = doc.latest_event(type="published_rfc") + if e: + event_revisions.append(dict(id=e.id, time=e.time, rev="RFC")) + event_revisions.sort(key=lambda x: (x["time"], x["id"])) for e in sorted(events, key=lambda e: (e.time, e.id), reverse=True): while event_revisions and (e.time, e.id) < (event_revisions[-1]["time"], event_revisions[-1]["id"]): From b8724d84f44209a474ba7ab35008315fcea87279 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 17 Jan 2013 16:00:36 +0000 Subject: [PATCH 16/38] Fix bug with tabs not using provided name but rather doc.name - Legacy-Id: 5287 --- ietf/idrfc/views_doc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index b248297a9..fd79d800c 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -68,9 +68,9 @@ def render_document_top(request, doc, tab, name): # FIXME: if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot: if doc.type_id != "conflrev": - tabs.append(("IESG Writeups", "writeup", urlreverse("ietf.idrfc.views_doc.document_writeup", kwargs=dict(name=doc.name)), True)) + tabs.append(("IESG Writeups", "writeup", urlreverse("ietf.idrfc.views_doc.document_writeup", kwargs=dict(name=name)), True)) - tabs.append(("History", "history", urlreverse("ietf.idrfc.views_doc.document_history", kwargs=dict(name=doc.name)), True)) + tabs.append(("History", "history", urlreverse("ietf.idrfc.views_doc.document_history", kwargs=dict(name=name)), True)) if name.startswith("rfc"): name = "RFC %s" % name[3:] From 188c619635d36eb8362d8b529d004a2575df0309 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 17 Jan 2013 16:02:50 +0000 Subject: [PATCH 17/38] Display draft-iesg state rather than doc.friendly_state as IESG state, also show a notice that the IESG state refers to post-RFC processing if it does, like the old separate RFC page did - Legacy-Id: 5288 --- ietf/doc/models.py | 6 ++++-- ietf/idrfc/views_doc.py | 1 + ietf/templates/idrfc/document_draft.html | 8 +++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ietf/doc/models.py b/ietf/doc/models.py index 3335400b9..5e43d06d6 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -138,8 +138,10 @@ class DocumentInfo(models.Model): def active_ballot(self): """Returns the most recently created ballot if it isn't closed.""" ballot = self.latest_event(BallotDocEvent, type="created_ballot") - open = self.ballot_open(ballot.ballot_type.slug) if ballot else False - return ballot if open else None + if ballot and self.ballot_open(ballot.ballot_type.slug): + return ballot + else: + return None class Meta: abstract = True diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index fd79d800c..60b6feedd 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -350,6 +350,7 @@ def document_main(request, name, rev=None): rfc_editor_state=doc.get_state("draft-rfceditor"), iana_review_state=doc.get_state("draft-iana-review"), iana_action_state=doc.get_state("draft-iana-action"), + started_iesg_process=doc.latest_event(type="started_iesg_process"), shepherd_writeup=shepherd_writeup, search_archive=search_archive, actions=actions, diff --git a/ietf/templates/idrfc/document_draft.html b/ietf/templates/idrfc/document_draft.html index b33f964da..8405843f6 100644 --- a/ietf/templates/idrfc/document_draft.html +++ b/ietf/templates/idrfc/document_draft.html @@ -143,11 +143,17 @@
+ {% if published and started_iesg_process and published.time < started_iesg_process.time %} + + This information refers to IESG processing after the RFC was initially published: + + {% endif %} + IESG State: - {{ doc.friendly_state|safe }} + {{ iesg_state|default:"I-D Exists" }} {% if iana_review_state %}
IANA Review State: From ce081cb31daf4d503ca2e944b5ab51201535e01e Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 17 Jan 2013 17:10:19 +0000 Subject: [PATCH 18/38] Fix the RFC number doc.note migration to catch combined "RFC XXX; BCP XXX" notes too, use the opportunity to remove inserted HTML tags from notes and rely on linebreaksbr filter instead (the other thing was a left-over from the Perl days), update the various uses of the note to reflect that - Legacy-Id: 5289 --- ...ber_notes.py => 0010_cleanup_doc_notes.py} | 24 +++++++++++++------ ietf/idrfc/views_edit.py | 10 ++++---- ietf/iesg/views.py | 3 --- ietf/templates/idrfc/document_draft.html | 2 +- ietf/templates/idtracker/document_entry.html | 2 +- ietf/templates/iesg/agenda_conflict_doc.html | 2 +- ietf/templates/iesg/agenda_doc.html | 2 +- ietf/templates/iesg/scribe_conflict_doc.html | 4 ++-- ietf/templates/iesg/scribe_doc.html | 2 +- 9 files changed, 28 insertions(+), 23 deletions(-) rename ietf/doc/migrations/{0010_cleanup_rfc_number_notes.py => 0010_cleanup_doc_notes.py} (97%) diff --git a/ietf/doc/migrations/0010_cleanup_rfc_number_notes.py b/ietf/doc/migrations/0010_cleanup_doc_notes.py similarity index 97% rename from ietf/doc/migrations/0010_cleanup_rfc_number_notes.py rename to ietf/doc/migrations/0010_cleanup_doc_notes.py index 720f9f518..533dad298 100644 --- a/ietf/doc/migrations/0010_cleanup_rfc_number_notes.py +++ b/ietf/doc/migrations/0010_cleanup_doc_notes.py @@ -7,14 +7,24 @@ from django.db import models class Migration(DataMigration): def forwards(self, orm): - # whack obsolete RFC 1234 notes (obsolete now that we got RFC alias links set up properly) for d in orm.Document.objects.filter(type="draft").exclude(note="").iterator(): - if re.match("^RFC\s*\d+$", d.note): - # there are a couple that match without a - # corresponding RFC DocAlias, but upon manual - # inspection these all turn out to be mistakes in the - # note (most are off-by-one in the RFC number) - note = re.sub("^RFC\s*\d+$", "", d.note).strip() + note = d.note + + # get rid of HTML garbage + note = note.replace("\r", "") + note = note.replace("
", "\n") + note = note.replace(" ", " ") + note = note.strip() + + # whack obsolete RFC/BCP/STD 1234 notes (obsolete now that + # we got RFC alias links set up properly), + # there are a couple that match without a + # corresponding RFC DocAlias, but upon manual + # inspection these all turn out to be mistakes in the + # note (most are off-by-one in the RFC number) + note = re.sub("^((STD|BCP|RFC)\s*#?\d+[\s,;]*)+", "", note).strip() + + if note != d.note: orm.Document.objects.filter(name=d.name).update(note=note) def backwards(self, orm): diff --git a/ietf/idrfc/views_edit.py b/ietf/idrfc/views_edit.py index acbb80440..58601b020 100644 --- a/ietf/idrfc/views_edit.py +++ b/ietf/idrfc/views_edit.py @@ -380,8 +380,7 @@ class EditInfoFormREDESIGN(forms.Form): self.standard_fields = [x for x in self.visible_fields() if x.name not in ('returning_item',)] def clean_note(self): - # note is stored munged in the database - return self.cleaned_data['note'].replace('\n', '
').replace('\r', '').replace(' ', '  ') + return self.cleaned_data['note'].replace('\r', '').strip() def get_initial_notify(doc): @@ -516,7 +515,7 @@ def edit_infoREDESIGN(request, name): area=doc.group_id, ad=doc.ad_id, notify=doc.notify, - note=dehtmlify_textarea_text(doc.note), + note=doc.note, telechat_date=initial_telechat_date, returning_item=initial_returning_item, ) @@ -811,15 +810,14 @@ class IESGNoteForm(forms.Form): note = forms.CharField(widget=forms.Textarea, label="IESG note", required=False) def clean_note(self): - # note is stored munged in the database - return self.cleaned_data['note'].replace('\n', '
').replace('\r', '').replace(' ', '  ') + return self.cleaned_data['note'].replace('\r', '').strip() @group_required("Area Director", "Secretariat") def edit_iesg_note(request, name): doc = get_object_or_404(Document, type="draft", name=name) login = request.user.get_profile() - initial = dict(note=dehtmlify_textarea_text(doc.note)) + initial = dict(note=doc.note) if request.method == "POST": form = IESGNoteForm(request.POST, initial=initial) diff --git a/ietf/iesg/views.py b/ietf/iesg/views.py index f956e220a..9d82f85b4 100644 --- a/ietf/iesg/views.py +++ b/ietf/iesg/views.py @@ -229,9 +229,6 @@ def agenda_docs(date, next_agenda): section_key = "s"+get_doc_section(id) if section_key not in res: res[section_key] = [] - if id.note: - # TODO: Find out why this is _here_ - id.note = id.note.replace(u"\240",u" ") res[section_key].append({'obj':id}) return res diff --git a/ietf/templates/idrfc/document_draft.html b/ietf/templates/idrfc/document_draft.html index 8405843f6..d8224f7b6 100644 --- a/ietf/templates/idrfc/document_draft.html +++ b/ietf/templates/idrfc/document_draft.html @@ -203,7 +203,7 @@ IESG Note: - {{ doc.note|default:"(None)"|format_textarea|safe }} + {{ doc.note|default:"(None)"|linebreaksbr }} diff --git a/ietf/templates/idtracker/document_entry.html b/ietf/templates/idtracker/document_entry.html index 56a7e06e8..d7b8f5f6c 100644 --- a/ietf/templates/idtracker/document_entry.html +++ b/ietf/templates/idtracker/document_entry.html @@ -20,6 +20,6 @@ {% if doc.primary_flag %} Token:{{ doc.token_name }} {% if doc.note %} -Note:{{ doc.note|safe|urlize }} +Note:{{ doc.note|linebreaksbr|urlize }} {% endif %} {% endif %} diff --git a/ietf/templates/iesg/agenda_conflict_doc.html b/ietf/templates/iesg/agenda_conflict_doc.html index 43d3c1187..24bb79bf3 100644 --- a/ietf/templates/iesg/agenda_conflict_doc.html +++ b/ietf/templates/iesg/agenda_conflict_doc.html @@ -83,7 +83,7 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved. [txt]
{{ doc.obj.conflictdoc.title|escape }} ({{doc.obj.conflictdoc.stream}}: {{ doc.obj.conflictdoc.intended_std_level }}) {% if doc.obj.conflictdoc.note %} -
Note: {{ doc.obj.conflictdoc.note|unescape }} +
Note: {{ doc.obj.conflictdoc.note|linebreaksbr }} {% endif %} {% if doc.obj.conflictdoc.ipr %} diff --git a/ietf/templates/iesg/agenda_doc.html b/ietf/templates/iesg/agenda_doc.html index 6e017e6db..bbc31cdf9 100644 --- a/ietf/templates/iesg/agenda_doc.html +++ b/ietf/templates/iesg/agenda_doc.html @@ -77,7 +77,7 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved. {% if doc.obj.note %} -
Note: {{ doc.obj.note|unescape }} +
Note: {{ doc.obj.note|linebreaksbr }} {% endif %} {% if doc.obj.ipr %} diff --git a/ietf/templates/iesg/scribe_conflict_doc.html b/ietf/templates/iesg/scribe_conflict_doc.html index d1800b9fb..8c618f9aa 100644 --- a/ietf/templates/iesg/scribe_conflict_doc.html +++ b/ietf/templates/iesg/scribe_conflict_doc.html @@ -51,8 +51,8 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved. {{ doc.obj.conflictdoc.title|escape }} ({{doc.obj.conflictdoc.stream}}: {{ doc.obj.conflictdoc.intended_std_level }})
{{doc.obj.conflictdoc.canonical_name}} [txt] - {% if doc.obj.conflictdoc.note %}{# note: note is not escaped #} -
Note: {{ doc.obj.conflictdoc.note|safe }} + {% if doc.obj.conflictdoc.note %} +
Note: {{ doc.obj.conflictdoc.note|linebreaksbr }} {% endif %} {% for ipr in doc.obj.conflictdoc.ipr %} {% ifequal ipr.ipr.status 1 %} diff --git a/ietf/templates/iesg/scribe_doc.html b/ietf/templates/iesg/scribe_doc.html index cb2126750..22491e7ea 100644 --- a/ietf/templates/iesg/scribe_doc.html +++ b/ietf/templates/iesg/scribe_doc.html @@ -55,7 +55,7 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved. {% endwith %}
Token: {{ doc.obj.ad.plain_name|escape }} ({{doc.obj.area_acronym}} area) {% if doc.obj.note %} -
Note: {{ doc.obj.note }} +
Note: {{ doc.obj.note|linebreaksbr }} {% endif %} {% for ipr in doc.obj.ipr %} {% ifequal ipr.ipr.status 1 %} From 024e98d9a8f9dafa0d1f3d6b11bb19038e6bd538 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 09:38:29 +0000 Subject: [PATCH 19/38] Delete unused code - Legacy-Id: 5290 --- ietf/idrfc/views_doc.py | 222 +--------------- ietf/templates/idrfc/doc_ballot.html | 96 ------- ietf/templates/idrfc/doc_ballot_list.html | 7 - ietf/templates/idrfc/doc_description.html | 6 - ietf/templates/idrfc/doc_diffs.html | 68 ----- ietf/templates/idrfc/doc_history.html | 80 ------ ietf/templates/idrfc/doc_main.html | 126 ---------- ietf/templates/idrfc/doc_tab_ballot.html | 47 ---- ietf/templates/idrfc/doc_tab_document.html | 88 ------- ietf/templates/idrfc/doc_tab_document_id.html | 237 ------------------ .../templates/idrfc/doc_tab_document_rfc.html | 110 -------- ietf/templates/idrfc/doc_tab_history.html | 52 ---- ietf/templates/idrfc/doc_tab_writeup.html | 73 ------ ietf/templates/idrfc/doc_title.html | 5 - 14 files changed, 6 insertions(+), 1211 deletions(-) delete mode 100644 ietf/templates/idrfc/doc_ballot.html delete mode 100644 ietf/templates/idrfc/doc_ballot_list.html delete mode 100644 ietf/templates/idrfc/doc_description.html delete mode 100644 ietf/templates/idrfc/doc_diffs.html delete mode 100644 ietf/templates/idrfc/doc_history.html delete mode 100644 ietf/templates/idrfc/doc_main.html delete mode 100644 ietf/templates/idrfc/doc_tab_ballot.html delete mode 100644 ietf/templates/idrfc/doc_tab_document.html delete mode 100644 ietf/templates/idrfc/doc_tab_document_id.html delete mode 100644 ietf/templates/idrfc/doc_tab_document_rfc.html delete mode 100644 ietf/templates/idrfc/doc_tab_history.html delete mode 100644 ietf/templates/idrfc/doc_tab_writeup.html delete mode 100644 ietf/templates/idrfc/doc_title.html diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index 60b6feedd..ce5995f27 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -43,13 +43,7 @@ from django.middleware.gzip import GZipMiddleware from django.core.urlresolvers import reverse as urlreverse, NoReverseMatch 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 from ietf.doc.models import * from ietf.doc.utils import * from ietf.utils.history import find_history_active_at @@ -84,13 +78,8 @@ def render_document_top(request, doc, tab, name): name=name)) +@decorator_from_middleware(GZipMiddleware) def document_main(request, name, rev=None): - if "old" in request.GET and (name.lower().startswith("draft") or name.lower().startswith("rfc")): - if rev != None: # no support for old revisions at the moment - raise Http404() - return document_main_idrfc(request, name, tab="document") - # generic part - doc = get_object_or_404(Document, docalias__name=name) # take care of possible redirections @@ -643,206 +632,16 @@ def document_json(request, name): return HttpResponse(json.dumps(data, indent=2), mimetype='text/plain') -def _get_html(key, filename, split=True): - # FIXME - return get_document_content(key, filename, split=split, markup=True), "" - -def include_text(request): - # FIXME - include_text = request.GET.get( 'include_text' ) - if "full_draft" in request.COOKIES: - if request.COOKIES["full_draft"] == "on": - include_text = 1 - return include_text - -def document_main_rfc(request, rfc_number, tab): - # FIXME - rfci = get_object_or_404(RfcIndex, rfc_number=rfc_number, states__type="draft", states__slug="rfc") - rfci.viewing_as_rfc = True - doc = RfcWrapper(rfci) - - info = {} - info['is_rfc'] = True - info['has_pdf'] = (".pdf" in doc.file_types()) - info['has_txt'] = (".txt" in doc.file_types()) - info['has_ps'] = (".ps" in doc.file_types()) - if info['has_txt']: - (content1, content2) = _get_html( - "rfc"+str(rfc_number)+",html", - os.path.join(settings.RFC_PATH, "rfc"+str(rfc_number)+".txt")) - else: - content1 = "" - content2 = "" - - history = _get_history(doc, None) - - template = "idrfc/doc_tab_%s" % tab - if tab == "document": - template += "_rfc" - return render_to_response(template + ".html", - {'content1':content1, 'content2':content2, - 'doc':doc, 'info':info, 'tab':tab, - 'include_text':include_text(request), - 'history':history}, - context_instance=RequestContext(request)); - -@decorator_from_middleware(GZipMiddleware) -def document_main_idrfc(request, name, tab): - # FIXME - r = re.compile("^rfc([1-9][0-9]*)$") - m = r.match(name) - if m: - return document_main_rfc(request, int(m.group(1)), tab) - id = get_object_or_404(InternetDraft, filename=name) - doc = IdWrapper(id) - - info = {} - info['has_pdf'] = (".pdf" in doc.file_types()) - 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(request.user, id) - info["can_edit_intended_std_level"] = can_edit_intended_std_level(request.user, id) - - (content1, content2) = _get_html( - str(name)+","+str(id.revision)+",html", - os.path.join(settings.INTERNET_DRAFT_PATH, name+"-"+id.revision+".txt")) - - versions = _get_versions(id) - history = _get_history(doc, versions) - - template = "idrfc/doc_tab_%s" % tab - if tab == "document": - template += "_id" - return render_to_response(template + ".html", - {'content1':content1, 'content2':content2, - 'doc':doc, 'info':info, 'tab':tab, - 'include_text':include_text(request), - 'stream_info': get_full_info_for_draft(id), - 'milestones': id.groupmilestone_set.filter(state="active"), - 'versions':versions, 'history':history}, - context_instance=RequestContext(request)); - -# doc is either IdWrapper or RfcWrapper -def _get_history(doc, versions): - results = [] - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - versions = [] # clear versions - event_holder = doc._draft if hasattr(doc, "_draft") else doc._rfcindex - for e in event_holder.docevent_set.all().select_related('by').order_by('-time', 'id'): - info = {} - if e.type == "new_revision": - filename = u"%s-%s" % (e.doc.name, e.newrevisiondocevent.rev) - e.desc = 'New version available: %s' % (filename, filename) - if int(e.newrevisiondocevent.rev) != 0: - e.desc += ' (diff from -%02d)' % (settings.RFCDIFF_PREFIX, filename, int(e.newrevisiondocevent.rev) - 1) - info["dontmolest"] = True - - multiset_ballot_text = "This was part of a ballot set with: " - if e.desc.startswith(multiset_ballot_text): - names = [ n.strip() for n in e.desc[len(multiset_ballot_text):].split(",") ] - e.desc = multiset_ballot_text + ", ".join(u'%s' % (urlreverse("doc_view", kwargs={'name': n }), n) for n in names) - info["dontmolest"] = True - - info['text'] = e.desc - info['by'] = e.by.plain_name() - info['textSnippet'] = truncatewords_html(format_textarea(fill(info['text'], 80)), 25) - info['snipped'] = info['textSnippet'][-3:] == "..." and e.type != "new_revision" - results.append({'comment':e, 'info':info, 'date':e.time, 'is_com':True}) - - prev_rev = "00" - # actually, we're already sorted and this ruins the sort from - # the ids which is sometimes needed, so the function should be - # rewritten to not rely on a resort - results.sort(key=lambda x: x['date']) - for o in results: - e = o["comment"] - if e.type == "new_revision": - e.version = e.newrevisiondocevent.rev - else: - e.version = prev_rev - prev_rev = e.version - else: - if doc.is_id_wrapper: - comments = DocumentComment.objects.filter(document=doc.tracker_id).exclude(rfc_flag=1) - else: - comments = DocumentComment.objects.filter(document=doc.rfc_number,rfc_flag=1) - if len(comments) > 0: - # also include rfc_flag=NULL, but only if at least one - # comment with rfc_flag=1 exists (usually NULL means same as 0) - comments = DocumentComment.objects.filter(document=doc.rfc_number).exclude(rfc_flag=0) - for comment in comments.order_by('-date','-time','-id').filter(public_flag=1).select_related('created_by'): - info = {} - info['text'] = comment.comment_text - info['by'] = comment.get_fullname() - info['textSnippet'] = truncatewords_html(format_textarea(fill(info['text'], 80)), 25) - info['snipped'] = info['textSnippet'][-3:] == "..." - results.append({'comment':comment, 'info':info, 'date':comment.datetime(), 'is_com':True}) - - if doc.is_id_wrapper and versions: - for v in versions: - if v['draft_name'] == doc.draft_name: - v = dict(v) # copy it, since we're modifying datetimes later - v['is_rev'] = True - results.insert(0, v) - if not settings.USE_DB_REDESIGN_PROXY_CLASSES and doc.is_id_wrapper and doc.draft_status == "Expired" and doc._draft.expiration_date: - results.append({'is_text':True, 'date':doc._draft.expiration_date, 'text':'Draft expired'}) - if not settings.USE_DB_REDESIGN_PROXY_CLASSES and doc.is_rfc_wrapper: - text = 'RFC Published' - if doc.draft_name: - try: - text = 'RFC Published (see %s for earlier history)' % (urlreverse('doc_view', args=[doc.draft_name]),doc.draft_name) - except NoReverseMatch: - pass - results.append({'is_text':True, 'date':doc.publication_date, 'text':text}) - - # convert plain dates to datetimes (required for sorting) - for x in results: - if not isinstance(x['date'], datetime.datetime): - if x['date']: - x['date'] = datetime.datetime.combine(x['date'], datetime.time(0,0,0)) - else: - x['date'] = datetime.datetime(1970,1,1) - - results.sort(key=lambda x: x['date']) - results.reverse() - return results - -# takes InternetDraft instance -def _get_versions(draft, include_replaced=True): - ov = [] - ov.append({"draft_name":draft.filename, "revision":draft.revision_display(), "date":draft.revision_date}) - if include_replaced: - draft_list = [draft]+list(draft.replaces_set.all()) - else: - draft_list = [draft] - - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - from ietf.doc.models import NewRevisionDocEvent - for e in NewRevisionDocEvent.objects.filter(type="new_revision", doc__in=draft_list).select_related('doc').order_by("-time", "-id"): - if not (e.doc.name == draft.name and e.rev == draft.rev): - ov.append(dict(draft_name=e.doc.name, revision=e.rev, date=e.time.date())) - - return ov - - for d in draft_list: - for v in DraftVersions.objects.filter(filename=d.filename).order_by('-revision'): - if (d.filename == draft.filename) and (draft.revision_display() == v.revision): - continue - ov.append({"draft_name":d.filename, "revision":v.revision, "date":v.revision_date}) - return ov +def ballot_for_popup(request, name): + doc = get_object_or_404(Document, docalias__name=name) + return HttpResponse(document_ballot_content(request, doc, ballot_id=None, editable=False)) def get_ballot(name): from ietf.doc.models import DocAlias alias = get_object_or_404(DocAlias, name=name) d = alias.document + from ietf.idtracker.models import InternetDraft + from ietf.idrfc.idrfc_wrapper import BallotWrapper, IdWrapper, RfcWrapper id = None bw = None dw = None @@ -873,15 +672,6 @@ def get_ballot(name): return (bw, dw, b, d) -def ballot_for_popup(request, name): - doc = get_object_or_404(Document, docalias__name=name) - return HttpResponse(document_ballot_content(request, doc, ballot_id=None, editable=False)) - -def ballot_html(request, name): - bw, dw, ballot, doc = get_ballot(name) - content = document_ballot_content(request, doc, ballot.pk, editable=True) - return HttpResponse(content) - def ballot_tsv(request, name): ballot, doc, b, d = get_ballot(name) return HttpResponse(render_to_string('idrfc/ballot.tsv', {'ballot':ballot}, RequestContext(request)), content_type="text/plain") diff --git a/ietf/templates/idrfc/doc_ballot.html b/ietf/templates/idrfc/doc_ballot.html deleted file mode 100644 index fcc3bbe8b..000000000 --- a/ietf/templates/idrfc/doc_ballot.html +++ /dev/null @@ -1,96 +0,0 @@ -{% comment %}{% endcomment %} -{% load ietf_filters %} - -
-{% if doc_ballot_edit_button and user|in_group:"Area_Director,Secretariat" %} -{% if user|in_group:"Area_Director" %} - -{% endif %} - -{% if doc.active_defer_event %} - -
Ballot deferred by {{ doc.active_defer_event.by }} on {{ doc.active_defer_event.time|date:"Y-m-d" }}.
-{% else %} - -{% endif %} - -{% endif %} - -{% if doc_ballot_edit_button and user|in_group:"Secretariat" %} - -{% endif %} - -

Discuss
-{% with bw.get_discuss as positions %}{% include "idrfc/doc_ballot_list.html" %}{% endwith %}

- -

Yes
-{% with bw.get_yes as positions %}{% include "idrfc/doc_ballot_list.html" %}{% endwith %}

- -

No Objection
-{% with bw.get_no_objection as positions %}{% include "idrfc/doc_ballot_list.html" %}{% endwith %}

- -

Abstain
-{% with bw.get_abstain as positions %}{% include "idrfc/doc_ballot_list.html" %}{% endwith %}

- -

Recuse
-{% with bw.get_recuse as positions %}{% include "idrfc/doc_ballot_list.html" %}{% endwith %}

- -

No Record
-{% with bw.get_no_record as positions %}{% include "idrfc/doc_ballot_list.html" %}{% endwith %}

- -
- -

Discusses and other comments

- -{% if bw.is_ballot_set %}

Other documents in this ballot set: {% for x in bw.ballot_set_other%}{{x|urlize_ietf_docs}}{% if not forloop.last %}, {% endif %}{% endfor %}

{% endif %} - -{% if dw.in_ietf_process and dw.ietf_process.has_active_iesg_ballot %} -

Summary: {{ dw.ietf_process.iesg_ballot_needed }}

-{% endif %} - -{% for pos in bw.get_texts|dictsort:"is_old_ad" %} -

{% if pos.is_old_ad %}[{%endif%}{{pos.ad_name|escape}}{% if pos.is_old_ad %}]{%endif%}

- -{% ifequal pos.position "Discuss" %} -

Discuss ({{pos.discuss_date}})

-
{{pos.discuss_text|wrap_text:80|escape }}
-{% endifequal %} - -{% if pos.comment_text %} -

Comment ({{pos.comment_date}})

-
{{pos.comment_text|wrap_text:80|escape }}
-{% endif %} -{% endfor %} -
diff --git a/ietf/templates/idrfc/doc_ballot_list.html b/ietf/templates/idrfc/doc_ballot_list.html deleted file mode 100644 index 5e2c1f342..000000000 --- a/ietf/templates/idrfc/doc_ballot_list.html +++ /dev/null @@ -1,7 +0,0 @@ -{% load ietf_filters %} -{% for p in positions %} -{% if p.is_old_ad %}[{%endif%}{{p.ad_name}}{% if p.is_old_ad %}]{%endif%}{% if p.has_text %} *{% endif %}
-{% if p.old_positions %}(was {{p.old_positions|join:", "}})
{%endif%} -{% empty %} -none -{% endfor %} diff --git a/ietf/templates/idrfc/doc_description.html b/ietf/templates/idrfc/doc_description.html deleted file mode 100644 index 83934e4af..000000000 --- a/ietf/templates/idrfc/doc_description.html +++ /dev/null @@ -1,6 +0,0 @@ -{{ doc.title }} -{% if info.is_rfc %} -({{doc.maturity_level}}, {{doc.publication_date|date:"Y"}}){% if doc.obsoleted_by %}; Obsoleted by {{doc.obsoleted_by}}{% endif %} -{% else %} -({{info.type}}; {{doc.publication_date|date:"Y"}}) -{% endif %} diff --git a/ietf/templates/idrfc/doc_diffs.html b/ietf/templates/idrfc/doc_diffs.html deleted file mode 100644 index 18a1608b2..000000000 --- a/ietf/templates/idrfc/doc_diffs.html +++ /dev/null @@ -1,68 +0,0 @@ -{% comment %} -Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -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. -{% endcomment %} - -
-

Diffs

- - - - - - - - -
- - -Format: - -
- - -
- -
diff --git a/ietf/templates/idrfc/doc_history.html b/ietf/templates/idrfc/doc_history.html deleted file mode 100644 index fb4ae80a6..000000000 --- a/ietf/templates/idrfc/doc_history.html +++ /dev/null @@ -1,80 +0,0 @@ -{% comment %} -Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -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. -{% endcomment %} - -{% load ietf_filters %} - - - -{% for c in history %} - - - -{% if c.is_rev %} - - - -{% endif %} - -{% if c.is_text %} - - - -{% endif %} - -{% if c.is_com %} - - - -{% endif %} - - -{% endfor %} - -
DateVersionByText
{{ c.date|date:"Y-m-d" }}{{ c.revision }}(System)New version available: {{c.draft_name}}-{{c.revision}} {% ifnotequal c.revision "00" %}(diff from -{{c.revision|add:"-1"|stringformat:"02d"}}){% endifnotequal %} (System){{ c.text|safe }}{{ c.comment.version }}{{ c.info.by|escape }}{% if c.comment.ballot %} -[Ballot {{ c.comment.get_ballot_display }}]
-{% endif %} -{% if c.info.snipped %} -
{{ c.info.textSnippet|safe }}
-[show all] - -{% else %} -{% if c.info.dontmolest %} -{{ c.info.text|safe }} -{% else %} -{{ c.info.text|safe|urlize|linebreaksbr|keep_spacing|sanitize_html|safe }} -{% endif %} -{% endif %} -
diff --git a/ietf/templates/idrfc/doc_main.html b/ietf/templates/idrfc/doc_main.html deleted file mode 100644 index 85da04715..000000000 --- a/ietf/templates/idrfc/doc_main.html +++ /dev/null @@ -1,126 +0,0 @@ -{% extends "base.html" %} -{% comment %} -Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -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. -{% endcomment %} - -{% load ietf_filters %} -{% block morecss %} -.metabox { width: 99%; margin-top:8px; padding:4px; margin-bottom:1em; } -#metatable { border: 0; border-spacing: 0; } -#metatable tr { vertical-align:top ;} -#metatable .post-rfc { font-style: italic; color: #004000; } -.comment_toggle { text-decoration: underline; color: blue; } -.comment_date { white-space: nowrap; } - -div.diffTool { padding: 8px 4px; margin: 8px 0;} -.diffTool label { float:left; width:50px; } - -.markup_draft pre {line-height: 1.2em; margin: 0; } -.m_hdr, .m_ftr { color: #808080; } -.m_ftr { border-bottom: 1px solid #a0a0a0; } -.m_h { font-family: arial; font-weight:bold;} - -a.editlink { - background-image: url("/images/pencil.png"); - background-size:10px; - background-position: right top; - background-attachment: scroll; - background-repeat: no-repeat; - padding-right: 12px; -} - -a.editlink:link {text-decoration:none; color:inherit;} -a.editlink:visited {text-decoration:none; color:inherit;} -a.editlink:hover {text-decoration:underline;} -a.editlink:active {text-decoration:underline;} - -{% endblock %} - -{% block pagehead %} -{% if doc.in_ietf_process %} - -{% endif %} - -{% comment %} -## See ticket #545 -- this is commented out because the versions -## that we currently serve is not sufficiently cachable, so the -## prefetched version is actually thrown away. -## Once the content becomes cacheable, these links should -## be reinserted into the document. -{% ifequal tab "document" %} -{% if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot %} - - -{% endif %} - -{% endifequal %} -{% endcomment %} -{% endblock %} - -{% block title %}{% include "idrfc/doc_title.html" %}{% endblock title %} - -{% block content %} -

{{ doc.title }}
{% include "idrfc/doc_title.html" %}

- -
- -
- -{% block tab_content %}{% endblock %} - -
-
- -{% endblock content %} - -{% block scripts %} -function toggleComment(n) { - var el = document.getElementById("commentF"+n); - var el2 = document.getElementById("commentS"+n); - var el3 = document.getElementById("commentT"+n); - if (el.style.display == 'none') { - el.style.display = 'block'; - el2.style.display = 'none'; - el3.innerHTML = ""; //[hide]"; - } else { - el.style.display = 'none'; - el2.style.display= 'block'; - el3.innerHTML = "[show all]"; - } -} -{% endblock scripts %} diff --git a/ietf/templates/idrfc/doc_tab_ballot.html b/ietf/templates/idrfc/doc_tab_ballot.html deleted file mode 100644 index 543fe1bd2..000000000 --- a/ietf/templates/idrfc/doc_tab_ballot.html +++ /dev/null @@ -1,47 +0,0 @@ -{% extends "idrfc/doc_main.html" %} -{% comment %} -Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -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. -{% endcomment %} - -{% load ietf_filters %} - -{% block tab_content %} -{% if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot %} -{% with 1 as doc_ballot_edit_button %} -{% with doc.ietf_process.iesg_ballot as ballot %} -{% include "idrfc/doc_ballot.html" %} -{% endwith %} -{% endwith %} -{% endif %} -{% endblock tab_content %} - diff --git a/ietf/templates/idrfc/doc_tab_document.html b/ietf/templates/idrfc/doc_tab_document.html deleted file mode 100644 index e4f91e1bd..000000000 --- a/ietf/templates/idrfc/doc_tab_document.html +++ /dev/null @@ -1,88 +0,0 @@ -{% extends "idrfc/doc_main.html" %} -{% comment %} -Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -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. -{% endcomment %} - -{% load ietf_filters %} - -{% block tab_content %} -
- -{% block doc_metatable %}{% endblock %} -
- -
-{% block doc_metalinks %}{% endblock %} -
- -{% block doc_metabuttons %} -{% if user|in_group:"Area_Director,Secretariat" %} -
-{% ifequal doc.draft_status "Expired" %} -{% if not doc.resurrect_requested_by %} -Request resurrect -{% endif %} -{% if user|in_group:"Secretariat" %} -Resurrect -{% endif %} -{% else %} -{% if stream_info.stream.name == 'ISE' or stream_info.stream.name == 'IRTF' %} -{% if user|in_group:"Secretariat" and not info.conflict_reviews %} -{% url conflict_review_start name=doc.draft_name as start_review_url %}{% if start_review_url %}Begin IETF Conflict Review {% if not doc.underlying_document.intended_std_level %}(note that intended status is not set){% endif %}{% endif %} -{% endif %} -{% else %} - {% if stream_info.stream.name == 'IETF'%}{%if not doc.in_ietf_process %} - {% url doc_edit_info name=doc.draft_name as doc_edit_url %}{% if doc_edit_url %}Begin IESG Processing{% endif %} - {% endif %}{% endif %} -{% endif %} -{% endifequal %} - -
-{% endif %}{# if user in group #} -{% endblock doc_metabuttons%} -
- -
-{% block doc_text1 %}{% endblock %} -
-{% endblock tab_content %} - -{% block content_end %} -
-{% if include_text %} -{% block doc_text2 %}{% endblock %} -{% else %} -[include full document text] -{% endif %} -
-{% endblock content_end %} diff --git a/ietf/templates/idrfc/doc_tab_document_id.html b/ietf/templates/idrfc/doc_tab_document_id.html deleted file mode 100644 index f0187b0e8..000000000 --- a/ietf/templates/idrfc/doc_tab_document_id.html +++ /dev/null @@ -1,237 +0,0 @@ -{% extends "idrfc/doc_tab_document.html" %} -{% comment %} -Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -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. -{% endcomment %} - -{% load ietf_filters ietf_streams %} - -{% block doc_metatable %} -{{ doc.draft_status }} {% ifnotequal doc.draft_status "RFC" %}Internet-Draft ({{ doc.submission|safe }}){% endifnotequal %} -{% ifequal doc.draft_status "Expired" %} -{% if doc.resurrect_requested_by %}(resurrect requested by {{ doc.resurrect_requested_by }}){% endif %} -{% endifequal %} - -Document Stream: -{% with user|in_group:"Area_Director,Secretariat" as add_link %} -{% if add_link %}{% endif %} -{% if stream_info.stream %}{{ stream_info.stream.name|default:"No stream defined" }}{% else %}No stream defined{% endif %} -{% if add_link %}{% endif %} -{% endwith %} - - -Last updated: {{ doc.publication_date|default:"(data missing)" }} - -{% with doc.replaces as r %}{% if r %}Replaces: {% filter urlize_ietf_docs %}{{ r|join:", "}}{% endfilter %}{% endif %}{% endwith %} -{% with doc.replaced_by as r %}{% if r %}Replaced by: {% filter urlize_ietf_docs %}{{ r|join:", "}}{% endfilter %}{% endif %}{% endwith %} - -{% with info.conflict_reviews as r %}{% if r %}IETF Conflict Review: {% filter urlize_ietf_docs %}{{ r|join:","}}{% endfilter %}{% endif %} {% endwith %} - -Intended RFC status: - -{{ doc.underlying_document.intended_std_level|default:"(None)" }} - - - -Other versions: -{% ifequal doc.draft_status "Active" %} - -plain text, -{% for ext in doc.file_types %} -{% ifnotequal ext ".txt" %} -{{ext|cut:"."}}, -{% endifnotequal %} -{% endfor %} -{% if not info.has_pdf %} -pdf, -{% endif %} -html - -{% else %} - -(expired, archived): -plain text, -{% for ext in doc.file_types %} -{% ifnotequal ext ".txt" %} -{{ext|cut:"."}}, -{% endifnotequal %} -{% endfor %} -{% if not info.has_pdf %} -pdf, -{% endif %} -html - - -{% endifequal %} - -
- -{% if stream_info.state %} -{% ifequal stream_info.stream.name "IETF" %} - - IETF State: - {{ stream_info.state.name }} ({{ stream_info.streamed.get_group }}) - {% if stream_info.tags %}
{% for tag in stream_info.tags %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endif %} - {% if milestones %}{% for m in milestones %}{{ m.due|date:"M Y" }}{% endfor %}{% endif %} - - -{% else %} - {% if stream_info.stream %} - - {{ stream_info.stream.name }} status: - - {{ stream_info.state.name }} {% if stream_info.streamed.get_group %}({{ stream_info.streamed.get_group }}) {% endif %} - {% if stream_info.tags %}
{% for tag in stream_info.tags %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endif %} - - - {% endif %} -{% endifequal %} -{% endif %} -Document shepherd:{{ stream_info.shepherd|default:"" }} - -{% if info.consensus %} -Consensus:{{ info.consensus }} -{% endif %} - -
- - -IESG State: -{% if doc.in_ietf_process and user|in_group:"Area_Director,Secretariat" %} - {{ doc.friendly_state|safe }} -{% else %} - {{ doc.friendly_state|safe }} -{% endif %} -{% if info.iana_review_state %}
IANA Review State: {{ info.iana_review_state.name|escape }}{% endif %} -{% if info.iana_action_state %}
IANA Action State: {{ info.iana_action_state.name|escape }}{% endif %} -{% if info.rfc_editor_state %}
RFC Editor State: {{ info.rfc_editor_state|escape }}{% endif %} -{% ifequal doc.draft_status "Expired" %} -{% if doc.resurrect_requested_by %}(resurrect requested by {{ doc.resurrect_requested_by }}){% endif %} -{% endifequal %} -{% with user|in_group:"Area_Director,Secretariat" as add_link %} -{% if add_link %}{% endif %} -{% if doc.underlying_document.telechat_date %}
On agenda of {{ doc.underlying_document.telechat_date }} IESG telechat {% if doc.underlying_document.returning_item %} (returning item){% endif %}{% else %}{%if add_link %}
Not on an upcoming telechat agenda{% endif %}{% endif %} -{% if add_link %}
{% endif %} -{% if doc.ietf_process.has_active_iesg_ballot %}
({{ doc.ietf_process.iesg_ballot_needed }}){%endif%} -{% endwith %} - -{# Submission:{{ doc.submission|safe }} #} -Responsible AD: -{% with user|in_group:"Area_Director,Secretariat" as add_link %} -{% if add_link %}{% endif %} -{% if doc.in_ietf_process %}{{ doc.ietf_process.ad_name|default:"(None)"|escape }}{%else%}(None){%endif%} -{% if add_link %}{% endif %} -{% endwith %} - -{% with user|in_group:"Area_Director,Secretariat" as add_link %} -{% if doc.in_ietf_process %}{% if doc.ietf_process.iesg_note or add_link %} -IESG Note: -{% if add_link %}{% endif %} -{{ doc.ietf_process.iesg_note|format_textarea|safe }} -{% if add_link %}{% endif %} -{% endif %}{% endif %} -{% endwith %} -Send notices to: -{% with user|in_group:"Area_Director,Secretariat" as add_link %} -{% if add_link %}{% endif %} -{{ doc.underlying_document.notify|default:"No addresses provided"}} -{% if add_link %}{% endif %} -{% endwith %} - - -
- - -{% endblock doc_metatable %} - -{% block doc_metalinks %} -{% edit_actions doc %} -
- Email Authors -| IPR Disclosures -| Dependencies to this draft -| Check nits -{% if doc.in_ietf_process %}| Comments feed{% endif %} -| Search Mailing Lists -{% if user|in_group:"Area_Director" %} -| Search Mailing Lists (ARO) -{% endif %} -
-{% if user|in_group:"Area_Director,Secretariat" %} -
-{% if doc.in_ietf_process %} - Last Call Text -| Ballot Text -| Announcement Text -{% endif %} -
-{% endif %} -{% endblock %} - -{% block doc_text1 %} -{% ifequal doc.draft_status "Active" %} -
-{{ content1|safe }} -
-{% else %} -

This Internet-Draft is no longer active. Unofficial copies of old Internet-Drafts can be found here:
-http://tools.ietf.org/id/{{doc.draft_name}}.

- -

Abstract:
{{ doc.abstract|escape }}

- -

Authors:
-{% for author in doc.authors.all %} - -{% if author.email %} -{{ author.person }} <{{author.email}}> -{% else %} -{% if author.person %} -{{ author.person }} -{% else %} -Missing author info #{{ author.person_id }} -{% endif %} -{% endif %}
- -{% endfor %}

- -

(Note: The e-mail addresses provided for the authors of this Internet-Draft may no longer be valid)

- -{% endifequal %} -{% endblock %}{# doc_text1 #} - -{% block doc_text2 %} -{% ifequal doc.draft_status "Active" %} -
-{{ content2|safe }} -
-{% endifequal %} -{% endblock %} {# doc_text2 #} diff --git a/ietf/templates/idrfc/doc_tab_document_rfc.html b/ietf/templates/idrfc/doc_tab_document_rfc.html deleted file mode 100644 index dab62087a..000000000 --- a/ietf/templates/idrfc/doc_tab_document_rfc.html +++ /dev/null @@ -1,110 +0,0 @@ -{% extends "idrfc/doc_tab_document.html" %} -{% comment %} -Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -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. -{% endcomment %} - -{% load ietf_filters %} - -{% block doc_metatable %} -Document type:RFC - {{ doc.maturity_level }} {% if doc.stream_name %}({{ doc.stream_name }}){% endif %} -{% if doc.obsoleted_by %}
Obsoleted by {{ doc.obsoleted_by|urlize_ietf_docs }}{%endif %} -{% if doc.updated_by %}
Updated by {{ doc.updated_by|urlize_ietf_docs }}{%endif %} -{% if doc.obsoletes %}
Obsoletes {{ doc.obsoletes|urlize_ietf_docs }}{%endif %} -{% if doc.updates %}
Updates {{ doc.updates|urlize_ietf_docs }}{%endif %} -{% if doc.also %}
Also Known As {{ doc.also|urlize_ietf_docs }}{%endif %} -{% if doc.draft_name %}
Was {{doc.draft_name}}{% endif %} -{% if doc.has_errata %}
Errata{% endif %} - -Published: {{ doc.publication_date|date:"Y-m"|default:"(data missing)" }} -{% if doc.in_ietf_process %} -* This information refers to IESG processing after the RFC was initially published -State: -{{ doc.friendly_state|safe }} (IESG: {{ doc.ietf_process.state}}) -{% if doc.ietf_process.telechat_date %}
On agenda of {{ doc.ietf_process.telechat_date }} IESG telechat {% if doc.ietf_process.telechat_returning_item %} (returning item){%endif%}{%endif%} - -Intended status:{% if doc.in_ietf_process %}{{ doc.ietf_process.intended_maturity_level|default:"-" }}{% else %}-{%endif%} -Responsible AD:{{ doc.ietf_process.ad_name|default:"-"|escape }} -{% if doc.ietf_process.iesg_note %}IESG Note:{{ doc.ietf_process.iesg_note|escape }}{% endif %} -{% if user|in_group:"Area_Director,Secretariat" %} -Send notices to:{{ doc.ietf_process.state_change_notice_to}} -{% endif %}{# if user|in_group:... #} - -{% endif %} -Other versions: -{% if info.has_txt or info.has_ps or info.has_pdf %} -{% if info.has_txt %} -plain text, -{% endif %} -{% if info.has_ps %} -ps, -{% endif %} -{% if info.has_pdf %} -pdf, -{% else %} -{% if info.has_txt %} -pdf, -{% endif %} -{% endif %} -{% if info.has_txt %} -html -{% endif %} -{% else %} -(not online) -{% endif %} - -{% endblock doc_metatable %} - -{% block doc_metalinks %} - IPR Disclosures -| Dependencies to this RFC -{% endblock %} - -{% block doc_text1 %} -{% if info.has_txt %} -
-{{ content1|safe }} -
-{% else %} -{% if info.has_pdf or info.has_ps %} -

This RFC is not available in plain text format.

-{% else %} -

This RFC is not currently available online.

-{% endif %} -{% endif %} -{% endblock %}{# doc_text1 #} - -{% block doc_text2 %} -
-{{ content2|safe }} -
-{% endblock %}{# doc_text2 #} diff --git a/ietf/templates/idrfc/doc_tab_history.html b/ietf/templates/idrfc/doc_tab_history.html deleted file mode 100644 index 11b45965d..000000000 --- a/ietf/templates/idrfc/doc_tab_history.html +++ /dev/null @@ -1,52 +0,0 @@ -{% extends "idrfc/doc_main.html" %} - - -{% load ietf_filters %} - -{% block tab_content %} -{% if not info.is_rfc %} -{% include "idrfc/doc_diffs.html" %} -{% endif %} -

Document history

-{% if user|in_group:"Area_Director,Secretariat,IANA,RFC Editor" and doc.in_ietf_process %} - -{% endif %} - -{% include "idrfc/doc_history.html" %} -{% endblock tab_content %} diff --git a/ietf/templates/idrfc/doc_tab_writeup.html b/ietf/templates/idrfc/doc_tab_writeup.html deleted file mode 100644 index f9ffb89d4..000000000 --- a/ietf/templates/idrfc/doc_tab_writeup.html +++ /dev/null @@ -1,73 +0,0 @@ -{% extends "idrfc/doc_main.html" %} -{% comment %} -Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -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. -{% endcomment %} - -{% load ietf_filters %} - -{% block tab_content %} ----- following is a DRAFT of message to be sent AFTER approval --- -{% if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot %} -{% if user|in_group:"Area_Director,Secretariat" %} -
-

- -Edit Announcement Text - -

-{% endif %} -{% endif %} -
-{{ doc.ietf_process.iesg_ballot.approval_text|escape|urlize }}
-
-{% if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot %} -{% if user|in_group:"Area_Director,Secretariat" %} -
- -
-

- -Edit Ballot Text - -

-{% endif %} -{% endif %} -
-{{ doc.ietf_process.iesg_ballot.ballot_writeup|escape|urlize }}
-
-{% if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot %} -{% if user|in_group:"Area_Director,Secretariat" %} -
-{% endif %} -{% endif %} -{% endblock tab_content %} diff --git a/ietf/templates/idrfc/doc_title.html b/ietf/templates/idrfc/doc_title.html deleted file mode 100644 index 7fc425c12..000000000 --- a/ietf/templates/idrfc/doc_title.html +++ /dev/null @@ -1,5 +0,0 @@ -{% if info.is_rfc %} -RFC {{ doc.rfc_number }} -{% else %} -{{ doc.draft_name_and_revision }} -{% endif %} From b881c64abf74f42c999ce5ef8a9fed8a8a0720d5 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 09:51:18 +0000 Subject: [PATCH 20/38] Fix bug in test of doc.note - Legacy-Id: 5291 --- ietf/idrfc/testsREDESIGN.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ietf/idrfc/testsREDESIGN.py b/ietf/idrfc/testsREDESIGN.py index 0cc597415..218927383 100644 --- a/ietf/idrfc/testsREDESIGN.py +++ b/ietf/idrfc/testsREDESIGN.py @@ -1339,13 +1339,11 @@ class IndividualInfoFormsTestCase(django.test.TestCase): q = PyQuery(r.content) self.assertEquals(len(q('form.edit-iesg-note')),1) - # No validation code to test - - # post - testing that the munge code exists in note.clean... - r = self.client.post(url,dict(note='ZpyQFGmA\nZpyQFGmA')) + # post + r = self.client.post(url,dict(note='ZpyQFGmA\r\nZpyQFGmA')) self.assertEquals(r.status_code,302) self.doc = Document.objects.get(name=self.docname) - self.assertEquals(self.doc.note,'ZpyQFGmA
ZpyQFGmA') + self.assertEquals(self.doc.note,'ZpyQFGmA\nZpyQFGmA') self.assertTrue('ZpyQFGmA' in self.doc.latest_event(DocEvent,type='added_comment').desc) def test_doc_change_ad(self): From 0c0a912941208f97a0817de88debd84868d93b8f Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 09:51:34 +0000 Subject: [PATCH 21/38] Remove obsolete tests.py file - Legacy-Id: 5292 --- ietf/idrfc/tests.py | 369 ---------------------------------------- ietf/idrfc/views_doc.py | 8 +- 2 files changed, 6 insertions(+), 371 deletions(-) delete mode 100644 ietf/idrfc/tests.py diff --git a/ietf/idrfc/tests.py b/ietf/idrfc/tests.py deleted file mode 100644 index a2d5d94f0..000000000 --- a/ietf/idrfc/tests.py +++ /dev/null @@ -1,369 +0,0 @@ -# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -# All rights reserved. Contact: Pasi Eronen -# -# 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. - -import unittest -import StringIO -import os, shutil -from datetime import date, timedelta - -import django.test -from django.core.urlresolvers import reverse as urlreverse -from django.conf import settings - -from pyquery import PyQuery - -from ietf.idrfc.models import * -from ietf.idtracker.models import * -from ietf.utils.test_utils import SimpleUrlTestCase, RealDatabaseTest, login_testing_unauthorized -from ietf.utils.mail import outbox - -from ietf.ietfworkflows.models import Stream -from django.contrib.auth.models import User - -# REMOVED ALL THE CLASS DEFINITIONS FROM THIS FILE -# AS A FIRST STEP TOWARDS TRANSITION CLEANUP. ALL -# OF WHAT WAS HERE IS REDEFINED BY THE INCLUDE -# BELOW - -TEST_RFC_INDEX = ''' - - - BCP0110 - - RFC4170 - - - - BCP0111 - - RFC4181 - RFC4841 - - - - FYI0038 - - RFC3098 - - - - RFC1938 - A One-Time Password System - - N. Haller - - - C. Metz - - - May - 1996 - - - ASCII - 44844 - 18 - - - OTP - authentication - S/KEY - -

This document describes a one-time password authentication system (OTP). [STANDARDS-TRACK]

- - RFC2289 - - PROPOSED STANDARD - PROPOSED STANDARD - Legacy -
- - RFC2289 - A One-Time Password System - - N. Haller - - - C. Metz - - - P. Nesser - - - M. Straw - - - February - 1998 - - - ASCII - 56495 - 25 - - - ONE-PASS - authentication - OTP - replay - attach - -

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]

- - RFC1938 - - - STD0061 - - STANDARD - DRAFT STANDARD - Legacy -
- - RFC3098 - How to Advertise Responsibly Using E-Mail and Newsgroups or - how NOT to $$$$$ MAKE ENEMIES FAST! $$$$$ - - T. Gavin - - - D. Eastlake 3rd - - - S. Hambridge - - - April - 2001 - - - ASCII - 64687 - 28 - - - internet - marketing - users - service - providers - isps - -

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.

- draft-ietf-run-adverts-02 - - FYI0038 - - INFORMATIONAL - INFORMATIONAL - Legacy -
- - RFC4170 - Tunneling Multiplexed Compressed RTP (TCRTP) - - B. Thompson - - - T. Koren - - - D. Wing - - - November - 2005 - - - ASCII - 48990 - 24 - - - real-time transport protocol - -

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.

- draft-ietf-avt-tcrtp-08 - - BCP0110 - - BEST CURRENT PRACTICE - BEST CURRENT PRACTICE - IETF - rai - avt -
- - RFC4181 - Guidelines for Authors and Reviewers of MIB Documents - - C. Heard - Editor - - - September - 2005 - - - ASCII - 102521 - 42 - - - standards-track specifications - management information base - review - -

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.

- draft-ietf-ops-mib-review-guidelines-04 - - RFC4841 - - - BCP0111 - - BEST CURRENT PRACTICE - BEST CURRENT PRACTICE - IETF - rtg - ospf - http://www.rfc-editor.org/errata_search.php?rfc=4181 -
- - RFC4841 - RFC 4181 Update to Recognize the IETF Trust - - C. Heard - Editor - - - March - 2007 - - - ASCII - 4414 - 3 - - - management information base - standards-track specifications - mib review - -

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.

- draft-heard-rfc4181-update-00 - - RFC4181 - - - BCP0111 - - BEST CURRENT PRACTICE - BEST CURRENT PRACTICE - IETF - NON WORKING GROUP -
- - STD0061 - A One-Time Password System - - RFC2289 - - -
-''' - -TEST_QUEUE = ''' -
- -draft-ietf-sipping-app-interaction-framework-05.txt -2005-10-17 -EDIT - -draft-ietf-sip-gruu -IN-QUEUE - -J. Rosenberg - -A Framework for Application Interaction in the Session Initiation Protocol (SIP) - -94672 -Session Initiation Proposal Investigation - -
-
- -draft-ietf-sip-gruu-15.txt -2007-10-15 -MISSREF - -draft-ietf-sip-outbound -NOT-RECEIVED - -J. Rosenberg - -Obtaining and Using Globally Routable User Agent (UA) URIs (GRUU) in the Session Initiation Protocol (SIP) - -95501 -Session Initiation Protocol - -
-
-
-
- -draft-thomson-beep-async-02.txt -2009-05-12 -EDIT -IANA -M. Thomson - -Asynchronous Channels for the Blocks Extensible Exchange Protocol (BEEP) - -17237 -IETF - NON WORKING GROUP - -
-
-
-
-
-
-
-
-''' - - -if settings.USE_DB_REDESIGN_PROXY_CLASSES: - from testsREDESIGN import * diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index ce5995f27..141980e9d 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -275,7 +275,10 @@ def document_main(request, name, rev=None): actions = [] if ((not doc.stream_id or doc.stream_id in ("ietf", "irtf")) and group.type_id == "individ" and - (Role.objects.filter(person__user=request.user, name__in=("chair", "delegate"), group__type__in=("wg",), group__state="active") + (request.user.is_authenticated() and + Role.objects.filter(person__user=request.user, name__in=("chair", "delegate"), + group__type__in=("wg",), + group__state="active") or has_role(request.user, "Secretariat"))): actions.append(("Adopt in Group", urlreverse('edit_adopt', kwargs=dict(name=doc.name)))) @@ -285,7 +288,8 @@ def document_main(request, name, rev=None): if doc.get_state_slug() == "expired" and has_role(request.user, ("Secretariat",)): actions.append(("Resurrect", urlreverse('doc_resurrect', kwargs=dict(name=doc.name)))) - if doc.get_state_slug() != "expired" and doc.stream_id in ("ise", "irtf") and has_role(request.user, ("Secretariat",)) and not conflict_reviews: + if (doc.get_state_slug() != "expired" and doc.stream_id in ("ise", "irtf") + and has_role(request.user, ("Secretariat",)) and not conflict_reviews): label = "Begin IETF Conflict Review" if not doc.intended_std_level: label += " (note that intended status is not set)" From 3e8de2a43f1fb1bd6f8fda3bbeb9efaeafdb364f Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 09:52:15 +0000 Subject: [PATCH 22/38] Rename REDESIGN tests.py file - Legacy-Id: 5293 --- ietf/idrfc/{testsREDESIGN.py => tests.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ietf/idrfc/{testsREDESIGN.py => tests.py} (100%) diff --git a/ietf/idrfc/testsREDESIGN.py b/ietf/idrfc/tests.py similarity index 100% rename from ietf/idrfc/testsREDESIGN.py rename to ietf/idrfc/tests.py From 1a3aa3b443cbfb0982e76d9b2e9c7751a94c501c Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 10:32:05 +0000 Subject: [PATCH 23/38] Refactor slightly to make views_doc.py independent of other idrfc code - Legacy-Id: 5294 --- ietf/doc/utils.py | 8 +++++++- ietf/idrfc/utils.py | 16 ---------------- ietf/idrfc/views_doc.py | 14 ++++++-------- ietf/idrfc/views_edit.py | 6 ++++-- ietf/templates/idrfc/document_draft.html | 4 ++-- 5 files changed, 19 insertions(+), 29 deletions(-) diff --git a/ietf/doc/utils.py b/ietf/doc/utils.py index 9e1966ac7..8ad4becb9 100644 --- a/ietf/doc/utils.py +++ b/ietf/doc/utils.py @@ -220,10 +220,16 @@ def add_state_change_event(doc, by, prev_state, new_state, timestamp=None): e.save() return e - def prettify_std_name(n): if re.match(r"(rfc|bcp|fyi|std)[0-9]{4}", n): return n[:3].upper() + " " + n[3:] else: return n +def nice_consensus(consensus): + mapping = { + None: "Unknown", + True: "Yes", + False: "No" + } + return mapping[consensus] diff --git a/ietf/idrfc/utils.py b/ietf/idrfc/utils.py index 4388bf893..e0fababef 100644 --- a/ietf/idrfc/utils.py +++ b/ietf/idrfc/utils.py @@ -177,19 +177,3 @@ 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(user, doc): - return user.is_authenticated() and ( - has_role(user, ["Secretariat", "Area Director"]) or is_authorized_in_doc_stream(user, doc)) - -def can_edit_consensus(user, doc): - return user.is_authenticated() and ( - has_role(user, ["Secretariat", "Area Director"]) or is_authorized_in_doc_stream(user, doc)) - -def nice_consensus(consensus): - mapping = { - None: "Unknown", - True: "Yes", - False: "No" - } - return mapping[consensus] - diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index 141980e9d..ea5fbbc55 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -43,7 +43,6 @@ from django.middleware.gzip import GZipMiddleware from django.core.urlresolvers import reverse as urlreverse, NoReverseMatch from django.conf import settings -from ietf.idrfc.utils import * from ietf.doc.models import * from ietf.doc.utils import * from ietf.utils.history import find_history_active_at @@ -140,10 +139,11 @@ def document_main(request, name, rev=None): can_edit = has_role(request.user, ("Area Director", "Secretariat")) stream_slugs = StreamName.objects.values_list("slug", flat=True) - can_change_stream = bool(can_edit or (request.user.is_authenticated() and - Role.objects.filter(name__in=("chair", "auth"), - group__acronym__in=stream_slugs, - person__user=request.user))) + can_change_stream = bool(can_edit or ( + request.user.is_authenticated() and + Role.objects.filter(name__in=("chair", "auth"), + group__acronym__in=stream_slugs, + person__user=request.user))) can_edit_iana_state = has_role(request.user, ("Secretariat", "IANA")) rfc_number = name[3:] if name.startswith("") else None @@ -313,8 +313,6 @@ def document_main(request, name, rev=None): can_change_stream=can_change_stream, can_edit_stream_info=can_edit_stream_info, can_edit_shepherd_writeup=can_edit_shepherd_writeup, - can_edit_intended_std_level=can_edit_intended_std_level(request.user, doc), - can_edit_consensus=can_edit_consensus(request.user, doc), can_edit_iana_state=can_edit_iana_state, rfc_number=rfc_number, @@ -644,7 +642,7 @@ def get_ballot(name): from ietf.doc.models import DocAlias alias = get_object_or_404(DocAlias, name=name) d = alias.document - from ietf.idtracker.models import InternetDraft + from ietf.idtracker.models import InternetDraft, BallotInfo from ietf.idrfc.idrfc_wrapper import BallotWrapper, IdWrapper, RfcWrapper id = None bw = None diff --git a/ietf/idrfc/views_edit.py b/ietf/idrfc/views_edit.py index 58601b020..306105e79 100644 --- a/ietf/idrfc/views_edit.py +++ b/ietf/idrfc/views_edit.py @@ -271,7 +271,8 @@ def change_intention(request, name): if doc.type_id != 'draft': raise Http404 - if not can_edit_intended_std_level(request.user, doc): + if not (has_role(request.user, ("Secretariat", "Area Director")) + or is_authorized_in_doc_stream(request.user, doc)): return HttpResponseForbidden("You do not have the necessary permissions to view this page") login = request.user.get_profile() @@ -902,7 +903,8 @@ def edit_consensus(request, name): doc = get_object_or_404(Document, type="draft", name=name) - if not can_edit_consensus(request.user, doc): + if not (has_role(request.user, ("Secretariat", "Area Director")) + or is_authorized_in_doc_stream(request.user, doc)): return HttpResponseForbidden("You do not have the necessary permissions to view this page") e = doc.latest_event(ConsensusDocEvent, type="changed_consensus") diff --git a/ietf/templates/idrfc/document_draft.html b/ietf/templates/idrfc/document_draft.html index d8224f7b6..878e71d2b 100644 --- a/ietf/templates/idrfc/document_draft.html +++ b/ietf/templates/idrfc/document_draft.html @@ -62,7 +62,7 @@ Intended RFC status: - + {{ doc.intended_std_level|default:"Unknown" }} @@ -110,7 +110,7 @@ Consensus: - + {{ consensus }} From accf6d4470db98508b81e4de3ebe6cbc3c5d77a6 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 13:17:00 +0000 Subject: [PATCH 24/38] Move idrfc/views_doc.py to doc/ with associated templates, replace the somewhat fragile simple URL tests for views_doc.py with ordinary unit tests. The new tests are still fairly basic but at least test more than the URL tests did. - Legacy-Id: 5295 --- ietf/doc/tests.py | 141 ++++++++++++++++++ ietf/{idrfc => doc}/views_doc.py | 26 ++-- ietf/idrfc/idrfc_wrapper.py | 2 +- ietf/idrfc/testurlREDESIGN.list | 59 -------- ietf/idrfc/urls.py | 3 +- .../{idrfc => doc}/document_ballot.html | 0 .../document_ballot_content.html | 0 .../{idrfc => doc}/document_charter.html | 2 +- .../document_conflict_review.html | 0 .../{idrfc => doc}/document_draft.html | 0 .../{idrfc => doc}/document_history.html | 0 .../{idrfc => doc}/document_top.html | 0 .../{idrfc => doc}/document_writeup.html | 0 ietf/templates/wginfo/wg_charter.html | 2 +- ietf/utils/test_data.py | 15 +- 15 files changed, 166 insertions(+), 84 deletions(-) rename ietf/{idrfc => doc}/views_doc.py (96%) rename ietf/templates/{idrfc => doc}/document_ballot.html (100%) rename ietf/templates/{idrfc => doc}/document_ballot_content.html (100%) rename ietf/templates/{idrfc => doc}/document_charter.html (97%) rename ietf/templates/{idrfc => doc}/document_conflict_review.html (100%) rename ietf/templates/{idrfc => doc}/document_draft.html (100%) rename ietf/templates/{idrfc => doc}/document_history.html (100%) rename ietf/templates/{idrfc => doc}/document_top.html (100%) rename ietf/templates/{idrfc => doc}/document_writeup.html (100%) diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py index 6ffbe2985..a4a7cff17 100644 --- a/ietf/doc/tests.py +++ b/ietf/doc/tests.py @@ -1,3 +1,144 @@ +import os, shutil, datetime +import django.test +from django.core.urlresolvers import reverse as urlreverse +from django.conf import settings +from pyquery import PyQuery + +from ietf.utils.mail import outbox +from ietf.utils.test_utils import login_testing_unauthorized +from ietf.utils.test_data import make_test_data + +from ietf.doc.models import * +from ietf.name.models import * +from ietf.group.models import * +from ietf.person.models import * +from ietf.meeting.models import Meeting, MeetingTypeName +from ietf.iesg.models import TelechatDate + +# extra tests from ietf.doc.tests_conflict_review import * + + +class DocTestCase(django.test.TestCase): + fixtures = ['names'] + + def test_document_draft(self): + draft = make_test_data() + + # these tests aren't testing all attributes yet, feel free to + # expand them + + + # active draft + draft.set_state(State.objects.get(type="draft", slug="active")) + + r = self.client.get(urlreverse("doc_view", kwargs=dict(name=draft.name))) + self.assertEqual(r.status_code, 200) + self.assertTrue("Active Internet-Draft" in r.content) + + # expired draft + draft.set_state(State.objects.get(type="draft", slug="expired")) + + r = self.client.get(urlreverse("doc_view", kwargs=dict(name=draft.name))) + self.assertEqual(r.status_code, 200) + self.assertTrue("Expired Internet-Draft" in r.content) + + # replaced draft + draft.set_state(State.objects.get(type="draft", slug="repl")) + + replacement = Document.objects.create( + name="draft-ietf-replacement", + time=datetime.datetime.now(), + type_id="draft", + title="Replacement Draft", + stream_id=draft.stream_id, group_id=draft.group_id, abstract=draft.stream, rev=draft.rev, + pages=draft.pages, intended_std_level_id=draft.intended_std_level_id, + shepherd_id=draft.shepherd_id, ad_id=draft.ad_id, expires=draft.expires, + notify=draft.notify, note=draft.note) + DocAlias.objects.create(name=replacement.name, document=replacement) + rel = RelatedDocument.objects.create(source=replacement, + target=draft.docalias_set.get(name__startswith="draft"), + relationship_id="replaces") + + r = self.client.get(urlreverse("doc_view", kwargs=dict(name=draft.name))) + self.assertEqual(r.status_code, 200) + self.assertTrue("Replaced Internet-Draft" in r.content) + self.assertTrue(replacement.name in r.content) + rel.delete() + + # draft published as RFC + draft.set_state(State.objects.get(type="draft", slug="rfc")) + draft.std_level_id = "bcp" + draft.save() + + DocEvent.objects.create(doc=draft, type="published_rfc", by=Person.objects.get(name="(System)")) + + rfc_alias = DocAlias.objects.create(name="rfc123456", document=draft) + bcp_alias = DocAlias.objects.create(name="bcp123456", document=draft) + + r = self.client.get(urlreverse("doc_view", kwargs=dict(name=draft.name))) + self.assertEqual(r.status_code, 302) + r = self.client.get(urlreverse("doc_view", kwargs=dict(name=bcp_alias.name))) + self.assertEqual(r.status_code, 302) + + r = self.client.get(urlreverse("doc_view", kwargs=dict(name=rfc_alias.name))) + self.assertEqual(r.status_code, 200) + self.assertTrue("RFC 123456" in r.content) + self.assertTrue(draft.name in r.content) + + # naked RFC + rfc = Document.objects.create( + name="rfc1234567", + type_id="draft", + title="RFC without a Draft", + stream_id="ise", + group=Group.objects.get(type="individ"), + std_level_id="ps") + DocAlias.objects.create(name=rfc.name, document=rfc) + r = self.client.get(urlreverse("doc_view", kwargs=dict(name=rfc.name))) + self.assertEqual(r.status_code, 200) + self.assertTrue("RFC 1234567" in r.content) + + # unknown draft + r = self.client.get(urlreverse("doc_view", kwargs=dict(name="draft-xyz123"))) + self.assertEqual(r.status_code, 404) + + def test_document_charter(self): + make_test_data() + + r = self.client.get(urlreverse("doc_view", kwargs=dict(name="charter-ietf-mars"))) + self.assertEqual(r.status_code, 200) + + def test_document_conflict_review(self): + make_test_data() + + r = self.client.get(urlreverse("doc_view", kwargs=dict(name='conflict-review-imaginary-irtf-submission'))) + self.assertEqual(r.status_code, 200) + + def test_document_ballot(self): + doc = make_test_data() + ballot = doc.active_ballot() + + BallotPositionDocEvent.objects.create( + doc=doc, + type="changed_ballot_position", + pos_id="yes", + comment="Looks fine to me", + comment_time=datetime.datetime.now(), + ad=Person.objects.get(user__username="ad"), + by=Person.objects.get(name="(System)")) + + r = self.client.get(urlreverse("ietf.doc.views_doc.document_ballot", kwargs=dict(name=doc.name))) + self.assertEqual(r.status_code, 200) + + # test popup too while we're at it + r = self.client.get(urlreverse("ietf.doc.views_doc.ballot_for_popup", kwargs=dict(name=doc.name))) + self.assertEqual(r.status_code, 200) + + def test_document_json(self): + doc = make_test_data() + + r = self.client.get(urlreverse("ietf.doc.views_doc.document_json", kwargs=dict(name=doc.name))) + self.assertEqual(r.status_code, 200) diff --git a/ietf/idrfc/views_doc.py b/ietf/doc/views_doc.py similarity index 96% rename from ietf/idrfc/views_doc.py rename to ietf/doc/views_doc.py index ea5fbbc55..20db8e6ad 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -50,27 +50,27 @@ from ietf.ietfauth.utils import * 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)) + tabs.append(("Document", "document", urlreverse("doc_view", kwargs=dict(name=name)), True)) ballot = doc.latest_event(BallotDocEvent, type="created_ballot") if doc.type_id in ("draft","conflrev"): # if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot: - tabs.append(("IESG Evaluation Record", "ballot", urlreverse("ietf.idrfc.views_doc.document_ballot", kwargs=dict(name=name)), ballot)) + tabs.append(("IESG Evaluation Record", "ballot", urlreverse("doc_ballot", kwargs=dict(name=name)), ballot)) elif doc.type_id == "charter": - tabs.append(("IESG Review", "ballot", urlreverse("ietf.idrfc.views_doc.document_ballot", kwargs=dict(name=name)), ballot)) + tabs.append(("IESG Review", "ballot", urlreverse("doc_ballot", kwargs=dict(name=name)), ballot)) # FIXME: if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot: if doc.type_id != "conflrev": - tabs.append(("IESG Writeups", "writeup", urlreverse("ietf.idrfc.views_doc.document_writeup", kwargs=dict(name=name)), True)) + tabs.append(("IESG Writeups", "writeup", urlreverse("doc_writeup", kwargs=dict(name=name)), True)) - tabs.append(("History", "history", urlreverse("ietf.idrfc.views_doc.document_history", kwargs=dict(name=name)), True)) + tabs.append(("History", "history", urlreverse("doc_history", kwargs=dict(name=name)), True)) if name.startswith("rfc"): name = "RFC %s" % name[3:] else: name += "-" + doc.rev - return render_to_string("idrfc/document_top.html", + return render_to_string("doc/document_top.html", dict(doc=doc, tabs=tabs, selected=tab, @@ -298,7 +298,7 @@ def document_main(request, name, rev=None): if doc.get_state_slug() != "expired" and doc.stream_id in ("ietf",) and can_edit and not iesg_state: actions.append(("Begin IESG Processing", urlreverse('doc_edit_info', kwargs=dict(name=doc.name)) + "?new=1")) - return render_to_response("idrfc/document_draft.html", + return render_to_response("doc/document_draft.html", dict(doc=doc, group=group, top=top, @@ -368,7 +368,7 @@ def document_main(request, name, rev=None): if chartering and not snapshot: milestones = doc.group.groupmilestone_set.filter(state="charter") - return render_to_response("idrfc/document_charter.html", + return render_to_response("doc/document_charter.html", dict(doc=doc, top=top, chartering=chartering, @@ -397,7 +397,7 @@ def document_main(request, name, rev=None): if doc.get_state_slug() in ("iesgeval"): ballot_summary = needed_ballot_positions(doc, doc.active_ballot().active_ad_positions().values()) - return render_to_response("idrfc/document_conflict_review.html", + return render_to_response("doc/document_conflict_review.html", dict(doc=doc, top=top, content=content, @@ -450,7 +450,7 @@ def document_history(request, name): augment_events_with_revision(doc, events) add_links_in_new_revision_events(doc, events, diff_revisions) - return render_to_response("idrfc/document_history.html", + return render_to_response("doc/document_history.html", dict(doc=doc, top=top, diff_revisions=diff_revisions, @@ -510,7 +510,7 @@ def document_writeup(request, name): if not sections: raise Http404() - return render_to_response("idrfc/document_writeup.html", + return render_to_response("doc/document_writeup.html", dict(doc=doc, top=top, sections=sections, @@ -562,7 +562,7 @@ def document_ballot_content(request, doc, ballot_id, editable=True): if not ballot_open: editable = False - return render_to_string("idrfc/document_ballot_content.html", + return render_to_string("doc/document_ballot_content.html", dict(doc=doc, ballot=ballot, position_groups=position_groups, @@ -581,7 +581,7 @@ def document_ballot(request, name, ballot_id=None): c = document_ballot_content(request, doc, ballot_id, editable=True) - return render_to_response("idrfc/document_ballot.html", + return render_to_response("doc/document_ballot.html", dict(doc=doc, top=top, ballot_content=c, diff --git a/ietf/idrfc/idrfc_wrapper.py b/ietf/idrfc/idrfc_wrapper.py index b9e1c7dd3..8ac5f53fa 100644 --- a/ietf/idrfc/idrfc_wrapper.py +++ b/ietf/idrfc/idrfc_wrapper.py @@ -395,7 +395,7 @@ class RfcWrapper: @models.permalink def get_absolute_url(self): - return ('ietf.idrfc.views_doc.document_main', ['rfc%s' % (str(self.rfc_number))]) + return ('ietf.doc.views_doc.document_main', ['rfc%s' % (str(self.rfc_number))]) def displayname_with_link(self): return 'RFC %d' % (self.get_absolute_url(), self.rfc_number) diff --git a/ietf/idrfc/testurlREDESIGN.list b/ietf/idrfc/testurlREDESIGN.list index 5b9b6a930..b44c197d0 100644 --- a/ietf/idrfc/testurlREDESIGN.list +++ b/ietf/idrfc/testurlREDESIGN.list @@ -3,71 +3,12 @@ 200,heavy /doc/all/ 200,heavy /doc/active/ -# draft that's now RFC -200 /doc/draft-ietf-avt-rtp-atrac-family/ -200 /doc/draft-ietf-avt-rtp-atrac-family/doc.json -200 /doc/draft-ietf-avt-rtp-atrac-family/ballot.json -200 /doc/draft-ietf-avt-rtp-atrac-family/ballotpopup/ - -# replaced draft, never went to IESG -200 /doc/draft-eronen-mobike-mopo/ -404 /doc/draft-eronen-mobike-mopo/ballot.json -404 /doc/draft-eronen-mobike-mopo/ballotpopup/ - -# expired draft -200 /doc/draft-eronen-eap-sim-aka-80211/ - -# Normal RFC -200 /doc/rfc4739/ -200 /doc/rfc4739/doc.json -200 /doc/rfc4739/ballot.json # has ballot from I-D -200 /doc/rfc4739/ballotpopup/ - -# RFC that's evaluated in IESG -200 /doc/rfc3852/ -200 /doc/rfc3852/doc.json -200 /doc/rfc3852/ballot.json -200 /doc/rfc3852/ballotpopup/ - -# old RFC -200 /doc/rfc822/ -200 /doc/rfc822/doc.json - -# ballot sets -200 /doc/rfc3550/ballot.json -200 /doc/rfc3550/ballotpopup/ -200 /doc/rfc3551/ballot.json -200 /doc/rfc3551/ballotpopup/ -200 /doc/draft-irtf-dtnrg-ltp/ballot.json -200 /doc/draft-irtf-dtnrg-ltp/ballotpopup/ - -# file formats -200 /doc/rfc9/ # PDF only -200 /doc/rfc2490/ # TXT+PDF+PS -200 /doc/rfc500/ # not online - -404 /doc/draft-no-such-draft/ -404 /doc/rfc4637/ - -200 /doc/rfc2444/doc.json # foreignkey problem with Django 1.x - # current AD -- needs to be updated at some point 200 /doc/ad/robert.sparks/ # former AD 200 /doc/ad/sam.hartman/ 404 /doc/ad/no.body/ -# ballot exists, but it's not issued -404 /doc/draft-ietf-aaa-diameter-api/ballot.json -404 /doc/draft-ietf-aaa-diameter-api/ballotpopup/ -# ballot does not exist -404 /doc/draft-zeilenga-cldap/ballot.json -404 /doc/draft-zeilenga-cldap/ballotpopup/ -# comment with created_by=999 -200 /doc/draft-ietf-l3vpn-2547bis-mcast-bgp/ -# comment with created_by=0 (and no idinternal entry) -200 /doc/draft-ietf-proto-wgdocument-states/ - 200 /doc/search/ 200 /doc/search/?rfcs=on&name=snmp 200 /doc/search/?rfcs=on&name=nfs&by=ad&ad=112773 diff --git a/ietf/idrfc/urls.py b/ietf/idrfc/urls.py index 2a0477be8..f42399aca 100644 --- a/ietf/idrfc/urls.py +++ b/ietf/idrfc/urls.py @@ -31,8 +31,9 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from django.conf.urls.defaults import patterns, url, include -from ietf.idrfc import views_doc, views_search, views_edit, views_ballot, views +from ietf.idrfc import views_search, views_edit, views_ballot, views from ietf.doc.models import State +from ietf.doc import views_doc urlpatterns = patterns('', (r'^/?$', views_search.search_main), diff --git a/ietf/templates/idrfc/document_ballot.html b/ietf/templates/doc/document_ballot.html similarity index 100% rename from ietf/templates/idrfc/document_ballot.html rename to ietf/templates/doc/document_ballot.html diff --git a/ietf/templates/idrfc/document_ballot_content.html b/ietf/templates/doc/document_ballot_content.html similarity index 100% rename from ietf/templates/idrfc/document_ballot_content.html rename to ietf/templates/doc/document_ballot_content.html diff --git a/ietf/templates/idrfc/document_charter.html b/ietf/templates/doc/document_charter.html similarity index 97% rename from ietf/templates/idrfc/document_charter.html rename to ietf/templates/doc/document_charter.html index 627f41d07..df88883b8 100644 --- a/ietf/templates/idrfc/document_charter.html +++ b/ietf/templates/doc/document_charter.html @@ -25,7 +25,7 @@ {% if snapshot %}Snapshot of{% endif %} {% if doc.get_state_slug != "approved" %}Proposed{% endif %} Charter for "{{ group.name }}" - ({{ group.acronym }}) {{ group.type.name }} + ({{ group.acronym }}) {{ group.type.name }}
diff --git a/ietf/templates/idrfc/document_conflict_review.html b/ietf/templates/doc/document_conflict_review.html similarity index 100% rename from ietf/templates/idrfc/document_conflict_review.html rename to ietf/templates/doc/document_conflict_review.html diff --git a/ietf/templates/idrfc/document_draft.html b/ietf/templates/doc/document_draft.html similarity index 100% rename from ietf/templates/idrfc/document_draft.html rename to ietf/templates/doc/document_draft.html diff --git a/ietf/templates/idrfc/document_history.html b/ietf/templates/doc/document_history.html similarity index 100% rename from ietf/templates/idrfc/document_history.html rename to ietf/templates/doc/document_history.html diff --git a/ietf/templates/idrfc/document_top.html b/ietf/templates/doc/document_top.html similarity index 100% rename from ietf/templates/idrfc/document_top.html rename to ietf/templates/doc/document_top.html diff --git a/ietf/templates/idrfc/document_writeup.html b/ietf/templates/doc/document_writeup.html similarity index 100% rename from ietf/templates/idrfc/document_writeup.html rename to ietf/templates/doc/document_writeup.html diff --git a/ietf/templates/wginfo/wg_charter.html b/ietf/templates/wginfo/wg_charter.html index 3ffe76e99..592d153f1 100644 --- a/ietf/templates/wginfo/wg_charter.html +++ b/ietf/templates/wginfo/wg_charter.html @@ -77,7 +77,7 @@ is occasionally incorrect. {% else %} none {% if user|has_role:"Area Director,Secretariat" %} - - Submit Charter + - Submit Charter {% endif %} {% endif %} diff --git a/ietf/utils/test_data.py b/ietf/utils/test_data.py index 619aa642b..4ab4d8553 100644 --- a/ietf/utils/test_data.py +++ b/ietf/utils/test_data.py @@ -391,18 +391,17 @@ def make_test_data(): ) # an independent submission before review - doc = Document.objects.create(name='draft-imaginary-independent-submission',type_id='draft') - DocAlias.objects.create( name='draft-imaginary-independent-submission',document=doc) + doc = Document.objects.create(name='draft-imaginary-independent-submission', type_id='draft') + DocAlias.objects.create(name=doc.name, document=doc) # an irtf submission mid review - doc = Document.objects.create( name='draft-imaginary-irtf-submission',type_id='draft') - docalias = DocAlias.objects.create(name='draft-imaginary-irtf-submission',document=doc) + doc = Document.objects.create(name='draft-imaginary-irtf-submission', type_id='draft') + docalias = DocAlias.objects.create(name=doc.name, document=doc) doc.stream = StreamName.objects.get(slug='irtf') doc.save() - crdoc = Document.objects.create(name='conflict-review-imaginary-irtf-submission',type_id='conflrev',rev='00',notify="fsm@ietf.org") - DocAlias.objects.create( name='conflict-review-imaginary-irtf-submission',document=crdoc) - crdoc.set_state(State.objects.get(name='Needs Shepherd',type__slug='conflrev')) - crdoc.save() + crdoc = Document.objects.create(name='conflict-review-imaginary-irtf-submission', type_id='conflrev', rev='00', notify="fsm@ietf.org") + DocAlias.objects.create(name=crdoc.name, document=crdoc) + crdoc.set_state(State.objects.get(name='Needs Shepherd', type__slug='conflrev')) crdoc.relateddocument_set.create(target=docalias,relationship_id='conflrev') return draft From 7998371ace270eb41ee288fefdaeeef426929390 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 13:47:31 +0000 Subject: [PATCH 25/38] Make sure RFC's (and BCP/STD/FYI) are stored as RFC123 instead of RFC0123 in the alias table with a new migration and a change to the RFC Editor sync, this in turn makes /doc/std1/ do the right thing - Legacy-Id: 5296 --- ietf/doc/migrations/0012_fix_rfc_aliases.py | 369 ++++++++++++++++++++ ietf/doc/utils.py | 2 +- ietf/sync/rfceditor.py | 26 +- 3 files changed, 388 insertions(+), 9 deletions(-) create mode 100644 ietf/doc/migrations/0012_fix_rfc_aliases.py diff --git a/ietf/doc/migrations/0012_fix_rfc_aliases.py b/ietf/doc/migrations/0012_fix_rfc_aliases.py new file mode 100644 index 000000000..14a128bf2 --- /dev/null +++ b/ietf/doc/migrations/0012_fix_rfc_aliases.py @@ -0,0 +1,369 @@ +# 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): + for alias in orm.DocAlias.objects.filter(models.Q(name__startswith="bcp") + | models.Q(name__startswith="std") + | models.Q(name__startswith="fyi")): + # remove left-padded zeros + alias.name = alias.name[:3] + str(int(alias.name[3:])) + alias.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.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'}), + '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'] diff --git a/ietf/doc/utils.py b/ietf/doc/utils.py index 8ad4becb9..62837313e 100644 --- a/ietf/doc/utils.py +++ b/ietf/doc/utils.py @@ -221,7 +221,7 @@ def add_state_change_event(doc, by, prev_state, new_state, timestamp=None): return e def prettify_std_name(n): - if re.match(r"(rfc|bcp|fyi|std)[0-9]{4}", n): + if re.match(r"(rfc|bcp|fyi|std)[0-9]+", n): return n[:3].upper() + " " + n[3:] else: return n diff --git a/ietf/sync/rfceditor.py b/ietf/sync/rfceditor.py index c725f4726..156d32c3e 100644 --- a/ietf/sync/rfceditor.py +++ b/ietf/sync/rfceditor.py @@ -194,11 +194,21 @@ def fetch_index_xml(url): return urllib2.urlopen(url) def parse_index(response): - def getDocList(parentNode, tagName): + def normalize_std_name(std_name): + # remove zero padding + prefix = std_name[:3] + if prefix in ("RFC", "FYI", "BCP", "STD"): + try: + return prefix + str(int(std_name[3:])) + except ValueError: + pass + return std_name + + def extract_doc_list(parentNode, tagName): l = [] for u in parentNode.getElementsByTagName(tagName): for d in u.getElementsByTagName("doc-id"): - l.append(d.firstChild.data) + l.append(normalize_std_name(d.firstChild.data)) return l also_list = {} @@ -208,8 +218,8 @@ def parse_index(response): 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") + bcpid = normalize_std_name(get_child_text(node, "doc-id")) + doclist = extract_doc_list(node, "is-also") for docid in doclist: if docid in also_list: also_list[docid].append(bcpid) @@ -234,10 +244,10 @@ def parse_index(response): 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") + updates = extract_doc_list(node, "updates") + updated_by = extract_doc_list(node, "updated-by") + obsoletes = extract_doc_list(node, "obsoletes") + obsoleted_by = extract_doc_list(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): From d868594dd1a273aa8ef4acc97aa0bbf666368e3f Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 13:49:25 +0000 Subject: [PATCH 26/38] Now /doc/std1/ works, we can actually do a local link in urlize_ietf_docs rather than linking to the tools.ietf.org server - Legacy-Id: 5297 --- ietf/idtracker/templatetags/ietf_filters.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ietf/idtracker/templatetags/ietf_filters.py b/ietf/idtracker/templatetags/ietf_filters.py index 0a8ae5a4d..d76f6318f 100644 --- a/ietf/idtracker/templatetags/ietf_filters.py +++ b/ietf/idtracker/templatetags/ietf_filters.py @@ -221,14 +221,12 @@ def urlize_ietf_docs(string, autoescape=None): """ if autoescape and not isinstance(string, SafeData): string = escape(string) - print string string = re.sub("(?)(RFC ?)0{0,3}(\d+)", "\\1\\2", string) - string = re.sub("(?)(BCP ?)0{0,3}(\d+)", "\\1\\2", string) - string = re.sub("(?)(STD ?)0{0,3}(\d+)", "\\1\\2", string) - string = re.sub("(?)(FYI ?)0{0,3}(\d+)", "\\1\\2", string) + string = re.sub("(?)(BCP ?)0{0,3}(\d+)", "\\1\\2", string) + string = re.sub("(?)(STD ?)0{0,3}(\d+)", "\\1\\2", string) + string = re.sub("(?)(FYI ?)0{0,3}(\d+)", "\\1\\2", string) string = re.sub("(?)(draft-[-0-9a-zA-Z._+]+)", "\\1", string) string = re.sub("(?)(conflict-review-[-0-9a-zA-Z._+]+)", "\\1", string) - print string return mark_safe(string) urlize_ietf_docs.is_safe = True urlize_ietf_docs.needs_autoescape = True From a8887c6ea08fdde670b734aa68ebb20657419a57 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 13:52:17 +0000 Subject: [PATCH 27/38] Remove obsolete testurl.list file - Legacy-Id: 5298 --- ietf/idrfc/testurl.list | 88 ----------------------------------------- 1 file changed, 88 deletions(-) delete mode 100644 ietf/idrfc/testurl.list diff --git a/ietf/idrfc/testurl.list b/ietf/idrfc/testurl.list deleted file mode 100644 index 60bf3e81f..000000000 --- a/ietf/idrfc/testurl.list +++ /dev/null @@ -1,88 +0,0 @@ -200 / -200 /doc/ -200,heavy /doc/all/ -200,heavy /doc/active/ - -# draft that's now RFC -200 /doc/draft-ietf-avt-rtp-atrac-family/ -200 /doc/draft-ietf-avt-rtp-atrac-family/doc.json -200 /doc/draft-ietf-avt-rtp-atrac-family/ballot.json -200 /doc/draft-ietf-avt-rtp-atrac-family/_ballot.data - -# replaced draft, never went to IESG -200 /doc/draft-eronen-mobike-mopo/ -404 /doc/draft-eronen-mobike-mopo/ballot.json -404 /doc/draft-eronen-mobike-mopo/_ballot.data - -# expired draft -200 /doc/draft-eronen-eap-sim-aka-80211/ - -# Normal RFC -200 /doc/rfc4739/ -200 /doc/rfc4739/doc.json -404 /doc/rfc4739/ballot.json -404 /doc/rfc4739/_ballot.data - -# RFC that's evaluated in IESG -200 /doc/rfc3852/ -200 /doc/rfc3852/doc.json -200 /doc/rfc3852/ballot.json -200 /doc/rfc3852/_ballot.data - -# old RFC -200 /doc/rfc822/ -200 /doc/rfc822/doc.json - -# ballot sets -200 /doc/rfc3550/ballot.json -200 /doc/rfc3550/_ballot.data -200 /doc/rfc3551/ballot.json -200 /doc/rfc3551/_ballot.data -200 /doc/draft-irtf-dtnrg-ltp/ballot.json -200 /doc/draft-irtf-dtnrg-ltp/_ballot.data - -# file formats -200 /doc/rfc9/ # PDF only -200 /doc/rfc2490/ # TXT+PDF+PS -200 /doc/rfc500/ # not online - -404 /doc/draft-no-such-draft/ -404 /doc/rfc4637/ - -200 /doc/rfc2444/doc.json # foreignkey problem with Django 1.x - -# current AD -- needs to be updated at some point -200 /doc/ad/robert.sparks/ -# former AD -200 /doc/ad/sam.hartman/ -404 /doc/ad/no.body/ - -# ballot exists, but it's not issued -404 /doc/draft-ietf-aaa-diameter-api/ballot.json -404 /doc/draft-ietf-aaa-diameter-api/_ballot.data -# ballot does not exist -404 /doc/draft-zeilenga-cldap/ballot.json -404 /doc/draft-zeilenga-cldap/_ballot.data -# comment with created_by=999 -200 /doc/draft-ietf-l3vpn-2547bis-mcast-bgp/ -# comment with created_by=0 (and no idinternal entry) -200 /doc/draft-ietf-proto-wgdocument-states/ - -200 /doc/search/ -200 /doc/search/?rfcs=on&name=snmp -200 /doc/search/?rfcs=on&name=nfs&by=ad&ad=53 -200 /doc/search/?activeDrafts=on&name=sipping -200 /doc/search/?oldDrafts=on&name=tls -200 /doc/search/?activeDrafts=on&oldDrafts=on&ad=53&by=ad -200 /doc/search/?activeDrafts=on&state=20&by=state -200 /doc/search/?activeDrafts=on&oldDrafts=on&subState=5&by=state -200 /doc/search/?activeDrafts=on&oldDrafts=on&rfcs=on&ad=53&name=nfs&by=ad -200 /doc/search/?rfcs=on&group=tls&by=group -200 /doc/search/?activeDrafts=on&group=tls&by=group -200 /doc/search/?activeDrafts=on&oldDrafts=on&rfcs=on&author=eronen&by=author -200 /doc/search/?activeDrafts=on&oldDrafts=on&rfcs=on&area=934&name=ldap&by=area -200 /doc/search/?activeDrafts=on&name=asdfsadfsdfasdf -200 /doc/search/?activeDrafts=on&name=%EF%BD%8C #non-ASCII - -# Test case for missing publication date -200 /doc/search/?oldDrafts=on&name=ppvpn From 9bcc4a9f3dc1dfd829cd063ece60c6988957f75c Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 13:54:33 +0000 Subject: [PATCH 28/38] Remove ballot.tsv view and comment out the ballot.json view in urls.py - Legacy-Id: 5299 --- ietf/doc/views_doc.py | 75 ++++++++++++++++----------------- ietf/idrfc/urls.py | 3 +- ietf/templates/idrfc/ballot.tsv | 2 - 3 files changed, 37 insertions(+), 43 deletions(-) delete mode 100644 ietf/templates/idrfc/ballot.tsv diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py index 20db8e6ad..ec5688675 100644 --- a/ietf/doc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -638,47 +638,44 @@ def ballot_for_popup(request, name): doc = get_object_or_404(Document, docalias__name=name) return HttpResponse(document_ballot_content(request, doc, ballot_id=None, editable=False)) -def get_ballot(name): - from ietf.doc.models import DocAlias - alias = get_object_or_404(DocAlias, name=name) - d = alias.document - from ietf.idtracker.models import InternetDraft, BallotInfo - from ietf.idrfc.idrfc_wrapper import BallotWrapper, IdWrapper, RfcWrapper - id = None - bw = None - dw = None - if (d.type_id=='draft'): - id = get_object_or_404(InternetDraft, name=d.name) - try: - if not id.ballot.ballot_issued: - raise Http404 - except BallotInfo.DoesNotExist: - raise Http404 - - bw = BallotWrapper(id) # XXX Fixme: Eliminate this as we go forward - # Python caches ~100 regex'es -- explicitly compiling it inside a method - # (where you then throw away the compiled version!) doesn't make sense at - # all. - if re.search("^rfc([1-9][0-9]*)$", name): - id.viewing_as_rfc = True - dw = RfcWrapper(id) - else: - dw = IdWrapper(id) - # XXX Fixme: Eliminate 'dw' as we go forward - - try: - b = d.latest_event(BallotDocEvent, type="created_ballot") - except BallotDocEvent.DoesNotExist: - raise Http404 - - return (bw, dw, b, d) - - -def ballot_tsv(request, name): - ballot, doc, b, d = get_ballot(name) - return HttpResponse(render_to_string('idrfc/ballot.tsv', {'ballot':ballot}, RequestContext(request)), content_type="text/plain") def ballot_json(request, name): + # REDESIGN: this view needs to be deleted or updated + def get_ballot(name): + from ietf.doc.models import DocAlias + alias = get_object_or_404(DocAlias, name=name) + d = alias.document + from ietf.idtracker.models import InternetDraft, BallotInfo + from ietf.idrfc.idrfc_wrapper import BallotWrapper, IdWrapper, RfcWrapper + id = None + bw = None + dw = None + if (d.type_id=='draft'): + id = get_object_or_404(InternetDraft, name=d.name) + try: + if not id.ballot.ballot_issued: + raise Http404 + except BallotInfo.DoesNotExist: + raise Http404 + + bw = BallotWrapper(id) # XXX Fixme: Eliminate this as we go forward + # Python caches ~100 regex'es -- explicitly compiling it inside a method + # (where you then throw away the compiled version!) doesn't make sense at + # all. + if re.search("^rfc([1-9][0-9]*)$", name): + id.viewing_as_rfc = True + dw = RfcWrapper(id) + else: + dw = IdWrapper(id) + # XXX Fixme: Eliminate 'dw' as we go forward + + try: + b = d.latest_event(BallotDocEvent, type="created_ballot") + except BallotDocEvent.DoesNotExist: + raise Http404 + + return (bw, dw, b, d) + ballot, doc, b, d = get_ballot(name) response = HttpResponse(mimetype='text/plain') response.write(json.dumps(ballot.dict(), indent=2)) diff --git a/ietf/idrfc/urls.py b/ietf/idrfc/urls.py index f42399aca..e7123fa1a 100644 --- a/ietf/idrfc/urls.py +++ b/ietf/idrfc/urls.py @@ -52,8 +52,7 @@ urlpatterns = patterns('', url(r'^(?P[A-Za-z0-9._+-]+)/ballot/$', views_doc.document_ballot, name="doc_ballot"), (r'^(?P[A-Za-z0-9._+-]+)/doc.json$', views_doc.document_json), (r'^(?P[A-Za-z0-9._+-]+)/ballotpopup/$', views_doc.ballot_for_popup), - (r'^(?P[A-Za-z0-9._+-]+)/ballot.tsv$', views_doc.ballot_tsv), - (r'^(?P[A-Za-z0-9._+-]+)/ballot.json$', views_doc.ballot_json), + #(r'^(?P[A-Za-z0-9._+-]+)/ballot.json$', views_doc.ballot_json), # legacy view url(r'^(?P[A-Za-z0-9._+-]+)/edit/state/$', views_edit.change_state, name='doc_change_state'), # IESG state url(r'^(?P[A-Za-z0-9._+-]+)/edit/state/(?Piana-action|iana-review)/$', views_edit.change_iana_state, name='doc_change_iana_state'), diff --git a/ietf/templates/idrfc/ballot.tsv b/ietf/templates/idrfc/ballot.tsv deleted file mode 100644 index 2db5be005..000000000 --- a/ietf/templates/idrfc/ballot.tsv +++ /dev/null @@ -1,2 +0,0 @@ -#Discuss Yes No Objection Abstain Recuse No Record -{% for p in ballot.get_discuss %}{{p.ad_name}}, {% endfor %} {% for p in ballot.get_yes %}{{p.ad_name}}, {% endfor %} {% for p in ballot.get_no_objection %}{{p.ad_name}}, {% endfor %} {% for p in ballot.get_abstain %}{{p.ad_name}}, {% endfor %} {% for p in ballot.get_recuse %}{{p.ad_name}}, {% endfor %} {% for p in ballot.get_no_record %}{{p.ad_name}}, {% endfor %} From f607fb7880891d0157c7352e170dbd58ee5e85db Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 15:25:57 +0000 Subject: [PATCH 29/38] Fix test bug - Legacy-Id: 5300 --- ietf/sync/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/sync/tests.py b/ietf/sync/tests.py index c422a20c1..99fe33d20 100644 --- a/ietf/sync/tests.py +++ b/ietf/sync/tests.py @@ -262,7 +262,7 @@ class RFCSyncTestCase(django.test.TestCase): 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(set(also), set(["BCP1", "FYI1", "STD1"])) self.assertEqual(draft, doc.name) self.assertEqual(wg, doc.group.acronym) self.assertEqual(has_errata, True) From 0dc47254a07ba7979a6343f66aad83688df37496 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 18 Jan 2013 16:09:24 +0000 Subject: [PATCH 30/38] ## Lines starting with '## ' will be removed from the log message. ## File(s) to commit recursively: ## ietf/sync/tests.py Fix another test bug, bcp0001 has become bcp1 - Legacy-Id: 5301 --- ietf/sync/tests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ietf/sync/tests.py b/ietf/sync/tests.py index 99fe33d20..b614742e8 100644 --- a/ietf/sync/tests.py +++ b/ietf/sync/tests.py @@ -281,9 +281,9 @@ class RFCSyncTestCase(django.test.TestCase): 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(DocAlias.objects.filter(name="bcp1", document=doc)) + self.assertTrue(DocAlias.objects.filter(name="fyi1", document=doc)) + self.assertTrue(DocAlias.objects.filter(name="std1", 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.") From e59224cd1c0ba8fe417210bcdecbafb7903b88cc Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Mon, 21 Jan 2013 10:29:15 +0000 Subject: [PATCH 31/38] Fix history text formatter: sanitize HTML before adding linebreaks and non-breaking spaces, this cuts the time to render a history page with long comments in half - Legacy-Id: 5310 --- ietf/idtracker/templatetags/ietf_filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/idtracker/templatetags/ietf_filters.py b/ietf/idtracker/templatetags/ietf_filters.py index d76f6318f..38d2323c1 100644 --- a/ietf/idtracker/templatetags/ietf_filters.py +++ b/ietf/idtracker/templatetags/ietf_filters.py @@ -466,7 +466,7 @@ def format_history_text(text): if text.startswith("This was part of a ballot set with:"): full = urlize_ietf_docs(full) - full = mark_safe(sanitize_html(keep_spacing(linebreaksbr(urlize(full))))) + full = mark_safe(keep_spacing(linebreaksbr(urlize(sanitize_html(full))))) snippet = truncate_html_words(full, 25) if snippet != full: return mark_safe(u'
%s[show all]
' % (snippet, full)) From db2c2a418cccf94c2fcd9f4cbd9d6b263d0d3445 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Mon, 21 Jan 2013 10:33:12 +0000 Subject: [PATCH 32/38] Add a test crawler that walks through the crawlable part of the site, reporting errors and slow pages - Legacy-Id: 5311 --- ietf/bin/test-crawl | 91 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100755 ietf/bin/test-crawl diff --git a/ietf/bin/test-crawl b/ietf/bin/test-crawl new file mode 100755 index 000000000..395ca1eb7 --- /dev/null +++ b/ietf/bin/test-crawl @@ -0,0 +1,91 @@ +#!/usr/bin/env python + +import os, sys, re, datetime, optparse, traceback +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) + +import django.test +from django.conf import settings + +# prevent memory from leaking when settings.DEBUG=True +from django.db import connection +class DontSaveQueries(object): + def append(self, x): + pass +connection.queries = DontSaveQueries() + +MAX_URL_LENGTH = 500 +SLOW_THRESHOLD = 1.0 + +def strip_url(url): + if url.startswith("http://testserver"): + url = url[len("http://testserver"):] + return url + +def extract_html_urls(content): + for m in re.finditer(r'', content): + url = strip_url(m.group(1)) + if len(url) > MAX_URL_LENGTH: + continue # avoid infinite GET parameter appendages + + if not url.startswith("/"): + continue + + yield url + + +visited = set() +blacklist = set() +urls = set(["/doc/all/"]) + +client = django.test.Client() + +while urls: + url = urls.pop() + + visited.add(url) + + try: + timestamp = datetime.datetime.now() + r = client.get(url) + elapsed = datetime.datetime.now() - timestamp + except KeyboardInterrupt: + print "was fetching", url + sys.exit(1) + except: + print "FAIL", url + print "=============" + traceback.print_exc() + print "=============" + else: + tags = [] + + if r.status_code in (301, 302): + u = strip_url(r["Location"]) + if u not in visited and u not in urls: + urls.add(u) + + elif r.status_code == 200: + ctype = r["Content-Type"] + if ";" in ctype: + ctype = ctype[:ctype.index(";")] + + if ctype == "text/html": + for u in extract_html_urls(r.content): + if u not in visited and u not in urls: + urls.add(u) + else: + tags.append("FAIL") + + if elapsed.total_seconds() > SLOW_THRESHOLD: + tags.append("SLOW") + + print r.status_code, "%.3fs" % elapsed.total_seconds(), url, " ".join(tags) + From ab6a7f85c05622a748072c29d0875176f976f203 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Mon, 21 Jan 2013 11:54:56 +0000 Subject: [PATCH 33/38] Get rid of initial "No record" positions when showing old positions, it's just noise - Legacy-Id: 5312 --- ietf/doc/models.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ietf/doc/models.py b/ietf/doc/models.py index 5e43d06d6..1a4cc6f9c 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -594,7 +594,13 @@ class BallotDocEvent(DocEvent): if e.pos != prev: latest.old_positions.append(e.pos) - + + # get rid of trailling "No record" positions, some old ballots + # have plenty of these + for p in positions: + while p.old_positions and p.old_positions[-1].slug == "norecord": + p.old_positions.pop() + # add any missing ADs through fake No Record events if self.doc.active_ballot() == self: norecord = BallotPositionName.objects.get(slug="norecord") From 06f4ed4cf3d593530ad9abed61844bc807e68fd4 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Mon, 21 Jan 2013 12:27:26 +0000 Subject: [PATCH 34/38] Add a .select_related() to the document main tab to reduce the number of DB queries, unfortunately it seems it doesn't really help with Django 1.2.x due to a bug (Document inherits from DocumentInfo which makes things a bit more complicated) - Legacy-Id: 5313 --- ietf/doc/views_doc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py index ec5688675..49cc295cd 100644 --- a/ietf/doc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -79,7 +79,7 @@ def render_document_top(request, doc, tab, name): @decorator_from_middleware(GZipMiddleware) def document_main(request, name, rev=None): - doc = get_object_or_404(Document, docalias__name=name) + doc = get_object_or_404(Document.objects.select_related(), docalias__name=name) # take care of possible redirections aliases = DocAlias.objects.filter(document=doc).values_list("name", flat=True) From 4b312de4646625d30b39dbe78af3271306724496 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Mon, 21 Jan 2013 14:01:33 +0000 Subject: [PATCH 35/38] Introduce a simple cache in doc.get_state so repeated reads don't cause a DB query - Legacy-Id: 5314 --- ietf/doc/models.py | 16 +++++++++++----- ietf/sync/tests.py | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/ietf/doc/models.py b/ietf/doc/models.py index 1a4cc6f9c..0fbd44d1d 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -100,20 +100,26 @@ class DocumentInfo(models.Model): self.states.remove(*others) if state not in already_set: self.states.add(state) + self.state_cache = None # invalidate cache def unset_state(self, state_type): """Unset state of type so no state of that type is any longer set.""" self.states.remove(*self.states.filter(type=state_type)) + self.state_cache = None # invalidate cache def get_state(self, state_type=None): - """Get state of type, or default state for document type if not specified.""" + """Get state of type, or default state for document type if + not specified. Uses a local cache to speed multiple state + reads up.""" if state_type == None: state_type = self.type_id - try: - return self.states.get(type=state_type) - except State.DoesNotExist: - return None + if not hasattr(self, "state_cache") or self.state_cache == None: + self.state_cache = {} + for s in self.states.all().select_related(): + self.state_cache[s.type_id] = s + + return self.state_cache.get(state_type, None) def get_state_slug(self, state_type=None): """Get state of type, or default if not specified, returning diff --git a/ietf/sync/tests.py b/ietf/sync/tests.py index b614742e8..73cf2172e 100644 --- a/ietf/sync/tests.py +++ b/ietf/sync/tests.py @@ -436,6 +436,7 @@ class RFCEditorUndoTestCase(django.test.TestCase): self.assertEquals(DeletedEvent.objects.count(), deleted_before + 1) # delete e1 + draft.state_cache = None r = self.client.post(url, dict(event=e1.id)) self.assertEquals(draft.get_state("draft-rfceditor"), None) From 833437aa8dfb08fec775a7f2a429b0b30fb8162c Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Mon, 25 Feb 2013 11:47:33 +0000 Subject: [PATCH 36/38] Remove dead code - Legacy-Id: 5463 --- ietf/idrfc/views_search.py | 535 +++++++++++-------------------------- 1 file changed, 160 insertions(+), 375 deletions(-) diff --git a/ietf/idrfc/views_search.py b/ietf/idrfc/views_search.py index de2e8b789..335e3d1a0 100644 --- a/ietf/idrfc/views_search.py +++ b/ietf/idrfc/views_search.py @@ -43,6 +43,10 @@ from ietf.idrfc.idrfc_wrapper import IdWrapper,RfcWrapper,IdRfcWrapper from ietf.utils import normalize_draftname from django.conf import settings +from ietf.doc.models import * +from ietf.person.models import * +from ietf.group.models import * + class SearchForm(forms.Form): name = forms.CharField(required=False) rfcs = forms.BooleanField(required=False,initial=True) @@ -53,15 +57,27 @@ class SearchForm(forms.Form): by = forms.ChoiceField(choices=[(x,x) for x in ('author','group','area','ad','state')], required=False, initial='wg', label='Foobar') author = forms.CharField(required=False) group = forms.CharField(required=False) - area = forms.ModelChoiceField(Area.active_areas(), empty_label="any area", required=False) + area = forms.ModelChoiceField(Group.objects.filter(type="area", state="active").order_by('name'), empty_label="any area", required=False) ad = forms.ChoiceField(choices=(), required=False) - state = forms.ModelChoiceField(IDState.objects.all(), empty_label="any state", required=False) + state = forms.ModelChoiceField(State.objects.filter(type="draft-iesg"), empty_label="any state", required=False) subState = forms.ChoiceField(choices=(), required=False) def __init__(self, *args, **kwargs): super(SearchForm, self).__init__(*args, **kwargs) - self.fields['ad'].choices = [('', 'any AD')] + [(ad.id, "%s %s" % (ad.first_name, ad.last_name)) for ad in IESGLogin.objects.filter(user_level=1).order_by('last_name')] + [('-99', '------------------')] + [(ad.id, "%s %s" % (ad.first_name, ad.last_name)) for ad in IESGLogin.objects.filter(user_level=2).order_by('last_name')] - self.fields['subState'].choices = [('', 'any substate'), ('0', 'no substate')] + [(state.sub_state_id, state.sub_state) for state in IDSubState.objects.all()] + responsible = Document.objects.values_list('ad', flat=True).distinct() + active_ads = list(Person.objects.filter(role__name="ad", + role__group__type="area", + role__group__state="active").distinct()) + inactive_ads = list(((Person.objects.filter(pk__in=responsible) | Person.objects.filter(role__name="pre-ad", + role__group__type="area", + role__group__state="active")).distinct()) + .exclude(pk__in=[x.pk for x in active_ads])) + extract_last_name = lambda x: x.name_parts()[3] + active_ads.sort(key=extract_last_name) + inactive_ads.sort(key=extract_last_name) + + self.fields['ad'].choices = c = [('', 'any AD')] + [(ad.pk, ad.plain_name()) for ad in active_ads] + [('', '------------------')] + [(ad.pk, ad.name) for ad in inactive_ads] + self.fields['subState'].choices = [('', 'any substate'), ('0', 'no substate')] + [(n.slug, n.name) for n in DocTagName.objects.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))] def clean_name(self): value = self.cleaned_data.get('name','') return normalize_draftname(value) @@ -72,9 +88,9 @@ class SearchForm(forms.Form): q['by'] = None else: for k in ('author','group','area','ad'): - if (q['by'] == k) and not q[k]: + if (q['by'] == k) and (k not in q or not q[k]): q['by'] = None - if (q['by'] == 'state') and not (q['state'] or q['subState']): + if (q['by'] == 'state') and (not 'state' in q or not 'subState' in q or not (q['state'] or q['subState'])): q['by'] = None # Reset other fields for k in ('author','group','area','ad'): @@ -87,7 +103,7 @@ class SearchForm(forms.Form): q['state'] = "" q['subState'] = "" return q - + def search_query(query_original, sort_by=None): query = dict(query_original.items()) drafts = query['activeDrafts'] or query['oldDrafts'] @@ -96,6 +112,7 @@ def search_query(query_original, sort_by=None): # Non-ASCII strings don't match anything; this check # is currently needed to avoid complaints from MySQL. + # FIXME: this should be fixed with MySQL if it's still a problem? for k in ['name','author','group']: try: tmp = str(query.get(k, '')) @@ -106,388 +123,156 @@ def search_query(query_original, sort_by=None): idresults = [] rfcresults = [] MAX = 500 - maxReached = False - prefix = "" - q_objs = [] - if query['by'] in ('ad','state'): - prefix = "draft__" - if query['name']: - q_objs.append(Q(**{prefix+"filename__icontains":query['name']})|Q(**{prefix+"title__icontains":query['name']})) + docs = InternetDraft.objects.all() - if query['by'] == 'author': - q_objs.append(Q(**{prefix+"authors__person__last_name__icontains":query['author']})) - elif query['by'] == 'group': - q_objs.append(Q(**{prefix+"group__acronym":query['group']})) - elif query['by'] == 'area': - q_objs.append(Q(**{prefix+"group__ietfwg__areagroup__area":query['area']})) - elif query['by'] == 'ad': - q_objs.append(Q(job_owner=query['ad'])) - elif query['by'] == 'state': - if query['state']: - q_objs.append(Q(cur_state=query['state'])) - if query['subState']: - q_objs.append(Q(cur_sub_state=query['subState'])) - if (not query['rfcs']) and query['activeDrafts'] and (not query['oldDrafts']): - q_objs.append(Q(**{prefix+"status":1})) - elif query['rfcs'] and query['activeDrafts'] and (not query['oldDrafts']): - q_objs.append(Q(**{prefix+"status":1})|Q(**{prefix+"status":3})) - elif query['rfcs'] and (not drafts): - q_objs.append(Q(**{prefix+"status":3})) - if prefix: - q_objs.append(Q(rfc_flag=0)) - matches = IDInternal.objects.filter(*q_objs) - else: - matches = InternetDraft.objects.filter(*q_objs) - if not query['activeDrafts']: - matches = matches.exclude(Q(**{prefix+"status":1})) - if not query['rfcs']: - matches = matches.exclude(Q(**{prefix+"status":3})) - if prefix: - matches = [id.draft for id in matches[:MAX]] - else: - matches = matches[:MAX] - if len(matches) == MAX: - maxReached = True - for id in matches: - if id.status.status == 'RFC': - rfcresults.append([id.rfc_number, id, None, None]) + # name + if query["name"]: + docs = docs.filter(Q(docalias__name__icontains=query["name"]) | + Q(title__icontains=query["name"])).distinct() + + # rfc/active/old check buttons + allowed_states = [] + if query["rfcs"]: + allowed_states.append("rfc") + if query["activeDrafts"]: + allowed_states.append("active") + if query["oldDrafts"]: + allowed_states.extend(['repl', 'expired', 'auth-rm', 'ietf-rm']) + + docs = docs.filter(states__type="draft", states__slug__in=allowed_states) + + # radio choices + by = query["by"] + if by == "author": + # FIXME: this is full name, not last name as hinted in the HTML + docs = docs.filter(authors__person__name__icontains=query["author"]) + elif by == "group": + docs = docs.filter(group__acronym=query["group"]) + elif by == "area": + docs = docs.filter(Q(group__type="wg", group__parent=query["area"]) | + Q(group=query["area"])).distinct() + elif by == "ad": + docs = docs.filter(ad=query["ad"]) + elif by == "state": + if query["state"]: + docs = docs.filter(states=query["state"]) + if query["subState"]: + docs = docs.filter(tags=query["subState"]) + + # evaluate and fill in values with aggregate queries to avoid + # too many individual queries + results = list(docs.select_related("states", "ad", "ad__person", "std_level", "intended_std_level", "group", "stream")[:MAX]) + + rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=[r.pk for r in results]).values_list("document_id", "name")) + # canonical name + for r in results: + if r.pk in rfc_aliases: + # lambda weirdness works around lambda binding in local for loop scope + r.canonical_name = (lambda x: lambda: x)(rfc_aliases[r.pk]) else: - idresults.append([id]) + r.canonical_name = (lambda x: lambda: x)(r.name) - # Next, search RFCs - if query['rfcs']: - q_objs = [] - searchRfcIndex = True - if query['name']: - r = re.compile("^\s*(?:RFC)?\s*(\d+)\s*$", re.IGNORECASE) - m = r.match(query['name']) - if m: - q_objs.append(Q(rfc_number__contains=m.group(1))|Q(title__icontains=query['name'])) + result_map = dict((r.pk, r) for r in results) + + # events + event_types = ("published_rfc", + "changed_ballot_position", + "started_iesg_process", + "new_revision") + for d in rfc_aliases.keys(): + for e in event_types: + setattr(result_map[d], e, None) + + for e in DocEvent.objects.filter(doc__in=rfc_aliases.keys(), type__in=event_types).order_by('-time'): + r = result_map[e.doc_id] + if not getattr(r, e.type): + # sets e.g. r.published_date = e for use in proxy wrapper + setattr(r, e.type, e) + + # obsoleted/updated by + for d in rfc_aliases: + r = result_map[d] + r.obsoleted_by_list = [] + r.updated_by_list = [] + + xed_by = RelatedDocument.objects.filter(target__name__in=rfc_aliases.values(), relationship__in=("obs", "updates")).select_related('target__document_id') + rel_rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=[rel.source_id for rel in xed_by]).values_list('document_id', 'name')) + for rel in xed_by: + r = result_map[rel.target.document_id] + if rel.relationship_id == "obs": + attr = "obsoleted_by_list" + else: + attr = "updated_by_list" + + getattr(r, attr).append(int(rel_rfc_aliases[rel.source_id][3:])) + + + # sort + def sort_key(d): + res = [] + + canonical = d.canonical_name() + if canonical.startswith('rfc'): + rfc_num = int(canonical[3:]) + else: + rfc_num = None + + if rfc_num != None: + res.append(2) + elif d.get_state_slug() == "active": + res.append(1) + else: + res.append(3) + + if sort_by == "title": + res.append(d.title) + elif sort_by == "date": + res.append(str(d.revision_date or datetime.date(1990, 1, 1))) + elif sort_by == "status": + if rfc_num != None: + res.append(rfc_num) else: - q_objs.append(Q(title__icontains=query['name'])) - if query['by'] == 'author': - q_objs.append(Q(authors__icontains=query['author'])) - elif query['by'] == 'group': - # We prefer searching RfcIndex, but it doesn't have group info - searchRfcIndex = False - q_objs.append(Q(group_acronym=query['group'])) - elif query['by'] == 'area': - # Ditto for area - searchRfcIndex = False - q_objs.append(Q(area_acronym=query['area'])) - elif query['by'] == 'ad': - numbers = IDInternal.objects.filter(rfc_flag=1,job_owner=query['ad']).values_list('draft_id',flat=True) - q_objs.append(Q(rfc_number__in=numbers)) - elif query['by'] == 'state': - numbers_q = [Q(rfc_flag=1)] - if query['state']: - numbers_q.append(Q(cur_state=query['state'])) - if query['subState']: - numbers_q.append(Q(cur_state=query['subState'])) - numbers = IDInternal.objects.filter(*numbers_q).values_list('draft_id',flat=True) - q_objs.append(Q(rfc_number__in=numbers)) - - if searchRfcIndex: - matches = RfcIndex.objects.filter(*q_objs)[:MAX] - else: - matches = Rfc.objects.filter(*q_objs)[:MAX] - if len(matches) == MAX: - maxReached = True - for rfc in matches: - found = False - for r2 in rfcresults: - if r2[0] == rfc.rfc_number: - if searchRfcIndex: - r2[3] = rfc - else: - r2[2] = rfc - found = True - if not found: - if searchRfcIndex: - rfcresults.append([rfc.rfc_number, None, None, rfc]) + res.append(d.get_state().order) + elif sort_by == "ipr": + res.append(d.name) + elif sort_by == "ad": + if rfc_num != None: + res.append(rfc_num) + elif d.get_state_slug() == "active": + if d.get_state("draft-iesg"): + res.append(d.get_state("draft-iesg").order) else: - rfcresults.append([rfc.rfc_number, None, rfc, None]) - - # Find missing InternetDraft objects - for r in rfcresults: - if not r[1]: - ids = InternetDraft.objects.filter(rfc_number=r[0]) - if len(ids) >= 1: - r[1] = ids[0] - if not r[1] and r[3] and r[3].draft: - ids = InternetDraft.objects.filter(filename=r[3].draft) - if len(ids) >= 1: - r[1] = ids[0] - - # Finally, find missing RFC objects - for r in rfcresults: - if not r[2]: - rfcs = Rfc.objects.filter(rfc_number=r[0]) - if len(rfcs) >= 1: - r[2] = rfcs[0] - if not r[3]: - rfcs = RfcIndex.objects.filter(rfc_number=r[0]) - if len(rfcs) >= 1: - r[3] = rfcs[0] - - # TODO: require that RfcIndex is present? - - results = [] - for res in idresults+rfcresults: - if len(res)==1: - doc = IdRfcWrapper(IdWrapper(res[0]), None) - results.append(doc) + res.append(0) else: - d = None - r = None - if res[1]: - d = IdWrapper(res[1]) - if res[3]: - r = RfcWrapper(res[3]) - if d or r: - doc = IdRfcWrapper(d, r) - results.append(doc) - results.sort(key=lambda obj: obj.view_sort_key(sort_by)) - + if rfc_num != None: + res.append(rfc_num) + else: + res.append(canonical) + + return res + + results.sort(key=sort_key) + meta = {} - if maxReached: + if len(docs) == MAX: meta['max'] = MAX if query['by']: meta['advanced'] = True - return (results,meta) -if settings.USE_DB_REDESIGN_PROXY_CLASSES: - from ietf.doc.models import * - from ietf.person.models import * - from ietf.group.models import * + # finally wrap in old wrappers - class SearchForm(forms.Form): - name = forms.CharField(required=False) - rfcs = forms.BooleanField(required=False,initial=True) - activeDrafts = forms.BooleanField(required=False,initial=True) - oldDrafts = forms.BooleanField(required=False,initial=False) - lucky = forms.BooleanField(required=False,initial=False) + wrapped_results = [] + for r in results: + draft = None + rfc = None + if not r.name.startswith('rfc'): + draft = IdWrapper(r) + if r.name.startswith('rfc') or r.pk in rfc_aliases: + rfc = RfcWrapper(r) + wrapped_results.append(IdRfcWrapper(draft, rfc)) - by = forms.ChoiceField(choices=[(x,x) for x in ('author','group','area','ad','state')], required=False, initial='wg', label='Foobar') - author = forms.CharField(required=False) - group = forms.CharField(required=False) - area = forms.ModelChoiceField(Group.objects.filter(type="area", state="active").order_by('name'), empty_label="any area", required=False) - ad = forms.ChoiceField(choices=(), required=False) - state = forms.ModelChoiceField(State.objects.filter(type="draft-iesg"), empty_label="any state", required=False) - subState = forms.ChoiceField(choices=(), required=False) - - def __init__(self, *args, **kwargs): - super(SearchForm, self).__init__(*args, **kwargs) - responsible = Document.objects.values_list('ad', flat=True).distinct() - active_ads = list(Person.objects.filter(role__name="ad", - role__group__type="area", - role__group__state="active").distinct()) - inactive_ads = list(((Person.objects.filter(pk__in=responsible) | Person.objects.filter(role__name="pre-ad", - role__group__type="area", - role__group__state="active")).distinct()) - .exclude(pk__in=[x.pk for x in active_ads])) - extract_last_name = lambda x: x.name_parts()[3] - active_ads.sort(key=extract_last_name) - inactive_ads.sort(key=extract_last_name) - - self.fields['ad'].choices = c = [('', 'any AD')] + [(ad.pk, ad.plain_name()) for ad in active_ads] + [('', '------------------')] + [(ad.pk, ad.name) for ad in inactive_ads] - self.fields['subState'].choices = [('', 'any substate'), ('0', 'no substate')] + [(n.slug, n.name) for n in DocTagName.objects.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))] - def clean_name(self): - value = self.cleaned_data.get('name','') - return normalize_draftname(value) - def clean(self): - q = self.cleaned_data - # Reset query['by'] if needed - if 'by' not in q: - q['by'] = None - else: - for k in ('author','group','area','ad'): - if (q['by'] == k) and (k not in q or not q[k]): - q['by'] = None - if (q['by'] == 'state') and (not 'state' in q or not 'subState' in q or not (q['state'] or q['subState'])): - q['by'] = None - # Reset other fields - for k in ('author','group','area','ad'): - if q['by'] != k: - self.data[k] = "" - q[k] = "" - if q['by'] != 'state': - self.data['state'] = "" - self.data['subState'] = "" - q['state'] = "" - q['subState'] = "" - return q - - def search_query(query_original, sort_by=None): - query = dict(query_original.items()) - drafts = query['activeDrafts'] or query['oldDrafts'] - if (not drafts) and (not query['rfcs']): - return ([], {}) - - # Non-ASCII strings don't match anything; this check - # is currently needed to avoid complaints from MySQL. - # FIXME: this should be fixed with MySQL if it's still a problem? - for k in ['name','author','group']: - try: - tmp = str(query.get(k, '')) - except: - query[k] = '*NOSUCH*' - - # Start by search InternetDrafts - idresults = [] - rfcresults = [] - MAX = 500 - - docs = InternetDraft.objects.all() - - # name - if query["name"]: - docs = docs.filter(Q(docalias__name__icontains=query["name"]) | - Q(title__icontains=query["name"])).distinct() - - # rfc/active/old check buttons - allowed_states = [] - if query["rfcs"]: - allowed_states.append("rfc") - if query["activeDrafts"]: - allowed_states.append("active") - if query["oldDrafts"]: - allowed_states.extend(['repl', 'expired', 'auth-rm', 'ietf-rm']) - - docs = docs.filter(states__type="draft", states__slug__in=allowed_states) - - # radio choices - by = query["by"] - if by == "author": - # FIXME: this is full name, not last name as hinted in the HTML - docs = docs.filter(authors__person__name__icontains=query["author"]) - elif by == "group": - docs = docs.filter(group__acronym=query["group"]) - elif by == "area": - docs = docs.filter(Q(group__type="wg", group__parent=query["area"]) | - Q(group=query["area"])).distinct() - elif by == "ad": - docs = docs.filter(ad=query["ad"]) - elif by == "state": - if query["state"]: - docs = docs.filter(states=query["state"]) - if query["subState"]: - docs = docs.filter(tags=query["subState"]) - - # evaluate and fill in values with aggregate queries to avoid - # too many individual queries - results = list(docs.select_related("states", "ad", "ad__person", "std_level", "intended_std_level", "group", "stream")[:MAX]) - - rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=[r.pk for r in results]).values_list("document_id", "name")) - # canonical name - for r in results: - if r.pk in rfc_aliases: - # lambda weirdness works around lambda binding in local for loop scope - r.canonical_name = (lambda x: lambda: x)(rfc_aliases[r.pk]) - else: - r.canonical_name = (lambda x: lambda: x)(r.name) - - result_map = dict((r.pk, r) for r in results) - - # events - event_types = ("published_rfc", - "changed_ballot_position", - "started_iesg_process", - "new_revision") - for d in rfc_aliases.keys(): - for e in event_types: - setattr(result_map[d], e, None) - - for e in DocEvent.objects.filter(doc__in=rfc_aliases.keys(), type__in=event_types).order_by('-time'): - r = result_map[e.doc_id] - if not getattr(r, e.type): - # sets e.g. r.published_date = e for use in proxy wrapper - setattr(r, e.type, e) - - # obsoleted/updated by - for d in rfc_aliases: - r = result_map[d] - r.obsoleted_by_list = [] - r.updated_by_list = [] - - xed_by = RelatedDocument.objects.filter(target__name__in=rfc_aliases.values(), relationship__in=("obs", "updates")).select_related('target__document_id') - rel_rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=[rel.source_id for rel in xed_by]).values_list('document_id', 'name')) - for rel in xed_by: - r = result_map[rel.target.document_id] - if rel.relationship_id == "obs": - attr = "obsoleted_by_list" - else: - attr = "updated_by_list" - - getattr(r, attr).append(int(rel_rfc_aliases[rel.source_id][3:])) - - - # sort - def sort_key(d): - res = [] - - canonical = d.canonical_name() - if canonical.startswith('rfc'): - rfc_num = int(canonical[3:]) - else: - rfc_num = None - - if rfc_num != None: - res.append(2) - elif d.get_state_slug() == "active": - res.append(1) - else: - res.append(3) - - if sort_by == "title": - res.append(d.title) - elif sort_by == "date": - res.append(str(d.revision_date or datetime.date(1990, 1, 1))) - elif sort_by == "status": - if rfc_num != None: - res.append(rfc_num) - else: - res.append(d.get_state().order) - elif sort_by == "ipr": - res.append(d.name) - elif sort_by == "ad": - if rfc_num != None: - res.append(rfc_num) - elif d.get_state_slug() == "active": - if d.get_state("draft-iesg"): - res.append(d.get_state("draft-iesg").order) - else: - res.append(0) - else: - if rfc_num != None: - res.append(rfc_num) - else: - res.append(canonical) - - return res - - results.sort(key=sort_key) - - meta = {} - if len(docs) == MAX: - meta['max'] = MAX - if query['by']: - meta['advanced'] = True - - # finally wrap in old wrappers - - wrapped_results = [] - for r in results: - draft = None - rfc = None - if not r.name.startswith('rfc'): - draft = IdWrapper(r) - if r.name.startswith('rfc') or r.pk in rfc_aliases: - rfc = RfcWrapper(r) - wrapped_results.append(IdRfcWrapper(draft, rfc)) - - return (wrapped_results, meta) + return (wrapped_results, meta) def generate_query_string(request, ignore_list): From a43ccee9112754ecea03aa924819000bf97f93e8 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Mon, 25 Feb 2013 11:50:00 +0000 Subject: [PATCH 37/38] Cleanup the search code in preparation for removal of the shim-layer, use a static button and don't send extraneous GET parameters - Legacy-Id: 5464 --- ietf/templates/idrfc/date_column.html | 37 ------ ietf/templates/idrfc/main.html | 5 - ietf/templates/idrfc/search_form.html | 40 +++--- ietf/templates/idrfc/search_main.html | 28 +---- ietf/templates/idrfc/search_result_row.html | 9 +- ietf/templates/idrfc/search_results.html | 24 ++-- ietf/templates/idrfc/table_header.html | 15 --- ietf/templates/ipr/search.html | 2 +- static/css/base2.css | 19 +-- static/js/doc-search.js | 131 +++++++++----------- 10 files changed, 114 insertions(+), 196 deletions(-) delete mode 100644 ietf/templates/idrfc/date_column.html delete mode 100644 ietf/templates/idrfc/table_header.html diff --git a/ietf/templates/idrfc/date_column.html b/ietf/templates/idrfc/date_column.html deleted file mode 100644 index 7852469cf..000000000 --- a/ietf/templates/idrfc/date_column.html +++ /dev/null @@ -1,37 +0,0 @@ -{% comment %} -Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -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. -{% endcomment %} -{% load ietf_filters %}
diff --git a/ietf/templates/idrfc/main.html b/ietf/templates/idrfc/main.html index eadd46981..15c0a4b19 100644 --- a/ietf/templates/idrfc/main.html +++ b/ietf/templates/idrfc/main.html @@ -77,11 +77,6 @@ about: {% endif %} {% endblock content %} -{% block scripts %} -YAHOO.util.Event.onContentReady("search_submit_button", function () { - var oButton = new YAHOO.widget.Button("search_submit_button", {}); -}); -{% endblock scripts %} {% block js %} diff --git a/ietf/templates/idrfc/search_form.html b/ietf/templates/idrfc/search_form.html index e2b179f11..9592ce186 100644 --- a/ietf/templates/idrfc/search_form.html +++ b/ietf/templates/idrfc/search_form.html @@ -32,54 +32,46 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% endcomment %} - +
{{ form.name }}
- -
{% if not doc.rfc %}{{ doc.publication_date }}{% else %}{{ doc.publication_date|date:"Y-m" }}{% endif %} -{% if doc.publication_date|timesince_days|new_enough:request %}
{% if not doc.rfc%}new{%else%}new{%endif%}{%endif%} -{% if doc.id and doc.id.expected_expiration_date and doc.id.expected_expiration_date|timesince_days|expires_soon:request %}
expires soon{%endif%} -
- - - -
{{ form.rfcs }} RFCs
{{ form.activeDrafts }} Internet-Drafts (active)
{{ form.oldDrafts }} Internet-Drafts (expired/replaced/withdrawn)
+ + + + + +
- Advanced + Advanced -
+
Additional search criteria:
- {{ form.author }} + {{ form.author }}
- {{ form.group }} + {{ form.group }}
- {{ form.area }} + {{ form.area }}
- {{ form.ad }} + {{ form.ad }}
- {{ form.state }} :: {{ form.subState }} + {{ form.state }} :: {{ form.subState }}
-{% comment %} -
- {{ form.positionAd }} has position {{ form.positionValue }} -
-{% endcomment %}
-
-{# #} - - - +
+
diff --git a/ietf/templates/idrfc/search_main.html b/ietf/templates/idrfc/search_main.html index a2fc630ff..9c235d03a 100644 --- a/ietf/templates/idrfc/search_main.html +++ b/ietf/templates/idrfc/search_main.html @@ -38,7 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% block content %}

Internet-Drafts and RFCs

-
+
{% include "idrfc/search_form.html" %}
@@ -48,32 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% endif %}
{% endblock content %} -{% block scripts %} -YAHOO.util.Event.onContentReady("search_submit_button", function () { - var oButton = new YAHOO.widget.Button("search_submit_button", {}); -}); -{% if meta.searching %} -(function ($) { - $(document).ready(function () { - $('.addtolist a').click(function() { - var trigger = $(this); - $.ajax({ - url: trigger.attr('href'), - type: 'GET', - cache: false, - dataType: 'json', - success: function(response){ - if (response.success) { - trigger.replaceWith('added'); - } - } - }); - return false; - }); - }); -})(jQuery); -{% endif %} -{% endblock scripts %} {% block js %} diff --git a/ietf/templates/idrfc/search_result_row.html b/ietf/templates/idrfc/search_result_row.html index af19ec72a..38ccd6192 100644 --- a/ietf/templates/idrfc/search_result_row.html +++ b/ietf/templates/idrfc/search_result_row.html @@ -35,7 +35,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% load ietf_filters %} {% load ballot_icon %} -{% if user.is_authenticated and show_add_to_list %} +{% if show_add_to_list and user.is_authenticated %} {% if doc.id %} Add to your personal ID list @@ -51,7 +51,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% endif %} {{ doc.title }} -{% include "idrfc/date_column.html" %} + +{% if not doc.rfc %}{{ doc.publication_date }}{% else %}{{ doc.publication_date|date:"Y-m" }}{% endif %} +{% if doc.publication_date|timesince_days|new_enough:request %}
{% if not doc.rfc%}new{%else%}new{%endif%}{%endif%} +{% if doc.id and doc.id.expected_expiration_date and doc.id.expected_expiration_date|timesince_days|expires_soon:request %}
expires soon{%endif%} + + {% include "idrfc/status_columns.html" %} {% include "idrfc/ipr_column.html" %} {# {% if doc.ad_name %}{{ doc.ad_name }}{% else %} {% endif %} #} diff --git a/ietf/templates/idrfc/search_results.html b/ietf/templates/idrfc/search_results.html index b9aa08780..ae7918688 100644 --- a/ietf/templates/idrfc/search_results.html +++ b/ietf/templates/idrfc/search_results.html @@ -38,19 +38,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% if not docs %}

No documents match your query.

{% else %} -{% regroup docs by view_sort_group as grouped_docs %} + -{% if user.is_authenticated %}{% endif %} - {% for hdr in meta.hdrs %} - {% include "idrfc/table_header.html" %} - {% endfor %} + + {% if user.is_authenticated %}{% endif %} + + {% for hdr in meta.hdrs %} + + {% endfor %} -{% for doc_group in grouped_docs %} - +{% regroup docs by view_sort_group as grouped_docs %} +{% for doc_group in grouped_docs %} + + {% with 1 as show_add_to_list %} {% for doc in doc_group.list %} -{% include "idrfc/search_result_row.html" %} + {% include "idrfc/search_result_row.html" %} {% endfor %} {% endwith %} diff --git a/ietf/templates/idrfc/table_header.html b/ietf/templates/idrfc/table_header.html deleted file mode 100644 index 604a92536..000000000 --- a/ietf/templates/idrfc/table_header.html +++ /dev/null @@ -1,15 +0,0 @@ -{# Copyright The IETF Trust 2011, All Rights Reserved #} - - diff --git a/ietf/templates/ipr/search.html b/ietf/templates/ipr/search.html index cdc7bfef5..eefa93114 100644 --- a/ietf/templates/ipr/search.html +++ b/ietf/templates/ipr/search.html @@ -10,7 +10,7 @@ label { float:left; width: 200px; }

IPR Search

Document Search

-
+
diff --git a/static/css/base2.css b/static/css/base2.css index 5b15d3322..66406b470 100644 --- a/static/css/base2.css +++ b/static/css/base2.css @@ -82,13 +82,16 @@ body { margin: 0; } .ietf-stream .entry-title .entry-date { float: right; } .ietf-stream .entry-comment { background: #eeeeee; margin: 1em 0px; padding: 1em; } -.search_form_box {width: 99.5%; margin-top:8px; padding:4px; margin-bottom:1em; padding-left:8px;} +.search-form-box { width: 99.5%; margin-top:8px; padding:4px; margin-bottom:1em; padding-left:8px; } form#search_form { padding-top: 4px; padding-bottom: 4px; } +#search_form .submit { padding-top: 0.5em; } +#search_form .submit .button { padding: 0.2em 0.5em; border: 1px solid #999; } #search_form input { padding: 0; padding-left: 2px; border: 1px solid #89d;} -#search_form input.radio { padding-left: 0; border: 0; } +#search_form input.radio { padding-left: 0; border: 0; } #search_form select { border: 1px solid #89d; } #search_form div.search_field { margin-top:2px; clear:both;} -#search_form label { width: 170px; float: left; } +#search_form .search_field > label { width: 170px; float: left; } +#search_form #search_advanced { margin-top: 1em; } /* checkboxes for document types */ #search_form table#search_types { border-collapse:collapse;} #search_form #search_types td { padding:0; } @@ -106,12 +109,13 @@ table.ietf-table { border-collapse:collapse; border:1px solid #7f7f7f; } .ietf-table tr.evenrow { background-color: #EDF5FF; } .ietf-table tr.oddrow { background-color: white; } .ietf-table td { border-right: 1px solid #cbcbcb; padding:3px 6px; vertical-align: top; } -.ietf-table th { color:white; background: #2647A0; text-align:left; padding:3px 6px; border-right: 1px solid #7f7f7f; } +.ietf-table th { color: #fff; background: #2647A0; text-align: left; padding:3px 6px; border-right: 1px solid #7f7f7f; } .ietf-doctable tr.header { border-top: 1px solid #7f7f7f; border-bottom: 1px solid #7f7f7f; border-left: 1px solid white; border-right:2px solid white;} .ietf-doctable tr.header td {padding: 6px 6px; font-weight: bold; } .ietf-doctable table { max-width: 1200px; } -.ietf-doctable th { cursor: pointer } +.ietf-doctable th { cursor: pointer; white-space: nowrap; } +.ietf-doctable th img { border-style: none; vertical-align: top; } .ietf-doctable th.doc, .ietf-doctable td.doc { min-width:20em; max-width: 35em; } .ietf-doctable th.title, .ietf-doctable td.title { min-width: 20em; max-width: 35em; } .ietf-doctable th.date, .ietf-doctable td.date { white-space:nowrap; min-width: 6em;} @@ -206,12 +210,13 @@ table.milestones .doc { display: block; padding-left: 1em; } .stream-state .milestone { display: inline-block; font-size: smaller; background-color: #d5dde6; padding: 0 0.2em; margin-left: 0.3em; } -.button { +.button, .button:hover:disabled { display: inline-block; padding: 4px 12px; margin-right: 0.3em; color: #222; font-weight: normal; text-align: center; text-decoration: none; outline: none; cursor: pointer; - background: #eee; background: linear-gradient(#fff, #ddd); background: -webkit-linear-gradient(#fff, #ddd); background: -moz-linear-gradient(#fff, #ddd); + background: #eee; background: linear-gradient(#fff, #e0e0e0); background: -webkit-linear-gradient(#fff, #e0e0e0); background: -moz-linear-gradient(#fff, #e0e0e0); border: 1px solid #666; border-radius: 3px; transition-duration: 0.2s; } .button:hover { color: #111; background: #ddd; background: linear-gradient(#eee, #ccc); background: -webkit-linear-gradient(#eee, #ccc); background: -moz-linear-gradient(#eee, #ccc); } .button:active { color: #000; background: #ccc; } +.button:disabled, .button:hover:disabled { color: #999; cursor: default; } diff --git a/static/js/doc-search.js b/static/js/doc-search.js index 313958572..5f999f38c 100644 --- a/static/js/doc-search.js +++ b/static/js/doc-search.js @@ -1,86 +1,77 @@ $(function () { var form = jQuery("#search_form"); - form.find(".search_field input[name=by]").parents("label").click(changeBy); - - form.find(".search_field").find("input,select") - .change(toggleSubmit).click(toggleSubmit).keyup(toggleSubmit); - - form.find(".toggle_advanced").click(function () { - togglePlusMinus("search_advanced"); - form.find('.search_field input[type="radio"]').attr("checked", false); - changeBy(); - }); - - changeBy(); - - // we want to disable our submit button if we have no search text, + // we want to disable our submit button if we have no search text, // and we have no advanced options selected function toggleSubmit() { - var button = document.getElementById("id_search_submit"); - var by = findCheckedSearchBy(); - var value = findSearchByValue(by); - var text = document.getElementById("id_name"); - if ((value == "") && (text.value == "")) { - button.disabled = true; - } else { - button.disabled = false; - } + var nameSearch = $.trim($("#id_name").val()); + + var noAdvanced = true; + + var by = form.find("input[name=by]:checked"); + if (by.length > 0) + by.closest(".search_field").find("input,select").not("input[name=by]").each(function () { + if ($.trim(this.value)) + noAdvanced = false; + }); + + form.find("input[type=submit]").get(0).disabled = !nameSearch && noAdvanced; } - function togglePlusMinus(id) { - var el = document.getElementById(id); - var imgEl = document.getElementById(id+"-img"); - if (el.style.display == 'none') { - el.style.display = 'block'; - imgEl.src = "/images/minus.png"; + function togglePlusMinus(toggler, toggled) { + var img = toggler.find("img").get(0); + if (toggled.is(":hidden")) { + toggled.show(); + img.src = "/images/minus.png"; } else { - el.style.display = 'none'; - imgEl.src = "/images/plus.png"; + toggled.hide(); + img.src = "/images/plus.png"; } } - function findCheckedSearchBy() { - var by=''; - var f = document.search_form; - for (var i = 0; i < f.by.length; i++) { - if (f.by[i].checked) { - by = f.by[i].value; - break; - } - } - return by; - } + function updateBy() { + form.find("input[name=by]:checked").closest(".search_field").find("input,select").not("input[name=by]").each(function () { + this.disabled = false; + }); - function findSearchByValue(by) { - if (by == 'author') { return document.getElementById("id_author").value; } - if (by == 'group') { return document.getElementById("id_group").value; } - if (by == 'area') { return document.getElementById("id_area").value; } - if (by == 'ad') { return document.getElementById("id_ad").value; } - if (by == 'state') { - // state might be state... - state_value = document.getElementById("id_state").value; - if (state_value) { return state_value; } - // ...or sub-state - return document.getElementById("id_subState").value; - } - return ''; - } - - function changeBy() { - var by = findCheckedSearchBy(); - var f = document.search_form; - f.author.disabled=true; - f.group.disabled=true; - f.area.disabled=true; - f.ad.disabled=true; - f.state.disabled=true; f.subState.disabled=true; - if (by=='author') { f.author.disabled=false;} - if (by=='group') { f.group.disabled=false;} - if (by=='area') { f.area.disabled=false;} - if (by=='ad') { f.ad.disabled=false; } - if (by=='state') { f.state.disabled=false; f.subState.disabled=false; } + form.find("input[name=by]").not(":checked").closest(".search_field").find("input,select").not("input[name=by]").each(function () { + this.disabled = true; + }); toggleSubmit(); } + + form.find(".search_field input[name=by]").closest("label").click(updateBy); + + form.find(".search_field input,select") + .change(toggleSubmit).click(toggleSubmit).keyup(toggleSubmit); + + form.find(".toggle_advanced").click(function () { + var advanced = $(this).next(); + advanced.find('.search_field input[type="radio"]').attr("checked", false); + togglePlusMinus($(this), advanced); + updateBy(); + }); + + updateBy(); + + $("#search_results th").click(function (e) { + window.location = $(this).find("a").attr("href"); + }) + + $('#search_results .addtolist a').click(function(e) { + e.preventDefault(); + var trigger = $(this); + $.ajax({ + url: trigger.attr('href'), + type: 'POST', + cache: false, + dataType: 'json', + success: function(response){ + if (response.success) { + trigger.replaceWith('added'); + } + } + }); + }); }); From 619b1d870ee6160d3add6f4ec4b3c6c9d63db75b Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Mon, 25 Feb 2013 11:50:25 +0000 Subject: [PATCH 38/38] Remove dead code - Legacy-Id: 5465 --- ietf/idrfc/views_ballot.py | 1 - ietf/wgchairs/views.py | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/ietf/idrfc/views_ballot.py b/ietf/idrfc/views_ballot.py index a3795b663..d20465150 100644 --- a/ietf/idrfc/views_ballot.py +++ b/ietf/idrfc/views_ballot.py @@ -26,7 +26,6 @@ from ietf.ipr.search import iprs_from_docs from ietf.idrfc.mails import * from ietf.idrfc.utils import * from ietf.idrfc.lastcall import request_last_call -from ietf.idrfc.idrfc_wrapper import BallotWrapper from ietf.doc.utils import * from ietf.doc.models import * diff --git a/ietf/wgchairs/views.py b/ietf/wgchairs/views.py index 8cfc6f8ac..d5f2f2736 100644 --- a/ietf/wgchairs/views.py +++ b/ietf/wgchairs/views.py @@ -4,7 +4,6 @@ from django.shortcuts import get_object_or_404, render_to_response from django.template import RequestContext from django.http import HttpResponseForbidden, Http404 -from ietf.idrfc.views_search import SearchForm, search_query from ietf.wgchairs.forms import (RemoveDelegateForm, add_form_factory, workflow_form_factory, TransitionFormSet, WriteUpEditForm, assign_shepherd) @@ -225,15 +224,7 @@ def wg_shepherd_documents(request, acronym): return HttpResponseForbidden('You have no permission to access this view') current_person = get_person_for_user(user) - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - base_qs = InternetDraft.objects.filter(group=wg, states__type="draft", states__slug="active").select_related("status").order_by('title') - else: - form = SearchForm({'by': 'group', 'group': str(wg.group_acronym.acronym), - 'activeDrafts': 'on'}) - if not form.is_valid(): - raise ValueError("form did not validate") - (docs, meta) = search_query(form.cleaned_data) - base_qs = InternetDraft.objects.filter(pk__in=[i.id._draft.pk for i in docs if i.id]).select_related('status') + base_qs = InternetDraft.objects.filter(group=wg, states__type="draft", states__slug="active").select_related("status").order_by('title') documents_no_shepherd = base_qs.filter(shepherd=None) documents_my = base_qs.filter(shepherd=current_person) documents_other = base_qs.exclude(shepherd=None).exclude(shepherd__pk__in=[current_person.pk, 0])
+ {{ hdr.htitle }} + + +
{{doc_group.grouper}}s
{{ doc_group.grouper }}s
- - - {% if hdr.selected %} - - {% else %} - - {% endif %} - -