parent
c5dd835e41
commit
204a4dd72b
135
ietf/templates/wgchairs/manage_workflow.html
Normal file
135
ietf/templates/wgchairs/manage_workflow.html
Normal file
|
@ -0,0 +1,135 @@
|
|||
{% extends "wginfo/wg_base.html" %}
|
||||
|
||||
{% block wg_titledetail %}Manage Workflow{% endblock %}
|
||||
|
||||
{% 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">
|
||||
<form action="#info" method="POST">
|
||||
<table class="ietf-table">
|
||||
<tr>
|
||||
<th>Used in {{ wg }}</th><th>Available states</th>
|
||||
</tr>
|
||||
{% for state in default_states %}
|
||||
<tr class="{% cycle "oddrow" "evenrow" %}">
|
||||
<td><input type="checkbox" id="id_states_{{ state.pk }}" name="states" value="{{ state.pk }}" {% if state.used %}checked="checked" {% endif %}/></td>
|
||||
<td><label for="id_states_{{ state.pk }}">{{ state.name }}</label></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<input type="submit" name="update_states" value="Update states" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="transitions">
|
||||
<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" 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>
|
||||
|
||||
<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 %}
|
|
@ -2,12 +2,17 @@ from django import forms
|
|||
from django.db.models import Q
|
||||
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
|
||||
from ietf.wgchairs.accounts import get_person_for_user
|
||||
from ietf.ietfworkflows.utils import get_default_workflow_for_wg, get_workflow_for_wg
|
||||
from ietf.idtracker.models import PersonOrOrgInfo
|
||||
|
||||
from workflows.models import Transition
|
||||
|
||||
|
||||
class RelatedWGForm(forms.Form):
|
||||
|
||||
|
@ -28,6 +33,131 @@ class RelatedWGForm(forms.Form):
|
|||
}
|
||||
|
||||
|
||||
class TagForm(RelatedWGForm):
|
||||
|
||||
tags = forms.ModelMultipleChoiceField(get_default_workflow_for_wg().annotation_tags.all(),
|
||||
widget=forms.CheckboxSelectMultiple)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
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()
|
||||
|
@ -148,7 +278,6 @@ class NotExistDelegateForm(MultipleDelegateForm):
|
|||
from_email=settings.DEFAULT_FROM_EMAIL)
|
||||
mail.send()
|
||||
|
||||
|
||||
def send_email_to_delegate(self, email):
|
||||
self.send_email(email, 'wgchairs/notexistsdelegate_delegate_email.txt')
|
||||
|
||||
|
@ -187,55 +316,52 @@ def add_form_factory(request, wg, user):
|
|||
class ManagingShepherdForm(forms.Form):
|
||||
email = forms.EmailField(required=False)
|
||||
is_assign_current = forms.BooleanField(required=False)
|
||||
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if kwargs.has_key('current_person'):
|
||||
self.current_person = kwargs.pop('current_person')
|
||||
if 'current_person' in kwargs.keys():
|
||||
self.current_person = kwargs.pop('current_person')
|
||||
return super(ManagingShepherdForm, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
def clean_email(self):
|
||||
email = self.cleaned_data.get('email')
|
||||
if not email:
|
||||
return None
|
||||
|
||||
|
||||
try:
|
||||
PersonOrOrgInfo.objects. \
|
||||
filter(emailaddress__type__in=[ "INET", "Prim",],
|
||||
emailaddress__address=email) \
|
||||
[:1].get()
|
||||
filter(emailaddress__type__in=["INET", "Prim", ],
|
||||
emailaddress__address=email)[:1].get()
|
||||
except PersonOrOrgInfo.DoesNotExist:
|
||||
if self.cleaned_data.get('is_assign_current'):
|
||||
self._send_email(email)
|
||||
raise forms.ValidationError("Person with such email does not exist")
|
||||
return email
|
||||
|
||||
|
||||
def clean(self):
|
||||
print self.cleaned_data.get('email') and self.cleaned_data.get('is_assign_current')
|
||||
if self.cleaned_data.get('email') and \
|
||||
self.cleaned_data.get('is_assign_current'):
|
||||
raise forms.ValidationError("You should choose to assign to current \
|
||||
person or input the email. Not both at te same time. ")
|
||||
|
||||
|
||||
return self.cleaned_data
|
||||
|
||||
|
||||
def change_shepherd(self, document, save=True):
|
||||
email = self.cleaned_data.get('email')
|
||||
email = self.cleaned_data.get('email')
|
||||
if email:
|
||||
person = PersonOrOrgInfo.objects. \
|
||||
filter(emailaddress__type__in=[ "INET", "Prim",],
|
||||
emailaddress__address=email) \
|
||||
[:1].get()
|
||||
filter(emailaddress__type__in=["INET", "Prim", ],
|
||||
emailaddress__address=email)[:1].get()
|
||||
else:
|
||||
person = self.current_person
|
||||
document.shepherd = person
|
||||
if save:
|
||||
person = self.current_person
|
||||
document.shepherd = person
|
||||
if save:
|
||||
document.save()
|
||||
return document
|
||||
|
||||
def _send_email(self, email,
|
||||
|
||||
def _send_email(self, email,
|
||||
template='wgchairs/edit_management_shepherd_email.txt'):
|
||||
subject = 'WG Delegate needs system credentials'
|
||||
subject = 'WG Delegate needs system credentials'
|
||||
body = render_to_string(template,
|
||||
{'email': email,
|
||||
})
|
||||
|
|
|
@ -5,9 +5,13 @@ from django.http import HttpResponseForbidden
|
|||
|
||||
from ietf.idrfc.views_search import SearchForm, search_query
|
||||
from ietf.wgchairs.forms import (RemoveDelegateForm, add_form_factory,
|
||||
ManagingShepherdForm)
|
||||
ManagingShepherdForm, workflow_form_factory,
|
||||
TransitionFormSet)
|
||||
from ietf.wgchairs.accounts import (can_manage_delegates_in_group, get_person_for_user,
|
||||
can_manage_shepherds_in_group)
|
||||
can_manage_shepherds_in_group,
|
||||
can_manage_workflow_in_group)
|
||||
from ietf.ietfworkflows.utils import (get_workflow_for_wg,
|
||||
get_default_workflow_for_wg)
|
||||
|
||||
|
||||
def manage_delegates(request, acronym):
|
||||
|
@ -34,6 +38,45 @@ def manage_delegates(request, acronym):
|
|||
}, 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()
|
||||
default_states = default_workflow.states.all()
|
||||
for i in default_states:
|
||||
if states.filter(name=i.name).count() == 1:
|
||||
i.used = 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,
|
||||
}, RequestContext(request))
|
||||
|
||||
|
||||
def managing_shepherd(request, acronym, name):
|
||||
"""
|
||||
View for managing the assigned shepherd of a document.
|
||||
|
@ -61,11 +104,11 @@ def wg_shepherd_documents(request, acronym):
|
|||
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'})
|
||||
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)
|
||||
(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)
|
||||
|
|
Loading…
Reference in a new issue