Merged in branch branch/yaco/wgchairs from esanchez@yaco.es. This provides the WG Chair Tracker functionality.

- Legacy-Id: 3120
This commit is contained in:
Henrik Levkowetz 2011-05-11 20:27:12 +00:00
commit a142e89a87
105 changed files with 10302 additions and 35 deletions

3
.gitignore vendored
View file

@ -15,3 +15,6 @@
.*.swp
.DS_store
# Simulated Subversion default ignores end here
/.project
/.pydevproject
/.settings

2
ietf/.gitignore vendored
View file

@ -1 +1,3 @@
/*.pyc
/settings_local.py
/ietfdb.sql.gz

View file

@ -49,6 +49,7 @@ from ietf.idtracker.templatetags.ietf_filters import format_textarea, fill
from ietf.idrfc import markup_txt
from ietf.idrfc.models import RfcIndex, DraftVersions
from ietf.idrfc.idrfc_wrapper import BallotWrapper, IdWrapper, RfcWrapper
from ietf.ietfworkflows.utils import get_full_info_for_draft
def document_debug(request, name):
r = re.compile("^rfc([1-9][0-9]*)$")
@ -123,25 +124,6 @@ def document_main(request, name, tab):
doc = IdWrapper(id)
info = {}
stream_id = doc.stream_id()
if stream_id == 2:
stream = " (IAB document)"
elif stream_id == 3:
stream = " (IRTF document)"
elif stream_id == 4:
stream = " (Independent submission via RFC Editor)"
elif doc.group_acronym():
stream = " ("+doc.group_acronym().upper()+" WG document)"
else:
stream = " (Individual document)"
if id.status.status == "Active":
info['is_active_draft'] = True
info['type'] = "Active Internet-Draft"+stream
else:
info['is_active_draft'] = False
info['type'] = "Old Internet-Draft"+stream
info['has_pdf'] = (".pdf" in doc.file_types())
info['is_rfc'] = False
@ -159,6 +141,7 @@ def document_main(request, name, tab):
{'content1':content1, 'content2':content2,
'doc':doc, 'info':info, 'tab':tab,
'include_text':include_text(request),
'stream_info': get_full_info_for_draft(id),
'versions':versions, 'history':history},
context_instance=RequestContext(request));

View file

@ -380,5 +380,3 @@ def add_comment(request, name):
dict(doc=doc,
form=form),
context_instance=RequestContext(request))

View file

@ -0,0 +1,437 @@
from south.db import db
from django.db import models
from ietf.idtracker.models import *
class Migration:
def forwards(self, orm):
# Adding field 'InternetDraft.shepherd'
db.add_column('internet_drafts', 'shepherd', orm['idtracker.internetdraft:shepherd'])
def backwards(self, orm):
# Deleting field 'InternetDraft.shepherd'
db.delete_column('internet_drafts', 'shepherd_id')
models = {
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.area': {
'Meta': {'db_table': "'areas'"},
'area_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'extra_email_addresses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'last_modified_date': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaStatus']"})
},
'idtracker.areadirector': {
'Meta': {'db_table': "'area_directors'"},
'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']", 'null': 'True', 'db_column': "'area_acronym_id'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.areagroup': {
'Meta': {'db_table': "'area_group'"},
'area': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'areagroup'", 'db_column': "'area_acronym_id'", 'to': "orm['idtracker.Area']"}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']", 'unique': 'True', 'db_column': "'group_acronym_id'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.areastatus': {
'Meta': {'db_table': "'area_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.areawgurl': {
'Meta': {'db_table': "'wg_www_pages'"},
'description': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True', 'db_column': "'area_ID'"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_column': "'area_Name'"}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.ballotinfo': {
'Meta': {'db_table': "'ballot_info'"},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'an_sent': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'an_sent_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ansent'", 'null': 'True', 'db_column': "'an_sent_by'", 'to': "orm['idtracker.IESGLogin']"}),
'an_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'approval_text': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'ballot': ('django.db.models.fields.AutoField', [], {'primary_key': 'True', 'db_column': "'ballot_id'"}),
'ballot_issued': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'ballot_writeup': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'defer': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'defer_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deferred'", 'null': 'True', 'db_column': "'defer_by'", 'to': "orm['idtracker.IESGLogin']"}),
'defer_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'last_call_text': ('django.db.models.fields.TextField', [], {'blank': 'True'})
},
'idtracker.chairshistory': {
'Meta': {'db_table': "'chairs_history'"},
'chair_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Role']"}),
'end_year': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'present_chair': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'start_year': ('django.db.models.fields.IntegerField', [], {})
},
'idtracker.documentcomment': {
'Meta': {'db_table': "'document_comments'"},
'ballot': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'comment_text': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'created_by': ('BrokenForeignKey', ["orm['idtracker.IESGLogin']"], {'null': 'True', 'db_column': "'created_by'", 'null_values': '(0,999)'}),
'date': ('django.db.models.fields.DateField', [], {'default': 'datetime.date.today', 'db_column': "'comment_date'"}),
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDInternal']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'origin_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments_coming_from_state'", 'null': 'True', 'db_column': "'origin_state'", 'to': "orm['idtracker.IDState']"}),
'public_flag': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'result_state': ('BrokenForeignKey', ["orm['idtracker.IDState']"], {'related_name': '"comments_leading_to_state"', 'null': 'True', 'db_column': "'result_state'", 'null_values': '(0,99)'}),
'rfc_flag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'time': ('django.db.models.fields.CharField', [], {'default': "'05:10:39'", 'max_length': '20', 'db_column': "'comment_time'"}),
'version': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'})
},
'idtracker.emailaddress': {
'Meta': {'db_table': "'email_addresses'"},
'address': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'email_address'"}),
'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'db_column': "'email_comment'", 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person_or_org': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'priority': ('django.db.models.fields.IntegerField', [], {'db_column': "'email_priority'"}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'db_column': "'email_type'"})
},
'idtracker.goalmilestone': {
'Meta': {'db_table': "'goals_milestones'"},
'description': ('django.db.models.fields.TextField', [], {}),
'done': ('django.db.models.fields.CharField', [], {'max_length': '4', 'blank': 'True'}),
'done_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expected_due_date': ('django.db.models.fields.DateField', [], {}),
'gm_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {})
},
'idtracker.idauthor': {
'Meta': {'db_table': "'id_authors'"},
'author_order': ('django.db.models.fields.IntegerField', [], {}),
'document': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'authors'", 'db_column': "'id_document_tag'", 'to': "orm['idtracker.InternetDraft']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.idintendedstatus': {
'Meta': {'db_table': "'id_intended_status'"},
'intended_status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idinternal': {
'Meta': {'db_table': "'id_internal'"},
'agenda': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'approved_in_minute': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'area_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']"}),
'assigned_to': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}),
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'drafts'", 'db_column': "'ballot_id'", 'to': "orm['idtracker.BallotInfo']"}),
'cur_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'docs'", 'db_column': "'cur_state'", 'to': "orm['idtracker.IDState']"}),
'cur_sub_state': ('BrokenForeignKey', ["orm['idtracker.IDSubState']"], {'related_name': "'docs'", 'null': 'True', 'null_values': '(0,-1)', 'blank': 'True'}),
'dnp': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'dnp_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'draft': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.InternetDraft']", 'unique': 'True', 'primary_key': 'True', 'db_column': "'id_document_tag'"}),
'email_display': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'event_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'group_flag': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}),
'job_owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'documents'", 'db_column': "'job_owner'", 'to': "orm['idtracker.IESGLogin']"}),
'mark_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'marked'", 'db_column': "'mark_by'", 'to': "orm['idtracker.IESGLogin']"}),
'noproblem': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'prev_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'docs_prev'", 'db_column': "'prev_state'", 'to': "orm['idtracker.IDState']"}),
'prev_sub_state': ('BrokenForeignKey', ["orm['idtracker.IDSubState']"], {'related_name': "'docs_prev'", 'null': 'True', 'null_values': '(0,-1)', 'blank': 'True'}),
'primary_flag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'resurrect_requested_by': ('BrokenForeignKey', ["orm['idtracker.IESGLogin']"], {'related_name': "'docsresurrected'", 'null': 'True', 'db_column': "'resurrect_requested_by'", 'blank': 'True'}),
'returning_item': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'rfc_flag': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'state_change_notice_to': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'status_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'telechat_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'token_email': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'token_name': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}),
'via_rfc_editor': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.idnextstate': {
'Meta': {'db_table': "'ref_next_states_new'"},
'condition': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'cur_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nextstate'", 'to': "orm['idtracker.IDState']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'next_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'prevstate'", 'to': "orm['idtracker.IDState']"})
},
'idtracker.idstate': {
'Meta': {'db_table': "'ref_doc_states_new'"},
'description': ('django.db.models.fields.TextField', [], {'db_column': "'document_desc'", 'blank': 'True'}),
'document_state_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'equiv_group_flag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'state': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_column': "'document_state_val'"})
},
'idtracker.idstatus': {
'Meta': {'db_table': "'id_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idsubstate': {
'Meta': {'db_table': "'sub_state'"},
'description': ('django.db.models.fields.TextField', [], {'db_column': "'sub_state_desc'", 'blank': 'True'}),
'sub_state': ('django.db.models.fields.CharField', [], {'max_length': '55', 'db_column': "'sub_state_val'"}),
'sub_state_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.iesgcomment': {
'Meta': {'unique_together': "(('ballot', 'ad'),)", 'db_table': "'ballots_comment'"},
'active': ('django.db.models.fields.IntegerField', [], {}),
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IESGLogin']"}),
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['idtracker.BallotInfo']"}),
'date': ('django.db.models.fields.DateField', [], {'db_column': "'comment_date'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'text': ('django.db.models.fields.TextField', [], {'db_column': "'comment_text'", 'blank': 'True'})
},
'idtracker.iesgdiscuss': {
'Meta': {'unique_together': "(('ballot', 'ad'),)", 'db_table': "'ballots_discuss'"},
'active': ('django.db.models.fields.IntegerField', [], {}),
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IESGLogin']"}),
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'discusses'", 'to': "orm['idtracker.BallotInfo']"}),
'date': ('django.db.models.fields.DateField', [], {'db_column': "'discuss_date'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'text': ('django.db.models.fields.TextField', [], {'db_column': "'discuss_text'", 'blank': 'True'})
},
'idtracker.iesglogin': {
'Meta': {'db_table': "'iesg_login'"},
'default_search': ('django.db.models.fields.NullBooleanField', [], {'null': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}),
'login_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '25'}),
'person': ('BrokenForeignKey', ["orm['idtracker.PersonOrOrgInfo']"], {'unique': 'True', 'null': 'True', 'db_column': "'person_or_org_tag'", 'null_values': '(0,888888)'}),
'pgp_id': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
'user_level': ('django.db.models.fields.IntegerField', [], {})
},
'idtracker.ietfwg': {
'Meta': {'db_table': "'groups_ietf'"},
'area_director': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaDirector']", 'null': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'dormant_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '60', 'blank': 'True'}),
'email_archive': ('django.db.models.fields.CharField', [], {'max_length': '95', 'blank': 'True'}),
'email_keyword': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'email_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
'group_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'group_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGType']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'meeting_scheduled': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'meeting_scheduled_old': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGStatus']"})
},
'idtracker.internetdraft': {
'Meta': {'db_table': "'internet_drafts'"},
'abstract': ('django.db.models.fields.TextField', [], {}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_discussion_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'dunn_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'expired_tombstone': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'extension_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Acronym']", 'db_column': "'group_acronym_id'"}),
'id_document_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id_document_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDIntendedStatus']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_changes': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True'}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'replaced_by': ('BrokenForeignKey', ["orm['idtracker.InternetDraft']"], {'related_name': "'replaces_set'", 'null': 'True', 'db_column': "'replaced_by'", 'blank': 'True'}),
'review_by_rfc_editor': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'revision_date': ('django.db.models.fields.DateField', [], {}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'start_date': ('django.db.models.fields.DateField', [], {}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDStatus']"}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'id_document_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {}),
'wgreturn_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.irtf': {
'Meta': {'db_table': "'irtf'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'irtf_acronym'", 'blank': 'True'}),
'charter_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'irtf_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'meeting_scheduled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'irtf_name'", 'blank': 'True'})
},
'idtracker.irtfchair': {
'Meta': {'db_table': "'irtf_chairs'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'irtf': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IRTF']"}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'idtracker.phonenumber': {
'Meta': {'db_table': "'phone_numbers'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person_or_org': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'phone_comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'phone_number': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'phone_priority': ('django.db.models.fields.IntegerField', [], {}),
'phone_type': ('django.db.models.fields.CharField', [], {'max_length': '3'})
},
'idtracker.position': {
'Meta': {'unique_together': "(('ballot', 'ad'),)", 'db_table': "'ballots'"},
'abstain': ('django.db.models.fields.IntegerField', [], {}),
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IESGLogin']"}),
'approve': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'positions'", 'to': "orm['idtracker.BallotInfo']"}),
'discuss': ('django.db.models.fields.IntegerField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'noobj': ('django.db.models.fields.IntegerField', [], {'db_column': "'no_col'"}),
'recuse': ('django.db.models.fields.IntegerField', [], {}),
'yes': ('django.db.models.fields.IntegerField', [], {'db_column': "'yes_col'"})
},
'idtracker.postaladdress': {
'Meta': {'db_table': "'postal_addresses'"},
'address_priority': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
'aff_company_key': ('django.db.models.fields.CharField', [], {'max_length': '70', 'blank': 'True'}),
'affiliated_company': ('django.db.models.fields.CharField', [], {'max_length': '70', 'blank': 'True'}),
'city': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'country': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'department': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mail_stop': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'person_or_org': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'person_title': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'staddr1': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'staddr2': ('django.db.models.fields.CharField', [], {'max_length': '40', 'blank': 'True'}),
'state_or_prov': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'})
},
'idtracker.rfc': {
'Meta': {'db_table': "'rfcs'"},
'area_acronym': ('django.db.models.fields.CharField', [], {'max_length': '8', 'blank': 'True'}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'draft_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'fyi_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'group_acronym': ('django.db.models.fields.CharField', [], {'max_length': '8', 'blank': 'True'}),
'historic_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'default': '5', 'to': "orm['idtracker.RfcIntendedStatus']", 'db_column': "'intended_status_id'"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'online_version': ('django.db.models.fields.CharField', [], {'default': "'YES'", 'max_length': '3'}),
'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'rfc_name_key': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'primary_key': 'True'}),
'rfc_published_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'standard_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.RfcStatus']", 'db_column': "'status_id'"}),
'std_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'db_column': "'rfc_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.rfcauthor': {
'Meta': {'db_table': "'rfc_authors'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'rfc': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'authors'", 'db_column': "'rfc_number'", 'to': "orm['idtracker.Rfc']"})
},
'idtracker.rfcintendedstatus': {
'Meta': {'db_table': "'rfc_intend_status'"},
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"})
},
'idtracker.rfcobsolete': {
'Meta': {'db_table': "'rfcs_obsolete'"},
'action': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'rfc': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'updates_or_obsoletes'", 'db_column': "'rfc_number'", 'to': "orm['idtracker.Rfc']"}),
'rfc_acted_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'updated_or_obsoleted_by'", 'db_column': "'rfc_acted_on'", 'to': "orm['idtracker.Rfc']"})
},
'idtracker.rfcstatus': {
'Meta': {'db_table': "'rfc_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.role': {
'Meta': {'db_table': "'chairs'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'role_name': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'chair_name'"})
},
'idtracker.wgchair': {
'Meta': {'db_table': "'g_chairs'"},
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.wgeditor': {
'Meta': {'db_table': "'g_editors'"},
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'unique': 'True', 'db_column': "'person_or_org_tag'"})
},
'idtracker.wgsecretary': {
'Meta': {'db_table': "'g_secretaries'"},
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.wgstatus': {
'Meta': {'db_table': "'g_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.wgtechadvisor': {
'Meta': {'db_table': "'g_tech_advisors'"},
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.wgtype': {
'Meta': {'db_table': "'g_type'"},
'group_type_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'group_type'"})
}
}
complete_apps = ['idtracker']

View file

@ -0,0 +1,439 @@
from south.db import db
from django.db import models
from ietf.idtracker.models import *
class Migration:
def forwards(self, orm):
# Changing field 'InternetDraft.shepherd'
# (to signature: django.db.models.fields.related.ForeignKey(to=orm['idtracker.PersonOrOrgInfo'], null=True, blank=True))
db.alter_column('internet_drafts', 'shepherd_id', orm['idtracker.internetdraft:shepherd'])
def backwards(self, orm):
# Changing field 'InternetDraft.shepherd'
# (to signature: django.db.models.fields.related.ForeignKey(to=orm['idtracker.PersonOrOrgInfo']))
db.alter_column('internet_drafts', 'shepherd_id', orm['idtracker.internetdraft:shepherd'])
models = {
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.area': {
'Meta': {'db_table': "'areas'"},
'area_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'extra_email_addresses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'last_modified_date': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaStatus']"})
},
'idtracker.areadirector': {
'Meta': {'db_table': "'area_directors'"},
'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']", 'null': 'True', 'db_column': "'area_acronym_id'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.areagroup': {
'Meta': {'db_table': "'area_group'"},
'area': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'areagroup'", 'db_column': "'area_acronym_id'", 'to': "orm['idtracker.Area']"}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']", 'unique': 'True', 'db_column': "'group_acronym_id'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.areastatus': {
'Meta': {'db_table': "'area_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.areawgurl': {
'Meta': {'db_table': "'wg_www_pages'"},
'description': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True', 'db_column': "'area_ID'"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_column': "'area_Name'"}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.ballotinfo': {
'Meta': {'db_table': "'ballot_info'"},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'an_sent': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'an_sent_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ansent'", 'null': 'True', 'db_column': "'an_sent_by'", 'to': "orm['idtracker.IESGLogin']"}),
'an_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'approval_text': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'ballot': ('django.db.models.fields.AutoField', [], {'primary_key': 'True', 'db_column': "'ballot_id'"}),
'ballot_issued': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'ballot_writeup': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'defer': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'defer_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deferred'", 'null': 'True', 'db_column': "'defer_by'", 'to': "orm['idtracker.IESGLogin']"}),
'defer_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'last_call_text': ('django.db.models.fields.TextField', [], {'blank': 'True'})
},
'idtracker.chairshistory': {
'Meta': {'db_table': "'chairs_history'"},
'chair_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Role']"}),
'end_year': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'present_chair': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'start_year': ('django.db.models.fields.IntegerField', [], {})
},
'idtracker.documentcomment': {
'Meta': {'db_table': "'document_comments'"},
'ballot': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'comment_text': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'created_by': ('BrokenForeignKey', ["orm['idtracker.IESGLogin']"], {'null': 'True', 'db_column': "'created_by'", 'null_values': '(0,999)'}),
'date': ('django.db.models.fields.DateField', [], {'default': 'datetime.date.today', 'db_column': "'comment_date'"}),
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDInternal']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'origin_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments_coming_from_state'", 'null': 'True', 'db_column': "'origin_state'", 'to': "orm['idtracker.IDState']"}),
'public_flag': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'result_state': ('BrokenForeignKey', ["orm['idtracker.IDState']"], {'related_name': '"comments_leading_to_state"', 'null': 'True', 'db_column': "'result_state'", 'null_values': '(0,99)'}),
'rfc_flag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'time': ('django.db.models.fields.CharField', [], {'default': "'08:36:20'", 'max_length': '20', 'db_column': "'comment_time'"}),
'version': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'})
},
'idtracker.emailaddress': {
'Meta': {'db_table': "'email_addresses'"},
'address': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'email_address'"}),
'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'db_column': "'email_comment'", 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person_or_org': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'priority': ('django.db.models.fields.IntegerField', [], {'db_column': "'email_priority'"}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'db_column': "'email_type'"})
},
'idtracker.goalmilestone': {
'Meta': {'db_table': "'goals_milestones'"},
'description': ('django.db.models.fields.TextField', [], {}),
'done': ('django.db.models.fields.CharField', [], {'max_length': '4', 'blank': 'True'}),
'done_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expected_due_date': ('django.db.models.fields.DateField', [], {}),
'gm_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {})
},
'idtracker.idauthor': {
'Meta': {'db_table': "'id_authors'"},
'author_order': ('django.db.models.fields.IntegerField', [], {}),
'document': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'authors'", 'db_column': "'id_document_tag'", 'to': "orm['idtracker.InternetDraft']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.idintendedstatus': {
'Meta': {'db_table': "'id_intended_status'"},
'intended_status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idinternal': {
'Meta': {'db_table': "'id_internal'"},
'agenda': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'approved_in_minute': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'area_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']"}),
'assigned_to': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}),
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'drafts'", 'db_column': "'ballot_id'", 'to': "orm['idtracker.BallotInfo']"}),
'cur_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'docs'", 'db_column': "'cur_state'", 'to': "orm['idtracker.IDState']"}),
'cur_sub_state': ('BrokenForeignKey', ["orm['idtracker.IDSubState']"], {'related_name': "'docs'", 'null': 'True', 'null_values': '(0,-1)', 'blank': 'True'}),
'dnp': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'dnp_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'draft': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.InternetDraft']", 'unique': 'True', 'primary_key': 'True', 'db_column': "'id_document_tag'"}),
'email_display': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'event_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'group_flag': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}),
'job_owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'documents'", 'db_column': "'job_owner'", 'to': "orm['idtracker.IESGLogin']"}),
'mark_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'marked'", 'db_column': "'mark_by'", 'to': "orm['idtracker.IESGLogin']"}),
'noproblem': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'prev_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'docs_prev'", 'db_column': "'prev_state'", 'to': "orm['idtracker.IDState']"}),
'prev_sub_state': ('BrokenForeignKey', ["orm['idtracker.IDSubState']"], {'related_name': "'docs_prev'", 'null': 'True', 'null_values': '(0,-1)', 'blank': 'True'}),
'primary_flag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'resurrect_requested_by': ('BrokenForeignKey', ["orm['idtracker.IESGLogin']"], {'related_name': "'docsresurrected'", 'null': 'True', 'db_column': "'resurrect_requested_by'", 'blank': 'True'}),
'returning_item': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'rfc_flag': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'state_change_notice_to': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'status_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'telechat_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'token_email': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'token_name': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}),
'via_rfc_editor': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.idnextstate': {
'Meta': {'db_table': "'ref_next_states_new'"},
'condition': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'cur_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nextstate'", 'to': "orm['idtracker.IDState']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'next_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'prevstate'", 'to': "orm['idtracker.IDState']"})
},
'idtracker.idstate': {
'Meta': {'db_table': "'ref_doc_states_new'"},
'description': ('django.db.models.fields.TextField', [], {'db_column': "'document_desc'", 'blank': 'True'}),
'document_state_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'equiv_group_flag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'state': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_column': "'document_state_val'"})
},
'idtracker.idstatus': {
'Meta': {'db_table': "'id_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idsubstate': {
'Meta': {'db_table': "'sub_state'"},
'description': ('django.db.models.fields.TextField', [], {'db_column': "'sub_state_desc'", 'blank': 'True'}),
'sub_state': ('django.db.models.fields.CharField', [], {'max_length': '55', 'db_column': "'sub_state_val'"}),
'sub_state_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.iesgcomment': {
'Meta': {'unique_together': "(('ballot', 'ad'),)", 'db_table': "'ballots_comment'"},
'active': ('django.db.models.fields.IntegerField', [], {}),
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IESGLogin']"}),
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['idtracker.BallotInfo']"}),
'date': ('django.db.models.fields.DateField', [], {'db_column': "'comment_date'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'text': ('django.db.models.fields.TextField', [], {'db_column': "'comment_text'", 'blank': 'True'})
},
'idtracker.iesgdiscuss': {
'Meta': {'unique_together': "(('ballot', 'ad'),)", 'db_table': "'ballots_discuss'"},
'active': ('django.db.models.fields.IntegerField', [], {}),
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IESGLogin']"}),
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'discusses'", 'to': "orm['idtracker.BallotInfo']"}),
'date': ('django.db.models.fields.DateField', [], {'db_column': "'discuss_date'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'text': ('django.db.models.fields.TextField', [], {'db_column': "'discuss_text'", 'blank': 'True'})
},
'idtracker.iesglogin': {
'Meta': {'db_table': "'iesg_login'"},
'default_search': ('django.db.models.fields.NullBooleanField', [], {'null': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}),
'login_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '25'}),
'person': ('BrokenForeignKey', ["orm['idtracker.PersonOrOrgInfo']"], {'unique': 'True', 'null': 'True', 'db_column': "'person_or_org_tag'", 'null_values': '(0,888888)'}),
'pgp_id': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
'user_level': ('django.db.models.fields.IntegerField', [], {})
},
'idtracker.ietfwg': {
'Meta': {'db_table': "'groups_ietf'"},
'area_director': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaDirector']", 'null': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'dormant_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '60', 'blank': 'True'}),
'email_archive': ('django.db.models.fields.CharField', [], {'max_length': '95', 'blank': 'True'}),
'email_keyword': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'email_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
'group_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'group_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGType']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'meeting_scheduled': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'meeting_scheduled_old': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGStatus']"})
},
'idtracker.internetdraft': {
'Meta': {'db_table': "'internet_drafts'"},
'abstract': ('django.db.models.fields.TextField', [], {}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_discussion_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'dunn_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'expired_tombstone': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'extension_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Acronym']", 'db_column': "'group_acronym_id'"}),
'id_document_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id_document_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDIntendedStatus']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_changes': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True'}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'replaced_by': ('BrokenForeignKey', ["orm['idtracker.InternetDraft']"], {'related_name': "'replaces_set'", 'null': 'True', 'db_column': "'replaced_by'", 'blank': 'True'}),
'review_by_rfc_editor': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'revision_date': ('django.db.models.fields.DateField', [], {}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDStatus']"}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'id_document_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {}),
'wgreturn_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.irtf': {
'Meta': {'db_table': "'irtf'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'irtf_acronym'", 'blank': 'True'}),
'charter_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'irtf_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'meeting_scheduled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'irtf_name'", 'blank': 'True'})
},
'idtracker.irtfchair': {
'Meta': {'db_table': "'irtf_chairs'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'irtf': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IRTF']"}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'idtracker.phonenumber': {
'Meta': {'db_table': "'phone_numbers'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person_or_org': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'phone_comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'phone_number': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'phone_priority': ('django.db.models.fields.IntegerField', [], {}),
'phone_type': ('django.db.models.fields.CharField', [], {'max_length': '3'})
},
'idtracker.position': {
'Meta': {'unique_together': "(('ballot', 'ad'),)", 'db_table': "'ballots'"},
'abstain': ('django.db.models.fields.IntegerField', [], {}),
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IESGLogin']"}),
'approve': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'positions'", 'to': "orm['idtracker.BallotInfo']"}),
'discuss': ('django.db.models.fields.IntegerField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'noobj': ('django.db.models.fields.IntegerField', [], {'db_column': "'no_col'"}),
'recuse': ('django.db.models.fields.IntegerField', [], {}),
'yes': ('django.db.models.fields.IntegerField', [], {'db_column': "'yes_col'"})
},
'idtracker.postaladdress': {
'Meta': {'db_table': "'postal_addresses'"},
'address_priority': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
'aff_company_key': ('django.db.models.fields.CharField', [], {'max_length': '70', 'blank': 'True'}),
'affiliated_company': ('django.db.models.fields.CharField', [], {'max_length': '70', 'blank': 'True'}),
'city': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'country': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'department': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mail_stop': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'person_or_org': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'person_title': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'staddr1': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'staddr2': ('django.db.models.fields.CharField', [], {'max_length': '40', 'blank': 'True'}),
'state_or_prov': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'})
},
'idtracker.rfc': {
'Meta': {'db_table': "'rfcs'"},
'area_acronym': ('django.db.models.fields.CharField', [], {'max_length': '8', 'blank': 'True'}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'draft_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'fyi_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'group_acronym': ('django.db.models.fields.CharField', [], {'max_length': '8', 'blank': 'True'}),
'historic_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'default': '5', 'to': "orm['idtracker.RfcIntendedStatus']", 'db_column': "'intended_status_id'"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'online_version': ('django.db.models.fields.CharField', [], {'default': "'YES'", 'max_length': '3'}),
'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'rfc_name_key': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'primary_key': 'True'}),
'rfc_published_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'standard_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.RfcStatus']", 'db_column': "'status_id'"}),
'std_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'db_column': "'rfc_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.rfcauthor': {
'Meta': {'db_table': "'rfc_authors'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'rfc': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'authors'", 'db_column': "'rfc_number'", 'to': "orm['idtracker.Rfc']"})
},
'idtracker.rfcintendedstatus': {
'Meta': {'db_table': "'rfc_intend_status'"},
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"})
},
'idtracker.rfcobsolete': {
'Meta': {'db_table': "'rfcs_obsolete'"},
'action': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'rfc': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'updates_or_obsoletes'", 'db_column': "'rfc_number'", 'to': "orm['idtracker.Rfc']"}),
'rfc_acted_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'updated_or_obsoleted_by'", 'db_column': "'rfc_acted_on'", 'to': "orm['idtracker.Rfc']"})
},
'idtracker.rfcstatus': {
'Meta': {'db_table': "'rfc_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.role': {
'Meta': {'db_table': "'chairs'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}),
'role_name': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'chair_name'"})
},
'idtracker.wgchair': {
'Meta': {'db_table': "'g_chairs'"},
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.wgeditor': {
'Meta': {'db_table': "'g_editors'"},
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'unique': 'True', 'db_column': "'person_or_org_tag'"})
},
'idtracker.wgsecretary': {
'Meta': {'db_table': "'g_secretaries'"},
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.wgstatus': {
'Meta': {'db_table': "'g_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.wgtechadvisor': {
'Meta': {'db_table': "'g_tech_advisors'"},
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.wgtype': {
'Meta': {'db_table': "'g_type'"},
'group_type_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'group_type'"})
}
}
complete_apps = ['idtracker']

View file

View file

@ -171,6 +171,7 @@ class InternetDraft(models.Model):
review_by_rfc_editor = models.BooleanField()
expired_tombstone = models.BooleanField()
idinternal = FKAsOneToOne('idinternal', reverse=True, query=models.Q(rfc_flag = 0))
shepherd = models.ForeignKey('PersonOrOrgInfo', null=True, blank=True)
def __str__(self):
return self.filename
def save(self, *args, **kwargs):
@ -270,7 +271,7 @@ class PersonOrOrgInfo(models.Model):
return u"(Person #%s)" % self.person_or_org_tag
return u"%s %s" % ( self.first_name or u"<nofirst>", self.last_name or u"<nolast>")
def email(self, priority=1, type=None):
name = str(self)
name = str(self)
email = ''
types = type and [ type ] or [ "INET", "Prim", None ]
for type in types:
@ -1073,6 +1074,8 @@ class IRTF(models.Model):
meeting_scheduled = models.BooleanField(blank=True)
def __str__(self):
return self.acronym
def chairs(self): # return a set of IRTFChair objects for this work group
return IRTFChair.objects.filter(irtf=self)
class Meta:
db_table = 'irtf'
verbose_name="IRTF Research Group"

View file

View file

@ -0,0 +1,52 @@
from ietf.ietfworkflows.streams import get_streamed_draft
def get_person_for_user(user):
try:
return user.get_profile().person()
except:
return None
def is_secretariat(user):
if not user or not user.is_authenticated():
return False
return bool(user.groups.filter(name='Secretariat'))
def is_wgchair(person):
return bool(person.wgchair_set.all())
def is_wgdelegate(person):
return bool(person.wgdelegate_set.all())
def is_chair_of_draft(user, draft):
person = get_person_for_user(user)
if not person:
return False
streamed = get_streamed_draft(draft)
if not streamed or not streamed.stream:
return False
group = streamed.group
if not group or not hasattr(group, 'chairs'):
return False
return bool(group.chairs().filter(person=person).count())
def can_edit_state(user, draft):
streamed = get_streamed_draft(draft)
if not streamed or not streamed.stream:
person = get_person_for_user(user)
if not person:
return False
return (is_secretariat(user) or
is_wgchair(person) or
is_wgdelegate(person))
return (is_secretariat(user) or
is_chair_of_draft(user, draft))
def can_edit_stream(user, draft):
return is_secretariat(user)

View file

@ -0,0 +1,17 @@
from django.contrib import admin
from ietf.ietfworkflows.models import (AnnotationTag, WGWorkflow,
Stream)
from workflows.admin import StateInline
class AnnotationTagInline(admin.TabularInline):
model = AnnotationTag
class IETFWorkflowAdmin(admin.ModelAdmin):
inlines = [StateInline, AnnotationTagInline]
admin.site.register(WGWorkflow, IETFWorkflowAdmin)
admin.site.register(Stream, admin.ModelAdmin)

View file

@ -0,0 +1,13 @@
# Required states
CALL_FOR_ADOPTION = 'Call For Adoption By WG Issued'
WG_DOCUMENT = 'WG Document'
SUBMITTED_TO_IESG = 'Submitted to IESG for Publication'
REQUIRED_STATES = (
CALL_FOR_ADOPTION,
WG_DOCUMENT,
SUBMITTED_TO_IESG,
)
# IETF Stream
IETF_STREAM = 'IETF'

View file

@ -0,0 +1,705 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="1" model="workflows.workflow">
<field type="CharField" name="name">Default WG Workflow</field>
<field to="workflows.state" name="initial_state" rel="ManyToOneRel">11</field>
</object>
<object pk="2" model="workflows.workflow">
<field type="CharField" name="name">IAB Workflow</field>
<field to="workflows.state" name="initial_state" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="3" model="workflows.workflow">
<field type="CharField" name="name">IRTF Workflow</field>
<field to="workflows.state" name="initial_state" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="4" model="workflows.workflow">
<field type="CharField" name="name">ISE Workflow</field>
<field to="workflows.state" name="initial_state" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="32" model="workflows.state">
<field type="CharField" name="name">Active IAB Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="42" model="workflows.state">
<field type="CharField" name="name">Active RG Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="12" model="workflows.state">
<field type="CharField" name="name">Adopted by a WG</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"><object pk="12"></object></field>
</object>
<object pk="13" model="workflows.state">
<field type="CharField" name="name">Adopted for WG Info Only</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="36" model="workflows.state">
<field type="CharField" name="name">Approved by IAB, To Be Sent to RFC Editor</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="47" model="workflows.state">
<field type="CharField" name="name">Awaiting IRSG Reviews</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="11" model="workflows.state">
<field type="CharField" name="name">Call For Adoption By WG Issued</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"><object pk="10"></object><object pk="11"></object></field>
</object>
<object pk="31" model="workflows.state">
<field type="CharField" name="name">Candidate IAB Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="41" model="workflows.state">
<field type="CharField" name="name">Candidate RG Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="35" model="workflows.state">
<field type="CharField" name="name">Community Review</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="40" model="workflows.state">
<field type="CharField" name="name">Dead IAB Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="53" model="workflows.state">
<field type="CharField" name="name">Dead IRTF Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="16" model="workflows.state">
<field type="CharField" name="name">Dead WG Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"><object pk="12"></object></field>
</object>
<object pk="51" model="workflows.state">
<field type="CharField" name="name">Document on Hold Based On IESG Request</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="62" model="workflows.state">
<field type="CharField" name="name">Document on Hold Based On IESG Request</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="55" model="workflows.state">
<field type="CharField" name="name">Finding Reviewers</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="34" model="workflows.state">
<field type="CharField" name="name">IAB Review</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="49" model="workflows.state">
<field type="CharField" name="name">In IESG Review</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="58" model="workflows.state">
<field type="CharField" name="name">In IESG Review</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="48" model="workflows.state">
<field type="CharField" name="name">In IRSG Poll</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="56" model="workflows.state">
<field type="CharField" name="name">In ISE Review</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="44" model="workflows.state">
<field type="CharField" name="name">In RG Last Call</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="17" model="workflows.state">
<field type="CharField" name="name">In WG Last Call</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"><object pk="12"></object><object pk="17"></object><object pk="18"></object></field>
</object>
<object pk="61" model="workflows.state">
<field type="CharField" name="name">No Longer In Independent Submission Stream</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="33" model="workflows.state">
<field type="CharField" name="name">Parked IAB Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="43" model="workflows.state">
<field type="CharField" name="name">Parked RG Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="15" model="workflows.state">
<field type="CharField" name="name">Parked WG Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"><object pk="12"></object></field>
</object>
<object pk="52" model="workflows.state">
<field type="CharField" name="name">Published RFC</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="60" model="workflows.state">
<field type="CharField" name="name">Published RFC</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="39" model="workflows.state">
<field type="CharField" name="name">Published RFC</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="57" model="workflows.state">
<field type="CharField" name="name">Response to Review Needed</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="37" model="workflows.state">
<field type="CharField" name="name">Sent to a Different Organization for Publication</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="38" model="workflows.state">
<field type="CharField" name="name">Sent to the RFC Editor</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="59" model="workflows.state">
<field type="CharField" name="name">Sent to the RFC Editor</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="50" model="workflows.state">
<field type="CharField" name="name">Sent to the RFC Editor</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="54" model="workflows.state">
<field type="CharField" name="name">Submission Received</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="20" model="workflows.state">
<field type="CharField" name="name">Submitted to IESG for Publication</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"><object pk="12"></object></field>
</object>
<object pk="45" model="workflows.state">
<field type="CharField" name="name">Waiting for Document Shepherd</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="46" model="workflows.state">
<field type="CharField" name="name">Waiting for IRTF Chair</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"></field>
</object>
<object pk="18" model="workflows.state">
<field type="CharField" name="name">Waiting for WG Chair Go-Ahead</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"><object pk="16"></object><object pk="17"></object></field>
</object>
<object pk="19" model="workflows.state">
<field type="CharField" name="name">WG Consensus: Waiting for Write-Up</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"><object pk="15"></object></field>
</object>
<object pk="14" model="workflows.state">
<field type="CharField" name="name">WG Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.transition" name="transitions" rel="ManyToManyRel"><object pk="13"></object><object pk="14"></object><object pk="16"></object><object pk="17"></object></field>
</object>
<object pk="18" model="workflows.transition">
<field type="CharField" name="name">Wait for go-ahead</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.state" name="destination" rel="ManyToOneRel">18</field>
<field type="CharField" name="condition"></field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="17" model="workflows.transition">
<field type="CharField" name="name">Reach consensus</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.state" name="destination" rel="ManyToOneRel">19</field>
<field type="CharField" name="condition"></field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="10" model="workflows.transition">
<field type="CharField" name="name">Adopt</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.state" name="destination" rel="ManyToOneRel">12</field>
<field type="CharField" name="condition"></field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="11" model="workflows.transition">
<field type="CharField" name="name">Adopt for WG info only</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.state" name="destination" rel="ManyToOneRel">13</field>
<field type="CharField" name="condition"></field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="12" model="workflows.transition">
<field type="CharField" name="name">Develop</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.state" name="destination" rel="ManyToOneRel">14</field>
<field type="CharField" name="condition"></field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="13" model="workflows.transition">
<field type="CharField" name="name">Park</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.state" name="destination" rel="ManyToOneRel">15</field>
<field type="CharField" name="condition"></field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="14" model="workflows.transition">
<field type="CharField" name="name">Die</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.state" name="destination" rel="ManyToOneRel">16</field>
<field type="CharField" name="condition"></field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="15" model="workflows.transition">
<field type="CharField" name="name">Submit to IESG</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.state" name="destination" rel="ManyToOneRel">20</field>
<field type="CharField" name="condition"></field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="16" model="workflows.transition">
<field type="CharField" name="name">Raise last call</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="workflows.state" name="destination" rel="ManyToOneRel">17</field>
<field type="CharField" name="condition"></field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="31" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Revised I-D Needed</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="29" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Shepherd Needed</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="30" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Waiting for Dependency on Other Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="26" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Revised I-D Needed</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="27" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Document Shepherd Followup</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="28" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Editor Needed</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="25" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Awaiting Reviews</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="24" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Waiting for Partner Feedback</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="11" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Other - see Comment Log</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="23" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Editor Needed</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">2</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="10" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Doc Shepherd Follow-Up Underway</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="9" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Revised I-D Needed - Issue raised by IESG</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="1" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Awaiting Expert Review/Resolution of Issues Raised</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="2" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Awaiting External Review/Resolution of Issues Raised</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="3" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Awaiting Merge with Other Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="4" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Author or Editor Needed</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="5" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Waiting for Referenced Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="8" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Revised I-D Needed - Issue raised by AD</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="7" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Revised I-D Needed - Issue raised by WGLC</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="6" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Waiting for Referencing Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">1</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="32" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">IESG Review Completed</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">3</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="33" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Waiting for Dependency on Other Document</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="34" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Awaiting Reviews</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="35" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">Revised I-D Needed</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="36" model="ietfworkflows.annotationtag">
<field type="CharField" name="name">IESG Review Completed</field>
<field to="workflows.workflow" name="workflow" rel="ManyToOneRel">4</field>
<field to="permissions.permission" name="permission" rel="ManyToOneRel"><None></None></field>
</object>
<object pk="1" model="ietfworkflows.wgworkflow">
<field to="workflows.state" name="selected_states" rel="ManyToManyRel"></field>
<field to="ietfworkflows.annotationtag" name="selected_tags" rel="ManyToManyRel"></field>
</object>
<object pk="2" model="ietfworkflows.wgworkflow">
<field to="workflows.state" name="selected_states" rel="ManyToManyRel"></field>
<field to="ietfworkflows.annotationtag" name="selected_tags" rel="ManyToManyRel"></field>
</object>
<object pk="3" model="ietfworkflows.wgworkflow">
<field to="workflows.state" name="selected_states" rel="ManyToManyRel"></field>
<field to="ietfworkflows.annotationtag" name="selected_tags" rel="ManyToManyRel"></field>
</object>
<object pk="4" model="ietfworkflows.wgworkflow">
<field to="workflows.state" name="selected_states" rel="ManyToManyRel"></field>
<field to="ietfworkflows.annotationtag" name="selected_tags" rel="ManyToManyRel"></field>
</object>
<object pk="1" model="ietfworkflows.stream">
<field type="CharField" name="name">IETF</field>
<field type="BooleanField" name="with_groups">True</field>
<field type="CharField" name="group_model">idtracker.IETFWG</field>
<field type="CharField" name="group_chair_model">idtracker.WGChair</field>
<field to="ietfworkflows.wgworkflow" name="workflow" rel="ManyToOneRel">1</field>
</object>
<object pk="2" model="ietfworkflows.stream">
<field type="CharField" name="name">IAB</field>
<field type="BooleanField" name="with_groups">False</field>
<field type="CharField" name="group_model"></field>
<field type="CharField" name="group_chair_model"></field>
<field to="ietfworkflows.wgworkflow" name="workflow" rel="ManyToOneRel">2</field>
</object>
<object pk="3" model="ietfworkflows.stream">
<field type="CharField" name="name">IRTF</field>
<field type="BooleanField" name="with_groups">True</field>
<field type="CharField" name="group_model">idtracker.IRTF</field>
<field type="CharField" name="group_chair_model">idtracker.IRTFChair</field>
<field to="ietfworkflows.wgworkflow" name="workflow" rel="ManyToOneRel">3</field>
</object>
<object pk="4" model="ietfworkflows.stream">
<field type="CharField" name="name">ISE</field>
<field type="BooleanField" name="with_groups">False</field>
<field type="CharField" name="group_model"></field>
<field type="CharField" name="group_chair_model"></field>
<field to="ietfworkflows.wgworkflow" name="workflow" rel="ManyToOneRel">4</field>
</object>
<object pk="1" model="ietfworkflows.statedescription">
<field to="workflows.state" name="state" rel="ManyToOneRel">11</field>
<field type="TextField" name="definition">&lt;a href="http://tools.ietf.org/html/rfc6174#section-4.2.1" target="_blank"&gt;4.2.1. Call for Adoption by WG Issued&lt;/a&gt;
The "Call for Adoption by WG Issued" state should be used to indicate
when an I-D is being considered for adoption by an IETF WG. An I-D
that is in this state is actively being considered for adoption and
has not yet achieved consensus, preference, or selection in the WG.
This state may be used to describe an I-D that someone has asked a WG
to consider for adoption, if the WG Chair has agreed with the
request. This state may also be used to identify an I-D that a WG
Chair asked an author to write specifically for consideration as a
candidate WG item [WGDTSPEC], and/or an I-D that is listed as a
'candidate draft' in the WG's charter.
Under normal conditions, it should not be possible for an I-D to be
in the "Call for Adoption by WG Issued" state in more than one
working group at the same time. This said, it is not uncommon for
authors to "shop" their I-Ds to more than one WG at a time, with the
hope of getting their documents adopted somewhere.
After this state is implemented in the Datatracker, an I-D that is in
the "Call for Adoption by WG Issued" state will not be able to be
"shopped" to any other WG without the consent of the WG Chairs and
the responsible ADs impacted by the shopping.
Note that Figure 1 includes an arc leading from this state to outside
of the WG state machine. This illustrates that some I-Ds that are
considered do not get adopted as WG drafts. An I-D that is not
adopted as a WG draft will transition out of the WG state machine and
revert back to having no stream-specific state; however, the status
change history log of the I-D will record that the I-D was previously
in the "Call for Adoption by WG Issued" state.
</field>
<field type="PositiveIntegerField" name="order">1</field>
</object>
<object pk="2" model="ietfworkflows.statedescription">
<field to="workflows.state" name="state" rel="ManyToOneRel">12</field>
<field type="TextField" name="definition">&lt;a href="http://tools.ietf.org/html/rfc6174#section-4.2.2" target="_blank"&gt;4.2.2. Adopted by a WG&lt;/a&gt;
The "Adopted by a WG" state describes an individual submission I-D
that an IETF WG has agreed to adopt as one of its WG drafts.
WG Chairs who use this state will be able to clearly indicate when
their WGs adopt individual submission I-Ds. This will facilitate the
Datatracker's ability to correctly capture "Replaces" information for
WG drafts and correct "Replaced by" information for individual
submission I-Ds that have been replaced by WG drafts.
This state is needed because the Datatracker uses the filename of an
I-D as a key to search its database for status information about the
I-D, and because the filename of a WG I-D is supposed to be different
from the filename of an individual submission I-D.
The filename of an individual submission I-D will typically be
formatted as 'draft-author-wgname-topic-nn'.
The filename of a WG document is supposed to be formatted as 'draft-
ietf-wgname-topic-nn'.
An individual I-D that is adopted by a WG may take weeks or months to
be resubmitted by the author as a new (version-00) WG draft. If the
"Adopted by a WG" state is not used, the Datatracker has no way to
determine that an I-D has been adopted until a new version of the I-D
is submitted to the WG by the author and until the I-D is approved
for posting by a WG Chair.
</field>
<field type="PositiveIntegerField" name="order">2</field>
</object>
<object pk="3" model="ietfworkflows.statedescription">
<field to="workflows.state" name="state" rel="ManyToOneRel">13</field>
<field type="TextField" name="definition">&lt;a href="http://tools.ietf.org/html/rfc6174#section-4.2.3" target="_blank"&gt;4.2.3. Adopted for WG Info Only&lt;/a&gt;
The "Adopted for WG Info Only" state describes a document that
contains useful information for the WG that adopted it, but the
document is not intended to be published as an RFC. The WG will not
actively develop the contents of the I-D or progress it for
publication as an RFC. The only purpose of the I-D is to provide
information for internal use by the WG.
</field>
<field type="PositiveIntegerField" name="order">3</field>
</object>
<object pk="4" model="ietfworkflows.statedescription">
<field to="workflows.state" name="state" rel="ManyToOneRel">14</field>
<field type="TextField" name="definition">&lt;a href="http://tools.ietf.org/html/rfc6174#section-4.2.4" target="_blank"&gt;4.2.4. WG Document&lt;/a&gt;
The "WG Document" state describes an I-D that has been adopted by an
IETF WG and is being actively developed.
A WG Chair may transition an I-D into the "WG Document" state at any
time as long as the I-D is not being considered or developed in any
other WG.
Alternatively, WG Chairs may rely upon new functionality to be added
to the Datatracker to automatically move version-00 drafts into the
"WG Document" state as described in Section 4.1.
Under normal conditions, it should not be possible for an I-D to be
in the "WG Document" state in more than one WG at a time. This said,
I-Ds may be transferred from one WG to another with the consent of
the WG Chairs and the responsible ADs.
</field>
<field type="PositiveIntegerField" name="order">4</field>
</object>
<object pk="5" model="ietfworkflows.statedescription">
<field to="workflows.state" name="state" rel="ManyToOneRel">15</field>
<field type="TextField" name="definition">&lt;a href="http://tools.ietf.org/html/rfc6174#section-4.2.5" target="_blank"&gt;4.2.5. Parked WG Document&lt;/a&gt;
A "Parked WG Document" is an I-D that has lost its author or editor,
is waiting for another document to be written or for a review to be
completed, or cannot be progressed by the working group for some
other reason.
Some of the annotation tags described in Section 4.3 may be used in
conjunction with this state to indicate why an I-D has been parked,
and/or what may need to happen for the I-D to be un-parked.
Parking a WG draft will not prevent it from expiring; however, this
state can be used to indicate why the I-D has stopped progressing in
the WG.
A "Parked WG Document" that is not expired may be transferred from
one WG to another with the consent of the WG Chairs and the
responsible ADs.
</field>
<field type="PositiveIntegerField" name="order">5</field>
</object>
<object pk="6" model="ietfworkflows.statedescription">
<field to="workflows.state" name="state" rel="ManyToOneRel">16</field>
<field type="TextField" name="definition">&lt;a href="http://tools.ietf.org/html/rfc6174#section-4.2.6" target="_blank"&gt;4.2.6. Dead WG Document&lt;/a&gt;
A "Dead WG Document" is an I-D that has been abandoned. Note that
'Dead' is not always a final state for a WG I-D. If consensus is
subsequently achieved, a "Dead WG Document" may be resurrected. A
"Dead WG Document" that is not resurrected will eventually expire.
Note that an I-D that is declared to be "Dead" in one WG and that is
not expired may be transferred to a non-dead state in another WG with
the consent of the WG Chairs and the responsible ADs.
</field>
<field type="PositiveIntegerField" name="order">6</field>
</object>
<object pk="7" model="ietfworkflows.statedescription">
<field to="workflows.state" name="state" rel="ManyToOneRel">17</field>
<field type="TextField" name="definition">&lt;a href="http://tools.ietf.org/html/rfc6174#section-4.2.7" target="_blank"&gt;4.2.7. In WG Last Call&lt;/a&gt;
A document "In WG Last Call" is an I-D for which a WG Last Call
(WGLC) has been issued and is in progress.
Note that conducting a WGLC is an optional part of the IETF WG
process, per Section 7.4 of RFC 2418 [RFC2418].
If a WG Chair decides to conduct a WGLC on an I-D, the "In WG Last
Call" state can be used to track the progress of the WGLC. The Chair
may configure the Datatracker to send a WGLC message to one or more
mailing lists when the Chair moves the I-D into this state. The WG
Chair may also be able to select a different set of mailing lists for
a different document undergoing a WGLC; some documents may deserve
coordination with other WGs.
A WG I-D in this state should remain "In WG Last Call" until the WG
Chair moves it to another state. The WG Chair may configure the
Datatracker to send an e-mail after a specified period of time to
remind or 'nudge' the Chair to conclude the WGLC and to determine the
next state for the document.
It is possible for one WGLC to lead into another WGLC for the same
document. For example, an I-D that completed a WGLC as an
"Informational" document may need another WGLC if a decision is taken
to convert the I-D into a Standards Track document.
</field>
<field type="PositiveIntegerField" name="order">7</field>
</object>
<object pk="8" model="ietfworkflows.statedescription">
<field to="workflows.state" name="state" rel="ManyToOneRel">18</field>
<field type="TextField" name="definition">&lt;a href="http://tools.ietf.org/html/rfc6174#section-4.2.8" target="_blank"&gt;4.2.8. Waiting for WG Chair Go-Ahead&lt;/a&gt;
A WG Chair may wish to place an I-D that receives a lot of comments
during a WGLC into the "Waiting for WG Chair Go-Ahead" state. This
state describes an I-D that has undergone a WGLC; however, the Chair
is not yet ready to call consensus on the document.
If comments from the WGLC need to be responded to, or a revision to
the I-D is needed, the Chair may place an I-D into this state until
all of the WGLC comments are adequately addressed and the (possibly
revised) document is in the I-D repository.
</field>
<field type="PositiveIntegerField" name="order">8</field>
</object>
<object pk="9" model="ietfworkflows.statedescription">
<field to="workflows.state" name="state" rel="ManyToOneRel">19</field>
<field type="TextField" name="definition">&lt;a href="http://tools.ietf.org/html/rfc6174#section-4.2.9" target="_blank"&gt;4.2.9. WG Consensus: Waiting for Writeup&lt;/a&gt;
A document in the "WG Consensus: Waiting for Writeup" state has
essentially completed its development within the working group, and
is nearly ready to be sent to the IESG for publication. The last
thing to be done is the preparation of a protocol writeup by a
Document Shepherd. The IESG requires that a document shepherd
writeup be completed before publication of the I-D is requested. The
IETF document shepherding process and the role of a WG Document
Shepherd is described in RFC 4858 [RFC4858]
A WG Chair may call consensus on an I-D without a formal WGLC and
transition an I-D that was in the "WG Document" state directly into
this state.
The name of this state includes the words "Waiting for Writeup"
because a good document shepherd writeup takes time to prepare.
</field>
<field type="PositiveIntegerField" name="order">9</field>
</object>
<object pk="10" model="ietfworkflows.statedescription">
<field to="workflows.state" name="state" rel="ManyToOneRel">20</field>
<field type="TextField" name="definition">&lt;a href="http://tools.ietf.org/html/rfc6174#section-4.2.10" target="_blank"&gt;4.2.10. Submitted to IESG for Publication&lt;/a&gt;
This state describes a WG document that has been submitted to the
IESG for publication and that has not been sent back to the working
group for revision.
An I-D in this state may be under review by the IESG, it may have
been approved and be in the RFC Editor's queue, or it may have been
published as an RFC. Other possibilities exist too. The document
may be "Dead" (in the IESG state machine) or in a "Do Not Publish"
state.
</field>
<field type="PositiveIntegerField" name="order">10</field>
</object>
</django-objects>

202
ietf/ietfworkflows/forms.py Normal file
View file

@ -0,0 +1,202 @@
import datetime
from django import forms
from django.template.loader import render_to_string
from workflows.models import State
from workflows.utils import set_workflow_for_object
from ietf.idtracker.models import PersonOrOrgInfo, IETFWG
from ietf.wgchairs.accounts import get_person_for_user
from ietf.ietfworkflows.models import Stream
from ietf.ietfworkflows.utils import (get_workflow_for_draft, get_workflow_for_wg,
get_state_for_draft, get_state_by_name,
update_state, FOLLOWUP_TAG,
get_annotation_tags_for_draft,
update_tags, update_stream)
from ietf.ietfworkflows.accounts import is_secretariat
from ietf.ietfworkflows.streams import (get_stream_from_draft, get_streamed_draft,
get_stream_by_name, set_stream_for_draft)
from ietf.ietfworkflows.constants import CALL_FOR_ADOPTION, IETF_STREAM
class StreamDraftForm(forms.Form):
can_cancel = False
template = None
def __init__(self, *args, **kwargs):
self.draft = kwargs.pop('draft', None)
self.user = kwargs.pop('user', None)
self.person = get_person_for_user(self.user)
self.workflow = get_workflow_for_draft(self.draft)
self.message = {}
super(StreamDraftForm, self).__init__(*args, **kwargs)
def get_message(self):
return self.message
def set_message(self, msg_type, msg_value):
self.message = {'type': msg_type,
'value': msg_value,
}
def __unicode__(self):
return render_to_string(self.template, {'form': self})
class NoWorkflowStateForm(StreamDraftForm):
comment = forms.CharField(widget=forms.Textarea)
weeks = forms.IntegerField(required=False)
wg = forms.ChoiceField(required=False)
template = 'ietfworkflows/noworkflow_state_form.html'
def __init__(self, *args, **kwargs):
super(NoWorkflowStateForm, self).__init__(*args, **kwargs)
self.wgs = None
self.onlywg = None
if is_secretariat(self.user):
wgs = IETFWG.objects.all()
else:
wgs = set([i.group_acronym for i in self.person.wgchair_set.all()]).union(set([i.wg for i in self.person.wgdelegate_set.all()]))
if len(wgs) > 1:
self.wgs = list(wgs)
self.wgs.sort(lambda x,y: cmp(x.group_acronym.acronym, y.group_acronym.acronym))
self.fields['wg'].choices = [(i.pk, '%s - %s' % (i.group_acronym.acronym, i.group_acronym.name)) for i in self.wgs]
else:
self.onlywg = list(wgs)[0].group_acronym
def save(self):
comment = self.cleaned_data.get('comment')
weeks = self.cleaned_data.get('weeks')
if self.onlywg:
wg = self.onlywg
else:
wg = IETFWG.objects.get(pk=self.cleaned_data.get('wg'))
estimated_date = None
if weeks:
now = datetime.date.today()
estimated_date = now + datetime.timedelta(weeks=weeks)
workflow = get_workflow_for_wg(wg)
set_workflow_for_object(self.draft, workflow)
stream = get_stream_by_name(IETF_STREAM)
streamed = get_streamed_draft(self.draft)
if not streamed:
set_stream_for_draft(self.draft, stream)
streamed = get_streamed_draft(self.draft)
streamed.stream = stream
streamed.group = wg
streamed.save()
update_state(obj=self.draft,
comment=comment,
person=self.person,
to_state=get_state_by_name(CALL_FOR_ADOPTION),
estimated_date=estimated_date)
class DraftTagsStateForm(StreamDraftForm):
comment = forms.CharField(widget=forms.Textarea)
new_state = forms.ChoiceField()
weeks = forms.IntegerField(required=False)
tags = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, required=False)
template = 'ietfworkflows/state_form.html'
def __init__(self, *args, **kwargs):
super(DraftTagsStateForm, self).__init__(*args, **kwargs)
self.state = get_state_for_draft(self.draft)
self.fields['new_state'].choices = self.get_states()
if self.is_bound:
for key, value in self.data.items():
if key.startswith('transition_'):
new_state = self.get_new_state(key)
if new_state:
self.data = self.data.copy()
self.data.update({'new_state': new_state.id})
self.available_tags = self.workflow.get_tags()
self.tags = [i.annotation_tag for i in get_annotation_tags_for_draft(self.draft)]
self.fields['tags'].choices = [(i.pk, i.name) for i in self.available_tags]
self.fields['tags'].initial = [i.pk for i in self.tags]
def get_new_state(self, key):
transition_id = key.replace('transition_', '')
transition = self.get_transitions().filter(id=transition_id)
if transition:
return transition[0].destination
return None
def get_transitions(self):
return self.state.transitions.filter(workflow=self.workflow)
def get_states(self):
return [(i.pk, i.name) for i in self.workflow.get_states()]
def save_tags(self):
comment = self.cleaned_data.get('comment')
new_tags = self.cleaned_data.get('tags')
set_tags = [tag for tag in self.available_tags if str(tag.pk) in new_tags and tag not in self.tags]
reset_tags = [tag for tag in self.available_tags if str(tag.pk) not in new_tags and tag in self.tags]
followup = bool([tag for tag in set_tags if tag.name == FOLLOWUP_TAG])
extra_notify = []
if followup:
try:
shepherd = self.draft.shepherd
if shepherd:
extra_notify = ['%s <%s>' % shepherd.email()]
except PersonOrOrgInfo.DoesNotExist:
pass
if not set_tags and not reset_tags:
return
update_tags(self.draft,
comment=comment,
person=self.person,
set_tags=set_tags,
reset_tags=reset_tags,
extra_notify=extra_notify)
def save_state(self):
comment = self.cleaned_data.get('comment')
state = State.objects.get(pk=self.cleaned_data.get('new_state'))
weeks = self.cleaned_data.get('weeks')
estimated_date = None
if weeks:
now = datetime.date.today()
estimated_date = now + datetime.timedelta(weeks=weeks)
update_state(obj=self.draft,
comment=comment,
person=self.person,
to_state=state,
estimated_date=estimated_date)
def save(self):
self.save_tags()
if 'only_tags' in self.data.keys():
return
self.save_state()
class DraftStreamForm(StreamDraftForm):
comment = forms.CharField(widget=forms.Textarea)
stream = forms.ModelChoiceField(Stream.objects.all())
template = 'ietfworkflows/stream_form.html'
def __init__(self, *args, **kwargs):
super(DraftStreamForm, self).__init__(*args, **kwargs)
self.stream = get_stream_from_draft(self.draft)
self.tags = [i.annotation_tag for i in get_annotation_tags_for_draft(self.draft)]
if self.stream:
self.fields['stream'].initial = self.stream.pk
def save(self):
comment = self.cleaned_data.get('comment')
to_stream = self.cleaned_data.get('stream')
update_stream(self.draft,
comment=comment,
person=self.person,
to_stream=to_stream)

View file

@ -0,0 +1,148 @@
from south.db import db
from django.db import models
from ietf.ietfworkflows.models import *
class Migration:
def forwards(self, orm):
# Adding model 'WGWorkflow'
db.create_table('ietfworkflows_wgworkflow', (
('workflow_ptr', orm['ietfworkflows.WGWorkflow:workflow_ptr']),
))
db.send_create_signal('ietfworkflows', ['WGWorkflow'])
# Adding model 'ObjectWorkflowHistoryEntry'
db.create_table('ietfworkflows_objectworkflowhistoryentry', (
('id', orm['ietfworkflows.ObjectWorkflowHistoryEntry:id']),
('content_type', orm['ietfworkflows.ObjectWorkflowHistoryEntry:content_type']),
('content_id', orm['ietfworkflows.ObjectWorkflowHistoryEntry:content_id']),
('from_state', orm['ietfworkflows.ObjectWorkflowHistoryEntry:from_state']),
('to_state', orm['ietfworkflows.ObjectWorkflowHistoryEntry:to_state']),
('transition_date', orm['ietfworkflows.ObjectWorkflowHistoryEntry:transition_date']),
('comment', orm['ietfworkflows.ObjectWorkflowHistoryEntry:comment']),
))
db.send_create_signal('ietfworkflows', ['ObjectWorkflowHistoryEntry'])
# Adding model 'ObjectAnnotationTagHistoryEntry'
db.create_table('ietfworkflows_objectannotationtaghistoryentry', (
('id', orm['ietfworkflows.ObjectAnnotationTagHistoryEntry:id']),
('content_type', orm['ietfworkflows.ObjectAnnotationTagHistoryEntry:content_type']),
('content_id', orm['ietfworkflows.ObjectAnnotationTagHistoryEntry:content_id']),
('setted', orm['ietfworkflows.ObjectAnnotationTagHistoryEntry:setted']),
('unsetted', orm['ietfworkflows.ObjectAnnotationTagHistoryEntry:unsetted']),
('change_date', orm['ietfworkflows.ObjectAnnotationTagHistoryEntry:change_date']),
('comment', orm['ietfworkflows.ObjectAnnotationTagHistoryEntry:comment']),
))
db.send_create_signal('ietfworkflows', ['ObjectAnnotationTagHistoryEntry'])
# Adding model 'AnnotationTag'
db.create_table('ietfworkflows_annotationtag', (
('id', orm['ietfworkflows.AnnotationTag:id']),
('name', orm['ietfworkflows.AnnotationTag:name']),
('workflow', orm['ietfworkflows.AnnotationTag:workflow']),
('permission', orm['ietfworkflows.AnnotationTag:permission']),
))
db.send_create_signal('ietfworkflows', ['AnnotationTag'])
# Adding model 'AnnotationTagObjectRelation'
db.create_table('ietfworkflows_annotationtagobjectrelation', (
('id', orm['ietfworkflows.AnnotationTagObjectRelation:id']),
('content_type', orm['ietfworkflows.AnnotationTagObjectRelation:content_type']),
('content_id', orm['ietfworkflows.AnnotationTagObjectRelation:content_id']),
('annotation_tag', orm['ietfworkflows.AnnotationTagObjectRelation:annotation_tag']),
))
db.send_create_signal('ietfworkflows', ['AnnotationTagObjectRelation'])
def backwards(self, orm):
# Deleting model 'WGWorkflow'
db.delete_table('ietfworkflows_wgworkflow')
# Deleting model 'ObjectWorkflowHistoryEntry'
db.delete_table('ietfworkflows_objectworkflowhistoryentry')
# Deleting model 'ObjectAnnotationTagHistoryEntry'
db.delete_table('ietfworkflows_objectannotationtaghistoryentry')
# Deleting model 'AnnotationTag'
db.delete_table('ietfworkflows_annotationtag')
# Deleting model 'AnnotationTagObjectRelation'
db.delete_table('ietfworkflows_annotationtagobjectrelation')
models = {
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'ietfworkflows.annotationtag': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'annotation_tags'", 'to': "orm['workflows.Workflow']"})
},
'ietfworkflows.annotationtagobjectrelation': {
'annotation_tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.AnnotationTag']"}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'ietfworkflows.objectannotationtaghistoryentry': {
'change_date': ('django.db.models.fields.DateTimeField', [], {}),
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'setted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'unsetted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objectworkflowhistoryentry': {
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'from_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'to_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transition_date': ('django.db.models.fields.DateTimeField', [], {})
},
'ietfworkflows.wgworkflow': {
'workflow_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['workflows.Workflow']", 'unique': 'True', 'primary_key': 'True'})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'workflows.state': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transitions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['workflows.Transition']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['workflows.Workflow']"})
},
'workflows.transition': {
'condition': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destination_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflow': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['permissions.Permission']", 'symmetrical': 'False'})
}
}
complete_apps = ['ietfworkflows']

View file

@ -0,0 +1,107 @@
from south.db import db
from django.db import models
from ietf.ietfworkflows.models import *
class Migration:
def forwards(self, orm):
# Adding ManyToManyField 'WGWorkflow.selected_tags'
db.create_table('ietfworkflows_wgworkflow_selected_tags', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('wgworkflow', models.ForeignKey(orm.WGWorkflow, null=False)),
('annotationtag', models.ForeignKey(orm.AnnotationTag, null=False))
))
# Adding ManyToManyField 'WGWorkflow.selected_states'
db.create_table('ietfworkflows_wgworkflow_selected_states', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('wgworkflow', models.ForeignKey(orm.WGWorkflow, null=False)),
('state', models.ForeignKey(orm['workflows.State'], null=False))
))
def backwards(self, orm):
# Dropping ManyToManyField 'WGWorkflow.selected_tags'
db.delete_table('ietfworkflows_wgworkflow_selected_tags')
# Dropping ManyToManyField 'WGWorkflow.selected_states'
db.delete_table('ietfworkflows_wgworkflow_selected_states')
models = {
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'ietfworkflows.annotationtag': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'annotation_tags'", 'to': "orm['workflows.Workflow']"})
},
'ietfworkflows.annotationtagobjectrelation': {
'annotation_tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.AnnotationTag']"}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'ietfworkflows.objectannotationtaghistoryentry': {
'change_date': ('django.db.models.fields.DateTimeField', [], {}),
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'setted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'unsetted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objectworkflowhistoryentry': {
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'from_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'to_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transition_date': ('django.db.models.fields.DateTimeField', [], {})
},
'ietfworkflows.wgworkflow': {
'selected_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['workflows.State']"}),
'selected_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['ietfworkflows.AnnotationTag']"}),
'workflow_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['workflows.Workflow']", 'unique': 'True', 'primary_key': 'True'})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'workflows.state': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transitions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['workflows.Transition']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['workflows.Workflow']"})
},
'workflows.transition': {
'condition': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destination_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflow': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['permissions.Permission']", 'symmetrical': 'False'})
}
}
complete_apps = ['ietfworkflows']

View file

@ -0,0 +1,119 @@
from south.db import db
from django.db import models
from ietf.ietfworkflows.models import *
class Migration:
def forwards(self, orm):
# Adding field 'ObjectWorkflowHistoryEntry.person'
db.add_column('ietfworkflows_objectworkflowhistoryentry', 'person', orm['ietfworkflows.objectworkflowhistoryentry:person'])
# Adding field 'ObjectAnnotationTagHistoryEntry.person'
db.add_column('ietfworkflows_objectannotationtaghistoryentry', 'person', orm['ietfworkflows.objectannotationtaghistoryentry:person'])
def backwards(self, orm):
# Deleting field 'ObjectWorkflowHistoryEntry.person'
db.delete_column('ietfworkflows_objectworkflowhistoryentry', 'person_id')
# Deleting field 'ObjectAnnotationTagHistoryEntry.person'
db.delete_column('ietfworkflows_objectannotationtaghistoryentry', 'person_id')
models = {
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.annotationtag': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'annotation_tags'", 'to': "orm['workflows.Workflow']"})
},
'ietfworkflows.annotationtagobjectrelation': {
'annotation_tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.AnnotationTag']"}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'ietfworkflows.objectannotationtaghistoryentry': {
'change_date': ('django.db.models.fields.DateTimeField', [], {}),
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'setted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'unsetted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objectworkflowhistoryentry': {
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'from_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'to_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transition_date': ('django.db.models.fields.DateTimeField', [], {})
},
'ietfworkflows.wgworkflow': {
'selected_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['workflows.State']", 'symmetrical': 'False'}),
'selected_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['ietfworkflows.AnnotationTag']", 'symmetrical': 'False'}),
'workflow_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['workflows.Workflow']", 'unique': 'True', 'primary_key': 'True'})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'workflows.state': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transitions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.Transition']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['workflows.Workflow']"})
},
'workflows.transition': {
'condition': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destination_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflow': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['permissions.Permission']", 'symmetrical': 'False'})
}
}
complete_apps = ['ietfworkflows']

View file

@ -0,0 +1,132 @@
from south.db import db
from django.db import models
from ietf.ietfworkflows.models import *
class Migration:
def forwards(self, orm):
# Adding model 'StateObjectRelationMetadata'
db.create_table('ietfworkflows_stateobjectrelationmetadata', (
('id', orm['ietfworkflows.stateobjectrelationmetadata:id']),
('relation', orm['ietfworkflows.stateobjectrelationmetadata:relation']),
('from_date', orm['ietfworkflows.stateobjectrelationmetadata:from_date']),
('estimated_date', orm['ietfworkflows.stateobjectrelationmetadata:estimated_date']),
))
db.send_create_signal('ietfworkflows', ['StateObjectRelationMetadata'])
def backwards(self, orm):
# Deleting model 'StateObjectRelationMetadata'
db.delete_table('ietfworkflows_stateobjectrelationmetadata')
models = {
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.annotationtag': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'annotation_tags'", 'to': "orm['workflows.Workflow']"})
},
'ietfworkflows.annotationtagobjectrelation': {
'annotation_tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.AnnotationTag']"}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'ietfworkflows.objectannotationtaghistoryentry': {
'change_date': ('django.db.models.fields.DateTimeField', [], {}),
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'setted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'unsetted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objectworkflowhistoryentry': {
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'from_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'to_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transition_date': ('django.db.models.fields.DateTimeField', [], {})
},
'ietfworkflows.stateobjectrelationmetadata': {
'estimated_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'from_date': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'relation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.StateObjectRelation']"})
},
'ietfworkflows.wgworkflow': {
'selected_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['workflows.State']", 'symmetrical': 'False'}),
'selected_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['ietfworkflows.AnnotationTag']", 'symmetrical': 'False'}),
'workflow_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['workflows.Workflow']", 'unique': 'True', 'primary_key': 'True'})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'workflows.state': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transitions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.Transition']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['workflows.Workflow']"})
},
'workflows.stateobjectrelation': {
'Meta': {'unique_together': "(('content_type', 'content_id', 'state'),)"},
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'state_object'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"})
},
'workflows.transition': {
'condition': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destination_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflow': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['permissions.Permission']", 'symmetrical': 'False'})
}
}
complete_apps = ['ietfworkflows']

View file

@ -0,0 +1,209 @@
from south.db import db
from django.db import models
from ietf.ietfworkflows.models import *
class Migration:
def forwards(self, orm):
# Adding model 'StreamedID'
db.create_table('ietfworkflows_streamedid', (
('id', orm['ietfworkflows.streamedid:id']),
('draft', orm['ietfworkflows.streamedid:draft']),
('stream', orm['ietfworkflows.streamedid:stream']),
))
db.send_create_signal('ietfworkflows', ['StreamedID'])
# Adding model 'Stream'
db.create_table('ietfworkflows_stream', (
('id', orm['ietfworkflows.stream:id']),
('name', orm['ietfworkflows.stream:name']),
('with_groups', orm['ietfworkflows.stream:with_groups']),
('group_model', orm['ietfworkflows.stream:group_model']),
('group_chair_model', orm['ietfworkflows.stream:group_chair_model']),
('workflow', orm['ietfworkflows.stream:workflow']),
))
db.send_create_signal('ietfworkflows', ['Stream'])
def backwards(self, orm):
# Deleting model 'StreamedID'
db.delete_table('ietfworkflows_streamedid')
# Deleting model 'Stream'
db.delete_table('ietfworkflows_stream')
models = {
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.idintendedstatus': {
'Meta': {'db_table': "'id_intended_status'"},
'intended_status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idstatus': {
'Meta': {'db_table': "'id_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.internetdraft': {
'Meta': {'db_table': "'internet_drafts'"},
'abstract': ('django.db.models.fields.TextField', [], {}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_discussion_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'dunn_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'expired_tombstone': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'extension_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Acronym']", 'db_column': "'group_acronym_id'"}),
'id_document_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id_document_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDIntendedStatus']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_changes': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True'}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'replaced_by': ('django.db.models.fields.related.ForeignKey', ["orm['idtracker.InternetDraft']"], {'related_name': "'replaces_set'", 'null': 'True', 'db_column': "'replaced_by'", 'blank': 'True'}),
'review_by_rfc_editor': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'revision_date': ('django.db.models.fields.DateField', [], {}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDStatus']"}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'id_document_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {}),
'wgreturn_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.annotationtag': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'annotation_tags'", 'to': "orm['workflows.Workflow']"})
},
'ietfworkflows.annotationtagobjectrelation': {
'annotation_tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.AnnotationTag']"}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'ietfworkflows.objectannotationtaghistoryentry': {
'change_date': ('django.db.models.fields.DateTimeField', [], {}),
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'setted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'unsetted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objectworkflowhistoryentry': {
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'from_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'to_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transition_date': ('django.db.models.fields.DateTimeField', [], {})
},
'ietfworkflows.stateobjectrelationmetadata': {
'estimated_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'from_date': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'relation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.StateObjectRelation']"})
},
'ietfworkflows.stream': {
'group_chair_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'group_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'with_groups': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.WGWorkflow']"})
},
'ietfworkflows.streamedid': {
'draft': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.InternetDraft']", 'unique': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.Stream']"})
},
'ietfworkflows.wgworkflow': {
'selected_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.State']", 'null': 'True', 'blank': 'True'}),
'selected_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['ietfworkflows.AnnotationTag']", 'null': 'True', 'blank': 'True'}),
'workflow_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['workflows.Workflow']", 'unique': 'True', 'primary_key': 'True'})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'workflows.state': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transitions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.Transition']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['workflows.Workflow']"})
},
'workflows.stateobjectrelation': {
'Meta': {'unique_together': "(('content_type', 'content_id', 'state'),)"},
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'state_object'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"})
},
'workflows.transition': {
'condition': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destination_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflow': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['permissions.Permission']", 'symmetrical': 'False'})
}
}
complete_apps = ['ietfworkflows']

View file

@ -0,0 +1,198 @@
from south.db import db
from django.db import models
from ietf.ietfworkflows.models import *
class Migration:
def forwards(self, orm):
# Adding field 'StreamedID.content_type'
db.add_column('ietfworkflows_streamedid', 'content_type', orm['ietfworkflows.streamedid:content_type'])
# Adding field 'StreamedID.content_id'
db.add_column('ietfworkflows_streamedid', 'content_id', orm['ietfworkflows.streamedid:content_id'])
def backwards(self, orm):
# Deleting field 'StreamedID.content_type'
db.delete_column('ietfworkflows_streamedid', 'content_type_id')
# Deleting field 'StreamedID.content_id'
db.delete_column('ietfworkflows_streamedid', 'content_id')
models = {
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.idintendedstatus': {
'Meta': {'db_table': "'id_intended_status'"},
'intended_status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idstatus': {
'Meta': {'db_table': "'id_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.internetdraft': {
'Meta': {'db_table': "'internet_drafts'"},
'abstract': ('django.db.models.fields.TextField', [], {}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_discussion_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'dunn_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'expired_tombstone': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'extension_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Acronym']", 'db_column': "'group_acronym_id'"}),
'id_document_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id_document_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDIntendedStatus']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_changes': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True'}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'replaced_by': ('django.db.models.fields.related.ForeignKey', ["orm['idtracker.InternetDraft']"], {'related_name': "'replaces_set'", 'null': 'True', 'db_column': "'replaced_by'", 'blank': 'True'}),
'review_by_rfc_editor': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'revision_date': ('django.db.models.fields.DateField', [], {}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDStatus']"}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'id_document_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {}),
'wgreturn_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.annotationtag': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'annotation_tags'", 'to': "orm['workflows.Workflow']"})
},
'ietfworkflows.annotationtagobjectrelation': {
'annotation_tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.AnnotationTag']"}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'ietfworkflows.objectannotationtaghistoryentry': {
'change_date': ('django.db.models.fields.DateTimeField', [], {}),
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'setted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'unsetted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objectworkflowhistoryentry': {
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'from_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'to_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transition_date': ('django.db.models.fields.DateTimeField', [], {})
},
'ietfworkflows.stateobjectrelationmetadata': {
'estimated_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'from_date': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'relation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.StateObjectRelation']"})
},
'ietfworkflows.stream': {
'group_chair_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'group_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'with_groups': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.WGWorkflow']"})
},
'ietfworkflows.streamedid': {
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'streamed_id'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'draft': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.InternetDraft']", 'unique': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.Stream']"})
},
'ietfworkflows.wgworkflow': {
'selected_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.State']", 'null': 'True', 'blank': 'True'}),
'selected_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['ietfworkflows.AnnotationTag']", 'null': 'True', 'blank': 'True'}),
'workflow_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['workflows.Workflow']", 'unique': 'True', 'primary_key': 'True'})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'workflows.state': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transitions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.Transition']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['workflows.Workflow']"})
},
'workflows.stateobjectrelation': {
'Meta': {'unique_together': "(('content_type', 'content_id', 'state'),)"},
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'state_object'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"})
},
'workflows.transition': {
'condition': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destination_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflow': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['permissions.Permission']", 'symmetrical': 'False'})
}
}
complete_apps = ['ietfworkflows']

View file

@ -0,0 +1,194 @@
from south.db import db
from django.db import models
from ietf.ietfworkflows.models import *
class Migration:
def forwards(self, orm):
# Changing field 'StreamedID.stream'
# (to signature: django.db.models.fields.related.ForeignKey(to=orm['ietfworkflows.Stream'], null=True, blank=True))
db.alter_column('ietfworkflows_streamedid', 'stream_id', orm['ietfworkflows.streamedid:stream'])
def backwards(self, orm):
# Changing field 'StreamedID.stream'
# (to signature: django.db.models.fields.related.ForeignKey(to=orm['ietfworkflows.Stream']))
db.alter_column('ietfworkflows_streamedid', 'stream_id', orm['ietfworkflows.streamedid:stream'])
models = {
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.idintendedstatus': {
'Meta': {'db_table': "'id_intended_status'"},
'intended_status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idstatus': {
'Meta': {'db_table': "'id_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.internetdraft': {
'Meta': {'db_table': "'internet_drafts'"},
'abstract': ('django.db.models.fields.TextField', [], {}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_discussion_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'dunn_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'expired_tombstone': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'extension_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Acronym']", 'db_column': "'group_acronym_id'"}),
'id_document_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id_document_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDIntendedStatus']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_changes': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True'}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'replaced_by': ('django.db.models.fields.related.ForeignKey', ["orm['idtracker.InternetDraft']"], {'related_name': "'replaces_set'", 'null': 'True', 'db_column': "'replaced_by'", 'blank': 'True'}),
'review_by_rfc_editor': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'revision_date': ('django.db.models.fields.DateField', [], {}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDStatus']"}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'id_document_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {}),
'wgreturn_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.annotationtag': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'annotation_tags'", 'to': "orm['workflows.Workflow']"})
},
'ietfworkflows.annotationtagobjectrelation': {
'annotation_tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.AnnotationTag']"}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'ietfworkflows.objectannotationtaghistoryentry': {
'change_date': ('django.db.models.fields.DateTimeField', [], {}),
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'setted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'unsetted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objectworkflowhistoryentry': {
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'from_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'to_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transition_date': ('django.db.models.fields.DateTimeField', [], {})
},
'ietfworkflows.stateobjectrelationmetadata': {
'estimated_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'from_date': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'relation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.StateObjectRelation']"})
},
'ietfworkflows.stream': {
'group_chair_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'group_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'with_groups': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.WGWorkflow']"})
},
'ietfworkflows.streamedid': {
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'streamed_id'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'draft': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.InternetDraft']", 'unique': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.Stream']", 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.wgworkflow': {
'selected_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.State']", 'null': 'True', 'blank': 'True'}),
'selected_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['ietfworkflows.AnnotationTag']", 'null': 'True', 'blank': 'True'}),
'workflow_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['workflows.Workflow']", 'unique': 'True', 'primary_key': 'True'})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'workflows.state': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transitions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.Transition']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['workflows.Workflow']"})
},
'workflows.stateobjectrelation': {
'Meta': {'unique_together': "(('content_type', 'content_id', 'state'),)"},
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'state_object'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"})
},
'workflows.transition': {
'condition': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destination_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflow': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['permissions.Permission']", 'symmetrical': 'False'})
}
}
complete_apps = ['ietfworkflows']

View file

@ -0,0 +1,267 @@
from south.db import db
from django.db import models
from ietf.ietfworkflows.models import *
class Migration:
def forwards(self, orm):
# Deleting model 'objectworkflowhistoryentry'
db.delete_table('ietfworkflows_objectworkflowhistoryentry')
# Deleting model 'objectannotationtaghistoryentry'
db.delete_table('ietfworkflows_objectannotationtaghistoryentry')
# Adding model 'ObjectAnnotationTagHistoryEntry'
db.create_table('ietfworkflows_objectannotationtaghistoryentry', (
('objecthistoryentry_ptr', orm['ietfworkflows.objectannotationtaghistoryentry:objecthistoryentry_ptr']),
('setted', orm['ietfworkflows.objectannotationtaghistoryentry:setted']),
('unsetted', orm['ietfworkflows.objectannotationtaghistoryentry:unsetted']),
))
db.send_create_signal('ietfworkflows', ['ObjectAnnotationTagHistoryEntry'])
# Adding model 'ObjectHistoryEntry'
db.create_table('ietfworkflows_objecthistoryentry', (
('id', orm['ietfworkflows.objecthistoryentry:id']),
('content_type', orm['ietfworkflows.objecthistoryentry:content_type']),
('content_id', orm['ietfworkflows.objecthistoryentry:content_id']),
('date', orm['ietfworkflows.objecthistoryentry:date']),
('comment', orm['ietfworkflows.objecthistoryentry:comment']),
('person', orm['ietfworkflows.objecthistoryentry:person']),
))
db.send_create_signal('ietfworkflows', ['ObjectHistoryEntry'])
# Adding model 'ObjectStreamHistoryEntry'
db.create_table('ietfworkflows_objectstreamhistoryentry', (
('objecthistoryentry_ptr', orm['ietfworkflows.objectstreamhistoryentry:objecthistoryentry_ptr']),
('from_stream', orm['ietfworkflows.objectstreamhistoryentry:from_stream']),
('to_stream', orm['ietfworkflows.objectstreamhistoryentry:to_stream']),
))
db.send_create_signal('ietfworkflows', ['ObjectStreamHistoryEntry'])
# Adding model 'ObjectWorkflowHistoryEntry'
db.create_table('ietfworkflows_objectworkflowhistoryentry', (
('objecthistoryentry_ptr', orm['ietfworkflows.objectworkflowhistoryentry:objecthistoryentry_ptr']),
('from_state', orm['ietfworkflows.objectworkflowhistoryentry:from_state']),
('to_state', orm['ietfworkflows.objectworkflowhistoryentry:to_state']),
))
db.send_create_signal('ietfworkflows', ['ObjectWorkflowHistoryEntry'])
def backwards(self, orm):
# Deleting model 'ObjectAnnotationTagHistoryEntry'
db.delete_table('ietfworkflows_objectannotationtaghistoryentry')
# Deleting model 'ObjectHistoryEntry'
db.delete_table('ietfworkflows_objecthistoryentry')
# Deleting model 'ObjectStreamHistoryEntry'
db.delete_table('ietfworkflows_objectstreamhistoryentry')
# Deleting model 'ObjectWorkflowHistoryEntry'
db.delete_table('ietfworkflows_objectworkflowhistoryentry')
# Adding model 'objectworkflowhistoryentry'
db.create_table('ietfworkflows_objectworkflowhistoryentry', (
('comment', orm['ietfworkflows.objectworkflowhistoryentry:comment']),
('from_state', orm['ietfworkflows.objectworkflowhistoryentry:from_state']),
('to_state', orm['ietfworkflows.objectworkflowhistoryentry:to_state']),
('content_type', orm['ietfworkflows.objectworkflowhistoryentry:content_type']),
('person', orm['ietfworkflows.objectworkflowhistoryentry:person']),
('content_id', orm['ietfworkflows.objectworkflowhistoryentry:content_id']),
('id', orm['ietfworkflows.objectworkflowhistoryentry:id']),
('transition_date', orm['ietfworkflows.objectworkflowhistoryentry:transition_date']),
))
db.send_create_signal('ietfworkflows', ['objectworkflowhistoryentry'])
# Adding model 'objectannotationtaghistoryentry'
db.create_table('ietfworkflows_objectannotationtaghistoryentry', (
('comment', orm['ietfworkflows.objectworkflowhistoryentry:comment']),
('person', orm['ietfworkflows.objectworkflowhistoryentry:person']),
('unsetted', orm['ietfworkflows.objectworkflowhistoryentry:unsetted']),
('content_type', orm['ietfworkflows.objectworkflowhistoryentry:content_type']),
('change_date', orm['ietfworkflows.objectworkflowhistoryentry:change_date']),
('setted', orm['ietfworkflows.objectworkflowhistoryentry:setted']),
('content_id', orm['ietfworkflows.objectworkflowhistoryentry:content_id']),
('id', orm['ietfworkflows.objectworkflowhistoryentry:id']),
))
db.send_create_signal('ietfworkflows', ['objectannotationtaghistoryentry'])
models = {
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.idintendedstatus': {
'Meta': {'db_table': "'id_intended_status'"},
'intended_status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idstatus': {
'Meta': {'db_table': "'id_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.internetdraft': {
'Meta': {'db_table': "'internet_drafts'"},
'abstract': ('django.db.models.fields.TextField', [], {}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_discussion_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'dunn_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'expired_tombstone': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'extension_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Acronym']", 'db_column': "'group_acronym_id'"}),
'id_document_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id_document_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDIntendedStatus']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_changes': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True'}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'replaced_by': ('django.db.models.fields.related.ForeignKey', ["orm['idtracker.InternetDraft']"], {'related_name': "'replaces_set'", 'null': 'True', 'db_column': "'replaced_by'", 'blank': 'True'}),
'review_by_rfc_editor': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'revision_date': ('django.db.models.fields.DateField', [], {}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDStatus']"}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'id_document_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {}),
'wgreturn_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.annotationtag': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'annotation_tags'", 'to': "orm['workflows.Workflow']"})
},
'ietfworkflows.annotationtagobjectrelation': {
'annotation_tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.AnnotationTag']"}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'ietfworkflows.objectannotationtaghistoryentry': {
'objecthistoryentry_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['ietfworkflows.ObjectHistoryEntry']", 'unique': 'True', 'primary_key': 'True'}),
'setted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'unsetted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objecthistoryentry': {
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"})
},
'ietfworkflows.objectstreamhistoryentry': {
'from_stream': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'objecthistoryentry_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['ietfworkflows.ObjectHistoryEntry']", 'unique': 'True', 'primary_key': 'True'}),
'to_stream': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objectworkflowhistoryentry': {
'from_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'objecthistoryentry_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['ietfworkflows.ObjectHistoryEntry']", 'unique': 'True', 'primary_key': 'True'}),
'to_state': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'ietfworkflows.stateobjectrelationmetadata': {
'estimated_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'from_date': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'relation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.StateObjectRelation']"})
},
'ietfworkflows.stream': {
'group_chair_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'group_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'with_groups': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.WGWorkflow']"})
},
'ietfworkflows.streamedid': {
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'streamed_id'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'draft': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.InternetDraft']", 'unique': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.Stream']", 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.wgworkflow': {
'selected_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.State']", 'null': 'True', 'blank': 'True'}),
'selected_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['ietfworkflows.AnnotationTag']", 'null': 'True', 'blank': 'True'}),
'workflow_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['workflows.Workflow']", 'unique': 'True', 'primary_key': 'True'})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'workflows.state': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transitions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.Transition']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['workflows.Workflow']"})
},
'workflows.stateobjectrelation': {
'Meta': {'unique_together': "(('content_type', 'content_id', 'state'),)"},
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'state_object'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"})
},
'workflows.transition': {
'condition': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destination_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflow': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['permissions.Permission']", 'symmetrical': 'False'})
}
}
complete_apps = ['ietfworkflows']

View file

@ -0,0 +1,197 @@
from south.db import db
from django.db import models
from ietf.ietfworkflows.models import *
class Migration:
def forwards(self, orm):
# Changing field 'StateObjectRelationMetadata.from_date'
# (to signature: django.db.models.fields.DateTimeField(null=True, blank=True))
db.alter_column('ietfworkflows_stateobjectrelationmetadata', 'from_date', orm['ietfworkflows.stateobjectrelationmetadata:from_date'])
def backwards(self, orm):
# Changing field 'StateObjectRelationMetadata.from_date'
# (to signature: django.db.models.fields.DateTimeField())
db.alter_column('ietfworkflows_stateobjectrelationmetadata', 'from_date', orm['ietfworkflows.stateobjectrelationmetadata:from_date'])
models = {
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.idintendedstatus': {
'Meta': {'db_table': "'id_intended_status'"},
'intended_status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idstatus': {
'Meta': {'db_table': "'id_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.internetdraft': {
'Meta': {'db_table': "'internet_drafts'"},
'abstract': ('django.db.models.fields.TextField', [], {}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_discussion_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'dunn_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'expired_tombstone': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'extension_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Acronym']", 'db_column': "'group_acronym_id'"}),
'id_document_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id_document_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDIntendedStatus']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_changes': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True'}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'replaced_by': ('django.db.models.fields.related.ForeignKey', ["orm['idtracker.InternetDraft']"], {'related_name': "'replaces_set'", 'null': 'True', 'db_column': "'replaced_by'", 'blank': 'True'}),
'review_by_rfc_editor': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'revision_date': ('django.db.models.fields.DateField', [], {}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDStatus']"}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'id_document_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {}),
'wgreturn_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.annotationtag': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'annotation_tags'", 'to': "orm['workflows.Workflow']"})
},
'ietfworkflows.annotationtagobjectrelation': {
'annotation_tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.AnnotationTag']"}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'ietfworkflows.objectannotationtaghistoryentry': {
'objecthistoryentry_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['ietfworkflows.ObjectHistoryEntry']", 'unique': 'True', 'primary_key': 'True'}),
'setted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'unsetted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objecthistoryentry': {
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"})
},
'ietfworkflows.objectstreamhistoryentry': {
'from_stream': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'objecthistoryentry_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['ietfworkflows.ObjectHistoryEntry']", 'unique': 'True', 'primary_key': 'True'}),
'to_stream': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objectworkflowhistoryentry': {
'from_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'objecthistoryentry_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['ietfworkflows.ObjectHistoryEntry']", 'unique': 'True', 'primary_key': 'True'}),
'to_state': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'ietfworkflows.stateobjectrelationmetadata': {
'estimated_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'from_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'relation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.StateObjectRelation']"})
},
'ietfworkflows.stream': {
'group_chair_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'group_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'with_groups': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.WGWorkflow']"})
},
'ietfworkflows.streamedid': {
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'streamed_id'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'draft': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.InternetDraft']", 'unique': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.Stream']", 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.wgworkflow': {
'selected_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.State']", 'null': 'True', 'blank': 'True'}),
'selected_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['ietfworkflows.AnnotationTag']", 'null': 'True', 'blank': 'True'}),
'workflow_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['workflows.Workflow']", 'unique': 'True', 'primary_key': 'True'})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'workflows.state': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transitions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['workflows.Transition']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['workflows.Workflow']"})
},
'workflows.stateobjectrelation': {
'Meta': {'unique_together': "(('content_type', 'content_id', 'state'),)"},
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'state_object'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"})
},
'workflows.transition': {
'condition': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destination_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflow': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['permissions.Permission']", 'symmetrical': 'False'})
}
}
complete_apps = ['ietfworkflows']

View file

@ -0,0 +1,207 @@
from south.db import db
from django.db import models
from ietf.ietfworkflows.models import *
class Migration:
def forwards(self, orm):
# Adding model 'StateDescription'
db.create_table('ietfworkflows_statedescription', (
('id', orm['ietfworkflows.statedescription:id']),
('state', orm['ietfworkflows.statedescription:state']),
('definition', orm['ietfworkflows.statedescription:definition']),
('order', orm['ietfworkflows.statedescription:order']),
))
db.send_create_signal('ietfworkflows', ['StateDescription'])
def backwards(self, orm):
# Deleting model 'StateDescription'
db.delete_table('ietfworkflows_statedescription')
models = {
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.idintendedstatus': {
'Meta': {'db_table': "'id_intended_status'"},
'intended_status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idstatus': {
'Meta': {'db_table': "'id_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.internetdraft': {
'Meta': {'db_table': "'internet_drafts'"},
'abstract': ('django.db.models.fields.TextField', [], {}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_discussion_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'dunn_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'expired_tombstone': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'extension_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Acronym']", 'db_column': "'group_acronym_id'"}),
'id_document_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id_document_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDIntendedStatus']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_changes': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True'}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'replaced_by': ('django.db.models.fields.related.ForeignKey', ["orm['idtracker.InternetDraft']"], {'related_name': "'replaces_set'", 'null': 'True', 'db_column': "'replaced_by'", 'blank': 'True'}),
'review_by_rfc_editor': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'revision_date': ('django.db.models.fields.DateField', [], {}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDStatus']"}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'id_document_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {}),
'wgreturn_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.annotationtag': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'annotation_tags'", 'to': "orm['workflows.Workflow']"})
},
'ietfworkflows.annotationtagobjectrelation': {
'annotation_tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.AnnotationTag']"}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'annotation_tags'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'ietfworkflows.objectannotationtaghistoryentry': {
'objecthistoryentry_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['ietfworkflows.ObjectHistoryEntry']", 'unique': 'True', 'primary_key': 'True'}),
'setted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'unsetted': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objecthistoryentry': {
'comment': ('django.db.models.fields.TextField', [], {}),
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_history'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"})
},
'ietfworkflows.objectstreamhistoryentry': {
'from_stream': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'objecthistoryentry_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['ietfworkflows.ObjectHistoryEntry']", 'unique': 'True', 'primary_key': 'True'}),
'to_stream': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'ietfworkflows.objectworkflowhistoryentry': {
'from_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'objecthistoryentry_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['ietfworkflows.ObjectHistoryEntry']", 'unique': 'True', 'primary_key': 'True'}),
'to_state': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'ietfworkflows.statedescription': {
'definition': ('django.db.models.fields.TextField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"})
},
'ietfworkflows.stateobjectrelationmetadata': {
'estimated_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'from_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'relation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.StateObjectRelation']"})
},
'ietfworkflows.stream': {
'group_chair_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'group_model': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'with_groups': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.WGWorkflow']"})
},
'ietfworkflows.streamedid': {
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'streamed_id'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'draft': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.InternetDraft']", 'unique': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ietfworkflows.Stream']", 'null': 'True', 'blank': 'True'})
},
'ietfworkflows.wgworkflow': {
'selected_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['workflows.State']", 'null': 'True', 'blank': 'True'}),
'selected_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['ietfworkflows.AnnotationTag']", 'null': 'True', 'blank': 'True'}),
'workflow_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['workflows.Workflow']", 'unique': 'True', 'primary_key': 'True'})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'workflows.state': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transitions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['workflows.Transition']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['workflows.Workflow']"})
},
'workflows.stateobjectrelation': {
'Meta': {'unique_together': "(('content_type', 'content_id', 'state'),)"},
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'state_object'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"})
},
'workflows.transition': {
'condition': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destination_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflow': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['permissions.Permission']", 'symmetrical': 'False'})
}
}
complete_apps = ['ietfworkflows']

View file

@ -0,0 +1,157 @@
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.translation import ugettext_lazy as _
from ietf.idtracker.models import PersonOrOrgInfo, InternetDraft
from workflows.models import Workflow, State, StateObjectRelation
from permissions.models import Permission
class ObjectHistoryEntry(models.Model):
content_type = models.ForeignKey(ContentType, verbose_name=_(u"Content type"), related_name="workflow_history", blank=True, null=True)
content_id = models.PositiveIntegerField(_(u"Content id"), blank=True, null=True)
content = generic.GenericForeignKey(ct_field="content_type", fk_field="content_id")
date = models.DateTimeField(_('Date'), auto_now_add=True)
comment = models.TextField(_('Comment'))
person = models.ForeignKey(PersonOrOrgInfo)
class Meta:
ordering = ('-date', )
def get_real_instance(self):
if hasattr(self, '_real_instance'):
return self._real_instance
for i in ('objectworkflowhistoryentry', 'objectannotationtaghistoryentry', 'objectstreamhistoryentry'):
try:
real_instance = getattr(self, i, None)
if real_instance:
self._real_instance = real_instance
return real_instance
except models.ObjectDoesNotExist:
continue
self._real_instance = self
return self
class ObjectWorkflowHistoryEntry(ObjectHistoryEntry):
from_state = models.CharField(_('From state'), max_length=100)
to_state = models.CharField(_('To state'), max_length=100)
def describe_change(self):
html = '<p class="describe_state_change">'
html += 'Changed state <i>%s</i> to <b>%s</b>' % (self.from_state, self.to_state)
html += '</p>'
return html
class ObjectAnnotationTagHistoryEntry(ObjectHistoryEntry):
setted = models.TextField(_('Setted tags'), blank=True, null=True)
unsetted = models.TextField(_('Unsetted tags'), blank=True, null=True)
def describe_change(self):
html = ''
if self.setted:
html += '<p class="describe_tags_set">'
html += 'Annotation tags set: '
html += self.setted
html += '</p>'
if self.unsetted:
html += '<p class="describe_tags_reset">'
html += 'Annotation tags reset: '
html += self.unsetted
html += '</p>'
return html
class ObjectStreamHistoryEntry(ObjectHistoryEntry):
from_stream = models.TextField(_('From stream'), blank=True, null=True)
to_stream = models.TextField(_('To stream'), blank=True, null=True)
def describe_change(self):
html = '<p class="describe_stream_change">'
html += 'Changed doc from stream <i>%s</i> to <b>%s</b>' % (self.from_stream, self.to_stream)
html += '</p>'
return html
class StateDescription(models.Model):
state = models.ForeignKey(State)
definition = models.TextField()
order = models.PositiveIntegerField()
class Meta:
ordering = ('order', )
def __unicode__(self):
return unicode(self.state)
class AnnotationTag(models.Model):
name = models.CharField(_(u"Name"), max_length=100)
workflow = models.ForeignKey(Workflow, verbose_name=_(u"Workflow"), related_name="annotation_tags")
permission = models.ForeignKey(Permission, verbose_name=_(u"Permission"), blank=True, null=True)
class Meta:
ordering = ('name', )
def __unicode__(self):
return self.name
class AnnotationTagObjectRelation(models.Model):
content_type = models.ForeignKey(ContentType, verbose_name=_(u"Content type"), related_name="annotation_tags", blank=True, null=True)
content_id = models.PositiveIntegerField(_(u"Content id"), blank=True, null=True)
content = generic.GenericForeignKey(ct_field="content_type", fk_field="content_id")
annotation_tag = models.ForeignKey(AnnotationTag, verbose_name=_(u"Annotation tag"))
class StateObjectRelationMetadata(models.Model):
relation = models.ForeignKey(StateObjectRelation)
from_date = models.DateTimeField(_('Initial date'), blank=True, null=True)
estimated_date = models.DateTimeField(_('Estimated date'), blank=True, null=True)
class WGWorkflow(Workflow):
selected_states = models.ManyToManyField(State, blank=True, null=True)
selected_tags = models.ManyToManyField(AnnotationTag, blank=True, null=True)
class Meta:
verbose_name = 'IETF Workflow'
verbose_name_plural = 'IETF Workflows'
def get_tags(self):
tags = self.annotation_tags.all()
if tags.count():
return tags
else:
return self.selected_tags.all()
def get_states(self):
states = self.states.all()
if states.count():
return states
else:
return self.selected_states.all()
class Stream(models.Model):
name = models.CharField(_(u"Name"), max_length=100)
with_groups = models.BooleanField(_(u'With groups'), default=False)
group_model = models.CharField(_(u'Group model'), max_length=100, blank=True, null=True)
group_chair_model = models.CharField(_(u'Group chair model'), max_length=100, blank=True, null=True)
workflow = models.ForeignKey(WGWorkflow)
def __unicode__(self):
return u'%s stream' % self.name
class StreamedID(models.Model):
draft = models.OneToOneField(InternetDraft)
stream = models.ForeignKey(Stream, blank=True, null=True)
content_type = models.ForeignKey(ContentType, verbose_name=_(u"Content type"), related_name="streamed_id", blank=True, null=True)
content_id = models.PositiveIntegerField(_(u"Content id"), blank=True, null=True)
group = generic.GenericForeignKey(ct_field="content_type", fk_field="content_id")

View file

@ -0,0 +1,114 @@
from django.db import models
from ietf.idrfc.idrfc_wrapper import IdRfcWrapper, IdWrapper
from ietf.ietfworkflows.models import StreamedID, Stream
def get_streamed_draft(draft):
if not draft:
return None
try:
return draft.streamedid
except StreamedID.DoesNotExist:
return None
def get_stream_from_draft(draft):
streamedid = get_streamed_draft(draft)
if streamedid:
return streamedid.stream
return False
def get_stream_by_name(stream_name):
try:
return Stream.objects.get(name=stream_name)
except Stream.DoesNotExist:
return None
def get_stream_from_id(stream_id):
try:
return Stream.objects.get(id=stream_id)
except Stream.DoesNotExist:
return None
def get_chair_model(stream):
model_str = stream.group_chair_model
if not model_str:
return None
try:
app, model = model_str.split('.', 1)
except ValueError:
return None
chair_model = models.get_model(app, model)
if not chair_model:
return
return chair_model
def _get_group_from_acronym(group_model_str, acronym):
try:
app, model = group_model_str.split('.', 1)
except ValueError:
return None
group_model = models.get_model(app, model)
if not group_model:
return
if 'acronym' in group_model._meta.get_all_field_names():
try:
return group_model._default_manager.get(acronym=acronym)
except group_model.DoesNotExist:
return None
elif 'group_acronym' in group_model._meta.get_all_field_names():
try:
return group_model._default_manager.get(group_acronym__acronym=acronym)
except group_model.DoesNotExist:
return None
else:
return None
def _set_stream_automatically(draft, stream):
streamed = StreamedID.objects.create(stream=stream, draft=draft)
if not stream or not stream.with_groups:
return
try:
draft_literal, stream_name, group_name, extra = draft.filename.split('-', 3)
if stream_name.lower() == stream.name.lower():
group = _get_group_from_acronym(stream.group_model, group_name)
if group:
streamed.group = group
streamed.save()
except ValueError:
return
def get_stream_from_wrapper(idrfc_wrapper):
idwrapper = None
if isinstance(idrfc_wrapper, IdRfcWrapper):
idwrapper = idrfc_wrapper.id
elif isinstance(idrfc_wrapper, IdWrapper):
idwrapper = idrfc_wrapper
if not idwrapper:
return None
draft = idwrapper._draft
stream = get_stream_from_draft(draft)
if stream == False:
stream_id = idwrapper.stream_id()
stream = get_stream_from_id(stream_id)
_set_stream_automatically(draft, stream)
return stream
else:
return stream
return None
def set_stream_for_draft(draft, stream):
(streamed, created) = StreamedID.objects.get_or_create(draft=draft)
if streamed.stream != stream:
streamed.stream = stream
streamed.group = None
streamed.save()
return streamed.stream

View file

@ -0,0 +1,74 @@
from django import template
from ietf.idrfc.idrfc_wrapper import IdRfcWrapper, IdWrapper
from ietf.ietfworkflows.utils import (get_workflow_for_draft,
get_state_for_draft)
from ietf.wgchairs.accounts import (can_manage_shepherd_of_a_document,
can_manage_writeup_of_a_document)
from ietf.ietfworkflows.streams import get_stream_from_wrapper
from ietf.ietfworkflows.accounts import (can_edit_state, can_edit_stream)
register = template.Library()
@register.inclusion_tag('ietfworkflows/stream_state.html', takes_context=True)
def stream_state(context, doc):
request = context.get('request', None)
data = {}
stream = get_stream_from_wrapper(doc)
data.update({'stream': stream})
if not stream:
return data
idwrapper = None
if isinstance(doc, IdRfcWrapper):
idwrapper = doc.id
elif isinstance(doc, IdWrapper):
idwrapper = doc
if not idwrapper:
return data
draft = getattr(idwrapper, '_draft', None)
if not draft:
return data
workflow = get_workflow_for_draft(draft)
state = get_state_for_draft(draft)
data.update({'workflow': workflow,
'draft': draft,
'state': state})
return data
@register.inclusion_tag('ietfworkflows/workflow_history_entry.html', takes_context=True)
def workflow_history_entry(context, entry):
real_entry = entry.get_real_instance()
return {'entry': real_entry,
'entry_class': real_entry.__class__.__name__.lower()}
@register.inclusion_tag('ietfworkflows/edit_actions.html', takes_context=True)
def edit_actions(context, wrapper):
request = context.get('request', None)
user = request and request.user
if not user:
return {}
idwrapper = None
if isinstance(wrapper, IdRfcWrapper):
idwrapper = wrapper.id
elif isinstance(wrapper, IdWrapper):
idwrapper = wrapper
if not idwrapper:
return None
draft = idwrapper._draft
return {
'can_edit_state': can_edit_state(user, draft),
'can_edit_stream': can_edit_stream(user, draft),
'can_writeup': can_manage_writeup_of_a_document(user, draft),
'can_shepherd': can_manage_shepherd_of_a_document(user, draft),
'draft': draft,
'doc': wrapper,
}

View file

@ -0,0 +1,9 @@
# Copyright The IETF Trust 2008, All Rights Reserved
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('ietf.ietfworkflows.views',
url(r'^(?P<name>[^/]+)/history/$', 'stream_history', name='stream_history'),
url(r'^(?P<name>[^/]+)/edit/state/$', 'edit_state', name='edit_state'),
url(r'^(?P<name>[^/]+)/edit/stream/$', 'edit_stream', name='edit_stream'),
)

294
ietf/ietfworkflows/utils.py Normal file
View file

@ -0,0 +1,294 @@
import copy
import datetime
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core.mail import EmailMessage
from django.template.loader import render_to_string
from workflows.models import State, StateObjectRelation
from workflows.utils import (get_workflow_for_object, set_workflow_for_object,
get_state, set_state)
from ietf.ietfworkflows.streams import (get_streamed_draft, get_stream_from_draft,
set_stream_for_draft)
from ietf.ietfworkflows.models import (WGWorkflow, AnnotationTagObjectRelation,
AnnotationTag, ObjectAnnotationTagHistoryEntry,
ObjectHistoryEntry, StateObjectRelationMetadata,
ObjectWorkflowHistoryEntry, ObjectStreamHistoryEntry)
WAITING_WRITEUP = 'WG Consensus: Waiting for Write-Up'
FOLLOWUP_TAG = 'Doc Shepherd Follow-up Underway'
def get_default_workflow_for_wg():
try:
workflow = WGWorkflow.objects.get(name='Default WG Workflow')
return workflow
except WGWorkflow.DoesNotExist:
return None
def clone_transition(transition):
new = copy.copy(transition)
new.pk = None
new.save()
# Reference original initial states
for state in transition.states.all():
new.states.add(state)
return new
def clone_workflow(workflow, name):
new = WGWorkflow.objects.create(name=name, initial_state=workflow.initial_state)
# Reference default states
for state in workflow.states.all():
new.selected_states.add(state)
# Reference default annotation tags
for tag in workflow.annotation_tags.all():
new.selected_tags.add(tag)
# Reference cloned transitions
for transition in workflow.transitions.all():
new.transitions.add(clone_transition(transition))
return new
def get_workflow_for_wg(wg, default=None):
workflow = get_workflow_for_object(wg)
try:
workflow = workflow and workflow.wgworkflow
except WGWorkflow.DoesNotExist:
workflow = None
if not workflow:
if default:
workflow = default
else:
workflow = get_default_workflow_for_wg()
if not workflow:
return None
workflow = clone_workflow(workflow, name='%s workflow' % wg)
set_workflow_for_object(wg, workflow)
return workflow
def get_workflow_for_draft(draft):
workflow = get_workflow_for_object(draft)
try:
workflow = workflow and workflow.wgworkflow
except WGWorkflow.DoesNotExist:
workflow = None
if not workflow:
streamed_draft = get_streamed_draft(draft)
if not streamed_draft or not streamed_draft.stream:
return None
stream = streamed_draft.stream
if stream.with_groups:
if not streamed_draft.group:
return None
else:
workflow = get_workflow_for_wg(streamed_draft.group, streamed_draft.stream.workflow)
else:
workflow = stream.workflow
set_workflow_for_object(draft, workflow)
return workflow
def get_workflow_history_for_draft(draft, entry_type=None):
ctype = ContentType.objects.get_for_model(draft)
filter_param = {'content_type': ctype,
'content_id': draft.pk}
if entry_type:
filter_param.update({'%s__isnull' % entry_type: False})
history = ObjectHistoryEntry.objects.filter(**filter_param).\
select_related('objectworkflowhistoryentry', 'objectannotationtaghistoryentry',
'objectstreamhistoryentry')
return history
def get_annotation_tags_for_draft(draft):
ctype = ContentType.objects.get_for_model(draft)
tags = AnnotationTagObjectRelation.objects.filter(content_type=ctype, content_id=draft.pk)
return tags
def get_state_for_draft(draft):
return get_state(draft)
def get_state_by_name(state_name):
try:
return State.objects.get(name=state_name)
except State.DoesNotExist:
return None
def get_annotation_tag_by_name(tag_name):
try:
return AnnotationTag.objects.get(name=tag_name)
except AnnotationTag.DoesNotExist:
return None
def set_tag(obj, tag):
ctype = ContentType.objects.get_for_model(obj)
(relation, created) = AnnotationTagObjectRelation.objects.get_or_create(
content_type=ctype,
content_id=obj.pk,
annotation_tag=tag)
return relation
def set_tag_by_name(obj, tag_name):
try:
tag = AnnotationTag.objects.get(name=tag_name)
return set_tag(obj, tag)
except AnnotationTag.DoesNotExist:
return None
def reset_tag(obj, tag):
ctype = ContentType.objects.get_for_model(obj)
try:
tag_relation = AnnotationTagObjectRelation.objects.get(
content_type=ctype,
content_id=obj.pk,
annotation_tag=tag)
tag_relation.delete()
return True
except AnnotationTagObjectRelation.DoesNotExist:
return False
def reset_tag_by_name(obj, tag_name):
try:
tag = AnnotationTag.objects.get(name=tag_name)
return reset_tag(obj, tag)
except AnnotationTag.DoesNotExist:
return False
def set_state_for_draft(draft, state, estimated_date=None):
workflow = get_workflow_for_draft(draft)
if state in workflow.get_states():
set_state(draft, state)
relation = StateObjectRelation.objects.get(
content_type=ContentType.objects.get_for_model(draft),
content_id=draft.pk)
metadata = StateObjectRelationMetadata.objects.get_or_create(relation=relation)[0]
metadata.from_date = datetime.date.today()
metadata.to_date = estimated_date
metadata.save()
return state
return False
def notify_entry(entry, template, extra_notify=[]):
doc = entry.content
wg = doc.group.ietfwg
mail_list = set(['%s <%s>' % i.person.email() for i in wg.wgchair_set.all() if i.person.email()])
mail_list = mail_list.union(['%s <%s>' % i.person.email() for i in wg.wgdelegate_set.all() if i.person.email()])
mail_list = mail_list.union(['%s <%s>' % i.person.email() for i in doc.authors.all() if i.person.email()])
mail_list = mail_list.union(extra_notify)
mail_list = list(mail_list)
subject = 'Annotation tags have changed for draft %s' % doc
body = render_to_string(template, {'doc': doc,
'entry': entry,
})
mail = EmailMessage(subject=subject,
body=body,
to=mail_list,
from_email=settings.DEFAULT_FROM_EMAIL)
# Only send emails if we are not debug mode
if not settings.DEBUG:
mail.send()
return mail
def notify_tag_entry(entry, extra_notify=[]):
return notify_entry(entry, 'ietfworkflows/annotation_tags_updated_mail.txt', extra_notify)
def notify_state_entry(entry, extra_notify=[]):
return notify_entry(entry, 'ietfworkflows/state_updated_mail.txt', extra_notify)
def notify_stream_entry(entry, extra_notify=[]):
return notify_entry(entry, 'ietfworkflows/stream_updated_mail.txt', extra_notify)
def update_tags(obj, comment, person, set_tags=[], reset_tags=[], extra_notify=[]):
ctype = ContentType.objects.get_for_model(obj)
setted = []
resetted = []
for tag in set_tags:
if isinstance(tag, basestring):
if set_tag_by_name(obj, tag):
setted.append(tag)
else:
if set_tag(obj, tag):
setted.append(tag.name)
for tag in reset_tags:
if isinstance(tag, basestring):
if reset_tag_by_name(obj, tag):
resetted.append(tag)
else:
if reset_tag(obj, tag):
resetted.append(tag.name)
entry = ObjectAnnotationTagHistoryEntry.objects.create(
content_type=ctype,
content_id=obj.pk,
setted=','.join(setted),
unsetted=','.join(resetted),
date=datetime.datetime.now(),
comment=comment,
person=person)
notify_tag_entry(entry, extra_notify)
def update_state(obj, comment, person, to_state, estimated_date=None, extra_notify=[]):
ctype = ContentType.objects.get_for_model(obj)
from_state = get_state_for_draft(obj)
to_state = set_state_for_draft(obj, to_state, estimated_date)
if not to_state:
return False
entry = ObjectWorkflowHistoryEntry.objects.create(
content_type=ctype,
content_id=obj.pk,
from_state=from_state and from_state.name or '',
to_state=to_state and to_state.name or '',
date=datetime.datetime.now(),
comment=comment,
person=person)
notify_state_entry(entry, extra_notify)
def update_stream(obj, comment, person, to_stream, extra_notify=[]):
ctype = ContentType.objects.get_for_model(obj)
from_stream = get_stream_from_draft(obj)
to_stream = set_stream_for_draft(obj, to_stream)
entry = ObjectStreamHistoryEntry.objects.create(
content_type=ctype,
content_id=obj.pk,
from_stream=from_stream and from_stream.name or '',
to_stream=to_stream and to_stream.name or '',
date=datetime.datetime.now(),
comment=comment,
person=person)
notify_stream_entry(entry, extra_notify)
def get_full_info_for_draft(draft):
return dict(
streamed=get_streamed_draft(draft),
stream=get_stream_from_draft(draft),
workflow=get_workflow_for_draft(draft),
tags=[i.annotation_tag for i in get_annotation_tags_for_draft(draft)],
state=get_state_for_draft(draft),
shepherd=draft.shepherd,
)

View file

@ -0,0 +1,88 @@
from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from ietf.idtracker.models import InternetDraft
from ietf.ietfworkflows.forms import (DraftTagsStateForm,
DraftStreamForm,
NoWorkflowStateForm)
from ietf.ietfworkflows.streams import (get_stream_from_draft,
get_streamed_draft)
from ietf.ietfworkflows.utils import (get_workflow_history_for_draft,
get_workflow_for_draft,
get_annotation_tags_for_draft,
get_state_for_draft)
from ietf.ietfworkflows.accounts import (can_edit_state, can_edit_stream)
REDUCED_HISTORY_LEN = 20
def stream_history(request, name):
draft = get_object_or_404(InternetDraft, filename=name)
streamed = get_streamed_draft(draft)
stream = get_stream_from_draft(draft)
workflow = get_workflow_for_draft(draft)
tags = []
if workflow:
tags_setted = [i.annotation_tag.pk for i in get_annotation_tags_for_draft(draft)]
for tag in workflow.get_tags():
tag.setted = tag.pk in tags_setted
tags.append(tag)
state = get_state_for_draft(draft)
history = get_workflow_history_for_draft(draft)
show_more = False
if history.count > REDUCED_HISTORY_LEN:
show_more = True
return render_to_response('ietfworkflows/stream_history.html',
{'stream': stream,
'streamed': streamed,
'draft': draft,
'tags': tags,
'state': state,
'workflow': workflow,
'show_more': show_more,
'history': history[:REDUCED_HISTORY_LEN],
},
context_instance=RequestContext(request))
def _edit_draft_stream(request, draft, form_class=DraftTagsStateForm):
user = request.user
workflow = get_workflow_for_draft(draft)
if not workflow:
form_class = NoWorkflowStateForm
if request.method == 'POST':
form = form_class(user=user, draft=draft, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('.')
else:
form = form_class(user=user, draft=draft)
state = get_state_for_draft(draft)
stream = get_stream_from_draft(draft)
history = get_workflow_history_for_draft(draft, 'objectworkflowhistoryentry')
tags = get_annotation_tags_for_draft(draft)
return render_to_response('ietfworkflows/state_edit.html',
{'draft': draft,
'state': state,
'stream': stream,
'workflow': workflow,
'history': history,
'tags': tags,
'form': form,
},
context_instance=RequestContext(request))
def edit_state(request, name):
draft = get_object_or_404(InternetDraft, filename=name)
if not can_edit_state(request.user, draft):
return HttpResponseForbidden('You have no permission to access this view')
return _edit_draft_stream(request, draft, DraftTagsStateForm)
def edit_stream(request, name):
draft = get_object_or_404(InternetDraft, filename=name)
if not can_edit_stream(request.user, draft):
return HttpResponseForbidden('You have no permission to access this view')
return _edit_draft_stream(request, draft, DraftStreamForm)

View file

@ -119,6 +119,8 @@ INSTALLED_APPS = (
'django.contrib.admindocs',
'django.contrib.humanize',
'south',
'workflows',
'permissions',
'ietf.announcements',
'ietf.idindex',
'ietf.idtracker',
@ -133,6 +135,8 @@ INSTALLED_APPS = (
'ietf.idrfc',
'ietf.wginfo',
'ietf.submit',
'ietf.ietfworkflows',
'ietf.wgchairs',
)
INTERNAL_IPS = (
@ -156,6 +160,9 @@ SERVER_MODE = 'development'
# The name of the method to use to invoke the test suite
TEST_RUNNER = 'ietf.utils.test_runner.run_tests'
# WG Chair configuration
MAX_WG_DELEGATES = 3
# Override this in settings_local.py if needed
# *_PATH variables ends with a slash/ .
INTERNET_DRAFT_PATH = '/a/www/ietf-ftp/internet-drafts/'

View file

@ -32,26 +32,30 @@ 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 %}
{% load ietf_filters ietf_streams %}
{% block title %}{{ doc.draft_name_and_revision }}{% endblock %}
{% block doc_meta_description %}{{ doc.title }} ({{info.type}}; {{doc.publication_date|date:"Y"}}){% endblock %}
{% block doc_h1 %}{{ doc.title|escape }}<br/>{{ doc.draft_name_and_revision }}{% endblock %}
{% block doc_metatable %}
<tr><td style="width:18ex;">Document type:</td><td>{{ info.type|escape }}
{% with doc.replaces as r %}{% if r %}<br />Replaces {% filter urlize_ietf_docs %}{{ r|join:", "}}{% endfilter %}{% endif %}{% endwith %}
</td></tr>
<tr><td>Last updated:</td><td> {{ doc.publication_date|default:"(data missing)" }}</td></tr>
<tr><td><a href="/idtracker/help/state/">State</>:</td><td>
{{ doc.friendly_state|safe }}
{% if doc.rfc_editor_state %}<br />RFC Editor State: <a href="http://www.rfc-editor.org/queue2.html#{{doc.draft_name}}">{{ doc.rfc_editor_state|escape }}</a>{% endif %}
<tr><td>Document Stream:</td><td> {{ stream_info.stream.name|default:"No stream defined" }}</td></tr>
<tr><td>I-D availability status:</td><td> {{ doc.draft_status }}
{% ifequal doc.draft_status "Expired" %}
{% if doc.resurrect_requested_by %}(resurrect requested by {{ doc.resurrect_requested_by }}){% endif %}
{% endifequal %}
{% with doc.replaces as r %}{% if r %}<br />Replaces {% filter urlize_ietf_docs %}{{ r|join:", "}}{% endfilter %}{% endif %}{% endwith %}
</td></tr>
<tr><td>Last updated:</td><td> {{ doc.publication_date|default:"(data missing)" }}</td></tr>
<tr><td>IETF WG status:</td><td>{{ stream_info.state.name }} ({{ stream_info.streamed.group }})
{% if stream_info.tags %}<br /><i>{% for tag in stream_info.tags %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endif %}
</td></tr>
<tr><td>Intended RFC status:</td><td>{% if doc.in_ietf_process %}{{ doc.ietf_process.intended_maturity_level|default:"-" }}{% else %}-{%endif%}</td></tr>
<tr><td>Document shepherd:</td><td>{{ stream_info.shepherd }}</td></tr>
<tr><td><a href="/idtracker/help/state/">IESG State</>:</td><td> {{ doc.friendly_state|safe }}
{% if doc.rfc_editor_state %}<br />RFC Editor State: <a href="http://www.rfc-editor.org/queue2.html#{{doc.draft_name}}">{{ doc.rfc_editor_state|escape }}</a>{% endif %}
{% if doc.in_ietf_process %}{% if doc.ietf_process.telechat_date %}<br/>On agenda of {{ doc.ietf_process.telechat_date }} IESG telechat {% if doc.ietf_process.telechat_returning_item %} (returning item){%endif%}{%endif%}{% if doc.ietf_process.has_active_iesg_ballot %}<br/><i>({{ doc.ietf_process.iesg_ballot_needed }})</i>{%endif%}{%endif%}
</td></tr>
<tr><td>Intended status:</td><td>{% if doc.in_ietf_process %}{{ doc.ietf_process.intended_maturity_level|default:"-" }}{% else %}-{%endif%}</td></tr>
<tr><td>Submission:</td><td>{{ doc.submission }}</td></tr>
<tr><td>Responsible AD:</td><td>{% if doc.in_ietf_process %}{{ doc.ietf_process.ad_name|default:"-"|escape }}{%else%}-{%endif%}</td></tr>
{% if doc.in_ietf_process and doc.ietf_process.iesg_note %}<tr><td>IESG Note:</td><td>{{ doc.ietf_process.iesg_note|format_textarea|safe }}</td></tr>{% endif %}
@ -76,6 +80,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% endblock doc_metatable %}
{% block doc_metalinks %}
{% edit_actions doc %}
<div>
<a href="mailto:{{doc.draft_name}}@tools.ietf.org?subject=Mail%20regarding%20{{doc.draft_name}}" rel="nofollow">Email Authors</a>
| <a href="/ipr/search/?option=document_search&amp;id_document_tag={{doc.tracker_id}}" rel="nofollow">IPR Disclosures</a>

View file

@ -31,7 +31,7 @@ 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 %}{% load ballot_icon %}
{% load ietf_filters ietf_streams %}{% load ballot_icon %}
<td class="status">
{{ doc.friendly_state|safe }} {% if not doc.rfc %}{{ doc.id|state_age_colored|safe }}{% endif %}
{% if not hide_telechat_date %}{% if doc.telechat_date %}<br/>IESG Telechat: {{ doc.telechat_date }}{% endif %}{% endif %}
@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% if doc.rfc.has_errata %}<br /><a href="http://www.rfc-editor.org/errata_search.php?rfc={{doc.rfc.rfc_number}}" rel="nofollow">Errata</a>{% endif %}
{% else %}{# not rfc #}
{% if doc.id.rfc_editor_state %}<br />RFC Editor State: <a href="http://www.rfc-editor.org/queue2.html#{{doc.id.draft_name}}">{{ doc.id.rfc_editor_state|escape }}</a>{% endif %}
{% stream_state doc %}
{% endif %}
</td>
<td class="ballot">

View file

@ -0,0 +1,9 @@
The annotation tags of document {{ doc }} have been updated. See more information below.
Annotation tags set: {{ entry.setted }}
Annotation tags reset: {{ entry.unsetted }}
Date of the change: {{ entry.change_date }}
Author of the change: {{ entry.person }}
Comment:
{{ entry.comment }}

View file

@ -0,0 +1,7 @@
<div style="margin-bottom: 1em;">
{% if can_edit_state %} <a href="{% url edit_state doc.draft_name %}">Change state</a> {% endif %}
{% if can_edit_stream %}{% if can_edit_state %} | {% endif %}<a href="{% url edit_stream doc.draft_name %}">Change draft stream</a>{% endif %}
{% if can_shepherd %}{% if can_edit_state or can_edit_stream %} | {% endif %}<a href="{% url doc_managing_shepherd draft.group.acronym draft.filename %}">Change draft shepherd</a>{% endif %}
{% if can_writeup %}{% if can_edit_state or can_edit_stream or can_writeup %} | {% endif %}<a href="{% url doc_managing_writeup draft.group.acronym draft.filename %}">Change draft writeup</a>{% endif %}
</div>

View file

@ -0,0 +1,26 @@
<form action="" method="post">
<table class="ietf-table edit-form" style="width: 100%;">
<tr>
<th>Adopt this draft in your WG</th>
</tr>
<tr style="vertical-align: top;"><td style="width: 50%;">
<div class="field{% if form.errors.comment %} error{% endif %}">
{{ form.errors.comment }}
Comment: <span class="required">*</span><br />
<textarea name="comment">{{ form.data.comment }}</textarea>
</div>
<div class="field{% if form.errors.weeks %} error{% endif %}">
{{ form.errors.weeks }}
Estimated time in 'Call for Adoption by WG Issued': <input type="text" name="weeks" value="{{ form.data.weeks }}" /> (in weeks)
</div>
<div class="field{% if form.errors.wg %} error{% endif %}">
<p>
You can manage different WGs, please select the WG in wich you want to call for adoption this draft
</p>
{{ form.errors.wg }}
Select a WG: {{ form.wg }}
</div>
<input type="submit" name="change" value="Call for adoption" />
</td></tr>
</table>
</form>

View file

@ -0,0 +1,70 @@
{% extends "base.html" %}
{% load ietf_streams %}
{% block morecss %}
table.state-history p { margin: 0px; }
table.edit-form ul { padding: 0px; list-style-type: none; margin: 0px; margin-bottom: 2em; }
table.edit-form ul li, table.edit-form div.free-change { padding: 0px 2em; }
table.edit-form ul li.evenrow { background-color: #edf5ff; }
table.edit-form textarea { width: 95%; height: 120px; }
table.edit-form span.required { color: red; }
table.edit-form ul.errorlist { border-width: 0px; padding: 0px; margin: 0px;}
table.edit-form ul.errorlist li { color: red; margin: 0px; padding: 0px;}
table.edit-form div.field { margin: 1em 0px; }
table.edit-form div.submit-row { margin: 0px 2em; }
table.edit-form div.error { border: 1px solid red; background-color: #ffeebb; padding: 5px 10px; }
table.edit-form-tags tr { vertical-align: top; }
table.edit-form-tags textarea { height: 200px; }
table.edit-form-tags ul { border-width: 0px; padding: 0px 2em; }
table.edit-form-tags ul li { padding: 0px; }
{% endblock morecss %}
{% block title %}Change state for {{ draft }}{% endblock %}
{% block content %}
<h1>Change state for {{ draft }}</h1>
<div class="return-to-document">
<p>
<a href="{% url doc_view draft.filename %}">Return to document view</a>
</p>
</div>
<table class="ietf-table" style="width: 100%;">
<tr>
<th>Current stream</th>
<th>Current state</th>
<th>Annotation tags</th>
</tr>
<tr><td style="width: 25%;">
{{ stream.name|default:"None" }}
</td>
<td style="width: 25%;">
{{ state.name|default:"None" }}
</td><td>
<ul style="list-style-type: none; padding: 0px;">
{% for tag in tags%}
<li>{{ tag.annotation_tag }}</li>
{% endfor %}
</ul>
</td></tr></table>
<br />
{{ form }}
<br />
<strong>State history</strong>
<table class="ietf-table state-history" style="width: 100%">
{% if history %}
<tr><th>Date</th><th>Person</th><th>Change</th><th>Comment</th></tr>
{% for baseentry in history %}
{% with baseentry.get_real_instance as entry %}
<tr class="{% cycle oddrow,evenrow %}"><td>{{ entry.date }}</td><td>{{ entry.person }}</td>
<td>{{ entry.describe_change|safe }}</td><td>{{ entry.comment }}</td>
</tr>
{% endwith %}
{% endfor %}
{% else %}
<tr><td>There is no state history for this document.</td></th>
{% endif %}
</table>
{% endblock %}

View file

@ -0,0 +1,60 @@
<form action="" method="post">
<table class="ietf-table edit-form" style="width: 100%;">
<tr>
<th>1. Input information about change</th>
<th>2. Change annotation tags if needed</th>
</tr>
<tr style="vertical-align: top;"><td style="width: 50%;">
<div class="field{% if form.errors.comment %} error{% endif %}">
{{ form.errors.comment }}
Comment: <span class="required">*</span><br />
<textarea name="comment">{{ form.data.comment }}</textarea>
</div>
<div class="field{% if form.errors.weeks %} error{% endif %}">
{{ form.errors.weeks }}
Estimated time in next status:<br />
<input type="text" name="weeks" value="{{ form.data.weeks }}" /> (in weeks)
</div>
</td><td>
<div class="field">
{{ form.tags }}
</div>
</td></tr>
</table>
<br />
<table class="ietf-table edit-form edit-form-tags" style="width: 100%;">
<tr>
<th>3. Select one action</th>
</tr>
<tr><td>
<div class="only-tags field">
<ul>
<li><input type="submit" name="only_tags" value="Update annotation tags" /> State remains unchanged: <strong>{{ form.state.name }}</strong></li>
</ul>
</div>
{% with form.get_transitions as transitions %}
{% if transitions %}
<ul>
{% for transition in transitions %}
<li class="{% cycle oddrow,evenrow %}">
<input type="submit" name="transition_{{ transition.pk }}" value="{{ transition.name }}" />
Changes state to: <strong>{{ transition.destination.name }}</strong>
</li>
{% endfor %}
{% endif %}
</ul>
{% endwith %}
<div class="free-change field{% if form.errors.new_state %} error{% endif %}">
{{ form.errors.new_state }}
<select name="new_state">
{% for value, name in form.get_states %}
<option value="{{ value }}">{{ name }}</option>
{% endfor %}
</select>
<input type="submit" name="change" value="State change" />
</div>
</td></tr>
</table>
</form>

View file

@ -0,0 +1,9 @@
The state of document {{ doc }} has been updated. See more information below.
Previous state: {{ entry.from_state }}
Current state: {{ entry.to_state }}
Transition date: {{ entry.transition_date }}
Author of the change: {{ entry.person }}
Comment:
{{ entry.comment }}

View file

@ -0,0 +1,21 @@
<form action="" method="post">
<table class="ietf-table edit-form" style="width: 100%;">
<tr>
<th>Select the new stream</th>
</tr>
<tr><td>
<div class="field{% if form.errors.comment %} error{% endif %}">
{{ form.errors.comment }}
Comment: <span class="required">*</span><br />
<textarea name="comment">{{ form.data.comment }}</textarea>
</div>
</td>
</tr>
<td>
<div class="field{% if form.errors.stream %} error{% endif %}">
{{ form.errors.stream }}
{{ form.stream }} <input type="submit" value="Change stream" />
</div>
</td></tr>
</table>
</form>

View file

@ -0,0 +1,44 @@
{% load ietf_streams %}
<table class="ietf-ballot ietf-stream">
<tr>
<td class="left">
{% if workflow %}
<ul class="ietf-stream-tag-list">
{% for tag in tags %}
<li{% if tag.setted %} class="tag_set"{% endif %}>{{ tag }}</li>
{% endfor %}
</ul>
{% endif %}
</td>
<td class="right">
<div class="ietf-stream-head">
{% if stream %}
<h2>
{{ stream|default:"Without stream" }}{% if stream.with_groups and streamed.group %} :: {{ streamed.group|default:"" }}{% endif %}
</h2>
<h3>Current state: {{ state|default:"None" }}</h3>
{% else %}
<h2>Without stream</h2>
{% endif %}
</div>
{% if history %}
<div class="ietf-stream-history">
{% if show_more %}
<p> Viewing the last 20 entries. <a href="">Show full log</a>.</p>
{% endif %}
{% for entry in history %}
{% workflow_history_entry entry %}
{% endfor %}
{% if show_more %}
<p> Viewing the last 20 entries. <a href="">Show full log</a>.</p>
{% endif %}
</div>
{% else %}
<p>
There is no stream history for this document.
</p>
{% endif %}
</td>
</tr>
</table>

View file

@ -0,0 +1,10 @@
{% if draft %}
<div class="stream_state" style="border: 1px solid black; padding: 0px 5px; margin: 5px 0px;">
<div class="stream_state_more" style="float: right; margin-left: 2em;"><a href="{% url stream_history draft.filename %}" class="show_stream_info" title="Stream information for {{ draft.filename }}" style="text-decoration: none; color: black;">+</a></div>
{% if stream %}
{{ stream }} {% if state %}:: {{ state }}{% endif %}
{% else %}
No stream asigned
{% endif %}
</div>
{% endif %}

View file

@ -0,0 +1,9 @@
The stream of document {{ doc }} has been updated. See more information below.
Previous stream: {{ entry.from_stream }}
Current stream: {{ entry.to_stream }}
Transition date: {{ entry.transition_date }}
Author of the change: {{ entry.person }}
Comment:
{{ entry.comment }}

View file

@ -0,0 +1,22 @@
<form action="" method="post">
<table class="ietf-table edit-form edit-form-tags" style="width: 100%;">
<tr>
<th>1. Input information about change</th>
<th>2. Select annotation tags</th>
</tr>
<tr><td style="width: 50%;">
<div class="field comment{% if form.errors.comment %} error{% endif %}">
{{ form.errors.comment }}
Comment: <span class="required">*</span><br />
<textarea name="comment">{{ form.data.comment }}</textarea>
</div>
</td><td style="padding: 0px; vertical-align: top;">
<div class="field">
{{ form.tags }}
</div>
<div class="submit-row">
<input type="submit" value="Edit tags" />
</div>
</td></tr>
</table>
</form>

View file

@ -0,0 +1,12 @@
<div class="workflow-history-entry workflow-history-entry-{{ entry_class }}">
<div class="entry-title">
<span class="entry-date">{{ entry.date }}</span>
{{ entry.person }}
</div>
<div class="entry-action">
{{ entry.describe_change|safe }}
</div>
<div class="entry-comment">
{{ entry.comment }}
</div>
</pre>

View file

@ -0,0 +1,55 @@
{% extends "wginfo/wg_base.html" %}
{% load ietf_filters wgchairs_tags %}
{% block title %}Chage shepherd for {{ doc }}{% endblock %}
{% block wg_content %}
<p>
<a href="{% url manage_shepherds wg.group_acronym.acronym %}">Return to shepherd list</a>
</p>
<h1>Updatting write-up for {{ doc }}</h1>
<p>
Before you modify the protocol write-up <strong>please revise the 'Doc Shepherd Follow-up Underway' annotation tag and set or reset it if appropriate</strong>.
</p>
<p>
Remember that you must provide a comment if you change the annotation tag state.
</p>
<form action="" method="POST">
<table style="width: 100%;"><tr style="vertical-align: top;"><td style="width: 50%;">
<table class="ietf-table" style="width: 100%;">
<tr><th>Doc Shepherd Follow-up Underway</th></tr>
{% if form.message %}
<tr><td class="message message-{{ form.message.type }}">
{{ form.message.value }}
</td></tr>
{% endif %}
<tr><td>
<input type="hidden" value="{{ form.get_writeup }}" name="writeup" />
<input type="hidden" value="confirm" name="confirm" />
<input type="checkbox" name="followup" id="followup_id" value="1"{% if followup %} checked="checked"{% endif %} />
<label for="followup_id">Doc Shepherd Follow-up Underway</label>
</td></tr><tr><td>
{{ form.comment }}
</td></tr>
</table>
<p>
<strong>Change write-up and ...</strong><br />
<input type="submit" name="modify_tag" value="Modify 'Doc Shepherd Follow-up Underway'" />
<input type="submit" name="change_writeup" value="Leave 'Doc Shepherd Follow-up Underway' untouched" /><br />
<a href="">Cancel, I don't want to do any change!</a>
</p>
</td><td style="width: 50%;">
<table class="ietf-table" style="width: 100%;">
<tr><th>New protocol write-up</th></tr>
<tr style="vertical-align: top;"><td>{{ form.get_writeup|linebreaksbr }}</td></tr>
</table>
</td></tr></table>
</form>
{% endblock %}

View file

@ -0,0 +1 @@
{{ state.name }}

View file

@ -0,0 +1,40 @@
{% extends "wginfo/wg_base.html" %}
{% load ietf_filters %}
{% block title %}Chage shepherd for {{ doc }}{% endblock %}
{% block wg_content %}
<p>
<a href="{% url manage_shepherds wg.group_acronym.acronym %}">Return to shepherd list</a>
</p>
<h1>Change shepherd for {{ doc }}</h1>
<table style="width: 100%;"><tr style="vertical-align: top;"><td style="width: 50%;">
<form action="" method="POST">
<table class="ietf-table" style="width: 100%;">
<tr><th>Actual shepherd</th></tr>
<tr><td>{% if doc.shepherd %}{{ doc.shepherd }}{% else %}No shephered assigned{% endif %}</td></tr>
</table>
<input type="hidden" name="update_shepherd" value="1" />
<input type="submit" name="remove_shepherd" value="Unassign shepherd" />
<input type="submit" name="setme" value="Set me as shepherd of this document" />
</form>
</td><td style="width: 50%;">
<form action="" method="POST">
<table class="ietf-table" style="width: 100%;">
<tr><th>Change shepherd</th></tr>
{% if form.message %}
<tr><td class="message message-{{ form.message.type }}">
{{ form.message.value }}
</td></tr>
{% endif %}
<tr><td>{{ form.as_p }}</td></tr>
</table>
<input type="submit" name="change_sheperd" value="Change shepherd" />
{% if form.can_cancel %}<a href="">No! I don't want to continue</a>{% endif %}
</form>
</td></tr></table>
{% endblock %}

View file

@ -0,0 +1,65 @@
{% extends "wginfo/wg_base.html" %}
{% load ietf_filters wgchairs_tags %}
{% block title %}Chage shepherd for {{ doc }}{% endblock %}
{% block wg_content %}
<p>
<a href="{% url manage_shepherds wg.group_acronym.acronym %}">Return to shepherd list</a>
</p>
<h1>Change protocol write-up for {{ doc }}</h1>
<table class="ietf-table" style="width: 100%;">
<tr><th>Draft state</th><th>Actual protocol write-up</th><th>Last updated</th></tr>
<tr style="vertical-align: top;"><td>{% show_state doc %}</td><td>{{ writeup.writeup|linebreaksbr }}</td><td>{% if writeup %}{{ writeup.date }} by {{ writeup.person }}{% endif %}</td></tr>
</table>
<p>
Please, <strong>note</strong> that the <strong>'Doc Shepherd Follow-up Underway'</strong> annotation tag is {% if not followup %}<strong>NOT</strong>{% endif %} setted for {{ doc }}.
</p>
{% if can_edit %}
<table style="width: 100%;"><tr style="vertical-align: top;"><td style="width: 75%;">
<form action="" method="POST">
<table class="ietf-table" style="width: 100%;">
<tr><th>Edit protocol write-up</th></tr>
{% if form.message %}
<tr><td class="message message-{{ form.message.type }}">
{{ form.message.value }}
</td></tr>
{% endif %}
<tr><td>
<textarea name="writeup" style="border: 1px solid #cccccc; width: 100%; height: 15em;">{{ form.get_writeup }}</textarea></td></tr>
</table>
<input type="submit" name="change_writeup" value="Change write-up" />
</form>
</td><td style="width: 25%;">
<form action="" method="POST" enctype="multipart/form-data">
<table class="ietf-table" style="width: 100%;">
<tr><th>Upload a new protocol write-up</th></tr>
<tr><td>
<p>Replace the current write-up with the contents of a plain ascii file:</p>
<input type="file" name="uploaded_writeup" /></td></tr>
</table>
<input type="submit" name="upload_writeup" value="Upload write-up" />
</form>
</td></tr></table>
{% else %}
<table class="ietf-table" style="width: 100%;">
<tr><th>Edit protocol write-up</th></tr>
<tr><td>
<p>
You can not edit or upload the protocol write-up for {{ doc }} cause the draft is not on "WG Consensus: Waiting for Write-Up" state.
</p>
<p>
Please contact with the {{ wg }} Working Group chair.
</p>
</td></tr>
</table>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,60 @@
{% extends "wginfo/wg_base.html" %}
{% block wg_titledetail %}Delegates{% endblock %}
{% block wg_content %}
<div class="wg-chair-management">
<h2>Manage delegates</h2>
<p>
Sometimes, a WG has one (or more) WG Secretaries, in addition to the WG Chairs.
This page lets the WG Chairs delegate the authority to do updates to the WG state of WG documents in the datatracker.
</p>
<p>
You may at most delegate the datatracker update rights to {{ max_delegates }} persons at any given time.
</p>
<table style="width: 100%;">
<tr style="vertical-align: top;"><td>
{% if delegates %}
<form action="" method="POST">
<table class="ietf-table" style="width: 100%">
<tr><th>Remove</th><th style="Width: 100%">Delegate name</th></tr>
{% for delegate in delegates %}
<tr class="{% cycle "oddrow" "evenrow" %}"><td><input type="checkbox" name="delete" value="{{ delegate.pk }}" /></td><td>{{ delegate.person }}</td></tr>
{% endfor %}
</table>
<input type="submit" value="Remove delegate(s)" name="remove" />
</form>
{% else %}
No delegates
{% endif %}
</td>
<td>
<table class="ietf-table" style="width: 100%;">
<tr><th>Add new delegate</th></tr>
{% if add_form.message %}
<tr><td class="message message-{{ add_form.message.type }}">
{{ add_form.message.value }}
</td></tr>
{% endif %}
<tr><td>
{% if can_add %}
<form action="" method="POST">
{{ add_form.as_p }}
<p>
<input type="submit" value="{% if add_form.submit_msg %}{{ add_form.submit_msg }}{% else %}Add delegate{% endif %}" name="add" />
{% if add_form.can_cancel %}<a href="">No! I don't want to continue</a>{% endif %}
</p>
</form>
{% else %}
You can only assign {{ max_delegates }} delegates. Please remove delegates to add a new one.
{% endif %}
</td></tr>
</table>
</td></tr>
</table>
</div>
{% endblock %}

View file

@ -0,0 +1,165 @@
{% extends "wginfo/wg_base.html" %}
{% block wg_titledetail %}Manage Workflow{% endblock %}
{% block pagehead %}
{{ block.super }}
<script type="text/javascript" src="/js/lib/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/js/yui/yui-20100305.js"></script>
<script type="text/javascript" src="/js/base.js"></script>
{% endblock pagehead %}
{% block wg_content %}
<div class="wg-workflow-management">
<h2>Edit workflow</h2>
<div id="mytabs" class="yui-navset">
<ul class="yui-nav">
<li class="selected"><a href="#info"><em>Info</em></a></li>
<li><a href="#states"><em>Select states</em></a></li>
<li><a href="#transitions"><em>Edit transitions</em></a></li>
<li><a href="#tags"><em>Select Annotation Tags</em></a></li>
</ul>
<div class="yui-content">
<div id="info">
<table style="width: 100%;"><tr style="vertical-align: top;"><td>
<table class="ietf-table" style="width: 100%">
<tr>
<th>States used in {{ wg }} Working Group</th>
</tr>
{% for state in states %}
<tr class="{% cycle "oddrow" "evenrow" %}">
<td>{{ state.name }}</td>
</tr>
{% endfor %}
</table><br />
<table class="ietf-table" style="width: 100%;">
<tr>
<th>Annotation tags used in {{ wg }} Working Group</th>
</tr>
{% for tag in tags %}
<tr class="{% cycle "oddrow" "evenrow" %}">
<td>{{ tag.name }}</td>
</tr>
{% endfor %}
</table>
</td><td>
<table class="ietf-table" style="width: 100%;">
<tr>
<th>Transition name</th><th>Initial states</th><th>Destination state</th>
</tr>
{% for transition in workflow.transitions.all %}
<tr class="{% cycle "oddrow" "evenrow" %}">
<td>
{{ transition.name }}
</td>
<td>
{% for state in transition.states.all %}
{{state.name }}{% if not forloop.last %}<br />{% endif %}
{% endfor %}
</td>
<td>
{{ transition.destination.name }}
</td>
</tr>
{% endfor %}
{% if not workflow.transitions.all.count %}
<tr class="oddrow"><td colspan="3">There are no transitions defined so any state change is allowed</td></tr>
{% endif %}
</table>
</td></tr></table>
</div>
<div id="states">
<p>
Please note that the states you can not uncheck are needed in all IETF WGs.
</p>
<p>
You can see the default Working Group I-D State Diagram in <a href="http://tools.ietf.org/html/rfc6174#section-4.1">Section 4.1 of RFC6174</a>
</p>
<form action="#info" method="POST">
<table class="ietf-table">
<tr>
<th>Used in {{ wg }}</th><th>Available states</th><th>Definition</th>
</tr>
{% for state in default_states %}
<tr class="{% cycle "oddrow" "evenrow" %}" style="vertical-align: top;">
<td><input type="checkbox" id="id_states_{{ state.pk }}" name="states" value="{{ state.pk }}" {% if state.used %}checked="checked" {% endif %}{% if state.freeze %} disabled="disabled"{% endif %}/></td>
<td><label for="id_states_{{ state.pk }}">{{ state.name }}</label></td>
<td>
<div class="statedefinition" style="height: 1em; overflow: hidden;">
<pre style="margin-top: 0px;"><a class="showDefinition" href="#">[+]</a><a class="hideDefinition" style="display: none;" href="#">[-]</a> {{ state.statedescription_set.all.0.definition|safe }}</pre>
</div>
</td>
</tr>
{% endfor %}
</table>
<input type="submit" name="update_states" value="Update states" />
</form>
</div>
<div id="transitions">
<p>
You can see the default Working Group I-D State Diagram in <a href="http://tools.ietf.org/html/rfc6174#section-4.1">Section 4.1 of RFC6174</a>
</p>
<form action="#transitions" method="POST">
<table class="ietf-table">
<tr>
<th>Delete</th><th>Transition name</th><th>Initial states</th><th>Destination state</th>
</tr>
{{ formset.as_table }}
</table>
<input type="submit" name="update_transitions" value="Update transitions" />
</form>
</div>
<div id="tags">
<form action="#info" method="POST">
<table class="ietf-table">
<tr>
<th>Used in {{ wg }}</th><th>Available annotation tags</th>
</tr>
{% for tag in default_tags %}
<tr class="{% cycle "oddrow" "evenrow" %}">
<td><input type="checkbox" id="id_tags_{{ tag.pk }}" name="tags" value="{{ tag.pk }}" {% if tag.used %}checked="checked" {% endif %}/></td>
<td><label for="id_tags_{{ tag.pk }}">{{ tag.name }}</label></td>
</tr>
{% endfor %}
</table>
<input type="submit" name="update_tags" value="Update tags" />
</form>
</div>
</div>
</div>
<script type="text/javascript">
//<![CDATA[
var tabView = new YAHOO.widget.TabView('mytabs');
var url = location.href.split('#');
if (url[1]) {
url[1] = "#"+url[1];
var tabs = tabView.get('tabs');
for (var i = 0; i < tabs.length; i++) {
if (url[1].indexOf(tabs[i].get('href')) == 0) {
tabView.set('activeIndex', i);
break;
}
}
}
jQuery('.showDefinition').click(function() {
jQuery(this).parent().parent().css('height', 'auto');
jQuery(this).hide();
jQuery(this).next().show();
return false;
});
jQuery('.hideDefinition').click(function() {
jQuery(this).parent().parent().css('height', '1em');
jQuery(this).hide();
jQuery(this).prev().show();
return false;
});
//]]>
</script>
{% endblock %}

View file

@ -0,0 +1,28 @@
{% if shepherd %}
<p>
The shepherd you are trying to designate does not have a personal user-id and password to log-on to the Datatracker.
</p>
<p>
An email will be sent to the following addresses to inform that
the person you have designated to be one of your document shepherds
currently does not have login credentials for the Datatracker
and should contact the Secretariat to obtain their own user-id and
password for the Datatracker.
</p>
{% else %}
<p>
The delegate you are trying to designate does not have a personal user-id and password to log-on to the Datatracker.
</p>
<p>
An email will be sent to the following addresses to inform that
the person you have designated to be one of your delegates
currently does not have login credentials for the Datatracker
and should contact the Secretariat to obtain their own user-id and
password for the Datatracker.
</p>
{% endif %}
<ul>
{% for email in email_list %}
<li>{{ email }}</li>
{% endfor %}
</ul>

View file

@ -0,0 +1,9 @@
{{ chair }} as a WG Chair of {{ wg }} wants to add you as a {{ wg }} {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}.
You don't have an user/password to log into the datatracker so you must contact
the Secretariat at iesg-secretary@ietf.org in order to get your credentials.
When you get your credentials, please inform {{ chair }} at
{{ chair.email.1 }} so he/she can finish the designate process.
Thank you.

View file

@ -0,0 +1,14 @@
{{ chair }} as a WG Chair of {{ wg }} wants to add a person with email
{{ delegate_email }} as a {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}.
This person don't have an user/password to log into the datatracker so
an email has been seent to {{ delegate_email }} in order to he/she contacs the
Secretariat to request his/her credentials.
{% if delegate_persons %}
Please, note that the following persons with {{ delegate_email }} email address
already exists in the system but they can not log in.
{% for person in delegate_persons %}
{{ person.pk }} - {{ person }}
{% endfor %}
{% endif %}

View file

@ -0,0 +1,11 @@
{{ chair }} as a WG Chair of {{ wg }} wants to add a person with email
{{ delegate_email }} as a {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}.
This person don't have an user/password to log into the datatracker so
an email has been seent to {{ delegate_email }} in order to he/she contacs the
Secretariat to request his/her credentials.
When he/she gets her credentials then he/she will send an email to
{{ chair }} at {{ chair.email.1 }}.
{{ chair }} could then assign this person as {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}.

View file

@ -0,0 +1,17 @@
{% load wgchairs_tags %}
<tr class="{% cycle oddrow,evenrow %}">
<td class="title">
<a href="{% url doc_view doc.filename %}">{{ doc.title }}</a>
</td>
<td class="shepherd">
<a href="{% url doc_managing_shepherd wg.group_acronym.acronym doc %}">Change shepherd</a>
</td>
<td class="writeup">
{% writeup doc %}
<a href="{% url doc_managing_writeup wg.group_acronym.acronym doc %}" style="display: block;" href="">[Edit]</a>
</td>
<td class="writeup_date">
{% writeupdate doc %}
</td>
</tr>

View file

@ -0,0 +1,122 @@
{% 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 %}
{% block wg_titledetail %}Documents{% endblock %}
{% block pagehead %}
{{ block.super }}
<script type="text/javascript" src="/js/lib/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/js/yui/yui-20100305.js"></script>
<script type="text/javascript" src="/js/base.js"></script>
{% endblock pagehead %}
{% block wg_content %}
<h2>Documents by its shepherd</h2>
<div id="mytabs" class="yui-navset">
<ul class="yui-nav">
<li class="selected"><a href="#noshepherd"><em>Without shepherd</em></a></li>
<li><a href="#mydocs"><em>Shepherded by me</em></a></li>
<li><a href="#othershepherds"><em>Shepherded by others</em></a></li>
</ul>
<div class="yui-content">
<div id="noshepherd">
<table class="ietf-table ietf-doctable" style="margin-top:16px; width: 100%;">
<tr>
<th class="title">Document</th>
<th class="shepherd">Change shepherd</th>
<th class="writeup">Protocol write-up</th>
<th class="writeup_date">Protocol write-up last update</th>
</tr>
{% for doc in no_shepherd %}
{% include "wgchairs/shepherd_document_row.html" %}
{% endfor %}
</table>
</div>
<div id="mydocs">
<table class="ietf-table ietf-doctable" style="margin-top:16px; width: 100%;">
<tr>
<th class="title">Document</th>
<th class="status">Status</th>
<th class="writeup">Protocol write-up</th>
<th class="writeup_date">Protocol write-up last update</th>
</tr>
{% for doc in my_documents %}
{% include "wgchairs/shepherd_document_row.html" %}
{% endfor %}
</table>
</div>
<div id="othershepherds">
{% regroup other_shepherds by shepherd as regrouped %}
{% for documents in regrouped %}
<h3 style="margin-bottom: 0px;">{{ documents.grouper }}</h3>
<table class="ietf-table ietf-doctable" style="width: 100%;">
<tr>
<th class="title">Document</th>
<th class="status">Status</th>
<th class="writeup">Protocol write-up</th>
<th class="writeup_date">Protocol write-up last update</th>
</tr>
{% for doc in documents.list %}
{% include "wgchairs/shepherd_document_row.html" %}
{% endfor %}
</table>
{% endfor %}
</div>
<script type="text/javascript">
//<![CDATA[
var tabView = new YAHOO.widget.TabView('mytabs');
var url = location.href.split('#');
if (url[1]) {
url[1] = "#"+url[1];
var tabs = tabView.get('tabs');
for (var i = 0; i < tabs.length; i++) {
if (url[1].indexOf(tabs[i].get('href')) == 0) {
tabView.set('activeIndex', i);
break;
}
}
}
//]]>
</script>
{% endblock wg_content %}

View file

@ -0,0 +1,23 @@
{% if can_manage_workflow %}
{% ifequal selected "manage_workflow" %}
<span class="selected">Manage workflow</span>
{% else %}
<a href="{% url manage_workflow wg.group_acronym.acronym %}">Manage workflow</a>
{% endifequal %} |
{% endif %}
{% if can_manage_delegates %}
{% ifequal selected "manage_delegates" %}
<span class="selected">Manage delegations</span>
{% else %}
<a href="{% url manage_delegates wg.group_acronym.acronym %}">Manage delegations</a>
{% endifequal %} |
{% endif %}
{% if can_manage_shepherds %}
{% ifequal selected "manage_shepherds" %}
<span class="selected">Manage shepherds</span>
{% else %}
<a href="{% url manage_shepherds wg.group_acronym.acronym %}">Manage shepherds</a>
{% endifequal %} |
{% endif %}

View file

@ -32,7 +32,7 @@ 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 %}
{% load ietf_filters wgchairs_tags %}
{% block title %}{{wg.group_acronym.name}} ({{wg.group_acronym.acronym}}) - {% block wg_titledetail %}{% endblock %}{% endblock %}
{% block morecss %}
@ -58,6 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<div class="ietf-navset">
{% ifequal selected "documents" %}<span class="selected">Documents</span>{% else %}<a href="/wg/{{wg}}/">Documents</a>{% endifequal %} |
{% ifequal selected "charter" %}<span class="selected">Charter</span>{% else %}<a href="/wg/{{wg}}/charter/">Charter</a>{% endifequal %} |
{% wgchairs_admin_options wg %}
{% if wg.clean_email_archive|startswith:"http:" or wg.clean_email_archive|startswith:"ftp:" %}
<a href="{{ wg.clean_email_archive }}">List Archive &#187;</a> |
{% endif %}

View file

@ -58,7 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<tr class="header"><td colspan="7">{{doc_group.grouper}}s</td></tr>
{% for doc in doc_group.list %}
{% include "idrfc/search_result_row.html" %}
{% include "idrfc/search_result_row.html" %}
{% endfor %}
{% endfor %}

View file

@ -58,6 +58,7 @@ urlpatterns = patterns('',
(r'^wg/', include('ietf.wginfo.urls')),
(r'^cookies/', include('ietf.cookies.urls')),
(r'^submit/', include('ietf.submit.urls')),
(r'^streams/', include('ietf.ietfworkflows.urls')),
(r'^$', 'ietf.idrfc.views.main'),
(r'^admin/doc/', include('django.contrib.admindocs.urls')),

View file

90
ietf/wgchairs/accounts.py Normal file
View file

@ -0,0 +1,90 @@
def is_secretariat(user):
if not user or not user.is_authenticated():
return False
return bool(user.groups.filter(name='Secretariat'))
def is_area_director_for_group(person, group):
return bool(group.area.area.areadirector_set.filter(person=person).count())
def is_group_chair(person, group):
if group.chairs().filter(person=person):
return True
return False
def is_group_delegate(person, group):
return bool(group.wgdelegate_set.filter(person=person).count())
def is_document_shepherd(person, document):
return person == document.shepherd
def get_person_for_user(user):
try:
return user.get_profile().person()
except:
return None
def can_do_wg_workflow_in_group(user, group):
person = get_person_for_user(user)
if not person:
return False
return (is_secretariat(user) or is_group_chair(person, group))
def can_do_wg_workflow_in_document(user, document):
person = get_person_for_user(user)
if not person or not document.group:
return False
return (is_secretariat(user) or can_do_wg_workflow_in_group(document.group.ietfwg))
def can_manage_workflow_in_group(user, group):
person = get_person_for_user(user)
if not person:
return False
return (is_secretariat(user) or is_group_chair(person, group))
def can_manage_delegates_in_group(user, group):
person = get_person_for_user(user)
if not person:
return False
return (is_secretariat(user) or is_group_chair(person, group))
def can_manage_shepherds_in_group(user, group):
person = get_person_for_user(user)
if not person:
return False
return (is_secretariat(user) or is_group_chair(person, group))
def can_manage_shepherd_of_a_document(user, document):
person = get_person_for_user(user)
if not person or not document.group:
return False
return can_manage_shepherds_in_group(user, document.group.ietfwg)
def can_manage_writeup_of_a_document_no_state(user, document):
person = get_person_for_user(user)
if not person or not document.group:
return False
group = document.group.ietfwg
return (is_secretariat(user) or
is_group_chair(person, group) or
is_area_director_for_group(person, group) or
is_group_delegate(person, group))
def can_manage_writeup_of_a_document(user, document):
person = get_person_for_user(user)
if not person or not document.group:
return False
return (can_manage_writeup_of_a_document_no_state(user, document) or
is_document_shepherd(person, document))

388
ietf/wgchairs/forms.py Normal file
View file

@ -0,0 +1,388 @@
from django import forms
from django.conf import settings
from django.core.mail import EmailMessage
from django.forms.models import BaseModelFormSet
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from ietf.wgchairs.models import WGDelegate, ProtoWriteUp
from ietf.wgchairs.accounts import get_person_for_user
from ietf.ietfworkflows.constants import REQUIRED_STATES
from ietf.ietfworkflows.utils import (get_default_workflow_for_wg, get_workflow_for_wg,
update_tags, FOLLOWUP_TAG, get_state_by_name)
from ietf.idtracker.models import PersonOrOrgInfo
from workflows.models import Transition
class RelatedWGForm(forms.Form):
can_cancel = False
def __init__(self, *args, **kwargs):
self.wg = kwargs.pop('wg', None)
self.user = kwargs.pop('user', None)
self.message = {}
super(RelatedWGForm, self).__init__(*args, **kwargs)
def get_message(self):
return self.message
def set_message(self, msg_type, msg_value):
self.message = {'type': msg_type,
'value': msg_value,
}
class TagForm(RelatedWGForm):
tags = forms.ModelMultipleChoiceField(get_default_workflow_for_wg().annotation_tags.all(),
widget=forms.CheckboxSelectMultiple, required=False)
def save(self):
workflow = get_workflow_for_wg(self.wg)
workflow.selected_tags.clear()
for tag in self.cleaned_data['tags']:
workflow.selected_tags.add(tag)
return workflow
class StateForm(RelatedWGForm):
states = forms.ModelMultipleChoiceField(get_default_workflow_for_wg().states.all(),
widget=forms.CheckboxSelectMultiple, required=False)
def update_transitions(self, workflow):
for transition in workflow.transitions.all():
if not workflow.selected_states.filter(pk=transition.destination.pk).count():
transition.delete()
continue
for state in transition.states.all():
if not workflow.selected_states.filter(pk=state.pk).count():
transition.states.remove(state)
if not transition.states.count():
transition.delete()
continue
def save(self):
workflow = get_workflow_for_wg(self.wg)
workflow.selected_states.clear()
for state in self.cleaned_data['states']:
workflow.selected_states.add(state)
for name in REQUIRED_STATES:
rstate = get_state_by_name(name)
if rstate:
workflow.selected_states.add(rstate)
self.update_transitions(workflow)
return workflow
class DeleteTransitionForm(RelatedWGForm):
transitions = forms.ModelMultipleChoiceField(Transition.objects.all(),
widget=forms.CheckboxSelectMultiple)
def __init__(self, *args, **kwargs):
super(DeleteTransitionForm, self).__init__(*args, **kwargs)
workflow = get_workflow_for_wg(self.wg)
self.fields['transitions'].queryset = self.fields['transitions'].queryset.filter(workflow=workflow)
def save(self):
for transition in self.cleaned_data['transitions']:
transition.delete()
class TransitionForm(forms.ModelForm):
states = forms.ModelMultipleChoiceField(get_default_workflow_for_wg().states.all())
class Meta:
model = Transition
fields = ('DELETE', 'name', 'states', 'destination', )
def __init__(self, *args, **kwargs):
self.wg = kwargs.pop('wg', None)
self.user = kwargs.pop('user', None)
super(TransitionForm, self).__init__(*args, **kwargs)
workflow = get_workflow_for_wg(self.wg)
self.fields['states'].queryset = workflow.selected_states.all()
self.fields['destination'].queryset = workflow.selected_states.all()
self.fields['destination'].required = True
if self.instance.pk:
self.fields['states'].initial = [i.pk for i in self.instance.states.all()]
self.instance.workflow = workflow
def as_row(self):
return self._html_output(u'<td>%(errors)s%(field)s%(help_text)s</td>', u'<td colspan="2">%s</td>', '</td>', u'<br />%s', False)
def save(self, *args, **kwargs):
instance = super(TransitionForm, self).save(*args, **kwargs)
for state in self.cleaned_data['states']:
state.transitions.add(instance)
class TransitionFormSet(BaseModelFormSet):
form = TransitionForm
can_delete = True
extra = 2
max_num = 0
can_order = False
model = Transition
def __init__(self, *args, **kwargs):
self.wg = kwargs.pop('wg', None)
self.user = kwargs.pop('user', None)
super(TransitionFormSet, self).__init__(*args, **kwargs)
def _construct_form(self, i, **kwargs):
kwargs = kwargs or {}
kwargs.update({'wg': self.wg, 'user': self.user})
return super(TransitionFormSet, self)._construct_form(i, **kwargs)
def as_table(self):
html = u''
csscl = 'oddrow'
for form in self.forms:
html += u'<tr class="%s">' % csscl
html += form.as_row()
html += u'</tr>'
if csscl == 'oddrow':
csscl = 'evenrow'
else:
csscl = 'oddrow'
return mark_safe(u'\n'.join([unicode(self.management_form), html]))
def workflow_form_factory(request, wg, user):
if request.POST.get('update_transitions', None):
return TransitionFormSet(wg=wg, user=user, data=request.POST)
elif request.POST.get('update_states', None):
return StateForm(wg=wg, user=user, data=request.POST)
return TagForm(wg=wg, user=user, data=request.POST)
class RemoveDelegateForm(RelatedWGForm):
delete = forms.MultipleChoiceField()
def __init__(self, *args, **kwargs):
super(RemoveDelegateForm, self).__init__(*args, **kwargs)
self.fields['delete'].choices = [(i.pk, i.pk) for i in self.wg.wgdelegate_set.all()]
def save(self):
delegates = self.cleaned_data.get('delete')
WGDelegate.objects.filter(pk__in=delegates).delete()
self.set_message('success', 'Delegates removed')
class AddDelegateForm(RelatedWGForm):
email = forms.EmailField()
form_type = forms.CharField(widget=forms.HiddenInput, initial='single')
def __init__(self, *args, **kwargs):
self.shepherd = kwargs.pop('shepherd', False)
super(AddDelegateForm, self).__init__(*args, **kwargs)
self.next_form = self
def get_next_form(self):
return self.next_form
def get_person(self, email):
persons = PersonOrOrgInfo.objects.filter(emailaddress__address=email, iesglogin__isnull=False).distinct()
if not persons:
raise PersonOrOrgInfo.DoesNotExist
if len(persons) > 1:
raise PersonOrOrgInfo.MultipleObjectsReturned
return persons[0]
def save(self):
email = self.cleaned_data.get('email')
try:
person = self.get_person(email)
except PersonOrOrgInfo.DoesNotExist:
self.next_form = NotExistDelegateForm(wg=self.wg, user=self.user, email=email, shepherd=self.shepherd)
self.next_form.set_message('doesnotexist', 'There is no user with this email allowed to login to the system')
return
except PersonOrOrgInfo.MultipleObjectsReturned:
self.next_form = MultipleDelegateForm(wg=self.wg, user=self.user, email=email, shepherd=self.shepherd)
self.next_form.set_message('multiple', 'There are multiple users with this email in the system')
return
if self.shepherd:
self.assign_shepherd(person)
else:
self.create_delegate(person)
def assign_shepherd(self, person):
self.shepherd.shepherd = person
self.shepherd.save()
self.next_form = AddDelegateForm(wg=self.wg, user=self.user, shepherd=self.shepherd)
self.next_form.set_message('success', 'Shepherd assigned successfully')
def create_delegate(self, person):
(delegate, created) = WGDelegate.objects.get_or_create(wg=self.wg,
person=person)
if not created:
self.set_message('error', 'The email belongs to a person who is already a delegate')
else:
self.next_form = AddDelegateForm(wg=self.wg, user=self.user)
self.next_form.set_message('success', 'A new delegate has been added')
class MultipleDelegateForm(AddDelegateForm):
email = forms.EmailField(widget=forms.HiddenInput)
form_type = forms.CharField(widget=forms.HiddenInput, initial='multiple')
persons = forms.ChoiceField(widget=forms.RadioSelect, help_text='Please select one person from the list')
submit_msg = 'Designate as delegate'
def __init__(self, *args, **kwargs):
self.email = kwargs.pop('email', None)
super(MultipleDelegateForm, self).__init__(*args, **kwargs)
if not self.email:
self.email = self.data.get('email', None)
self.fields['email'].initial = self.email
self.fields['persons'].choices = [(i.pk, unicode(i)) for i in PersonOrOrgInfo.objects.filter(emailaddress__address=self.email, iesglogin__isnull=False).distinct().order_by('first_name')]
def save(self):
person_id = self.cleaned_data.get('persons')
person = PersonOrOrgInfo.objects.get(pk=person_id)
if self.shepherd:
self.assign_shepherd(person)
else:
self.create_delegate(person)
class NotExistDelegateForm(MultipleDelegateForm):
email = forms.EmailField(widget=forms.HiddenInput)
form_type = forms.CharField(widget=forms.HiddenInput, initial='notexist')
can_cancel = True
submit_msg = 'Send email to these addresses'
def __init__(self, *args, **kwargs):
super(NotExistDelegateForm, self).__init__(*args, **kwargs)
self.email_list = []
del(self.fields['persons'])
def get_email_list(self):
if self.email_list:
return self.email_list
email_list = [self.email]
email_list.append('IETF Secretariat <iesg-secretary@ietf.org>')
email_list += ['%s <%s>' % i.person.email() for i in self.wg.wgchair_set.all() if i.person.email()]
self.email_list = email_list
return email_list
def as_p(self):
email_list = self.get_email_list()
info = render_to_string('wgchairs/notexistdelegate.html', {'email_list': email_list, 'shepherd': self.shepherd})
return info + super(NotExistDelegateForm, self).as_p()
def send_email(self, email, template):
if self.shepherd:
subject = 'WG shepherd needs system credentials'
else:
subject = 'WG Delegate needs system credentials'
persons = PersonOrOrgInfo.objects.filter(emailaddress__address=self.email).distinct()
body = render_to_string(template,
{'chair': get_person_for_user(self.user),
'delegate_email': self.email,
'shepherd': self.shepherd,
'delegate_persons': persons,
'wg': self.wg,
})
mail = EmailMessage(subject=subject,
body=body,
to=email,
from_email=settings.DEFAULT_FROM_EMAIL)
mail.send()
def send_email_to_delegate(self, email):
self.send_email(email, 'wgchairs/notexistsdelegate_delegate_email.txt')
def send_email_to_secretariat(self, email):
self.send_email(email, 'wgchairs/notexistsdelegate_secretariat_email.txt')
def send_email_to_wgchairs(self, email):
self.send_email(email, 'wgchairs/notexistsdelegate_wgchairs_email.txt')
def save(self):
self.next_form = AddDelegateForm(wg=self.wg, user=self.user)
if settings.DEBUG:
self.next_form.set_message('warning', 'Email was not sent cause tool is in DEBUG mode')
else:
email_list = self.get_email_list()
self.send_email_to_delegate([email_list[0]])
self.send_email_to_secretariat([email_list[1]])
self.send_email_to_wgchairs(email_list[2:])
self.next_form.set_message('success', 'Email sent successfully')
def add_form_factory(request, wg, user, shepherd=False):
if request.method != 'POST' or request.POST.get('update_shepehrd'):
return AddDelegateForm(wg=wg, user=user, shepherd=shepherd)
if request.POST.get('form_type', None) == 'multiple':
return MultipleDelegateForm(wg=wg, user=user, data=request.POST.copy(), shepherd=shepherd)
elif request.POST.get('form_type', None) == 'notexist':
return NotExistDelegateForm(wg=wg, user=user, data=request.POST.copy(), shepherd=shepherd)
elif request.POST.get('form_type', None) == 'single':
return AddDelegateForm(wg=wg, user=user, data=request.POST.copy(), shepherd=shepherd)
return AddDelegateForm(wg=wg, user=user, shepherd=shepherd)
class WriteUpEditForm(RelatedWGForm):
writeup = forms.CharField(widget=forms.Textarea, required=False)
followup = forms.BooleanField(required=False)
comment = forms.CharField(widget=forms.Textarea, required=False)
def __init__(self, *args, **kwargs):
self.doc = kwargs.pop('doc', None)
self.doc_writeup = self.doc.protowriteup_set.all()
if self.doc_writeup.count():
self.doc_writeup = self.doc_writeup[0]
else:
self.doc_writeup = None
super(WriteUpEditForm, self).__init__(*args, **kwargs)
self.person = get_person_for_user(self.user)
def get_writeup(self):
return self.data.get('writeup', self.doc_writeup and self.doc_writeup.writeup or '')
def save(self):
if not self.doc_writeup:
self.doc_writeup = ProtoWriteUp.objects.create(
person=self.person,
draft=self.doc,
writeup=self.cleaned_data['writeup'])
else:
self.doc_writeup.writeup = self.cleaned_data['writeup']
self.doc_writeup.save()
if self.data.get('modify_tag', False):
followup = self.cleaned_data.get('followup', False)
comment = self.cleaned_data.get('comment', False)
try:
shepherd = self.doc.shepherd
except PersonOrOrgInfo.DoesNotExist:
shepherd = None
if shepherd:
extra_notify = ['%s <%s>' % shepherd.email()]
else:
extra_notify = []
if followup:
update_tags(self.doc, comment, self.person, set_tags=[FOLLOWUP_TAG], extra_notify=extra_notify)
else:
update_tags(self.doc, comment, self.person, reset_tags=[FOLLOWUP_TAG], extra_notify=extra_notify)
return self.doc_writeup
def is_valid(self):
if self.data.get('confirm', False) and self.data.get('modify_tag', False):
self.fields['comment'].required = True
else:
self.fields['comment'].required = False
return super(WriteUpEditForm, self).is_valid()

View file

@ -0,0 +1,110 @@
from south.db import db
from django.db import models
from ietf.wgchairs.models import *
class Migration:
def forwards(self, orm):
# Adding model 'WGDelegate'
db.create_table('wgchairs_wgdelegate', (
('id', orm['wgchairs.WGDelegate:id']),
('person', orm['wgchairs.WGDelegate:person']),
('wg', orm['wgchairs.WGDelegate:wg']),
))
db.send_create_signal('wgchairs', ['WGDelegate'])
def backwards(self, orm):
# Deleting model 'WGDelegate'
db.delete_table('wgchairs_wgdelegate')
models = {
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.area': {
'Meta': {'db_table': "'areas'"},
'area_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'extra_email_addresses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'last_modified_date': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaStatus']"})
},
'idtracker.areadirector': {
'Meta': {'db_table': "'area_directors'"},
'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']", 'null': 'True', 'db_column': "'area_acronym_id'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.areastatus': {
'Meta': {'db_table': "'area_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.ietfwg': {
'Meta': {'db_table': "'groups_ietf'"},
'area_director': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaDirector']", 'null': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'dormant_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '60', 'blank': 'True'}),
'email_archive': ('django.db.models.fields.CharField', [], {'max_length': '95', 'blank': 'True'}),
'email_keyword': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'email_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
'group_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'group_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGType']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'meeting_scheduled': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'meeting_scheduled_old': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGStatus']"})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'idtracker.wgstatus': {
'Meta': {'db_table': "'g_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.wgtype': {
'Meta': {'db_table': "'g_type'"},
'group_type_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'group_type'"})
},
'wgchairs.wgdelegate': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'wg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"})
}
}
complete_apps = ['wgchairs']

View file

@ -0,0 +1,163 @@
from south.db import db
from django.db import models
from ietf.wgchairs.models import *
class Migration:
def forwards(self, orm):
# Adding model 'ProtoWriteUp'
db.create_table('wgchairs_protowriteup', (
('id', orm['wgchairs.protowriteup:id']),
('person', orm['wgchairs.protowriteup:person']),
('draft', orm['wgchairs.protowriteup:draft']),
('date', orm['wgchairs.protowriteup:date']),
('writeup', orm['wgchairs.protowriteup:writeup']),
))
db.send_create_signal('wgchairs', ['ProtoWriteUp'])
def backwards(self, orm):
# Deleting model 'ProtoWriteUp'
db.delete_table('wgchairs_protowriteup')
models = {
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.area': {
'Meta': {'db_table': "'areas'"},
'area_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'extra_email_addresses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'last_modified_date': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaStatus']"})
},
'idtracker.areadirector': {
'Meta': {'db_table': "'area_directors'"},
'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']", 'null': 'True', 'db_column': "'area_acronym_id'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.areastatus': {
'Meta': {'db_table': "'area_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idintendedstatus': {
'Meta': {'db_table': "'id_intended_status'"},
'intended_status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idstatus': {
'Meta': {'db_table': "'id_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.ietfwg': {
'Meta': {'db_table': "'groups_ietf'"},
'area_director': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaDirector']", 'null': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'dormant_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '60', 'blank': 'True'}),
'email_archive': ('django.db.models.fields.CharField', [], {'max_length': '95', 'blank': 'True'}),
'email_keyword': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'email_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
'group_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'group_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGType']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'meeting_scheduled': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'meeting_scheduled_old': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGStatus']"})
},
'idtracker.internetdraft': {
'Meta': {'db_table': "'internet_drafts'"},
'abstract': ('django.db.models.fields.TextField', [], {}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_discussion_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'dunn_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'expired_tombstone': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'extension_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Acronym']", 'db_column': "'group_acronym_id'"}),
'id_document_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id_document_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDIntendedStatus']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_changes': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True'}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'replaced_by': ('django.db.models.fields.related.ForeignKey', ["orm['idtracker.InternetDraft']"], {'related_name': "'replaces_set'", 'null': 'True', 'db_column': "'replaced_by'", 'blank': 'True'}),
'review_by_rfc_editor': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'revision_date': ('django.db.models.fields.DateField', [], {}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDStatus']"}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'id_document_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {}),
'wgreturn_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'idtracker.wgstatus': {
'Meta': {'db_table': "'g_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.wgtype': {
'Meta': {'db_table': "'g_type'"},
'group_type_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'group_type'"})
},
'wgchairs.protowriteup': {
'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now()'}),
'draft': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.InternetDraft']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'writeup': ('django.db.models.fields.TextField', [], {})
},
'wgchairs.wgdelegate': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'wg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"})
}
}
complete_apps = ['wgchairs']

View file

45
ietf/wgchairs/models.py Normal file
View file

@ -0,0 +1,45 @@
import datetime
from django.db import models
from ietf.idtracker.models import (IETFWG, PersonOrOrgInfo,
InternetDraft)
class WGDelegate(models.Model):
person = models.ForeignKey(
PersonOrOrgInfo,
)
wg = models.ForeignKey(IETFWG)
def __unicode__(self):
return "%s" % self.person
class Meta:
verbose_name = "WG Delegate"
class ProtoWriteUp(models.Model):
person = models.ForeignKey(
PersonOrOrgInfo,
blank=False,
null=False,
)
draft = models.ForeignKey(
InternetDraft,
blank=False,
null=False,
)
date = models.DateTimeField(
default=datetime.datetime.now(),
blank=False,
null=False,
)
writeup = models.TextField(
blank=False,
null=False,
)

View file

View file

@ -0,0 +1,46 @@
from django import template
from ietf.ietfworkflows.utils import get_state_for_draft
from ietf.wgchairs.accounts import (can_manage_workflow_in_group,
can_manage_delegates_in_group,
can_manage_shepherds_in_group)
register = template.Library()
@register.inclusion_tag('wgchairs/wgchairs_admin_options.html', takes_context=True)
def wgchairs_admin_options(context, wg):
request = context.get('request', None)
user = request and request.user
return {'user': user,
'can_manage_delegates': can_manage_delegates_in_group(user, wg),
'can_manage_workflow': can_manage_workflow_in_group(user, wg),
'can_manage_shepherds': can_manage_shepherds_in_group(user, wg),
'wg': wg,
'selected': context.get('selected', None),
}
@register.simple_tag
def writeup(doc):
writeup = doc.protowriteup_set.all()
if not writeup.count():
return ''
else:
return writeup[0].writeup
@register.simple_tag
def writeupdate(doc):
writeup = doc.protowriteup_set.all()
if not writeup.count():
return ''
else:
return writeup[0].date
@register.inclusion_tag('wgchairs/draft_state.html', takes_context=True)
def show_state(context, doc):
return {'doc': doc,
'state': get_state_for_draft(doc),
}

11
ietf/wgchairs/urls.py Normal file
View file

@ -0,0 +1,11 @@
# Copyright The IETF Trust 2008, All Rights Reserved
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('ietf.wgchairs.views',
url(r'^workflows/$', 'manage_workflow', name='manage_workflow'),
url(r'^delegates/$', 'manage_delegates', name='manage_delegates'),
url(r'^shepherds/$', 'wg_shepherd_documents', name='manage_shepherds'),
url(r'^shepherds/(?P<name>[^/]+)/$', 'managing_shepherd', name='doc_managing_shepherd'),
url(r'^shepherds/(?P<name>[^/]+)/writeup/$', 'managing_writeup', name='doc_managing_writeup'),
)

214
ietf/wgchairs/views.py Normal file
View file

@ -0,0 +1,214 @@
from django.conf import settings
from ietf.idtracker.models import IETFWG, InternetDraft
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from django.http import HttpResponseForbidden, Http404
from ietf.idrfc.views_search import SearchForm, search_query
from ietf.wgchairs.forms import (RemoveDelegateForm, add_form_factory,
workflow_form_factory, TransitionFormSet,
WriteUpEditForm)
from ietf.wgchairs.accounts import (can_manage_delegates_in_group, get_person_for_user,
can_manage_shepherds_in_group,
can_manage_workflow_in_group,
can_manage_shepherd_of_a_document,
can_manage_writeup_of_a_document,
can_manage_writeup_of_a_document_no_state,
)
from ietf.ietfworkflows.constants import REQUIRED_STATES
from ietf.ietfworkflows.utils import (get_workflow_for_wg,
get_default_workflow_for_wg,
get_state_by_name,
get_annotation_tags_for_draft,
get_state_for_draft, WAITING_WRITEUP,
FOLLOWUP_TAG)
def manage_delegates(request, acronym):
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
user = request.user
if not can_manage_delegates_in_group(user, wg):
return HttpResponseForbidden('You have no permission to access this view')
delegates = wg.wgdelegate_set.all()
add_form = add_form_factory(request, wg, user)
if request.method == 'POST':
if request.POST.get('remove', None):
form = RemoveDelegateForm(wg=wg, data=request.POST.copy())
if form.is_valid():
form.save()
elif add_form.is_valid():
add_form.save()
add_form = add_form.get_next_form()
max_delegates = getattr(settings, 'MAX_WG_DELEGATES', 3)
return render_to_response('wgchairs/manage_delegates.html',
{'wg': wg,
'delegates': delegates,
'selected': 'manage_delegates',
'can_add': delegates.count() < max_delegates,
'max_delegates': max_delegates,
'add_form': add_form,
}, RequestContext(request))
def manage_workflow(request, acronym):
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
user = request.user
if not can_manage_workflow_in_group(user, wg):
return HttpResponseForbidden('You have no permission to access this view')
workflow = get_workflow_for_wg(wg)
default_workflow = get_default_workflow_for_wg()
formset = None
if request.method == 'POST':
form = workflow_form_factory(request, wg=wg, user=user)
if form.is_valid():
form.save()
elif isinstance(form, TransitionFormSet):
formset = form
tags = workflow.selected_tags.all()
default_tags = default_workflow.annotation_tags.all()
states = workflow.selected_states.all().order_by('statedescription__order')
default_states = default_workflow.states.all().order_by('statedescription__order')
for i in default_states:
if states.filter(name=i.name).count() == 1:
i.used = True
if i.name in REQUIRED_STATES:
i.freeze = True
for i in default_tags:
if tags.filter(name=i.name).count() == 1:
i.used = True
if not formset:
formset = TransitionFormSet(queryset=workflow.transitions.all(), user=user, wg=wg)
return render_to_response('wgchairs/manage_workflow.html',
{'wg': wg,
'workflow': workflow,
'default_workflow': default_workflow,
'states': states,
'tags': tags,
'default_states': default_states,
'default_tags': default_tags,
'formset': formset,
'selected': 'manage_workflow',
}, RequestContext(request))
def managing_shepherd(request, acronym, name):
"""
View for managing the assigned shepherd of a document.
"""
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
user = request.user
person = get_person_for_user(user)
if not can_manage_shepherds_in_group(user, wg):
return HttpResponseForbidden('You have no permission to access this view')
doc = get_object_or_404(InternetDraft, filename=name)
if not can_manage_shepherd_of_a_document(user, doc):
raise Http404
add_form = add_form_factory(request, wg, user, shepherd=doc)
if request.method == 'POST':
if request.POST.get('remove_shepherd'):
doc.shepherd = None
doc.save()
elif request.POST.get('setme'):
doc.shepherd = person
doc.save()
elif add_form.is_valid():
add_form.save()
add_form = add_form.get_next_form()
return render_to_response('wgchairs/edit_management_shepherd.html',
dict(doc=doc,
form=add_form,
user=user,
selected='manage_shepherds',
wg=wg,
),
context_instance=RequestContext(request))
def wg_shepherd_documents(request, acronym):
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
user = request.user
if not can_manage_shepherds_in_group(user, wg):
return HttpResponseForbidden('You have no permission to access this view')
current_person = get_person_for_user(user)
form = SearchForm({'by': 'group', 'group': str(wg.group_acronym.acronym),
'activeDrafts': 'on'})
if not form.is_valid():
raise ValueError("form did not validate")
(docs, meta) = search_query(form.cleaned_data)
base_qs = InternetDraft.objects.filter(pk__in=[i.id._draft.pk for i in docs if i.id]).select_related('status')
documents_no_shepherd = base_qs.filter(shepherd__isnull=True)
documents_my = base_qs.filter(shepherd=current_person)
documents_other = base_qs.exclude(shepherd__isnull=True).exclude(shepherd__pk__in=[current_person.pk, 0])
context = {
'no_shepherd': documents_no_shepherd,
'my_documents': documents_my,
'other_shepherds': documents_other,
'selected': 'manage_shepherds',
'wg': wg,
}
return render_to_response('wgchairs/wg_shepherd_documents.html', context, RequestContext(request))
def managing_writeup(request, acronym, name):
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
user = request.user
doc = get_object_or_404(InternetDraft, filename=name)
if not can_manage_writeup_of_a_document(user, doc):
raise Http404
current_state = get_state_for_draft(doc)
can_edit = True
if current_state != get_state_by_name(WAITING_WRITEUP) and not can_manage_writeup_of_a_document_no_state(user, doc):
can_edit = False
writeup = doc.protowriteup_set.all()
if writeup.count():
writeup = writeup[0]
else:
writeup = None
error = False
followup_tag = get_annotation_tags_for_draft(doc).filter(annotation_tag__name=FOLLOWUP_TAG)
followup = bool(followup_tag.count())
if request.method == 'POST':
form = WriteUpEditForm(wg=wg, doc=doc, user=user, data=request.POST, files=request.FILES)
if request.FILES.get('uploaded_writeup', None):
try:
newwriteup = request.FILES['uploaded_writeup'].read().encode('ascii')
form.data.update({'writeup': newwriteup})
except:
form.set_message('error', 'You have try to upload a non ascii file')
error = True
valid = form.is_valid()
if (valid and not error and not request.POST.get('confirm', None)) or (not valid and not error):
if not valid:
form.set_message('error', 'You have to specify a comment')
return render_to_response('wgchairs/confirm_management_writeup.html',
dict(doc=doc,
user=user,
selected='manage_shepherds',
wg=wg,
followup=followup,
form=form,
writeup=writeup,
can_edit=can_edit,
),
context_instance=RequestContext(request))
elif valid and not error:
writeup = form.save()
form = WriteUpEditForm(wg=wg, doc=doc, user=user)
followup_tag = get_annotation_tags_for_draft(doc).filter(annotation_tag__name=FOLLOWUP_TAG)
followup = bool(followup_tag.count())
else:
form = WriteUpEditForm(wg=wg, doc=doc, user=user)
return render_to_response('wgchairs/edit_management_writeup.html',
dict(doc=doc,
user=user,
selected='manage_shepherds',
wg=wg,
form=form,
writeup=writeup,
followup=followup,
can_edit=can_edit,
),
context_instance=RequestContext(request))

View file

@ -1,6 +1,6 @@
# Copyright The IETF Trust 2008, All Rights Reserved
from django.conf.urls.defaults import patterns
from django.conf.urls.defaults import patterns, include
from ietf.wginfo import views
from django.views.generic.simple import redirect_to
@ -16,4 +16,5 @@ urlpatterns = patterns('',
(r'^(?P<acronym>[a-z0-9-]+)/documents/txt/$', views.wg_documents_txt),
(r'^(?P<acronym>[a-z0-9-]+)/$', views.wg_documents_html),
(r'^(?P<acronym>[a-z0-9-]+)/charter/$', views.wg_charter),
(r'^(?P<acronym>[^/]+)/management/', include('ietf.wgchairs.urls')),
)

148
permissions/__init__.py Normal file
View file

@ -0,0 +1,148 @@
import permissions.utils
class PermissionBase(object):
"""Mix-in class for permissions.
"""
def grant_permission(self, role, permission):
"""Grants passed permission to passed role. Returns True if the
permission was able to be added, otherwise False.
**Parameters:**
role
The role for which the permission should be granted.
permission
The permission which should be granted. Either a permission
object or the codename of a permission.
"""
return permissions.utils.grant_permission(self, role, permission)
def remove_permission(self, role, permission):
"""Removes passed permission from passed role. Returns True if the
permission has been removed.
**Parameters:**
role
The role for which a permission should be removed.
permission
The permission which should be removed. Either a permission object
or the codename of a permission.
"""
return permissions.utils.remove_permission(self, role, permission)
def has_permission(self, user, permission, roles=[]):
"""Returns True if the passed user has passed permission for this
instance. Otherwise False.
**Parameters:**
permission
The permission's codename which should be checked. Must be a
string with a valid codename.
user
The user for which the permission should be checked.
roles
If passed, these roles will be assigned to the user temporarily
before the permissions are checked.
"""
return permissions.utils.has_permission(self, user, permission, roles)
def check_permission(self, user, permission, roles=[]):
"""Raise Unauthorized if the the passed user hasn't passed permission
for this instance.
**Parameters:**
permission
The permission's codename which should be checked. Must be a
string with a valid codename.
user
The user for which the permission should be checked.
roles
If passed, these roles will be assigned to the user temporarily
before the permissions are checked.
"""
if not self.has_permission(user, permission, roles):
raise Unauthorized("User %s doesn't have permission %s for object %s" % (user, permission, obj.slug))
def add_inheritance_block(self, permission):
"""Adds an inheritance block for the passed permission.
**Parameters:**
permission
The permission for which an inheritance block should be added.
Either a permission object or the codename of a permission.
"""
return permissions.utils.add_inheritance_block(self, permission)
def remove_inheritance_block(self, permission):
"""Removes a inheritance block for the passed permission.
**Parameters:**
permission
The permission for which an inheritance block should be removed.
Either a permission object or the codename of a permission.
"""
return permissions.utils.remove_inheritance_block(self, permission)
def is_inherited(self, codename):
"""Returns True if the passed permission is inherited.
**Parameters:**
codename
The permission which should be checked. Must be the codename of
the permission.
"""
return permissions.utils.is_inherited(self, codename)
def add_role(self, principal, role):
"""Adds a local role for the principal.
**Parameters:**
principal
The principal (user or group) which gets the role.
role
The role which is assigned.
"""
return permissions.utils.add_local_role(self, principal, role)
def get_roles(self, principal):
"""Returns *direct* local roles for passed principal (user or group).
"""
return permissions.utils.get_local_roles(self, principal)
def remove_role(self, principal, role):
"""Adds a local role for the principal to the object.
**Parameters:**
principal
The principal (user or group) from which the role is removed.
role
The role which is removed.
"""
return permissions.utils.remove_local_role(self, principal, role)
def remove_roles(self, principal):
"""Removes all local roles for the passed principal from the object.
**Parameters:**
principal
The principal (user or group) from which all local roles are
removed.
"""
return permissions.utils.remove_local_roles(self, principal)

13
permissions/admin.py Normal file
View file

@ -0,0 +1,13 @@
from django.contrib import admin
from permissions.models import ObjectPermission
admin.site.register(ObjectPermission)
from permissions.models import Permission
admin.site.register(Permission)
from permissions.models import Role
admin.site.register(Role)
from permissions.models import PrincipalRoleRelation
admin.site.register(PrincipalRoleRelation)

45
permissions/backend.py Normal file
View file

@ -0,0 +1,45 @@
# permissions imports
import permissions.utils
class ObjectPermissionsBackend(object):
"""Django backend for object permissions. Needs Django 1.2.
Use it together with the default ModelBackend like so::
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'permissions.backend.ObjectPermissionsBackend',
)
Then you can use it like:
user.has_perm("view", your_object)
"""
supports_object_permissions = True
supports_anonymous_user = True
def authenticate(self, username, password):
return None
def has_perm(self, user_obj, perm, obj=None):
"""Checks whether the passed user has passed permission for passed
object (obj).
This should be the primary method to check wether a user has a certain
permission.
Parameters
==========
perm
The permission's codename which should be checked.
user_obj
The user for which the permission should be checked.
obj
The object for which the permission should be checked.
"""
return permissions.utils.has_permission(obj, user_obj, perm)

View file

@ -0,0 +1,3 @@
class Unauthorized(Exception):
def __init__(self, str):
super(Unauthorized, self).__init__(str)

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="1" model="permissions.permission">
<field type="CharField" name="name">View</field>
<field type="CharField" name="codename">view</field>
</object>
<object pk="2" model="permissions.permission">
<field type="CharField" name="name">Edit</field>
<field type="CharField" name="codename">edit</field>
</object>
<object pk="3" model="permissions.permission">
<field type="CharField" name="name">Delete</field>
<field type="CharField" name="codename">delete</field>
</object>
<object pk="4" model="permissions.permission">
<field type="CharField" name="name">Cut</field>
<field type="CharField" name="codename">cut</field>
</object>
<object pk="5" model="permissions.permission">
<field type="CharField" name="name">Copy</field>
<field type="CharField" name="codename">copy</field>
</object>
</django-objects>

Binary file not shown.

View file

@ -0,0 +1,52 @@
# German translations for django-permissions
# Copyright (C) 2010 Kai Diefenbach
# This file is distributed under the same license as the PACKAGE package.
# Kai Diefenbach <kai.diefenbach@iqpp.de>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-30 23:12+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:154
msgid "Name"
msgstr "Name"
#: models.py:155
msgid "Codename"
msgstr "Codename"
#: models.py:156
msgid "Content Types"
msgstr "Inhaltstypen"
#: models.py:175 models.py:280
msgid "Role"
msgstr "Rolle"
#: models.py:176 models.py:216
msgid "Permission"
msgstr "Recht"
#: models.py:178 models.py:218 models.py:282
msgid "Content type"
msgstr "Inhaltstyp"
#: models.py:179 models.py:219 models.py:283
msgid "Content id"
msgstr "Inhalts-ID"
#: models.py:278
msgid "User"
msgstr "Benutzer"
#: models.py:279
msgid "Group"
msgstr "Gruppe"

View file

@ -0,0 +1,154 @@
from south.db import db
from django.db import models
from permissions.models import *
class Migration:
def forwards(self, orm):
# Adding model 'Role'
db.create_table('permissions_role', (
('id', orm['permissions.Role:id']),
('name', orm['permissions.Role:name']),
))
db.send_create_signal('permissions', ['Role'])
# Adding model 'ObjectPermissionInheritanceBlock'
db.create_table('permissions_objectpermissioninheritanceblock', (
('id', orm['permissions.ObjectPermissionInheritanceBlock:id']),
('permission', orm['permissions.ObjectPermissionInheritanceBlock:permission']),
('content_type', orm['permissions.ObjectPermissionInheritanceBlock:content_type']),
('content_id', orm['permissions.ObjectPermissionInheritanceBlock:content_id']),
))
db.send_create_signal('permissions', ['ObjectPermissionInheritanceBlock'])
# Adding model 'ObjectPermission'
db.create_table('permissions_objectpermission', (
('id', orm['permissions.ObjectPermission:id']),
('role', orm['permissions.ObjectPermission:role']),
('permission', orm['permissions.ObjectPermission:permission']),
('content_type', orm['permissions.ObjectPermission:content_type']),
('content_id', orm['permissions.ObjectPermission:content_id']),
))
db.send_create_signal('permissions', ['ObjectPermission'])
# Adding model 'Permission'
db.create_table('permissions_permission', (
('id', orm['permissions.Permission:id']),
('name', orm['permissions.Permission:name']),
('codename', orm['permissions.Permission:codename']),
))
db.send_create_signal('permissions', ['Permission'])
# Adding model 'PrincipalRoleRelation'
db.create_table('permissions_principalrolerelation', (
('id', orm['permissions.PrincipalRoleRelation:id']),
('user', orm['permissions.PrincipalRoleRelation:user']),
('group', orm['permissions.PrincipalRoleRelation:group']),
('role', orm['permissions.PrincipalRoleRelation:role']),
('content_type', orm['permissions.PrincipalRoleRelation:content_type']),
('content_id', orm['permissions.PrincipalRoleRelation:content_id']),
))
db.send_create_signal('permissions', ['PrincipalRoleRelation'])
# Adding ManyToManyField 'Permission.content_types'
db.create_table('permissions_permission_content_types', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('permission', models.ForeignKey(orm.Permission, null=False)),
('contenttype', models.ForeignKey(orm['contenttypes.ContentType'], null=False))
))
def backwards(self, orm):
# Deleting model 'Role'
db.delete_table('permissions_role')
# Deleting model 'ObjectPermissionInheritanceBlock'
db.delete_table('permissions_objectpermissioninheritanceblock')
# Deleting model 'ObjectPermission'
db.delete_table('permissions_objectpermission')
# Deleting model 'Permission'
db.delete_table('permissions_permission')
# Deleting model 'PrincipalRoleRelation'
db.delete_table('permissions_principalrolerelation')
# Dropping ManyToManyField 'Permission.content_types'
db.delete_table('permissions_permission_content_types')
models = {
'auth.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']", 'blank': 'True'})
},
'auth.permission': {
'Meta': {'unique_together': "(('content_type', 'codename'),)"},
'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': {
'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']", 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'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']", 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'permissions.objectpermission': {
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']"}),
'role': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Role']", 'null': 'True', 'blank': 'True'})
},
'permissions.objectpermissioninheritanceblock': {
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']"})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'permissions.principalrolerelation': {
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'role': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Role']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
},
'permissions.role': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
}
}
complete_apps = ['permissions']

View file

193
permissions/models.py Normal file
View file

@ -0,0 +1,193 @@
# python imports
import sets
# django imports
from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth.models import Group
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _
class Permission(models.Model):
"""A permission which can be granted to users/groups and objects.
**Attributes:**
name
The unique name of the permission. This is displayed to users.
codename
The unique codename of the permission. This is used internal to
identify a permission.
content_types
The content types for which the permission is active. This can be
used to display only reasonable permissions for an object.
"""
name = models.CharField(_(u"Name"), max_length=100, unique=True)
codename = models.CharField(_(u"Codename"), max_length=100, unique=True)
content_types = models.ManyToManyField(ContentType, verbose_name=_(u"Content Types"), blank=True, null=True, related_name="content_types")
def __unicode__(self):
return "%s (%s)" % (self.name, self.codename)
class ObjectPermission(models.Model):
"""Grants permission for specific user/group and object.
**Attributes:**
role
The role for which the permission is granted.
permission
The permission which is granted.
content
The object for which the permission is granted.
"""
role = models.ForeignKey("Role", verbose_name=_(u"Role"), blank=True, null=True)
permission = models.ForeignKey(Permission, verbose_name=_(u"Permission"))
content_type = models.ForeignKey(ContentType, verbose_name=_(u"Content type"))
content_id = models.PositiveIntegerField(verbose_name=_(u"Content id"))
content = generic.GenericForeignKey(ct_field="content_type", fk_field="content_id")
def __unicode__(self):
if self.role:
principal = self.role
else:
principal = self.user
return "%s / %s / %s - %s" % (self.permission.name, principal, self.content_type, self.content_id)
def get_principal(self):
"""Returns the principal.
"""
return self.user or self.group
def set_principal(self, principal):
"""Sets the principal.
"""
if isinstance(principal, User):
self.user = principal
else:
self.group = principal
principal = property(get_principal, set_principal)
class ObjectPermissionInheritanceBlock(models.Model):
"""Blocks the inheritance for specific permission and object.
**Attributes:**
permission
The permission for which inheritance is blocked.
content
The object for which the inheritance is blocked.
"""
permission = models.ForeignKey(Permission, verbose_name=_(u"Permission"))
content_type = models.ForeignKey(ContentType, verbose_name=_(u"Content type"))
content_id = models.PositiveIntegerField(verbose_name=_(u"Content id"))
content = generic.GenericForeignKey(ct_field="content_type", fk_field="content_id")
def __unicode__(self):
return "%s / %s - %s" % (self.permission, self.content_type, self.content_id)
class Role(models.Model):
"""A role gets permissions to do something. Principals (users and groups)
can only get permissions via roles.
**Attributes:**
name
The unique name of the role
"""
name = models.CharField(max_length=100, unique=True)
class Meta:
ordering = ("name", )
def __unicode__(self):
return self.name
def add_principal(self, principal, content=None):
"""Addes the given principal (user or group) ot the Role.
"""
if isinstance(principal, User):
PrincipalRoleRelation.objects.create(user=principal, role=self)
else:
PrincipalRoleRelation.objects.create(group=principal, role=self)
def get_groups(self, content=None):
"""Returns all groups which has this role assigned. If content is given
it returns also the local roles.
"""
if content:
ctype = ContentType.objects.get_for_model(content)
prrs = PrincipalRoleRelation.objects.filter(role=self,
content_id__in = (None, content.pk),
content_type__in = (None, ctype)).exclude(group=None)
else:
prrs = PrincipalRoleRelation.objects.filter(role=self,
content_id=None, content_type=None).exclude(group=None)
return [prr.group for prr in prrs]
def get_users(self, content=None):
"""Returns all users which has this role assigned. If content is given
it returns also the local roles.
"""
if content:
ctype = ContentType.objects.get_for_model(content)
prrs = PrincipalRoleRelation.objects.filter(role=self,
content_id__in = (None, content.pk),
content_type__in = (None, ctype)).exclude(user=None)
else:
prrs = PrincipalRoleRelation.objects.filter(role=self,
content_id=None, content_type=None).exclude(user=None)
return [prr.user for prr in prrs]
class PrincipalRoleRelation(models.Model):
"""A role given to a principal (user or group). If a content object is
given this is a local role, i.e. the principal has this role only for this
content object. Otherwise it is a global role, i.e. the principal has
this role generally.
user
A user instance. Either a user xor a group needs to be given.
group
A group instance. Either a user xor a group needs to be given.
role
The role which is given to the principal for content.
content
The content object which gets the local role (optional).
"""
user = models.ForeignKey(User, verbose_name=_(u"User"), blank=True, null=True)
group = models.ForeignKey(Group, verbose_name=_(u"Group"), blank=True, null=True)
role = models.ForeignKey(Role, verbose_name=_(u"Role"))
content_type = models.ForeignKey(ContentType, verbose_name=_(u"Content type"), blank=True, null=True)
content_id = models.PositiveIntegerField(verbose_name=_(u"Content id"), blank=True, null=True)
content = generic.GenericForeignKey(ct_field="content_type", fk_field="content_id")
def get_principal(self):
"""Returns the principal.
"""
return self.user or self.group
def set_principal(self, principal):
"""Sets the principal.
"""
if isinstance(principal, User):
self.user = principal
else:
self.group = principal
principal = property(get_principal, set_principal)

View file

View file

@ -0,0 +1,48 @@
# django imports
from django import template
from django.core.exceptions import ImproperlyConfigured
from django.contrib.auth.models import User, AnonymousUser
import permissions.utils
register = template.Library()
class PermissionComparisonNode(template.Node):
"""Implements a node to provide an if current user has passed permission
for current object.
"""
@classmethod
def handle_token(cls, parser, token):
bits = token.contents.split()
if len(bits) != 2:
raise template.TemplateSyntaxError(
"'%s' tag takes one argument" % bits[0])
end_tag = 'endifhasperm'
nodelist_true = parser.parse(('else', end_tag))
token = parser.next_token()
if token.contents == 'else': # there is an 'else' clause in the tag
nodelist_false = parser.parse((end_tag,))
parser.delete_first_token()
else:
nodelist_false = ""
return cls(bits[1], nodelist_true, nodelist_false)
def __init__(self, permission, nodelist_true, nodelist_false):
self.permission = permission
self.nodelist_true = nodelist_true
self.nodelist_false = nodelist_false
def render(self, context):
obj = context.get("obj")
request = context.get("request")
if permissions.utils.has_permission(self.permission, request.user, obj):
return self.nodelist_true.render(context)
else:
return self.nodelist_false
@register.tag
def ifhasperm(parser, token):
"""This function provides functionality for the 'ifhasperm' template tag.
"""
return PermissionComparisonNode.handle_token(parser, token)

783
permissions/tests.py Normal file
View file

@ -0,0 +1,783 @@
# django imports
from django.contrib.flatpages.models import FlatPage
from django.contrib.auth.models import Group
from django.contrib.auth.models import User
from django.conf import settings
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.client import Client
# permissions imports
from permissions.models import Permission
from permissions.models import ObjectPermission
from permissions.models import ObjectPermissionInheritanceBlock
from permissions.models import Role
import permissions.utils
class BackendTestCase(TestCase):
"""
"""
def setUp(self):
"""
"""
settings.AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'permissions.backend.ObjectPermissionsBackend',
)
self.role_1 = permissions.utils.register_role("Role 1")
self.user = User.objects.create(username="john")
self.page_1 = FlatPage.objects.create(url="/page-1/", title="Page 1")
self.view = permissions.utils.register_permission("View", "view")
# Add user to role
self.role_1.add_principal(self.user)
def test_has_perm(self):
"""Tests has perm of the backend.
"""
result = self.user.has_perm(self.view, self.page_1)
self.assertEqual(result, False)
# assign view permission to role 1
permissions.utils.grant_permission(self.page_1, self.role_1, self.view)
result = self.user.has_perm("view", self.page_1)
self.assertEqual(result, True)
class RoleTestCase(TestCase):
"""
"""
def setUp(self):
"""
"""
self.role_1 = permissions.utils.register_role("Role 1")
self.role_2 = permissions.utils.register_role("Role 2")
self.user = User.objects.create(username="john")
self.group = Group.objects.create(name="brights")
self.user.groups.add(self.group)
self.page_1 = FlatPage.objects.create(url="/page-1/", title="Page 1")
self.page_2 = FlatPage.objects.create(url="/page-1/", title="Page 2")
def test_getter(self):
"""
"""
result = permissions.utils.get_group(self.group.id)
self.assertEqual(result, self.group)
result = permissions.utils.get_group(42)
self.assertEqual(result, None)
result = permissions.utils.get_role(self.role_1.id)
self.assertEqual(result, self.role_1)
result = permissions.utils.get_role(42)
self.assertEqual(result, None)
result = permissions.utils.get_user(self.user.id)
self.assertEqual(result, self.user)
result = permissions.utils.get_user(42)
self.assertEqual(result, None)
def test_global_roles_user(self):
"""
"""
# Add role 1
result = permissions.utils.add_role(self.user, self.role_1)
self.assertEqual(result, True)
# Add role 1 again
result = permissions.utils.add_role(self.user, self.role_1)
self.assertEqual(result, False)
result = permissions.utils.get_roles(self.user)
self.assertEqual(result, [self.role_1])
# Add role 2
result = permissions.utils.add_role(self.user, self.role_2)
self.assertEqual(result, True)
result = permissions.utils.get_roles(self.user)
self.assertEqual(result, [self.role_1, self.role_2])
# Remove role 1
result = permissions.utils.remove_role(self.user, self.role_1)
self.assertEqual(result, True)
# Remove role 1 again
result = permissions.utils.remove_role(self.user, self.role_1)
self.assertEqual(result, False)
result = permissions.utils.get_roles(self.user)
self.assertEqual(result, [self.role_2])
# Remove role 2
result = permissions.utils.remove_role(self.user, self.role_2)
self.assertEqual(result, True)
result = permissions.utils.get_roles(self.user)
self.assertEqual(result, [])
def test_global_roles_group(self):
"""
"""
# Add role 1
result = permissions.utils.add_role(self.group, self.role_1)
self.assertEqual(result, True)
# Add role 1 again
result = permissions.utils.add_role(self.group, self.role_1)
self.assertEqual(result, False)
result = permissions.utils.get_roles(self.group)
self.assertEqual(result, [self.role_1])
# Add role 2
result = permissions.utils.add_role(self.group, self.role_2)
self.assertEqual(result, True)
result = permissions.utils.get_roles(self.group)
self.assertEqual(result, [self.role_1, self.role_2])
# Remove role 1
result = permissions.utils.remove_role(self.group, self.role_1)
self.assertEqual(result, True)
# Remove role 1 again
result = permissions.utils.remove_role(self.group, self.role_1)
self.assertEqual(result, False)
result = permissions.utils.get_roles(self.group)
self.assertEqual(result, [self.role_2])
# Remove role 2
result = permissions.utils.remove_role(self.group, self.role_2)
self.assertEqual(result, True)
result = permissions.utils.get_roles(self.group)
self.assertEqual(result, [])
def test_remove_roles_user(self):
"""
"""
# Add role 1
result = permissions.utils.add_role(self.user, self.role_1)
self.assertEqual(result, True)
# Add role 2
result = permissions.utils.add_role(self.user, self.role_2)
self.assertEqual(result, True)
result = permissions.utils.get_roles(self.user)
self.assertEqual(result, [self.role_1, self.role_2])
# Remove roles
result = permissions.utils.remove_roles(self.user)
self.assertEqual(result, True)
result = permissions.utils.get_roles(self.user)
self.assertEqual(result, [])
# Remove roles
result = permissions.utils.remove_roles(self.user)
self.assertEqual(result, False)
def test_remove_roles_group(self):
"""
"""
# Add role 1
result = permissions.utils.add_role(self.group, self.role_1)
self.assertEqual(result, True)
# Add role 2
result = permissions.utils.add_role(self.group, self.role_2)
self.assertEqual(result, True)
result = permissions.utils.get_roles(self.group)
self.assertEqual(result, [self.role_1, self.role_2])
# Remove roles
result = permissions.utils.remove_roles(self.group)
self.assertEqual(result, True)
result = permissions.utils.get_roles(self.group)
self.assertEqual(result, [])
# Remove roles
result = permissions.utils.remove_roles(self.group)
self.assertEqual(result, False)
def test_local_role_user(self):
"""
"""
# Add local role to page 1
result = permissions.utils.add_local_role(self.page_1, self.user, self.role_1)
self.assertEqual(result, True)
# Again
result = permissions.utils.add_local_role(self.page_1, self.user, self.role_1)
self.assertEqual(result, False)
result = permissions.utils.get_local_roles(self.page_1, self.user)
self.assertEqual(result, [self.role_1])
# Add local role 2
result = permissions.utils.add_local_role(self.page_1, self.user, self.role_2)
self.assertEqual(result, True)
result = permissions.utils.get_local_roles(self.page_1, self.user)
self.assertEqual(result, [self.role_1, self.role_2])
# Remove role 1
result = permissions.utils.remove_local_role(self.page_1, self.user, self.role_1)
self.assertEqual(result, True)
# Remove role 1 again
result = permissions.utils.remove_local_role(self.page_1, self.user, self.role_1)
self.assertEqual(result, False)
result = permissions.utils.get_local_roles(self.page_1, self.user)
self.assertEqual(result, [self.role_2])
# Remove role 2
result = permissions.utils.remove_local_role(self.page_1, self.user, self.role_2)
self.assertEqual(result, True)
result = permissions.utils.get_local_roles(self.page_1, self.user)
self.assertEqual(result, [])
def test_local_role_group(self):
"""
"""
# Add local role to page 1
result = permissions.utils.add_local_role(self.page_1, self.group, self.role_1)
self.assertEqual(result, True)
# Again
result = permissions.utils.add_local_role(self.page_1, self.group, self.role_1)
self.assertEqual(result, False)
result = permissions.utils.get_local_roles(self.page_1, self.group)
self.assertEqual(result, [self.role_1])
# Add local role 2
result = permissions.utils.add_local_role(self.page_1, self.group, self.role_2)
self.assertEqual(result, True)
result = permissions.utils.get_local_roles(self.page_1, self.group)
self.assertEqual(result, [self.role_1, self.role_2])
# Remove role 1
result = permissions.utils.remove_local_role(self.page_1, self.group, self.role_1)
self.assertEqual(result, True)
# Remove role 1 again
result = permissions.utils.remove_local_role(self.page_1, self.group, self.role_1)
self.assertEqual(result, False)
result = permissions.utils.get_local_roles(self.page_1, self.group)
self.assertEqual(result, [self.role_2])
# Remove role 2
result = permissions.utils.remove_local_role(self.page_1, self.group, self.role_2)
self.assertEqual(result, True)
result = permissions.utils.get_local_roles(self.page_1, self.group)
self.assertEqual(result, [])
def test_remove_local_roles_user(self):
"""
"""
# Add local role to page 1
result = permissions.utils.add_local_role(self.page_1, self.user, self.role_1)
self.assertEqual(result, True)
# Add local role 2
result = permissions.utils.add_local_role(self.page_1, self.user, self.role_2)
self.assertEqual(result, True)
result = permissions.utils.get_local_roles(self.page_1, self.user)
self.assertEqual(result, [self.role_1, self.role_2])
# Remove all local roles
result = permissions.utils.remove_local_roles(self.page_1, self.user)
self.assertEqual(result, True)
result = permissions.utils.get_local_roles(self.page_1, self.user)
self.assertEqual(result, [])
# Remove all local roles again
result = permissions.utils.remove_local_roles(self.page_1, self.user)
self.assertEqual(result, False)
def test_get_groups_1(self):
"""Tests global roles for groups.
"""
result = self.role_1.get_groups()
self.assertEqual(len(result), 0)
result = permissions.utils.add_role(self.group, self.role_1)
self.assertEqual(result, True)
result = self.role_1.get_groups()
self.assertEqual(result[0].name, "brights")
# Add another group
self.group_2 = Group.objects.create(name="atheists")
result = permissions.utils.add_role(self.group_2, self.role_1)
result = self.role_1.get_groups()
self.assertEqual(result[0].name, "brights")
self.assertEqual(result[1].name, "atheists")
self.assertEqual(len(result), 2)
# Add the role to an user
result = permissions.utils.add_role(self.user, self.role_1)
self.assertEqual(result, True)
# This shouldn't have an effect on the result
result = self.role_1.get_groups()
self.assertEqual(result[0].name, "brights")
self.assertEqual(result[1].name, "atheists")
self.assertEqual(len(result), 2)
def test_get_groups_2(self):
"""Tests local roles for groups.
"""
result = self.role_1.get_groups(self.page_1)
self.assertEqual(len(result), 0)
result = permissions.utils.add_local_role(self.page_1, self.group, self.role_1)
self.assertEqual(result, True)
result = self.role_1.get_groups(self.page_1)
self.assertEqual(result[0].name, "brights")
# Add another local group
self.group_2 = Group.objects.create(name="atheists")
result = permissions.utils.add_local_role(self.page_1, self.group_2, self.role_1)
result = self.role_1.get_groups(self.page_1)
self.assertEqual(result[0].name, "brights")
self.assertEqual(result[1].name, "atheists")
# A the global role to group
result = permissions.utils.add_role(self.group, self.role_1)
self.assertEqual(result, True)
# Nontheless there are just two groups returned (and no duplicate)
result = self.role_1.get_groups(self.page_1)
self.assertEqual(result[0].name, "brights")
self.assertEqual(result[1].name, "atheists")
self.assertEqual(len(result), 2)
# Andere there should one global role
result = self.role_1.get_groups()
self.assertEqual(result[0].name, "brights")
# Add the role to an user
result = permissions.utils.add_local_role(self.page_1, self.user, self.role_1)
self.assertEqual(result, True)
# This shouldn't have an effect on the result
result = self.role_1.get_groups(self.page_1)
self.assertEqual(result[0].name, "brights")
self.assertEqual(result[1].name, "atheists")
self.assertEqual(len(result), 2)
def test_get_users_1(self):
"""Tests global roles for users.
"""
result = self.role_1.get_users()
self.assertEqual(len(result), 0)
result = permissions.utils.add_role(self.user, self.role_1)
self.assertEqual(result, True)
result = self.role_1.get_users()
self.assertEqual(result[0].username, "john")
# Add another role to an user
self.user_2 = User.objects.create(username="jane")
result = permissions.utils.add_role(self.user_2, self.role_1)
result = self.role_1.get_users()
self.assertEqual(result[0].username, "john")
self.assertEqual(result[1].username, "jane")
self.assertEqual(len(result), 2)
# Add the role to an user
result = permissions.utils.add_role(self.group, self.role_1)
self.assertEqual(result, True)
# This shouldn't have an effect on the result
result = self.role_1.get_users()
self.assertEqual(result[0].username, "john")
self.assertEqual(result[1].username, "jane")
self.assertEqual(len(result), 2)
def test_get_users_2(self):
"""Tests local roles for users.
"""
result = self.role_1.get_users(self.page_1)
self.assertEqual(len(result), 0)
result = permissions.utils.add_local_role(self.page_1, self.user, self.role_1)
self.assertEqual(result, True)
result = self.role_1.get_users(self.page_1)
self.assertEqual(result[0].username, "john")
# Add another local role to an user
self.user_2 = User.objects.create(username="jane")
result = permissions.utils.add_local_role(self.page_1, self.user_2, self.role_1)
result = self.role_1.get_users(self.page_1)
self.assertEqual(result[0].username, "john")
self.assertEqual(result[1].username, "jane")
# A the global role to user
result = permissions.utils.add_role(self.user, self.role_1)
self.assertEqual(result, True)
# Nontheless there are just two users returned (and no duplicate)
result = self.role_1.get_users(self.page_1)
self.assertEqual(result[0].username, "john")
self.assertEqual(result[1].username, "jane")
self.assertEqual(len(result), 2)
# Andere there should one user for the global role
result = self.role_1.get_users()
self.assertEqual(result[0].username, "john")
# Add the role to an group
result = permissions.utils.add_local_role(self.page_1, self.group, self.role_1)
self.assertEqual(result, True)
# This shouldn't have an effect on the result
result = self.role_1.get_users(self.page_1)
self.assertEqual(result[0].username, "john")
self.assertEqual(result[1].username, "jane")
self.assertEqual(len(result), 2)
class PermissionTestCase(TestCase):
"""
"""
def setUp(self):
"""
"""
self.role_1 = permissions.utils.register_role("Role 1")
self.role_2 = permissions.utils.register_role("Role 2")
self.user = User.objects.create(username="john")
permissions.utils.add_role(self.user, self.role_1)
self.user.save()
self.page_1 = FlatPage.objects.create(url="/page-1/", title="Page 1")
self.page_2 = FlatPage.objects.create(url="/page-1/", title="Page 2")
self.permission = permissions.utils.register_permission("View", "view")
def test_add_permissions(self):
"""
"""
# Add per object
result = permissions.utils.grant_permission(self.page_1, self.role_1, self.permission)
self.assertEqual(result, True)
# Add per codename
result = permissions.utils.grant_permission(self.page_1, self.role_1, "view")
self.assertEqual(result, True)
# Add ermission which does not exist
result = permissions.utils.grant_permission(self.page_1, self.role_1, "hurz")
self.assertEqual(result, False)
def test_remove_permission(self):
"""
"""
# Add
result = permissions.utils.grant_permission(self.page_1, self.role_1, "view")
self.assertEqual(result, True)
# Remove
result = permissions.utils.remove_permission(self.page_1, self.role_1, "view")
self.assertEqual(result, True)
# Remove again
result = permissions.utils.remove_permission(self.page_1, self.role_1, "view")
self.assertEqual(result, False)
def test_has_permission_role(self):
"""
"""
result = permissions.utils.has_permission(self.page_1, self.user, "view")
self.assertEqual(result, False)
result = permissions.utils.grant_permission(self.page_1, self.role_1, self.permission)
self.assertEqual(result, True)
result = permissions.utils.has_permission(self.page_1, self.user, "view")
self.assertEqual(result, True)
result = permissions.utils.remove_permission(self.page_1, self.role_1, "view")
self.assertEqual(result, True)
result = permissions.utils.has_permission(self.page_1, self.user, "view")
self.assertEqual(result, False)
def test_has_permission_owner(self):
"""
"""
creator = User.objects.create(username="jane")
result = permissions.utils.has_permission(self.page_1, creator, "view")
self.assertEqual(result, False)
owner = permissions.utils.register_role("Owner")
permissions.utils.grant_permission(self.page_1, owner, "view")
result = permissions.utils.has_permission(self.page_1, creator, "view", [owner])
self.assertEqual(result, True)
def test_local_role(self):
"""
"""
result = permissions.utils.has_permission(self.page_1, self.user, "view")
self.assertEqual(result, False)
permissions.utils.grant_permission(self.page_1, self.role_2, self.permission)
permissions.utils.add_local_role(self.page_1, self.user, self.role_2)
result = permissions.utils.has_permission(self.page_1, self.user, "view")
self.assertEqual(result, True)
def test_ineritance(self):
"""
"""
result = permissions.utils.is_inherited(self.page_1, "view")
self.assertEqual(result, True)
# per permission
permissions.utils.add_inheritance_block(self.page_1, self.permission)
result = permissions.utils.is_inherited(self.page_1, "view")
self.assertEqual(result, False)
permissions.utils.remove_inheritance_block(self.page_1, self.permission)
result = permissions.utils.is_inherited(self.page_1, "view")
self.assertEqual(result, True)
# per codename
permissions.utils.add_inheritance_block(self.page_1, "view")
result = permissions.utils.is_inherited(self.page_1, "view")
self.assertEqual(result, False)
permissions.utils.remove_inheritance_block(self.page_1, "view")
result = permissions.utils.is_inherited(self.page_1, "view")
self.assertEqual(result, True)
def test_unicode(self):
"""
"""
# Permission
self.assertEqual(self.permission.__unicode__(), "View (view)")
# ObjectPermission
permissions.utils.grant_permission(self.page_1, self.role_1, self.permission)
opr = ObjectPermission.objects.get(permission=self.permission, role=self.role_1)
self.assertEqual(opr.__unicode__(), "View / Role 1 / flat page - 1")
# ObjectPermissionInheritanceBlock
permissions.utils.add_inheritance_block(self.page_1, self.permission)
opb = ObjectPermissionInheritanceBlock.objects.get(permission=self.permission)
self.assertEqual(opb.__unicode__(), "View (view) / flat page - 1")
def test_reset(self):
"""
"""
result = permissions.utils.grant_permission(self.page_1, self.role_1, "view")
self.assertEqual(result, True)
result = permissions.utils.has_permission(self.page_1, self.user, "view")
self.assertEqual(result, True)
permissions.utils.add_inheritance_block(self.page_1, "view")
result = permissions.utils.is_inherited(self.page_1, "view")
self.assertEqual(result, False)
permissions.utils.reset(self.page_1)
result = permissions.utils.has_permission(self.page_1, self.user, "view")
self.assertEqual(result, False)
result = permissions.utils.is_inherited(self.page_1, "view")
self.assertEqual(result, True)
permissions.utils.reset(self.page_1)
class RegistrationTestCase(TestCase):
"""Tests the registration of different components.
"""
def test_group(self):
"""Tests registering/unregistering of a group.
"""
# Register a group
result = permissions.utils.register_group("Brights")
self.failUnless(isinstance(result, Group))
# It's there
group = Group.objects.get(name="Brights")
self.assertEqual(group.name, "Brights")
# Trying to register another group with same name
result = permissions.utils.register_group("Brights")
self.assertEqual(result, False)
group = Group.objects.get(name="Brights")
self.assertEqual(group.name, "Brights")
# Unregister the group
result = permissions.utils.unregister_group("Brights")
self.assertEqual(result, True)
# It's not there anymore
self.assertRaises(Group.DoesNotExist, Group.objects.get, name="Brights")
# Trying to unregister the group again
result = permissions.utils.unregister_group("Brights")
self.assertEqual(result, False)
def test_role(self):
"""Tests registering/unregistering of a role.
"""
# Register a role
result = permissions.utils.register_role("Editor")
self.failUnless(isinstance(result, Role))
# It's there
role = Role.objects.get(name="Editor")
self.assertEqual(role.name, "Editor")
# Trying to register another role with same name
result = permissions.utils.register_role("Editor")
self.assertEqual(result, False)
role = Role.objects.get(name="Editor")
self.assertEqual(role.name, "Editor")
# Unregister the role
result = permissions.utils.unregister_role("Editor")
self.assertEqual(result, True)
# It's not there anymore
self.assertRaises(Role.DoesNotExist, Role.objects.get, name="Editor")
# Trying to unregister the role again
result = permissions.utils.unregister_role("Editor")
self.assertEqual(result, False)
def test_permission(self):
"""Tests registering/unregistering of a permission.
"""
# Register a permission
result = permissions.utils.register_permission("Change", "change")
self.failUnless(isinstance(result, Permission))
# Is it there?
p = Permission.objects.get(codename="change")
self.assertEqual(p.name, "Change")
# Register a permission with the same codename
result = permissions.utils.register_permission("Change2", "change")
self.assertEqual(result, False)
# Is it there?
p = Permission.objects.get(codename="change")
self.assertEqual(p.name, "Change")
# Register a permission with the same name
result = permissions.utils.register_permission("Change", "change2")
self.assertEqual(result, False)
# Is it there?
p = Permission.objects.get(codename="change")
self.assertEqual(p.name, "Change")
# Unregister the permission
result = permissions.utils.unregister_permission("change")
self.assertEqual(result, True)
# Is it not there anymore?
self.assertRaises(Permission.DoesNotExist, Permission.objects.get, codename="change")
# Unregister the permission again
result = permissions.utils.unregister_permission("change")
self.assertEqual(result, False)
# django imports
from django.core.handlers.wsgi import WSGIRequest
from django.contrib.auth.models import User
from django.contrib.sessions.backends.file import SessionStore
from django.test.client import Client
# Taken from "http://www.djangosnippets.org/snippets/963/"
class RequestFactory(Client):
"""
Class that lets you create mock Request objects for use in testing.
Usage:
rf = RequestFactory()
get_request = rf.get('/hello/')
post_request = rf.post('/submit/', {'foo': 'bar'})
This class re-uses the django.test.client.Client interface, docs here:
http://www.djangoproject.com/documentation/testing/#the-test-client
Once you have a request object you can pass it to any view function,
just as if that view had been hooked up using a URLconf.
"""
def request(self, **request):
"""
Similar to parent class, but returns the request object as soon as it
has created it.
"""
environ = {
'HTTP_COOKIE': self.cookies,
'PATH_INFO': '/',
'QUERY_STRING': '',
'REQUEST_METHOD': 'GET',
'SCRIPT_NAME': '',
'SERVER_NAME': 'testserver',
'SERVER_PORT': 80,
'SERVER_PROTOCOL': 'HTTP/1.1',
}
environ.update(self.defaults)
environ.update(request)
return WSGIRequest(environ)
def create_request():
"""
"""
rf = RequestFactory()
request = rf.get('/')
request.session = SessionStore()
user = User()
user.is_superuser = True
user.save()
request.user = user
return request

665
permissions/utils.py Normal file
View file

@ -0,0 +1,665 @@
# django imports
from django.db import IntegrityError
from django.db.models import Q
from django.db import connection
from django.contrib.auth.models import User
from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist
# permissions imports
from permissions.exceptions import Unauthorized
from permissions.models import ObjectPermission
from permissions.models import ObjectPermissionInheritanceBlock
from permissions.models import Permission
from permissions.models import PrincipalRoleRelation
from permissions.models import Role
# Roles ######################################################################
def add_role(principal, role):
"""Adds a global role to a principal.
**Parameters:**
principal
The principal (user or group) which gets the role added.
role
The role which is assigned.
"""
if isinstance(principal, User):
try:
ppr = PrincipalRoleRelation.objects.get(user=principal, role=role, content_id=None, content_type=None)
except PrincipalRoleRelation.DoesNotExist:
PrincipalRoleRelation.objects.create(user=principal, role=role)
return True
else:
try:
ppr = PrincipalRoleRelation.objects.get(group=principal, role=role, content_id=None, content_type=None)
except PrincipalRoleRelation.DoesNotExist:
PrincipalRoleRelation.objects.create(group=principal, role=role)
return True
return False
def add_local_role(obj, principal, role):
"""Adds a local role to a principal.
**Parameters:**
obj
The object for which the principal gets the role.
principal
The principal (user or group) which gets the role.
role
The role which is assigned.
"""
ctype = ContentType.objects.get_for_model(obj)
if isinstance(principal, User):
try:
ppr = PrincipalRoleRelation.objects.get(user=principal, role=role, content_id=obj.pk, content_type=ctype)
except PrincipalRoleRelation.DoesNotExist:
PrincipalRoleRelation.objects.create(user=principal, role=role, content=obj)
return True
else:
try:
ppr = PrincipalRoleRelation.objects.get(group=principal, role=role, content_id=obj.pk, content_type=ctype)
except PrincipalRoleRelation.DoesNotExist:
PrincipalRoleRelation.objects.create(group=principal, role=role, content=obj)
return True
return False
def remove_role(principal, role):
"""Removes role from passed principal.
**Parameters:**
principal
The principal (user or group) from which the role is removed.
role
The role which is removed.
"""
try:
if isinstance(principal, User):
ppr = PrincipalRoleRelation.objects.get(
user=principal, role=role, content_id=None, content_type=None)
else:
ppr = PrincipalRoleRelation.objects.get(
group=principal, role=role, content_id=None, content_type=None)
except PrincipalRoleRelation.DoesNotExist:
return False
else:
ppr.delete()
return True
def remove_local_role(obj, principal, role):
"""Removes role from passed object and principle.
**Parameters:**
obj
The object from which the role is removed.
principal
The principal (user or group) from which the role is removed.
role
The role which is removed.
"""
try:
ctype = ContentType.objects.get_for_model(obj)
if isinstance(principal, User):
ppr = PrincipalRoleRelation.objects.get(
user=principal, role=role, content_id=obj.pk, content_type=ctype)
else:
ppr = PrincipalRoleRelation.objects.get(
group=principal, role=role, content_id=obj.pk, content_type=ctype)
except PrincipalRoleRelation.DoesNotExist:
return False
else:
ppr.delete()
return True
def remove_roles(principal):
"""Removes all roles passed principal (user or group).
**Parameters:**
principal
The principal (user or group) from which all roles are removed.
"""
if isinstance(principal, User):
ppr = PrincipalRoleRelation.objects.filter(
user=principal, content_id=None, content_type=None)
else:
ppr = PrincipalRoleRelation.objects.filter(
group=principal, content_id=None, content_type=None)
if ppr:
ppr.delete()
return True
else:
return False
def remove_local_roles(obj, principal):
"""Removes all local roles from passed object and principal (user or
group).
**Parameters:**
obj
The object from which the roles are removed.
principal
The principal (user or group) from which the roles are removed.
"""
ctype = ContentType.objects.get_for_model(obj)
if isinstance(principal, User):
ppr = PrincipalRoleRelation.objects.filter(
user=principal, content_id=obj.pk, content_type=ctype)
else:
ppr = PrincipalRoleRelation.objects.filter(
group=principal, content_id=obj.pk, content_type=ctype)
if ppr:
ppr.delete()
return True
else:
return False
def get_roles(user, obj=None):
"""Returns *all* roles of the passed user.
This takes direct roles and roles via the user's groups into account.
If an object is passed local roles will also added. Then all local roles
from all ancestors and all user's groups are also taken into account.
This is the method to use if one want to know whether the passed user
has a role in general (for the passed object).
**Parameters:**
user
The user for which the roles are returned.
obj
The object for which local roles will returned.
"""
roles = []
groups = user.groups.all()
groups_ids_str = ", ".join([str(g.id) for g in groups])
# Gobal roles for user and the user's groups
cursor = connection.cursor()
cursor.execute("""SELECT role_id
FROM permissions_principalrolerelation
WHERE (user_id=%s OR group_id IN (%s))
AND content_id is Null""" % (user.id, groups_ids_str))
for row in cursor.fetchall():
roles.append(row[0])
# Local roles for user and the user's groups and all ancestors of the
# passed object.
while obj:
ctype = ContentType.objects.get_for_model(obj)
cursor.execute("""SELECT role_id
FROM permissions_principalrolerelation
WHERE (user_id='%s' OR group_id IN (%s))
AND content_id='%s'
AND content_type_id='%s'""" % (user.id, groups_ids_str, obj.pk, ctype.id))
for row in cursor.fetchall():
roles.append(row[0])
try:
obj = obj.get_parent_for_permissions()
except AttributeError:
obj = None
return roles
def get_global_roles(principal):
"""Returns *direct* global roles of passed principal (user or group).
"""
if isinstance(principal, User):
return [prr.role for prr in PrincipalRoleRelation.objects.filter(
user=principal, content_id=None, content_type=None)]
else:
if isinstance(principal, Group):
principal = (principal,)
return [prr.role for prr in PrincipalRoleRelation.objects.filter(
group__in=principal, content_id=None, content_type=None)]
def get_local_roles(obj, principal):
"""Returns *direct* local roles for passed principal and content object.
"""
ctype = ContentType.objects.get_for_model(obj)
if isinstance(principal, User):
return [prr.role for prr in PrincipalRoleRelation.objects.filter(
user=principal, content_id=obj.pk, content_type=ctype)]
else:
return [prr.role for prr in PrincipalRoleRelation.objects.filter(
group=principal, content_id=obj.pk, content_type=ctype)]
# Permissions ################################################################
def check_permission(obj, user, codename, roles=None):
"""Checks whether passed user has passed permission for passed obj.
**Parameters:**
obj
The object for which the permission should be checked.
codename
The permission's codename which should be checked.
user
The user for which the permission should be checked.
roles
If given these roles will be assigned to the user temporarily before
the permissions are checked.
"""
if not has_permission(obj, user, codename):
raise Unauthorized("User '%s' doesn't have permission '%s' for object '%s' (%s)"
% (user, codename, obj.slug, obj.__class__.__name__))
def grant_permission(obj, role, permission):
"""Grants passed permission to passed role. Returns True if the permission
was able to be added, otherwise False.
**Parameters:**
obj
The content object for which the permission should be granted.
role
The role for which the permission should be granted.
permission
The permission which should be granted. Either a permission
object or the codename of a permission.
"""
if not isinstance(permission, Permission):
try:
permission = Permission.objects.get(codename = permission)
except Permission.DoesNotExist:
return False
ct = ContentType.objects.get_for_model(obj)
try:
ObjectPermission.objects.get(role=role, content_type = ct, content_id=obj.pk, permission=permission)
except ObjectPermission.DoesNotExist:
ObjectPermission.objects.create(role=role, content=obj, permission=permission)
return True
def remove_permission(obj, role, permission):
"""Removes passed permission from passed role and object. Returns True if
the permission has been removed.
**Parameters:**
obj
The content object for which a permission should be removed.
role
The role for which a permission should be removed.
permission
The permission which should be removed. Either a permission object
or the codename of a permission.
"""
if not isinstance(permission, Permission):
try:
permission = Permission.objects.get(codename = permission)
except Permission.DoesNotExist:
return False
ct = ContentType.objects.get_for_model(obj)
try:
op = ObjectPermission.objects.get(role=role, content_type = ct, content_id=obj.pk, permission = permission)
except ObjectPermission.DoesNotExist:
return False
op.delete()
return True
def has_permission(obj, user, codename, roles=None):
"""Checks whether the passed user has passed permission for passed object.
**Parameters:**
obj
The object for which the permission should be checked.
codename
The permission's codename which should be checked.
request
The current request.
roles
If given these roles will be assigned to the user temporarily before
the permissions are checked.
"""
cache_key = "%s-%s-%s" % (obj.content_type, obj.pk, codename)
result = _get_cached_permission(user, cache_key)
if result is not None:
return result
if roles is None:
roles = []
if user.is_superuser:
return True
if not user.is_anonymous():
roles.extend(get_roles(user, obj))
ct = ContentType.objects.get_for_model(obj)
result = False
while obj is not None:
p = ObjectPermission.objects.filter(
content_type=ct, content_id=obj.pk, role__in=roles, permission__codename = codename).values("id")
if len(p) > 0:
result = True
break
if is_inherited(obj, codename) == False:
result = False
break
try:
obj = obj.get_parent_for_permissions()
ct = ContentType.objects.get_for_model(obj)
except AttributeError:
result = False
break
_cache_permission(user, cache_key, result)
return result
# Inheritance ################################################################
def add_inheritance_block(obj, permission):
"""Adds an inheritance for the passed permission on the passed obj.
**Parameters:**
permission
The permission for which an inheritance block should be added.
Either a permission object or the codename of a permission.
obj
The content object for which an inheritance block should be added.
"""
if not isinstance(permission, Permission):
try:
permission = Permission.objects.get(codename = permission)
except Permission.DoesNotExist:
return False
ct = ContentType.objects.get_for_model(obj)
try:
ObjectPermissionInheritanceBlock.objects.get(content_type = ct, content_id=obj.pk, permission=permission)
except ObjectPermissionInheritanceBlock.DoesNotExist:
try:
result = ObjectPermissionInheritanceBlock.objects.create(content=obj, permission=permission)
except IntegrityError:
return False
return True
def remove_inheritance_block(obj, permission):
"""Removes a inheritance block for the passed permission from the passed
object.
**Parameters:**
obj
The content object for which an inheritance block should be added.
permission
The permission for which an inheritance block should be removed.
Either a permission object or the codename of a permission.
"""
if not isinstance(permission, Permission):
try:
permission = Permission.objects.get(codename = permission)
except Permission.DoesNotExist:
return False
ct = ContentType.objects.get_for_model(obj)
try:
opi = ObjectPermissionInheritanceBlock.objects.get(content_type = ct, content_id=obj.pk, permission=permission)
except ObjectPermissionInheritanceBlock.DoesNotExist:
return False
opi.delete()
return True
def is_inherited(obj, codename):
"""Returns True if the passed permission is inherited for passed object.
**Parameters:**
obj
The content object for which the permission should be checked.
codename
The permission which should be checked. Must be the codename of
the permission.
"""
ct = ContentType.objects.get_for_model(obj)
try:
ObjectPermissionInheritanceBlock.objects.get(
content_type=ct, content_id=obj.pk, permission__codename = codename)
except ObjectDoesNotExist:
return True
else:
return False
def get_group(id):
"""Returns the group with passed id or None.
"""
try:
return Group.objects.get(pk=id)
except Group.DoesNotExist:
return None
def get_role(id):
"""Returns the role with passed id or None.
"""
try:
return Role.objects.get(pk=id)
except Role.DoesNotExist:
return None
def get_user(id):
"""Returns the user with passed id or None.
"""
try:
return User.objects.get(pk=id)
except User.DoesNotExist:
return None
def has_group(user, group):
"""Returns True if passed user has passed group.
"""
if isinstance(group, str):
group = Group.objects.get(name=group)
return group in user.groups.all()
def reset(obj):
"""Resets all permissions and inheritance blocks of passed object.
"""
ctype = ContentType.objects.get_for_model(obj)
ObjectPermissionInheritanceBlock.objects.filter(content_id=obj.pk, content_type=ctype).delete()
ObjectPermission.objects.filter(content_id=obj.pk, content_type=ctype).delete()
# Registering ################################################################
def register_permission(name, codename, ctypes=[]):
"""Registers a permission to the framework. Returns the permission if the
registration was successfully, otherwise False.
**Parameters:**
name
The unique name of the permission. This is displayed to the
customer.
codename
The unique codename of the permission. This is used internally to
identify the permission.
content_types
The content type for which the permission is active. This can be
used to display only reasonable permissions for an object. This
must be a Django ContentType
"""
try:
p = Permission.objects.create(name=name, codename=codename)
ctypes = [ContentType.objects.get_for_model(ctype) for ctype in ctypes]
if ctypes:
p.content_types = ctypes
p.save()
except IntegrityError:
return False
return p
def unregister_permission(codename):
"""Unregisters a permission from the framework
**Parameters:**
codename
The unique codename of the permission.
"""
try:
permission = Permission.objects.get(codename=codename)
except Permission.DoesNotExist:
return False
permission.delete()
return True
def register_role(name):
"""Registers a role with passed name to the framework. Returns the new
role if the registration was successfully, otherwise False.
**Parameters:**
name
The unique role name.
"""
try:
role = Role.objects.create(name=name)
except IntegrityError:
return False
return role
def unregister_role(name):
"""Unregisters the role with passed name.
**Parameters:**
name
The unique role name.
"""
try:
role = Role.objects.get(name=name)
except Role.DoesNotExist:
return False
role.delete()
return True
def register_group(name):
"""Registers a group with passed name to the framework. Returns the new
group if the registration was successfully, otherwise False.
Actually this creates just a default Django Group.
**Parameters:**
name
The unique group name.
"""
try:
group = Group.objects.create(name=name)
except IntegrityError:
return False
return group
def unregister_group(name):
"""Unregisters the group with passed name. Returns True if the
unregistration was succesfull otherwise False.
Actually this deletes just a default Django Group.
**Parameters:**
name
The unique role name.
"""
try:
group = Group.objects.get(name=name)
except Group.DoesNotExist:
return False
group.delete()
return True
def _cache_permission(user, cache_key, data):
"""Stores the passed data on the passed user object.
**Parameters:**
user
The user on which the data is stored.
cache_key
The key under which the data is stored.
data
The data which is stored.
"""
if not getattr(user, "permissions", None):
user.permissions = {}
user.permissions[cache_key] = data
def _get_cached_permission(user, cache_key):
"""Returns the stored data from passed user object for passed cache_key.
**Parameters:**
user
The user from which the data is retrieved.
cache_key
The key under which the data is stored.
"""
permissions = getattr(user, "permissions", None)
if permissions:
return user.permissions.get(cache_key, None)

View file

@ -71,6 +71,17 @@ body { margin: 0; }
.ietf-ballot .square { border:1px solid black; display: block; float:left;width: 10px; height:10px;font-size:1px;margin-right:4px; margin-top:1px;}
.ietf-ballot .was { padding-left: 10px; font-size:85%; }
.ietf-stream tr { vertical-align: top; }
.ietf-stream ul.ietf-stream-tag-list { padding: 10px; margin: 0px; list-style-type: none; font-size: 10px; }
.ietf-stream ul.ietf-stream-tag-list li { margin-bottom: 1em; list-style-type: circle; color: #999999; }
.ietf-stream ul.ietf-stream-tag-list li.tag_set { font-weight: bold; list-style-type: disc; color: black; }
.ietf-stream td.right { padding-top: 1em; }
.ietf-stream .ietf-stream-head h2, .ietf-stream .ietf-stream-head h3 { margin: 0px; }
.ietf-stream .ietf-stream-head { margin-bottom: 2em; }
.ietf-stream .entry-title { background: #2647A0; color:white; padding: 2px 4px; font-size: 108%; margin-top: 0;}
.ietf-stream .entry-title .entry-date { float: right; }
.ietf-stream .entry-comment { background: #eeeeee; margin: 1em 0px; padding: 1em; }
.search_form_box {width: 99.5%; margin-top:8px; padding:4px; margin-bottom:1em; padding-left:8px;}
form#search_form { padding-top: 4px; padding-bottom: 4px; }
#search_form input { padding: 0; padding-left: 2px; border: 1px solid #89d;}

View file

@ -74,3 +74,53 @@ function showBallot(draftName, editPositionUrl) {
function editBallot(editPositionUrl) {
window.open(editPositionUrl);
}
function showStream(dialogTitle, infoStreamUrl) {
var handleClose = function() {
IETF.streamDialog.hide();
};
var el;
if (!IETF.streamDialog) {
el = document.createElement("div");
el.innerHTML = '<div id="stream_dialog" style="visibility:hidden;"><div class="hd"><span id="stream_title">' + dialogTitle + '</span></div><div class="bd"> <div id="stream_dialog_body" style="overflow-y:scroll; height:400px;"></div> </div></div>';
document.getElementById("ietf-extras").appendChild(el);
var buttons = [{text:"Close", handler:handleClose, isDefault:true}];
var kl = [new YAHOO.util.KeyListener(document, {keys:27}, handleClose)]
IETF.streamDialog = new YAHOO.widget.Dialog("stream_dialog", {
visible:false, draggable:false, close:true, modal:true,
width:"860px", fixedcenter:true, constraintoviewport:true,
buttons: buttons, keylisteners:kl});
IETF.streamDialog.render();
}
document.getElementById("stream_title").innerHTML = dialogTitle;
IETF.streamDialog.show();
el = document.getElementById("stream_dialog_body");
el.innerHTML = "Loading...";
YAHOO.util.Connect.asyncRequest('GET',
infoStreamUrl,
{ success: function(o) { el.innerHTML = (o.responseText !== undefined) ? o.responseText : "?"; },
failure: function(o) { el.innerHTML = "Error: "+o.status+" "+o.statusText; },
argument: null
}, null);
}
(function ($) {
$.fn.StreamInfo = function() {
return this.each(function () {
var infoStreamUrl = $(this).attr('href');
var title = $(this).attr('title');
$(this).click(function() {
showStream(title, infoStreamUrl);
return false;
});
});
};
$(document).ready(function () {
$('a.show_stream_info').StreamInfo();
});
})(jQuery);

61
workflows/__init__.py Normal file
View file

@ -0,0 +1,61 @@
# workflows imports
import workflows.utils
class WorkflowBase(object):
"""Mixin class to make objects workflow aware.
"""
def get_workflow(self):
"""Returns the current workflow of the object.
"""
return workflows.utils.get_workflow(self)
def remove_workflow(self):
"""Removes the workflow from the object. After this function has been
called the object has no *own* workflow anymore (it might have one via
its content type).
"""
return workflows.utils.remove_workflow_from_object(self)
def set_workflow(self, workflow):
"""Sets the passed workflow to the object. This will set the local
workflow for the object.
If the object has already the given workflow nothing happens.
Otherwise the object gets the passed workflow and the state is set to
the workflow's initial state.
**Parameters:**
workflow
The workflow which should be set to the object. Can be a Workflow
instance or a string with the workflow name.
obj
The object which gets the passed workflow.
"""
return workflows.utils.set_workflow_for_object(workflow)
def get_state(self):
"""Returns the current workflow state of the object.
"""
return workflows.utils.get_state(self)
def set_state(self, state):
"""Sets the workflow state of the object.
"""
return workflows.utils.set_state(self, state)
def set_initial_state(self):
"""Sets the initial state of the current workflow to the object.
"""
return self.set_state(self.get_workflow().initial_state)
def get_allowed_transitions(self, user):
"""Returns allowed transitions for the current state.
"""
return workflows.utils.get_allowed_transitions(self, user)
def do_transition(self, transition, user):
"""Processes the passed transition (if allowed).
"""
return workflows.utils.do_transition(self, transition, user)

30
workflows/admin.py Normal file
View file

@ -0,0 +1,30 @@
from django.contrib import admin
from workflows.models import State
from workflows.models import StateInheritanceBlock
from workflows.models import StatePermissionRelation
from workflows.models import StateObjectRelation
from workflows.models import Transition
from workflows.models import Workflow
from workflows.models import WorkflowObjectRelation
from workflows.models import WorkflowModelRelation
from workflows.models import WorkflowPermissionRelation
class StateInline(admin.TabularInline):
model = State
class WorkflowAdmin(admin.ModelAdmin):
inlines = [
StateInline,
]
admin.site.register(Workflow, WorkflowAdmin)
admin.site.register(State)
admin.site.register(StateInheritanceBlock)
admin.site.register(StateObjectRelation)
admin.site.register(StatePermissionRelation)
admin.site.register(Transition)
admin.site.register(WorkflowObjectRelation)
admin.site.register(WorkflowModelRelation)
admin.site.register(WorkflowPermissionRelation)

Binary file not shown.

View file

@ -0,0 +1,60 @@
# German translations for django-workflows
# Copyright (C) 2010 Kai Diefenbach
# This file is distributed under the same license as the PACKAGE package.
# Kai Diefenbach <kai.diefenbach@iqpp.de>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-04-02 09:16+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:98 models.py:199 models.py:237
msgid "Name"
msgstr "Name"
#: models.py:200 models.py:238 models.py:285 models.py:307
msgid "Workflow"
msgstr "Arbeitsablauf"
#: models.py:201
msgid "Transitions"
msgstr "Übergänge"
#: models.py:239
msgid "Destination"
msgstr "Ziel"
#: models.py:240
msgid "Condition"
msgstr "Kondition"
#: models.py:241 models.py:350 models.py:373
msgid "Permission"
msgstr "Recht"
#: models.py:258 models.py:282
msgid "Content type"
msgstr "Inhaltstyp"
#: models.py:259 models.py:283
msgid "Content id"
msgstr "Inhalts-ID"
#: models.py:261 models.py:349 models.py:372
msgid "State"
msgstr "Status"
#: models.py:306
msgid "Content Type"
msgstr "Inhaltstyp"
#: models.py:374
msgid "Role"
msgstr "Rolle"

View file

@ -0,0 +1,225 @@
from south.db import db
from django.db import models
from workflows.models import *
class Migration:
def forwards(self, orm):
# Adding model 'Workflow'
db.create_table('workflows_workflow', (
('id', orm['workflows.Workflow:id']),
('name', orm['workflows.Workflow:name']),
('initial_state', orm['workflows.Workflow:initial_state']),
))
db.send_create_signal('workflows', ['Workflow'])
# Adding model 'StatePermissionRelation'
db.create_table('workflows_statepermissionrelation', (
('id', orm['workflows.StatePermissionRelation:id']),
('state', orm['workflows.StatePermissionRelation:state']),
('permission', orm['workflows.StatePermissionRelation:permission']),
('role', orm['workflows.StatePermissionRelation:role']),
))
db.send_create_signal('workflows', ['StatePermissionRelation'])
# Adding model 'StateInheritanceBlock'
db.create_table('workflows_stateinheritanceblock', (
('id', orm['workflows.StateInheritanceBlock:id']),
('state', orm['workflows.StateInheritanceBlock:state']),
('permission', orm['workflows.StateInheritanceBlock:permission']),
))
db.send_create_signal('workflows', ['StateInheritanceBlock'])
# Adding model 'WorkflowModelRelation'
db.create_table('workflows_workflowmodelrelation', (
('id', orm['workflows.WorkflowModelRelation:id']),
('content_type', orm['workflows.WorkflowModelRelation:content_type']),
('workflow', orm['workflows.WorkflowModelRelation:workflow']),
))
db.send_create_signal('workflows', ['WorkflowModelRelation'])
# Adding model 'WorkflowPermissionRelation'
db.create_table('workflows_workflowpermissionrelation', (
('id', orm['workflows.WorkflowPermissionRelation:id']),
('workflow', orm['workflows.WorkflowPermissionRelation:workflow']),
('permission', orm['workflows.WorkflowPermissionRelation:permission']),
))
db.send_create_signal('workflows', ['WorkflowPermissionRelation'])
# Adding model 'State'
db.create_table('workflows_state', (
('id', orm['workflows.State:id']),
('name', orm['workflows.State:name']),
('workflow', orm['workflows.State:workflow']),
))
db.send_create_signal('workflows', ['State'])
# Adding model 'Transition'
db.create_table('workflows_transition', (
('id', orm['workflows.Transition:id']),
('name', orm['workflows.Transition:name']),
('workflow', orm['workflows.Transition:workflow']),
('destination', orm['workflows.Transition:destination']),
('condition', orm['workflows.Transition:condition']),
('permission', orm['workflows.Transition:permission']),
))
db.send_create_signal('workflows', ['Transition'])
# Adding model 'WorkflowObjectRelation'
db.create_table('workflows_workflowobjectrelation', (
('id', orm['workflows.WorkflowObjectRelation:id']),
('content_type', orm['workflows.WorkflowObjectRelation:content_type']),
('content_id', orm['workflows.WorkflowObjectRelation:content_id']),
('workflow', orm['workflows.WorkflowObjectRelation:workflow']),
))
db.send_create_signal('workflows', ['WorkflowObjectRelation'])
# Adding model 'StateObjectRelation'
db.create_table('workflows_stateobjectrelation', (
('id', orm['workflows.StateObjectRelation:id']),
('content_type', orm['workflows.StateObjectRelation:content_type']),
('content_id', orm['workflows.StateObjectRelation:content_id']),
('state', orm['workflows.StateObjectRelation:state']),
))
db.send_create_signal('workflows', ['StateObjectRelation'])
# Adding ManyToManyField 'State.transitions'
db.create_table('workflows_state_transitions', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('state', models.ForeignKey(orm.State, null=False)),
('transition', models.ForeignKey(orm.Transition, null=False))
))
# Creating unique_together for [content_type, content_id] on WorkflowObjectRelation.
db.create_unique('workflows_workflowobjectrelation', ['content_type_id', 'content_id'])
# Creating unique_together for [content_type, content_id, state] on StateObjectRelation.
db.create_unique('workflows_stateobjectrelation', ['content_type_id', 'content_id', 'state_id'])
# Creating unique_together for [workflow, permission] on WorkflowPermissionRelation.
db.create_unique('workflows_workflowpermissionrelation', ['workflow_id', 'permission_id'])
def backwards(self, orm):
# Deleting unique_together for [workflow, permission] on WorkflowPermissionRelation.
db.delete_unique('workflows_workflowpermissionrelation', ['workflow_id', 'permission_id'])
# Deleting unique_together for [content_type, content_id, state] on StateObjectRelation.
db.delete_unique('workflows_stateobjectrelation', ['content_type_id', 'content_id', 'state_id'])
# Deleting unique_together for [content_type, content_id] on WorkflowObjectRelation.
db.delete_unique('workflows_workflowobjectrelation', ['content_type_id', 'content_id'])
# Deleting model 'Workflow'
db.delete_table('workflows_workflow')
# Deleting model 'StatePermissionRelation'
db.delete_table('workflows_statepermissionrelation')
# Deleting model 'StateInheritanceBlock'
db.delete_table('workflows_stateinheritanceblock')
# Deleting model 'WorkflowModelRelation'
db.delete_table('workflows_workflowmodelrelation')
# Deleting model 'WorkflowPermissionRelation'
db.delete_table('workflows_workflowpermissionrelation')
# Deleting model 'State'
db.delete_table('workflows_state')
# Deleting model 'Transition'
db.delete_table('workflows_transition')
# Deleting model 'WorkflowObjectRelation'
db.delete_table('workflows_workflowobjectrelation')
# Deleting model 'StateObjectRelation'
db.delete_table('workflows_stateobjectrelation')
# Dropping ManyToManyField 'State.transitions'
db.delete_table('workflows_state_transitions')
models = {
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", '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'})
},
'permissions.permission': {
'codename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'content_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'permissions.role': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'})
},
'workflows.state': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'transitions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['workflows.Transition']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['workflows.Workflow']"})
},
'workflows.stateinheritanceblock': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']"}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"})
},
'workflows.stateobjectrelation': {
'Meta': {'unique_together': "(('content_type', 'content_id', 'state'),)"},
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'state_object'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"})
},
'workflows.statepermissionrelation': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']"}),
'role': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Role']"}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"})
},
'workflows.transition': {
'condition': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destination_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']", 'null': 'True', 'blank': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflow': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_state'", 'null': 'True', 'to': "orm['workflows.State']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['permissions.Permission']", 'symmetrical': 'False'})
},
'workflows.workflowmodelrelation': {
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']", 'unique': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'wmrs'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflowobjectrelation': {
'Meta': {'unique_together': "(('content_type', 'content_id'),)"},
'content_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_object'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'wors'", 'to': "orm['workflows.Workflow']"})
},
'workflows.workflowpermissionrelation': {
'Meta': {'unique_together': "(('workflow', 'permission'),)"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'permission': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'permissions'", 'to': "orm['permissions.Permission']"}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.Workflow']"})
}
}
complete_apps = ['workflows']

View file

357
workflows/models.py Normal file
View file

@ -0,0 +1,357 @@
from django.db import models
# django imports
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _
# permissions imports
import permissions.utils
from permissions.models import Permission
from permissions.models import Role
class Workflow(models.Model):
"""A workflow consists of a sequence of connected (through transitions)
states. It can be assigned to a model and / or model instances. If a
model instance has a workflow it takes precendence over the model's
workflow.
**Attributes:**
model
The model the workflow belongs to. Can be any
content
The object the workflow belongs to.
name
The unique name of the workflow.
states
The states of the workflow.
initial_state
The initial state the model / content gets if created.
"""
name = models.CharField(_(u"Name"), max_length=100, unique=True)
initial_state = models.ForeignKey("State", related_name="workflow_state", blank=True, null=True)
permissions = models.ManyToManyField(Permission, symmetrical=False, through="WorkflowPermissionRelation")
def __unicode__(self):
return self.name
def get_initial_state(self):
"""Returns the initial state of the workflow. Takes the first one if
no state has been defined.
"""
if self.initial_state:
return self.initial_state
else:
try:
return self.states.all()[0]
except IndexError:
return None
def get_objects(self):
"""Returns all objects which have this workflow assigned. Globally
(via the object's content type) or locally (via the object itself).
"""
import workflows.utils
objs = []
# Get all objects whose content type has this workflow
for wmr in WorkflowModelRelation.objects.filter(workflow=self):
ctype = wmr.content_type
# We have also to check whether the global workflow is not
# overwritten.
for obj in ctype.model_class().objects.all():
if workflows.utils.get_workflow(obj) == self:
objs.append(obj)
# Get all objects whose local workflow this workflow
for wor in WorkflowObjectRelation.objects.filter(workflow=self):
if wor.content not in objs:
objs.append(wor.content)
return objs
def set_to(self, ctype_or_obj):
"""Sets the workflow to passed content type or object. See the specific
methods for more information.
**Parameters:**
ctype_or_obj
The content type or the object to which the workflow should be set.
Can be either a ContentType instance or any Django model instance.
"""
if isinstance(ctype_or_obj, ContentType):
return self.set_to_model(ctype_or_obj)
else:
return self.set_to_object(ctype_or_obj)
def set_to_model(self, ctype):
"""Sets the workflow to the passed content type. If the content
type has already an assigned workflow the workflow is overwritten.
**Parameters:**
ctype
The content type which gets the workflow. Can be any Django model
instance.
"""
try:
wor = WorkflowModelRelation.objects.get(content_type=ctype)
except WorkflowModelRelation.DoesNotExist:
WorkflowModelRelation.objects.create(content_type=ctype, workflow=self)
else:
wor.workflow = self
wor.save()
def set_to_object(self, obj):
"""Sets the workflow to the passed object.
If the object has already the given workflow nothing happens. Otherwise
the workflow is set to the objectthe state is set to the workflow's
initial state.
**Parameters:**
obj
The object which gets the workflow.
"""
import workflows.utils
ctype = ContentType.objects.get_for_model(obj)
try:
wor = WorkflowObjectRelation.objects.get(content_type=ctype, content_id=obj.pk)
except WorkflowObjectRelation.DoesNotExist:
WorkflowObjectRelation.objects.create(content = obj, workflow=self)
workflows.utils.set_state(obj, self.initial_state)
else:
if wor.workflow != self:
wor.workflow = self
wor.save()
workflows.utils.set_state(self.initial_state)
class State(models.Model):
"""A certain state within workflow.
**Attributes:**
name
The unique name of the state within the workflow.
workflow
The workflow to which the state belongs.
transitions
The transitions of a workflow state.
"""
name = models.CharField(_(u"Name"), max_length=100)
workflow = models.ForeignKey(Workflow, verbose_name=_(u"Workflow"), related_name="states")
transitions = models.ManyToManyField("Transition", verbose_name=_(u"Transitions"), blank=True, null=True, related_name="states")
class Meta:
ordering = ("name", )
def __unicode__(self):
return "%s (%s)" % (self.name, self.workflow.name)
def get_allowed_transitions(self, obj, user):
"""Returns all allowed transitions for passed object and user.
"""
transitions = []
for transition in self.transitions.all():
permission = transition.permission
if permission is None:
transitions.append(transition)
else:
# First we try to get the objects specific has_permission
# method (in case the object inherits from the PermissionBase
# class).
try:
if obj.has_permission(user, permission.codename):
transitions.append(transition)
except AttributeError:
if permissions.utils.has_permission(obj, user, permission.codename):
transitions.append(transition)
return transitions
class Transition(models.Model):
"""A transition from a source to a destination state. The transition can
be used from several source states.
**Attributes:**
name
The unique name of the transition within a workflow.
workflow
The workflow to which the transition belongs. Must be a Workflow
instance.
destination
The state after a transition has been processed. Must be a State
instance.
condition
The condition when the transition is available. Can be any python
expression.
permission
The necessary permission to process the transition. Must be a
Permission instance.
"""
name = models.CharField(_(u"Name"), max_length=100)
workflow = models.ForeignKey(Workflow, verbose_name=_(u"Workflow"), related_name="transitions")
destination = models.ForeignKey(State, verbose_name=_(u"Destination"), null=True, blank=True, related_name="destination_state")
condition = models.CharField(_(u"Condition"), blank=True, max_length=100)
permission = models.ForeignKey(Permission, verbose_name=_(u"Permission"), blank=True, null=True)
def __unicode__(self):
return self.name
class StateObjectRelation(models.Model):
"""Stores the workflow state of an object.
Provides a way to give any object a workflow state without changing the
object's model.
**Attributes:**
content
The object for which the state is stored. This can be any instance of
a Django model.
state
The state of content. This must be a State instance.
"""
content_type = models.ForeignKey(ContentType, verbose_name=_(u"Content type"), related_name="state_object", blank=True, null=True)
content_id = models.PositiveIntegerField(_(u"Content id"), blank=True, null=True)
content = generic.GenericForeignKey(ct_field="content_type", fk_field="content_id")
state = models.ForeignKey(State, verbose_name = _(u"State"))
def __unicode__(self):
return "%s %s - %s" % (self.content_type.name, self.content_id, self.state.name)
class Meta:
unique_together = ("content_type", "content_id", "state")
class WorkflowObjectRelation(models.Model):
"""Stores an workflow of an object.
Provides a way to give any object a workflow without changing the object's
model.
**Attributes:**
content
The object for which the workflow is stored. This can be any instance of
a Django model.
workflow
The workflow which is assigned to an object. This needs to be a workflow
instance.
"""
content_type = models.ForeignKey(ContentType, verbose_name=_(u"Content type"), related_name="workflow_object", blank=True, null=True)
content_id = models.PositiveIntegerField(_(u"Content id"), blank=True, null=True)
content = generic.GenericForeignKey(ct_field="content_type", fk_field="content_id")
workflow = models.ForeignKey(Workflow, verbose_name=_(u"Workflow"), related_name="wors")
class Meta:
unique_together = ("content_type", "content_id")
def __unicode__(self):
return "%s %s - %s" % (self.content_type.name, self.content_id, self.workflow.name)
class WorkflowModelRelation(models.Model):
"""Stores an workflow for a model (ContentType).
Provides a way to give any object a workflow without changing the model.
**Attributes:**
Content Type
The content type for which the workflow is stored. This can be any
instance of a Django model.
workflow
The workflow which is assigned to an object. This needs to be a
workflow instance.
"""
content_type = models.ForeignKey(ContentType, verbose_name=_(u"Content Type"), unique=True)
workflow = models.ForeignKey(Workflow, verbose_name=_(u"Workflow"), related_name="wmrs")
def __unicode__(self):
return "%s - %s" % (self.content_type.name, self.workflow.name)
# Permissions relation #######################################################
class WorkflowPermissionRelation(models.Model):
"""Stores the permissions for which a workflow is responsible.
**Attributes:**
workflow
The workflow which is responsible for the permissions. Needs to be a
Workflow instance.
permission
The permission for which the workflow is responsible. Needs to be a
Permission instance.
"""
workflow = models.ForeignKey(Workflow)
permission = models.ForeignKey(Permission, related_name="permissions")
class Meta:
unique_together = ("workflow", "permission")
def __unicode__(self):
return "%s %s" % (self.workflow.name, self.permission.name)
class StateInheritanceBlock(models.Model):
"""Stores inheritance block for state and permission.
**Attributes:**
state
The state for which the inheritance is blocked. Needs to be a State
instance.
permission
The permission for which the instance is blocked. Needs to be a
Permission instance.
"""
state = models.ForeignKey(State, verbose_name=_(u"State"))
permission = models.ForeignKey(Permission, verbose_name=_(u"Permission"))
def __unicode__(self):
return "%s %s" % (self.state.name, self.permission.name)
class StatePermissionRelation(models.Model):
"""Stores granted permission for state and role.
**Attributes:**
state
The state for which the role has the permission. Needs to be a State
instance.
permission
The permission for which the workflow is responsible. Needs to be a
Permission instance.
role
The role for which the state has the permission. Needs to be a lfc
Role instance.
"""
state = models.ForeignKey(State, verbose_name=_(u"State"))
permission = models.ForeignKey(Permission, verbose_name=_(u"Permission"))
role = models.ForeignKey(Role, verbose_name=_(u"Role"))
def __unicode__(self):
return "%s %s %s" % (self.state.name, self.role.name, self.permission.name)

View file

@ -0,0 +1,10 @@
{% load i18n %}
<label>{{ state.name }}</label>
<select name="transition">
{% for transition in transitions %}
<option {% if transition.selected %}selected="selected"{% endif %}
value="{{ transition.id }}">
{{ transition.name }}
</option>
{% endfor %}
</select>

View file

Some files were not shown because too many files have changed in this diff Show more