diff --git a/ietf/templates/wgchairs/manage_workflowREDESIGN.html b/ietf/templates/wginfo/customize_workflow.html similarity index 80% rename from ietf/templates/wgchairs/manage_workflowREDESIGN.html rename to ietf/templates/wginfo/customize_workflow.html index 4a385afaf..d1c939e64 100644 --- a/ietf/templates/wgchairs/manage_workflowREDESIGN.html +++ b/ietf/templates/wginfo/customize_workflow.html @@ -1,13 +1,6 @@ -{% extends "wginfo/wg_base.html" %} +{% extends "base.html" %} -{% block wg_titledetail %}Manage Workflow{% endblock %} - -{% block pagehead %} -{{ block.super }} - - - -{% endblock pagehead %} +{% block title %}Customize Workflow for {{ group.acronym }} {{ group.type.name }}{% endblock %} {% block morecss %} {{ block.super }} @@ -53,13 +46,20 @@ } {% endblock %} -{% block wg_content %} -
-

Edit workflow

+{% block content %} +{% load ietf_filters %} -

Below you can customize the draft states and tags used in the {{ wg.acronym }} WG. Note that some states are mandatory for WG operation and cannot be deactivated.

+
+ +

Customize Workflow for {{ group.acronym }} {{ group.type.name }}

+ +

Below you can customize the draft states and tags used in the +{{ group.acronym }} {{ group.type.name }}. Note that some states are +mandatory for group operation and cannot be deactivated.

+ +

You can see the default Working Group I-D State Diagram +in Section 4.1 of RFC6174.

-

You can see the default Working Group I-D State Diagram in Section 4.1 of RFC6174.

States

@@ -90,11 +90,7 @@ {% endif %} -
- {{ state.name }} {% if not state.used %} (not used in {{ wg.acronym }}){% endif %} - + -
-
{{ state.desc|safe|linebreaks }}
+ {{ state.name }} {% if not state.used %} (not used in {{ group.acronym }}){% endif %} {{ state|statehelp }}
@@ -142,11 +138,14 @@ - {{ tag.name }} {% if not tag.used %} (not used in {{ wg.acronym }}){% endif %} + {{ tag.name }} {% if not tag.used %} (not used in {{ group.acronym }}){% endif %} {% endfor %} +{% endblock content %} + +{% block js %} - {% endblock %} diff --git a/ietf/templates/wginfo/group_base.html b/ietf/templates/wginfo/group_base.html index ef5000cd0..1496a7e57 100644 --- a/ietf/templates/wginfo/group_base.html +++ b/ietf/templates/wginfo/group_base.html @@ -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 wgchairs_tags %} +{% load ietf_filters %} {% block title %}{{ group.name }} ({{ group.acronym }}) - {% block group_subtitle %}{% endblock %}{% endblock %} {% block morecss %} @@ -73,18 +73,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Documents | Charter | - {% if can_manage_workflow %} - Manage workflow | - {% endif %} - - {% if can_manage_delegates %} - Manage delegations | - {% endif %} - - {% if can_manage_shepherds %} - Manage shepherds | - {% endif %} - History | {% if group.list_archive|startswith:"http:" or group.list_archive|startswith:"https:" or group.list_archive|startswith:"ftp:" %} List Archive » | diff --git a/ietf/templates/wginfo/group_charter.html b/ietf/templates/wginfo/group_charter.html index fb4d448b1..7175748a3 100644 --- a/ietf/templates/wginfo/group_charter.html +++ b/ietf/templates/wginfo/group_charter.html @@ -130,7 +130,7 @@ is occasionally incorrect. {% if user|has_role:"Area Director,Secretariat" %}
{% for name, url in actions %} - {{ name }} + {{ name }} {% if not forloop.last %} | {% endif %} {% endfor %}
{% endif %} diff --git a/ietf/wgchairs/urls.py b/ietf/wgchairs/urls.py index d8cadb8ee..b9b32c240 100644 --- a/ietf/wgchairs/urls.py +++ b/ietf/wgchairs/urls.py @@ -3,7 +3,5 @@ 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'), ) diff --git a/ietf/wgchairs/views.py b/ietf/wgchairs/views.py index 3bcd6e026..1f9552e3d 100644 --- a/ietf/wgchairs/views.py +++ b/ietf/wgchairs/views.py @@ -51,133 +51,6 @@ 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 don't have 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 manage_workflowREDESIGN(request, acronym): - from ietf.doc.models import State - from ietf.group.models import GroupStateTransitions - - MANDATORY_STATES = ('c-adopt', 'wg-doc', 'sub-pub') - - 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 don't have permission to access this view") - - if request.method == 'POST': - action = request.POST.get("action") - if action == "setstateactive": - active = request.POST.get("active") == "1" - try: - state = State.objects.exclude(slug__in=MANDATORY_STATES).get(pk=request.POST.get("state")) - except State.DoesNotExist: - return HttpResponse("Invalid state %s" % request.POST.get("state")) - - if active: - wg.unused_states.remove(state) - else: - wg.unused_states.add(state) - - if action == "setnextstates": - try: - state = State.objects.get(pk=request.POST.get("state")) - except State.DoesNotExist: - return HttpResponse("Invalid state %s" % request.POST.get("state")) - - next_states = State.objects.filter(used=True, type='draft-stream-ietf', pk__in=request.POST.getlist("next_states")) - unused = wg.unused_states.all() - if set(next_states.exclude(pk__in=unused)) == set(state.next_states.exclude(pk__in=unused)): - # just use the default - wg.groupstatetransitions_set.filter(state=state).delete() - else: - transitions, _ = GroupStateTransitions.objects.get_or_create(group=wg, state=state) - transitions.next_states = next_states - - if action == "settagactive": - active = request.POST.get("active") == "1" - try: - tag = DocTagName.objects.get(pk=request.POST.get("tag")) - except DocTagName.DoesNotExist: - return HttpResponse("Invalid tag %s" % request.POST.get("tag")) - - if active: - wg.unused_tags.remove(tag) - else: - wg.unused_tags.add(tag) - - - # put some info for the template on tags and states - unused_tags = wg.unused_tags.all().values_list('slug', flat=True) - tags = DocTagName.objects.filter(slug__in=get_tags_for_stream_id("ietf")) - for t in tags: - t.used = t.slug not in unused_tags - - unused_states = wg.unused_states.all().values_list('slug', flat=True) - states = State.objects.filter(used=True, type="draft-stream-ietf") - transitions = dict((o.state, o) for o in wg.groupstatetransitions_set.all()) - for s in states: - s.used = s.slug not in unused_states - s.mandatory = s.slug in MANDATORY_STATES - - default_n = s.next_states.all() - if s in transitions: - n = transitions[s].next_states.all() - else: - n = default_n - - s.next_states_checkboxes = [(x in n, x in default_n, x) for x in states] - s.used_next_states = [x for x in n if x.slug not in unused_states] - - return render_to_response('wgchairs/manage_workflowREDESIGN.html', - {'wg': wg, - 'states': states, - 'tags': tags, - 'selected': 'manage_workflow', - }, RequestContext(request)) - - -if settings.USE_DB_REDESIGN_PROXY_CLASSES: - manage_workflow = manage_workflowREDESIGN - def wg_shepherd_documents(request, acronym): wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1) user = request.user diff --git a/ietf/wginfo/edit.py b/ietf/wginfo/edit.py index 670d876c5..eb73783c0 100644 --- a/ietf/wginfo/edit.py +++ b/ietf/wginfo/edit.py @@ -20,7 +20,7 @@ from ietf.group.models import * from ietf.group.utils import save_group_in_history from ietf.wgcharter.mails import email_secretariat from ietf.person.forms import EmailsField - +from ietf.doc.utils import get_tags_for_stream_id class WGForm(forms.Form): name = forms.CharField(max_length=255, label="WG Name", required=True) @@ -320,3 +320,81 @@ def conclude(request, acronym): dict(form=form, wg=wg), context_instance=RequestContext(request)) + + +def customize_workflow(request, acronym): + MANDATORY_STATES = ('c-adopt', 'wg-doc', 'sub-pub') + + group = get_object_or_404(Group, acronym=acronym, type="wg") + if not request.user.is_authenticated() or not (has_role(request.user, "Secretariat") or group.role_set.filter(name="chair", person__user=request.user)): + return HttpResponseForbidden("You don't have permission to access this view") + + if request.method == 'POST': + action = request.POST.get("action") + if action == "setstateactive": + active = request.POST.get("active") == "1" + try: + state = State.objects.exclude(slug__in=MANDATORY_STATES).get(pk=request.POST.get("state")) + except State.DoesNotExist: + return HttpResponse("Invalid state %s" % request.POST.get("state")) + + if active: + group.unused_states.remove(state) + else: + group.unused_states.add(state) + + if action == "setnextstates": + try: + state = State.objects.get(pk=request.POST.get("state")) + except State.DoesNotExist: + return HttpResponse("Invalid state %s" % request.POST.get("state")) + + next_states = State.objects.filter(used=True, type='draft-stream-ietf', pk__in=request.POST.getlist("next_states")) + unused = group.unused_states.all() + if set(next_states.exclude(pk__in=unused)) == set(state.next_states.exclude(pk__in=unused)): + # just use the default + group.groupstatetransitions_set.filter(state=state).delete() + else: + transitions, _ = GroupStateTransitions.objects.get_or_create(group=group, state=state) + transitions.next_states = next_states + + if action == "settagactive": + active = request.POST.get("active") == "1" + try: + tag = DocTagName.objects.get(pk=request.POST.get("tag")) + except DocTagName.DoesNotExist: + return HttpResponse("Invalid tag %s" % request.POST.get("tag")) + + if active: + group.unused_tags.remove(tag) + else: + group.unused_tags.add(tag) + + + # put some info for the template on tags and states + unused_tags = group.unused_tags.all().values_list('slug', flat=True) + tags = DocTagName.objects.filter(slug__in=get_tags_for_stream_id("ietf")) + for t in tags: + t.used = t.slug not in unused_tags + + unused_states = group.unused_states.all().values_list('slug', flat=True) + states = State.objects.filter(used=True, type="draft-stream-ietf") + transitions = dict((o.state, o) for o in group.groupstatetransitions_set.all()) + for s in states: + s.used = s.slug not in unused_states + s.mandatory = s.slug in MANDATORY_STATES + + default_n = s.next_states.all() + if s in transitions: + n = transitions[s].next_states.all() + else: + n = default_n + + s.next_states_checkboxes = [(x in n, x in default_n, x) for x in states] + s.used_next_states = [x for x in n if x.slug not in unused_states] + + return render_to_response('wginfo/customize_workflow.html', { + 'group': group, + 'states': states, + 'tags': tags, + }, RequestContext(request)) diff --git a/ietf/wginfo/urls.py b/ietf/wginfo/urls.py index 956ee2de6..bad932b21 100644 --- a/ietf/wginfo/urls.py +++ b/ietf/wginfo/urls.py @@ -29,6 +29,6 @@ urlpatterns = patterns('', (r'^(?P[a-zA-Z0-9-]+)/milestones/charter/$', milestones.edit_milestones, {'milestone_set': "charter"}, "wg_edit_charter_milestones"), (r'^(?P[a-zA-Z0-9-]+)/milestones/charter/reset/$', milestones.reset_charter_milestones, None, "wg_reset_charter_milestones"), (r'^(?P[a-zA-Z0-9-]+)/ajax/searchdocs/$', milestones.ajax_search_docs, None, "wg_ajax_search_docs"), + (r'^(?P[a-zA-Z0-9-]+)/workflow/$', edit.customize_workflow), (r'^(?P[^/]+)/management/', include('ietf.wgchairs.urls')), - ) diff --git a/ietf/wginfo/views.py b/ietf/wginfo/views.py index 446c1ba59..b45310929 100644 --- a/ietf/wginfo/views.py +++ b/ietf/wginfo/views.py @@ -49,10 +49,6 @@ from ietf.person.models import Email from ietf.group.utils import get_charter_text from ietf.doc.templatetags.ietf_filters import clean_whitespace -from ietf.wgchairs.accounts import (can_manage_workflow_in_group, - can_manage_delegates_in_group, - can_manage_shepherds_in_group) - def fill_in_charter_info(group, include_drafts=False): group.areadirector = group.ad.role_email("ad", group.parent) if group.ad else None @@ -179,9 +175,6 @@ def construct_group_menu_context(request, group, selected, others): d = { "group": group, "selected": selected, - "can_manage_delegates": can_manage_delegates_in_group(request.user, group), - "can_manage_workflow": can_manage_workflow_in_group(request.user, group), - "can_manage_shepherds": can_manage_shepherds_in_group(request.user, group), } d.update(others) @@ -274,6 +267,10 @@ def group_charter(request, acronym): is_chair = request.user.is_authenticated() and group.role_set.filter(name="chair", person__user=request.user) + if is_chair or has_role(request.user, "Secretariat"): + actions.append((u"Manage delegates", urlreverse("manage_delegates", kwargs=dict(acronym=group.acronym)))) + actions.append((u"Customize workflow", urlreverse("ietf.wginfo.edit.customize_workflow", kwargs=dict(acronym=group.acronym)))) + return render_to_response('wginfo/group_charter.html', construct_group_menu_context(request, group, "charter", { "actions": actions,