From d43159cd90217d66490c18248929326365676f69 Mon Sep 17 00:00:00 2001 From: Ole Laursen <olau@iola.dk> Date: Fri, 3 Feb 2012 16:22:31 +0000 Subject: [PATCH] Add support for incoming ADs with a new "pre-ad" role - Legacy-Id: 3900 --- ietf/idrfc/testsREDESIGN.py | 16 ++++++++++++++++ ietf/idrfc/views_ballot.py | 12 ++++++++---- ietf/idrfc/views_search.py | 9 ++++++--- ietf/idtracker/templatetags/ietf_filters.py | 2 +- ietf/ietfauth/decorators.py | 4 ++-- ietf/templates/wginfo/wg-dirREDESIGN.html | 2 +- ietf/wgchairs/accounts.py | 2 +- ietf/wginfo/views.py | 11 ++++++++++- redesign/importing/import-roles.py | 15 ++++++++++++--- 9 files changed, 57 insertions(+), 16 deletions(-) diff --git a/ietf/idrfc/testsREDESIGN.py b/ietf/idrfc/testsREDESIGN.py index b99cc3ea4..e09b4885d 100644 --- a/ietf/idrfc/testsREDESIGN.py +++ b/ietf/idrfc/testsREDESIGN.py @@ -500,6 +500,22 @@ class EditPositionTestCase(django.test.TestCase): self.assertEquals(pos.discuss, "Test discuss text") self.assertTrue("New position" in pos.desc) self.assertTrue("by Sec" in pos.desc) + + def test_cannot_edit_position_as_pre_ad(self): + draft = make_test_data() + url = urlreverse('doc_edit_position', kwargs=dict(name=draft.name)) + + # transform to pre-ad + ad_role = Role.objects.filter(name="ad")[0] + ad_role.name_id = "pre-ad" + ad_role.save() + + # we can see + login_testing_unauthorized(self, ad_role.person.user.username, url) + + # but not touch + r = self.client.post(url, dict(position="discuss", discuss="Test discuss text")) + self.assertEquals(r.status_code, 403) def test_send_ballot_comment(self): draft = make_test_data() diff --git a/ietf/idrfc/views_ballot.py b/ietf/idrfc/views_ballot.py index 2e4d96271..a7a240171 100644 --- a/ietf/idrfc/views_ballot.py +++ b/ietf/idrfc/views_ballot.py @@ -3,7 +3,7 @@ import re, os from datetime import datetime, date, time, timedelta -from django.http import HttpResponse, HttpResponseRedirect, Http404 +from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404 from django.shortcuts import render_to_response, get_object_or_404 from django.core.urlresolvers import reverse as urlreverse from django.template.loader import render_to_string @@ -15,7 +15,7 @@ from django.conf import settings from ietf.utils.mail import send_mail_text, send_mail_preformatted from ietf.ietfauth.decorators import group_required from ietf.idtracker.templatetags.ietf_filters import in_group -from ietf.ietfauth.decorators import has_role +from ietf.ietfauth.decorators import has_role, role_required from ietf.idtracker.models import * from ietf.iesg.models import * from ietf.ipr.models import IprDetail @@ -222,7 +222,7 @@ class EditPositionFormREDESIGN(forms.Form): raise forms.ValidationError("You must enter a non-empty discuss") return entered_discuss -@group_required('Area_Director','Secretariat') +@role_required('Area Director','Secretariat') def edit_positionREDESIGN(request, name): """Vote and edit discuss and comment on Internet Draft as Area Director.""" doc = get_object_or_404(Document, docalias__name=name) @@ -238,7 +238,7 @@ def edit_positionREDESIGN(request, name): return_to_url = doc.get_absolute_url() # if we're in the Secretariat, we can select an AD to act as stand-in for - if not has_role(request.user, "Area Director"): + if has_role(request.user, "Secretariat"): ad_id = request.GET.get('ad') if not ad_id: raise Http404() @@ -248,6 +248,10 @@ def edit_positionREDESIGN(request, name): old_pos = doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad=ad, time__gte=started_process.time) if request.method == 'POST': + if not has_role(request.user, "Secretariat") and not ad.role_set.filter(name="ad", group__type="area", group__state="active"): + # prevent pre-ADs from voting + return HttpResponseForbidden("Must be a proper Area Director in an active area to cast ballot") + form = EditPositionForm(request.POST) if form.is_valid(): diff --git a/ietf/idrfc/views_search.py b/ietf/idrfc/views_search.py index 55e15eac6..971447122 100644 --- a/ietf/idrfc/views_search.py +++ b/ietf/idrfc/views_search.py @@ -301,7 +301,9 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES: active_ads = list(Person.objects.filter(role__name="ad", role__group__type="area", role__group__state="active").distinct()) - inactive_ads = list(Person.objects.filter(pk__in=responsible) + inactive_ads = list((Person.objects.filter(pk__in=responsible) | Person.objects.filter(role__name="pre-ad", + role__group__type="area", + role__group__state="active")) .exclude(pk__in=[x.pk for x in active_ads])) extract_last_name = lambda x: x.name_parts()[3] active_ads.sort(key=extract_last_name) @@ -568,10 +570,11 @@ def by_ad(request, name): ad_name = None if settings.USE_DB_REDESIGN_PROXY_CLASSES: responsible = Document.objects.values_list('ad', flat=True).distinct() - for p in Person.objects.filter(Q(role__name="ad", + for p in Person.objects.filter(Q(role__name__in=("pre-ad", "ad"), role__group__type="area", role__group__state="active") - | Q(pk__in=responsible)): + | Q(pk__in=responsible)).distinct(): + print name, p.full_name_as_key() if name == p.full_name_as_key(): ad_id = p.id ad_name = p.plain_name() diff --git a/ietf/idtracker/templatetags/ietf_filters.py b/ietf/idtracker/templatetags/ietf_filters.py index 4bb35bc49..f01f06f6d 100644 --- a/ietf/idtracker/templatetags/ietf_filters.py +++ b/ietf/idtracker/templatetags/ietf_filters.py @@ -436,7 +436,7 @@ def stable_dictsort(value, arg): def ad_area(user): if user and user.is_authenticated(): from ietf.group.models import Group - g = Group.objects.filter(role__name="ad", role__person__user=user) + g = Group.objects.filter(role__name__in=("pre-ad", "ad"), role__person__user=user) if g: return g[0].acronym return None diff --git a/ietf/ietfauth/decorators.py b/ietf/ietfauth/decorators.py index a5d74e12f..a599bc746 100644 --- a/ietf/ietfauth/decorators.py +++ b/ietf/ietfauth/decorators.py @@ -79,7 +79,7 @@ def has_role(user, role_names): return False role_qs = { - "Area Director": Q(person=person, name="ad", group__type="area", group__state="active"), + "Area Director": Q(person=person, name__in=("pre-ad", "ad"), group__type="area", group__state="active"), "Secretariat": Q(person=person, name="secr", group__acronym="secretariat"), "IANA": Q(person=person, name="auth", group__acronym="iana"), "WG Chair": Q(person=person,name="chair", group__type="wg", group__state="active"), @@ -97,7 +97,7 @@ def role_required(*role_names): """View decorator for checking that the user is logged in and has one of the listed roles.""" return passes_test_decorator(lambda u: has_role(u, role_names), - "Restricted to role%s %s" % ("s" if len(role_names) != 1 else "", ",".join(role_names))) + "Restricted to role%s %s" % ("s" if len(role_names) != 1 else "", ", ".join(role_names))) if settings.USE_DB_REDESIGN_PROXY_CLASSES: # overwrite group_required diff --git a/ietf/templates/wginfo/wg-dirREDESIGN.html b/ietf/templates/wginfo/wg-dirREDESIGN.html index 212528123..a74f48ba9 100644 --- a/ietf/templates/wginfo/wg-dirREDESIGN.html +++ b/ietf/templates/wginfo/wg-dirREDESIGN.html @@ -58,7 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <p>Area Director{{ forloop.revcounter|pluralize }}:</p> <table style="margin-left: 2em" class="ietf-wg-table"> {% endif %} - <tr><td><span class="square bgcolor{{forloop.counter}}"> </span></td> <td><a href="mailto:{{ ad.address }}">{{ ad.person.plain_name }} <{{ ad.address }}></a></td></tr> + <tr><td><span class="square bgcolor{{forloop.counter}}"> </span></td> <td><a href="mailto:{{ ad.address }}">{{ ad.person.plain_name }} <{{ ad.address }}></a>{% if ad.incoming %} (Incoming AD){% endif %}</td></tr> {% if forloop.last %} </table> {% endif %} diff --git a/ietf/wgchairs/accounts.py b/ietf/wgchairs/accounts.py index 0741f1189..e668edefe 100644 --- a/ietf/wgchairs/accounts.py +++ b/ietf/wgchairs/accounts.py @@ -11,7 +11,7 @@ def is_area_director_for_group(person, group): return bool(group.area.area.areadirector_set.filter(person=person).count()) def is_area_director_for_groupREDESIGN(person, group): - return bool(Role.objects.filter(group=group.parent, person=person, name="ad")) + return bool(Role.objects.filter(group=group.parent, person=person, name=("ad", "pre-ad"))) def is_group_chair(person, group): diff --git a/ietf/wginfo/views.py b/ietf/wginfo/views.py index be68ec5db..85fb51835 100644 --- a/ietf/wginfo/views.py +++ b/ietf/wginfo/views.py @@ -99,7 +99,16 @@ def wg_dirREDESIGN(request): areas = Group.objects.filter(type="area", state="active").order_by("name") for area in areas: - area.ads = sorted(Email.objects.filter(role__group=area, role__name="ad").select_related("person"), key=lambda e: e.person.name_parts()[3]) + area.ads = [] + for e in Email.objects.filter(role__group=area, role__name="ad").select_related("person"): + e.incoming = False + area.ads.append(e) + + for e in Email.objects.filter(role__group=area, role__name="pre-ad").select_related("person"): + e.incoming = True + area.ads.append(e) + + area.ads.sort(key=lambda e: (e.incoming, e.person.name_parts()[3])) area.wgs = Group.objects.filter(parent=area, type="wg", state="active").order_by("acronym") area.urls = area.groupurl_set.all().order_by("name") for wg in area.wgs: diff --git a/redesign/importing/import-roles.py b/redesign/importing/import-roles.py index 63283e60e..bfae4c62b 100755 --- a/redesign/importing/import-roles.py +++ b/redesign/importing/import-roles.py @@ -33,6 +33,7 @@ from ietf.utils.history import * # SDOAuthorizedIndividual, WGDelegate area_director_role = name(RoleName, "ad", "Area Director") +pre_area_director_role = name(RoleName, "pre-ad", "Incoming Area Director") chair_role = name(RoleName, "chair", "Chair") editor_role = name(RoleName, "editor", "Editor") secretary_role = name(RoleName, "secr", "Secretary") @@ -237,14 +238,22 @@ for o in AreaDirector.objects.all(): area = Group.objects.get(acronym=o.area.area_acronym.acronym) - r = Role.objects.filter(name=area_director_role, + role_type = area_director_role + + try: + if IESGLogin.objects.get(person=o.person).user_level == 4: + role_type = pre_area_director_role + except IESGLogin.DoesNotExist: + pass + + r = Role.objects.filter(name=role_type, person=email.person) if r and r[0].group == "iesg": r[0].group = area - r[0].name = area_director_role + r[0].name = role_type r[0].save() else: - Role.objects.get_or_create(name=area_director_role, group=area, person=email.person, email=email) + Role.objects.get_or_create(name=role_type, group=area, person=email.person, email=email) # IESGHistory emails_for_time = {}