Merge in milestones branch
- Legacy-Id: 5091
This commit is contained in:
commit
b19f6d8060
45
ietf/bin/send-milestone-reminders
Executable file
45
ietf/bin/send-milestone-reminders
Executable file
|
@ -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))
|
|
@ -461,6 +461,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"),
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
481
ietf/group/migrations/0001_initial.py
Normal file
481
ietf/group/migrations/0001_initial.py
Normal file
|
@ -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']
|
|
@ -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", "0006_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']
|
331
ietf/group/migrations/0003_fixup_milestone.py
Normal file
331
ietf/group/migrations/0003_fixup_milestone.py
Normal file
|
@ -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']
|
|
@ -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']
|
349
ietf/group/migrations/0005_auto__add_groupmilestonehistory.py
Normal file
349
ietf/group/migrations/0005_auto__add_groupmilestonehistory.py
Normal file
|
@ -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']
|
0
ietf/group/migrations/__init__.py
Normal file
0
ietf/group/migrations/__init__.py
Normal file
|
@ -60,17 +60,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
|
||||
|
@ -87,6 +101,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):
|
||||
|
@ -106,6 +121,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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -149,10 +149,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,
|
||||
|
@ -160,6 +167,7 @@ def document_main(request, name, rev=None):
|
|||
telechat=telechat,
|
||||
ballot_summary=ballot_summary,
|
||||
group=group,
|
||||
milestones=milestones,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
@ -202,32 +210,32 @@ 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")
|
||||
|
||||
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("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"):
|
||||
url = request.build_absolute_uri(urlreverse("charter_with_milestones_txt", kwargs=dict(name=e.doc.name, rev=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("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")
|
||||
|
@ -431,6 +439,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));
|
||||
|
||||
|
|
|
@ -60,7 +60,8 @@ urlpatterns += patterns('',
|
|||
(r'^agenda/documents/$', views.agenda_documents),
|
||||
(r'^agenda/telechat-(?P<year>\d+)-(?P<month>\d+)-(?P<day>\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<wga_id>\d+)/$', views.edit_working_group_action, name="iesg_edit_working_group_action"),
|
||||
|
|
|
@ -53,11 +53,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
|
||||
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."""
|
||||
|
@ -615,43 +615,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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -134,7 +134,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:
|
||||
|
|
|
@ -325,35 +325,29 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="no" model="name.groupballotpositionname">
|
||||
<field type="CharField" name="name">No</field>
|
||||
<object pk="active" model="name.groupmilestonestatename">
|
||||
<field type="CharField" name="name">Active</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field type="IntegerField" name="order">1</field>
|
||||
</object>
|
||||
<object pk="yes" model="name.groupballotpositionname">
|
||||
<field type="CharField" name="name">Yes</field>
|
||||
<object pk="deleted" model="name.groupmilestonestatename">
|
||||
<field type="CharField" name="name">Deleted</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field type="IntegerField" name="order">2</field>
|
||||
</object>
|
||||
<object pk="abstain" model="name.groupballotpositionname">
|
||||
<field type="CharField" name="name">Abstain</field>
|
||||
<object pk="review" model="name.groupmilestonestatename">
|
||||
<field type="CharField" name="name">For review</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field type="IntegerField" name="order">3</field>
|
||||
</object>
|
||||
<object pk="block" model="name.groupballotpositionname">
|
||||
<field type="CharField" name="name">Block</field>
|
||||
<object pk="charter" model="name.groupmilestonestatename">
|
||||
<field type="CharField" name="name">Chartering/rechartering</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="norecord" model="name.groupballotpositionname">
|
||||
<field type="CharField" name="name">No record</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field type="IntegerField" name="order">4</field>
|
||||
</object>
|
||||
<object pk="bof" model="name.groupstatename">
|
||||
<field type="CharField" name="name">BOF</field>
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
# 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'
|
||||
db.delete_table('name_groupballotpositionname')
|
||||
|
||||
# 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']
|
170
ietf/name/migrations/0006_add_groupmilestonestatenames.py
Normal file
170
ietf/name/migrations/0006_add_groupmilestonestatenames.py
Normal file
|
@ -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']
|
|
@ -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):
|
||||
|
@ -44,8 +46,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):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -43,15 +43,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<li><a href="{% url doc_search_by_ad name=user.get_profile.person.full_name_as_key %}">My Documents</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.agenda_documents %}">Next Telechat</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.discusses %}">Discusses</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.milestones_needing_review %}">Milestones</a></li>
|
||||
{# FIXME: this link should be removed when the old WG Actions are completely dead #}
|
||||
<li><a href="{% url ietf.iesg.views.working_group_actions %}">Working Groups</a></li>
|
||||
{# FIXME: wgcharter <li><a href="{% url wg_search_by_area name=user|ad_area %}">Working Groups</a></li> #}
|
||||
{% endif %}
|
||||
{% if user|in_group:"Secretariat" %}
|
||||
<li class="sect first">Secretariat</li>
|
||||
<li><a href="{% url ietf.iesg.views.telechat_dates %}">Telechat Dates</a></li>
|
||||
<li><a href="/admin/iesg/telechatdate/">Telechat Dates</a></li>
|
||||
<li><a href="/admin/iesg/telechatagendaitem/">Management Items</a></li>
|
||||
{# FIXME: this link should be removed when the old WG Actions are completely dead #}
|
||||
<li><a href="{% url ietf.iesg.views.working_group_actions %}">Working Groups</a></li>
|
||||
{# FIXME: wgcharter <li><a href="{% url wg_search_in_process %}">Working Groups</a></li> #}
|
||||
{% endif %}
|
||||
{% if user %}
|
||||
{% get_user_managed_streams user as stream_list %}
|
||||
|
|
|
@ -101,9 +101,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% ifequal stream_info.stream.name "IETF" %}
|
||||
<tr>
|
||||
<td>IETF State:</td>
|
||||
<td>{{ stream_info.state.name }} ({{ stream_info.streamed.get_group }})
|
||||
{% if stream_info.tags %}<br /><i>{% for tag in stream_info.tags %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endif %}
|
||||
</td>
|
||||
<td class="stream-state">{{ stream_info.state.name }} ({{ stream_info.streamed.get_group }})
|
||||
{% if stream_info.tags %}<br /><i>{% for tag in stream_info.tags %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}</i>{% endif %}
|
||||
{% if milestones %}{% for m in milestones %}<span title="In {{ m.group.acronym }} milestone: {{ m.desc }}" class="milestone">{{ m.due|date:"M Y" }}</span>{% endfor %}{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
{% if stream_info.stream %}
|
||||
|
@ -111,7 +112,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<td>{{ stream_info.stream.name }} status:</td>
|
||||
<td>
|
||||
{{ stream_info.state.name }} {% if stream_info.streamed.get_group %}({{ stream_info.streamed.get_group }}) {% endif %}
|
||||
{% if stream_info.tags %}<br /><i>{% for tag in stream_info.tags %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endif %}
|
||||
{% if stream_info.tags %}<br /><i>{% for tag in stream_info.tags %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}</i>{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
</a>
|
||||
{% if chartering == "initial" %} - (Initial Chartering){% endif %}
|
||||
{% if chartering == "rechartering" %} - (Rechartering){% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% if not snapshot and chartering %}
|
||||
|
@ -134,11 +133,25 @@
|
|||
{% endif %}
|
||||
</h3>
|
||||
|
||||
{% if doc.rev %}
|
||||
{% if doc.rev != "" %}
|
||||
<div class="markup_draft">
|
||||
{{ content|safe|linebreaksbr|keep_spacing|sanitize_html|safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if not snapshot and chartering %}
|
||||
<h3>Proposed Milestones
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
<a class="edit" href="{% url wg_edit_charter_milestones acronym=doc.group.acronym %}">Edit charter milestones</a>
|
||||
{% endif %}
|
||||
</h3>
|
||||
|
||||
{% if milestones %}
|
||||
{% include "wginfo/milestones.html" %}
|
||||
{% else %}
|
||||
<p>No milestones for charter found.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
27
ietf/templates/iesg/milestones_needing_review.html
Normal file
27
ietf/templates/iesg/milestones_needing_review.html
Normal file
|
@ -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 %}
|
||||
<h1>Milestones Needing Review</h1>
|
||||
|
||||
{% for ad in ads %}
|
||||
<h3 class="ad">{{ ad.plain_name }}</h4>
|
||||
|
||||
{% for g in ad.groups_needing_review %}
|
||||
|
||||
<div class="milestones-for-group">New milestones for <a href="{% url wg_edit_milestones acronym=g.acronym %}">{{ g.name }} ({{ g.acronym }})</a>:</div>
|
||||
|
||||
{% with g.milestones_needing_review as milestones %}
|
||||
{% include "wginfo/milestones.html" %}
|
||||
{% endwith %}
|
||||
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
|
@ -1,26 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Manage Telechat Dates{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Manage Telechat Dates</h1>
|
||||
|
||||
<form action="" method="POST">
|
||||
<table>
|
||||
{% for f in form %}
|
||||
<tr>
|
||||
<td>{{ f.label_tag }}</td>
|
||||
<td>{{ f }}</td>
|
||||
<td style="font-weight:bold;color:#a00">{% if not f.field.thursday %}NOT THURSDAY{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<div class="actions">
|
||||
<input type="reset" value="Reset"/>
|
||||
<input type="submit" value="Save"/>
|
||||
<input style="margin-left: 8px" type="submit" name="rollup_dates" value="Rollup"/>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -29,6 +29,19 @@ table.edit-form-tags ul li { padding: 0px; }
|
|||
<a href="{% url doc_view draft.filename %}">Return to document view</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% if state and state.slug == "wg-doc" and not milestones %}
|
||||
<p>This document is not part of any milestone. You may wish to <a href="{% url wg_edit_milestones acronym=draft.group.acronym %}">add it to one</a>.</p>
|
||||
{% endif %}
|
||||
|
||||
{% if state and state.slug == "sub-pub" and milestones %}
|
||||
<p>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
|
||||
<a href="{% url wg_edit_milestones acronym=draft.group.acronym %}">update the
|
||||
milestone{{ milestones|pluralize }}</a>.</p>
|
||||
{% endif %}
|
||||
|
||||
<table class="ietf-table" style="width: 100%;">
|
||||
<tr>
|
||||
<th>Current stream</th>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
{% if draft %}
|
||||
<div class="stream_state">
|
||||
<div class="stream_state_more" style="float: left; margin: 1px 0.5em 0 0;"><a href="{% url stream_history draft.filename %}" class="show_stream_info" title="Stream information for {{ draft.filename }}" style="text-decoration: none; color:transparent; margin: 0; padding: 0; border: 0;"><img src="/images/plus.png" style="margin: 0; padding: 0; border:0;"><img></a></div>
|
||||
<div class="stream-state">
|
||||
<div class="stream_state_more" style="float: left; margin: 1px 0.5em 0 0;"><a href="{% url stream_history draft.filename %}" class="show_stream_info" title="Stream information for {{ draft.filename }}" style="text-decoration: none; color:transparent; margin: 0; padding: 0; border: 0;"><img src="/images/plus.png" style="margin: 0; padding: 0; border:0;"></a></div>
|
||||
{% if stream %}
|
||||
{% if state %}{{ state.name }}{% else %}{{ stream }}{% endif %}
|
||||
{% if milestones %}{% for m in milestones %}<span title="Included in milestone: {{ m.desc }}" class="milestone">{{ m.due|date:"M Y" }}</span>{% endfor %}{% endif %}
|
||||
{% else %}
|
||||
No stream assigned
|
||||
{% endif %}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{% load ietf_filters %}{% autoescape off %}From: The IESG <iesg-secretary@ietf.org>
|
||||
To: IETF-Announce <ietf-announce@ietf.org>{% if wg.list_email %}
|
||||
Cc: {{ wg.acronym }} WG <{{ wg.list_email }}> {% endif %}
|
||||
Subject: WG Action: {{ action_type }} {{ wg.name }} ({{ wg.acronym }})
|
||||
To: IETF-Announce <ietf-announce@ietf.org>{% 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 %}
|
||||
|
|
8
ietf/templates/wgcharter/charter_with_milestones.txt
Normal file
8
ietf/templates/wgcharter/charter_with_milestones.txt
Normal file
|
@ -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 %}
|
|
@ -1,6 +1,6 @@
|
|||
{% load ietf_filters %}{% autoescape off %}
|
||||
{{ text|fill:70 }}
|
||||
|
||||
WG: {{ wg_url }}
|
||||
{{ group.type.name}}: {{ group_url }}
|
||||
Charter: {{ charter_url }}
|
||||
{% endautoescape %}
|
||||
|
|
28
ietf/templates/wgcharter/group_info.txt
Normal file
28
ietf/templates/wgcharter/group_info.txt
Normal file
|
@ -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 %}
|
|
@ -1,8 +1,8 @@
|
|||
{% load ietf_filters %}{% autoescape off %}From: The IESG <iesg-secretary@ietf.org>
|
||||
To: IETF-Announce <ietf-announce@ietf.org>{% if wg.list_email %}
|
||||
Cc: {{ wg.acronym }} WG <{{ wg.list_email }}> {% endif %}
|
||||
Subject: WG Review: {{ wg.name }} ({{ wg.acronym }})
|
||||
To: IETF-Announce <ietf-announce@ietf.org>{% 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 %}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
|
||||
<td class="acronym">
|
||||
<a href="{% url wg_view name=wg.acronym %}">{{ wg.acronym|safe }}</a>
|
||||
</td>
|
||||
<td class="title">{{ wg.name }}</td>
|
||||
{% include "wgcharter/date_column.html" %}
|
||||
{% include "wgcharter/status_columns.html" %}
|
||||
</tr>
|
|
@ -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 %}
|
||||
<h1>Charter submission for {{ wg.acronym }}</h1>
|
||||
<h1>Charter submission for {{ group.acronym }} {{ group.type.name }}</h1>
|
||||
|
||||
<p>The text will be submitted as <strong>charter-ietf-{{ wg.acronym }}-{{ next_rev }}</strong></p>
|
||||
<p>The text will be submitted as <strong>charter-ietf-{{ group.acronym }}-{{ next_rev }}</strong></p>
|
||||
<form class="edit-info" action="" enctype="multipart/form-data" method="POST">
|
||||
<table>
|
||||
{% for field in form.visible_fields %}
|
||||
|
@ -30,7 +30,7 @@ Charter submission for {{ wg.acronym }}
|
|||
<tr>
|
||||
<td></td>
|
||||
<td class="actions">
|
||||
<a href="{% url doc_view name=wg.charter.name %}">Back</a>
|
||||
<a href="{% url doc_view name=group.charter.name %}">Back</a>
|
||||
<input type="submit" value="Submit"/>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -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 %}
|
|
@ -84,7 +84,7 @@ Create new WG or BoF
|
|||
{% block content_end %}
|
||||
<script type="text/javascript" src="/js/lib/jquery.tokeninput.js"></script>
|
||||
<script type="text/javascript" src="/js/lib/json2.js"></script>
|
||||
<script type="text/javascript" src="/js/emails-field.js"></script>
|
||||
<script type="text/javascript" src="/js/tokenized-field.js"></script>
|
||||
<script>
|
||||
jQuery(function () {
|
||||
if (jQuery('input[name="confirmed"]').length > 0) {
|
||||
|
|
101
ietf/templates/wginfo/edit_milestones.html
Normal file
101
ietf/templates/wginfo/edit_milestones.html
Normal file
|
@ -0,0 +1,101 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
tr.milestone td { padding: 0.2em 0; cursor: pointer; vertical-align: top; }
|
||||
tr.milestone:hover { background-color: #e8f0fa; }
|
||||
td.due { width: 5em; }
|
||||
.milestone .needs-accept { font-style: italic; display: inline-block; margin-left: 0.5em; color: #2647a0; }
|
||||
.milestone .doc { display: block; padding-left: 1em; }
|
||||
.edit-milestone { display: none; }
|
||||
.edit-milestone.delete, .edit-milestone.delete input { color: #aaa !important; }
|
||||
.edit-milestone table { margin: 0.3em 0; }
|
||||
.edit-milestone table td { padding: 0.1em; }
|
||||
.edit-milestone .desc input { width: 50em; }
|
||||
.edit-milestone .due input { width: 6em; }
|
||||
.edit-milestone input[type=checkbox] { vertical-align: middle; margin: 0 0.2em 0 0.8em;}
|
||||
.edit-milestone .resolved label { vertical-align: middle; }
|
||||
.edit-milestone .delete label { vertical-align: middle; }
|
||||
.edit-milestone .accept ul { display: inline-block; margin: 0; padding: 0; }
|
||||
.edit-milestone .accept ul li { list-style: none; display: inline-block; margin: 0; padding: 0; padding-left: 0.4em; }
|
||||
.edit-milestone .accept ul li label { vertical-align: middle; }
|
||||
.edit-milestone .accept ul li input { margin: 0; padding: 0; vertical-align: middle; }
|
||||
.edit-milestone .docs td { vertical-align: top; }
|
||||
|
||||
ul.errorlist { border-width: 0px; padding: 0px; margin: 0px; display: inline-block; }
|
||||
ul.errorlist li { color: #a00; margin: 0px; padding: 0px; list-style: none; }
|
||||
p.help { font-style: italic; }
|
||||
p.error { color: #a00; font-size: larger; }
|
||||
tr.milestone.add { font-style: italic; }
|
||||
{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
<link rel="stylesheet" type="text/css" href="/css/token-input.css"></link>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% load ietf_filters %}
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
<noscript>This page depends on Javascript being enabled to work properly.</noscript>
|
||||
|
||||
<p class="help">{% if forms %}Click a milestone to edit it.{% endif %}
|
||||
|
||||
{% if needs_review %}
|
||||
Note that as {{ group.type.name }} Chair you cannot edit descriptions of existing
|
||||
milestones and milestones you add are subject to review by the Area
|
||||
Director.
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% if can_reset %}
|
||||
<p>
|
||||
You can <a href="{% url wg_reset_charter_milestones acronym=group.acronym %}">reset
|
||||
this list</a> to the currently in-use milestones for the {{ group.acronym }} {{ group.type.name }}.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if form_errors %}
|
||||
<p class="error">There were errors, see below.</p>
|
||||
{% endif %}
|
||||
|
||||
<form action="" method="post" id="milestones-form">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
{% for form in forms %}
|
||||
<tr class="milestone">
|
||||
<td class="due">{% if form.milestone.resolved %}{{ form.milestone.resolved }}{% else %}{{ form.milestone.due|date:"M Y" }}{% endif %}</td>
|
||||
<td>
|
||||
<div>{{ form.milestone.desc }}
|
||||
{% if form.needs_review %}<span class="needs-accept">awaiting accept</span>{% endif %}</div>
|
||||
|
||||
{% for d in form.docs_names %}
|
||||
<div class="doc">{{ d }}</div>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="edit-milestone"><td colspan="2">{% include "wginfo/milestone_form.html" %}</td></tr>
|
||||
{% endfor %}
|
||||
<tr class="milestone add"><td></td><td>Add {% if milestone_set == "chartering" %}charter{% endif%} milestone {% if needs_review %}for AD review{% endif %}</td></tr>
|
||||
<tr class="edit-milestone template"><td colspan="2">{% with empty_form as form %}{% include "wginfo/milestone_form.html" %}{% endwith %}</td></tr>
|
||||
</table>
|
||||
|
||||
<div class="actions">
|
||||
<a href="{% if milestone_set == "charter" %}{% url doc_view name=group.charter.canonical_name %}{% else %}{% url wg_charter acronym=group.acronym %}{% endif %}">Back</a>
|
||||
<input type="submit" data-labelsave="Save" data-labelreview="Review changes" value="Save"/>
|
||||
<input type="hidden" name="action" value="save">
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_end %}
|
||||
<script type="text/javascript" src="/js/lib/jquery.tokeninput.js"></script>
|
||||
<script type="text/javascript" src="/js/lib/json2.js"></script>
|
||||
<script type="text/javascript" src="/js/tokenized-field.js"></script>
|
||||
<script>
|
||||
var finishedMilestoneText = "{{ finished_milestone_text|escapejs }}";
|
||||
</script>
|
||||
<script type="text/javascript" src="/js/edit-milestones.js"></script>
|
||||
{% endblock %}
|
42
ietf/templates/wginfo/milestone_form.html
Normal file
42
ietf/templates/wginfo/milestone_form.html
Normal file
|
@ -0,0 +1,42 @@
|
|||
{# assumes group, form, needs_review are in the context #}
|
||||
<input type="hidden" name="prefix" value="{{ form.prefix|default:"" }}"/>
|
||||
{{ form.id }}
|
||||
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td>{{ form.desc.label_tag }}:</td>
|
||||
<td>
|
||||
<span class="desc">
|
||||
{% if needs_review and form.milestone and form.milestone.state_id != "review" %}
|
||||
{{ form.milestone.desc }} {{ form.desc.as_hidden }}
|
||||
{% else %}
|
||||
{{ form.desc }}
|
||||
{% endif %}
|
||||
</span>
|
||||
<span class="delete">{{ form.delete }} {{ form.delete.label_tag }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% if form.desc.errors %}<tr><td></td><td colspan="2">{{ form.desc.errors }}</td></tr>{% endif %}
|
||||
<tr>
|
||||
<td>Due date:</td>
|
||||
<td><span class="due">{{ form.due_month }} {{ form.due_year }}</span> {{ form.due_month.errors }} {{ form.due_year.errors }}
|
||||
<span class="resolved">{{ form.resolved_checkbox }} {{ form.resolved_checkbox.label_tag }} {{ form.resolved }}</span>
|
||||
{{ form.resolved.errors }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="docs">
|
||||
<td>Drafts:</td>
|
||||
<td><input name="{{ form.docs.html_name }}" class="tokenized-field" data-ajaxurl="{% url wg_ajax_search_docs group.acronym %}" data-pre="{{ form.docs_prepopulate }}"/>
|
||||
{{ form.docs.errors }}
|
||||
</td>
|
||||
</tr>
|
||||
{% if form.needs_review %}
|
||||
<tr class="needs-review">
|
||||
<td>Review:</td>
|
||||
<td class="accept">
|
||||
This milestone is not active yet, awaiting
|
||||
AD acceptance{% if needs_review %}.{% else %}: {{ form.accept }}{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
17
ietf/templates/wginfo/milestones.html
Normal file
17
ietf/templates/wginfo/milestones.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
{# assumes milestones is in context #}
|
||||
|
||||
<table class="milestones">
|
||||
{% for milestone in milestones %}
|
||||
<tr>
|
||||
<td class="due">
|
||||
{% if milestone.resolved %}{{ milestone.resolved }}{% else %}{{ milestone.due|date:"M Y" }}{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div>{{ milestone.desc|escape }}</div>
|
||||
{% for d in milestone.docs.all %}
|
||||
<a class="doc" href="{% url doc_view name=d.name %}">{{ d.name }}</a>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
7
ietf/templates/wginfo/reminder_milestones_due.txt
Normal file
7
ietf/templates/wginfo/reminder_milestones_due.txt
Normal file
|
@ -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 %}
|
10
ietf/templates/wginfo/reminder_milestones_need_review.txt
Normal file
10
ietf/templates/wginfo/reminder_milestones_need_review.txt
Normal file
|
@ -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 %}
|
7
ietf/templates/wginfo/reminder_milestones_overdue.txt
Normal file
7
ietf/templates/wginfo/reminder_milestones_overdue.txt
Normal file
|
@ -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 %}
|
36
ietf/templates/wginfo/reset_charter_milestones.html
Normal file
36
ietf/templates/wginfo/reset_charter_milestones.html
Normal file
|
@ -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 %}
|
||||
<h1>Reset Charter Milestones for {{ group.acronym }} {{ group.type.name }}</h1>
|
||||
|
||||
<p>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 %}
|
||||
</p>
|
||||
|
||||
<form action="" method="post" id="reset-form">
|
||||
{% for milestone in current_milestones %}
|
||||
<div>
|
||||
<label>
|
||||
<input type="checkbox" name="milestone" value="{{ milestone.id }}" {% if not milestone.resolved %}checked="checked"{% endif %} />
|
||||
|
||||
<span class="date">{% if milestone.resolved %}{{ milestone.resolved }}{% else %}{{ milestone.due|date:"M Y" }}{% endif %}</span>
|
||||
|
||||
{{ milestone.desc }}
|
||||
</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="actions">
|
||||
<a href="{% url wg_edit_charter_milestones acronym=group.acronym %}">Back</a>
|
||||
<input type="submit" value="Reset charter milestones"/>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -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)
|
||||
|
|
|
@ -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.edit { font-weight: normal; font-size: 13px; display: inline-block; margin-left: 0.5em; }
|
||||
{% endblock %}
|
||||
|
||||
{% block wg_content %}
|
||||
<div class="ietf-box ietf-wg-details">
|
||||
{% if concluded %}
|
||||
<span class="ietf-concluded-warning">Note: The data for concluded WGs
|
||||
is occasionally incorrect.</span>
|
||||
{% endif %}
|
||||
<table>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<b>Personnel</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><th colspan="2">Group</th></tr>
|
||||
|
||||
<tr valign="top">
|
||||
<td style="width:14ex;">Chair{{ wg.chairs.count|pluralize:",s" }}:</td>
|
||||
<td>
|
||||
{% for chair in wg.chairs %}
|
||||
<a href="mailto:{{ chair.person.email.1 }}">{{ chair.person|escape }} <{{ chair.person.email.1 }}></a><br/>
|
||||
{% endfor %}
|
||||
</td></tr>
|
||||
<tr><td>Area Director:</td>
|
||||
<td>
|
||||
{% ifequal wg.area_director.person.email.1 "noreply@ietf.org" %}?{%else%}
|
||||
<a href="mailto:{{ wg.area_director.person.email.1 }}">{{ wg.area_director.person }} <{{wg.area_director.person.email.1 }}></a>{% endifequal %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if wg.wgtechadvisor_set.count %}
|
||||
<tr>
|
||||
<td>Tech Advisor{{ wg.wgtechadvisor_set.count|pluralize:",s" }}:</td>
|
||||
<td>
|
||||
{% for techadvisor in wg.wgtechadvisor_set.all %}
|
||||
<a href="mailto:{{ techadvisor.person.email.1 }}">{{ techadvisor.person }} <{{ techadvisor.person.email.1 }}></a><br/>
|
||||
{% endfor %}
|
||||
</td></tr>
|
||||
{% endif %}
|
||||
{% if wg.wgeditor_set.count %}
|
||||
<td>Editor{{ wg.wgeditor_set.count|pluralize:",s" }}:</td>
|
||||
<td>
|
||||
{% for editor in wg.wgeditor_set.all %}
|
||||
<a href="mailto:{{ editor.person.email.1 }}">{{ editor.person }} <{{ editor.person.email.1 }}></a><br/>
|
||||
{% endfor %}
|
||||
</td></tr>
|
||||
{% endif %}
|
||||
{% if wg.secretaries %}
|
||||
<tr><td>Secretar{{ wg.secretaries.count|pluralize:"y,ies" }}:</td>
|
||||
<td>
|
||||
{% for secretary in wg.secretaries %}
|
||||
<a href="mailto:{{ secretary.person.email.1 }}">{{ secretary.person }} <{{ secretary.person.email.1 }}></a><br/>
|
||||
{% endfor %}
|
||||
</td></tr>
|
||||
{% endif %}
|
||||
<tr valign="top">
|
||||
<td style="width:14ex;">Name:</td>
|
||||
<td>{{ wg.name }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<br/><b>Mailing List</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td>Acronym:</td><td>{{ wg.acronym }}</td></tr>
|
||||
|
||||
<tr><td>Address:</td><td>{{ wg.email_address|urlize }}</td></tr>
|
||||
<tr><td>To Subscribe:</td><td>{{ wg.email_subscribe|urlize }}</td></tr>
|
||||
<tr><td>Archive:</td><td>{{ wg.clean_email_archive|urlize }}</td></tr>
|
||||
{% if wg.parent %}
|
||||
<tr><td>Area:</td><td>{{ wg.parent.name }} ({{ wg.parent.acronym }})</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if not concluded %}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<br/><b>Jabber Chat</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>State:</td>
|
||||
<td>{{ wg.state.name }}
|
||||
{% if requested_close %}
|
||||
(but in the process of being closed)
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td>Room Address:</td><td><a href="xmpp:{{wg}}@jabber.ietf.org">xmpp:{{wg}}@jabber.ietf.org</a></td></tr>
|
||||
<tr><td>Logs:</td><td><a href="http://jabber.ietf.org/logs/{{wg}}/">http://jabber.ietf.org/logs/{{wg}}/</a></td></tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>Charter:</td>
|
||||
<td>
|
||||
{% if wg.charter %}
|
||||
<a href="{% url doc_view name=wg.charter.name %}">{{ wg.charter.name }}-{{ wg.charter.rev }}</a> ({{ wg.charter.get_state.name }})
|
||||
{% else %}
|
||||
none
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
- <a href="{% url wginfo.edit.submit_initial_charter acronym=wg.acronym %}">Submit Charter</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><th colspan="2">Personnel</th></tr>
|
||||
|
||||
<tr valign="top">
|
||||
<td>Chair{{ wg.chairs|pluralize }}:</td>
|
||||
<td>
|
||||
{% for chair in wg.chairs %}
|
||||
<a href="mailto:{{ chair.address }}">{{ chair.person.plain_name }} <{{ chair.address }}></a><br/>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td>Area Director:</td>
|
||||
<td>
|
||||
{% if not wg.ad %}?{% else %}
|
||||
<a href="mailto:{{ wg.areadirector.address }}">{{ wg.ad.plain_name }} <{{ wg.areadirector.address }}></a>{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if wg.techadvisors %}
|
||||
<tr>
|
||||
<td>Tech Advisor{{ wg.techadvisors|pluralize }}:</td>
|
||||
<td>
|
||||
{% for techadvisor in wg.techadvisors %}
|
||||
<a href="mailto:{{ techadvisor.address }}">{{ techadvisor.person.plain_name }} <{{ techadvisor.address }}></a><br/>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if wg.editors %}
|
||||
<td>Editor{{ wg.editors|pluralize }}:</td>
|
||||
<td>
|
||||
{% for editor in wg.editors %}
|
||||
<a href="mailto:{{ editor.address }}">{{ editor.person.plain_name }} <{{ editor.address }}></a><br/>
|
||||
{% endfor %}
|
||||
</td></tr>
|
||||
{% endif %}
|
||||
{% if wg.secretaries %}
|
||||
<tr>
|
||||
<td>Secretar{{ wg.secretaries|pluralize:"y,ies" }}:</td>
|
||||
<td>
|
||||
{% for secretary in wg.secretaries %}
|
||||
<a href="mailto:{{ secretary.address }}">{{ secretary.person.plain_name }} <{{ secretary.address }}></a><br/>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
<tr><th colspan="2">Mailing List</th></tr>
|
||||
|
||||
<tr><td>Address:</td><td>{{ wg.email_address|urlize }}</td></tr>
|
||||
<tr><td>To Subscribe:</td><td>{{ wg.email_subscribe|urlize }}</td></tr>
|
||||
<tr><td>Archive:</td><td>{{ wg.clean_email_archive|urlize }}</td></tr>
|
||||
|
||||
{% if not concluded %}
|
||||
<tr><th colspan="2">Jabber Chat</th></tr>
|
||||
|
||||
<tr><td>Room Address:</td><td><a href="xmpp:{{ wg.acronym }}@jabber.ietf.org">xmpp:{{ wg.acronym }}@jabber.ietf.org</a></td></tr>
|
||||
<tr><td>Logs:</td><td><a href="http://jabber.ietf.org/logs/{{ wg.acronym }}/">http://jabber.ietf.org/logs/{{ wg.acronym }}/</a></td></tr>
|
||||
{% endif %}
|
||||
|
||||
</table>
|
||||
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
<div style="margin: 2px; margin-top: 2em;">
|
||||
{% for name, url in actions %}
|
||||
<a href="{{ url }}">{{ name }}</a>
|
||||
{% if not forloop.last %}|{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if wg.additional_urls %}
|
||||
<p>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 %}
|
||||
<a href="{{ url.url }}">{{ url.description}}</a>{% if not forloop.last %}, {% endif %}
|
||||
<a href="{{ url.url }}">{{ url.name }}</a>{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<h2>Description of Working Group</h2>
|
||||
<h2>Charter for Working Group</h2>
|
||||
<p>{{ wg.charter_text|escape|format_charter|safe }}</p>
|
||||
|
||||
<h2>Goals and Milestones</h2>
|
||||
<table>
|
||||
{% for milestone in wg.milestones %}
|
||||
<tr>
|
||||
<td width="80px">
|
||||
{% 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 %}
|
||||
</td>
|
||||
<td>{{ milestone.description|escape }}
|
||||
</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock wg_content %}
|
||||
<h2>Milestones
|
||||
{% if user|has_role:"Area Director,Secretariat" or is_chair %}
|
||||
<a class="edit" href="{% url wg_edit_milestones acronym=wg.acronym %}">Add or edit milestones</a>
|
||||
{% endif %}
|
||||
</h2>
|
||||
|
||||
{% with wg.milestones as milestones %}{% include "wginfo/milestones.html" %}{% endwith %}
|
||||
|
||||
{% if milestones_in_review %}
|
||||
<p>+ {{ milestones_in_review|length }} new milestone{{ milestones_in_review|pluralize }}
|
||||
currently in Area Director review.</p>
|
||||
{% endif %}
|
||||
{% endblock wg_content %}
|
||||
|
|
|
@ -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 <pasi.eronen@nokia.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of the Nokia Corporation and/or its
|
||||
subsidiary(-ies) nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{% endcomment %}
|
||||
{% load ietf_filters %}
|
||||
{% block wg_titledetail %}Charter{% endblock %}
|
||||
|
||||
{% block wg_content %}
|
||||
<div class="ietf-box ietf-wg-details">
|
||||
{% if concluded %}
|
||||
<span class="ietf-concluded-warning">Note: The data for concluded WGs
|
||||
is occasionally incorrect.</span>
|
||||
{% endif %}
|
||||
<table>
|
||||
<tr><th colspan="2">Group</th></tr>
|
||||
|
||||
<tr valign="top">
|
||||
<td style="width:14ex;">Name:</td>
|
||||
<td>{{ wg.name }}</td>
|
||||
</tr>
|
||||
|
||||
<tr><td>Acronym:</td><td>{{ wg.acronym }}</td></tr>
|
||||
|
||||
{% if wg.parent %}
|
||||
<tr><td>Area:</td><td>{{ wg.parent.name }} ({{ wg.parent.acronym }})</td></tr>
|
||||
{% endif %}
|
||||
|
||||
<tr>
|
||||
<td>State:</td>
|
||||
<td>{{ wg.state.name }}
|
||||
{% if requested_close %}
|
||||
(but in the process of being closed)
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Charter:</td>
|
||||
<td>
|
||||
{% if wg.charter %}
|
||||
<a href="{% url doc_view name=wg.charter.name %}">{{ wg.charter.name }}-{{ wg.charter.rev }}</a> ({{ wg.charter.get_state.name }})
|
||||
{% else %}
|
||||
none
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
- <a href="{% url wginfo.edit.submit_initial_charter acronym=wg.acronym %}">Submit Charter</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><th colspan="2">Personnel</th></tr>
|
||||
|
||||
<tr valign="top">
|
||||
<td>Chair{{ wg.chairs|pluralize }}:</td>
|
||||
<td>
|
||||
{% for chair in wg.chairs %}
|
||||
<a href="mailto:{{ chair.address }}">{{ chair.person.plain_name }} <{{ chair.address }}></a><br/>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td>Area Director:</td>
|
||||
<td>
|
||||
{% if not wg.ad %}?{% else %}
|
||||
<a href="mailto:{{ wg.areadirector.address }}">{{ wg.ad.plain_name }} <{{ wg.areadirector.address }}></a>{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if wg.techadvisors %}
|
||||
<tr>
|
||||
<td>Tech Advisor{{ wg.techadvisors|pluralize }}:</td>
|
||||
<td>
|
||||
{% for techadvisor in wg.techadvisors %}
|
||||
<a href="mailto:{{ techadvisor.address }}">{{ techadvisor.person.plain_name }} <{{ techadvisor.address }}></a><br/>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if wg.editors %}
|
||||
<td>Editor{{ wg.editors|pluralize }}:</td>
|
||||
<td>
|
||||
{% for editor in wg.editors %}
|
||||
<a href="mailto:{{ editor.address }}">{{ editor.person.plain_name }} <{{ editor.address }}></a><br/>
|
||||
{% endfor %}
|
||||
</td></tr>
|
||||
{% endif %}
|
||||
{% if wg.secretaries %}
|
||||
<tr>
|
||||
<td>Secretar{{ wg.secretaries|pluralize:"y,ies" }}:</td>
|
||||
<td>
|
||||
{% for secretary in wg.secretaries %}
|
||||
<a href="mailto:{{ secretary.address }}">{{ secretary.person.plain_name }} <{{ secretary.address }}></a><br/>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
<tr><th colspan="2">Mailing List</th></tr>
|
||||
|
||||
<tr><td>Address:</td><td>{{ wg.email_address|urlize }}</td></tr>
|
||||
<tr><td>To Subscribe:</td><td>{{ wg.email_subscribe|urlize }}</td></tr>
|
||||
<tr><td>Archive:</td><td>{{ wg.clean_email_archive|urlize }}</td></tr>
|
||||
|
||||
{% if not concluded %}
|
||||
<tr><th colspan="2">Jabber Chat</th></tr>
|
||||
|
||||
<tr><td>Room Address:</td><td><a href="xmpp:{{ wg.acronym }}@jabber.ietf.org">xmpp:{{ wg.acronym }}@jabber.ietf.org</a></td></tr>
|
||||
<tr><td>Logs:</td><td><a href="http://jabber.ietf.org/logs/{{ wg.acronym }}/">http://jabber.ietf.org/logs/{{ wg.acronym }}/</a></td></tr>
|
||||
{% endif %}
|
||||
|
||||
</table>
|
||||
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
<div style="margin: 2px; margin-top: 2em;">
|
||||
{% for name, url in actions %}
|
||||
<a href="{{ url }}">{{ name }}</a>
|
||||
{% if not forloop.last %}|{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if wg.additional_urls %}
|
||||
<p>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 %}
|
||||
<a href="{{ url.url }}">{{ url.name }}</a>{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<h2>Description of Working Group</h2>
|
||||
<p>{{ wg.charter_text|escape|format_charter|safe }}</p>
|
||||
|
||||
<h2>Goals and Milestones</h2>
|
||||
<table>
|
||||
{% for milestone in wg.milestones %}
|
||||
<tr>
|
||||
<td width="80px">
|
||||
{% if milestone.done %}Done{% else %}{{ milestone.expected_due_date|date:"M Y" }}{% endif %}
|
||||
</td>
|
||||
<td>{{ milestone.desc|escape }}
|
||||
</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock wg_content %}
|
|
@ -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())
|
||||
|
|
|
@ -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,
|
||||
|
@ -147,6 +149,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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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(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)
|
||||
|
|
|
@ -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/
|
||||
|
||||
#
|
||||
|
||||
|
|
@ -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<option>initcharter|recharter)/$', "ietf.wgcharter.views.submit", name='charter_submit'),
|
||||
url(r'^submit/(?P<option>initcharter|recharter)/$', "ietf.wgcharter.views.submit", name='charter_submit'), # shouldn't be here
|
||||
url(r'^withmilestones-(?P<rev>[0-9-]+).txt$', "ietf.wgcharter.views.charter_with_milestones_txt", name='charter_with_milestones_txt'),
|
||||
)
|
||||
|
|
|
@ -4,7 +4,6 @@ from django.conf import settings
|
|||
|
||||
from ietf.group.models import GroupEvent, ChangeStateGroupEvent
|
||||
from ietf.doc.models import Document, DocAlias, DocHistory, RelatedDocument, DocumentAuthor, DocEvent
|
||||
from ietf.utils.history import find_history_active_at
|
||||
|
||||
def log_state_changed(request, doc, by, prev_state):
|
||||
e = DocEvent(doc=doc, by=by)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import re, os, string, datetime, shutil
|
||||
import re, os, string, datetime, shutil, textwrap
|
||||
|
||||
from django.http import HttpResponse, HttpResponseRedirect, Http404
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound, Http404
|
||||
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||
from django.template.loader import render_to_string
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
|
@ -14,8 +14,9 @@ from django.utils.safestring import mark_safe
|
|||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
|
||||
from ietf.utils.mail import send_mail_text, send_mail_preformatted
|
||||
from ietf.utils.mail import send_mail_preformatted
|
||||
from ietf.utils.textupload import get_cleaned_text_file_content
|
||||
from ietf.utils.history import find_history_active_at
|
||||
from ietf.ietfauth.decorators import has_role, role_required
|
||||
from ietf.iesg.models import TelechatDate
|
||||
from ietf.doc.models import *
|
||||
|
@ -23,7 +24,7 @@ from ietf.doc.utils import *
|
|||
from ietf.name.models import *
|
||||
from ietf.person.models import *
|
||||
from ietf.group.models import *
|
||||
from ietf.group.utils import save_group_in_history
|
||||
from ietf.group.utils import save_group_in_history, save_milestone_in_history
|
||||
from ietf.wgcharter.mails import *
|
||||
from ietf.wgcharter.utils import *
|
||||
|
||||
|
@ -44,10 +45,10 @@ class ChangeStateForm(forms.Form):
|
|||
|
||||
@role_required("Area Director", "Secretariat")
|
||||
def change_state(request, name, option=None):
|
||||
"""Change state of WG and charter, notifying parties as necessary
|
||||
and logging the change as a comment."""
|
||||
"""Change state of charter, notifying parties as necessary and
|
||||
logging the change as a comment."""
|
||||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
wg = charter.group
|
||||
group = charter.group
|
||||
|
||||
chartering_type = get_chartering_type(charter)
|
||||
|
||||
|
@ -75,17 +76,17 @@ def change_state(request, name, option=None):
|
|||
if "-" not in charter_rev:
|
||||
charter_rev = charter_rev + "-00"
|
||||
elif option == "abandon":
|
||||
oldstate = wg.state_id
|
||||
if oldstate in ("proposed","bof","unknown"):
|
||||
oldstate = group.state_id
|
||||
if oldstate in ("proposed", "bof", "unknown"):
|
||||
charter_state = State.objects.get(type="charter", slug="notrev")
|
||||
#TODO : set an abandoned state and leave some comments here
|
||||
wg.state=GroupStateName.objects.get(slug='abandon')
|
||||
wg.save()
|
||||
group.state = GroupStateName.objects.get(slug='abandon')
|
||||
group.save()
|
||||
e = ChangeStateGroupEvent(group=wg, type="changed_state")
|
||||
e.time = wg.time
|
||||
e.by = login
|
||||
e.state_id = clean["state"].slug
|
||||
e.desc = "Group state changed to %s from %s" % clean["state"].name,oldstate
|
||||
e.desc = "Group state changed to %s from %s" % (clean["state"].name, oldstate)
|
||||
e.save()
|
||||
|
||||
else:
|
||||
|
@ -125,7 +126,7 @@ def change_state(request, name, option=None):
|
|||
charter.save()
|
||||
|
||||
if message:
|
||||
email_secretariat(request, wg, "state-%s" % charter_state.slug, message)
|
||||
email_secretariat(request, group, "state-%s" % charter_state.slug, message)
|
||||
|
||||
email_state_changed(request, charter, "State changed to %s." % charter_state)
|
||||
|
||||
|
@ -134,8 +135,8 @@ def change_state(request, name, option=None):
|
|||
create_ballot_if_not_open(charter, login, "r-wo-ext")
|
||||
else:
|
||||
create_ballot_if_not_open(charter, login, "r-extrev")
|
||||
default_review_text(wg, charter, login)
|
||||
default_action_text(wg, charter, login)
|
||||
default_review_text(group, charter, login)
|
||||
default_action_text(group, charter, login)
|
||||
elif charter_state.slug == "iesgrev":
|
||||
create_ballot_if_not_open(charter, login, "approve")
|
||||
|
||||
|
@ -152,10 +153,10 @@ def change_state(request, name, option=None):
|
|||
init = dict()
|
||||
elif option == "initcharter":
|
||||
hide = ['charter_state']
|
||||
init = dict(initial_time=1, message='%s has initiated chartering of the proposed WG:\n "%s" (%s).' % (login.plain_name(), wg.name, wg.acronym))
|
||||
init = dict(initial_time=1, message='%s has initiated chartering of the proposed %s:\n "%s" (%s).' % (login.plain_name(), group.type.name, group.name, group.acronym))
|
||||
elif option == "abandon":
|
||||
hide = ['initial_time', 'charter_state']
|
||||
init = dict(message='%s has abandoned the chartering effort on the WG:\n "%s" (%s).' % (login.plain_name(), wg.name, wg.acronym))
|
||||
init = dict(message='%s has abandoned the chartering effort on the %s:\n "%s" (%s).' % (login.plain_name(), group.type.name, group.name, group.acronym))
|
||||
else:
|
||||
hide = ['initial_time']
|
||||
s = charter.get_state()
|
||||
|
@ -168,27 +169,27 @@ def change_state(request, name, option=None):
|
|||
prev_charter_state = charter_hists[0].get_state()
|
||||
|
||||
title = {
|
||||
"initcharter": "Initiate chartering of WG %s" % wg.acronym,
|
||||
"recharter": "Recharter WG %s" % wg.acronym,
|
||||
"abandon": "Abandon effort on WG %s" % wg.acronym,
|
||||
"initcharter": "Initiate chartering of %s %s" % (group.acronym, group.type.name),
|
||||
"recharter": "Recharter %s %s" % (group.acronym, group.type.name),
|
||||
"abandon": "Abandon effort on %s %s" % (group.acronym, group.type.name),
|
||||
}.get(option)
|
||||
if not title:
|
||||
title = "Change chartering state of WG %s" % wg.acronym
|
||||
title = "Change chartering state of %s %s" % (group.acronym, group.type.name)
|
||||
|
||||
def state_pk(slug):
|
||||
return State.objects.get(type="charter", slug=slug).pk
|
||||
|
||||
info_msg = {
|
||||
state_pk("infrev"): 'The WG "%s" (%s) has been set to Informal IESG review by %s.' % (wg.name, wg.acronym, login.plain_name()),
|
||||
state_pk("intrev"): 'The WG "%s" (%s) has been set to Internal review by %s.\nPlease place it on the next IESG telechat and inform the IAB.' % (wg.name, wg.acronym, login.plain_name()),
|
||||
state_pk("extrev"): 'The WG "%s" (%s) has been set to External review by %s.\nPlease send out the external review announcement to the appropriate lists.\n\nSend the announcement to other SDOs: Yes\nAdditional recipients of the announcement: ' % (wg.name, wg.acronym, login.plain_name()),
|
||||
state_pk("infrev"): 'The %s "%s" (%s) has been set to Informal IESG review by %s.' % (group.type.name, group.name, group.acronym, login.plain_name()),
|
||||
state_pk("intrev"): 'The %s "%s" (%s) has been set to Internal review by %s.\nPlease place it on the next IESG telechat and inform the IAB.' % (group.type.name, group.name, group.acronym, login.plain_name()),
|
||||
state_pk("extrev"): 'The %s "%s" (%s) has been set to External review by %s.\nPlease send out the external review announcement to the appropriate lists.\n\nSend the announcement to other SDOs: Yes\nAdditional recipients of the announcement: ' % (group.type.name, group.name, group.acronym, login.plain_name()),
|
||||
}
|
||||
|
||||
states_for_ballot_wo_extern = State.objects.filter(type="charter", slug="intrev").values_list("pk", flat=True)
|
||||
|
||||
return render_to_response('wgcharter/change_state.html',
|
||||
dict(form=form,
|
||||
doc=wg.charter,
|
||||
doc=group.charter,
|
||||
login=login,
|
||||
option=option,
|
||||
prev_charter_state=prev_charter_state,
|
||||
|
@ -340,8 +341,8 @@ class UploadForm(forms.Form):
|
|||
def clean_txt(self):
|
||||
return get_cleaned_text_file_content(self.cleaned_data["txt"])
|
||||
|
||||
def save(self, wg, rev):
|
||||
filename = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (wg.charter.canonical_name(), rev))
|
||||
def save(self, group, rev):
|
||||
filename = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (group.charter.canonical_name(), rev))
|
||||
with open(filename, 'wb') as destination:
|
||||
if self.cleaned_data['txt']:
|
||||
destination.write(self.cleaned_data['txt'])
|
||||
|
@ -356,7 +357,7 @@ def submit(request, name=None, acronym=None, option=None):
|
|||
elif acronym:
|
||||
name = "charter-ietf-" + acronym
|
||||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
wg = charter.group
|
||||
group = charter.group
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
|
@ -378,7 +379,7 @@ def submit(request, name=None, acronym=None, option=None):
|
|||
if form.is_valid():
|
||||
save_document_in_history(charter)
|
||||
# Also save group history so we can search for it
|
||||
save_group_in_history(wg)
|
||||
save_group_in_history(group)
|
||||
|
||||
charter.rev = next_rev
|
||||
|
||||
|
@ -388,7 +389,7 @@ def submit(request, name=None, acronym=None, option=None):
|
|||
e.save()
|
||||
|
||||
# Save file on disk
|
||||
form.save(wg, charter.rev)
|
||||
form.save(group, charter.rev)
|
||||
|
||||
charter.time = datetime.datetime.now()
|
||||
charter.save()
|
||||
|
@ -419,7 +420,7 @@ def submit(request, name=None, acronym=None, option=None):
|
|||
return render_to_response('wgcharter/submit.html',
|
||||
{'form': form,
|
||||
'next_rev': next_rev,
|
||||
'wg': wg },
|
||||
'group': group },
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class AnnouncementTextForm(forms.Form):
|
||||
|
@ -432,19 +433,20 @@ class AnnouncementTextForm(forms.Form):
|
|||
def announcement_text(request, name, ann):
|
||||
"""Editing of announcement text"""
|
||||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
wg = charter.group
|
||||
group = charter.group
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
if ann == "action":
|
||||
existing = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
elif ann == "review":
|
||||
existing = charter.latest_event(WriteupDocEvent, type="changed_review_announcement")
|
||||
if ann in ("action", "review"):
|
||||
existing = charter.latest_event(WriteupDocEvent, type="changed_%s_announcement" % ann)
|
||||
if not existing:
|
||||
if ann == "action":
|
||||
existing = default_action_text(wg, charter, login)
|
||||
existing = default_action_text(group, charter, login)
|
||||
elif ann == "review":
|
||||
existing = default_review_text(wg, charter, login)
|
||||
existing = default_review_text(group, charter, login)
|
||||
|
||||
if not existing:
|
||||
raise Http404
|
||||
|
||||
form = AnnouncementTextForm(initial=dict(announcement_text=existing.text))
|
||||
|
||||
|
@ -456,7 +458,7 @@ def announcement_text(request, name, ann):
|
|||
e = WriteupDocEvent(doc=charter, by=login)
|
||||
e.by = login
|
||||
e.type = "changed_%s_announcement" % ann
|
||||
e.desc = "WG %s text was changed" % ann
|
||||
e.desc = "%s %s text was changed" % (group.type.name, ann)
|
||||
e.text = t
|
||||
e.save()
|
||||
|
||||
|
@ -470,20 +472,14 @@ def announcement_text(request, name, ann):
|
|||
|
||||
if "regenerate_text" in request.POST:
|
||||
if ann == "action":
|
||||
e = default_action_text(wg, charter, login)
|
||||
e = default_action_text(group, charter, login)
|
||||
elif ann == "review":
|
||||
e = default_review_text(wg, charter, login)
|
||||
e = default_review_text(group, charter, login)
|
||||
# make sure form has the updated text
|
||||
form = AnnouncementTextForm(initial=dict(announcement_text=e.text))
|
||||
|
||||
if "send_text" in request.POST and form.is_valid():
|
||||
msg = form.cleaned_data['announcement_text']
|
||||
import email
|
||||
parsed_msg = email.message_from_string(msg.encode("utf-8"))
|
||||
|
||||
send_mail_text(request, parsed_msg["To"],
|
||||
parsed_msg["From"], parsed_msg["Subject"],
|
||||
parsed_msg.get_payload())
|
||||
send_mail_preformatted(request, form.cleaned_data['announcement_text'])
|
||||
messages.success(request, "The email To: '%s' with Subjet: '%s' has been sent." % (parsed_msg["To"],parsed_msg["Subject"],))
|
||||
return redirect('doc_writeup', name=charter.name)
|
||||
|
||||
|
@ -505,7 +501,6 @@ class BallotWriteupForm(forms.Form):
|
|||
def ballot_writeupnotes(request, name):
|
||||
"""Editing of ballot write-up and notes"""
|
||||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
wg = charter.group
|
||||
|
||||
ballot = charter.latest_event(BallotDocEvent, type="created_ballot")
|
||||
if not ballot:
|
||||
|
@ -573,13 +568,13 @@ def ballot_writeupnotes(request, name):
|
|||
def approve(request, name):
|
||||
"""Approve charter, changing state, fixing revision, copying file to final location."""
|
||||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
wg = charter.group
|
||||
group = charter.group
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
e = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
if not e:
|
||||
announcement = default_action_text(wg, charter, login).text
|
||||
announcement = default_action_text(group, charter, login).text
|
||||
else:
|
||||
announcement = e.text
|
||||
|
||||
|
@ -601,23 +596,22 @@ def approve(request, name):
|
|||
change_description = e.desc
|
||||
|
||||
new_state = GroupStateName.objects.get(slug="active")
|
||||
if wg.state != new_state:
|
||||
# update history with current state
|
||||
save_group_in_history(wg)
|
||||
# change wg state and save the wg
|
||||
prev_state = wg.state
|
||||
wg.state = new_state
|
||||
wg.time = e.time
|
||||
wg.save()
|
||||
if group.state != new_state:
|
||||
save_group_in_history(group)
|
||||
prev_state = group.state
|
||||
group.state = new_state
|
||||
group.time = e.time
|
||||
group.save()
|
||||
|
||||
# create an event for the wg state change, too
|
||||
e = ChangeStateGroupEvent(group=wg, type="changed_state")
|
||||
e.time = wg.time
|
||||
e = ChangeStateGroupEvent(group=group, type="changed_state")
|
||||
e.time = group.time
|
||||
e.by = login
|
||||
e.state_id = "proposed"
|
||||
e.desc = "Proposed group"
|
||||
e.state = prev_state
|
||||
e.desc = "Group state changed to %s from %s" % (group.state.name, prev_state)
|
||||
e.save()
|
||||
# update the change description for the email
|
||||
change_description += " and WG state has been changed to %s" % new_state.name
|
||||
|
||||
change_description += " and %s state has been changed to %s" % (group.type.name, new_state.name)
|
||||
|
||||
e = log_state_changed(request, charter, login, prev_charter_state)
|
||||
|
||||
|
@ -627,7 +621,9 @@ def approve(request, name):
|
|||
new = os.path.join(charter.get_file_path(), '%s-%s.txt' % (charter.canonical_name(), next_approved_revision(charter.rev)))
|
||||
shutil.copy(old, new)
|
||||
except IOError:
|
||||
raise Http404("Charter text %s" % filename)
|
||||
return HttpResponse("There was an error copying %s to %s" %
|
||||
('%s-%s.txt' % (charter.canonical_name(), charter.rev),
|
||||
'%s-%s.txt' % (charter.canonical_name(), next_approved_revision(charter.rev))))
|
||||
|
||||
e = NewRevisionDocEvent(doc=charter, by=login, type="new_revision")
|
||||
e.rev = next_approved_revision(charter.rev)
|
||||
|
@ -638,7 +634,57 @@ def approve(request, name):
|
|||
charter.time = e.time
|
||||
charter.save()
|
||||
|
||||
email_secretariat(request, wg, "state-%s" % new_charter_state.slug, change_description)
|
||||
email_secretariat(request, group, "state-%s" % new_charter_state.slug, change_description)
|
||||
|
||||
# move milestones over
|
||||
milestones_to_delete = list(group.groupmilestone_set.filter(state__in=("active", "review")))
|
||||
|
||||
for m in group.groupmilestone_set.filter(state="charter"):
|
||||
# see if we got this milestone already (i.e. it was copied
|
||||
# verbatim to the charter)
|
||||
found = False
|
||||
for i, o in enumerate(milestones_to_delete):
|
||||
if o.desc == m.desc and o.due == m.due and set(o.docs.all()) == set(m.docs.all()):
|
||||
found = True
|
||||
break
|
||||
|
||||
if found:
|
||||
# keep existing, whack charter milestone
|
||||
if not o.state_id == "active":
|
||||
save_milestone_in_history(o)
|
||||
o.state_id = "active"
|
||||
o.save()
|
||||
MilestoneGroupEvent.objects.create(
|
||||
group=group, type="changed_milestone", by=login,
|
||||
desc="Changed milestone \"%s\", set state to active from review" % o.desc,
|
||||
milestone=o)
|
||||
|
||||
del milestones_to_delete[i]
|
||||
|
||||
# don't generate a DocEvent for this, it's implicit in the approval event
|
||||
save_milestone_in_history(m)
|
||||
m.state_id = "deleted"
|
||||
m.save()
|
||||
else:
|
||||
# move charter milestone
|
||||
save_milestone_in_history(m)
|
||||
m.state_id = "active"
|
||||
m.save()
|
||||
|
||||
MilestoneGroupEvent.objects.create(
|
||||
group=group, type="changed_milestone", by=login,
|
||||
desc="Added milestone \"%s\", due %s, from approved charter" % (m.desc, m.due),
|
||||
milestone=m)
|
||||
|
||||
for m in milestones_to_delete:
|
||||
save_milestone_in_history(m)
|
||||
m.state_id = "deleted"
|
||||
m.save()
|
||||
|
||||
MilestoneGroupEvent.objects.create(
|
||||
group=group, type="changed_milestone", by=login,
|
||||
desc="Deleted milestone \"%s\", not present in approved charter" % m.desc,
|
||||
milestone=m)
|
||||
|
||||
# send announcement
|
||||
send_mail_preformatted(request, announcement)
|
||||
|
@ -647,7 +693,61 @@ def approve(request, name):
|
|||
|
||||
return render_to_response('wgcharter/approve.html',
|
||||
dict(charter=charter,
|
||||
announcement=announcement,
|
||||
wg=wg),
|
||||
announcement=announcement),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def charter_with_milestones_txt(request, name, rev):
|
||||
charter = get_object_or_404(Document, type="charter", docalias__name=name)
|
||||
|
||||
revision_event = charter.latest_event(NewRevisionDocEvent, type="new_revision", rev=rev)
|
||||
if not revision_event:
|
||||
return HttpResponseNotFound("Revision %s not found in database" % rev)
|
||||
|
||||
# read charter text
|
||||
c = find_history_active_at(charter, revision_event.time) or charter
|
||||
filename = '%s-%s.txt' % (c.canonical_name(), rev)
|
||||
|
||||
charter_text = ""
|
||||
|
||||
try:
|
||||
with open(os.path.join(settings.CHARTER_PATH, filename), 'r') as f:
|
||||
charter_text = f.read()
|
||||
except IOError:
|
||||
charter_text = "Error reading charter text %s" % filename
|
||||
|
||||
|
||||
# find milestones
|
||||
|
||||
chartering = "-" in rev
|
||||
if chartering:
|
||||
need_state = "charter"
|
||||
else:
|
||||
need_state = "active"
|
||||
|
||||
# slight complication - we can assign milestones to a revision up
|
||||
# until the point where the next superseding revision is
|
||||
# published, so that time shall be our limit
|
||||
e = charter.docevent_set.filter(time__gt=revision_event.time, type="new_revision").order_by("time")
|
||||
if not chartering:
|
||||
e = e.exclude(newrevisiondocevent__rev__contains="-")
|
||||
|
||||
if e:
|
||||
# subtract a margen of error
|
||||
just_before_next_rev = e[0].time - datetime.timedelta(seconds=5)
|
||||
else:
|
||||
just_before_next_rev = datetime.datetime.now()
|
||||
|
||||
wrapper = textwrap.TextWrapper(initial_indent="", subsequent_indent=" " * 11, width=80, break_long_words=False)
|
||||
|
||||
milestones = []
|
||||
for m in charter.chartered_group.groupmilestone_set.all():
|
||||
mh = find_history_active_at(m, just_before_next_rev)
|
||||
if mh and mh.state_id == need_state:
|
||||
mh.desc_filled = wrapper.fill(mh.desc)
|
||||
milestones.append(mh)
|
||||
|
||||
return render_to_response('wgcharter/charter_with_milestones.txt',
|
||||
dict(charter_text=charter_text,
|
||||
milestones=milestones),
|
||||
context_instance=RequestContext(request),
|
||||
mimetype="text/plain")
|
||||
|
|
129
ietf/wginfo/mails.py
Normal file
129
ietf/wginfo/mails.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
# generation of mails
|
||||
|
||||
import textwrap, datetime, re
|
||||
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.html import strip_tags
|
||||
from django.utils.text import wrap
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
|
||||
from ietf.utils.mail import send_mail, send_mail_text
|
||||
|
||||
from ietf.group.models import *
|
||||
|
||||
def email_milestones_changed(request, group, changes):
|
||||
def wrap_up_email(to, text):
|
||||
text = wrap(strip_tags(text), 70)
|
||||
text += "\n\n"
|
||||
text += u"URL: %s" % (settings.IDTRACKER_BASE_URL + urlreverse("wg_charter", kwargs=dict(acronym=group.acronym)))
|
||||
|
||||
send_mail_text(request, to, None,
|
||||
u"Milestones changed for %s %s" % (group.acronym, group.type.name),
|
||||
text)
|
||||
|
||||
# first send to AD and chairs
|
||||
to = []
|
||||
if group.ad:
|
||||
to.append(group.ad.role_email("ad").formatted_email())
|
||||
|
||||
for r in group.role_set.filter(name="chair"):
|
||||
to.append(r.formatted_email())
|
||||
|
||||
if to:
|
||||
wrap_up_email(to, u"\n\n".join(c + "." for c in changes))
|
||||
|
||||
# then send to WG
|
||||
if group.list_email:
|
||||
review_re = re.compile("Added .* for review, due")
|
||||
to = [ group.list_email ]
|
||||
wrap_up_email(to, u"\n\n".join(c + "." for c in changes if not review_re.match(c)))
|
||||
|
||||
|
||||
def email_milestone_review_reminder(group, grace_period=7):
|
||||
"""Email reminders about milestones needing review to AD."""
|
||||
if not group.ad:
|
||||
return False
|
||||
|
||||
to = [group.ad.role_email("ad").formatted_email()]
|
||||
cc = [r.formatted_email() for r in group.role_set.filter(name="chair")]
|
||||
|
||||
now = datetime.datetime.now()
|
||||
too_early = True
|
||||
|
||||
milestones = group.groupmilestone_set.filter(state="review")
|
||||
for m in milestones:
|
||||
e = m.milestonegroupevent_set.filter(type="changed_milestone").order_by("-time")[:1]
|
||||
m.days_ready = (now - e[0].time).days if e else None
|
||||
|
||||
if m.days_ready == None or m.days_ready >= grace_period:
|
||||
too_early = False
|
||||
|
||||
if too_early:
|
||||
return False
|
||||
|
||||
subject = u"Reminder: Milestone%s needing review in %s %s" % ("s" if len(milestones) > 1 else "", group.acronym, group.type.name)
|
||||
|
||||
send_mail(None, to, None,
|
||||
subject,
|
||||
"wginfo/reminder_milestones_need_review.txt",
|
||||
dict(group=group,
|
||||
milestones=milestones,
|
||||
url=settings.IDTRACKER_BASE_URL + urlreverse("wg_edit_milestones", kwargs=dict(acronym=group.acronym))
|
||||
))
|
||||
|
||||
return True
|
||||
|
||||
def groups_with_milestones_needing_review():
|
||||
return Group.objects.filter(groupmilestone__state="review").distinct()
|
||||
|
||||
def email_milestones_due(group, early_warning_days):
|
||||
to = [r.formatted_email() for r in group.role_set.filter(name="chair")]
|
||||
|
||||
today = datetime.date.today()
|
||||
early_warning = today + datetime.timedelta(days=early_warning_days)
|
||||
|
||||
milestones = group.groupmilestone_set.filter(due__in=[today, early_warning],
|
||||
resolved="", state="active")
|
||||
|
||||
subject = u"Reminder: Milestone%s are soon due in %s %s" % ("s" if len(milestones) > 1 else "", group.acronym, group.type.name)
|
||||
|
||||
send_mail(None, to, None,
|
||||
subject,
|
||||
"wginfo/reminder_milestones_due.txt",
|
||||
dict(group=group,
|
||||
milestones=milestones,
|
||||
today=today,
|
||||
early_warning_days=early_warning_days,
|
||||
url=settings.IDTRACKER_BASE_URL + urlreverse("wg_charter", kwargs=dict(acronym=group.acronym))
|
||||
))
|
||||
|
||||
def groups_needing_milestones_due_reminder(early_warning_days):
|
||||
"""Return groups having milestones that are either
|
||||
early_warning_days from being due or are due today."""
|
||||
today = datetime.date.today()
|
||||
return Group.objects.filter(state="active", groupmilestone__due__in=[today, today + datetime.timedelta(days=early_warning_days)], groupmilestone__resolved="", groupmilestone__state="active").distinct()
|
||||
|
||||
def email_milestones_overdue(group):
|
||||
to = [r.formatted_email() for r in group.role_set.filter(name="chair")]
|
||||
|
||||
today = datetime.date.today()
|
||||
|
||||
milestones = group.groupmilestone_set.filter(due__lt=today, resolved="", state="active")
|
||||
for m in milestones:
|
||||
m.months_overdue = (today - m.due).days // 30
|
||||
|
||||
subject = u"Reminder: Milestone%s overdue in %s %s" % ("s" if len(milestones) > 1 else "", group.acronym, group.type.name)
|
||||
|
||||
send_mail(None, to, None,
|
||||
subject,
|
||||
"wginfo/reminder_milestones_overdue.txt",
|
||||
dict(group=group,
|
||||
milestones=milestones,
|
||||
url=settings.IDTRACKER_BASE_URL + urlreverse("wg_charter", kwargs=dict(acronym=group.acronym))
|
||||
))
|
||||
|
||||
def groups_needing_milestones_overdue_reminder(grace_period=30):
|
||||
cut_off = datetime.date.today() - datetime.timedelta(days=grace_period)
|
||||
return Group.objects.filter(state="active", groupmilestone__due__lt=cut_off, groupmilestone__resolved="", groupmilestone__state="active").distinct()
|
||||
|
396
ietf/wginfo/milestones.py
Normal file
396
ietf/wginfo/milestones.py
Normal file
|
@ -0,0 +1,396 @@
|
|||
# WG milestone editing views
|
||||
|
||||
import re, os, string, datetime, shutil, calendar
|
||||
|
||||
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template import RequestContext
|
||||
from django import forms
|
||||
from django.http import HttpResponse, HttpResponseForbidden, HttpResponseBadRequest
|
||||
from django.utils import simplejson
|
||||
from django.utils.html import mark_safe, escape
|
||||
from django.utils.functional import lazy
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
|
||||
from ietf.ietfauth.decorators import role_required, has_role
|
||||
from ietf.doc.models import Document, DocEvent
|
||||
from ietf.doc.utils import get_chartering_type
|
||||
from ietf.group.models import *
|
||||
from ietf.group.utils import save_group_in_history, save_milestone_in_history
|
||||
from ietf.wginfo.mails import email_milestones_changed
|
||||
|
||||
def json_doc_names(docs):
|
||||
return simplejson.dumps([{"id": doc.pk, "name": doc.name } for doc in docs])
|
||||
|
||||
def parse_doc_names(s):
|
||||
return Document.objects.filter(pk__in=[x.strip() for x in s.split(",") if x.strip()], type="draft")
|
||||
|
||||
class MilestoneForm(forms.Form):
|
||||
id = forms.IntegerField(required=True, widget=forms.HiddenInput)
|
||||
|
||||
desc = forms.CharField(max_length=500, label="Milestone", required=True)
|
||||
due_month = forms.TypedChoiceField(choices=(), required=True, coerce=int)
|
||||
due_year = forms.TypedChoiceField(choices=(), required=True, coerce=int)
|
||||
resolved_checkbox = forms.BooleanField(required=False, label="Resolved")
|
||||
resolved = forms.CharField(max_length=50, required=False)
|
||||
|
||||
delete = forms.BooleanField(required=False, initial=False)
|
||||
|
||||
docs = forms.CharField(max_length=10000, required=False)
|
||||
|
||||
accept = forms.ChoiceField(choices=(("accept", "Accept"), ("reject", "Reject and delete"), ("noaction", "No action")),
|
||||
required=False, initial="noaction", widget=forms.RadioSelect)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
m = self.milestone = kwargs.pop("instance", None)
|
||||
|
||||
self.needs_review = kwargs.pop("needs_review", False)
|
||||
|
||||
if m:
|
||||
if not "initial" in kwargs:
|
||||
kwargs["initial"] = {}
|
||||
kwargs["initial"].update(dict(id=m.pk,
|
||||
desc=m.desc,
|
||||
due_month=m.due.month,
|
||||
due_year=m.due.year,
|
||||
resolved_checkbox=bool(m.resolved),
|
||||
resolved=m.resolved,
|
||||
docs=",".join(m.docs.values_list("pk", flat=True)),
|
||||
))
|
||||
|
||||
kwargs["prefix"] = "m%s" % m.pk
|
||||
|
||||
self.needs_review = m.state_id == "review"
|
||||
|
||||
super(MilestoneForm, self).__init__(*args, **kwargs)
|
||||
|
||||
# set choices for due date
|
||||
this_year = datetime.date.today().year
|
||||
|
||||
self.fields["due_month"].choices = [(m, datetime.date(this_year, m, 1).strftime("%B")) for m in range(1, 13)]
|
||||
|
||||
years = [ y for y in range(this_year, this_year + 10)]
|
||||
|
||||
initial = self.initial.get("due_year")
|
||||
if initial and initial not in years:
|
||||
years.insert(0, initial)
|
||||
|
||||
self.fields["due_year"].choices = zip(years, map(str, years))
|
||||
|
||||
|
||||
# figure out what to prepopulate many-to-many field with
|
||||
pre = ""
|
||||
if not self.is_bound:
|
||||
pre = self.initial.get("docs", "")
|
||||
else:
|
||||
pre = self["docs"].data or ""
|
||||
|
||||
# this is ugly, but putting it on self["docs"] is buggy with a
|
||||
# bound/unbound form in Django 1.2
|
||||
self.docs_names = parse_doc_names(pre)
|
||||
self.docs_prepopulate = json_doc_names(self.docs_names)
|
||||
|
||||
def clean_docs(self):
|
||||
s = self.cleaned_data["docs"]
|
||||
return Document.objects.filter(pk__in=[x.strip() for x in s.split(",") if x.strip()], type="draft")
|
||||
|
||||
def clean_resolved(self):
|
||||
r = self.cleaned_data["resolved"].strip()
|
||||
|
||||
if self.cleaned_data["resolved_checkbox"]:
|
||||
if not r:
|
||||
raise forms.ValidationError('Please provide explanation (like "Done") for why the milestone is no longer due.')
|
||||
else:
|
||||
r = ""
|
||||
|
||||
return r
|
||||
|
||||
|
||||
@role_required('WG Chair', 'Area Director', 'Secretariat')
|
||||
def edit_milestones(request, acronym, milestone_set="current"):
|
||||
# milestones_set + needs_review: we have several paths into this view
|
||||
# AD/Secr. -> all actions on current + add new
|
||||
# group chair -> limited actions on current + add new for review
|
||||
# (re)charter -> all actions on existing in state charter + add new in state charter
|
||||
#
|
||||
# For charters we store the history on the charter document to not confuse people.
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
group = get_object_or_404(Group, acronym=acronym)
|
||||
|
||||
needs_review = False
|
||||
if not has_role(request.user, ("Area Director", "Secretariat")):
|
||||
if group.role_set.filter(name="chair", person=login):
|
||||
if milestone_set == "current":
|
||||
needs_review = True
|
||||
else:
|
||||
return HttpResponseForbidden("You are not chair of this group.")
|
||||
|
||||
if milestone_set == "current":
|
||||
title = "Edit milestones for %s %s" % (group.acronym, group.type.name)
|
||||
milestones = group.groupmilestone_set.filter(state__in=("active", "review"))
|
||||
elif milestone_set == "charter":
|
||||
title = "Edit charter milestones for %s %s" % (group.acronym, group.type.name)
|
||||
milestones = group.groupmilestone_set.filter(state="charter")
|
||||
|
||||
forms = []
|
||||
|
||||
milestones_dict = dict((str(m.id), m) for m in milestones)
|
||||
|
||||
def due_month_year_to_date(c):
|
||||
y = c["due_year"]
|
||||
m = c["due_month"]
|
||||
return datetime.date(y, m, calendar.monthrange(y, m)[1])
|
||||
|
||||
def set_attributes_from_form(f, m):
|
||||
c = f.cleaned_data
|
||||
m.group = group
|
||||
if milestone_set == "current":
|
||||
if needs_review:
|
||||
m.state = GroupMilestoneStateName.objects.get(slug="review")
|
||||
else:
|
||||
m.state = GroupMilestoneStateName.objects.get(slug="active")
|
||||
elif milestone_set == "charter":
|
||||
m.state = GroupMilestoneStateName.objects.get(slug="charter")
|
||||
m.desc = c["desc"]
|
||||
m.due = due_month_year_to_date(c)
|
||||
m.resolved = c["resolved"]
|
||||
|
||||
def save_milestone_form(f):
|
||||
c = f.cleaned_data
|
||||
|
||||
if f.milestone:
|
||||
m = f.milestone
|
||||
|
||||
named_milestone = 'milestone "%s"' % m.desc
|
||||
if milestone_set == "charter":
|
||||
named_milestone = "charter " + named_milestone
|
||||
|
||||
if c["delete"]:
|
||||
save_milestone_in_history(m)
|
||||
|
||||
m.state_id = "deleted"
|
||||
m.save()
|
||||
|
||||
return 'Deleted %s' % named_milestone
|
||||
|
||||
# compute changes
|
||||
history = None
|
||||
|
||||
changes = ['Changed %s' % named_milestone]
|
||||
|
||||
if m.state_id == "review" and not needs_review and c["accept"] != "noaction":
|
||||
if not history:
|
||||
history = save_milestone_in_history(m)
|
||||
|
||||
if c["accept"] == "accept":
|
||||
m.state_id = "active"
|
||||
changes.append("set state to active from review, accepting new milestone")
|
||||
elif c["accept"] == "reject":
|
||||
m.state_id = "deleted"
|
||||
changes.append("set state to deleted from review, rejecting new milestone")
|
||||
|
||||
|
||||
if c["desc"] != m.desc and not needs_review:
|
||||
if not history:
|
||||
history = save_milestone_in_history(m)
|
||||
m.desc = c["desc"]
|
||||
changes.append('set description to "%s"' % m.desc)
|
||||
|
||||
|
||||
c_due = due_month_year_to_date(c)
|
||||
if c_due != m.due:
|
||||
if not history:
|
||||
history = save_milestone_in_history(m)
|
||||
changes.append('set due date to %s from %s' % (c_due.strftime("%B %Y"), m.due.strftime("%B %Y")))
|
||||
m.due = c_due
|
||||
|
||||
resolved = c["resolved"]
|
||||
if resolved != m.resolved:
|
||||
if resolved and not m.resolved:
|
||||
changes.append('resolved as "%s"' % resolved)
|
||||
elif not resolved and m.resolved:
|
||||
changes.append("reverted to not being resolved")
|
||||
elif resolved and m.resolved:
|
||||
changes.append('set resolution to "%s"' % resolved)
|
||||
|
||||
if not history:
|
||||
history = save_milestone_in_history(m)
|
||||
|
||||
m.resolved = resolved
|
||||
|
||||
new_docs = set(c["docs"])
|
||||
old_docs = set(m.docs.all())
|
||||
if new_docs != old_docs:
|
||||
added = new_docs - old_docs
|
||||
if added:
|
||||
changes.append('added %s to milestone' % ", ".join(d.name for d in added))
|
||||
|
||||
removed = old_docs - new_docs
|
||||
if removed:
|
||||
changes.append('removed %s from milestone' % ", ".join(d.name for d in removed))
|
||||
|
||||
if not history:
|
||||
history = save_milestone_in_history(m)
|
||||
|
||||
m.docs = new_docs
|
||||
|
||||
if len(changes) > 1:
|
||||
m.save()
|
||||
|
||||
return ", ".join(changes)
|
||||
|
||||
else: # new milestone
|
||||
m = f.milestone = GroupMilestone()
|
||||
set_attributes_from_form(f, m)
|
||||
m.save()
|
||||
|
||||
m.docs = c["docs"]
|
||||
|
||||
named_milestone = 'milestone "%s"' % m.desc
|
||||
if milestone_set == "charter":
|
||||
named_milestone = "charter " + named_milestone
|
||||
|
||||
if m.state_id in ("active", "charter"):
|
||||
return 'Added %s, due %s' % (named_milestone, m.due.strftime("%B %Y"))
|
||||
elif m.state_id == "review":
|
||||
return 'Added %s for review, due %s' % (named_milestone, m.due.strftime("%B %Y"))
|
||||
|
||||
finished_milestone_text = "Done"
|
||||
|
||||
form_errors = False
|
||||
|
||||
if request.method == 'POST':
|
||||
# parse out individual milestone forms
|
||||
for prefix in request.POST.getlist("prefix"):
|
||||
if not prefix: # empty form
|
||||
continue
|
||||
|
||||
# new milestones have non-existing ids so instance end up as None
|
||||
instance = milestones_dict.get(request.POST.get(prefix + "-id", ""), None)
|
||||
f = MilestoneForm(request.POST, prefix=prefix, instance=instance,
|
||||
needs_review=needs_review)
|
||||
forms.append(f)
|
||||
|
||||
form_errors = form_errors or not f.is_valid()
|
||||
|
||||
action = request.POST.get("action", "review")
|
||||
if action == "review":
|
||||
for f in forms:
|
||||
if not f.is_valid():
|
||||
continue
|
||||
|
||||
# let's fill in the form milestone so we can output it in the template
|
||||
if not f.milestone:
|
||||
f.milestone = GroupMilestone()
|
||||
set_attributes_from_form(f, f.milestone)
|
||||
elif action == "save" and not form_errors:
|
||||
changes = []
|
||||
for f in forms:
|
||||
change = save_milestone_form(f)
|
||||
|
||||
if not change:
|
||||
continue
|
||||
|
||||
if milestone_set == "charter":
|
||||
DocEvent.objects.create(doc=group.charter, type="changed_charter_milestone",
|
||||
by=login, desc=change)
|
||||
else:
|
||||
MilestoneGroupEvent.objects.create(group=group, type="changed_milestone",
|
||||
by=login, desc=change, milestone=f.milestone)
|
||||
|
||||
changes.append(change)
|
||||
|
||||
if milestone_set == "current":
|
||||
email_milestones_changed(request, group, changes)
|
||||
|
||||
if milestone_set == "charter":
|
||||
return redirect('doc_view', name=group.charter.canonical_name())
|
||||
else:
|
||||
return redirect('wg_charter', acronym=group.acronym)
|
||||
else:
|
||||
for m in milestones:
|
||||
forms.append(MilestoneForm(instance=m, needs_review=needs_review))
|
||||
|
||||
can_reset = milestone_set == "charter" and get_chartering_type(group.charter) == "rechartering"
|
||||
|
||||
empty_form = MilestoneForm(needs_review=needs_review)
|
||||
|
||||
forms.sort(key=lambda f: f.milestone.due if f.milestone else datetime.date.max)
|
||||
|
||||
return render_to_response('wginfo/edit_milestones.html',
|
||||
dict(group=group,
|
||||
title=title,
|
||||
forms=forms,
|
||||
form_errors=form_errors,
|
||||
empty_form=empty_form,
|
||||
milestone_set=milestone_set,
|
||||
finished_milestone_text=finished_milestone_text,
|
||||
needs_review=needs_review,
|
||||
can_reset=can_reset),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
@role_required('WG Chair', 'Area Director', 'Secretariat')
|
||||
def reset_charter_milestones(request, acronym):
|
||||
"""Reset charter milestones to the currently in-use milestones."""
|
||||
login = request.user.get_profile()
|
||||
|
||||
group = get_object_or_404(Group, acronym=acronym)
|
||||
|
||||
if (not has_role(request.user, ("Area Director", "Secretariat")) and
|
||||
not group.role_set.filter(name="chair", person=login)):
|
||||
return HttpResponseForbidden("You are not chair of this group.")
|
||||
|
||||
current_milestones = group.groupmilestone_set.filter(state="active")
|
||||
charter_milestones = group.groupmilestone_set.filter(state="charter")
|
||||
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
milestone_ids = [int(v) for v in request.POST.getlist("milestone")]
|
||||
except ValueError as e:
|
||||
return HttpResponseBadRequest("error in list of ids - %s" % e)
|
||||
|
||||
# delete existing
|
||||
for m in charter_milestones:
|
||||
save_milestone_in_history(m)
|
||||
|
||||
m.state_id = "deleted"
|
||||
m.save()
|
||||
|
||||
DocEvent.objects.create(type="changed_charter_milestone",
|
||||
doc=group.charter,
|
||||
desc='Deleted milestone "%s"' % m.desc,
|
||||
by=login,
|
||||
)
|
||||
|
||||
# add current
|
||||
for m in current_milestones.filter(id__in=milestone_ids):
|
||||
new = GroupMilestone.objects.create(group=m.group,
|
||||
state_id="charter",
|
||||
desc=m.desc,
|
||||
due=m.due,
|
||||
resolved=m.resolved,
|
||||
)
|
||||
new.docs = m.docs.all()
|
||||
|
||||
DocEvent.objects.create(type="changed_charter_milestone",
|
||||
doc=group.charter,
|
||||
desc='Added milestone "%s", due %s, from current group milestones' % (new.desc, new.due.strftime("%B %Y")),
|
||||
by=login,
|
||||
)
|
||||
|
||||
|
||||
return redirect('wg_edit_charter_milestones', acronym=group.acronym)
|
||||
|
||||
return render_to_response('wginfo/reset_charter_milestones.html',
|
||||
dict(group=group,
|
||||
charter_milestones=charter_milestones,
|
||||
current_milestones=current_milestones,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def ajax_search_docs(request, acronym):
|
||||
docs = Document.objects.filter(name__icontains=request.GET.get('q',''), type="draft").order_by('name').distinct()[:20]
|
||||
return HttpResponse(json_doc_names(docs), mimetype='application/json')
|
|
@ -30,7 +30,7 @@
|
|||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import os, unittest, shutil
|
||||
import os, unittest, shutil, calendar
|
||||
|
||||
import django.test
|
||||
from django.conf import settings
|
||||
|
@ -48,6 +48,7 @@ from ietf.group.models import *
|
|||
from ietf.group.utils import *
|
||||
from ietf.name.models import *
|
||||
from ietf.person.models import *
|
||||
from ietf.wginfo.mails import *
|
||||
|
||||
|
||||
class WgInfoUrlTestCase(SimpleUrlTestCase):
|
||||
|
@ -262,3 +263,409 @@ class WgEditTestCase(django.test.TestCase):
|
|||
# the WG remains active until the Secretariat takes action
|
||||
group = Group.objects.get(acronym=group.acronym)
|
||||
self.assertEquals(group.state_id, "active")
|
||||
|
||||
class MilestoneTestCase(django.test.TestCase):
|
||||
fixtures = ["names"]
|
||||
|
||||
def create_test_milestones(self):
|
||||
draft = make_test_data()
|
||||
|
||||
group = Group.objects.get(acronym="mars")
|
||||
|
||||
m1 = GroupMilestone.objects.create(group=group,
|
||||
desc="Test 1",
|
||||
due=datetime.date.today(),
|
||||
resolved="",
|
||||
state_id="active")
|
||||
m1.docs = [draft]
|
||||
|
||||
m2 = GroupMilestone.objects.create(group=group,
|
||||
desc="Test 2",
|
||||
due=datetime.date.today(),
|
||||
resolved="",
|
||||
state_id="charter")
|
||||
m2.docs = [draft]
|
||||
|
||||
return (m1, m2, group)
|
||||
|
||||
def last_day_of_month(self, d):
|
||||
return datetime.date(d.year, d.month, calendar.monthrange(d.year, d.month)[1])
|
||||
|
||||
|
||||
def test_milestone_sets(self):
|
||||
m1, m2, group = self.create_test_milestones()
|
||||
|
||||
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertTrue(m1.desc in r.content)
|
||||
self.assertTrue(m2.desc not in r.content)
|
||||
|
||||
url = urlreverse('wg_edit_charter_milestones', kwargs=dict(acronym=group.acronym))
|
||||
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertTrue(m1.desc not in r.content)
|
||||
self.assertTrue(m2.desc in r.content)
|
||||
|
||||
def test_add_milestone(self):
|
||||
m1, m2, group = self.create_test_milestones()
|
||||
|
||||
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
|
||||
milestones_before = GroupMilestone.objects.count()
|
||||
events_before = group.groupevent_set.count()
|
||||
docs = Document.objects.filter(type="draft").values_list("name", flat=True)
|
||||
|
||||
due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365))
|
||||
|
||||
# faulty post
|
||||
r = self.client.post(url, { 'prefix': "m-1",
|
||||
'm-1-id': "-1",
|
||||
'm-1-desc': "", # no description
|
||||
'm-1-due_month': str(due.month),
|
||||
'm-1-due_year': str(due.year),
|
||||
'm-1-resolved': "",
|
||||
'm-1-docs': ",".join(docs),
|
||||
'action': "save",
|
||||
})
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(len(q('form ul.errorlist')) > 0)
|
||||
self.assertEquals(GroupMilestone.objects.count(), milestones_before)
|
||||
|
||||
# add
|
||||
r = self.client.post(url, { 'prefix': "m-1",
|
||||
'm-1-id': "-1",
|
||||
'm-1-desc': "Test 3",
|
||||
'm-1-due_month': str(due.month),
|
||||
'm-1-due_year': str(due.year),
|
||||
'm-1-resolved': "",
|
||||
'm-1-docs': ",".join(docs),
|
||||
'action': "save",
|
||||
})
|
||||
self.assertEquals(r.status_code, 302)
|
||||
self.assertEquals(GroupMilestone.objects.count(), milestones_before + 1)
|
||||
self.assertEquals(group.groupevent_set.count(), events_before + 1)
|
||||
|
||||
m = GroupMilestone.objects.get(desc="Test 3")
|
||||
self.assertEquals(m.state_id, "active")
|
||||
self.assertEquals(m.due, due)
|
||||
self.assertEquals(m.resolved, "")
|
||||
self.assertEquals(set(m.docs.values_list("name", flat=True)), set(docs))
|
||||
self.assertTrue("Added milestone" in m.milestonegroupevent_set.all()[0].desc)
|
||||
|
||||
def test_add_milestone_as_chair(self):
|
||||
m1, m2, group = self.create_test_milestones()
|
||||
|
||||
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
|
||||
login_testing_unauthorized(self, "marschairman", url)
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
|
||||
milestones_before = GroupMilestone.objects.count()
|
||||
events_before = group.groupevent_set.count()
|
||||
due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365))
|
||||
|
||||
# add
|
||||
r = self.client.post(url, { 'prefix': "m-1",
|
||||
'm-1-id': -1,
|
||||
'm-1-desc': "Test 3",
|
||||
'm-1-due_month': str(due.month),
|
||||
'm-1-due_year': str(due.year),
|
||||
'm-1-resolved': "",
|
||||
'm-1-docs': "",
|
||||
'action': "save",
|
||||
})
|
||||
self.assertEquals(r.status_code, 302)
|
||||
self.assertEquals(GroupMilestone.objects.count(), milestones_before + 1)
|
||||
|
||||
m = GroupMilestone.objects.get(desc="Test 3")
|
||||
self.assertEquals(m.state_id, "review")
|
||||
self.assertEquals(group.groupevent_set.count(), events_before + 1)
|
||||
self.assertTrue("for review" in m.milestonegroupevent_set.all()[0].desc)
|
||||
|
||||
def test_accept_milestone(self):
|
||||
m1, m2, group = self.create_test_milestones()
|
||||
m1.state_id = "review"
|
||||
m1.save()
|
||||
|
||||
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
|
||||
login_testing_unauthorized(self, "ad", url)
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
|
||||
events_before = group.groupevent_set.count()
|
||||
due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365))
|
||||
|
||||
# add
|
||||
r = self.client.post(url, { 'prefix': "m1",
|
||||
'm1-id': m1.id,
|
||||
'm1-desc': m1.desc,
|
||||
'm1-due_month': str(m1.due.month),
|
||||
'm1-due_year': str(m1.due.year),
|
||||
'm1-resolved': m1.resolved,
|
||||
'm1-docs': ",".join(m1.docs.values_list("name", flat=True)),
|
||||
'm1-accept': "accept",
|
||||
'action': "save",
|
||||
})
|
||||
print r.content
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
m = GroupMilestone.objects.get(pk=m1.pk)
|
||||
self.assertEquals(m.state_id, "active")
|
||||
self.assertEquals(group.groupevent_set.count(), events_before + 1)
|
||||
self.assertTrue("to active from review" in m.milestonegroupevent_set.all()[0].desc)
|
||||
|
||||
def test_delete_milestone(self):
|
||||
m1, m2, group = self.create_test_milestones()
|
||||
|
||||
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
milestones_before = GroupMilestone.objects.count()
|
||||
events_before = group.groupevent_set.count()
|
||||
|
||||
# delete
|
||||
r = self.client.post(url, { 'prefix': "m1",
|
||||
'm1-id': m1.id,
|
||||
'm1-desc': m1.desc,
|
||||
'm1-due_month': str(m1.due.month),
|
||||
'm1-due_year': str(m1.due.year),
|
||||
'm1-resolved': "",
|
||||
'm1-docs': ",".join(m1.docs.values_list("name", flat=True)),
|
||||
'm1-delete': "checked",
|
||||
'action': "save",
|
||||
})
|
||||
self.assertEquals(r.status_code, 302)
|
||||
self.assertEquals(GroupMilestone.objects.count(), milestones_before)
|
||||
self.assertEquals(group.groupevent_set.count(), events_before + 1)
|
||||
|
||||
m = GroupMilestone.objects.get(pk=m1.pk)
|
||||
self.assertEquals(m.state_id, "deleted")
|
||||
self.assertTrue("Deleted milestone" in m.milestonegroupevent_set.all()[0].desc)
|
||||
|
||||
def test_edit_milestone(self):
|
||||
m1, m2, group = self.create_test_milestones()
|
||||
|
||||
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
milestones_before = GroupMilestone.objects.count()
|
||||
events_before = group.groupevent_set.count()
|
||||
docs = Document.objects.filter(type="draft").values_list("name", flat=True)
|
||||
|
||||
due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365))
|
||||
|
||||
# faulty post
|
||||
r = self.client.post(url, { 'prefix': "m1",
|
||||
'm1-id': m1.id,
|
||||
'm1-desc': "", # no description
|
||||
'm1-due_month': str(due.month),
|
||||
'm1-due_year': str(due.year),
|
||||
'm1-resolved': "",
|
||||
'm1-docs': ",".join(docs),
|
||||
'action': "save",
|
||||
})
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(len(q('form ul.errorlist')) > 0)
|
||||
m = GroupMilestone.objects.get(pk=m1.pk)
|
||||
self.assertEquals(GroupMilestone.objects.count(), milestones_before)
|
||||
self.assertEquals(m.due, m1.due)
|
||||
|
||||
# edit
|
||||
mailbox_before = len(outbox)
|
||||
r = self.client.post(url, { 'prefix': "m1",
|
||||
'm1-id': m1.id,
|
||||
'm1-desc': "Test 2 - changed",
|
||||
'm1-due_month': str(due.month),
|
||||
'm1-due_year': str(due.year),
|
||||
'm1-resolved': "Done",
|
||||
'm1-resolved_checkbox': "checked",
|
||||
'm1-docs': ",".join(docs),
|
||||
'action': "save",
|
||||
})
|
||||
self.assertEquals(r.status_code, 302)
|
||||
self.assertEquals(GroupMilestone.objects.count(), milestones_before)
|
||||
self.assertEquals(group.groupevent_set.count(), events_before + 1)
|
||||
|
||||
m = GroupMilestone.objects.get(pk=m1.pk)
|
||||
self.assertEquals(m.state_id, "active")
|
||||
self.assertEquals(m.due, due)
|
||||
self.assertEquals(m.resolved, "Done")
|
||||
self.assertEquals(set(m.docs.values_list("name", flat=True)), set(docs))
|
||||
self.assertTrue("Changed milestone" in m.milestonegroupevent_set.all()[0].desc)
|
||||
self.assertEquals(len(outbox), mailbox_before + 2)
|
||||
self.assertTrue("Milestones changed" in outbox[-2]["Subject"])
|
||||
self.assertTrue(group.ad.role_email("ad").address in str(outbox[-2]))
|
||||
self.assertTrue("Milestones changed" in outbox[-1]["Subject"])
|
||||
self.assertTrue(group.list_email in str(outbox[-1]))
|
||||
|
||||
def test_reset_charter_milestones(self):
|
||||
m1, m2, group = self.create_test_milestones()
|
||||
|
||||
url = urlreverse('wg_reset_charter_milestones', kwargs=dict(acronym=group.acronym))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(q('input[name=milestone]').val(), str(m1.pk))
|
||||
|
||||
events_before = group.charter.docevent_set.count()
|
||||
|
||||
# reset
|
||||
r = self.client.post(url, dict(milestone=[str(m1.pk)]))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
self.assertEquals(GroupMilestone.objects.get(pk=m1.pk).state_id, "active")
|
||||
self.assertEquals(GroupMilestone.objects.get(pk=m2.pk).state_id, "deleted")
|
||||
self.assertEquals(GroupMilestone.objects.filter(due=m1.due, desc=m1.desc, state="charter").count(), 1)
|
||||
|
||||
self.assertEquals(group.charter.docevent_set.count(), events_before + 2) # 1 delete, 1 add
|
||||
|
||||
def test_send_review_needed_reminders(self):
|
||||
draft = make_test_data()
|
||||
|
||||
group = Group.objects.get(acronym="mars")
|
||||
person = Person.objects.get(user__username="marschairman")
|
||||
|
||||
m1 = GroupMilestone.objects.create(group=group,
|
||||
desc="Test 1",
|
||||
due=datetime.date.today(),
|
||||
resolved="",
|
||||
state_id="review")
|
||||
MilestoneGroupEvent.objects.create(
|
||||
group=group, type="changed_milestone",
|
||||
by=person, desc='Added milestone "%s"' % m1.desc, milestone=m1,
|
||||
time=datetime.datetime.now() - datetime.timedelta(seconds=60))
|
||||
|
||||
# send
|
||||
mailbox_before = len(outbox)
|
||||
for g in groups_with_milestones_needing_review():
|
||||
email_milestone_review_reminder(g)
|
||||
|
||||
self.assertEquals(len(outbox), mailbox_before) # too early to send reminder
|
||||
|
||||
|
||||
# add earlier added milestone
|
||||
m2 = GroupMilestone.objects.create(group=group,
|
||||
desc="Test 2",
|
||||
due=datetime.date.today(),
|
||||
resolved="",
|
||||
state_id="review")
|
||||
MilestoneGroupEvent.objects.create(
|
||||
group=group, type="changed_milestone",
|
||||
by=person, desc='Added milestone "%s"' % m2.desc, milestone=m2,
|
||||
time=datetime.datetime.now() - datetime.timedelta(days=10))
|
||||
|
||||
# send
|
||||
mailbox_before = len(outbox)
|
||||
for g in groups_with_milestones_needing_review():
|
||||
email_milestone_review_reminder(g)
|
||||
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue(group.acronym in outbox[-1]["Subject"])
|
||||
self.assertTrue(m1.desc in unicode(outbox[-1]))
|
||||
self.assertTrue(m2.desc in unicode(outbox[-1]))
|
||||
|
||||
def test_send_milestones_due_reminders(self):
|
||||
draft = make_test_data()
|
||||
|
||||
group = Group.objects.get(acronym="mars")
|
||||
person = Person.objects.get(user__username="marschairman")
|
||||
|
||||
early_warning_days = 30
|
||||
|
||||
# due dates here aren't aligned on the last day of the month,
|
||||
# but everything should still work
|
||||
|
||||
m1 = GroupMilestone.objects.create(group=group,
|
||||
desc="Test 1",
|
||||
due=datetime.date.today(),
|
||||
resolved="Done",
|
||||
state_id="active")
|
||||
m2 = GroupMilestone.objects.create(group=group,
|
||||
desc="Test 2",
|
||||
due=datetime.date.today() + datetime.timedelta(days=early_warning_days - 10),
|
||||
resolved="",
|
||||
state_id="active")
|
||||
|
||||
# send
|
||||
mailbox_before = len(outbox)
|
||||
for g in groups_needing_milestones_due_reminder(early_warning_days):
|
||||
email_milestones_due(g, early_warning_days)
|
||||
|
||||
self.assertEquals(len(outbox), mailbox_before) # none found
|
||||
|
||||
m1.resolved = ""
|
||||
m1.save()
|
||||
|
||||
m2.due = datetime.date.today() + datetime.timedelta(days=early_warning_days)
|
||||
m2.save()
|
||||
|
||||
# send
|
||||
mailbox_before = len(outbox)
|
||||
for g in groups_needing_milestones_due_reminder(early_warning_days):
|
||||
email_milestones_due(g, early_warning_days)
|
||||
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue(group.acronym in outbox[-1]["Subject"])
|
||||
self.assertTrue(m1.desc in unicode(outbox[-1]))
|
||||
self.assertTrue(m2.desc in unicode(outbox[-1]))
|
||||
|
||||
def test_send_milestones_overdue_reminders(self):
|
||||
draft = make_test_data()
|
||||
|
||||
group = Group.objects.get(acronym="mars")
|
||||
person = Person.objects.get(user__username="marschairman")
|
||||
|
||||
# due dates here aren't aligned on the last day of the month,
|
||||
# but everything should still work
|
||||
|
||||
m1 = GroupMilestone.objects.create(group=group,
|
||||
desc="Test 1",
|
||||
due=datetime.date.today() - datetime.timedelta(days=200),
|
||||
resolved="Done",
|
||||
state_id="active")
|
||||
m2 = GroupMilestone.objects.create(group=group,
|
||||
desc="Test 2",
|
||||
due=datetime.date.today() - datetime.timedelta(days=10),
|
||||
resolved="",
|
||||
state_id="active")
|
||||
|
||||
# send
|
||||
mailbox_before = len(outbox)
|
||||
for g in groups_needing_milestones_overdue_reminder(grace_period=30):
|
||||
email_milestones_overdue(g)
|
||||
|
||||
self.assertEquals(len(outbox), mailbox_before) # none found
|
||||
|
||||
m1.resolved = ""
|
||||
m1.save()
|
||||
|
||||
m2.due = self.last_day_of_month(datetime.date.today() - datetime.timedelta(days=300))
|
||||
m2.save()
|
||||
|
||||
# send
|
||||
mailbox_before = len(outbox)
|
||||
for g in groups_needing_milestones_overdue_reminder(grace_period=30):
|
||||
email_milestones_overdue(g)
|
||||
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue(group.acronym in outbox[-1]["Subject"])
|
||||
self.assertTrue(m1.desc in unicode(outbox[-1]))
|
||||
self.assertTrue(m2.desc in unicode(outbox[-1]))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright The IETF Trust 2008, All Rights Reserved
|
||||
|
||||
from django.conf.urls.defaults import patterns, include
|
||||
from ietf.wginfo import views, edit
|
||||
from ietf.wginfo import views, edit, milestones
|
||||
from django.views.generic.simple import redirect_to
|
||||
|
||||
|
||||
|
@ -21,11 +21,14 @@ urlpatterns = patterns('',
|
|||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/documents/txt/$', views.wg_documents_txt),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/$', views.wg_documents_html, None, "wg_docs"),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/charter/$', views.wg_charter, None, 'wg_charter'),
|
||||
(r'^(?P<acronym>[A-Za-z0-9-]+)/charter/', include('ietf.wgcharter.urls')),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/history/', views.history),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/edit/', edit.edit, {'action': "edit"}, "wg_edit"),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/init-charter/', edit.submit_initial_charter, None, "wg_init_charter"),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/conclude/', edit.conclude, None, "wg_conclude"),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/history/$', views.history),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/edit/$', edit.edit, {'action': "edit"}, "wg_edit"),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/conclude/$', edit.conclude, None, "wg_conclude"),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/milestones/$', milestones.edit_milestones, {'milestone_set': "current"}, "wg_edit_milestones"),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/milestones/charter/$', milestones.edit_milestones, {'milestone_set': "charter"}, "wg_edit_charter_milestones"),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/milestones/charter/reset/$', milestones.reset_charter_milestones, None, "wg_reset_charter_milestones"),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/ajax/searchdocs/$', milestones.ajax_search_docs, None, "wg_ajax_search_docs"),
|
||||
(r'^(?P<acronym>[^/]+)/management/', include('ietf.wgchairs.urls')),
|
||||
|
||||
)
|
||||
|
|
|
@ -55,7 +55,7 @@ def fill_in_charter_info(wg, include_drafts=False):
|
|||
wg.techadvisors = Email.objects.filter(role__group=wg, role__name="techadv")
|
||||
wg.editors = Email.objects.filter(role__group=wg, role__name="editor")
|
||||
wg.secretaries = Email.objects.filter(role__group=wg, role__name="secr")
|
||||
wg.milestones = wg.groupmilestone_set.all().order_by('expected_due_date')
|
||||
wg.milestones = wg.groupmilestone_set.filter(state="active").order_by('due')
|
||||
|
||||
if include_drafts:
|
||||
aliases = DocAlias.objects.filter(document__type="draft", document__group=wg).select_related('document').order_by("name")
|
||||
|
@ -194,29 +194,28 @@ def wg_charter(request, acronym):
|
|||
concluded = wg.status_id in [ 2, 3, ]
|
||||
proposed = (wg.status_id == 4)
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
fill_in_charter_info(wg)
|
||||
actions = []
|
||||
fill_in_charter_info(wg)
|
||||
actions = []
|
||||
if wg.state_id != "conclude":
|
||||
actions.append(("Edit WG", urlreverse("wg_edit", kwargs=dict(acronym=wg.acronym))))
|
||||
|
||||
e = wg.latest_event(type__in=("changed_state", "requested_close",))
|
||||
requested_close = wg.state_id != "conclude" and e and e.type == "requested_close"
|
||||
e = wg.latest_event(type__in=("changed_state", "requested_close",))
|
||||
requested_close = wg.state_id != "conclude" and e and e.type == "requested_close"
|
||||
|
||||
if wg.state_id != "conclude":
|
||||
actions.append(("Edit WG", urlreverse("wg_edit", kwargs=dict(acronym=wg.acronym))))
|
||||
if wg.state_id in ("active", "dormant"):
|
||||
actions.append(("Request closing WG", urlreverse("wg_conclude", kwargs=dict(acronym=wg.acronym))))
|
||||
if wg.state_id in ("active", "dormant"):
|
||||
actions.append(("Request closing WG", urlreverse("wg_conclude", kwargs=dict(acronym=wg.acronym))))
|
||||
|
||||
context = get_wg_menu_context(wg, "charter")
|
||||
context.update(dict(
|
||||
actions=actions,
|
||||
requested_close=requested_close,
|
||||
))
|
||||
context = get_wg_menu_context(wg, "charter")
|
||||
context.update(dict(
|
||||
actions=actions,
|
||||
is_chair=request.user.is_authenticated() and wg.role_set.filter(name="chair", person__user=request.user),
|
||||
milestones_in_review=wg.groupmilestone_set.filter(state="review"),
|
||||
requested_close=requested_close,
|
||||
))
|
||||
|
||||
return render_to_response('wginfo/wg_charterREDESIGN.html',
|
||||
context,
|
||||
RequestContext(request))
|
||||
|
||||
return render_to_response('wginfo/wg_charter.html', {'wg': wg, 'concluded':concluded, 'proposed': proposed, 'selected':'charter'}, RequestContext(request))
|
||||
return render_to_response('wginfo/wg_charter.html',
|
||||
context,
|
||||
RequestContext(request))
|
||||
|
||||
def get_wg_menu_context(wg, selected):
|
||||
# it would probably be better to refactor wginfo into rendering
|
||||
|
|
|
@ -200,4 +200,8 @@ li.info { margin: 0.5em; background-color: #ff8; }
|
|||
li.success { margin: 0.5em; background-color: #4f4; }
|
||||
li.warning { margin: 0.5em; background-color: #fc8; color: black;}
|
||||
li.error { margin: 0.5em; background-color: #f44; }
|
||||
|
||||
|
||||
table.milestones td.due { vertical-align: top; width: 80px; }
|
||||
table.milestones .doc { display: block; padding-left: 1em; }
|
||||
|
||||
.stream-state .milestone { display: inline-block; font-size: smaller; background-color: #d5dde6; padding: 0 0.2em; margin-left: 0.3em; }
|
||||
|
|
|
@ -6,8 +6,6 @@ ul.token-input-list {
|
|||
width: 400px;
|
||||
border: 1px solid #999;
|
||||
cursor: text;
|
||||
font-size: 12px;
|
||||
font-family: Verdana;
|
||||
z-index: 999;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
@ -34,9 +32,8 @@ li.token-input-token {
|
|||
height: 1%;
|
||||
margin: 3px;
|
||||
padding: 3px 5px;
|
||||
background-color: #d0efa0;
|
||||
background-color: #e8f0fa;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
cursor: default;
|
||||
display: block;
|
||||
}
|
||||
|
@ -54,8 +51,8 @@ li.token-input-token span {
|
|||
}
|
||||
|
||||
li.token-input-selected-token {
|
||||
background-color: #08844e;
|
||||
color: #fff;
|
||||
background-color: #d5dde6;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
li.token-input-selected-token span {
|
||||
|
@ -71,15 +68,12 @@ div.token-input-dropdown {
|
|||
border-right: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
cursor: default;
|
||||
font-size: 12px;
|
||||
font-family: Verdana;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
div.token-input-dropdown p {
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
|
@ -108,6 +102,6 @@ div.token-input-dropdown ul li em {
|
|||
}
|
||||
|
||||
div.token-input-dropdown ul li.token-input-selected-dropdown-item {
|
||||
background-color: #d0efa0;
|
||||
background-color: #d5dde6;
|
||||
}
|
||||
|
||||
|
|
107
static/js/edit-milestones.js
Normal file
107
static/js/edit-milestones.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
jQuery(function () {
|
||||
var idCounter = -1;
|
||||
|
||||
// make sure we got the lowest number for idCounter
|
||||
jQuery('#milestones-form .edit-milestone input[name$="-id"]').each(function () {
|
||||
var v = +this.value;
|
||||
if (!isNaN(v) && v < idCounter)
|
||||
idCounter = v - 1;
|
||||
});
|
||||
|
||||
function setSubmitButtonState() {
|
||||
var action, label;
|
||||
if (jQuery("#milestones-form input[name$=delete]:visible").length > 0)
|
||||
action = "review";
|
||||
else
|
||||
action = "save";
|
||||
|
||||
var submit = jQuery("#milestones-form input[type=submit]");
|
||||
submit.val(submit.data("label" + action));
|
||||
jQuery("#milestones-form input[name=action]").val(action);
|
||||
}
|
||||
|
||||
jQuery("#milestones-form tr.milestone").click(function () {
|
||||
var row = jQuery(this), editRow = row.next("tr.edit-milestone");
|
||||
|
||||
if (row.hasClass("add")) {
|
||||
// move Add milestone row and duplicate hidden template
|
||||
row.closest("table").append(row).append(editRow.clone());
|
||||
|
||||
// fixup template
|
||||
var newId = idCounter;
|
||||
--idCounter;
|
||||
|
||||
var prefix = "m" + newId;
|
||||
editRow.find('input[name="prefix"]').val(prefix);
|
||||
|
||||
editRow.find("input,select,textarea").each(function () {
|
||||
if (this.name == "prefix")
|
||||
return;
|
||||
|
||||
if (this.name == "id")
|
||||
this.value = "" + idCounter;
|
||||
|
||||
this.name = prefix + "-" + this.name;
|
||||
});
|
||||
|
||||
editRow.removeClass("template");
|
||||
setupTokenizedField(editRow.find(".tokenized-field")); // from tokenized-field.js
|
||||
editRow.show();
|
||||
}
|
||||
else {
|
||||
row.hide();
|
||||
editRow.show();
|
||||
}
|
||||
|
||||
editRow.find('input[name$="expanded_for_editing"]').val("True");
|
||||
editRow.find('input[name$="desc"]').focus();
|
||||
|
||||
setSubmitButtonState();
|
||||
});
|
||||
|
||||
function setResolvedState() {
|
||||
var resolved = jQuery(this).is(":checked");
|
||||
var label = jQuery(this).siblings("label");
|
||||
var reason = jQuery(this).siblings("input[type=text]");
|
||||
if (resolved) {
|
||||
if (label.text().indexOf(":") == -1)
|
||||
label.text(label.text() + ":");
|
||||
reason.show();
|
||||
if (!reason.val())
|
||||
reason.val(finishedMilestoneText);
|
||||
}
|
||||
else {
|
||||
if (label.text().indexOf(":") != -1)
|
||||
label.text(label.text().replace(":", ""));
|
||||
reason.hide();
|
||||
reason.val("");
|
||||
}
|
||||
}
|
||||
|
||||
jQuery("#milestones-form .edit-milestone .resolved input[type=checkbox]")
|
||||
.each(setResolvedState)
|
||||
.live("change", setResolvedState);
|
||||
|
||||
function setDeleteState() {
|
||||
var top = jQuery(this).closest(".edit-milestone");
|
||||
|
||||
if (jQuery(this).is(":checked")) {
|
||||
if (+top.find('input[name$="id"]').val() < 0) {
|
||||
top.remove();
|
||||
setSubmitButtonState();
|
||||
}
|
||||
else
|
||||
top.addClass("delete")
|
||||
}
|
||||
else
|
||||
top.removeClass("delete")
|
||||
}
|
||||
|
||||
jQuery("#milestones-form .edit-milestone .delete input[type=checkbox]")
|
||||
.each(setDeleteState)
|
||||
.live("change", setDeleteState);
|
||||
|
||||
jQuery('#milestones-form .edit-milestone .errorlist').each(function () {
|
||||
jQuery(this).closest(".edit-milestone").prev().click();
|
||||
});
|
||||
});
|
|
@ -1,13 +0,0 @@
|
|||
jQuery(function () {
|
||||
jQuery(".emails-field").each(function () {
|
||||
var e = jQuery(this);
|
||||
var pre = [];
|
||||
if (e.val())
|
||||
pre = JSON.parse(e.val());
|
||||
e.tokenInput(e.data("ajax-url"), {
|
||||
hintText: "",
|
||||
preventDuplicates: true,
|
||||
prePopulate: pre
|
||||
});
|
||||
});
|
||||
});
|
20
static/js/tokenized-field.js
Normal file
20
static/js/tokenized-field.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
function setupTokenizedField(field) {
|
||||
if (field.parents(".template").length > 0)
|
||||
return; // don't tokenize hidden template snippets
|
||||
|
||||
var pre = [];
|
||||
if (field.val())
|
||||
pre = JSON.parse((field.val() || "").replace(/"/g, '"'));
|
||||
else if (field.data("pre"))
|
||||
pre = JSON.parse((field.attr("data-pre") || "").replace(/"/g, '"'));
|
||||
|
||||
field.tokenInput(field.data("ajaxurl"), {
|
||||
hintText: "",
|
||||
preventDuplicates: true,
|
||||
prePopulate: pre
|
||||
});
|
||||
}
|
||||
|
||||
jQuery(function () {
|
||||
jQuery(".tokenized-field").each(function () { setupTokenizedField(jQuery(this)); });
|
||||
});
|
Loading…
Reference in a new issue