diff --git a/INSTALL b/INSTALL index 07aa60c0c..ea33a69ce 100644 --- a/INSTALL +++ b/INSTALL @@ -121,6 +121,17 @@ usual, with re-pointing the symlink and restarting apache. Additional Version-Specific Instructions ======================================== +Version 4.46 +------------ + +Before you run step 3 (migration) of the general instructions, please run some specific +initial migrations with the a --fake argument: + + cd $releasenumber + PYTHONPATH=$PWD ietf/manage.py migrate group 0001 --fake + cd .. + + Version 4.42 ------------ diff --git a/changelog b/changelog index e9d2c1de5..9c918fa17 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,14 @@ +ietfdb (4.46) ietf; urgency=medium + + This is a major feature release, which introduces datatracker support + for milestone management. WG Chairs will, if they are logged in, see + an 'Add or edit milestones' button on the WG's Charter page in the + datatracker, just below the charter text, and Area Directors and + Secretariat staff will see a new link 'Milestones' in the left-hand + menu-bar, leading to a page which lists Milestones Needing Review. + + -- Henrik Levkowetz 14 May 2013 21:50:09 +0200 + ietfdb (4.45) ietf; urgency=medium This release contains bugfixes and some minor features. diff --git a/ietf/__init__.py b/ietf/__init__.py index ef08ac675..22887db83 100644 --- a/ietf/__init__.py +++ b/ietf/__init__.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8-no-bom -*- # Copyright The IETF Trust 2007, All Rights Reserved __version__ = "4.46-dev" diff --git a/ietf/bin/send-milestone-reminders b/ietf/bin/send-milestone-reminders new file mode 100755 index 000000000..a23a7bcb9 --- /dev/null +++ b/ietf/bin/send-milestone-reminders @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# +# This script will send various milestone reminders. It's supposed to +# be run daily, and will then send reminders weekly/monthly as +# appropriate. + +import datetime, os +import syslog + +from ietf import settings +from django.core import management +management.setup_environ(settings) + +syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_LOCAL0) + +from ietf.wginfo.mails import * + +today = datetime.date.today() + +MONDAY = 1 +FIRST_DAY_OF_MONTH = 1 + +if today.isoweekday() == MONDAY: + # send milestone review reminders - ideally we'd keep track of + # exactly when we sent one last time for a group, but it's a bit + # complicated because people can change the milestones in the mean + # time, so dodge all of this by simply sending once a week only + for g in groups_with_milestones_needing_review(): + mail_sent = email_milestone_review_reminder(g, grace_period=7) + if mail_sent: + syslog.syslog("Sent milestone review reminder for %s %s" % (g.acronym, g.type.name)) + + +early_warning_days = 30 + +# send any milestones due reminders +for g in groups_needing_milestones_due_reminder(early_warning_days): + email_milestones_due(g, early_warning_days) + syslog.syslog("Sent milestones due reminder for %s %s" % (g.acronym, g.type.name)) + +if today.day == FIRST_DAY_OF_MONTH: + # send milestone overdue reminders - once a month + for g in groups_needing_milestones_overdue_reminder(grace_period=30): + email_milestones_overdue(g) + syslog.syslog("Sent milestones overdue reminder for %s %s" % (g.acronym, g.type.name)) diff --git a/ietf/doc/models.py b/ietf/doc/models.py index a64753d0e..31d6a35f6 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -465,6 +465,7 @@ EVENT_TYPES = [ # WG events ("changed_group", "Changed group"), ("changed_protocol_writeup", "Changed protocol writeup"), + ("changed_charter_milestone", "Changed charter milestone"), # charter events ("initial_review", "Set initial review time"), diff --git a/ietf/group/admin.py b/ietf/group/admin.py index 2af54013c..ff0040af0 100644 --- a/ietf/group/admin.py +++ b/ietf/group/admin.py @@ -116,9 +116,9 @@ class GroupHistoryAdmin(admin.ModelAdmin): admin.site.register(GroupHistory, GroupHistoryAdmin) class GroupMilestoneAdmin(admin.ModelAdmin): - list_display = ["group", "desc", "expected_due_date", "time"] - search_fields = ["group__name", "group__acronym", "desc"] - raw_id_fields = ["group"] + list_display = ["group", "desc", "due", "resolved", "time"] + search_fields = ["group__name", "group__acronym", "desc", "resolved"] + raw_id_fields = ["group", "docs"] admin.site.register(GroupMilestone, GroupMilestoneAdmin) diff --git a/ietf/group/migrations/0001_initial.py b/ietf/group/migrations/0001_initial.py new file mode 100644 index 000000000..6e9852f5d --- /dev/null +++ b/ietf/group/migrations/0001_initial.py @@ -0,0 +1,481 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'Group' + db.create_table('group_group', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('time', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=80)), + ('state', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.GroupStateName'], null=True)), + ('type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.GroupTypeName'], null=True)), + ('parent', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.Group'], null=True, blank=True)), + ('ad', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Person'], null=True, blank=True)), + ('list_email', self.gf('django.db.models.fields.CharField')(max_length=64, blank=True)), + ('list_subscribe', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('list_archive', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('comments', self.gf('django.db.models.fields.TextField')(blank=True)), + ('acronym', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=40, db_index=True)), + ('charter', self.gf('django.db.models.fields.related.OneToOneField')(blank=True, related_name='chartered_group', unique=True, null=True, to=orm['doc.Document'])), + )) + db.send_create_signal('group', ['Group']) + + # Adding M2M table for field unused_states on 'Group' + db.create_table('group_group_unused_states', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('group', models.ForeignKey(orm['group.group'], null=False)), + ('state', models.ForeignKey(orm['doc.state'], null=False)) + )) + db.create_unique('group_group_unused_states', ['group_id', 'state_id']) + + # Adding M2M table for field unused_tags on 'Group' + db.create_table('group_group_unused_tags', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('group', models.ForeignKey(orm['group.group'], null=False)), + ('doctagname', models.ForeignKey(orm['name.doctagname'], null=False)) + )) + db.create_unique('group_group_unused_tags', ['group_id', 'doctagname_id']) + + # Adding model 'GroupHistory' + db.create_table('group_grouphistory', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('time', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=80)), + ('state', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.GroupStateName'], null=True)), + ('type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.GroupTypeName'], null=True)), + ('parent', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.Group'], null=True, blank=True)), + ('ad', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Person'], null=True, blank=True)), + ('list_email', self.gf('django.db.models.fields.CharField')(max_length=64, blank=True)), + ('list_subscribe', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('list_archive', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('comments', self.gf('django.db.models.fields.TextField')(blank=True)), + ('group', self.gf('django.db.models.fields.related.ForeignKey')(related_name='history_set', to=orm['group.Group'])), + ('acronym', self.gf('django.db.models.fields.CharField')(max_length=40)), + )) + db.send_create_signal('group', ['GroupHistory']) + + # Adding M2M table for field unused_states on 'GroupHistory' + db.create_table('group_grouphistory_unused_states', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('grouphistory', models.ForeignKey(orm['group.grouphistory'], null=False)), + ('state', models.ForeignKey(orm['doc.state'], null=False)) + )) + db.create_unique('group_grouphistory_unused_states', ['grouphistory_id', 'state_id']) + + # Adding M2M table for field unused_tags on 'GroupHistory' + db.create_table('group_grouphistory_unused_tags', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('grouphistory', models.ForeignKey(orm['group.grouphistory'], null=False)), + ('doctagname', models.ForeignKey(orm['name.doctagname'], null=False)) + )) + db.create_unique('group_grouphistory_unused_tags', ['grouphistory_id', 'doctagname_id']) + + # Adding model 'GroupURL' + db.create_table('group_groupurl', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.Group'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('url', self.gf('django.db.models.fields.URLField')(max_length=200)), + )) + db.send_create_signal('group', ['GroupURL']) + + # Adding model 'GroupMilestone' + db.create_table('group_groupmilestone', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.Group'])), + ('desc', self.gf('django.db.models.fields.TextField')()), + ('expected_due_date', self.gf('django.db.models.fields.DateField')()), + ('done', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('done_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)), + ('time', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), + )) + db.send_create_signal('group', ['GroupMilestone']) + + # Adding model 'GroupStateTransitions' + db.create_table('group_groupstatetransitions', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.Group'])), + ('state', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.State'])), + )) + db.send_create_signal('group', ['GroupStateTransitions']) + + # Adding M2M table for field next_states on 'GroupStateTransitions' + db.create_table('group_groupstatetransitions_next_states', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('groupstatetransitions', models.ForeignKey(orm['group.groupstatetransitions'], null=False)), + ('state', models.ForeignKey(orm['doc.state'], null=False)) + )) + db.create_unique('group_groupstatetransitions_next_states', ['groupstatetransitions_id', 'state_id']) + + # Adding model 'GroupEvent' + db.create_table('group_groupevent', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.Group'])), + ('time', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('type', self.gf('django.db.models.fields.CharField')(max_length=50)), + ('by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Person'])), + ('desc', self.gf('django.db.models.fields.TextField')()), + )) + db.send_create_signal('group', ['GroupEvent']) + + # Adding model 'ChangeStateGroupEvent' + db.create_table('group_changestategroupevent', ( + ('groupevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['group.GroupEvent'], unique=True, primary_key=True)), + ('state', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.GroupStateName'])), + )) + db.send_create_signal('group', ['ChangeStateGroupEvent']) + + # Adding model 'Role' + db.create_table('group_role', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.RoleName'])), + ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.Group'])), + ('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Person'])), + ('email', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Email'])), + )) + db.send_create_signal('group', ['Role']) + + # Adding model 'RoleHistory' + db.create_table('group_rolehistory', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.RoleName'])), + ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.GroupHistory'])), + ('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Person'])), + ('email', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Email'])), + )) + db.send_create_signal('group', ['RoleHistory']) + + + def backwards(self, orm): + + # Deleting model 'Group' + db.delete_table('group_group') + + # Removing M2M table for field unused_states on 'Group' + db.delete_table('group_group_unused_states') + + # Removing M2M table for field unused_tags on 'Group' + db.delete_table('group_group_unused_tags') + + # Deleting model 'GroupHistory' + db.delete_table('group_grouphistory') + + # Removing M2M table for field unused_states on 'GroupHistory' + db.delete_table('group_grouphistory_unused_states') + + # Removing M2M table for field unused_tags on 'GroupHistory' + db.delete_table('group_grouphistory_unused_tags') + + # Deleting model 'GroupURL' + db.delete_table('group_groupurl') + + # Deleting model 'GroupMilestone' + db.delete_table('group_groupmilestone') + + # Deleting model 'GroupStateTransitions' + db.delete_table('group_groupstatetransitions') + + # Removing M2M table for field next_states on 'GroupStateTransitions' + db.delete_table('group_groupstatetransitions_next_states') + + # Deleting model 'GroupEvent' + db.delete_table('group_groupevent') + + # Deleting model 'ChangeStateGroupEvent' + db.delete_table('group_changestategroupevent') + + # Deleting model 'Role' + db.delete_table('group_role') + + # Deleting model 'RoleHistory' + db.delete_table('group_rolehistory') + + + 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.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.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.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'}) + }, + 'group.changestategroupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'ChangeStateGroupEvent', '_ormbases': ['group.GroupEvent']}, + 'groupevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['group.GroupEvent']", 'unique': 'True', 'primary_key': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']"}) + }, + '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'}) + }, + 'group.groupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'GroupEvent'}, + 'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}), + 'desc': ('django.db.models.fields.TextField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + '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'}) + }, + 'group.grouphistory': { + 'Meta': {'object_name': 'GroupHistory'}, + 'acronym': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['group.Group']"}), + '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'}) + }, + 'group.groupmilestone': { + 'Meta': {'ordering': "['expected_due_date']", 'object_name': 'GroupMilestone'}, + 'desc': ('django.db.models.fields.TextField', [], {}), + 'done': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'done_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'expected_due_date': ('django.db.models.fields.DateField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + 'group.groupstatetransitions': { + 'Meta': {'object_name': 'GroupStateTransitions'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'previous_groupstatetransitions_states'", 'symmetrical': 'False', 'to': "orm['doc.State']"}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.State']"}) + }, + 'group.groupurl': { + 'Meta': {'object_name': 'GroupURL'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) + }, + 'group.role': { + 'Meta': {'object_name': 'Role'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}) + }, + 'group.rolehistory': { + 'Meta': {'object_name': 'RoleHistory'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.GroupHistory']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}) + }, + '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.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.rolename': { + 'Meta': {'ordering': "['order']", 'object_name': 'RoleName'}, + '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 = ['group'] diff --git a/ietf/group/migrations/0002_auto__add_milestonegroupevent__del_field_groupmilestone_expected_due_d.py b/ietf/group/migrations/0002_auto__add_milestonegroupevent__del_field_groupmilestone_expected_due_d.py new file mode 100644 index 000000000..b7b05efc2 --- /dev/null +++ b/ietf/group/migrations/0002_auto__add_milestonegroupevent__del_field_groupmilestone_expected_due_d.py @@ -0,0 +1,361 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + depends_on = ( + ("name", "0009_add_groupmilestonestatenames"), + ) + + def forwards(self, orm): + + # Adding model 'MilestoneGroupEvent' + db.create_table('group_milestonegroupevent', ( + ('groupevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['group.GroupEvent'], unique=True, primary_key=True)), + ('milestone', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.GroupMilestone'])), + )) + db.send_create_signal('group', ['MilestoneGroupEvent']) + + # rename expected_due_date + db.rename_column('group_groupmilestone', 'expected_due_date', "due") + + # Adding field 'GroupMilestone.resolved' + db.add_column('group_groupmilestone', 'resolved', self.gf('django.db.models.fields.CharField')(default='', max_length=50, blank=True), keep_default=False) + + # Adding field 'GroupMilestone.state' + db.add_column('group_groupmilestone', 'state', self.gf('django.db.models.fields.related.ForeignKey')(default='active', to=orm['name.GroupMilestoneStateName']), keep_default=False) + + # Adding M2M table for field docs on 'GroupMilestone' + db.create_table('group_groupmilestone_docs', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('groupmilestone', models.ForeignKey(orm['group.groupmilestone'], null=False)), + ('document', models.ForeignKey(orm['doc.document'], null=False)) + )) + db.create_unique('group_groupmilestone_docs', ['groupmilestone_id', 'document_id']) + + # Changing field 'GroupMilestone.desc' + db.alter_column('group_groupmilestone', 'desc', self.gf('django.db.models.fields.CharField')(max_length=500)) + + + def backwards(self, orm): + + # Deleting model 'MilestoneGroupEvent' + db.delete_table('group_milestonegroupevent') + + # rename due + db.rename_column('group_groupmilestone', 'due', "expected_due_date") + + # Deleting field 'GroupMilestone.resolved' + db.delete_column('group_groupmilestone', 'resolved') + + # Deleting field 'GroupMilestone.state' + db.delete_column('group_groupmilestone', 'state_id') + + # Removing M2M table for field docs on 'GroupMilestone' + db.delete_table('group_groupmilestone_docs') + + # Changing field 'GroupMilestone.desc' + db.alter_column('group_groupmilestone', 'desc', self.gf('django.db.models.fields.TextField')()) + + + 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.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.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.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'}) + }, + 'group.changestategroupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'ChangeStateGroupEvent', '_ormbases': ['group.GroupEvent']}, + 'groupevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['group.GroupEvent']", 'unique': 'True', 'primary_key': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']"}) + }, + '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'}) + }, + 'group.groupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'GroupEvent'}, + 'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}), + 'desc': ('django.db.models.fields.TextField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + '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'}) + }, + 'group.grouphistory': { + 'Meta': {'object_name': 'GroupHistory'}, + 'acronym': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['group.Group']"}), + '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'}) + }, + 'group.groupmilestone': { + 'Meta': {'ordering': "['due', 'id']", 'object_name': 'GroupMilestone'}, + 'desc': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'docs': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']", 'symmetrical': 'False', 'blank': 'True'}), + 'done': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'done_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'due': ('django.db.models.fields.DateField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'resolved': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupMilestoneStateName']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + 'group.groupstatetransitions': { + 'Meta': {'object_name': 'GroupStateTransitions'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'previous_groupstatetransitions_states'", 'symmetrical': 'False', 'to': "orm['doc.State']"}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.State']"}) + }, + 'group.groupurl': { + 'Meta': {'object_name': 'GroupURL'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) + }, + 'group.milestonegroupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'MilestoneGroupEvent', '_ormbases': ['group.GroupEvent']}, + 'groupevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['group.GroupEvent']", 'unique': 'True', 'primary_key': 'True'}), + 'milestone': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.GroupMilestone']"}) + }, + 'group.role': { + 'Meta': {'object_name': 'Role'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}) + }, + 'group.rolehistory': { + 'Meta': {'object_name': 'RoleHistory'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.GroupHistory']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}) + }, + '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.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.groupmilestonestatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupMilestoneStateName'}, + '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.rolename': { + 'Meta': {'ordering': "['order']", 'object_name': 'RoleName'}, + '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 = ['group'] diff --git a/ietf/group/migrations/0003_fixup_milestone.py b/ietf/group/migrations/0003_fixup_milestone.py new file mode 100644 index 000000000..8abdc3d6f --- /dev/null +++ b/ietf/group/migrations/0003_fixup_milestone.py @@ -0,0 +1,331 @@ +# 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): + "Write your forwards methods here." + + system_person = orm["person.Person"].objects.get(name="(System)") + + for m in orm.GroupMilestone.objects.all(): + if m.done: + m.resolved = "Done" + m.save() + + orm.MilestoneGroupEvent.objects.get_or_create( + group_id=m.group_id, + type="changed_milestone", + time=datetime.datetime.combine(m.done_date, datetime.time(0, 0, 0)), + by=system_person, + desc='Changed milestone "%s", resolved as "%s"' % (m.desc, m.resolved), + milestone=m, + ) + + + 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.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.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.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'}) + }, + 'group.changestategroupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'ChangeStateGroupEvent', '_ormbases': ['group.GroupEvent']}, + 'groupevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['group.GroupEvent']", 'unique': 'True', 'primary_key': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']"}) + }, + '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'}) + }, + 'group.groupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'GroupEvent'}, + 'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}), + 'desc': ('django.db.models.fields.TextField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + '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'}) + }, + 'group.grouphistory': { + 'Meta': {'object_name': 'GroupHistory'}, + 'acronym': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['group.Group']"}), + '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'}) + }, + 'group.groupmilestone': { + 'Meta': {'ordering': "['due', 'id']", 'object_name': 'GroupMilestone'}, + 'desc': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'docs': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']", 'symmetrical': 'False', 'blank': 'True'}), + 'done': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'done_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'due': ('django.db.models.fields.DateField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'resolved': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupMilestoneStateName']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + 'group.groupstatetransitions': { + 'Meta': {'object_name': 'GroupStateTransitions'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'previous_groupstatetransitions_states'", 'symmetrical': 'False', 'to': "orm['doc.State']"}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.State']"}) + }, + 'group.groupurl': { + 'Meta': {'object_name': 'GroupURL'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) + }, + 'group.milestonegroupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'MilestoneGroupEvent', '_ormbases': ['group.GroupEvent']}, + 'groupevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['group.GroupEvent']", 'unique': 'True', 'primary_key': 'True'}), + 'milestone': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.GroupMilestone']"}) + }, + 'group.role': { + 'Meta': {'object_name': 'Role'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}) + }, + 'group.rolehistory': { + 'Meta': {'object_name': 'RoleHistory'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.GroupHistory']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}) + }, + '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.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.groupmilestonestatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupMilestoneStateName'}, + '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.rolename': { + 'Meta': {'ordering': "['order']", 'object_name': 'RoleName'}, + '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 = ['group'] diff --git a/ietf/group/migrations/0004_auto__del_field_groupmilestone_done_date__del_field_groupmilestone_don.py b/ietf/group/migrations/0004_auto__del_field_groupmilestone_done_date__del_field_groupmilestone_don.py new file mode 100644 index 000000000..e08a26e94 --- /dev/null +++ b/ietf/group/migrations/0004_auto__del_field_groupmilestone_done_date__del_field_groupmilestone_don.py @@ -0,0 +1,322 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Deleting field 'GroupMilestone.done_date' + db.delete_column('group_groupmilestone', 'done_date') + + # Deleting field 'GroupMilestone.done' + db.delete_column('group_groupmilestone', 'done') + + + def backwards(self, orm): + + # Adding field 'GroupMilestone.done_date' + db.add_column('group_groupmilestone', 'done_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True), keep_default=False) + + # Adding field 'GroupMilestone.done' + db.add_column('group_groupmilestone', 'done', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False) + + + 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.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.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.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'}) + }, + 'group.changestategroupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'ChangeStateGroupEvent', '_ormbases': ['group.GroupEvent']}, + 'groupevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['group.GroupEvent']", 'unique': 'True', 'primary_key': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']"}) + }, + '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'}) + }, + 'group.groupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'GroupEvent'}, + 'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}), + 'desc': ('django.db.models.fields.TextField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + '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'}) + }, + 'group.grouphistory': { + 'Meta': {'object_name': 'GroupHistory'}, + 'acronym': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['group.Group']"}), + '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'}) + }, + 'group.groupmilestone': { + 'Meta': {'ordering': "['due', 'id']", 'object_name': 'GroupMilestone'}, + 'desc': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'docs': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']", 'symmetrical': 'False', 'blank': 'True'}), + 'due': ('django.db.models.fields.DateField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'resolved': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupMilestoneStateName']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + 'group.groupstatetransitions': { + 'Meta': {'object_name': 'GroupStateTransitions'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'previous_groupstatetransitions_states'", 'symmetrical': 'False', 'to': "orm['doc.State']"}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.State']"}) + }, + 'group.groupurl': { + 'Meta': {'object_name': 'GroupURL'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) + }, + 'group.milestonegroupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'MilestoneGroupEvent', '_ormbases': ['group.GroupEvent']}, + 'groupevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['group.GroupEvent']", 'unique': 'True', 'primary_key': 'True'}), + 'milestone': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.GroupMilestone']"}) + }, + 'group.role': { + 'Meta': {'object_name': 'Role'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}) + }, + 'group.rolehistory': { + 'Meta': {'object_name': 'RoleHistory'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.GroupHistory']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}) + }, + '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.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.groupmilestonestatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupMilestoneStateName'}, + '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.rolename': { + 'Meta': {'ordering': "['order']", 'object_name': 'RoleName'}, + '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 = ['group'] diff --git a/ietf/group/migrations/0005_auto__add_groupmilestonehistory.py b/ietf/group/migrations/0005_auto__add_groupmilestonehistory.py new file mode 100644 index 000000000..394e83cd3 --- /dev/null +++ b/ietf/group/migrations/0005_auto__add_groupmilestonehistory.py @@ -0,0 +1,349 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'GroupMilestoneHistory' + db.create_table('group_groupmilestonehistory', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.Group'])), + ('state', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.GroupMilestoneStateName'])), + ('desc', self.gf('django.db.models.fields.CharField')(max_length=500)), + ('due', self.gf('django.db.models.fields.DateField')()), + ('resolved', self.gf('django.db.models.fields.CharField')(max_length=50, blank=True)), + ('time', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), + ('milestone', self.gf('django.db.models.fields.related.ForeignKey')(related_name='history_set', to=orm['group.GroupMilestone'])), + )) + db.send_create_signal('group', ['GroupMilestoneHistory']) + + # Adding M2M table for field docs on 'GroupMilestoneHistory' + db.create_table('group_groupmilestonehistory_docs', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('groupmilestonehistory', models.ForeignKey(orm['group.groupmilestonehistory'], null=False)), + ('document', models.ForeignKey(orm['doc.document'], null=False)) + )) + db.create_unique('group_groupmilestonehistory_docs', ['groupmilestonehistory_id', 'document_id']) + + + def backwards(self, orm): + + # Deleting model 'GroupMilestoneHistory' + db.delete_table('group_groupmilestonehistory') + + # Removing M2M table for field docs on 'GroupMilestoneHistory' + db.delete_table('group_groupmilestonehistory_docs') + + + 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.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.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.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'}) + }, + 'group.changestategroupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'ChangeStateGroupEvent', '_ormbases': ['group.GroupEvent']}, + 'groupevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['group.GroupEvent']", 'unique': 'True', 'primary_key': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']"}) + }, + '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'}) + }, + 'group.groupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'GroupEvent'}, + 'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}), + 'desc': ('django.db.models.fields.TextField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + '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'}) + }, + 'group.grouphistory': { + 'Meta': {'object_name': 'GroupHistory'}, + 'acronym': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['group.Group']"}), + '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'}) + }, + 'group.groupmilestone': { + 'Meta': {'ordering': "['due', 'id']", 'object_name': 'GroupMilestone'}, + 'desc': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'docs': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']", 'symmetrical': 'False', 'blank': 'True'}), + 'due': ('django.db.models.fields.DateField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'resolved': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupMilestoneStateName']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + 'group.groupmilestonehistory': { + 'Meta': {'ordering': "['due', 'id']", 'object_name': 'GroupMilestoneHistory'}, + 'desc': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'docs': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']", 'symmetrical': 'False', 'blank': 'True'}), + 'due': ('django.db.models.fields.DateField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'milestone': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['group.GroupMilestone']"}), + 'resolved': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupMilestoneStateName']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + 'group.groupstatetransitions': { + 'Meta': {'object_name': 'GroupStateTransitions'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'previous_groupstatetransitions_states'", 'symmetrical': 'False', 'to': "orm['doc.State']"}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.State']"}) + }, + 'group.groupurl': { + 'Meta': {'object_name': 'GroupURL'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) + }, + 'group.milestonegroupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'MilestoneGroupEvent', '_ormbases': ['group.GroupEvent']}, + 'groupevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['group.GroupEvent']", 'unique': 'True', 'primary_key': 'True'}), + 'milestone': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.GroupMilestone']"}) + }, + 'group.role': { + 'Meta': {'object_name': 'Role'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}) + }, + 'group.rolehistory': { + 'Meta': {'object_name': 'RoleHistory'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.GroupHistory']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}) + }, + '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.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.groupmilestonestatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupMilestoneStateName'}, + '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.rolename': { + 'Meta': {'ordering': "['order']", 'object_name': 'RoleName'}, + '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 = ['group'] diff --git a/ietf/group/migrations/__init__.py b/ietf/group/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ietf/group/models.py b/ietf/group/models.py index 7546fd37b..8559b9931 100644 --- a/ietf/group/models.py +++ b/ietf/group/models.py @@ -66,17 +66,31 @@ class GroupURL(models.Model): def __unicode__(self): return u"%s (%s)" % (self.url, self.name) -class GroupMilestone(models.Model): +class GroupMilestoneInfo(models.Model): group = models.ForeignKey(Group) - desc = models.TextField(verbose_name="Description") - expected_due_date = models.DateField() - done = models.BooleanField() - done_date = models.DateField(null=True, blank=True) - time = models.DateTimeField(auto_now=True) + # a group has two sets of milestones, current milestones + # (active/under review/deleted) and charter milestones (active + # during a charter/recharter event), events for charter milestones + # are stored on the charter document + state = models.ForeignKey(GroupMilestoneStateName) + desc = models.CharField(verbose_name="Description", max_length=500) + due = models.DateField() + resolved = models.CharField(max_length=50, blank=True, help_text="Explanation of why milestone is resolved (usually \"Done\"), or empty if still due") + + docs = models.ManyToManyField('doc.Document', blank=True) + def __unicode__(self): return self.desc[:20] + "..." class Meta: - ordering = ['expected_due_date'] + abstract = True + ordering = ['due', 'id'] + +class GroupMilestone(GroupMilestoneInfo): + time = models.DateTimeField(auto_now=True) + +class GroupMilestoneHistory(GroupMilestoneInfo): + time = models.DateTimeField() + milestone = models.ForeignKey(GroupMilestone, related_name="history_set") class GroupStateTransitions(models.Model): """Captures that a group has overriden the default available @@ -93,6 +107,7 @@ GROUP_EVENT_CHOICES = [ ("added_comment", "Added comment"), ("info_changed", "Changed metadata"), ("requested_close", "Requested closing group"), + ("changed_milestone", "Changed milestone"), ] class GroupEvent(models.Model): @@ -112,6 +127,9 @@ class GroupEvent(models.Model): class ChangeStateGroupEvent(GroupEvent): state = models.ForeignKey(GroupStateName) +class MilestoneGroupEvent(GroupEvent): + milestone = models.ForeignKey(GroupMilestone) + class Role(models.Model): name = models.ForeignKey(RoleName) group = models.ForeignKey(Group) diff --git a/ietf/group/utils.py b/ietf/group/utils.py index 47f56a581..6eb1f5a6f 100644 --- a/ietf/group/utils.py +++ b/ietf/group/utils.py @@ -3,6 +3,7 @@ import os from django.conf import settings from ietf.group.models import * +from ietf.utils.history import get_history_object_for, copy_many_to_many_for_history def save_group_in_history(group): @@ -11,30 +12,17 @@ def save_group_in_history(group): the Group entry contain the current state. XXX TODO: Call this directly from Group.save() """ - def get_model_fields_as_dict(obj): - return dict((field.name, getattr(obj, field.name)) - for field in obj._meta.fields - if field is not obj._meta.pk) - - # copy fields - fields = get_model_fields_as_dict(group) - del fields["charter"] # Charter is saved canonically on Group - fields["group"] = group - - grouphist = GroupHistory(**fields) - grouphist.save() + h = get_history_object_for(group) + h.save() # save RoleHistory for role in group.role_set.all(): - rh = RoleHistory(name=role.name, group=grouphist, email=role.email, person=role.person) + rh = RoleHistory(name=role.name, group=h, email=role.email, person=role.person) rh.save() - # copy many to many - for field in group._meta.many_to_many: - if field.rel.through and field.rel.through._meta.auto_created: - setattr(grouphist, field.name, getattr(group, field.name).all()) + copy_many_to_many_for_history(h, group) - return grouphist + return h def get_charter_text(group): # get file path from settings. Syntesize file name from path, acronym, and suffix @@ -60,3 +48,12 @@ def get_charter_text(group): except BaseException: desc = 'Error Loading Work Group Description' return desc + +def save_milestone_in_history(milestone): + h = get_history_object_for(milestone) + h.milestone = milestone + h.save() + + copy_many_to_many_for_history(h, milestone) + + return h diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index a56b06a4d..8b5509bf9 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -150,10 +150,17 @@ def document_main(request, name, rev=None): else: ballot_summary = "No active ballot found." + chartering = get_chartering_type(doc) + + # inject milestones from group + milestones = None + if chartering and not snapshot: + milestones = doc.group.groupmilestone_set.filter(state="charter") + return render_to_response("idrfc/document_charter.html", dict(doc=doc, top=top, - chartering=get_chartering_type(doc), + chartering=chartering, content=content, txt_url=settings.CHARTER_TXT_URL + filename, revisions=revisions, @@ -161,6 +168,7 @@ def document_main(request, name, rev=None): telechat=telechat, ballot_summary=ballot_summary, group=group, + milestones=milestones, ), context_instance=RequestContext(request)) @@ -237,35 +245,36 @@ def document_history(request, name): doc = get_object_or_404(Document, docalias__name=name) top = render_document_top(request, doc, "history", name) - diff_documents = [ doc ] - diff_documents.extend(Document.objects.filter(docalias__relateddocument__source=doc, docalias__relateddocument__relationship="replaces")) - # pick up revisions from events diff_revisions = [] - seen = set() diffable = name.startswith("draft") or name.startswith("charter") or name.startswith("conflict-review") or name.startswith("status-change") - if diffable: + diff_documents = [ doc ] + diff_documents.extend(Document.objects.filter(docalias__relateddocument__source=doc, docalias__relateddocument__relationship="replaces")) + + seen = set() for e in NewRevisionDocEvent.objects.filter(type="new_revision", doc__in=diff_documents).select_related('doc').order_by("-time", "-id"): - if not (e.doc.name, e.rev) in seen: - seen.add((e.doc.name, e.rev)) + if (e.doc.name, e.rev) in seen: + continue - url = "" - if name.startswith("charter"): - h = find_history_active_at(e.doc, e.time) - url = settings.CHARTER_TXT_URL + ("%s-%s.txt" % ((h or doc).canonical_name(), e.rev)) - elif name.startswith("conflict-review"): - h = find_history_active_at(e.doc, e.time) - url = settings.CONFLICT_REVIEW_TXT_URL + ("%s-%s.txt" % ((h or doc).canonical_name(), e.rev)) - elif name.startswith("status-change"): - h = find_history_active_at(e.doc, e.time) - url = settings.STATUS_CHANGE_TXT_URL + ("%s-%s.txt" % ((h or doc).canonical_name(), e.rev)) - elif name.startswith("draft"): - # rfcdiff tool has special support for IDs - url = e.doc.name + "-" + e.rev + seen.add((e.doc.name, e.rev)) - diff_revisions.append((e.doc.name, e.rev, e.time, url)) + url = "" + if name.startswith("charter"): + h = find_history_active_at(e.doc, e.time) + url = settings.CHARTER_TXT_URL + ("%s-%s.txt" % ((h or doc).canonical_name(), e.rev)) + elif name.startswith("conflict-review"): + h = find_history_active_at(e.doc, e.time) + url = settings.CONFLICT_REVIEW_TXT_URL + ("%s-%s.txt" % ((h or doc).canonical_name(), e.rev)) + elif name.startswith("status-change"): + h = find_history_active_at(e.doc, e.time) + url = settings.STATUS_CHANGE_TXT_URL + ("%s-%s.txt" % ((h or doc).canonical_name(), e.rev)) + elif name.startswith("draft"): + # rfcdiff tool has special support for IDs + url = e.doc.name + "-" + e.rev + + diff_revisions.append((e.doc.name, e.rev, e.time, url)) # grab event history events = doc.docevent_set.all().order_by("-time", "-id").select_related("by") @@ -533,6 +542,7 @@ def document_main_idrfc(request, name, tab): '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)); diff --git a/ietf/iesg/urls.py b/ietf/iesg/urls.py index 3ec407096..aa6532e13 100644 --- a/ietf/iesg/urls.py +++ b/ietf/iesg/urls.py @@ -60,7 +60,8 @@ urlpatterns += patterns('', (r'^agenda/documents/$', views.agenda_documents), (r'^agenda/telechat-(?P\d+)-(?P\d+)-(?P\d+)-docs.tgz', views.telechat_docs_tarfile), (r'^discusses/$', views.discusses), - (r'^telechatdates/$', views.telechat_dates), + (r'^milestones', views.milestones_needing_review), + (r'^telechatdates/$', 'django.views.generic.simple.redirect_to', { 'url': '/admin/iesg/telechatdate/' }), url(r'^wgactions/$', views.working_group_actions, name="iesg_working_group_actions"), url(r'^wgactions/add/$', views.edit_working_group_action, { 'wga_id': None }, name="iesg_add_working_group_action"), url(r'^wgactions/(?P\d+)/$', views.edit_working_group_action, name="iesg_edit_working_group_action"), diff --git a/ietf/iesg/views.py b/ietf/iesg/views.py index 3bde47bb2..ba06e0f2e 100644 --- a/ietf/iesg/views.py +++ b/ietf/iesg/views.py @@ -51,11 +51,11 @@ from ietf.iesg.models import TelechatDates, TelechatAgendaItem, WGAction from ietf.idrfc.idrfc_wrapper import IdWrapper, RfcWrapper from ietf.idrfc.models import RfcIndex from ietf.idrfc.utils import update_telechat -from ietf.ietfauth.decorators import group_required +from ietf.ietfauth.decorators import group_required, role_required from ietf.idtracker.templatetags.ietf_filters import in_group from ietf.ipr.models import IprDocAlias from ietf.doc.models import Document, TelechatDocEvent, LastCallDocEvent, ConsensusDocEvent -from ietf.group.models import Group +from ietf.group.models import Group, GroupMilestone def date_threshold(): """Return the first day of the month that is 185 days ago.""" @@ -663,43 +663,25 @@ def discusses(request): return direct_to_template(request, 'iesg/discusses.html', {'docs':res}) -if not settings.USE_DB_REDESIGN_PROXY_CLASSES: - class TelechatDatesForm(forms.ModelForm): - class Meta: - model = TelechatDates - fields = ['date1', 'date2', 'date3', 'date4'] +@role_required('Area Director', 'Secretariat') +def milestones_needing_review(request): + # collect milestones, grouped on AD and group + ads = {} + for m in GroupMilestone.objects.filter(state="review").exclude(group__state="concluded", group__ad=None).distinct().select_related("group", "group__ad"): + groups = ads.setdefault(m.group.ad, {}) + milestones = groups.setdefault(m.group, []) + milestones.append(m) -@group_required('Secretariat') -def telechat_dates(request): - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - return HttpResponseRedirect("/admin/iesg/telechatdate/") + ad_list = [] + for ad, groups in ads.iteritems(): + ad_list.append(ad) + ad.groups_needing_review = sorted(groups, key=lambda g: g.acronym) + for g, milestones in groups.iteritems(): + g.milestones_needing_review = sorted(milestones, key=lambda m: m.due) - dates = TelechatDates.objects.all()[0] - - if request.method == 'POST': - if request.POST.get('rollup_dates'): - TelechatDates.objects.all().update( - date1=dates.date2, date2=dates.date3, date3=dates.date4, - date4=dates.date4 + datetime.timedelta(days=14)) - form = TelechatDatesForm(instance=dates) - else: - form = TelechatDatesForm(request.POST, instance=dates) - if form.is_valid(): - form.save(commit=False) - TelechatDates.objects.all().update(date1 = dates.date1, - date2 = dates.date2, - date3 = dates.date3, - date4 = dates.date4) - else: - form = TelechatDatesForm(instance=dates) - - from django.contrib.humanize.templatetags import humanize - for f in form.fields: - form.fields[f].label = "Date " + humanize.ordinal(form.fields[f].label[4]) - form.fields[f].thursday = getattr(dates, f).isoweekday() == 4 - - return render_to_response("iesg/telechat_dates.html", - dict(form=form), + return render_to_response('iesg/milestones_needing_review.html', + dict(ads=sorted(ad_list, key=lambda ad: ad.plain_name()), + ), context_instance=RequestContext(request)) def parse_wg_action_file(path): diff --git a/ietf/ietfworkflows/templatetags/ietf_streams.py b/ietf/ietfworkflows/templatetags/ietf_streams.py index 58dd0d8c7..f9e69803f 100644 --- a/ietf/ietfworkflows/templatetags/ietf_streams.py +++ b/ietf/ietfworkflows/templatetags/ietf_streams.py @@ -40,7 +40,9 @@ def stream_state(context, doc): data.update({'workflow': workflow, 'draft': draft, - 'state': state}) + 'state': state, + 'milestones': draft.groupmilestone_set.filter(state="active") + }) return data diff --git a/ietf/ietfworkflows/views.py b/ietf/ietfworkflows/views.py index 62bc5ecd3..26dc6f859 100644 --- a/ietf/ietfworkflows/views.py +++ b/ietf/ietfworkflows/views.py @@ -83,6 +83,7 @@ def _edit_draft_stream(request, draft, form_class=DraftTagsStateForm): stream = get_stream_from_draft(draft) history = get_workflow_history_for_draft(draft, 'objectworkflowhistoryentry') tags = get_annotation_tags_for_draft(draft) + milestones = draft.groupmilestone_set.all() return render_to_response('ietfworkflows/state_edit.html', {'draft': draft, 'state': state, @@ -91,6 +92,7 @@ def _edit_draft_stream(request, draft, form_class=DraftTagsStateForm): 'history': history, 'tags': tags, 'form': form, + 'milestones': milestones, }, context_instance=RequestContext(request)) diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index ce56ee96c..ecf1080d7 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -135,7 +135,7 @@ def agenda_infoREDESIGN(num=None): meeting_time = datetime.datetime.combine(meeting.date, datetime.time(0, 0, 0)) for g in Group.objects.filter(type="area").order_by("acronym"): history = find_history_active_at(g, meeting_time) - if history: + if history and history != g: if history.state_id == "active": ads.extend(IESGHistory().from_role(x, meeting_time) for x in history.rolehistory_set.filter(name="ad").select_related()) else: diff --git a/ietf/name/fixtures/names.xml b/ietf/name/fixtures/names.xml index ab9895adf..592204e07 100644 --- a/ietf/name/fixtures/names.xml +++ b/ietf/name/fixtures/names.xml @@ -411,35 +411,29 @@ True 0 - - No + + Active True - 0 + 1 - - Yes + + Deleted True - 0 + 2 - - Abstain + + For review True - 0 + 3 - - Block + + Chartering/rechartering True - 0 - - - No record - - True - 0 + 4 BOF diff --git a/ietf/name/migrations/0008_auto__del_groupballotpositionname__add_groupmilestonestatename.py b/ietf/name/migrations/0008_auto__del_groupballotpositionname__add_groupmilestonestatename.py new file mode 100644 index 000000000..8304ebfaa --- /dev/null +++ b/ietf/name/migrations/0008_auto__del_groupballotpositionname__add_groupmilestonestatename.py @@ -0,0 +1,183 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Deleting model 'GroupBallotPositionName' + try: + db.delete_table('name_groupballotpositionname') + except Exception: + pass + + # Adding model 'GroupMilestoneStateName' + db.create_table('name_groupmilestonestatename', ( + ('slug', self.gf('django.db.models.fields.CharField')(max_length=8, primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('desc', self.gf('django.db.models.fields.TextField')(blank=True)), + ('used', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('order', self.gf('django.db.models.fields.IntegerField')(default=0)), + )) + db.send_create_signal('name', ['GroupMilestoneStateName']) + + def backwards(self, orm): + + # Adding model 'GroupBallotPositionName' + db.create_table('name_groupballotpositionname', ( + ('used', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('slug', self.gf('django.db.models.fields.CharField')(max_length=8, primary_key=True)), + ('order', self.gf('django.db.models.fields.IntegerField')(default=0)), + ('desc', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('name', ['GroupBallotPositionName']) + + # Deleting model 'GroupMilestoneStateName' + db.delete_table('name_groupmilestonestatename') + + + models = { + '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.constraintname': { + 'Meta': {'ordering': "['order']", 'object_name': 'ConstraintName'}, + '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.groupmilestonestatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupMilestoneStateName'}, + '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.liaisonstatementpurposename': { + 'Meta': {'ordering': "['order']", 'object_name': 'LiaisonStatementPurposeName'}, + '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.meetingtypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'MeetingTypeName'}, + '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.rolename': { + 'Meta': {'ordering': "['order']", 'object_name': 'RoleName'}, + '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.sessionstatusname': { + 'Meta': {'ordering': "['order']", 'object_name': 'SessionStatusName'}, + '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'}) + }, + 'name.timeslottypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'TimeSlotTypeName'}, + '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'}) + } + } + + complete_apps = ['name'] diff --git a/ietf/name/migrations/0009_add_groupmilestonestatenames.py b/ietf/name/migrations/0009_add_groupmilestonestatenames.py new file mode 100644 index 000000000..323f20f7a --- /dev/null +++ b/ietf/name/migrations/0009_add_groupmilestonestatenames.py @@ -0,0 +1,170 @@ +# 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): + # add names + orm.GroupMilestoneStateName.objects.get_or_create(slug="active", + name="Active", + order=1) + orm.GroupMilestoneStateName.objects.get_or_create(slug="deleted", + name="Deleted", + order=2) + orm.GroupMilestoneStateName.objects.get_or_create(slug="review", + name="For review", + order=3) + orm.GroupMilestoneStateName.objects.get_or_create(slug="charter", + name="Chartering/rechartering", + order=4) + + + def backwards(self, orm): + # remove names + orm.GroupMilestoneStateName.objects.filter(slug__in=("active", "deleted", "review", "charter")).delete() + + + models = { + '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.constraintname': { + 'Meta': {'ordering': "['order']", 'object_name': 'ConstraintName'}, + '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.groupmilestonestatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupMilestoneStateName'}, + '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.liaisonstatementpurposename': { + 'Meta': {'ordering': "['order']", 'object_name': 'LiaisonStatementPurposeName'}, + '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.meetingtypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'MeetingTypeName'}, + '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.rolename': { + 'Meta': {'ordering': "['order']", 'object_name': 'RoleName'}, + '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.sessionstatusname': { + 'Meta': {'ordering': "['order']", 'object_name': 'SessionStatusName'}, + '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'}) + }, + 'name.timeslottypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'TimeSlotTypeName'}, + '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'}) + } + } + + complete_apps = ['name'] diff --git a/ietf/name/models.py b/ietf/name/models.py index e3d1e8fce..a9e8bce8b 100644 --- a/ietf/name/models.py +++ b/ietf/name/models.py @@ -20,6 +20,8 @@ class GroupStateName(NameModel): """BOF, Proposed, Active, Dormant, Concluded, Abandoned""" class GroupTypeName(NameModel): """IETF, Area, WG, RG, Team, etc.""" +class GroupMilestoneStateName(NameModel): + """Active, Deleted, For Review, Chartering""" class RoleName(NameModel): """AD, Chair""" class StreamName(NameModel): @@ -47,8 +49,6 @@ class DocReminderTypeName(NameModel): class BallotPositionName(NameModel): """ Yes, No Objection, Abstain, Discuss, Block, Recuse """ blocking = models.BooleanField(default=False) -class GroupBallotPositionName(NameModel): - """ Yes, No, Block, Abstain """ class MeetingTypeName(NameModel): """IETF, Interim""" class SessionStatusName(NameModel): diff --git a/ietf/person/forms.py b/ietf/person/forms.py index 46c80314c..bf68544f0 100644 --- a/ietf/person/forms.py +++ b/ietf/person/forms.py @@ -14,22 +14,30 @@ def json_emails(emails): return simplejson.dumps([{"id": e.address + "", "name": escape(u"%s <%s>" % (e.person.name, e.address))} for e in emails]) class EmailsField(forms.CharField): + """Multi-select field using jquery.tokeninput.js. Since the API of + tokeninput" is asymmetric, we have to pass it a JSON + representation on the way out and parse the ids coming back as a + comma-separated list on the way in.""" + def __init__(self, *args, **kwargs): kwargs["max_length"] = 1000 if not "help_text" in kwargs: kwargs["help_text"] = "Type in name to search for person" super(EmailsField, self).__init__(*args, **kwargs) - self.widget.attrs["class"] = "emails-field" + self.widget.attrs["class"] = "tokenized-field" self.widget.attrs["data-ajax-url"] = lazy(urlreverse, str)("ajax_search_emails") # make this lazy to prevent initialization problem + def parse_tokenized_value(self, value): + return Email.objects.filter(address__in=[x.strip() for x in value.split(",") if x.strip()]).select_related("person") + def prepare_value(self, value): if not value: return "" - if isinstance(value, str): - return value + if isinstance(value, str) or isinstance(value, unicode): + value = self.parse_tokenized_value(value) return json_emails(value) def clean(self, value): value = super(EmailsField, self).clean(value) - return Email.objects.filter(address__in=[x.strip() for x in value.split(",") if x.strip()]).select_related("person") + return self.parse_tokenized_value(value) diff --git a/ietf/person/models.py b/ietf/person/models.py index cababcda8..d292019e5 100644 --- a/ietf/person/models.py +++ b/ietf/person/models.py @@ -107,8 +107,8 @@ class Email(models.Model): return self.person.plain_name() if self.person else self.address def formatted_email(self): - if self.person and self.person.name: - return u'"%s" <%s>' % (self.person.plain_name(), self.address) + if self.person and self.person.ascii: + return u'"%s" <%s>' % (self.person.ascii, self.address) else: return self.address diff --git a/ietf/templates/base_leftmenu.html b/ietf/templates/base_leftmenu.html index a06495e69..d4b0462ce 100644 --- a/ietf/templates/base_leftmenu.html +++ b/ietf/templates/base_leftmenu.html @@ -44,12 +44,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  • My Documents (new)
  • Next Telechat
  • Discusses
  • +
  • Milestones
  • + {# FIXME: this link should be removed when the old WG Actions are completely dead #}
  • Working Groups
  • {% endif %} {% if user|in_group:"Secretariat" %}
  • Secretariat
  • -
  • Telechat Dates
  • +
  • Telechat Dates
  • Management Items
  • +
  • Milestones
  • + {# FIXME: this link should be removed when the old WG Actions are completely dead #}
  • Working Groups
  • Sync discrepancies {% endif %} diff --git a/ietf/templates/idrfc/doc_tab_document_id.html b/ietf/templates/idrfc/doc_tab_document_id.html index cbffffb65..83858fa25 100644 --- a/ietf/templates/idrfc/doc_tab_document_id.html +++ b/ietf/templates/idrfc/doc_tab_document_id.html @@ -99,9 +99,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% 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 %} - + {{ 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 %} @@ -109,7 +110,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {{ 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 %} + {% if stream_info.tags %}
    {% for tag in stream_info.tags %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endif %} {% endif %} diff --git a/ietf/templates/idrfc/document_charter.html b/ietf/templates/idrfc/document_charter.html index b63680aba..5070cc851 100644 --- a/ietf/templates/idrfc/document_charter.html +++ b/ietf/templates/idrfc/document_charter.html @@ -47,7 +47,6 @@ {% if chartering == "initial" %} - (Initial Chartering){% endif %} {% if chartering == "rechartering" %} - (Rechartering){% endif %} - {% if not snapshot and chartering %} @@ -134,11 +133,25 @@ {% endif %} -{% if doc.rev %} +{% if doc.rev != "" %}
    {{ content|safe|keep_spacing|sanitize_html|wordwrap:80|safe }}
    {% endif %} +{% if not snapshot and chartering %} +

    Proposed Milestones +{% if user|has_role:"Area Director,Secretariat" %} +Edit charter milestones +{% endif %} +

    + +{% if milestones %} +{% include "wginfo/milestones.html" %} +{% else %} +

    No milestones for charter found.

    +{% endif %} +{% endif %} + {% endblock %} diff --git a/ietf/templates/iesg/milestones_needing_review.html b/ietf/templates/iesg/milestones_needing_review.html new file mode 100644 index 000000000..f4c0b47d0 --- /dev/null +++ b/ietf/templates/iesg/milestones_needing_review.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} + +{% block title %}Milestones Needing Review{% endblock %} + +{% block morecss %} +h3.ad { margin-bottom: 0.5em; } +div.milestones-for-group { margin: 0.5em 0; } +{% endblock %} + +{% block content %} +

    Milestones Needing Review

    + +{% for ad in ads %} +

    {{ ad.plain_name }}

    + +{% for g in ad.groups_needing_review %} + +
    {{ g.name }} ({{ g.acronym }}) has new milestones:
    + +{% with g.milestones_needing_review as milestones %} +{% include "wginfo/milestones.html" %} +{% endwith %} + +{% endfor %} +{% endfor %} + +{% endblock %} diff --git a/ietf/templates/iesg/telechat_dates.html b/ietf/templates/iesg/telechat_dates.html deleted file mode 100644 index b3dcb4a46..000000000 --- a/ietf/templates/iesg/telechat_dates.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Manage Telechat Dates{% endblock %} - -{% block content %} -

    Manage Telechat Dates

    - -
    - -{% for f in form %} - - - - - -{% endfor %} -
    {{ f.label_tag }}{{ f }}{% if not f.field.thursday %}NOT THURSDAY{% endif %}
    - -
    - - - -
    - -
    -{% endblock %} diff --git a/ietf/templates/ietfworkflows/state_edit.html b/ietf/templates/ietfworkflows/state_edit.html index b2c281fa4..19f0265a4 100644 --- a/ietf/templates/ietfworkflows/state_edit.html +++ b/ietf/templates/ietfworkflows/state_edit.html @@ -29,6 +29,19 @@ table.edit-form-tags ul li { padding: 0px; } Return to document view

    + +{% if state and state.slug == "wg-doc" and not milestones %} +

    This document is not part of any milestone. You may wish to add it to one.

    +{% endif %} + +{% if state and state.slug == "sub-pub" and milestones %} +

    This document is part of {% if milestones|length > 1 %}{{ milestones|length }} +milestones{% else %}a milestone{% endif %}. Now that the draft is +submitted to IESG for publication, you may wish to +update the +milestone{{ milestones|pluralize }}.

    +{% endif %} + diff --git a/ietf/templates/ietfworkflows/stream_state.html b/ietf/templates/ietfworkflows/stream_state.html index fa7d02234..d06c4ac1e 100644 --- a/ietf/templates/ietfworkflows/stream_state.html +++ b/ietf/templates/ietfworkflows/stream_state.html @@ -3,6 +3,7 @@
    {% if stream %} {% if state %}{{ state.name }}{% else %}{{ stream }}{% endif %} +{% if milestones %}{% for m in milestones %}{{ m.due|date:"M Y" }}{% endfor %}{% endif %} {% else %} No stream assigned {% endif %} diff --git a/ietf/templates/wgcharter/action_text.txt b/ietf/templates/wgcharter/action_text.txt index 30f7435de..bee83bc6c 100644 --- a/ietf/templates/wgcharter/action_text.txt +++ b/ietf/templates/wgcharter/action_text.txt @@ -1,8 +1,8 @@ {% load ietf_filters %}{% autoescape off %}From: The IESG -To: IETF-Announce {% if wg.list_email %} -Cc: {{ wg.acronym }} WG <{{ wg.list_email }}> {% endif %} -Subject: WG Action: {{ action_type }} {{ wg.name }} ({{ wg.acronym }}) +To: IETF-Announce {% if group.list_email %} +Cc: {{ group.acronym }} {{ group.type.name }} <{{ group.list_email }}> {% endif %} +Subject: WG Action: {{ action_type }} {{ group.name }} ({{ group.acronym }}) -{% filter wordwrap:73 %}{% ifequal action_type "Formed" %}A new IETF working group has been formed in the {{ wg.parent.name }}.{% endifequal %}{% ifequal action_type "Rechartered" %}The {{ wg.name }} ({{ wg.acronym }}) working group in the {{ wg.parent.name }} of the IETF has been rechartered.{% endifequal %} For additional information please contact the Area Directors or the WG Chair{{ chairs|pluralize}}. +{% filter wordwrap:73 %}{% ifequal action_type "Formed" %}A new IETF working group has been formed in the {{ group.parent.name }}.{% endifequal %}{% ifequal action_type "Rechartered" %}The {{ group.name }} ({{ group.acronym }}) working group in the {{ group.parent.name }} of the IETF has been rechartered.{% endifequal %} For additional information please contact the Area Directors or the {{ group.type.name }} Chair{{ chairs|pluralize}}. -{% include "wgcharter/wg_info.txt" %}{% endfilter %}{% endautoescape %} +{% include "wgcharter/group_info.txt" %}{% endfilter %}{% endautoescape %} diff --git a/ietf/templates/wgcharter/charter_with_milestones.txt b/ietf/templates/wgcharter/charter_with_milestones.txt new file mode 100644 index 000000000..cfa74b052 --- /dev/null +++ b/ietf/templates/wgcharter/charter_with_milestones.txt @@ -0,0 +1,8 @@ +{% load ietf_filters %}{% autoescape off %}{% filter wrap_long_lines %}{{ charter_text }}{% endfilter %} + +Milestones + +{% for milestone in milestones %}{% if milestone.resolved %}{{ milestone.resolved|ljust:8 }}{% else %}{{ milestone.due|date:"M Y" }}{% endif %} - {{ milestone.desc_filled }}{% for d in milestone.docs.all %} + o {{ d.name }}{% endfor %} + +{% endfor %}{% endautoescape %} diff --git a/ietf/templates/wgcharter/email_secretariat.txt b/ietf/templates/wgcharter/email_secretariat.txt index 140714df6..4b8480fe7 100644 --- a/ietf/templates/wgcharter/email_secretariat.txt +++ b/ietf/templates/wgcharter/email_secretariat.txt @@ -1,6 +1,6 @@ {% load ietf_filters %}{% autoescape off %} {{ text|fill:70 }} -WG: {{ wg_url }} +{{ group.type.name}}: {{ group_url }} Charter: {{ charter_url }} {% endautoescape %} diff --git a/ietf/templates/wgcharter/group_info.txt b/ietf/templates/wgcharter/group_info.txt new file mode 100644 index 000000000..4d21461ec --- /dev/null +++ b/ietf/templates/wgcharter/group_info.txt @@ -0,0 +1,28 @@ +{{ group.name }} ({{ group.acronym }}) +------------------------------------------------ +Current Status: {{ group.state.name }} {{ group.type.name }} + +{% if chairs %}Chairs: +{% for r in chairs %} {{ r.person.plain_name }} <{{r.email.address}}> +{% endfor %} +{% endif %}{% if secr %}Secretaries: +{% for r in secr %} {{ r.person.plain_name }} <{{r.email.address}}> +{% endfor %} +{% endif %}{% if techadv %}Technical advisors: +{% for r in techadv %} {{ r.person.plain_name }} <{{r.email.address}}> +{% endfor %} +{% endif %}{% if group.ad %}Assigned Area Director: + {{ group.ad.plain_name }} <{{ ad_email }}> + +{% endif %}{% if group.list_email %}Mailing list + Address: {{ group.list_email }} + To Subscribe: {{ group.list_subscribe }} + Archive: {{ group.list_archive }} +{% endif %} +Charter: + +{{ charter_text }} + +Milestones: +{% for milestone in milestones %} {% if milestone.resolved %}{{ milestone.resolved }} {% else %}{{ milestone.due|date:"M Y" }}{% endif %} - {{ milestone.desc|safe }} +{% endfor %} diff --git a/ietf/templates/wgcharter/review_text.txt b/ietf/templates/wgcharter/review_text.txt index a683516e9..de8c83c28 100644 --- a/ietf/templates/wgcharter/review_text.txt +++ b/ietf/templates/wgcharter/review_text.txt @@ -1,8 +1,8 @@ {% load ietf_filters %}{% autoescape off %}From: The IESG -To: IETF-Announce {% if wg.list_email %} -Cc: {{ wg.acronym }} WG <{{ wg.list_email }}> {% endif %} -Subject: WG Review: {{ wg.name }} ({{ wg.acronym }}) +To: IETF-Announce {% if group.list_email %} +Cc: {{ group.acronym }} {{ group.type.name }} <{{ group.list_email }}> {% endif %} +Subject: WG Review: {{ group.name }} ({{ group.acronym }}) -{% filter wordwrap:73 %}{% ifequal review_type "new" %}A new IETF working group has been proposed in the {{ wg.parent.name }}.{% endifequal %}{% ifequal review_type "recharter" %}The {{ wg.name }} ({{wg.acronym}}) working group in the {{ wg.parent.name }} of the IETF is undergoing rechartering.{% endifequal %} The IESG has not made any determination yet. The following draft charter was submitted, and is provided for informational purposes only. Please send your comments to the IESG mailing list (iesg at ietf.org) by {{ review_date }}. +{% filter wordwrap:73 %}{% ifequal review_type "new" %}A new IETF working group has been proposed in the {{ group.parent.name }}.{% endifequal %}{% ifequal review_type "recharter" %}The {{ group.name }} ({{group.acronym}}) working group in the {{ group.parent.name }} of the IETF is undergoing rechartering.{% endifequal %} The IESG has not made any determination yet. The following draft charter was submitted, and is provided for informational purposes only. Please send your comments to the IESG mailing list (iesg at ietf.org) by {{ review_date }}. -{% include "wgcharter/wg_info.txt" %}{% endfilter %}{% endautoescape %} +{% include "wgcharter/group_info.txt" %}{% endfilter %}{% endautoescape %} diff --git a/ietf/templates/wgcharter/search_result_row.html b/ietf/templates/wgcharter/search_result_row.html deleted file mode 100644 index babfb2343..000000000 --- a/ietf/templates/wgcharter/search_result_row.html +++ /dev/null @@ -1,13 +0,0 @@ -{% comment %} -Copyright The IETF Trust 2011, All Rights Reserved -{% endcomment %} - -{% load ietf_filters %} - - - -{% include "wgcharter/date_column.html" %} -{% include "wgcharter/status_columns.html" %} - diff --git a/ietf/templates/wgcharter/submit.html b/ietf/templates/wgcharter/submit.html index 9646d452a..8cae45f6b 100644 --- a/ietf/templates/wgcharter/submit.html +++ b/ietf/templates/wgcharter/submit.html @@ -8,13 +8,13 @@ form #id_content { {% endblock %} {% block title %} -Charter submission for {{ wg.acronym }} +Charter submission for {{ group.acronym }} {{ group.type.name }} {% endblock %} {% block content %} -

    Charter submission for {{ wg.acronym }}

    +

    Charter submission for {{ group.acronym }} {{ group.type.name }}

    -

    The text will be submitted as charter-ietf-{{ wg.acronym }}-{{ next_rev }}

    +

    The text will be submitted as charter-ietf-{{ group.acronym }}-{{ next_rev }}

    Current stream
    -{{ wg.acronym|safe }} -{{ wg.name }}
    {% for field in form.visible_fields %} @@ -30,7 +30,7 @@ Charter submission for {{ wg.acronym }} diff --git a/ietf/templates/wgcharter/wg_info.txt b/ietf/templates/wgcharter/wg_info.txt deleted file mode 100644 index 209768f97..000000000 --- a/ietf/templates/wgcharter/wg_info.txt +++ /dev/null @@ -1,28 +0,0 @@ -{{ wg.name }} ({{ wg.acronym }}) ------------------------------------------------- -Current Status: {{ wg.state.name }} Working Group - -{% if chairs %}Chairs: -{% for r in chairs %} {{ r.person.plain_name }} <{{r.email.address}}> -{% endfor %} -{% endif %}{% if secr %}Secretaries: -{% for r in secr %} {{ r.person.plain_name }} <{{r.email.address}}> -{% endfor %} -{% endif %}{% if techadv %}Technical advisors: -{% for r in techadv %} {{ r.person.plain_name }} <{{r.email.address}}> -{% endfor %} -{% endif %}{% if wg.ad %}Assigned Area Director: - {{ wg.ad.plain_name }} <{{ ad_email }}> - -{% endif %}{% if wg.list_email %}Mailing list - Address: {{ wg.list_email }} - To Subscribe: {{ wg.list_subscribe }} - Archive: {{ wg.list_archive }} -{% endif %} -Charter of Working Group: - -{{ charter_text }} - -Milestones: -{% for milestone in milestones %} {% if milestone.done %}Done {% else %}{{ milestone.expected_due_date|date:"M Y" }}{% endif %} - {{ milestone.desc|safe }} -{% endfor %} diff --git a/ietf/templates/wginfo/edit.html b/ietf/templates/wginfo/edit.html index 683467eb9..ad77789a9 100644 --- a/ietf/templates/wginfo/edit.html +++ b/ietf/templates/wginfo/edit.html @@ -84,7 +84,7 @@ Create new WG or BoF {% block content_end %} - + + + + + +{% endblock %} diff --git a/ietf/templates/wginfo/milestone_form.html b/ietf/templates/wginfo/milestone_form.html new file mode 100644 index 000000000..0fb19b563 --- /dev/null +++ b/ietf/templates/wginfo/milestone_form.html @@ -0,0 +1,42 @@ +{# assumes group, form, needs_review are in the context #} + +{{ form.id }} + +
    - Back + Back
    + + + + + {% if form.desc.errors %}{% endif %} + + + + + + + + + {% if form.needs_review %} + + + + + {% endif %} +
    {{ form.desc.label_tag }}: + + {% if needs_review and form.milestone and form.milestone.state_id != "review" %} + {{ form.milestone.desc }} {{ form.desc.as_hidden }} + {% else %} + {{ form.desc }} + {% endif %} + + {{ form.delete }} {{ form.delete.label_tag }} +
    {{ form.desc.errors }}
    Due date:{{ form.due_month }} {{ form.due_year }} {{ form.due_month.errors }} {{ form.due_year.errors }} + {{ form.resolved_checkbox }} {{ form.resolved_checkbox.label_tag }} {{ form.resolved }} + {{ form.resolved.errors }} +
    Drafts: + {{ form.docs.errors }} +
    Review: + This milestone is not active yet, awaiting + AD acceptance{% if needs_review %}.{% else %}: {{ form.accept }}{% endif %} +
    diff --git a/ietf/templates/wginfo/milestones.html b/ietf/templates/wginfo/milestones.html new file mode 100644 index 000000000..ee811c291 --- /dev/null +++ b/ietf/templates/wginfo/milestones.html @@ -0,0 +1,17 @@ +{# assumes milestones is in context #} + + +{% for milestone in milestones %} + + + + +{% endfor %} +
    + {% if milestone.resolved %}{{ milestone.resolved }}{% else %}{{ milestone.due|date:"M Y" }}{% endif %} + +
    {{ milestone.desc|escape }}
    + {% for d in milestone.docs.all %} + {{ d.name }} + {% endfor %} +
    diff --git a/ietf/templates/wginfo/reminder_milestones_due.txt b/ietf/templates/wginfo/reminder_milestones_due.txt new file mode 100644 index 000000000..ad905e576 --- /dev/null +++ b/ietf/templates/wginfo/reminder_milestones_due.txt @@ -0,0 +1,7 @@ +{% autoescape off %}{% filter wordwrap:73 %}This is a reminder that milestones in "{{ group.name }}" are soon due. + +{% for m in milestones %}"{{ m.desc }}" is due {% if m.due == today %}today!{% else %}in {{ early_warning_days }} days.{% endif %} + +{% endfor %} +URL: {{ url }} +{% endfilter %}{% endautoescape %} diff --git a/ietf/templates/wginfo/reminder_milestones_need_review.txt b/ietf/templates/wginfo/reminder_milestones_need_review.txt new file mode 100644 index 000000000..e32dbfac7 --- /dev/null +++ b/ietf/templates/wginfo/reminder_milestones_need_review.txt @@ -0,0 +1,10 @@ +{% autoescape off %}{% filter wordwrap:73 %}{{ milestones|length }} new milestone{{ milestones|pluralize }} in "{{ group.name }}" {% if milestones|length > 1 %}need{% else %}needs{%endif %} an AD review: + +{% for m in milestones %}"{{ m.desc }}"{% if m.days_ready != None %} +Waiting for {{ m.days_ready }} day{{ m.days_ready|pluralize }}.{% endif %} + +{% endfor %} +Go here to either accept or reject the new milestones: + +{{ url }} +{% endfilter %}{% endautoescape %} diff --git a/ietf/templates/wginfo/reminder_milestones_overdue.txt b/ietf/templates/wginfo/reminder_milestones_overdue.txt new file mode 100644 index 000000000..9acaf096f --- /dev/null +++ b/ietf/templates/wginfo/reminder_milestones_overdue.txt @@ -0,0 +1,7 @@ +{% autoescape off %}{% filter wordwrap:73 %}This is a reminder that milestones in "{{ group.name }}" are overdue. + +{% for m in milestones %}"{{ m.desc }}" is overdue{% if m.months_overdue > 0 %} with {{ m.months_overdue }} month{{ m.months_overdue|pluralize }}{% endif %}! + +{% endfor %} +URL: {{ url }} +{% endfilter %}{% endautoescape %} diff --git a/ietf/templates/wginfo/reset_charter_milestones.html b/ietf/templates/wginfo/reset_charter_milestones.html new file mode 100644 index 000000000..eb7b08212 --- /dev/null +++ b/ietf/templates/wginfo/reset_charter_milestones.html @@ -0,0 +1,36 @@ +{% extends "base.html" %} + +{% block title %}Reset Charter Milestones for {{ group.acronym }} {{ group.type.name }}{% endblock %} + +{% block morecss %} +#reset-form .date { display: inline-block; min-width: 5em; } +{% endblock %} + +{% block content %} +{% load ietf_filters %} +

    Reset Charter Milestones for {{ group.acronym }} {{ group.type.name }}

    + +

    Select which of the current {{ group.type.name }} milestones you would like to copy to the charter. + +{% if charter_milestones %}This will discard {{ charter_milestones|length }} existing charter milestone{{ charter_milestones|pluralize }}{% endif %} +

    + + +{% for milestone in current_milestones %} +
    + +
    +{% endfor %} + +
    + Back + +
    + +{% endblock %} diff --git a/ietf/templates/wginfo/wg-charterREDESIGN.txt b/ietf/templates/wginfo/wg-charterREDESIGN.txt index ef99aa2ef..a46bb0b08 100644 --- a/ietf/templates/wginfo/wg-charterREDESIGN.txt +++ b/ietf/templates/wginfo/wg-charterREDESIGN.txt @@ -34,7 +34,7 @@ Description of Working Group: {{ wg.charter_text|indent|safe }} Goals and Milestones: -{% for milestone in wg.milestones %} {% if milestone.done %}Done {% else %}{{ milestone.expected_due_date|date:"M Y" }}{% endif %} - {{ milestone.desc|safe }} +{% for milestone in wg.milestones %} {% if milestone.resolved %}{{ milestone.resolved }} {% else %}{{ milestone.due|date:"M Y" }}{% endif %} - {{ milestone.desc|safe }} {% endfor %} Internet-Drafts: {% for alias in wg.drafts %} - {{alias.document.title|safe}} [{{alias.name}}-{{alias.document.rev}}] ({{ alias.document.pages }} pages) diff --git a/ietf/templates/wginfo/wg_charter.html b/ietf/templates/wginfo/wg_charter.html index c4aa2fcaa..3ffe76e99 100644 --- a/ietf/templates/wginfo/wg_charter.html +++ b/ietf/templates/wginfo/wg_charter.html @@ -35,119 +35,146 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% load ietf_filters %} {% block wg_titledetail %}Charter{% endblock %} -{% block wg_content %} +{% block morecss %} +{{ block.super }} +h2 a.button { margin-left: 0.5em; font-size: 13px; } +{% endblock %} +{% block wg_content %}
    {% if concluded %} Note: The data for concluded WGs is occasionally incorrect. {% endif %} - - - + - - - - - - -{% if wg.wgtechadvisor_set.count %} - - - -{% endif %} -{% if wg.wgeditor_set.count %} - - -{% endif %} -{% if wg.secretaries %} - - -{% endif %} + + + + - - - + - - - + {% if wg.parent %} + + {% endif %} -{% if not concluded %} - - - + + + + - - -{% endif %} + + + + + + + + + + + + + + + + {% if wg.techadvisors %} + + + + + {% endif %} + {% if wg.editors %} + + + {% endif %} + {% if wg.secretaries %} + + + + + {% endif %} + + + + + + + + {% if not concluded %} + + + + + {% endif %}
    -Personnel -
    Group
    Chair{{ wg.chairs.count|pluralize:",s" }}: -{% for chair in wg.chairs %} -{{ chair.person|escape }} <{{ chair.person.email.1 }}>
    -{% endfor %} -
    Area Director: -{% ifequal wg.area_director.person.email.1 "noreply@ietf.org" %}?{%else%} -{{ wg.area_director.person }} <{{wg.area_director.person.email.1 }}>{% endifequal %} -
    Tech Advisor{{ wg.wgtechadvisor_set.count|pluralize:",s" }}: -{% for techadvisor in wg.wgtechadvisor_set.all %} -{{ techadvisor.person }} <{{ techadvisor.person.email.1 }}>
    -{% endfor %} -
    Editor{{ wg.wgeditor_set.count|pluralize:",s" }}: -{% for editor in wg.wgeditor_set.all %} -{{ editor.person }} <{{ editor.person.email.1 }}>
    -{% endfor %} -
    Secretar{{ wg.secretaries.count|pluralize:"y,ies" }}: -{% for secretary in wg.secretaries %} -{{ secretary.person }} <{{ secretary.person.email.1 }}>
    -{% endfor %} -
    Name:{{ wg.name }}
    -
    Mailing List -
    Acronym:{{ wg.acronym }}
    Address:{{ wg.email_address|urlize }}
    To Subscribe:{{ wg.email_subscribe|urlize }}
    Archive:{{ wg.clean_email_archive|urlize }}
    Area:{{ wg.parent.name }} ({{ wg.parent.acronym }})
    -
    Jabber Chat -
    State:{{ wg.state.name }} + {% if requested_close %} + (but in the process of being closed) + {% endif %} +
    Room Address:xmpp:{{wg}}@jabber.ietf.org
    Logs:http://jabber.ietf.org/logs/{{wg}}/
    Charter: + {% if wg.charter %} + {{ wg.charter.name }}-{{ wg.charter.rev }} ({{ wg.charter.get_state.name }}) + {% else %} + none + {% if user|has_role:"Area Director,Secretariat" %} + - Submit Charter + {% endif %} + {% endif %} +
    Personnel
    Chair{{ wg.chairs|pluralize }}: + {% for chair in wg.chairs %} + {{ chair.person.plain_name }} <{{ chair.address }}>
    + {% endfor %} +
    Area Director: + {% if not wg.ad %}?{% else %} + {{ wg.ad.plain_name }} <{{ wg.areadirector.address }}>{% endif %} +
    Tech Advisor{{ wg.techadvisors|pluralize }}: + {% for techadvisor in wg.techadvisors %} + {{ techadvisor.person.plain_name }} <{{ techadvisor.address }}>
    + {% endfor %} +
    Editor{{ wg.editors|pluralize }}: + {% for editor in wg.editors %} + {{ editor.person.plain_name }} <{{ editor.address }}>
    + {% endfor %} +
    Secretar{{ wg.secretaries|pluralize:"y,ies" }}: + {% for secretary in wg.secretaries %} + {{ secretary.person.plain_name }} <{{ secretary.address }}>
    + {% endfor %} +
    Mailing List
    Address:{{ wg.email_address|urlize }}
    To Subscribe:{{ wg.email_subscribe|urlize }}
    Archive:{{ wg.clean_email_archive|urlize }}
    Jabber Chat
    Room Address:xmpp:{{ wg.acronym }}@jabber.ietf.org
    Logs:http://jabber.ietf.org/logs/{{ wg.acronym }}/
    + +{% if user|has_role:"Area Director,Secretariat" %} +
    + {% for name, url in actions %} + {{ name }} + {% if not forloop.last %}|{% endif %} + {% endfor %} +
    +{% endif %}
    {% if wg.additional_urls %}

    In addition to the charter maintained by the IETF Secretariat, there is additional information about this working group on the Web at: {% for url in wg.additional_urls %} -{{ url.description}}{% if not forloop.last %}, {% endif %} +{{ url.name }}{% if not forloop.last %}, {% endif %} {% endfor %}

    {% endif %} -

    Description of Working Group

    +

    Charter for Working Group

    {{ wg.charter_text|escape|format_charter|safe }}

    -

    Goals and Milestones

    - -{% for milestone in wg.milestones %} - - - -{% endfor %} -
    - {% ifequal milestone.done 'Done' %} Done - {% else %} - {%ifequal milestone.expected_due_date.month 1 %}Jan{% endifequal %} - {%ifequal milestone.expected_due_date.month 2 %}Feb{% endifequal %} - {%ifequal milestone.expected_due_date.month 3 %}Mar{% endifequal %} - {%ifequal milestone.expected_due_date.month 4 %}Apr{% endifequal %} - {%ifequal milestone.expected_due_date.month 5 %}May{% endifequal %} - {%ifequal milestone.expected_due_date.month 6 %}Jun{% endifequal %} - {%ifequal milestone.expected_due_date.month 7 %}Jul{% endifequal %} - {%ifequal milestone.expected_due_date.month 8 %}Aug{% endifequal %} - {%ifequal milestone.expected_due_date.month 9 %}Sep{% endifequal %} - {%ifequal milestone.expected_due_date.month 10 %}Oct{% endifequal %} - {%ifequal milestone.expected_due_date.month 11 %}Nov{% endifequal %} - {%ifequal milestone.expected_due_date.month 12 %}Dec{% endifequal %} - {{ milestone.expected_due_date.year }} - {% endifequal %} - {{ milestone.description|escape }} -
    -{% endblock wg_content %} +

    Milestones +{% if user|has_role:"Area Director,Secretariat" or is_chair %} +Add or edit milestones +{% endif %} +

    +{% with wg.milestones as milestones %}{% include "wginfo/milestones.html" %}{% endwith %} + +{% if milestones_in_review %} +

    + {{ milestones_in_review|length }} new milestone{{ milestones_in_review|pluralize }} +currently in Area Director review.

    +{% endif %} +{% endblock wg_content %} diff --git a/ietf/templates/wginfo/wg_charterREDESIGN.html b/ietf/templates/wginfo/wg_charterREDESIGN.html deleted file mode 100644 index 1f762ba56..000000000 --- a/ietf/templates/wginfo/wg_charterREDESIGN.html +++ /dev/null @@ -1,174 +0,0 @@ -{% extends "wginfo/wg_base.html" %} -{% comment %} -Copyright (C) 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 wg_titledetail %}Charter{% endblock %} - -{% block wg_content %} -
    -{% if concluded %} -Note: The data for concluded WGs -is occasionally incorrect. -{% endif %} - - - - - - - - - - - {% if wg.parent %} - - {% endif %} - - - - - - - - - - - - - - - - - - - - - - {% if wg.techadvisors %} - - - - - {% endif %} - {% if wg.editors %} - - - {% endif %} - {% if wg.secretaries %} - - - - - {% endif %} - - - - - - - - {% if not concluded %} - - - - - {% endif %} - -
    Group
    Name:{{ wg.name }}
    Acronym:{{ wg.acronym }}
    Area:{{ wg.parent.name }} ({{ wg.parent.acronym }})
    State:{{ wg.state.name }} - {% if requested_close %} - (but in the process of being closed) - {% endif %} -
    Charter: - {% if wg.charter %} - {{ wg.charter.name }}-{{ wg.charter.rev }} ({{ wg.charter.get_state.name }}) - {% else %} - none - {% if user|has_role:"Area Director,Secretariat" %} - - Submit Charter - {% endif %} - {% endif %} -
    Personnel
    Chair{{ wg.chairs|pluralize }}: - {% for chair in wg.chairs %} - {{ chair.person.plain_name }} <{{ chair.address }}>
    - {% endfor %} -
    Area Director: - {% if not wg.ad %}?{% else %} - {{ wg.ad.plain_name }} <{{ wg.areadirector.address }}>{% endif %} -
    Tech Advisor{{ wg.techadvisors|pluralize }}: - {% for techadvisor in wg.techadvisors %} - {{ techadvisor.person.plain_name }} <{{ techadvisor.address }}>
    - {% endfor %} -
    Editor{{ wg.editors|pluralize }}: - {% for editor in wg.editors %} - {{ editor.person.plain_name }} <{{ editor.address }}>
    - {% endfor %} -
    Secretar{{ wg.secretaries|pluralize:"y,ies" }}: - {% for secretary in wg.secretaries %} - {{ secretary.person.plain_name }} <{{ secretary.address }}>
    - {% endfor %} -
    Mailing List
    Address:{{ wg.email_address|urlize }}
    To Subscribe:{{ wg.email_subscribe|urlize }}
    Archive:{{ wg.clean_email_archive|urlize }}
    Jabber Chat
    Room Address:xmpp:{{ wg.acronym }}@jabber.ietf.org
    Logs:http://jabber.ietf.org/logs/{{ wg.acronym }}/
    - -{% if user|has_role:"Area Director,Secretariat" %} -
    - {% for name, url in actions %} - {{ name }} - {% if not forloop.last %}|{% endif %} - {% endfor %} -
    -{% endif %} -
    - -{% if wg.additional_urls %} -

    In addition to the charter maintained by the IETF Secretariat, there is additional information about this working group on the Web at: -{% for url in wg.additional_urls %} -{{ url.name }}{% if not forloop.last %}, {% endif %} -{% endfor %} -

    -{% endif %} - -

    Description of Working Group

    -

    {{ wg.charter_text|escape|format_charter|safe }}

    - -

    Goals and Milestones

    - -{% for milestone in wg.milestones %} - - - -{% endfor %} -
    - {% if milestone.done %}Done{% else %}{{ milestone.expected_due_date|date:"M Y" }}{% endif %} - {{ milestone.desc|escape }} -
    -{% endblock wg_content %} diff --git a/ietf/utils/history.py b/ietf/utils/history.py index e0b790044..24f72e55a 100644 --- a/ietf/utils/history.py +++ b/ietf/utils/history.py @@ -1,17 +1,18 @@ def find_history_active_at(obj, time): - """Assumes obj has a corresponding history object (e.g. obj could - be Person with a corresponding PersonHistory model), then returns - the history object active at time, or None if the object itself - was active at the time. + """Assumes obj has a corresponding history model (e.g. obj could + be Person with a corresponding PersonHistory model), then either + returns the object itself if it was active at time, or the history + object active at time, or None if time predates the object and its + history (assuming history is complete). For this to work, the history model must use related_name="history_set" for the foreign key connecting to the live model, both models must have a "time" DateTimeField and a history object must be saved with a copy of the old values and - time when the time field changes. + old time when the time field changes. """ if obj.time <= time: - return None + return obj histories = obj.history_set.order_by('-time') @@ -20,3 +21,40 @@ def find_history_active_at(obj, time): return h return None + +def get_history_object_for(obj): + """Construct history object for obj, i.e. instantiate history + object, copy relevant attributes and set a link to obj, but don't + save. Any customizations can be done by the caller afterwards. + Many-to-many fields are not copied (impossible without save). + + The history model must use related_name="history_set" for the + foreign key connecting to the live model for this function to be + able to discover it.""" + + history_model = obj.history_set.model + h = history_model() + + # copy attributes shared between history and obj + history_field_names = set(f.name for f in history_model._meta.fields) + + for field in obj._meta.fields: + if field is not obj._meta.pk and field.name in history_field_names: + setattr(h, field.name, getattr(obj, field.name)) + + # try setting foreign key to obj + key_name = obj._meta.object_name.lower() + if key_name in history_field_names: + setattr(h, key_name, obj) + + # we can't copy many-to-many fields as h isn't saved yet, leave + # that to caller + + return h + +def copy_many_to_many_for_history(history_obj, obj): + """Copy basic many-to-many fields from obj to history_obj.""" + # copy many to many + for field in obj._meta.many_to_many: + if field.rel.through and field.rel.through._meta.auto_created: + setattr(history_obj, field.name, getattr(obj, field.name).all()) diff --git a/ietf/utils/test_data.py b/ietf/utils/test_data.py index 019ffe138..0fa40ed9e 100644 --- a/ietf/utils/test_data.py +++ b/ietf/utils/test_data.py @@ -58,6 +58,7 @@ def make_test_data(): state_id="active", type_id="wg", parent=area, + list_email="mars-wg@ietf.org", ) charter = Document.objects.create( name="charter-ietf-" + group.acronym, @@ -80,6 +81,7 @@ def make_test_data(): state_id="proposed", type_id="wg", parent=area, + list_email="ames-wg@ietf.org", ) charter = Document.objects.create( name="charter-ietf-" + group.acronym, @@ -163,6 +165,9 @@ def make_test_data(): person=p, email=email) + mars_wg.ad = ad + mars_wg.save() + # create a bunch of ads for swarm tests for i in range(1, 10): u = User.objects.create(username="ad%s" % i) diff --git a/ietf/wgchairs/forms.py b/ietf/wgchairs/forms.py index 5e3992314..001acec7c 100644 --- a/ietf/wgchairs/forms.py +++ b/ietf/wgchairs/forms.py @@ -20,7 +20,7 @@ from workflows.models import Transition from ietf.doc.models import WriteupDocEvent from ietf.person.models import Person, Email -from ietf.group.models import Role, RoleName +from ietf.group.models import Group, Role, RoleName from ietf.group.utils import save_group_in_history from ietf.name.models import DocTagName @@ -183,7 +183,7 @@ class RemoveDelegateForm(RelatedWGForm): def save(self): delegates = self.cleaned_data.get('delete') - save_group_in_history(self.wg) + save_group_in_history(Group.objects.get(pk=self.wg.pk)) WGDelegate.objects.filter(pk__in=delegates).delete() self.set_message('success', 'Delegates removed') @@ -284,7 +284,7 @@ class AddDelegateForm(RelatedWGForm): e = Email.objects.get(address=self.cleaned_data.get('email')) if not Role.objects.filter(name="delegate", group=self.wg, person=person, email=e): created = True - save_group_in_history(self.wg) + save_group_in_history(Group.objects.get(pk=self.wg.pk)) delegate, _ = Role.objects.get_or_create( name=RoleName.objects.get(slug="delegate"), group=self.wg, person=e.person, email=e) else: diff --git a/ietf/wgcharter/feeds.py b/ietf/wgcharter/feeds.py index 31369daf8..5abf7708c 100644 --- a/ietf/wgcharter/feeds.py +++ b/ietf/wgcharter/feeds.py @@ -9,7 +9,6 @@ from django.core.urlresolvers import reverse as urlreverse from django.utils.html import strip_tags from django.utils.text import truncate_words -from ietf.utils.history import find_history_active_at from ietf.group.models import Group, GroupEvent from ietf.doc.models import DocEvent diff --git a/ietf/wgcharter/mails.py b/ietf/wgcharter/mails.py index e59da36cc..29c603b4e 100644 --- a/ietf/wgcharter/mails.py +++ b/ietf/wgcharter/mails.py @@ -13,7 +13,7 @@ from ietf.doc.models import WriteupDocEvent, DocAlias, BallotPositionDocEvent from ietf.person.models import Person from ietf.wgcharter.utils import * -def email_secretariat(request, wg, type, text): +def email_secretariat(request, group, type, text): to = ["iesg-secretary@ietf.org"] types = {} @@ -24,16 +24,17 @@ def email_secretariat(request, wg, type, text): types['state-extrev'] = "State changed to External review" types['state-iesgrev'] = "State changed to IESG review" types['state-approved'] = "Charter approved" - types['conclude'] = "Request closing of WG" + types['conclude'] = "Request closing of group" - subject = u"Regarding WG %s: %s" % (wg.acronym, types[type]) + subject = u"Regarding %s %s: %s" % (group.type.name, group.acronym, types[type]) text = strip_tags(text) send_mail(request, to, None, subject, "wgcharter/email_secretariat.txt", dict(text=text, - wg_url=settings.IDTRACKER_BASE_URL + urlreverse('wg_charter', kwargs=dict(acronym=wg.acronym)), - charter_url=settings.IDTRACKER_BASE_URL + urlreverse('doc_view', kwargs=dict(name=wg.charter.name)), + group=group, + group_url=settings.IDTRACKER_BASE_URL + urlreverse('wg_charter', kwargs=dict(acronym=group.acronym)), + charter_url=settings.IDTRACKER_BASE_URL + urlreverse('doc_view', kwargs=dict(name=group.charter.name)), ) ) @@ -62,8 +63,8 @@ def generate_ballot_writeup(request, doc): return e -def default_action_text(wg, charter, user): - if next_approved_revision(wg.charter.rev) == "01": +def default_action_text(group, charter, user): + if next_approved_revision(group.charter.rev) == "01": action = "Formed" else: action = "Rechartered" @@ -71,38 +72,38 @@ def default_action_text(wg, charter, user): e = WriteupDocEvent(doc=charter, by=user) e.by = user e.type = "changed_action_announcement" - e.desc = "WG action text was changed" + e.desc = "%s action text was changed" % group.type.name e.text = render_to_string("wgcharter/action_text.txt", - dict(wg=wg, + dict(group=group, charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(), charter_text=read_charter_text(charter), - chairs=wg.role_set.filter(name="chair"), - secr=wg.role_set.filter(name="secr"), - techadv=wg.role_set.filter(name="techadv"), - milestones=wg.groupmilestone_set.all(), - ad_email=wg.ad.role_email("ad") if wg.ad else None, + chairs=group.role_set.filter(name="chair"), + secr=group.role_set.filter(name="secr"), + techadv=group.role_set.filter(name="techadv"), + milestones=group.groupmilestone_set.filter(state="charter"), + ad_email=group.ad.role_email("ad") if group.ad else None, action_type=action, )) e.save() return e -def default_review_text(wg, charter, user): +def default_review_text(group, charter, user): e = WriteupDocEvent(doc=charter, by=user) e.by = user e.type = "changed_review_announcement" - e.desc = "WG review text was changed" + e.desc = "%s review text was changed" % group.type.name e.text = render_to_string("wgcharter/review_text.txt", - dict(wg=wg, + dict(group=group, charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(), charter_text=read_charter_text(charter), - chairs=wg.role_set.filter(name="chair"), - secr=wg.role_set.filter(name="secr"), - techadv=wg.role_set.filter(name="techadv"), - milestones=wg.groupmilestone_set.all(), - ad_email=wg.ad.role_email("ad") if wg.ad else None, + chairs=group.role_set.filter(name="chair"), + secr=group.role_set.filter(name="secr"), + techadv=group.role_set.filter(name="techadv"), + milestones=group.groupmilestone_set.filter(state="charter"), + ad_email=group.ad.role_email("ad") if group.ad else None, review_date=(datetime.date.today() + datetime.timedelta(weeks=1)).isoformat(), - review_type="new" if wg.state_id == "proposed" else "recharter", + review_type="new" if group.state_id == "proposed" else "recharter", ) ) e.save() diff --git a/ietf/wgcharter/tests.py b/ietf/wgcharter/tests.py index 90892e8d3..b6208a631 100644 --- a/ietf/wgcharter/tests.py +++ b/ietf/wgcharter/tests.py @@ -197,7 +197,7 @@ class EditCharterTestCase(django.test.TestCase): self.assertEquals(f.read(), "Windows line\nMac line\nUnix line\n" + utf_8_snippet) -class CharterApproveBallotTestCase(django.test.TestCase): +class ApproveCharterTestCase(django.test.TestCase): fixtures = ['names'] def setUp(self): @@ -232,6 +232,28 @@ class CharterApproveBallotTestCase(django.test.TestCase): charter.set_state(State.objects.get(used=True, type="charter", slug="iesgrev")) + due_date = datetime.date.today() + datetime.timedelta(days=180) + m1 = GroupMilestone.objects.create(group=group, + state_id="active", + desc="Has been copied", + due=due_date, + resolved="") + m2 = GroupMilestone.objects.create(group=group, + state_id="active", + desc="To be deleted", + due=due_date, + resolved="") + m3 = GroupMilestone.objects.create(group=group, + state_id="charter", + desc="Has been copied", + due=due_date, + resolved="") + m4 = GroupMilestone.objects.create(group=group, + state_id="charter", + desc="New charter milestone", + due=due_date, + resolved="") + # normal get r = self.client.get(url) self.assertEquals(r.status_code, 200) @@ -255,3 +277,8 @@ class CharterApproveBallotTestCase(django.test.TestCase): self.assertEquals(len(outbox), mailbox_before + 2) self.assertTrue("WG Action" in outbox[-1]['Subject']) self.assertTrue("Charter approved" in outbox[-2]['Subject']) + + self.assertEquals(group.groupmilestone_set.filter(state="charter").count(), 0) + self.assertEquals(group.groupmilestone_set.filter(state="active").count(), 2) + self.assertEquals(group.groupmilestone_set.filter(state="active", desc=m1.desc).count(), 1) + self.assertEquals(group.groupmilestone_set.filter(state="active", desc=m4.desc).count(), 1) diff --git a/ietf/wgcharter/testurl.list b/ietf/wgcharter/testurl.list deleted file mode 100644 index fe9e47c8f..000000000 --- a/ietf/wgcharter/testurl.list +++ /dev/null @@ -1,55 +0,0 @@ -200 / -200 /wgcharter/ - -# In IESG process -200 /wgcharter/in_process/ - -# by AD -# current AD -- needs to be updated at some point -200 /wgcharter/ad/aread.irector/ -# former AD -200 /wgcharter/ad/exaread.irector/ -404 /wgcharter/ad/no.body/ - -# create -302 /wgcharter/create/ - -# WG -200 /wgcharter/mars/ -200 /wgcharter/mars/00-00/ -200 /wgcharter/mars/_ballot.data - -# Edit WG -302 /wgcharter/mars/edit/state/ -302 /wgcharter/mars/edit/info/ -302 /wgcharter/mars/edit/conclude/ -302 /wgcharter/mars/edit/addcomment/ -302 /wgcharter/mars/edit/action/ -302 /wgcharter/mars/edit/review/ - -# ballots -302 /wgcharter/mars/edit/position/ -302 /wgcharter/mars/edit/sendballotcomment/ -302 /wgcharter/mars/edit/approveballot/ - -# submission of charters -302 /wgcharter/mars/submit/ - -# search -200 /wgcharter/search/ -302 /wgcharter/search/?name=martian -200 /wgcharter/search/?name=something -200 /wgcharter/search/?name=something&by=acronym&acronym=some -200 /wgcharter/search/?name=something&by=state&state=active&charter_state= -200 /wgcharter/search/?name=something&by=state&state=&charter_state=approved -200 /wgcharter/search/?name=something&by=ad&ad=1 -200 /wgcharter/search/?name=something&by=area&area=2 -200 /wgcharter/search/?name=something&by=anyfield&anyfield=something -200 /wgcharter/search/?name=something&by=eacronym&eacronym=someold - -# searchPerson (ajax) -200 /wgcharter/searchPerson/ - -# - - diff --git a/ietf/wgcharter/urls.py b/ietf/wgcharter/urls.py index 91adfb355..e93a7f089 100644 --- a/ietf/wgcharter/urls.py +++ b/ietf/wgcharter/urls.py @@ -12,5 +12,6 @@ urlpatterns = patterns('', url(r'^ballotwriteupnotes/$', "ietf.wgcharter.views.ballot_writeupnotes"), url(r'^approve/$', "ietf.wgcharter.views.approve", name='charter_approve'), url(r'^submit/$', "ietf.wgcharter.views.submit", name='charter_submit'), - url(r'^submit/(?P