Allow to edit the stream/state/tags of a draft. Fixes #582

- Legacy-Id: 2818
This commit is contained in:
Emilio A. Sánchez López 2011-02-07 19:44:54 +00:00
parent 3f13f31569
commit 53ad5be094
13 changed files with 496 additions and 106 deletions

View file

@ -48,6 +48,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]*)$")
@ -109,25 +110,6 @@ def document_main(request, name):
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
@ -141,6 +123,7 @@ def document_main(request, name):
return render_to_response('idrfc/doc_main_id.html',
{'content1':content1, 'content2':content2,
'doc':doc, 'info':info,
'stream_info': get_full_info_for_draft(id),
'versions':versions, 'history':history},
context_instance=RequestContext(request));

View file

@ -1,16 +1,31 @@
from django import forms
import datetime
from django import forms
from django.template.loader import render_to_string
from workflows.models import State
from ietf.idtracker.models import PersonOrOrgInfo
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_state_for_draft)
get_state_for_draft,
update_state, FOLLOWUP_TAG,
get_annotation_tags_for_draft,
update_tags, update_stream)
from ietf.ietfworkflows.streams import get_stream_from_draft
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)
@ -22,6 +37,9 @@ class StreamDraftForm(forms.Form):
'value': msg_value,
}
def __unicode__(self):
return render_to_string(self.template, {'form': self})
class DraftStateForm(StreamDraftForm):
@ -29,17 +47,19 @@ class DraftStateForm(StreamDraftForm):
new_state = forms.ChoiceField()
weeks = forms.IntegerField(required=False)
template = 'ietfworkflows/state_form.html'
def __init__(self, *args, **kwargs):
super(DraftStateForm, 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.workflow = get_workflow_for_draft(self.draft)
self.state = get_state_for_draft(self.draft)
self.fields['new_state'].choices = self.get_states()
def get_new_state(self, key):
transition_id = key.replace('transition_', '')
@ -53,3 +73,78 @@ class DraftStateForm(StreamDraftForm):
def get_states(self):
return [(i.pk, i.name) for i in self.workflow.get_states()]
def save(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)
class DraftTagsForm(StreamDraftForm):
comment = forms.CharField(widget=forms.Textarea)
tags = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, required=False)
template = 'ietfworkflows/tags_form.html'
def __init__(self, *args, **kwargs):
super(DraftTagsForm, self).__init__(*args, **kwargs)
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 save(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
update_tags(self.draft,
comment=comment,
person=self.person,
set_tags=set_tags,
reset_tags=reset_tags,
extra_notify=extra_notify)
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,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

@ -98,7 +98,7 @@ class AnnotationTagObjectRelation(models.Model):
class StateObjectRelationMetadata(models.Model):
relation = models.ForeignKey(StateObjectRelation)
from_date = models.DateTimeField(_('Initial date'))
from_date = models.DateTimeField(_('Initial date'), blank=True, null=True)
estimated_date = models.DateTimeField(_('Estimated date'), blank=True, null=True)

View file

@ -1,5 +1,7 @@
from django.db import models
from workflows.utils import set_workflow_for_object
from ietf.idrfc.idrfc_wrapper import IdRfcWrapper, IdWrapper
from ietf.ietfworkflows.models import StreamedID, Stream
@ -82,3 +84,13 @@ def get_stream_from_wrapper(idrfc_wrapper):
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()
set_workflow_for_object(draft, stream.workflow)
return streamed.stream

View file

@ -10,11 +10,12 @@ 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
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)
ObjectWorkflowHistoryEntry, ObjectStreamHistoryEntry)
WAITING_WRITEUP = 'WG Consensus: Waiting for Write-Up'
@ -133,23 +134,25 @@ def get_annotation_tag_by_name(tag_name):
return None
def set_tag_by_name(obj, tag_name):
def set_tag(obj, tag):
ctype = ContentType.objects.get_for_model(obj)
try:
tag = AnnotationTag.objects.get(name=tag_name)
(relation, created) = AnnotationTagObjectRelation.objects.get_or_create(
content_type=ctype,
content_id=obj.pk,
annotation_tag=tag)
except AnnotationTag.DoesNotExist:
return None
(relation, created) = AnnotationTagObjectRelation.objects.get_or_create(
content_type=ctype,
content_id=obj.pk,
annotation_tag=tag)
return relation
def reset_tag_by_name(obj, tag_name):
ctype = ContentType.objects.get_for_model(obj)
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,
@ -158,6 +161,12 @@ def reset_tag_by_name(obj, tag_name):
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
@ -208,16 +217,28 @@ 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 name in set_tags:
if set_tag_by_name(obj, name):
setted.append(name)
for name in reset_tags:
if reset_tag_by_name(obj, name):
resetted.append(name)
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,
@ -238,14 +259,29 @@ def update_state(obj, comment, person, to_state, estimated_date=None, extra_noti
entry = ObjectWorkflowHistoryEntry.objects.create(
content_type=ctype,
content_id=obj.pk,
from_state=from_state.name,
to_state=to_state.name,
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),

View file

@ -2,7 +2,8 @@ from ietf.idtracker.models import InternetDraft
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from ietf.ietfworkflows.forms import DraftStateForm
from ietf.ietfworkflows.forms import (DraftStateForm, DraftTagsForm,
DraftStreamForm)
from ietf.ietfworkflows.streams import (get_stream_from_draft,
get_streamed_draft)
from ietf.ietfworkflows.utils import (get_workflow_history_for_draft,
@ -43,18 +44,21 @@ def stream_history(request, name):
context_instance=RequestContext(request))
def edit_state(request, name):
def edit_state(request, name, form_class=DraftStateForm):
user = request.user
draft = get_object_or_404(InternetDraft, filename=name)
if request.method == 'POST':
form = form_class(user=user, draft=draft, data=request.POST)
if form.is_valid():
form.save()
form = form_class(user=user, draft=draft)
else:
form = form_class(user=user, draft=draft)
state = get_state_for_draft(draft)
stream = get_stream_from_draft(draft)
workflow = get_workflow_for_draft(draft)
history = get_workflow_history_for_draft(draft, 'objectworkflowhistoryentry')
tags = get_annotation_tags_for_draft(draft)
if request.method == 'POST':
form = DraftStateForm(user=user, draft=draft, data=request.POST)
else:
form = DraftStateForm(user=user, draft=draft)
return render_to_response('ietfworkflows/state_edit.html',
{'draft': draft,
'state': state,
@ -68,8 +72,8 @@ def edit_state(request, name):
def edit_tags(request, name):
pass
return edit_state(request, name, DraftTagsForm)
def edit_stream(request, name):
pass
return edit_state(request, name, DraftStreamForm)

View file

@ -39,19 +39,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% 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>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>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 %}

View file

@ -11,7 +11,12 @@ 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-bottom: 1em; }
table.edit-form div.submit-row { margin: 1em 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: 1em 2em; }
table.edit-form-tags ul li { padding: 0px; }
{% endblock morecss %}
{% block title %}Change state for {{ draft }}{% endblock %}
@ -26,7 +31,7 @@ table.edit-form div.error { border: 1px solid red; background-color: #ffeebb; pa
<th>Annotation tags</th>
</tr>
<tr><td style="width: 25%;">
{{ state.name|default:"None" }}
{{ stream.name|default:"None" }}
</td>
<td style="width: 25%;">
{{ state.name|default:"None" }}
@ -39,48 +44,7 @@ table.edit-form div.error { border: 1px solid red; background-color: #ffeebb; pa
</td></tr></table>
<br />
<form action="" method="post">
<table class="ietf-table edit-form" style="width: 100%;">
<tr>
<th>1. Input information about change</th>
<th>2. Select the new state</th>
</tr>
<tr><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 style="padding: 0px; vertical-align: top;">
{% 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>
{{ form }}
<br />
<strong>State history</strong>

View file

@ -0,0 +1,42 @@
<form action="" method="post">
<table class="ietf-table edit-form" style="width: 100%;">
<tr>
<th>1. Input information about change</th>
<th>2. Select the new state</th>
</tr>
<tr><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 style="padding: 0px; vertical-align: top;">
{% 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,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,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>