Main views for state change and state history. See #582
- Legacy-Id: 2811
This commit is contained in:
parent
256dd73dd4
commit
7a2302d377
|
@ -4,12 +4,14 @@ 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)
|
||||
|
|
55
ietf/ietfworkflows/forms.py
Normal file
55
ietf/ietfworkflows/forms.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
from django import forms
|
||||
|
||||
from ietf.ietfworkflows.utils import (get_workflow_for_draft,
|
||||
get_state_for_draft)
|
||||
|
||||
|
||||
class StreamDraftForm(forms.Form):
|
||||
|
||||
can_cancel = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.draft = kwargs.pop('draft', None)
|
||||
self.user = kwargs.pop('user', None)
|
||||
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,
|
||||
}
|
||||
|
||||
|
||||
class DraftStateForm(StreamDraftForm):
|
||||
|
||||
comment = forms.CharField(widget=forms.Textarea)
|
||||
new_state = forms.ChoiceField()
|
||||
weeks = forms.IntegerField(required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DraftStateForm, self).__init__(*args, **kwargs)
|
||||
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.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_', '')
|
||||
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()]
|
|
@ -20,9 +20,8 @@ class ObjectHistoryEntry(models.Model):
|
|||
class Meta:
|
||||
ordering = ('-date', )
|
||||
|
||||
|
||||
def get_real_instance(self):
|
||||
if hasattr(self, '_real_instance'):
|
||||
if hasattr(self, '_real_instance'):
|
||||
return self._real_instance
|
||||
for i in ('objectworkflowhistoryentry', 'objectannotationtaghistoryentry', 'objectstreamhistoryentry'):
|
||||
try:
|
||||
|
@ -118,6 +117,13 @@ class WGWorkflow(Workflow):
|
|||
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)
|
||||
|
@ -133,7 +139,7 @@ class Stream(models.Model):
|
|||
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")
|
||||
|
|
|
@ -12,7 +12,6 @@ register = template.Library()
|
|||
@register.inclusion_tag('ietfworkflows/stream_state.html', takes_context=True)
|
||||
def stream_state(context, doc):
|
||||
request = context.get('request', None)
|
||||
user = request and request.user
|
||||
data = {}
|
||||
stream = get_stream_from_wrapper(doc)
|
||||
data.update({'stream': stream})
|
||||
|
|
|
@ -4,4 +4,7 @@ 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/tags/$', 'edit_tags', name='edit_tags'),
|
||||
url(r'^(?P<name>[^/]+)/edit/stream/$', 'edit_stream', name='edit_stream'),
|
||||
)
|
||||
|
|
|
@ -10,7 +10,7 @@ from workflows.models import State
|
|||
from workflows.utils import (get_workflow_for_object, set_workflow_for_object,
|
||||
get_state)
|
||||
|
||||
from ietf.ietfworkflows.streams import get_streamed_draft
|
||||
from ietf.ietfworkflows.streams import get_streamed_draft, get_stream_from_draft
|
||||
from ietf.ietfworkflows.models import (WGWorkflow, AnnotationTagObjectRelation,
|
||||
AnnotationTag, ObjectAnnotationTagHistoryEntry,
|
||||
ObjectHistoryEntry)
|
||||
|
@ -96,9 +96,13 @@ def get_workflow_for_draft(draft):
|
|||
return workflow
|
||||
|
||||
|
||||
def get_workflow_history_for_draft(draft):
|
||||
def get_workflow_history_for_draft(draft, entry_type=None):
|
||||
ctype = ContentType.objects.get_for_model(draft)
|
||||
history = ObjectHistoryEntry.objects.filter(content_type=ctype, content_id=draft.pk).\
|
||||
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
|
||||
|
@ -207,3 +211,14 @@ def update_tags(obj, comment, person, set_tags=[], reset_tags=[], extra_notify=[
|
|||
comment=comment,
|
||||
person=person)
|
||||
notify_tag_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,
|
||||
)
|
||||
|
|
|
@ -1,37 +1,20 @@
|
|||
from ietf.idtracker.models import IETFWG, InternetDraft, IESGLogin
|
||||
from ietf.idtracker.models import 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.forms import DraftStateForm
|
||||
from ietf.ietfworkflows.streams import (get_stream_from_draft,
|
||||
get_streamed_draft)
|
||||
from ietf.ietfworkflows.utils import (get_workflow_for_wg,
|
||||
get_default_workflow_for_wg,
|
||||
get_workflow_history_for_draft,
|
||||
from ietf.ietfworkflows.utils import (get_workflow_history_for_draft,
|
||||
get_workflow_for_draft,
|
||||
get_state_by_name,
|
||||
get_annotation_tags_for_draft,
|
||||
get_state_for_draft, WAITING_WRITEUP,
|
||||
FOLLOWUP_TAG)
|
||||
get_state_for_draft)
|
||||
|
||||
|
||||
REDUCED_HISTORY_LEN = 20
|
||||
|
||||
|
||||
def stream_history(request, name):
|
||||
user = request.user
|
||||
person = get_person_for_user(user)
|
||||
draft = get_object_or_404(InternetDraft, filename=name)
|
||||
streamed = get_streamed_draft(draft)
|
||||
stream = get_stream_from_draft(draft)
|
||||
|
@ -58,3 +41,35 @@ def stream_history(request, name):
|
|||
'history': history[:REDUCED_HISTORY_LEN],
|
||||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def edit_state(request, name):
|
||||
user = request.user
|
||||
draft = get_object_or_404(InternetDraft, filename=name)
|
||||
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,
|
||||
'stream': stream,
|
||||
'workflow': workflow,
|
||||
'history': history,
|
||||
'tags': tags,
|
||||
'form': form,
|
||||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def edit_tags(request, name):
|
||||
pass
|
||||
|
||||
|
||||
def edit_stream(request, name):
|
||||
pass
|
||||
|
|
101
ietf/templates/ietfworkflows/state_edit.html
Normal file
101
ietf/templates/ietfworkflows/state_edit.html
Normal file
|
@ -0,0 +1,101 @@
|
|||
{% 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; border-bottom: 1px dashed #cccccc; }
|
||||
table.edit-form ul li, table.edit-form div.free-change { padding: 10px 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-bottom: 1em; }
|
||||
table.edit-form div.error { border: 1px solid red; background-color: #ffeebb; padding: 5px 10px; }
|
||||
{% endblock morecss %}
|
||||
|
||||
{% block title %}Change state for {{ draft }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Change state for {{ draft }}</h1>
|
||||
|
||||
<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%;">
|
||||
{{ state.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 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>
|
||||
|
||||
<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 %}
|
Loading…
Reference in a new issue