diff --git a/ietf/ietfworkflows/admin.py b/ietf/ietfworkflows/admin.py index d282d7aa9..0e9d7c6d7 100644 --- a/ietf/ietfworkflows/admin.py +++ b/ietf/ietfworkflows/admin.py @@ -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) diff --git a/ietf/ietfworkflows/forms.py b/ietf/ietfworkflows/forms.py new file mode 100644 index 000000000..32cf9f399 --- /dev/null +++ b/ietf/ietfworkflows/forms.py @@ -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()] diff --git a/ietf/ietfworkflows/models.py b/ietf/ietfworkflows/models.py index ede8ac995..62701d979 100644 --- a/ietf/ietfworkflows/models.py +++ b/ietf/ietfworkflows/models.py @@ -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") diff --git a/ietf/ietfworkflows/templatetags/ietf_streams.py b/ietf/ietfworkflows/templatetags/ietf_streams.py index f18d7709e..b26963b9f 100644 --- a/ietf/ietfworkflows/templatetags/ietf_streams.py +++ b/ietf/ietfworkflows/templatetags/ietf_streams.py @@ -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}) diff --git a/ietf/ietfworkflows/urls.py b/ietf/ietfworkflows/urls.py index 7ea564563..7b93d997d 100644 --- a/ietf/ietfworkflows/urls.py +++ b/ietf/ietfworkflows/urls.py @@ -4,4 +4,7 @@ from django.conf.urls.defaults import patterns, url urlpatterns = patterns('ietf.ietfworkflows.views', url(r'^(?P[^/]+)/history/$', 'stream_history', name='stream_history'), + url(r'^(?P[^/]+)/edit/state/$', 'edit_state', name='edit_state'), + url(r'^(?P[^/]+)/edit/tags/$', 'edit_tags', name='edit_tags'), + url(r'^(?P[^/]+)/edit/stream/$', 'edit_stream', name='edit_stream'), ) diff --git a/ietf/ietfworkflows/utils.py b/ietf/ietfworkflows/utils.py index 3f40b614b..821c53eda 100644 --- a/ietf/ietfworkflows/utils.py +++ b/ietf/ietfworkflows/utils.py @@ -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, + ) diff --git a/ietf/ietfworkflows/views.py b/ietf/ietfworkflows/views.py index a11f3b3d0..a278ba03b 100644 --- a/ietf/ietfworkflows/views.py +++ b/ietf/ietfworkflows/views.py @@ -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 diff --git a/ietf/templates/ietfworkflows/state_edit.html b/ietf/templates/ietfworkflows/state_edit.html new file mode 100644 index 000000000..a50f05c9f --- /dev/null +++ b/ietf/templates/ietfworkflows/state_edit.html @@ -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 %} +

Change state for {{ draft }}

+ + + + + + + + +
Current streamCurrent stateAnnotation tags
+ {{ state.name|default:"None" }} + + {{ state.name|default:"None" }} + +
    + {% for tag in tags%} +
  • {{ tag.annotation_tag }}
  • + {% endfor %} +
+
+
+ +
+ + + + + + +
1. Input information about change2. Select the new state
+
+ {{ form.errors.comment }} + Comment: *
+ +
+
+ {{ form.errors.weeks }} + Estimated time in next status:
+ (in weeks) +
+
+ {% with form.get_transitions as transitions %} + {% if transitions %} +
    + {% for transition in transitions %} +
  • + + Changes state to: {{ transition.destination.name }} +
  • + {% endfor %} + {% endif %} +
+ {% endwith %} +
+ {{ form.errors.new_state }} + + +
+
+
+ +
+State history + + {% if history %} + + {% for baseentry in history %} + {% with baseentry.get_real_instance as entry %} + + + + {% endwith %} + {% endfor %} + {% else %} + + {% endif %} +
DatePersonChangeComment
{{ entry.date }}{{ entry.person }}{{ entry.describe_change|safe }}{{ entry.comment }}
There is no state history for this document.
+{% endblock %}