From e8a59ce1e56ad0cb454b5f7f828fc43c0449a3a0 Mon Sep 17 00:00:00 2001 From: Henrik Levkowetz Date: Thu, 21 Feb 2019 15:27:58 +0000 Subject: [PATCH] Rewrote the submission deduce_group() to consider all groups with acronyms that are also GroupTypeNames. Added GroupTypeName for iesg,ise,adhoc groups, and appropriate GroupFeatures for each. Updated the names.json fixture. - Legacy-Id: 15960 --- ietf/bin/generate-wg-aliases | 19 ++- ietf/group/migrations/0011_add_group_types.py | 157 ++++++++++++++++++ ietf/name/fixtures/names.json | 131 ++++++++++++++- ietf/submit/forms.py | 43 +++-- 4 files changed, 318 insertions(+), 32 deletions(-) create mode 100644 ietf/group/migrations/0011_add_group_types.py diff --git a/ietf/bin/generate-wg-aliases b/ietf/bin/generate-wg-aliases index 26cf1dd0c..07804c3e4 100755 --- a/ietf/bin/generate-wg-aliases +++ b/ietf/bin/generate-wg-aliases @@ -34,6 +34,7 @@ import debug # pyflakes:ignore from ietf.group.models import Group from ietf.group.utils import get_group_ad_emails, get_group_role_emails, get_child_group_role_emails +from ietf.name.models import GroupTypeName from ietf.utils.aliases import dump_sublist # from secr/utils/group.py.. @@ -82,20 +83,16 @@ if __name__ == '__main__': # - Research groups ----------------------------------------- rgs = Group.objects.filter(type='rg').all() - debug.pprint('rgs') - + # - status = Active active_rgs = rgs.filter(state__in=ACTIVE_STATES) - debug.pprint('active_rgs') # - activity within last year? (use concluded_date) inactive_recent_rgs = rgs.exclude(state__in=ACTIVE_STATES).filter(time__gte=show_since) interesting_rgs = active_rgs | inactive_recent_rgs - debug.pprint('interesting_rgs') for rg in interesting_rgs.distinct().iterator(): name = rg.acronym - debug.show('rg.acronym') #dump_sublist('%s%s' % (name, '-ads'), get_group_ad_emails, rg, True) dump_sublist(afile, vfile, name+'-chairs', ['ietf.org', 'irtf.org', ], settings.GROUP_VIRTUAL_DOMAIN, get_group_role_emails(rg, ['chair', 'secr'])) @@ -115,7 +112,7 @@ if __name__ == '__main__': dump_sublist(afile, vfile, name+'-chairs', ['ietf.org', ], settings.GROUP_VIRTUAL_DOMAIN, get_group_role_emails(directorate, ['chair', 'secr'])) # - Areas -------------------------------------------------- - # Additionally, for areaz, we should list -ads and -chairs + # Additionally, for areas, we should list -ads and -chairs # (for every chair in active groups within the area). areas = Group.objects.filter(type='area').all() active_areas = areas.filter(state__in=ACTIVE_STATES) @@ -125,3 +122,13 @@ if __name__ == '__main__': dump_sublist(afile, vfile, name+'-ads' , ['ietf.org', ], settings.GROUP_VIRTUAL_DOMAIN, area_ad_emails) dump_sublist(afile, vfile, name+'-chairs', ['ietf.org', ], settings.GROUP_VIRTUAL_DOMAIN, (get_child_group_role_emails(area, ['chair', 'secr']) | area_ad_emails)) + + # - Special groups -------------------------------------------------- + # We need to be able to send mail to chairs of groups that require + # group draft submission approval and don't otherwise have aliases + gtypes = GroupTypeName.objects.values_list('slug', flat=True) + special_groups = Group.objects.filter(type__features__req_subm_approval=True, acronym__in=gtypes, state='active') + for group in special_groups: + dump_sublist(afile, vfile, group.acronym+'-chairs', ['ietf.org', ], settings.GROUP_VIRTUAL_DOMAIN, get_group_role_emails(group, ['chair', 'delegate'])) + + diff --git a/ietf/group/migrations/0011_add_group_types.py b/ietf/group/migrations/0011_add_group_types.py new file mode 100644 index 000000000..ffb6b0a79 --- /dev/null +++ b/ietf/group/migrations/0011_add_group_types.py @@ -0,0 +1,157 @@ +# 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 = { + 'adhoc': { + 'grouptypename': { + "slug": 'adhoc', + "desc": 'Ad Hoc schedulable Group Type, for instance HotRfc', + "name": "Ad Hoc", + "order": 0, + "used": True, + "verbose_name": "Ad Hoc Group Type", + }, + 'groupfeatures': { + 'about_page': 'ietf.group.views.group_about', + 'acts_like_wg': False, + 'admin_roles': '["chair"]', + 'agenda_type_id': 'ietf', + 'create_wiki': True, + 'custom_group_roles': False, + 'customize_workflow': False, + 'default_tab': 'ietf.group.views.group_about', + 'docman_roles': '["chair"]', + 'groupman_roles': '["chair","delegate"]', + 'has_chartering_process': False, + 'has_default_jabber': True, + 'has_documents': False, + 'has_meetings': True, + 'has_milestones': False, + 'has_nonsession_materials': False, + 'has_reviews': False, + 'has_session_materials': True, + 'is_schedulable': True, + 'material_types': '["slides"]', + 'matman_roles': '["chair","delegate"]', + 'req_subm_approval': True, + 'role_order': '["chair","delegate"]', + 'show_on_agenda': True, + }, + }, + 'iesg': { + 'grouptypename': { + "slug": 'iesg', + "desc": '', + "name": "IESG", + "order": 0, + "used": True, + "verbose_name": "Internet Engineering Steering Group" + }, + 'groupfeatures': { + 'about_page': 'ietf.group.views.group_about', + 'acts_like_wg': False, + 'admin_roles': '["chair"]', + 'agenda_type_id': None, + 'create_wiki': False, + 'custom_group_roles': True, + 'customize_workflow': False, + 'default_tab': 'ietf.group.views.group_about', + 'docman_roles': '["chair"]', + 'groupman_roles': '["chair","delegate"]', + 'has_chartering_process': False, + 'has_default_jabber': False, + 'has_documents': False, + 'has_meetings': False, + 'has_milestones': False, + 'has_nonsession_materials': False, + 'has_reviews': False, + 'has_session_materials': False, + 'is_schedulable': False, + 'material_types': '[]', + 'matman_roles': '["chair","delegate"]', + 'req_subm_approval': True, + 'role_order': '["chair","secr"]', + 'show_on_agenda': False + }, + }, + 'ise': { + 'grouptypename': { + "slug": 'ise', + "desc": '', + "name": "ISE", + "order": 0, + "used": True, + "verbose_name": "Independent Stream Editor", + }, + 'groupfeatures': { + 'about_page': 'ietf.group.views.group_about', + 'acts_like_wg': False, + 'admin_roles': '["chair","lead"]', + 'agenda_type_id': None, + 'create_wiki': False, + 'custom_group_roles': True, + 'customize_workflow': False, + 'default_tab': 'ietf.group.views.group_about', + 'docman_roles': '["chair"]', + 'groupman_roles': '["chair","delegate"]', + 'has_chartering_process': False, + 'has_default_jabber': False, + 'has_documents': False, + 'has_meetings': False, + 'has_milestones': False, + 'has_nonsession_materials': False, + 'has_reviews': False, + 'has_session_materials': False, + 'is_schedulable': False, + 'material_types': '[]', + 'matman_roles': '["chair","delegate"]', + 'req_subm_approval': True, + 'role_order': '["chair"]', + 'show_on_agenda': False + }, + }, +} + +def forward(apps, schema_editor): + GroupTypeName = apps.get_model('name', 'GroupTypeName') + GroupFeatures = apps.get_model('group', 'GroupFeatures') + for slug in group_type_features: + typename = group_type_features[slug]['grouptypename'] + gt, _ = GroupTypeName.objects.get_or_create(slug=slug) + for k,v in typename.items(): + setattr(gt, k, v) + gt.save() + # + features = group_type_features[slug]['groupfeatures'] + gf, _ = GroupFeatures.objects.get_or_create(type_id=slug) + for k,v in features.items(): + setattr(gf, k, v) + gf.save() + + +# This migration does not remove or change any previous fields, and executes +# swirftly, so we permit it to be interleaved with schema migrations +forward.interleavable = True + +def reverse(apps, schema_editor): + pass + +class Migration(migrations.Migration): + + dependencies = [ + ('group', '0010_remove_groupfeatures_has_dependencies') + ] + + operations = [ + migrations.RunPython(forward, reverse), + ] diff --git a/ietf/name/fixtures/names.json b/ietf/name/fixtures/names.json index 5720879bd..53fa91ec1 100644 --- a/ietf/name/fixtures/names.json +++ b/ietf/name/fixtures/names.json @@ -2344,6 +2344,36 @@ "model": "doc.statetype", "pk": "statchg" }, + { + "fields": { + "about_page": "ietf.group.views.group_about", + "acts_like_wg": false, + "admin_roles": "\"[\\\"chair\\\"]\"", + "agenda_type": "ietf", + "create_wiki": true, + "custom_group_roles": false, + "customize_workflow": false, + "default_tab": "ietf.group.views.group_about", + "docman_roles": "\"[\\\"chair\\\"]\"", + "groupman_roles": "\"[\\\"chair\\\",\\\"delegate\\\"]\"", + "has_chartering_process": false, + "has_default_jabber": true, + "has_documents": false, + "has_meetings": true, + "has_milestones": false, + "has_nonsession_materials": false, + "has_reviews": false, + "has_session_materials": true, + "is_schedulable": true, + "material_types": "\"[\\\"slides\\\"]\"", + "matman_roles": "\"[\\\"chair\\\",\\\"delegate\\\"]\"", + "req_subm_approval": true, + "role_order": "\"[\\\"chair\\\",\\\"delegate\\\"]\"", + "show_on_agenda": true + }, + "model": "group.groupfeatures", + "pk": "adhoc" + }, { "fields": { "about_page": "ietf.group.views.group_about", @@ -2464,6 +2494,36 @@ "model": "group.groupfeatures", "pk": "iab" }, + { + "fields": { + "about_page": "ietf.group.views.group_about", + "acts_like_wg": false, + "admin_roles": "\"[\\\"chair\\\"]\"", + "agenda_type": null, + "create_wiki": false, + "custom_group_roles": true, + "customize_workflow": false, + "default_tab": "ietf.group.views.group_about", + "docman_roles": "\"[\\\"chair\\\"]\"", + "groupman_roles": "\"[\\\"chair\\\",\\\"delegate\\\"]\"", + "has_chartering_process": false, + "has_default_jabber": false, + "has_documents": false, + "has_meetings": false, + "has_milestones": false, + "has_nonsession_materials": false, + "has_reviews": false, + "has_session_materials": false, + "is_schedulable": false, + "material_types": "\"[]\"", + "matman_roles": "\"[\\\"chair\\\",\\\"delegate\\\"]\"", + "req_subm_approval": true, + "role_order": "\"[\\\"chair\\\",\\\"secr\\\"]\"", + "show_on_agenda": false + }, + "model": "group.groupfeatures", + "pk": "iesg" + }, { "fields": { "about_page": "ietf.group.views.group_about", @@ -2554,6 +2614,36 @@ "model": "group.groupfeatures", "pk": "irtf" }, + { + "fields": { + "about_page": "ietf.group.views.group_about", + "acts_like_wg": false, + "admin_roles": "\"[\\\"chair\\\",\\\"lead\\\"]\"", + "agenda_type": null, + "create_wiki": false, + "custom_group_roles": true, + "customize_workflow": false, + "default_tab": "ietf.group.views.group_about", + "docman_roles": "\"[\\\"chair\\\"]\"", + "groupman_roles": "\"[\\\"chair\\\",\\\"delegate\\\"]\"", + "has_chartering_process": false, + "has_default_jabber": false, + "has_documents": false, + "has_meetings": false, + "has_milestones": false, + "has_nonsession_materials": false, + "has_reviews": false, + "has_session_materials": false, + "is_schedulable": false, + "material_types": "\"[]\"", + "matman_roles": "\"[\\\"chair\\\",\\\"delegate\\\"]\"", + "req_subm_approval": true, + "role_order": "\"[\\\"chair\\\"]\"", + "show_on_agenda": false + }, + "model": "group.groupfeatures", + "pk": "ise" + }, { "fields": { "about_page": "ietf.group.views.group_about", @@ -8843,6 +8933,17 @@ "model": "name.groupstatename", "pk": "unknown" }, + { + "fields": { + "desc": "Ad Hoc schedulable Group Type, for instance HotRfc", + "name": "Ad Hoc", + "order": 0, + "used": true, + "verbose_name": "Ad Hoc Group Type" + }, + "model": "name.grouptypename", + "pk": "adhoc" + }, { "fields": { "desc": "Area group", @@ -8887,6 +8988,17 @@ "model": "name.grouptypename", "pk": "iab" }, + { + "fields": { + "desc": "", + "name": "IESG", + "order": 0, + "used": true, + "verbose_name": "Internet Engineering Steering Group" + }, + "model": "name.grouptypename", + "pk": "iesg" + }, { "fields": { "desc": "", @@ -8920,6 +9032,17 @@ "model": "name.grouptypename", "pk": "irtf" }, + { + "fields": { + "desc": "", + "name": "ISE", + "order": 0, + "used": true, + "verbose_name": "Independent Stream Editor" + }, + "model": "name.grouptypename", + "pk": "ise" + }, { "fields": { "desc": "", @@ -10702,7 +10825,7 @@ "fields": { "command": "xym", "switch": "--version", - "time": "2019-02-06T00:08:09.183", + "time": "2019-02-18T00:07:55.553", "used": true, "version": "xym 0.4" }, @@ -10713,7 +10836,7 @@ "fields": { "command": "pyang", "switch": "--version", - "time": "2019-02-06T00:08:10.172", + "time": "2019-02-18T00:07:56.776", "used": true, "version": "pyang 1.7.8" }, @@ -10724,7 +10847,7 @@ "fields": { "command": "yanglint", "switch": "--version", - "time": "2019-02-06T00:08:10.404", + "time": "2019-02-18T00:07:57.000", "used": true, "version": "yanglint 0.14.80" }, @@ -10735,7 +10858,7 @@ "fields": { "command": "xml2rfc", "switch": "--version", - "time": "2019-02-06T00:08:11.933", + "time": "2019-02-18T00:07:58.212", "used": true, "version": "xml2rfc 2.17.2" }, diff --git a/ietf/submit/forms.py b/ietf/submit/forms.py index 48adfa189..3a5da6cf9 100644 --- a/ietf/submit/forms.py +++ b/ietf/submit/forms.py @@ -22,7 +22,7 @@ from ietf.doc.fields import SearchableDocAliasesField from ietf.ipr.mail import utc_from_string from ietf.meeting.models import Meeting from ietf.message.models import Message -from ietf.name.models import FormalLanguageName +from ietf.name.models import FormalLanguageName, GroupTypeName from ietf.submit.models import Submission, Preapproval from ietf.submit.utils import validate_submission_rev, validate_submission_document_date from ietf.submit.parsers.pdf_parser import PDFParser @@ -293,43 +293,42 @@ class SubmissionBaseUploadForm(forms.Form): else: return None else: - if name.startswith('draft-ietf-') or name.startswith("draft-irtf-"): - components = name.split("-") - if len(components) < 3: - raise forms.ValidationError(u"The draft name \"%s\" is missing a third part, please rename it" % name) + name_parts = name.split("-") + if len(name_parts) < 3: + raise forms.ValidationError(u"The draft name \"%s\" is missing a third part, please rename it" % name) - if components[1] == "ietf": + if name.startswith('draft-ietf-') or name.startswith("draft-irtf-"): + + if name_parts[1] == "ietf": group_type = "wg" - elif components[1] == "irtf": + elif name_parts[1] == "irtf": group_type = "rg" # first check groups with dashes for g in Group.objects.filter(acronym__contains="-", type=group_type): - if name.startswith('draft-%s-%s-' % (components[1], g.acronym)): + if name.startswith('draft-%s-%s-' % (name_parts[1], g.acronym)): return g try: - return Group.objects.get(acronym=components[2], type=group_type) + return Group.objects.get(acronym=name_parts[2], type=group_type) except Group.DoesNotExist: - raise forms.ValidationError('There is no active group with acronym \'%s\', please rename your draft' % components[2]) + raise forms.ValidationError('There is no active group with acronym \'%s\', please rename your draft' % name_parts[2]) elif name.startswith("draft-rfc-"): return Group.objects.get(acronym="iesg") - - elif name.startswith("draft-irtf-"): - return Group.objects.get(acronym="irtf") - - elif name.startswith("draft-iab-"): - return Group.objects.get(acronym="iab") - - elif name.startswith("draft-iana-"): - return Group.objects.get(acronym="iana") - elif name.startswith("draft-rfc-editor-") or name.startswith("draft-rfced-") or name.startswith("draft-rfceditor-"): return Group.objects.get(acronym="rfceditor") - else: - return None + ntype = name_parts[1].lower() + debug.show('ntype') + # This covers group types iesg, iana, iab, ise, and others: + if GroupTypeName.objects.filter(slug=ntype).exists(): + group = Group.objects.filter(acronym=ntype).first() + if group: + return group + else: + raise forms.ValidationError('Draft names starting with draft-%s- are restricted, please pick a differen name' % ntype) + return None class SubmissionManualUploadForm(SubmissionBaseUploadForm): xml = forms.FileField(label=u'.xml format', required=False) # xml field with required=False instead of True