Added 9 new group features, and changed list-like char fields to json fields, to get better support for using the values as lists. Modified code to use the group features instead of explicit lists of group types in many places in the code.
- Legacy-Id: 15908
This commit is contained in:
parent
d59eb23fd4
commit
57a4c9f41f
|
@ -47,12 +47,8 @@ def can_manage_community_list(user, clist):
|
|||
if has_role(user, 'Secretariat'):
|
||||
return True
|
||||
|
||||
if clist.group.type_id == 'area':
|
||||
return Role.objects.filter(name__slug='ad', person__user=user, group=clist.group).exists()
|
||||
elif clist.group.type_id in ('wg', 'rg', 'ag'):
|
||||
return Role.objects.filter(name__slug='chair', person__user=user, group=clist.group).exists()
|
||||
elif clist.group.type_id in ('program'):
|
||||
return Role.objects.filter(name__slug='lead', person__user=user, group=clist.group).exists()
|
||||
if clist.group.type_id in ['area', 'wg', 'rg', 'ag', 'program', ]:
|
||||
return Role.objects.filter(name__slug__in=clist.group.features.admin_roles, person__user=user, group=clist.group).exists()
|
||||
|
||||
return False
|
||||
|
||||
|
|
|
@ -269,7 +269,9 @@ def generate_approval_mail_rfc_editor(request, doc):
|
|||
def generate_publication_request(request, doc):
|
||||
group_description = ""
|
||||
if doc.group and doc.group.acronym != "none":
|
||||
group_description = doc.group.name_with_acronym()
|
||||
group_description = doc.group.name
|
||||
if doc.group.type_id not in ("ietf", "irtf", "iab",):
|
||||
group_description += " %s (%s)" % (doc.group.type, doc.group.acronym)
|
||||
|
||||
e = doc.latest_event(ConsensusDocEvent, type="changed_consensus")
|
||||
consensus = e.consensus if e else None
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django import template
|
||||
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.models import Group, Role
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
@ -9,18 +9,11 @@ def managed_groups(user):
|
|||
if not (user and hasattr(user, "is_authenticated") and user.is_authenticated):
|
||||
return []
|
||||
|
||||
groups = []
|
||||
# groups.extend(Group.objects.filter(
|
||||
# role__name__slug='ad',
|
||||
# role__person__user=user,
|
||||
# type__slug='area',
|
||||
# state__slug='active').select_related("type"))
|
||||
|
||||
groups.extend(Group.objects.filter(
|
||||
role__name__slug__in=['chair', 'delegate', 'ad', ],
|
||||
groups = [ g for g in Group.objects.filter(
|
||||
role__person__user=user,
|
||||
type__slug__in=('rg', 'wg', 'ag', 'ietf'),
|
||||
state__slug__in=('active', 'bof')).select_related("type"))
|
||||
type__features__has_session_materials=True,
|
||||
state__slug__in=('active', 'bof')).select_related("type")
|
||||
if Role.objects.filter(group=g, person__user=user, name__slug__in=g.type.features.matman_roles) ]
|
||||
|
||||
return groups
|
||||
|
||||
|
|
|
@ -887,17 +887,17 @@ class DocTestCase(TestCase):
|
|||
self.client.login(username='iab-chair', password='iab-chair+password')
|
||||
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc.name)))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue("Request publication" not in unicontent(r))
|
||||
self.assertNotIn("Request publication", unicontent(r))
|
||||
|
||||
Document.objects.filter(pk=doc.pk).update(stream='iab')
|
||||
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc.name)))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue("Request publication" in unicontent(r))
|
||||
self.assertIn("Request publication", unicontent(r))
|
||||
|
||||
doc.states.add(State.objects.get(type_id='draft-stream-iab',slug='rfc-edit'))
|
||||
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc.name)))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue("Request publication" not in unicontent(r))
|
||||
self.assertNotIn("Request publication", unicontent(r))
|
||||
|
||||
|
||||
def test_document_bibtex(self):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright The IETF Trust 2016, All Rights Reserved
|
||||
# Copyright The IETF Trust 2016-2018, All Rights Reserved
|
||||
|
||||
|
||||
# Parts Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
|
||||
|
@ -160,11 +161,14 @@ def document_main(request, name, rev=None):
|
|||
iesg_state_summary = doc.friendly_state()
|
||||
can_edit = has_role(request.user, ("Area Director", "Secretariat"))
|
||||
stream_slugs = StreamName.objects.values_list("slug", flat=True)
|
||||
can_change_stream = bool(can_edit or (
|
||||
request.user.is_authenticated and
|
||||
Role.objects.filter(name__in=("chair", "secr", "auth", "delegate"),
|
||||
group__acronym__in=stream_slugs,
|
||||
person__user=request.user)))
|
||||
# For some reason, AnonymousUser has __iter__, but is not iterable,
|
||||
# which causes problems in the filter() below. Work around this:
|
||||
if request.user.is_authenticated:
|
||||
roles = [ r for r in Role.objects.filter(group__acronym__in=stream_slugs, person__user=request.user)
|
||||
if r.name.slug in r.group.type.features.matman_roles ]
|
||||
else:
|
||||
roles = []
|
||||
can_change_stream = bool(can_edit or roles)
|
||||
can_edit_iana_state = has_role(request.user, ("Secretariat", "IANA"))
|
||||
|
||||
can_edit_replaces = has_role(request.user, ("Area Director", "Secretariat", "IRTF Chair", "WG Chair", "RG Chair", "WG Secretary", "RG Secretary"))
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# Copyright The IETF Trust 2010-2019, All Rights Reserved
|
||||
|
||||
# changing state and metadata on Internet Drafts
|
||||
|
||||
import datetime
|
||||
|
@ -31,7 +33,7 @@ from ietf.doc.utils import ( add_state_change_event, can_adopt_draft, can_unadop
|
|||
set_replaces_for_document, default_consensus, tags_suffix, )
|
||||
from ietf.doc.lastcall import request_last_call
|
||||
from ietf.doc.fields import SearchableDocAliasesField
|
||||
from ietf.group.models import Group, Role
|
||||
from ietf.group.models import Group, Role, GroupFeatures
|
||||
from ietf.iesg.models import TelechatDate
|
||||
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, user_is_person, is_individual_draft_author
|
||||
from ietf.ietfauth.utils import role_required
|
||||
|
@ -1294,13 +1296,15 @@ def request_publication(request, name):
|
|||
)
|
||||
|
||||
class AdoptDraftForm(forms.Form):
|
||||
group = forms.ModelChoiceField(queryset=Group.objects.filter(type__in=["wg", "rg"], state="active").order_by("-type", "acronym"), required=True, empty_label=None)
|
||||
group = forms.ModelChoiceField(queryset=Group.objects.filter(type__features__acts_like_wg=True, state="active").order_by("-type", "acronym"), required=True, empty_label=None)
|
||||
newstate = forms.ModelChoiceField(queryset=State.objects.filter(type__in=['draft-stream-ietf','draft-stream-irtf'], used=True).exclude(slug__in=settings.GROUP_STATES_WITH_EXTRA_PROCESSING), required=True, label="State")
|
||||
comment = forms.CharField(widget=forms.Textarea, required=False, label="Comment", help_text="Optional comment explaining the reasons for the adoption.", strip=False)
|
||||
weeks = forms.IntegerField(required=False, label="Expected weeks in adoption state")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
user = kwargs.pop("user")
|
||||
rg_features = GroupFeatures.objects.get(type_id='rg')
|
||||
wg_features = GroupFeatures.objects.get(type_id='wg')
|
||||
|
||||
super(AdoptDraftForm, self).__init__(*args, **kwargs)
|
||||
|
||||
|
@ -1308,17 +1312,21 @@ class AdoptDraftForm(forms.Form):
|
|||
if has_role(user, "Secretariat"):
|
||||
state_types.update(['draft-stream-ietf','draft-stream-irtf'])
|
||||
else:
|
||||
if has_role(user, "IRTF Chair") or Group.objects.filter(type="rg", state="active", role__person__user=user, role__name__in=("chair", "delegate", "secr")).exists():
|
||||
if has_role(user, "IRTF Chair") or Group.objects.filter(type="rg", state="active", role__person__user=user, role__name__in=rg_features.matman_roles).exists():
|
||||
state_types.add('draft-stream-irtf')
|
||||
if Group.objects.filter(type="wg", state="active", role__person__user=user, role__name__in=("chair", "delegate", "secr")).exists():
|
||||
if Group.objects.filter(type="wg", state="active", role__person__user=user, role__name__in=wg_features.matman_roles).exists():
|
||||
state_types.add('draft-stream-ietf')
|
||||
|
||||
|
||||
|
||||
|
||||
state_choices = State.objects.filter(type__in=state_types, used=True).exclude(slug__in=settings.GROUP_STATES_WITH_EXTRA_PROCESSING)
|
||||
|
||||
if not has_role(user, "Secretariat"):
|
||||
if has_role(user, "IRTF Chair"):
|
||||
group_queryset = self.fields["group"].queryset.filter(Q(role__person__user=user, role__name__in=("chair", "delegate", "secr"))|Q(type="rg", state="active")).distinct()
|
||||
group_queryset = self.fields["group"].queryset.filter(Q(role__person__user=user, role__name__in=rg_features.matman_roles)|Q(type="rg", state="active")).distinct()
|
||||
else:
|
||||
group_queryset = self.fields["group"].queryset.filter(role__person__user=user, role__name__in=("chair", "delegate", "secr")).distinct()
|
||||
group_queryset = self.fields["group"].queryset.filter(role__person__user=user, role__name__in=wg_features.matman_roles).distinct()
|
||||
self.fields["group"].queryset = group_queryset
|
||||
|
||||
self.fields['group'].choices = [(g.pk, '%s - %s' % (g.acronym, g.name)) for g in self.fields["group"].queryset]
|
||||
|
|
|
@ -102,20 +102,29 @@ admin.site.register(Group, GroupAdmin)
|
|||
|
||||
class GroupFeaturesAdmin(admin.ModelAdmin):
|
||||
list_display = [
|
||||
|
||||
'type',
|
||||
'customize_workflow',
|
||||
'has_chartering_process',
|
||||
'has_default_jabber',
|
||||
'has_dependencies',
|
||||
'has_documents',
|
||||
'has_nonsession_materials',
|
||||
'has_milestones',
|
||||
'has_chartering_process',
|
||||
'has_documents',
|
||||
'has_dependencies',
|
||||
'has_session_materials',
|
||||
'has_nonsession_materials',
|
||||
'has_meetings',
|
||||
'has_reviews',
|
||||
'material_types',
|
||||
'has_default_jabber',
|
||||
'acts_like_wg',
|
||||
'create_wiki',
|
||||
'custom_group_roles',
|
||||
'customize_workflow',
|
||||
'is_schedulable',
|
||||
'show_on_agenda',
|
||||
'req_subm_approval',
|
||||
'agenda_type',
|
||||
'material_types',
|
||||
'admin_roles',
|
||||
'about_page',
|
||||
'default_tab',
|
||||
'matman_roles',
|
||||
'role_order',
|
||||
]
|
||||
admin.site.register(GroupFeatures, GroupFeaturesAdmin)
|
||||
|
||||
|
|
107
ietf/group/migrations/0004_add_group_feature_fields.py
Normal file
107
ietf/group/migrations/0004_add_group_feature_fields.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
# Copyright The IETF Trust 2019, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-10 07:51
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0003_groupfeatures_data'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='groupfeatures',
|
||||
name='acts_like_wg',
|
||||
field=models.BooleanField(default=False, verbose_name=b'WG-Like'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='groupfeatures',
|
||||
name='create_wiki',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Wiki'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='groupfeatures',
|
||||
name='custom_group_roles',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Group Roles'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='groupfeatures',
|
||||
name='has_session_materials',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Materials'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='groupfeatures',
|
||||
name='is_schedulable',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Schedulable'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='groupfeatures',
|
||||
name='role_order',
|
||||
field=models.CharField(default=b'chair,secr,member', help_text=b'The order in which roles are shown, for instance on photo pages', max_length=128, validators=[django.core.validators.RegexValidator(code=b'invalid', message=b'Enter a comma-separated list of role slugs', regex=b'[a-z0-9_-]+(,[a-z0-9_-]+)*')]),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='groupfeatures',
|
||||
name='show_on_agenda',
|
||||
field=models.BooleanField(default=False, verbose_name=b'On Agenda'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='groupfeatures',
|
||||
name='req_subm_approval',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Subm. Approval'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='groupfeatures',
|
||||
name='matman_roles',
|
||||
field=models.CharField(default=b'ad,chair,delegate,secr', max_length=64, validators=[django.core.validators.RegexValidator(code=b'invalid', message=b'Enter a comma-separated list of role slugs', regex=b'[a-z0-9_-]+(,[a-z0-9_-]+)*')]),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='acts_like_wg',
|
||||
field=models.BooleanField(default=False, verbose_name=b'WG-Like'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='create_wiki',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Wiki'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='custom_group_roles',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Group Roles'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='has_session_materials',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Materials'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='is_schedulable',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Schedulable'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='role_order',
|
||||
field=models.CharField(default=b'chair,secr,member', help_text=b'The order in which roles are shown, for instance on photo pages', max_length=128, validators=[django.core.validators.RegexValidator(code=b'invalid', message=b'Enter a comma-separated list of role slugs', regex=b'[a-z0-9_-]+(,[a-z0-9_-]+)*')]),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='show_on_agenda',
|
||||
field=models.BooleanField(default=False, verbose_name=b'On Agenda'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='req_subm_approval',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Subm. Approval'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='matman_roles',
|
||||
field=models.CharField(default=b'ad,chair,delegate,secr', max_length=64, validators=[django.core.validators.RegexValidator(code=b'invalid', message=b'Enter a comma-separated list of role slugs', regex=b'[a-z0-9_-]+(,[a-z0-9_-]+)*')]),
|
||||
),
|
||||
]
|
|
@ -1,21 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.17 on 2018-12-18 23:49
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0003_groupfeatures_data'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='agenda_type',
|
||||
field=models.ForeignKey(blank=True, db_constraint=False, default=b'ietf', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='name.AgendaTypeName'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,49 @@
|
|||
# Copyright The IETF Trust 2019, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-09 09:02
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
import re
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
GroupFeatures = apps.get_model('group', 'GroupFeatures')
|
||||
for f in GroupFeatures.objects.all():
|
||||
for a in ['material_types', 'admin_roles', 'matman_roles', 'role_order']:
|
||||
v = getattr(f, a, None)
|
||||
if v != None:
|
||||
v = re.sub(r'[][\\"\' ]+', '', v)
|
||||
v = v.split(',')
|
||||
v = json.dumps(v)
|
||||
setattr(f, a, v)
|
||||
f.save()
|
||||
# This migration changes existing data fields in an incompatible manner, and
|
||||
# would not be interleavable if we hadn't added compatibility code in
|
||||
# Group.features() beforehand. With that patched in, we permit interleaving.
|
||||
forward.interleavable = True
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
GroupFeatures = apps.get_model('group', 'GroupFeatures')
|
||||
for f in GroupFeatures.objects.all():
|
||||
for a in ['material_types', 'admin_roles', 'matman_roles', 'role_order']:
|
||||
v = getattr(f, a, None)
|
||||
if v != None:
|
||||
v = getattr(f, a)
|
||||
v = json.loads(v)
|
||||
v = ','.join(v)
|
||||
setattr(f, a, v)
|
||||
f.save()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0004_add_group_feature_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse),
|
||||
]
|
|
@ -0,0 +1,86 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-16 05:53
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import jsonfield.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0005_group_features_list_data_to_json'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='groupfeatures',
|
||||
name='admin_roles',
|
||||
field=jsonfield.fields.JSONField(default=b'chair', max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='groupfeatures',
|
||||
name='custom_group_roles',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Cust. Roles'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='groupfeatures',
|
||||
name='has_nonsession_materials',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Other Matrl.'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='groupfeatures',
|
||||
name='has_session_materials',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Sess Matrl.'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='groupfeatures',
|
||||
name='material_types',
|
||||
field=jsonfield.fields.JSONField(default=b'slides', max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='groupfeatures',
|
||||
name='matman_roles',
|
||||
field=jsonfield.fields.JSONField(default=b'ad,chair,delegate,secr', max_length=128),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='groupfeatures',
|
||||
name='role_order',
|
||||
field=jsonfield.fields.JSONField(default=b'chair,secr,member', help_text=b'The order in which roles are shown, for instance on photo pages. Enter valid JSON.', max_length=128),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='admin_roles',
|
||||
field=jsonfield.fields.JSONField(default=b'chair', max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='custom_group_roles',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Cust. Roles'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='has_nonsession_materials',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Other Matrl.'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='has_session_materials',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Sess Matrl.'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='material_types',
|
||||
field=jsonfield.fields.JSONField(default=b'slides', max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='matman_roles',
|
||||
field=jsonfield.fields.JSONField(default=b'ad,chair,delegate,secr', max_length=128),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='role_order',
|
||||
field=jsonfield.fields.JSONField(default=b'chair,secr,member', help_text=b'The order in which roles are shown, for instance on photo pages. Enter valid JSON.', max_length=128),
|
||||
),
|
||||
]
|
211
ietf/group/migrations/0007_new_group_features_data.py
Normal file
211
ietf/group/migrations/0007_new_group_features_data.py
Normal file
|
@ -0,0 +1,211 @@
|
|||
# Copyright The IETF Trust 2019, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-09 09:02
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
group_type_features = {
|
||||
u'ag': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': True,
|
||||
'acts_like_wg': True,
|
||||
'create_wiki': True,
|
||||
'is_schedulable': True,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': True,
|
||||
'matman_roles': ['ad', 'chair', 'delegate', 'secr'],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'area': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': True,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['ad', 'chair', 'delegate', 'secr'],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'dir': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': True,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['ad', 'chair', 'delegate', 'secr'],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'review': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': True,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['ad', 'secr'],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'iab': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': False,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': True,
|
||||
'matman_roles': [],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'ietf': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': True,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': False,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['chair', 'delegate'],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'individ': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': False,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': False,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['auth'],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'irtf': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': False,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['chair', 'delegate', 'secr'],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'isoc': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': False,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['chair', 'secr'],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'nomcom': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': True,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['chair'],
|
||||
'role_order': ['chair', 'member', 'advisor'],
|
||||
},
|
||||
u'program': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': False,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': False,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['chair', 'secr'],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'rfcedtyp': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': False,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['chair', 'secr'],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'rg': {
|
||||
'custom_group_roles': False,
|
||||
'has_session_materials': True,
|
||||
'acts_like_wg': True,
|
||||
'create_wiki': True,
|
||||
'is_schedulable': True,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': True,
|
||||
'matman_roles': ['chair', 'secr'],
|
||||
'role_order': ['chair', 'secr'],
|
||||
},
|
||||
u'sdo': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': False,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['liaiman', 'matman'],
|
||||
'role_order': ['liaiman'],
|
||||
},
|
||||
u'team': {
|
||||
'custom_group_roles': True,
|
||||
'has_session_materials': False,
|
||||
'acts_like_wg': False,
|
||||
'create_wiki': True,
|
||||
'is_schedulable': False,
|
||||
'req_subm_approval': False,
|
||||
'show_on_agenda': False,
|
||||
'matman_roles': ['chair', 'matman'],
|
||||
'role_order': ['chair', 'member', 'matman'],
|
||||
},
|
||||
u'wg': {
|
||||
'custom_group_roles': False,
|
||||
'has_session_materials': True,
|
||||
'acts_like_wg': True,
|
||||
'create_wiki': True,
|
||||
'is_schedulable': True,
|
||||
'req_subm_approval': True,
|
||||
'show_on_agenda': True,
|
||||
'matman_roles': ['ad', 'chair', 'delegate', 'secr'],
|
||||
'role_order': ['chair', 'secr', 'delegate'],
|
||||
},
|
||||
}
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
GroupFeatures = apps.get_model('group', 'GroupFeatures')
|
||||
for type in group_type_features:
|
||||
features = group_type_features[type]
|
||||
gf = GroupFeatures.objects.get(type=type)
|
||||
for k,v in features.items():
|
||||
setattr(gf, k, v)
|
||||
gf.save()
|
||||
forward.interleavable = True
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
pass
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0006_group_features_lists_to_jsonfield')
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse),
|
||||
]
|
26
ietf/group/migrations/0008_group_features_onetoone.py
Normal file
26
ietf/group/migrations/0008_group_features_onetoone.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-19 10:08
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import ietf.utils.models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0007_new_group_features_data'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='groupfeatures',
|
||||
name='type',
|
||||
field=ietf.utils.models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='features', serialize=False, to='name.GroupTypeName'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='type',
|
||||
field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='name.GroupTypeName'),
|
||||
),
|
||||
]
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import datetime
|
||||
import email.utils
|
||||
import jsonfield
|
||||
import os
|
||||
import re
|
||||
from urlparse import urljoin
|
||||
|
@ -40,31 +41,20 @@ class GroupInfo(models.Model):
|
|||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
def name_with_acronym(self):
|
||||
res = self.name
|
||||
if self.type_id in ("wg", "rg", "ag", "area"):
|
||||
res += " %s (%s)" % (self.type, self.acronym)
|
||||
return res
|
||||
|
||||
def ad_role(self):
|
||||
return self.role_set.filter(name='ad').first()
|
||||
|
||||
@property
|
||||
def features(self):
|
||||
if not hasattr(self, "features_cache"):
|
||||
features = GroupFeatures.objects.get(type=self.type)
|
||||
# convert textual lists to python lists:
|
||||
for a in ['material_types', 'admin_roles', ]:
|
||||
v = getattr(features, a)
|
||||
setattr(features, a, v.split(','))
|
||||
self.features_cache = features
|
||||
self.features_cache = GroupFeatures.objects.get(type=self.type)
|
||||
return self.features_cache
|
||||
|
||||
def about_url(self):
|
||||
# bridge gap between group-type prefixed URLs and /group/ ones
|
||||
from django.urls import reverse as urlreverse
|
||||
kwargs = { 'acronym': self.acronym }
|
||||
if self.type_id in ("wg", "rg", "ag"):
|
||||
if self.features.acts_like_wg:
|
||||
kwargs["group_type"] = self.type_id
|
||||
return urlreverse(self.features.about_page, kwargs=kwargs)
|
||||
|
||||
|
@ -214,25 +204,35 @@ validate_comma_separated_roles = RegexValidator(
|
|||
)
|
||||
|
||||
class GroupFeatures(models.Model):
|
||||
type = ForeignKey(GroupTypeName, primary_key=True, null=False, related_name='features')
|
||||
type = OneToOneField(GroupTypeName, primary_key=True, null=False, related_name='features')
|
||||
history = HistoricalRecords()
|
||||
#
|
||||
has_milestones = models.BooleanField("Milestones", default=False)
|
||||
has_chartering_process = models.BooleanField("Chartering", default=False)
|
||||
has_documents = models.BooleanField("Documents", default=False) # i.e. drafts/RFCs
|
||||
has_dependencies = models.BooleanField("Dependencies",default=False) # Do dependency graphs for group documents make sense?
|
||||
has_nonsession_materials= models.BooleanField("Materials", default=False)
|
||||
has_session_materials = models.BooleanField("Sess Matrl.", default=False)
|
||||
has_nonsession_materials= models.BooleanField("Other Matrl.", default=False)
|
||||
has_meetings = models.BooleanField("Meetings", default=False)
|
||||
has_reviews = models.BooleanField("Reviews", default=False)
|
||||
has_default_jabber = models.BooleanField("Jabber", default=False)
|
||||
#
|
||||
acts_like_wg = models.BooleanField("WG-Like", default=False)
|
||||
create_wiki = models.BooleanField("Wiki", default=False)
|
||||
custom_group_roles = models.BooleanField("Cust. Roles",default=False)
|
||||
customize_workflow = models.BooleanField("Workflow", default=False)
|
||||
is_schedulable = models.BooleanField("Schedulable",default=False)
|
||||
show_on_agenda = models.BooleanField("On Agenda", default=False)
|
||||
req_subm_approval = models.BooleanField("Subm. Approval", default=False)
|
||||
#
|
||||
agenda_type = models.ForeignKey(AgendaTypeName, null=True, default="ietf", on_delete=CASCADE)
|
||||
about_page = models.CharField(max_length=64, blank=False, default="ietf.group.views.group_about" )
|
||||
default_tab = models.CharField(max_length=64, blank=False, default="ietf.group.views.group_about" )
|
||||
material_types = models.CharField(max_length=64, blank=False, default="slides",
|
||||
validators=[validate_comma_separated_materials])
|
||||
admin_roles = models.CharField(max_length=64, blank=False, default="chair",
|
||||
validators=[validate_comma_separated_roles])
|
||||
material_types = jsonfield.JSONField(max_length=64, blank=False, default="slides")
|
||||
admin_roles = jsonfield.JSONField(max_length=64, blank=False, default="chair")
|
||||
matman_roles = jsonfield.JSONField(max_length=128, blank=False, default="ad,chair,delegate,secr")
|
||||
role_order = jsonfield.JSONField(max_length=128, blank=False, default="chair,secr,member",
|
||||
help_text="The order in which roles are shown, for instance on photo pages. Enter valid JSON.")
|
||||
|
||||
|
||||
class GroupHistory(GroupInfo):
|
||||
|
|
|
@ -121,12 +121,12 @@ def milestone_reviewer_for_group_type(group_type):
|
|||
return "Area Director"
|
||||
|
||||
def can_manage_materials(user, group):
|
||||
return has_role(user, 'Secretariat') or group.has_role(user, ("chair", "delegate", "secr", "matman", "ad"))
|
||||
return has_role(user, 'Secretariat') or group.has_role(user, group.features.matman_roles)
|
||||
|
||||
def can_provide_status_update(user, group):
|
||||
if not group.type_id in ['wg','rg','ag','team']:
|
||||
if not group.features.acts_like_wg:
|
||||
return False
|
||||
return has_role(user, 'Secretariat') or group.has_role(user, ("chair", "delegate", "secr", "ad",))
|
||||
return has_role(user, 'Secretariat') or group.has_role(user, group.features.matman_roles)
|
||||
|
||||
def get_group_or_404(acronym, group_type):
|
||||
"""Helper to overcome the schism between group-type prefixed URLs and generic."""
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
# Copyright The IETF Trust 2007-2019, All Rights Reserved
|
||||
|
||||
|
||||
# Portion Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
|
||||
|
@ -69,7 +70,8 @@ from ietf.group.forms import (GroupForm, StatusUpdateForm, ConcludeGroupForm, St
|
|||
ManageReviewRequestForm, EmailOpenAssignmentsForm, ReviewerSettingsForm,
|
||||
AddUnavailablePeriodForm, EndUnavailablePeriodForm, ReviewSecretarySettingsForm, )
|
||||
from ietf.group.mails import email_admin_re_charter, email_personnel_change, email_comment
|
||||
from ietf.group.models import ( Group, Role, GroupEvent, GroupStateTransitions, GroupURL, ChangeStateGroupEvent )
|
||||
from ietf.group.models import ( Group, Role, GroupEvent, GroupStateTransitions, GroupURL,
|
||||
ChangeStateGroupEvent, GroupFeatures )
|
||||
from ietf.group.utils import (get_charter_text, can_manage_group_type,
|
||||
milestone_reviewer_for_group_type, can_provide_status_update,
|
||||
can_manage_materials,
|
||||
|
@ -385,7 +387,8 @@ def bofs(request, group_type):
|
|||
def chartering_groups(request):
|
||||
charter_states = State.objects.filter(used=True, type="charter").exclude(slug__in=("approved", "notrev"))
|
||||
|
||||
group_types = GroupTypeName.objects.filter(slug__in=("wg", "rg"))
|
||||
group_type_slugs = [ f.type.slug for f in GroupFeatures.objects.filter(has_chartering_process=True) ]
|
||||
group_types = GroupTypeName.objects.filter(slug__in=group_type_slugs)
|
||||
|
||||
for t in group_types:
|
||||
t.chartering_groups = Group.objects.filter(type=t, charter__states__in=charter_states).select_related("state", "charter").order_by("acronym")
|
||||
|
@ -788,16 +791,7 @@ def group_photos(request, group_type=None, acronym=None):
|
|||
group = get_object_or_404(Group, acronym=acronym)
|
||||
roles = sorted(Role.objects.filter(group__acronym=acronym),key=lambda x: x.name.name+x.person.last_name())
|
||||
|
||||
if group.type_id in ['wg', 'rg', 'ag', ]:
|
||||
roles = reorder_roles(roles, ['chair', 'secr'])
|
||||
elif group.type_id in ['nomcom', ]:
|
||||
roles = reorder_roles(roles, ['chair', 'member', 'advisor', ])
|
||||
elif group.type_id in ['team', ]:
|
||||
roles = reorder_roles(roles, ['chair', 'member', 'matman', ])
|
||||
elif group.type_id in ['sdo', ]:
|
||||
roles = reorder_roles(roles, ['liaiman', ])
|
||||
else:
|
||||
pass
|
||||
roles = reorder_roles(roles, group.features.role_order)
|
||||
for role in roles:
|
||||
role.last_initial = role.person.last_name()[0]
|
||||
return render(request, 'group/group_photos.html',
|
||||
|
@ -1197,6 +1191,7 @@ def stream_documents(request, acronym):
|
|||
docs, meta = prepare_document_table(request, qs, max_results=1000)
|
||||
return render(request, 'group/stream_documents.html', {'stream':stream, 'docs':docs, 'meta':meta, 'editable':editable } )
|
||||
|
||||
|
||||
def stream_edit(request, acronym):
|
||||
group = get_object_or_404(Group, acronym=acronym)
|
||||
|
||||
|
@ -1252,7 +1247,7 @@ def group_json(request, acronym):
|
|||
@cache_control(public=True, max_age=30*60)
|
||||
@cache_page(30 * 60)
|
||||
def group_menu_data(request):
|
||||
groups = Group.objects.filter(state="active", type__in=("wg", "rg"), parent__state="active").order_by("acronym")
|
||||
groups = Group.objects.filter(state="active", type__features__acts_like_wg=True, parent__state="active").order_by("acronym")
|
||||
|
||||
groups_by_parent = defaultdict(list)
|
||||
for g in groups:
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# Copyright The IETF Trust 2013-2019, All Rights Reserved
|
||||
|
||||
# various authentication and authorization utilities
|
||||
|
||||
from functools import wraps
|
||||
|
@ -11,7 +13,7 @@ from django.utils.decorators import available_attrs
|
|||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.group.models import Role
|
||||
from ietf.group.models import Group, Role
|
||||
from ietf.person.models import Person
|
||||
|
||||
def user_is_person(user, person):
|
||||
|
@ -134,16 +136,20 @@ def is_authorized_in_doc_stream(user, doc):
|
|||
if doc.stream.slug == "ietf" and doc.group.type_id == "individ":
|
||||
return False
|
||||
|
||||
matman_roles = doc.group.features.matman_roles
|
||||
if doc.stream.slug == "ietf":
|
||||
group_req = Q(group=doc.group)
|
||||
elif doc.stream.slug == "irtf":
|
||||
group_req = Q(group__acronym=doc.stream.slug) | Q(group=doc.group)
|
||||
elif doc.stream.slug in ("iab", "ise"):
|
||||
if doc.group.type.slug == 'individ':
|
||||
# A lot of special cases here, for stream slugs and group acronyms
|
||||
matman_roles = Group.objects.get(acronym=doc.stream.slug).features.matman_roles
|
||||
group_req = Q(group__acronym=doc.stream.slug)
|
||||
else:
|
||||
group_req = Q()
|
||||
|
||||
return Role.objects.filter(Q(name__in=("chair", "secr", "delegate", "auth"), person__user=user) & group_req).exists()
|
||||
return Role.objects.filter(Q(name__in=matman_roles, person__user=user) & group_req).exists()
|
||||
|
||||
def is_authorized_in_group(user, group):
|
||||
"""Return whether user is authorized to perform duties on
|
||||
|
@ -163,7 +169,7 @@ def is_authorized_in_group(user, group):
|
|||
if group.parent.acronym == 'iab' and has_role(user, ['IAB','IAB Executive Director',]):
|
||||
return True
|
||||
|
||||
return Role.objects.filter(name__in=("chair", "secr", "delegate", "auth"), person__user=user,group=group ).exists()
|
||||
return Role.objects.filter(name__in=group.features.matman_roles, person__user=user,group=group ).exists()
|
||||
|
||||
def is_individual_draft_author(user, doc):
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ from ietf.group.models import Group
|
|||
from ietf.mailinglists.models import List
|
||||
|
||||
def groups(request):
|
||||
groups = Group.objects.filter(type__in=("wg", "rg", "ag"), list_archive__startswith='http').exclude(state__in=('bof', 'conclude')).order_by("acronym")
|
||||
groups = Group.objects.filter(type__features__acts_like_wg=True, list_archive__startswith='http').exclude(state__in=('bof', 'conclude')).order_by("acronym")
|
||||
|
||||
return render(request, "mailinglists/group_archives.html", { "groups": groups } )
|
||||
|
||||
|
@ -19,7 +19,7 @@ def groups(request):
|
|||
# safely cache this for some time.
|
||||
@cache_page(15*60)
|
||||
def nonwg(request):
|
||||
groups = Group.objects.filter(type__in=("wg", "rg")).exclude(state__in=['bof', 'conclude']).order_by("acronym")
|
||||
groups = Group.objects.filter(type__features__acts_like_wg=True).exclude(state__in=['bof', 'conclude']).order_by("acronym")
|
||||
|
||||
#urls = [ g.list_archive for g in groups if '.ietf.org' in g.list_archive ]
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ class Recipient(models.Model):
|
|||
addrs = []
|
||||
if 'doc' in kwargs:
|
||||
doc=kwargs['doc']
|
||||
if doc.group and doc.group.type.slug in ['wg','rg','ag',]:
|
||||
if doc.group and doc.group.features.acts_like_wg:
|
||||
addrs.append('%s-chairs@ietf.org'%doc.group.acronym)
|
||||
return addrs
|
||||
|
||||
|
@ -76,7 +76,7 @@ class Recipient(models.Model):
|
|||
addrs = []
|
||||
if 'doc' in kwargs:
|
||||
doc=kwargs['doc']
|
||||
if doc.group and doc.group.type.slug in ['wg','rg','ag',]:
|
||||
if doc.group and doc.group.features.acts_like_wg:
|
||||
addrs.extend(doc.group.role_set.filter(name='delegate').values_list('email__address',flat=True))
|
||||
return addrs
|
||||
|
||||
|
@ -84,7 +84,7 @@ class Recipient(models.Model):
|
|||
addrs = []
|
||||
if 'doc' in kwargs:
|
||||
doc=kwargs['doc']
|
||||
if doc.group.type.slug in ['wg','rg','ag',]:
|
||||
if doc.group.features.acts_like_wg:
|
||||
if doc.group.list_email:
|
||||
addrs.append(doc.group.list_email)
|
||||
return addrs
|
||||
|
@ -226,7 +226,7 @@ class Recipient(models.Model):
|
|||
new_author_email_set = set(author["email"] for author in submission.authors if author.get("email"))
|
||||
|
||||
if doc.group and old_author_email_set != new_author_email_set:
|
||||
if doc.group.type_id in ['wg','rg','ag']:
|
||||
if doc.group.features.acts_like_wg:
|
||||
addrs.extend(Recipient.objects.get(slug='group_chairs').gather(**{'group':doc.group}))
|
||||
elif doc.group.type_id in ['area']:
|
||||
addrs.extend(Recipient.objects.get(slug='group_responsible_directors').gather(**{'group':doc.group}))
|
||||
|
|
|
@ -67,9 +67,9 @@ def gather_relevant_expansions(**kwargs):
|
|||
relevant.update(starts_with('group_'))
|
||||
relevant.update(starts_with('milestones_'))
|
||||
group = kwargs['group']
|
||||
if group.type_id in ['rg','wg','ag',]:
|
||||
if group.features.acts_like_wg:
|
||||
relevant.update(starts_with('session_'))
|
||||
if group.type_id in ['wg',]:
|
||||
if group.features.has_chartering_process:
|
||||
relevant.update(['charter_external_review',])
|
||||
|
||||
if 'submission' in kwargs:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# Copyright The IETF Trust 2009-2019, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import json
|
||||
|
@ -294,14 +295,16 @@ class MeetingTests(TestCase):
|
|||
self.assertTrue("1. WG status" in unicontent(r))
|
||||
|
||||
# session minutes
|
||||
r = self.client.get(urlreverse("ietf.meeting.views.materials_document",
|
||||
kwargs=dict(num=meeting.number, document=session.minutes())))
|
||||
url = urlreverse("ietf.meeting.views.materials_document",
|
||||
kwargs=dict(num=meeting.number, document=session.minutes()))
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue("1. More work items underway" in unicontent(r))
|
||||
|
||||
# test with explicit meeting number in url
|
||||
if meeting.number.isdigit():
|
||||
r = self.client.get(urlreverse("ietf.meeting.views.materials", kwargs=dict(num=meeting.number)))
|
||||
url = urlreverse("ietf.meeting.views.materials", kwargs=dict(num=meeting.number))
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
row = q('#content #%s' % str(session.group.acronym)).closest("tr")
|
||||
|
@ -311,7 +314,8 @@ class MeetingTests(TestCase):
|
|||
self.assertFalse(row.find("a:contains(\"Bad Slideshow\")"))
|
||||
|
||||
# test with no meeting number in url
|
||||
r = self.client.get(urlreverse("ietf.meeting.views.materials", kwargs=dict()))
|
||||
url = urlreverse("ietf.meeting.views.materials", kwargs=dict())
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
row = q('#content #%s' % str(session.group.acronym)).closest("tr")
|
||||
|
@ -322,7 +326,8 @@ class MeetingTests(TestCase):
|
|||
|
||||
# test with a loggged-in wg chair
|
||||
self.client.login(username="marschairman", password="marschairman+password")
|
||||
r = self.client.get(urlreverse("ietf.meeting.views.materials", kwargs=dict(num=meeting.number)))
|
||||
url = urlreverse("ietf.meeting.views.materials", kwargs=dict(num=meeting.number))
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
row = q('#content #%s' % str(session.group.acronym)).closest("tr")
|
||||
|
|
|
@ -1264,8 +1264,8 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "This is the initial state when an AD proposes a new charter. The normal next state is Internal review if the idea is accepted, or Not currently under review if the idea is abandoned.",
|
||||
"name": "Informal IESG review",
|
||||
"desc": "The proposed charter is not being considered at this time. A proposed charter will remain in this state until an AD moves it to Start Chartering/Rechartering (Internal IESG/IAB Review). This state is useful for drafting the charter, discussing with chairs, etc.",
|
||||
"name": "Draft Charter",
|
||||
"next_states": [],
|
||||
"order": 0,
|
||||
"slug": "infrev",
|
||||
|
@ -1277,8 +1277,8 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "The IESG and IAB are reviewing the early draft of the charter; this is the initial IESG and IAB review. The usual next state is External review if the idea is adopted, or Informal IESG review if the IESG decides the idea needs more work, or Not currently under review if the idea is abandoned",
|
||||
"name": "Internal review",
|
||||
"desc": "This is the state when you'd like to propose the charter / new charter. This state also allows you to ask whether external review can be skipped in ballot. After you select this state, the Secretariat takes over and drives the rest of the process.",
|
||||
"name": "Start Chartering/Rechartering (Internal IESG/IAB Review)",
|
||||
"next_states": [],
|
||||
"order": 0,
|
||||
"slug": "intrev",
|
||||
|
@ -1290,8 +1290,8 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "The IETF community and possibly other standards development organizations (SDOs) are reviewing the proposed charter. The usual next state is IESG review, although it might move to Not currently under review if the idea is abandoned during the external review.",
|
||||
"name": "External review",
|
||||
"desc": "This state is selected by the Secretariat (AD's, keep yer grubby mits off this!) when it has been decided that the charter needs external review.",
|
||||
"name": "External Review (Message to Community, Selected by Secretariat)",
|
||||
"next_states": [],
|
||||
"order": 0,
|
||||
"slug": "extrev",
|
||||
|
@ -1303,8 +1303,8 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "The IESG is reviewing the discussion from the external review of the proposed charter. The usual next state is Approved, or Not currently under review if the idea is abandoned.",
|
||||
"name": "IESG review",
|
||||
"desc": "This state is selected by the Secretariat (AD's, keep yer grubby mits off this!) when the IESG is reviewing the discussion from the external review of the proposed charter (this is similar to the IESG Evaluation state for a draft).",
|
||||
"name": "IESG Review (Charter for Approval, Selected by Secretariat)",
|
||||
"next_states": [],
|
||||
"order": 0,
|
||||
"slug": "iesgrev",
|
||||
|
@ -2181,7 +2181,7 @@
|
|||
"used": true
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 152
|
||||
"pk": 150
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
|
@ -2347,8 +2347,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair",
|
||||
"acts_like_wg": true,
|
||||
"admin_roles": "[\"chair\"]",
|
||||
"agenda_type": "ietf",
|
||||
"create_wiki": true,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2359,7 +2362,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": true,
|
||||
"is_schedulable": true,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"ad\",\"chair\",\"delegate\",\"secr\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": true
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "ag"
|
||||
|
@ -2367,8 +2376,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "ad",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"ad\"]",
|
||||
"agenda_type": "ietf",
|
||||
"create_wiki": true,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2379,7 +2391,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"ad\",\"chair\",\"delegate\",\"secr\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "area"
|
||||
|
@ -2387,8 +2405,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair,secr",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"chair\",\"secr\"]",
|
||||
"agenda_type": null,
|
||||
"create_wiki": true,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2399,7 +2420,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"ad\",\"chair\",\"delegate\",\"secr\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "dir"
|
||||
|
@ -2407,8 +2434,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"chair\"]",
|
||||
"agenda_type": "ietf",
|
||||
"create_wiki": false,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2419,7 +2449,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": true
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "iab"
|
||||
|
@ -2427,8 +2463,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair,lead",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"chair\",\"lead\"]",
|
||||
"agenda_type": "ietf",
|
||||
"create_wiki": false,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2439,7 +2478,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": true,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"chair\",\"delegate\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "ietf"
|
||||
|
@ -2447,8 +2492,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"chair\"]",
|
||||
"agenda_type": null,
|
||||
"create_wiki": false,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2459,7 +2507,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"auth\"]",
|
||||
"req_subm_approval": false,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "individ"
|
||||
|
@ -2467,8 +2521,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"chair\"]",
|
||||
"agenda_type": "ietf",
|
||||
"create_wiki": false,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2479,7 +2536,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"chair\",\"delegate\",\"secr\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "irtf"
|
||||
|
@ -2487,8 +2550,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"chair\"]",
|
||||
"agenda_type": null,
|
||||
"create_wiki": false,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2499,7 +2565,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"chair\",\"secr\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "isoc"
|
||||
|
@ -2507,8 +2579,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"chair\"]",
|
||||
"agenda_type": "side",
|
||||
"create_wiki": true,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2519,7 +2594,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"chair\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"member\",\"advisor\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "nomcom"
|
||||
|
@ -2527,8 +2608,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "lead",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"lead\"]",
|
||||
"agenda_type": null,
|
||||
"create_wiki": false,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2539,7 +2623,13 @@
|
|||
"has_milestones": true,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"chair\",\"secr\"]",
|
||||
"req_subm_approval": false,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "program"
|
||||
|
@ -2547,8 +2637,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair,secr",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"chair\",\"secr\"]",
|
||||
"agenda_type": null,
|
||||
"create_wiki": true,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.review_requests",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2559,7 +2652,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": true,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"ad\",\"secr\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "review"
|
||||
|
@ -2567,8 +2666,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"chair\"]",
|
||||
"agenda_type": "side",
|
||||
"create_wiki": false,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2579,7 +2681,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"chair\",\"secr\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "rfcedtyp"
|
||||
|
@ -2587,8 +2695,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair",
|
||||
"acts_like_wg": true,
|
||||
"admin_roles": "[\"chair\"]",
|
||||
"agenda_type": "ietf",
|
||||
"create_wiki": true,
|
||||
"custom_group_roles": false,
|
||||
"customize_workflow": true,
|
||||
"default_tab": "ietf.group.views.group_documents",
|
||||
"has_chartering_process": true,
|
||||
|
@ -2599,7 +2710,13 @@
|
|||
"has_milestones": true,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": true,
|
||||
"is_schedulable": true,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"chair\",\"secr\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"secr\"]",
|
||||
"show_on_agenda": true
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "rg"
|
||||
|
@ -2607,8 +2724,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"chair\"]",
|
||||
"agenda_type": null,
|
||||
"create_wiki": false,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2619,7 +2739,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"liaiman\",\"matman\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"liaiman\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "sdo"
|
||||
|
@ -2627,8 +2753,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair",
|
||||
"acts_like_wg": false,
|
||||
"admin_roles": "[\"chair\"]",
|
||||
"agenda_type": "ietf",
|
||||
"create_wiki": true,
|
||||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"has_chartering_process": false,
|
||||
|
@ -2639,7 +2768,13 @@
|
|||
"has_milestones": false,
|
||||
"has_nonsession_materials": true,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"chair\",\"matman\"]",
|
||||
"req_subm_approval": false,
|
||||
"role_order": "[\"chair\",\"member\",\"matman\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "team"
|
||||
|
@ -2647,8 +2782,11 @@
|
|||
{
|
||||
"fields": {
|
||||
"about_page": "ietf.group.views.group_about",
|
||||
"admin_roles": "chair",
|
||||
"acts_like_wg": true,
|
||||
"admin_roles": "[\"chair\"]",
|
||||
"agenda_type": "ietf",
|
||||
"create_wiki": true,
|
||||
"custom_group_roles": false,
|
||||
"customize_workflow": true,
|
||||
"default_tab": "ietf.group.views.group_documents",
|
||||
"has_chartering_process": true,
|
||||
|
@ -2659,7 +2797,13 @@
|
|||
"has_milestones": true,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"material_types": "slides"
|
||||
"has_session_materials": true,
|
||||
"is_schedulable": true,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"ad\",\"chair\",\"delegate\",\"secr\"]",
|
||||
"req_subm_approval": true,
|
||||
"role_order": "[\"chair\",\"secr\",\"delegate\"]",
|
||||
"show_on_agenda": true
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
"pk": "wg"
|
||||
|
@ -3360,7 +3504,9 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"cc": [],
|
||||
"cc": [
|
||||
"liaison_admin"
|
||||
],
|
||||
"desc": "Recipients for a message that a pending liaison statement needs approval",
|
||||
"to": [
|
||||
"liaison_approvers"
|
||||
|
@ -4134,6 +4280,14 @@
|
|||
"model": "mailtrigger.recipient",
|
||||
"pk": "ipr_updatedipr_holders"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "Alias for secretariat liaison administration",
|
||||
"template": "<statements@ietf.org>"
|
||||
},
|
||||
"model": "mailtrigger.recipient",
|
||||
"pk": "liaison_admin"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "The set of people who can approve this liasion statemetns",
|
||||
|
@ -10532,7 +10686,7 @@
|
|||
"fields": {
|
||||
"command": "xym",
|
||||
"switch": "--version",
|
||||
"time": "2018-12-04T00:08:13.259",
|
||||
"time": "2019-01-21T00:08:23.930",
|
||||
"used": true,
|
||||
"version": "xym 0.4"
|
||||
},
|
||||
|
@ -10543,7 +10697,7 @@
|
|||
"fields": {
|
||||
"command": "pyang",
|
||||
"switch": "--version",
|
||||
"time": "2018-12-04T00:08:13.958",
|
||||
"time": "2019-01-21T00:08:25.229",
|
||||
"used": true,
|
||||
"version": "pyang 1.7.5"
|
||||
},
|
||||
|
@ -10554,7 +10708,7 @@
|
|||
"fields": {
|
||||
"command": "yanglint",
|
||||
"switch": "--version",
|
||||
"time": "2018-12-04T00:08:14.121",
|
||||
"time": "2019-01-21T00:08:25.465",
|
||||
"used": true,
|
||||
"version": "yanglint 0.14.80"
|
||||
},
|
||||
|
@ -10565,9 +10719,9 @@
|
|||
"fields": {
|
||||
"command": "xml2rfc",
|
||||
"switch": "--version",
|
||||
"time": "2018-12-04T00:08:15.775",
|
||||
"time": "2019-01-21T00:08:26.897",
|
||||
"used": true,
|
||||
"version": "xml2rfc 2.15.2"
|
||||
"version": "xml2rfc 2.16.3"
|
||||
},
|
||||
"model": "utils.versioninfo",
|
||||
"pk": 4
|
||||
|
|
|
@ -712,7 +712,7 @@ def setup_reviewer_field(field, review_req):
|
|||
def get_default_filter_re(person):
|
||||
if type(person) != Person:
|
||||
person = Person.objects.get(id=person)
|
||||
groups_to_avoid = [r.group for r in person.role_set.filter(name='chair',group__type__in=['wg','rg'])]
|
||||
groups_to_avoid = [ r.group for r in person.role_set.all() if r.name in r.group.features.admin_roles and r.group.features.acts_like_wg ]
|
||||
if not groups_to_avoid:
|
||||
return '^draft-%s-.*$' % ( person.last_name().lower(), )
|
||||
else:
|
||||
|
|
|
@ -78,7 +78,7 @@ class GroupModelForm(forms.ModelForm):
|
|||
parent = self.cleaned_data['parent']
|
||||
type = self.cleaned_data['type']
|
||||
|
||||
if type.slug in ('ag','wg','rg') and not parent:
|
||||
if type.features.acts_like_wg and not parent:
|
||||
raise forms.ValidationError("This field is required.")
|
||||
|
||||
return parent
|
||||
|
@ -130,8 +130,7 @@ class RoleForm(forms.Form):
|
|||
self.group = kwargs.pop('group')
|
||||
super(RoleForm, self).__init__(*args,**kwargs)
|
||||
# this form is re-used in roles app, use different roles in select
|
||||
# TODO: should 'ag' be excluded here as well?
|
||||
if self.group.type.slug not in ('wg','rg'):
|
||||
if self.group.features.custom_group_roles:
|
||||
self.fields['name'].queryset = RoleName.objects.all()
|
||||
|
||||
# check for id within parenthesis to ensure name was selected from the list
|
||||
|
|
|
@ -552,7 +552,7 @@ MAX_WG_DELEGATES = 3
|
|||
# These states aren't available in forms with drop-down choices for new
|
||||
# document state:
|
||||
GROUP_STATES_WITH_EXTRA_PROCESSING = ["sub-pub", "rfc-edit", ]
|
||||
|
||||
GROUP_TYPES_LISTED_ACTIVE = ['wg', 'rg', 'ag', 'team', 'dir', 'review', 'area', 'program', ]
|
||||
|
||||
DATE_FORMAT = "Y-m-d"
|
||||
DATETIME_FORMAT = "Y-m-d H:i T"
|
||||
|
@ -901,7 +901,8 @@ TRAC_ISSUE_URL_PATTERN = "https://trac.ietf.org/trac/%s/report/1"
|
|||
TRAC_SVN_DIR_PATTERN = "/a/svn/group/%s"
|
||||
#TRAC_SVN_URL_PATTERN = "https://svn.ietf.org/svn/group/%s/"
|
||||
|
||||
TRAC_CREATE_GROUP_TYPES = ['wg', 'rg', 'area', 'team', 'dir', 'review', 'ag', 'nomcom', ]
|
||||
# The group types setting was replaced by a group feature entry 10 Jan 2019
|
||||
#TRAC_CREATE_GROUP_TYPES = ['wg', 'rg', 'area', 'team', 'dir', 'review', 'ag', 'nomcom', ]
|
||||
TRAC_CREATE_GROUP_STATES = ['bof', 'active', ]
|
||||
TRAC_CREATE_GROUP_ACRONYMS = ['iesg', 'iaoc', 'ietf', ]
|
||||
TRAC_CREATE_ADHOC_WIKIS = [
|
||||
|
|
|
@ -466,7 +466,7 @@ class PreapprovalForm(forms.Form):
|
|||
if not components[-1]:
|
||||
raise forms.ValidationError("Name ends with a dash.")
|
||||
acronym = components[2]
|
||||
if acronym not in self.groups.values_list('acronym', flat=True):
|
||||
if acronym not in [ g.acronym for g in self.groups ]:
|
||||
raise forms.ValidationError("Group acronym not recognized as one you can approve drafts for.")
|
||||
|
||||
if Preapproval.objects.filter(name=n):
|
||||
|
|
|
@ -556,7 +556,7 @@ def preapprovals_for_user(user):
|
|||
if has_role(user, "Secretariat"):
|
||||
return res
|
||||
|
||||
acronyms = [g.acronym for g in Group.objects.filter(role__person__user=user, type__in=("wg", "rg"))]
|
||||
acronyms = [g.acronym for g in Group.objects.filter(role__person__user=user, type__features__acts_like_wg=True)]
|
||||
|
||||
res = res.filter(name__regex="draft-[^-]+-(%s)-.*" % "|".join(acronyms))
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
# Copyright The IETF Trust 2007-2019, All Rights Reserved
|
||||
|
||||
import re
|
||||
import base64
|
||||
|
@ -17,7 +17,7 @@ import debug # pyflakes:ignore
|
|||
|
||||
from ietf.doc.models import Document, DocAlias, AddedMessageEvent
|
||||
from ietf.doc.utils import prettify_std_name
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.models import Group, Role
|
||||
from ietf.ietfauth.utils import has_role, role_required
|
||||
from ietf.mailtrigger.utils import gather_address_lists
|
||||
from ietf.message.models import Message, MessageAttachment
|
||||
|
@ -124,7 +124,9 @@ def api_submit(request):
|
|||
submission.submitter = user.person.formatted_email()
|
||||
docevent_from_submission(request, submission, desc="Uploaded new revision")
|
||||
|
||||
requires_group_approval = (submission.rev == '00' and submission.group and submission.group.type_id in ("wg", "rg", "ietf", "irtf", "iab", "iana", "rfcedtyp") and not Preapproval.objects.filter(name=submission.name).exists())
|
||||
requires_group_approval = (submission.rev == '00'
|
||||
and submission.group and submission.group.features.req_subm_approval
|
||||
and not Preapproval.objects.filter(name=submission.name).exists())
|
||||
requires_prev_authors_approval = Document.objects.filter(name=submission.name)
|
||||
|
||||
sent_to, desc, docDesc = send_confirmation_emails(request, submission, requires_group_approval, requires_prev_authors_approval)
|
||||
|
@ -212,7 +214,9 @@ def submission_status(request, submission_id, access_token=None):
|
|||
confirmation_list = addrs.to
|
||||
confirmation_list.extend(addrs.cc)
|
||||
|
||||
requires_group_approval = (submission.rev == '00' and submission.group and submission.group.type_id in ("wg", "rg", "ietf", "irtf", "iab", "iana", "rfcedtyp") and not Preapproval.objects.filter(name=submission.name).exists())
|
||||
requires_group_approval = (submission.rev == '00'
|
||||
and submission.group and submission.group.features.req_subm_approval
|
||||
and not Preapproval.objects.filter(name=submission.name).exists())
|
||||
|
||||
requires_prev_authors_approval = Document.objects.filter(name=submission.name)
|
||||
|
||||
|
@ -506,10 +510,11 @@ def approvals(request):
|
|||
|
||||
@role_required("Secretariat", "Area Director", "WG Chair", "RG Chair")
|
||||
def add_preapproval(request):
|
||||
groups = Group.objects.filter(type__in=("wg", "rg")).exclude(state__in=["conclude","bof-conc"]).order_by("acronym").distinct()
|
||||
groups = Group.objects.filter(type__features__acts_like_wg=True).exclude(state__in=["conclude","bof-conc"]).order_by("acronym").distinct()
|
||||
|
||||
if not has_role(request.user, "Secretariat"):
|
||||
groups = groups.filter(role__person__user=request.user,role__name__in=['ad','chair','delegate','secr'])
|
||||
groups = [ g for g in groups.filter(role__person__user=request.user)
|
||||
if Role.objects.filter(group=g, person__user=request.user, name__slug__in=g.type.features.matman_roles).exists() ]
|
||||
|
||||
if request.method == "POST":
|
||||
form = PreapprovalForm(request.POST)
|
||||
|
|
|
@ -19,7 +19,7 @@ from django.template.loader import render_to_string
|
|||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.group.models import Group, GroupURL
|
||||
from ietf.group.models import Group, GroupURL, GroupFeatures
|
||||
from ietf.utils.pipe import pipe
|
||||
|
||||
logtag = __name__.split('.')[-1]
|
||||
|
@ -216,7 +216,7 @@ class Command(BaseCommand):
|
|||
self.maybe_add_group_url(group, 'Issue tracker', settings.TRAC_ISSUE_URL_PATTERN % group.acronym)
|
||||
# Use custom assets (if any) from the master setup
|
||||
self.symlink_to_master_assets(group.trac_dir, env)
|
||||
if group.type_id in ['wg', 'rg', 'ag', ]:
|
||||
if group.features.acts_like_wg:
|
||||
self.add_wg_draft_states(group, env)
|
||||
self.add_custom_wiki_pages(group, env)
|
||||
self.add_default_wiki_pages(env)
|
||||
|
@ -338,7 +338,8 @@ class Command(BaseCommand):
|
|||
if not os.path.exists(os.path.dirname(self.svn_dir_pattern)):
|
||||
raise CommandError('The SVN base direcory specified for the SVN directories (%s) does not exist.' % os.path.dirname(self.svn_dir_pattern))
|
||||
|
||||
gfilter = Q(type__slug__in=settings.TRAC_CREATE_GROUP_TYPES, state__slug__in=settings.TRAC_CREATE_GROUP_STATES)
|
||||
gtypes = [ f.type for f in GroupFeatures.objects.filter(create_wiki=True) ]
|
||||
gfilter = Q(type__in=gtypes, state__slug__in=settings.TRAC_CREATE_GROUP_STATES)
|
||||
gfilter |= Q(acronym__in=settings.TRAC_CREATE_GROUP_ACRONYMS)
|
||||
|
||||
groups = Group.objects.filter(gfilter).order_by('acronym')
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
# Copyright The IETF Trust 2007-2019, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
# Portion Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
|
||||
|
@ -422,6 +424,8 @@ class CoverageTest(unittest.TestCase):
|
|||
if issubclass(cl, ModelOperation) or issubclass(cl, FieldOperation):
|
||||
ops.append(('schema', cl.__name__))
|
||||
elif issubclass(cl, Operation):
|
||||
if getattr(op, 'code', None) and getattr(op.code, 'interleavable', None) == True:
|
||||
continue
|
||||
ops.append(('data', cl.__name__))
|
||||
else:
|
||||
raise RuntimeError("Found unexpected operation type in migration: %s" % (op))
|
||||
|
@ -441,10 +445,15 @@ class CoverageTest(unittest.TestCase):
|
|||
unreleased.append((node, op, nm))
|
||||
# gather the transitions in operation types. We'll allow 1
|
||||
# transition, but not 2 or more.
|
||||
mixed = [ unreleased[i] for i in range(1,len(unreleased)) if unreleased[i][1] != unreleased[i-1][1] ]
|
||||
for s in range(len(unreleased)):
|
||||
# ignore leading data migrations, they run with the production
|
||||
# schema so can take any time they like
|
||||
if unreleased[s][1] != 'data':
|
||||
break
|
||||
mixed = [ unreleased[i] for i in range(s+1,len(unreleased)) if unreleased[i][1] != unreleased[i-1][1] ]
|
||||
if len(mixed) > 1:
|
||||
raise self.failureException('Found interleaved schema and data operations in unreleased migrations;'
|
||||
' please see if they can be re-ordered with all schema migrations before the data migrations:\n'
|
||||
' please see if they can be re-ordered with all data migrations before the schema migrations:\n'
|
||||
+('\n'.join([' %-6s: %-12s, %s (%s)'% (op, node.key[0], node.key[1], nm) for (node, op, nm) in unreleased ])))
|
||||
|
||||
class IetfTestRunner(DiscoverRunner):
|
||||
|
|
|
@ -10,7 +10,7 @@ coverage>=4.0.1,!=4.0.2
|
|||
#cssselect>=0.6.1 # for PyQuery
|
||||
decorator>=4.0.4
|
||||
defusedxml>=0.4.1 # for TastyPie when ussing xml; not a declared dependency
|
||||
Django>=1.11,<1.12
|
||||
Django>=1.11,!=1.11.18,<1.12 # 1.11.18 has problems exporting BinaryField from django.db.models
|
||||
django-bcrypt>=0.9.2 # for the BCrypt password hasher option. Remove when all bcrypt upgraded to argon2
|
||||
django-bootstrap3>=8.2.1,<9.0.0
|
||||
django-cors-headers>=2.4.0
|
||||
|
|
Loading…
Reference in a new issue