# Copyright The IETF Trust 2008, All Rights Reserved # Portion Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). # All rights reserved. Contact: Pasi Eronen # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # * Neither the name of the Nokia Corporation and/or its # subsidiary(-ies) nor the names of its contributors may be used # to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # 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. import itertools from django.shortcuts import get_object_or_404, render_to_response from django.template import RequestContext from django.http import HttpResponse from django.conf import settings from django.core.urlresolvers import reverse as urlreverse from ietf.doc.views_search import SearchForm, retrieve_search_results from ietf.group.models import Group, GroupURL, Role from ietf.doc.models import State, DocAlias, RelatedDocument from ietf.doc.utils import get_chartering_type from ietf.group.utils import get_charter_text from ietf.doc.templatetags.ietf_filters import clean_whitespace from ietf.ietfauth.utils import has_role def roles(group, role_name): return Role.objects.filter(group=group, name=role_name).select_related("email", "person") def fill_in_charter_info(group, include_drafts=False): group.areadirector = group.ad.role_email("ad", group.parent) if group.ad else None group.chairs = roles(group, "chair") group.techadvisors = roles(group, "techadv") group.editors = roles(group, "editor") group.secretaries = roles(group, "secr") milestone_state = "charter" if group.state_id == "proposed" else "active" group.milestones = group.groupmilestone_set.filter(state=milestone_state).order_by('due') if group.charter: group.charter_text = get_charter_text(group) else: group.charter_text = u"Not chartered yet." if include_drafts: aliases = DocAlias.objects.filter(document__type="draft", document__group=group).select_related('document').order_by("name") group.drafts = [] group.rfcs = [] for a in aliases: if a.name.startswith("draft"): group.drafts.append(a) else: group.rfcs.append(a) a.rel = RelatedDocument.objects.filter(source=a.document).distinct() a.invrel = RelatedDocument.objects.filter(target=a).distinct() def extract_last_name(role): return role.person.name_parts()[3] def wg_summary_area(request): areas = Group.objects.filter(type="area", state="active").order_by("name") for area in areas: area.ads = sorted(roles(area, "ad"), key=extract_last_name) area.groups = Group.objects.filter(parent=area, type="wg", state="active").order_by("acronym") for group in area.groups: group.chairs = sorted(roles(group, "chair"), key=extract_last_name) areas = [a for a in areas if a.groups] return render_to_response('wginfo/1wg-summary.txt', { 'areas': areas }, content_type='text/plain; charset=UTF-8') def wg_summary_acronym(request): areas = Group.objects.filter(type="area", state="active").order_by("name") groups = Group.objects.filter(type="wg", state="active").order_by("acronym").select_related("parent") for group in groups: group.chairs = sorted(roles(group, "chair"), key=extract_last_name) return render_to_response('wginfo/1wg-summary-by-acronym.txt', { 'areas': areas, 'groups': groups }, content_type='text/plain; charset=UTF-8') def wg_charters(request): areas = Group.objects.filter(type="area", state="active").order_by("name") for area in areas: area.ads = sorted(roles(area, "ad"), key=extract_last_name) area.groups = Group.objects.filter(parent=area, type="wg", state="active").order_by("name") for group in area.groups: fill_in_charter_info(group, include_drafts=True) group.area = area return render_to_response('wginfo/1wg-charters.txt', { 'areas': areas }, content_type='text/plain; charset=UTF-8') def wg_charters_by_acronym(request): areas = dict((a.id, a) for a in Group.objects.filter(type="area", state="active").order_by("name")) for area in areas.itervalues(): area.ads = sorted(roles(area, "ad"), key=extract_last_name) groups = Group.objects.filter(type="wg", state="active").exclude(parent=None).order_by("acronym") for group in groups: fill_in_charter_info(group, include_drafts=True) group.area = areas.get(group.parent_id) return render_to_response('wginfo/1wg-charters-by-acronym.txt', { 'groups': groups }, content_type='text/plain; charset=UTF-8') def active_wgs(request): areas = Group.objects.filter(type="area", state="active").order_by("name") for area in areas: # dig out information for template area.ads = (list(sorted(roles(area, "ad"), key=extract_last_name)) + list(sorted(roles(area, "pre-ad"), key=extract_last_name))) area.groups = Group.objects.filter(parent=area, type="wg", state="active").order_by("acronym") area.urls = area.groupurl_set.all().order_by("name") for group in area.groups: group.chairs = sorted(roles(group, "chair"), key=extract_last_name) return render_to_response('wginfo/active_wgs.html', {'areas':areas}, RequestContext(request)) def bofs(request): groups = Group.objects.filter(type="wg", state="bof") return render_to_response('wginfo/bofs.html',dict(groups=groups), RequestContext(request)) def chartering_wgs(request): charter_states = State.objects.filter(used=True, type="charter").exclude(slug__in=("approved", "notrev")) groups = Group.objects.filter(type="wg", charter__states__in=charter_states).select_related("state", "charter") for g in groups: g.chartering_type = get_chartering_type(g.charter) return render_to_response('wginfo/chartering_wgs.html', dict(charter_states=charter_states, groups=groups), RequestContext(request)) def construct_group_menu_context(request, group, selected, others): """Return context with info for the group menu filled in.""" actions = [] is_chair = group.has_role(request.user, "chair") is_ad_or_secretariat = has_role(request.user, ("Area Director", "Secretariat")) if group.state_id != "proposed" and (is_chair or is_ad_or_secretariat): actions.append((u"Add or edit milestones", urlreverse("wg_edit_milestones", kwargs=dict(acronym=group.acronym)))) if group.state_id != "conclude" and is_ad_or_secretariat: actions.append((u"Edit group", urlreverse("group_edit", kwargs=dict(acronym=group.acronym)))) if is_chair or is_ad_or_secretariat: actions.append((u"Customize workflow", urlreverse("ietf.wginfo.edit.customize_workflow", kwargs=dict(acronym=group.acronym)))) if group.state_id in ("active", "dormant") and is_ad_or_secretariat: actions.append((u"Request closing group", urlreverse("wg_conclude", kwargs=dict(acronym=group.acronym)))) d = { "group": group, "selected": selected, "menu_actions": actions, } d.update(others) return d def search_for_group_documents(group): form = SearchForm({ 'by':'group', 'group': group.acronym or "", 'rfcs':'on', 'activedrafts': 'on' }) docs, meta = retrieve_search_results(form) # get the related docs form_related = SearchForm({ 'by':'group', 'name': u'-%s-' % group.acronym, 'activedrafts': 'on' }) raw_docs_related, meta_related = retrieve_search_results(form_related) docs_related = [] for d in raw_docs_related: parts = d.name.split("-", 2); # canonical form draft--wg-etc if len(parts) >= 3 and parts[1] != "ietf" and parts[2].startswith(group.acronym + "-"): d.search_heading = "Related Internet-Draft" docs_related.append(d) # move call for WG adoption to related cleaned_docs = [] docs_related_names = set(d.name for d in docs_related) for d in docs: if d.stream_id and d.get_state_slug("draft-stream-%s" % d.stream_id) in ("c-adopt", "wg-cand"): if d.name not in docs_related_names: d.search_heading = "Related Internet-Draft" docs_related.append(d) else: cleaned_docs.append(d) docs = cleaned_docs docs_related.sort(key=lambda d: d.name) return docs, meta, docs_related, meta_related def group_documents(request, acronym): group = get_object_or_404(Group, type="wg", acronym=acronym) docs, meta, docs_related, meta_related = search_for_group_documents(group) return render_to_response('wginfo/group_documents.html', construct_group_menu_context(request, group, "documents", { 'docs': docs, 'meta': meta, 'docs_related': docs_related, 'meta_related': meta_related }), RequestContext(request)) def group_documents_txt(request, acronym): """Return tabulator-separated rows with documents for group.""" group = get_object_or_404(Group, type="wg", acronym=acronym) docs, meta, docs_related, meta_related = search_for_group_documents(group) for d in docs: d.prefix = d.get_state().name for d in docs_related: d.prefix = u"Related %s" % d.get_state().name rows = [] for d in itertools.chain(docs, docs_related): rfc_number = d.rfc_number() if rfc_number != None: name = rfc_number else: name = "%s-%s" % (d.name, d.rev) rows.append(u"\t".join((d.prefix, name, clean_whitespace(d.title)))) return HttpResponse(u"\n".join(rows), content_type='text/plain; charset=UTF-8') def group_charter(request, acronym): group = get_object_or_404(Group, type="wg", acronym=acronym) fill_in_charter_info(group, include_drafts=False) group.delegates = roles(group, "delegate") e = group.latest_event(type__in=("changed_state", "requested_close",)) requested_close = group.state_id != "conclude" and e and e.type == "requested_close" return render_to_response('wginfo/group_charter.html', construct_group_menu_context(request, group, "charter", { "milestones_in_review": group.groupmilestone_set.filter(state="review"), "requested_close": requested_close, }), RequestContext(request)) def history(request, acronym): group = get_object_or_404(Group, acronym=acronym) events = group.groupevent_set.all().select_related('by').order_by('-time', '-id') return render_to_response('wginfo/history.html', construct_group_menu_context(request, group, "history", { "events": events, }), RequestContext(request))