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'):
|
if has_role(user, 'Secretariat'):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if clist.group.type_id == 'area':
|
if clist.group.type_id in ['area', 'wg', 'rg', 'ag', 'program', ]:
|
||||||
return Role.objects.filter(name__slug='ad', person__user=user, group=clist.group).exists()
|
return Role.objects.filter(name__slug__in=clist.group.features.admin_roles, 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()
|
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -269,7 +269,9 @@ def generate_approval_mail_rfc_editor(request, doc):
|
||||||
def generate_publication_request(request, doc):
|
def generate_publication_request(request, doc):
|
||||||
group_description = ""
|
group_description = ""
|
||||||
if doc.group and doc.group.acronym != "none":
|
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")
|
e = doc.latest_event(ConsensusDocEvent, type="changed_consensus")
|
||||||
consensus = e.consensus if e else None
|
consensus = e.consensus if e else None
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django import template
|
from django import template
|
||||||
|
|
||||||
from ietf.group.models import Group
|
from ietf.group.models import Group, Role
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
@ -9,18 +9,11 @@ def managed_groups(user):
|
||||||
if not (user and hasattr(user, "is_authenticated") and user.is_authenticated):
|
if not (user and hasattr(user, "is_authenticated") and user.is_authenticated):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
groups = []
|
groups = [ g for g in Group.objects.filter(
|
||||||
# groups.extend(Group.objects.filter(
|
role__person__user=user,
|
||||||
# role__name__slug='ad',
|
type__features__has_session_materials=True,
|
||||||
# role__person__user=user,
|
state__slug__in=('active', 'bof')).select_related("type")
|
||||||
# type__slug='area',
|
if Role.objects.filter(group=g, person__user=user, name__slug__in=g.type.features.matman_roles) ]
|
||||||
# state__slug='active').select_related("type"))
|
|
||||||
|
|
||||||
groups.extend(Group.objects.filter(
|
|
||||||
role__name__slug__in=['chair', 'delegate', 'ad', ],
|
|
||||||
role__person__user=user,
|
|
||||||
type__slug__in=('rg', 'wg', 'ag', 'ietf'),
|
|
||||||
state__slug__in=('active', 'bof')).select_related("type"))
|
|
||||||
|
|
||||||
return groups
|
return groups
|
||||||
|
|
||||||
|
|
|
@ -887,17 +887,17 @@ class DocTestCase(TestCase):
|
||||||
self.client.login(username='iab-chair', password='iab-chair+password')
|
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)))
|
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc.name)))
|
||||||
self.assertEqual(r.status_code, 200)
|
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')
|
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)))
|
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc.name)))
|
||||||
self.assertEqual(r.status_code, 200)
|
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'))
|
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)))
|
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc.name)))
|
||||||
self.assertEqual(r.status_code, 200)
|
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):
|
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).
|
# Parts Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
|
# 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()
|
iesg_state_summary = doc.friendly_state()
|
||||||
can_edit = has_role(request.user, ("Area Director", "Secretariat"))
|
can_edit = has_role(request.user, ("Area Director", "Secretariat"))
|
||||||
stream_slugs = StreamName.objects.values_list("slug", flat=True)
|
stream_slugs = StreamName.objects.values_list("slug", flat=True)
|
||||||
can_change_stream = bool(can_edit or (
|
# For some reason, AnonymousUser has __iter__, but is not iterable,
|
||||||
request.user.is_authenticated and
|
# which causes problems in the filter() below. Work around this:
|
||||||
Role.objects.filter(name__in=("chair", "secr", "auth", "delegate"),
|
if request.user.is_authenticated:
|
||||||
group__acronym__in=stream_slugs,
|
roles = [ r for r in Role.objects.filter(group__acronym__in=stream_slugs, person__user=request.user)
|
||||||
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_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"))
|
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
|
# changing state and metadata on Internet Drafts
|
||||||
|
|
||||||
import datetime
|
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, )
|
set_replaces_for_document, default_consensus, tags_suffix, )
|
||||||
from ietf.doc.lastcall import request_last_call
|
from ietf.doc.lastcall import request_last_call
|
||||||
from ietf.doc.fields import SearchableDocAliasesField
|
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.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 has_role, is_authorized_in_doc_stream, user_is_person, is_individual_draft_author
|
||||||
from ietf.ietfauth.utils import role_required
|
from ietf.ietfauth.utils import role_required
|
||||||
|
@ -1294,13 +1296,15 @@ def request_publication(request, name):
|
||||||
)
|
)
|
||||||
|
|
||||||
class AdoptDraftForm(forms.Form):
|
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")
|
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)
|
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")
|
weeks = forms.IntegerField(required=False, label="Expected weeks in adoption state")
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
user = kwargs.pop("user")
|
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)
|
super(AdoptDraftForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
@ -1308,17 +1312,21 @@ class AdoptDraftForm(forms.Form):
|
||||||
if has_role(user, "Secretariat"):
|
if has_role(user, "Secretariat"):
|
||||||
state_types.update(['draft-stream-ietf','draft-stream-irtf'])
|
state_types.update(['draft-stream-ietf','draft-stream-irtf'])
|
||||||
else:
|
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')
|
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_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)
|
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 not has_role(user, "Secretariat"):
|
||||||
if has_role(user, "IRTF Chair"):
|
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:
|
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"].queryset = group_queryset
|
||||||
|
|
||||||
self.fields['group'].choices = [(g.pk, '%s - %s' % (g.acronym, g.name)) for g in self.fields["group"].queryset]
|
self.fields['group'].choices = [(g.pk, '%s - %s' % (g.acronym, g.name)) for g in self.fields["group"].queryset]
|
||||||
|
|
|
@ -102,21 +102,30 @@ admin.site.register(Group, GroupAdmin)
|
||||||
|
|
||||||
class GroupFeaturesAdmin(admin.ModelAdmin):
|
class GroupFeaturesAdmin(admin.ModelAdmin):
|
||||||
list_display = [
|
list_display = [
|
||||||
|
|
||||||
'type',
|
'type',
|
||||||
'customize_workflow',
|
|
||||||
'has_chartering_process',
|
|
||||||
'has_default_jabber',
|
|
||||||
'has_dependencies',
|
|
||||||
'has_documents',
|
|
||||||
'has_nonsession_materials',
|
|
||||||
'has_milestones',
|
'has_milestones',
|
||||||
|
'has_chartering_process',
|
||||||
|
'has_documents',
|
||||||
|
'has_dependencies',
|
||||||
|
'has_session_materials',
|
||||||
|
'has_nonsession_materials',
|
||||||
|
'has_meetings',
|
||||||
'has_reviews',
|
'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',
|
'agenda_type',
|
||||||
|
'material_types',
|
||||||
'admin_roles',
|
'admin_roles',
|
||||||
'about_page',
|
'matman_roles',
|
||||||
'default_tab',
|
'role_order',
|
||||||
]
|
]
|
||||||
admin.site.register(GroupFeatures, GroupFeaturesAdmin)
|
admin.site.register(GroupFeatures, GroupFeaturesAdmin)
|
||||||
|
|
||||||
class GroupHistoryAdmin(admin.ModelAdmin):
|
class GroupHistoryAdmin(admin.ModelAdmin):
|
||||||
|
|
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 datetime
|
||||||
import email.utils
|
import email.utils
|
||||||
|
import jsonfield
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from urlparse import urljoin
|
from urlparse import urljoin
|
||||||
|
@ -40,31 +41,20 @@ class GroupInfo(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
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):
|
def ad_role(self):
|
||||||
return self.role_set.filter(name='ad').first()
|
return self.role_set.filter(name='ad').first()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def features(self):
|
def features(self):
|
||||||
if not hasattr(self, "features_cache"):
|
if not hasattr(self, "features_cache"):
|
||||||
features = GroupFeatures.objects.get(type=self.type)
|
self.features_cache = 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
|
|
||||||
return self.features_cache
|
return self.features_cache
|
||||||
|
|
||||||
def about_url(self):
|
def about_url(self):
|
||||||
# bridge gap between group-type prefixed URLs and /group/ ones
|
# bridge gap between group-type prefixed URLs and /group/ ones
|
||||||
from django.urls import reverse as urlreverse
|
from django.urls import reverse as urlreverse
|
||||||
kwargs = { 'acronym': self.acronym }
|
kwargs = { 'acronym': self.acronym }
|
||||||
if self.type_id in ("wg", "rg", "ag"):
|
if self.features.acts_like_wg:
|
||||||
kwargs["group_type"] = self.type_id
|
kwargs["group_type"] = self.type_id
|
||||||
return urlreverse(self.features.about_page, kwargs=kwargs)
|
return urlreverse(self.features.about_page, kwargs=kwargs)
|
||||||
|
|
||||||
|
@ -214,25 +204,35 @@ validate_comma_separated_roles = RegexValidator(
|
||||||
)
|
)
|
||||||
|
|
||||||
class GroupFeatures(models.Model):
|
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()
|
history = HistoricalRecords()
|
||||||
#
|
#
|
||||||
has_milestones = models.BooleanField("Milestones", default=False)
|
has_milestones = models.BooleanField("Milestones", default=False)
|
||||||
has_chartering_process = models.BooleanField("Chartering", default=False)
|
has_chartering_process = models.BooleanField("Chartering", default=False)
|
||||||
has_documents = models.BooleanField("Documents", default=False) # i.e. drafts/RFCs
|
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_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_meetings = models.BooleanField("Meetings", default=False)
|
||||||
has_reviews = models.BooleanField("Reviews", default=False)
|
has_reviews = models.BooleanField("Reviews", default=False)
|
||||||
has_default_jabber = models.BooleanField("Jabber", 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)
|
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)
|
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" )
|
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" )
|
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",
|
material_types = jsonfield.JSONField(max_length=64, blank=False, default="slides")
|
||||||
validators=[validate_comma_separated_materials])
|
admin_roles = jsonfield.JSONField(max_length=64, blank=False, default="chair")
|
||||||
admin_roles = models.CharField(max_length=64, blank=False, default="chair",
|
matman_roles = jsonfield.JSONField(max_length=128, blank=False, default="ad,chair,delegate,secr")
|
||||||
validators=[validate_comma_separated_roles])
|
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):
|
class GroupHistory(GroupInfo):
|
||||||
|
|
|
@ -121,12 +121,12 @@ def milestone_reviewer_for_group_type(group_type):
|
||||||
return "Area Director"
|
return "Area Director"
|
||||||
|
|
||||||
def can_manage_materials(user, group):
|
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):
|
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 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):
|
def get_group_or_404(acronym, group_type):
|
||||||
"""Helper to overcome the schism between group-type prefixed URLs and generic."""
|
"""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).
|
# Portion Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
|
# 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,
|
ManageReviewRequestForm, EmailOpenAssignmentsForm, ReviewerSettingsForm,
|
||||||
AddUnavailablePeriodForm, EndUnavailablePeriodForm, ReviewSecretarySettingsForm, )
|
AddUnavailablePeriodForm, EndUnavailablePeriodForm, ReviewSecretarySettingsForm, )
|
||||||
from ietf.group.mails import email_admin_re_charter, email_personnel_change, email_comment
|
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,
|
from ietf.group.utils import (get_charter_text, can_manage_group_type,
|
||||||
milestone_reviewer_for_group_type, can_provide_status_update,
|
milestone_reviewer_for_group_type, can_provide_status_update,
|
||||||
can_manage_materials,
|
can_manage_materials,
|
||||||
|
@ -385,7 +387,8 @@ def bofs(request, group_type):
|
||||||
def chartering_groups(request):
|
def chartering_groups(request):
|
||||||
charter_states = State.objects.filter(used=True, type="charter").exclude(slug__in=("approved", "notrev"))
|
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:
|
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")
|
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)
|
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())
|
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, group.features.role_order)
|
||||||
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
|
|
||||||
for role in roles:
|
for role in roles:
|
||||||
role.last_initial = role.person.last_name()[0]
|
role.last_initial = role.person.last_name()[0]
|
||||||
return render(request, 'group/group_photos.html',
|
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)
|
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 } )
|
return render(request, 'group/stream_documents.html', {'stream':stream, 'docs':docs, 'meta':meta, 'editable':editable } )
|
||||||
|
|
||||||
|
|
||||||
def stream_edit(request, acronym):
|
def stream_edit(request, acronym):
|
||||||
group = get_object_or_404(Group, acronym=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_control(public=True, max_age=30*60)
|
||||||
@cache_page(30 * 60)
|
@cache_page(30 * 60)
|
||||||
def group_menu_data(request):
|
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)
|
groups_by_parent = defaultdict(list)
|
||||||
for g in groups:
|
for g in groups:
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# Copyright The IETF Trust 2013-2019, All Rights Reserved
|
||||||
|
|
||||||
# various authentication and authorization utilities
|
# various authentication and authorization utilities
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
@ -11,7 +13,7 @@ from django.utils.decorators import available_attrs
|
||||||
|
|
||||||
import debug # pyflakes:ignore
|
import debug # pyflakes:ignore
|
||||||
|
|
||||||
from ietf.group.models import Role
|
from ietf.group.models import Group, Role
|
||||||
from ietf.person.models import Person
|
from ietf.person.models import Person
|
||||||
|
|
||||||
def user_is_person(user, 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":
|
if doc.stream.slug == "ietf" and doc.group.type_id == "individ":
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
matman_roles = doc.group.features.matman_roles
|
||||||
if doc.stream.slug == "ietf":
|
if doc.stream.slug == "ietf":
|
||||||
group_req = Q(group=doc.group)
|
group_req = Q(group=doc.group)
|
||||||
elif doc.stream.slug == "irtf":
|
elif doc.stream.slug == "irtf":
|
||||||
group_req = Q(group__acronym=doc.stream.slug) | Q(group=doc.group)
|
group_req = Q(group__acronym=doc.stream.slug) | Q(group=doc.group)
|
||||||
elif doc.stream.slug in ("iab", "ise"):
|
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)
|
group_req = Q(group__acronym=doc.stream.slug)
|
||||||
else:
|
else:
|
||||||
group_req = Q()
|
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):
|
def is_authorized_in_group(user, group):
|
||||||
"""Return whether user is authorized to perform duties on
|
"""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',]):
|
if group.parent.acronym == 'iab' and has_role(user, ['IAB','IAB Executive Director',]):
|
||||||
return True
|
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):
|
def is_individual_draft_author(user, doc):
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ from ietf.group.models import Group
|
||||||
from ietf.mailinglists.models import List
|
from ietf.mailinglists.models import List
|
||||||
|
|
||||||
def groups(request):
|
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 } )
|
return render(request, "mailinglists/group_archives.html", { "groups": groups } )
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ def groups(request):
|
||||||
# safely cache this for some time.
|
# safely cache this for some time.
|
||||||
@cache_page(15*60)
|
@cache_page(15*60)
|
||||||
def nonwg(request):
|
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 ]
|
#urls = [ g.list_archive for g in groups if '.ietf.org' in g.list_archive ]
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ class Recipient(models.Model):
|
||||||
addrs = []
|
addrs = []
|
||||||
if 'doc' in kwargs:
|
if 'doc' in kwargs:
|
||||||
doc=kwargs['doc']
|
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)
|
addrs.append('%s-chairs@ietf.org'%doc.group.acronym)
|
||||||
return addrs
|
return addrs
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ class Recipient(models.Model):
|
||||||
addrs = []
|
addrs = []
|
||||||
if 'doc' in kwargs:
|
if 'doc' in kwargs:
|
||||||
doc=kwargs['doc']
|
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))
|
addrs.extend(doc.group.role_set.filter(name='delegate').values_list('email__address',flat=True))
|
||||||
return addrs
|
return addrs
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ class Recipient(models.Model):
|
||||||
addrs = []
|
addrs = []
|
||||||
if 'doc' in kwargs:
|
if 'doc' in kwargs:
|
||||||
doc=kwargs['doc']
|
doc=kwargs['doc']
|
||||||
if doc.group.type.slug in ['wg','rg','ag',]:
|
if doc.group.features.acts_like_wg:
|
||||||
if doc.group.list_email:
|
if doc.group.list_email:
|
||||||
addrs.append(doc.group.list_email)
|
addrs.append(doc.group.list_email)
|
||||||
return addrs
|
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"))
|
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 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}))
|
addrs.extend(Recipient.objects.get(slug='group_chairs').gather(**{'group':doc.group}))
|
||||||
elif doc.group.type_id in ['area']:
|
elif doc.group.type_id in ['area']:
|
||||||
addrs.extend(Recipient.objects.get(slug='group_responsible_directors').gather(**{'group':doc.group}))
|
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('group_'))
|
||||||
relevant.update(starts_with('milestones_'))
|
relevant.update(starts_with('milestones_'))
|
||||||
group = kwargs['group']
|
group = kwargs['group']
|
||||||
if group.type_id in ['rg','wg','ag',]:
|
if group.features.acts_like_wg:
|
||||||
relevant.update(starts_with('session_'))
|
relevant.update(starts_with('session_'))
|
||||||
if group.type_id in ['wg',]:
|
if group.features.has_chartering_process:
|
||||||
relevant.update(['charter_external_review',])
|
relevant.update(['charter_external_review',])
|
||||||
|
|
||||||
if 'submission' in kwargs:
|
if 'submission' in kwargs:
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# Copyright The IETF Trust 2009-2019, All Rights Reserved
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
@ -294,14 +295,16 @@ class MeetingTests(TestCase):
|
||||||
self.assertTrue("1. WG status" in unicontent(r))
|
self.assertTrue("1. WG status" in unicontent(r))
|
||||||
|
|
||||||
# session minutes
|
# session minutes
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.materials_document",
|
url = urlreverse("ietf.meeting.views.materials_document",
|
||||||
kwargs=dict(num=meeting.number, document=session.minutes())))
|
kwargs=dict(num=meeting.number, document=session.minutes()))
|
||||||
|
r = self.client.get(url)
|
||||||
self.assertEqual(r.status_code, 200)
|
self.assertEqual(r.status_code, 200)
|
||||||
self.assertTrue("1. More work items underway" in unicontent(r))
|
self.assertTrue("1. More work items underway" in unicontent(r))
|
||||||
|
|
||||||
# test with explicit meeting number in url
|
# test with explicit meeting number in url
|
||||||
if meeting.number.isdigit():
|
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)
|
self.assertEqual(r.status_code, 200)
|
||||||
q = PyQuery(r.content)
|
q = PyQuery(r.content)
|
||||||
row = q('#content #%s' % str(session.group.acronym)).closest("tr")
|
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\")"))
|
self.assertFalse(row.find("a:contains(\"Bad Slideshow\")"))
|
||||||
|
|
||||||
# test with no meeting number in url
|
# 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)
|
self.assertEqual(r.status_code, 200)
|
||||||
q = PyQuery(r.content)
|
q = PyQuery(r.content)
|
||||||
row = q('#content #%s' % str(session.group.acronym)).closest("tr")
|
row = q('#content #%s' % str(session.group.acronym)).closest("tr")
|
||||||
|
@ -322,7 +326,8 @@ class MeetingTests(TestCase):
|
||||||
|
|
||||||
# test with a loggged-in wg chair
|
# test with a loggged-in wg chair
|
||||||
self.client.login(username="marschairman", password="marschairman+password")
|
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)
|
self.assertEqual(r.status_code, 200)
|
||||||
q = PyQuery(r.content)
|
q = PyQuery(r.content)
|
||||||
row = q('#content #%s' % str(session.group.acronym)).closest("tr")
|
row = q('#content #%s' % str(session.group.acronym)).closest("tr")
|
||||||
|
|
|
@ -1264,8 +1264,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fields": {
|
"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.",
|
"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": "Informal IESG review",
|
"name": "Draft Charter",
|
||||||
"next_states": [],
|
"next_states": [],
|
||||||
"order": 0,
|
"order": 0,
|
||||||
"slug": "infrev",
|
"slug": "infrev",
|
||||||
|
@ -1277,8 +1277,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fields": {
|
"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",
|
"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": "Internal review",
|
"name": "Start Chartering/Rechartering (Internal IESG/IAB Review)",
|
||||||
"next_states": [],
|
"next_states": [],
|
||||||
"order": 0,
|
"order": 0,
|
||||||
"slug": "intrev",
|
"slug": "intrev",
|
||||||
|
@ -1290,8 +1290,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fields": {
|
"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.",
|
"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",
|
"name": "External Review (Message to Community, Selected by Secretariat)",
|
||||||
"next_states": [],
|
"next_states": [],
|
||||||
"order": 0,
|
"order": 0,
|
||||||
"slug": "extrev",
|
"slug": "extrev",
|
||||||
|
@ -1303,8 +1303,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fields": {
|
"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.",
|
"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",
|
"name": "IESG Review (Charter for Approval, Selected by Secretariat)",
|
||||||
"next_states": [],
|
"next_states": [],
|
||||||
"order": 0,
|
"order": 0,
|
||||||
"slug": "iesgrev",
|
"slug": "iesgrev",
|
||||||
|
@ -2181,7 +2181,7 @@
|
||||||
"used": true
|
"used": true
|
||||||
},
|
},
|
||||||
"model": "doc.state",
|
"model": "doc.state",
|
||||||
"pk": 152
|
"pk": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -2347,8 +2347,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair",
|
"acts_like_wg": true,
|
||||||
|
"admin_roles": "[\"chair\"]",
|
||||||
"agenda_type": "ietf",
|
"agenda_type": "ietf",
|
||||||
|
"create_wiki": true,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2359,7 +2362,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "ag"
|
"pk": "ag"
|
||||||
|
@ -2367,8 +2376,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "ad",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"ad\"]",
|
||||||
"agenda_type": "ietf",
|
"agenda_type": "ietf",
|
||||||
|
"create_wiki": true,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2379,7 +2391,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "area"
|
"pk": "area"
|
||||||
|
@ -2387,8 +2405,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair,secr",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"chair\",\"secr\"]",
|
||||||
"agenda_type": null,
|
"agenda_type": null,
|
||||||
|
"create_wiki": true,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2399,7 +2420,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "dir"
|
"pk": "dir"
|
||||||
|
@ -2407,8 +2434,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"chair\"]",
|
||||||
"agenda_type": "ietf",
|
"agenda_type": "ietf",
|
||||||
|
"create_wiki": false,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2419,7 +2449,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "iab"
|
"pk": "iab"
|
||||||
|
@ -2427,8 +2463,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair,lead",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"chair\",\"lead\"]",
|
||||||
"agenda_type": "ietf",
|
"agenda_type": "ietf",
|
||||||
|
"create_wiki": false,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2439,7 +2478,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "ietf"
|
"pk": "ietf"
|
||||||
|
@ -2447,8 +2492,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"chair\"]",
|
||||||
"agenda_type": null,
|
"agenda_type": null,
|
||||||
|
"create_wiki": false,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2459,7 +2507,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "individ"
|
"pk": "individ"
|
||||||
|
@ -2467,8 +2521,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"chair\"]",
|
||||||
"agenda_type": "ietf",
|
"agenda_type": "ietf",
|
||||||
|
"create_wiki": false,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2479,7 +2536,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "irtf"
|
"pk": "irtf"
|
||||||
|
@ -2487,8 +2550,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"chair\"]",
|
||||||
"agenda_type": null,
|
"agenda_type": null,
|
||||||
|
"create_wiki": false,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2499,7 +2565,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "isoc"
|
"pk": "isoc"
|
||||||
|
@ -2507,8 +2579,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"chair\"]",
|
||||||
"agenda_type": "side",
|
"agenda_type": "side",
|
||||||
|
"create_wiki": true,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2519,7 +2594,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "nomcom"
|
"pk": "nomcom"
|
||||||
|
@ -2527,8 +2608,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "lead",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"lead\"]",
|
||||||
"agenda_type": null,
|
"agenda_type": null,
|
||||||
|
"create_wiki": false,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2539,7 +2623,13 @@
|
||||||
"has_milestones": true,
|
"has_milestones": true,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "program"
|
"pk": "program"
|
||||||
|
@ -2547,8 +2637,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair,secr",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"chair\",\"secr\"]",
|
||||||
"agenda_type": null,
|
"agenda_type": null,
|
||||||
|
"create_wiki": true,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.review_requests",
|
"default_tab": "ietf.group.views.review_requests",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2559,7 +2652,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": true,
|
"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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "review"
|
"pk": "review"
|
||||||
|
@ -2567,8 +2666,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"chair\"]",
|
||||||
"agenda_type": "side",
|
"agenda_type": "side",
|
||||||
|
"create_wiki": false,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2579,7 +2681,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "rfcedtyp"
|
"pk": "rfcedtyp"
|
||||||
|
@ -2587,8 +2695,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair",
|
"acts_like_wg": true,
|
||||||
|
"admin_roles": "[\"chair\"]",
|
||||||
"agenda_type": "ietf",
|
"agenda_type": "ietf",
|
||||||
|
"create_wiki": true,
|
||||||
|
"custom_group_roles": false,
|
||||||
"customize_workflow": true,
|
"customize_workflow": true,
|
||||||
"default_tab": "ietf.group.views.group_documents",
|
"default_tab": "ietf.group.views.group_documents",
|
||||||
"has_chartering_process": true,
|
"has_chartering_process": true,
|
||||||
|
@ -2599,7 +2710,13 @@
|
||||||
"has_milestones": true,
|
"has_milestones": true,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "rg"
|
"pk": "rg"
|
||||||
|
@ -2607,8 +2724,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"chair\"]",
|
||||||
"agenda_type": null,
|
"agenda_type": null,
|
||||||
|
"create_wiki": false,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2619,7 +2739,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "sdo"
|
"pk": "sdo"
|
||||||
|
@ -2627,8 +2753,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair",
|
"acts_like_wg": false,
|
||||||
|
"admin_roles": "[\"chair\"]",
|
||||||
"agenda_type": "ietf",
|
"agenda_type": "ietf",
|
||||||
|
"create_wiki": true,
|
||||||
|
"custom_group_roles": true,
|
||||||
"customize_workflow": false,
|
"customize_workflow": false,
|
||||||
"default_tab": "ietf.group.views.group_about",
|
"default_tab": "ietf.group.views.group_about",
|
||||||
"has_chartering_process": false,
|
"has_chartering_process": false,
|
||||||
|
@ -2639,7 +2768,13 @@
|
||||||
"has_milestones": false,
|
"has_milestones": false,
|
||||||
"has_nonsession_materials": true,
|
"has_nonsession_materials": true,
|
||||||
"has_reviews": false,
|
"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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "team"
|
"pk": "team"
|
||||||
|
@ -2647,8 +2782,11 @@
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"about_page": "ietf.group.views.group_about",
|
"about_page": "ietf.group.views.group_about",
|
||||||
"admin_roles": "chair",
|
"acts_like_wg": true,
|
||||||
|
"admin_roles": "[\"chair\"]",
|
||||||
"agenda_type": "ietf",
|
"agenda_type": "ietf",
|
||||||
|
"create_wiki": true,
|
||||||
|
"custom_group_roles": false,
|
||||||
"customize_workflow": true,
|
"customize_workflow": true,
|
||||||
"default_tab": "ietf.group.views.group_documents",
|
"default_tab": "ietf.group.views.group_documents",
|
||||||
"has_chartering_process": true,
|
"has_chartering_process": true,
|
||||||
|
@ -2659,7 +2797,13 @@
|
||||||
"has_milestones": true,
|
"has_milestones": true,
|
||||||
"has_nonsession_materials": false,
|
"has_nonsession_materials": false,
|
||||||
"has_reviews": 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",
|
"model": "group.groupfeatures",
|
||||||
"pk": "wg"
|
"pk": "wg"
|
||||||
|
@ -3360,7 +3504,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"cc": [],
|
"cc": [
|
||||||
|
"liaison_admin"
|
||||||
|
],
|
||||||
"desc": "Recipients for a message that a pending liaison statement needs approval",
|
"desc": "Recipients for a message that a pending liaison statement needs approval",
|
||||||
"to": [
|
"to": [
|
||||||
"liaison_approvers"
|
"liaison_approvers"
|
||||||
|
@ -4134,6 +4280,14 @@
|
||||||
"model": "mailtrigger.recipient",
|
"model": "mailtrigger.recipient",
|
||||||
"pk": "ipr_updatedipr_holders"
|
"pk": "ipr_updatedipr_holders"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fields": {
|
||||||
|
"desc": "Alias for secretariat liaison administration",
|
||||||
|
"template": "<statements@ietf.org>"
|
||||||
|
},
|
||||||
|
"model": "mailtrigger.recipient",
|
||||||
|
"pk": "liaison_admin"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"desc": "The set of people who can approve this liasion statemetns",
|
"desc": "The set of people who can approve this liasion statemetns",
|
||||||
|
@ -10532,7 +10686,7 @@
|
||||||
"fields": {
|
"fields": {
|
||||||
"command": "xym",
|
"command": "xym",
|
||||||
"switch": "--version",
|
"switch": "--version",
|
||||||
"time": "2018-12-04T00:08:13.259",
|
"time": "2019-01-21T00:08:23.930",
|
||||||
"used": true,
|
"used": true,
|
||||||
"version": "xym 0.4"
|
"version": "xym 0.4"
|
||||||
},
|
},
|
||||||
|
@ -10543,7 +10697,7 @@
|
||||||
"fields": {
|
"fields": {
|
||||||
"command": "pyang",
|
"command": "pyang",
|
||||||
"switch": "--version",
|
"switch": "--version",
|
||||||
"time": "2018-12-04T00:08:13.958",
|
"time": "2019-01-21T00:08:25.229",
|
||||||
"used": true,
|
"used": true,
|
||||||
"version": "pyang 1.7.5"
|
"version": "pyang 1.7.5"
|
||||||
},
|
},
|
||||||
|
@ -10554,7 +10708,7 @@
|
||||||
"fields": {
|
"fields": {
|
||||||
"command": "yanglint",
|
"command": "yanglint",
|
||||||
"switch": "--version",
|
"switch": "--version",
|
||||||
"time": "2018-12-04T00:08:14.121",
|
"time": "2019-01-21T00:08:25.465",
|
||||||
"used": true,
|
"used": true,
|
||||||
"version": "yanglint 0.14.80"
|
"version": "yanglint 0.14.80"
|
||||||
},
|
},
|
||||||
|
@ -10565,9 +10719,9 @@
|
||||||
"fields": {
|
"fields": {
|
||||||
"command": "xml2rfc",
|
"command": "xml2rfc",
|
||||||
"switch": "--version",
|
"switch": "--version",
|
||||||
"time": "2018-12-04T00:08:15.775",
|
"time": "2019-01-21T00:08:26.897",
|
||||||
"used": true,
|
"used": true,
|
||||||
"version": "xml2rfc 2.15.2"
|
"version": "xml2rfc 2.16.3"
|
||||||
},
|
},
|
||||||
"model": "utils.versioninfo",
|
"model": "utils.versioninfo",
|
||||||
"pk": 4
|
"pk": 4
|
||||||
|
|
|
@ -712,7 +712,7 @@ def setup_reviewer_field(field, review_req):
|
||||||
def get_default_filter_re(person):
|
def get_default_filter_re(person):
|
||||||
if type(person) != Person:
|
if type(person) != Person:
|
||||||
person = Person.objects.get(id=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:
|
if not groups_to_avoid:
|
||||||
return '^draft-%s-.*$' % ( person.last_name().lower(), )
|
return '^draft-%s-.*$' % ( person.last_name().lower(), )
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -78,7 +78,7 @@ class GroupModelForm(forms.ModelForm):
|
||||||
parent = self.cleaned_data['parent']
|
parent = self.cleaned_data['parent']
|
||||||
type = self.cleaned_data['type']
|
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.")
|
raise forms.ValidationError("This field is required.")
|
||||||
|
|
||||||
return parent
|
return parent
|
||||||
|
@ -130,8 +130,7 @@ class RoleForm(forms.Form):
|
||||||
self.group = kwargs.pop('group')
|
self.group = kwargs.pop('group')
|
||||||
super(RoleForm, self).__init__(*args,**kwargs)
|
super(RoleForm, self).__init__(*args,**kwargs)
|
||||||
# this form is re-used in roles app, use different roles in select
|
# this form is re-used in roles app, use different roles in select
|
||||||
# TODO: should 'ag' be excluded here as well?
|
if self.group.features.custom_group_roles:
|
||||||
if self.group.type.slug not in ('wg','rg'):
|
|
||||||
self.fields['name'].queryset = RoleName.objects.all()
|
self.fields['name'].queryset = RoleName.objects.all()
|
||||||
|
|
||||||
# check for id within parenthesis to ensure name was selected from the list
|
# 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
|
# These states aren't available in forms with drop-down choices for new
|
||||||
# document state:
|
# document state:
|
||||||
GROUP_STATES_WITH_EXTRA_PROCESSING = ["sub-pub", "rfc-edit", ]
|
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"
|
DATE_FORMAT = "Y-m-d"
|
||||||
DATETIME_FORMAT = "Y-m-d H:i T"
|
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_DIR_PATTERN = "/a/svn/group/%s"
|
||||||
#TRAC_SVN_URL_PATTERN = "https://svn.ietf.org/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_STATES = ['bof', 'active', ]
|
||||||
TRAC_CREATE_GROUP_ACRONYMS = ['iesg', 'iaoc', 'ietf', ]
|
TRAC_CREATE_GROUP_ACRONYMS = ['iesg', 'iaoc', 'ietf', ]
|
||||||
TRAC_CREATE_ADHOC_WIKIS = [
|
TRAC_CREATE_ADHOC_WIKIS = [
|
||||||
|
|
|
@ -466,7 +466,7 @@ class PreapprovalForm(forms.Form):
|
||||||
if not components[-1]:
|
if not components[-1]:
|
||||||
raise forms.ValidationError("Name ends with a dash.")
|
raise forms.ValidationError("Name ends with a dash.")
|
||||||
acronym = components[2]
|
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.")
|
raise forms.ValidationError("Group acronym not recognized as one you can approve drafts for.")
|
||||||
|
|
||||||
if Preapproval.objects.filter(name=n):
|
if Preapproval.objects.filter(name=n):
|
||||||
|
|
|
@ -556,7 +556,7 @@ def preapprovals_for_user(user):
|
||||||
if has_role(user, "Secretariat"):
|
if has_role(user, "Secretariat"):
|
||||||
return res
|
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))
|
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 re
|
||||||
import base64
|
import base64
|
||||||
|
@ -17,7 +17,7 @@ import debug # pyflakes:ignore
|
||||||
|
|
||||||
from ietf.doc.models import Document, DocAlias, AddedMessageEvent
|
from ietf.doc.models import Document, DocAlias, AddedMessageEvent
|
||||||
from ietf.doc.utils import prettify_std_name
|
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.ietfauth.utils import has_role, role_required
|
||||||
from ietf.mailtrigger.utils import gather_address_lists
|
from ietf.mailtrigger.utils import gather_address_lists
|
||||||
from ietf.message.models import Message, MessageAttachment
|
from ietf.message.models import Message, MessageAttachment
|
||||||
|
@ -124,7 +124,9 @@ def api_submit(request):
|
||||||
submission.submitter = user.person.formatted_email()
|
submission.submitter = user.person.formatted_email()
|
||||||
docevent_from_submission(request, submission, desc="Uploaded new revision")
|
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)
|
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)
|
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 = addrs.to
|
||||||
confirmation_list.extend(addrs.cc)
|
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)
|
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")
|
@role_required("Secretariat", "Area Director", "WG Chair", "RG Chair")
|
||||||
def add_preapproval(request):
|
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"):
|
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":
|
if request.method == "POST":
|
||||||
form = PreapprovalForm(request.POST)
|
form = PreapprovalForm(request.POST)
|
||||||
|
|
|
@ -19,7 +19,7 @@ from django.template.loader import render_to_string
|
||||||
|
|
||||||
import debug # pyflakes:ignore
|
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
|
from ietf.utils.pipe import pipe
|
||||||
|
|
||||||
logtag = __name__.split('.')[-1]
|
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)
|
self.maybe_add_group_url(group, 'Issue tracker', settings.TRAC_ISSUE_URL_PATTERN % group.acronym)
|
||||||
# Use custom assets (if any) from the master setup
|
# Use custom assets (if any) from the master setup
|
||||||
self.symlink_to_master_assets(group.trac_dir, env)
|
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_wg_draft_states(group, env)
|
||||||
self.add_custom_wiki_pages(group, env)
|
self.add_custom_wiki_pages(group, env)
|
||||||
self.add_default_wiki_pages(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)):
|
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))
|
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)
|
gfilter |= Q(acronym__in=settings.TRAC_CREATE_GROUP_ACRONYMS)
|
||||||
|
|
||||||
groups = Group.objects.filter(gfilter).order_by('acronym')
|
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).
|
# Portion Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
|
# 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):
|
if issubclass(cl, ModelOperation) or issubclass(cl, FieldOperation):
|
||||||
ops.append(('schema', cl.__name__))
|
ops.append(('schema', cl.__name__))
|
||||||
elif issubclass(cl, Operation):
|
elif issubclass(cl, Operation):
|
||||||
|
if getattr(op, 'code', None) and getattr(op.code, 'interleavable', None) == True:
|
||||||
|
continue
|
||||||
ops.append(('data', cl.__name__))
|
ops.append(('data', cl.__name__))
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Found unexpected operation type in migration: %s" % (op))
|
raise RuntimeError("Found unexpected operation type in migration: %s" % (op))
|
||||||
|
@ -441,10 +445,15 @@ class CoverageTest(unittest.TestCase):
|
||||||
unreleased.append((node, op, nm))
|
unreleased.append((node, op, nm))
|
||||||
# gather the transitions in operation types. We'll allow 1
|
# gather the transitions in operation types. We'll allow 1
|
||||||
# transition, but not 2 or more.
|
# 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:
|
if len(mixed) > 1:
|
||||||
raise self.failureException('Found interleaved schema and data operations in unreleased migrations;'
|
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 ])))
|
+('\n'.join([' %-6s: %-12s, %s (%s)'% (op, node.key[0], node.key[1], nm) for (node, op, nm) in unreleased ])))
|
||||||
|
|
||||||
class IetfTestRunner(DiscoverRunner):
|
class IetfTestRunner(DiscoverRunner):
|
||||||
|
|
|
@ -10,7 +10,7 @@ coverage>=4.0.1,!=4.0.2
|
||||||
#cssselect>=0.6.1 # for PyQuery
|
#cssselect>=0.6.1 # for PyQuery
|
||||||
decorator>=4.0.4
|
decorator>=4.0.4
|
||||||
defusedxml>=0.4.1 # for TastyPie when ussing xml; not a declared dependency
|
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-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-bootstrap3>=8.2.1,<9.0.0
|
||||||
django-cors-headers>=2.4.0
|
django-cors-headers>=2.4.0
|
||||||
|
|
Loading…
Reference in a new issue