Merged in [17764] from rjsparks@nostrum.com:
Allow IAB programs to use normal meeting mechanics. Fixes #2970.
- Legacy-Id: 17773
Note: SVN reference [17764] has been migrated to Git commit fb8e5c6842
This commit is contained in:
commit
a26ace5bfa
|
@ -18,6 +18,15 @@ class GroupFactory(factory.DjangoModelFactory):
|
|||
list_email = factory.LazyAttribute(lambda a: '%s@ietf.org'% a.acronym)
|
||||
uses_milestone_dates = True
|
||||
|
||||
@factory.lazy_attribute
|
||||
def parent(self):
|
||||
if self.type_id in ['wg','ag']:
|
||||
return GroupFactory(type_id='area')
|
||||
elif self.type_id in ['rg']:
|
||||
return GroupFactory(acronym='irtf', type_id='irtf')
|
||||
else:
|
||||
return None
|
||||
|
||||
class ReviewTeamFactory(GroupFactory):
|
||||
|
||||
type_id = 'review'
|
||||
|
|
26
ietf/group/migrations/0024_add_groupman_authroles.py
Normal file
26
ietf/group/migrations/0024_add_groupman_authroles.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.29 on 2020-05-04 13:10
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
import jsonfield.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0023_use_milestone_dates_default_to_true'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='groupfeatures',
|
||||
name='groupman_authroles',
|
||||
field=jsonfield.fields.JSONField(default=['Secretariat'], max_length=128),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='groupman_authroles',
|
||||
field=jsonfield.fields.JSONField(default=['Secretariat'], max_length=128),
|
||||
),
|
||||
]
|
47
ietf/group/migrations/0025_populate_groupman_authroles.py
Normal file
47
ietf/group/migrations/0025_populate_groupman_authroles.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.29 on 2020-05-01 12:54
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
authroles_map = {
|
||||
'adhoc': ['Secretariat'],
|
||||
'admin': ['Secretariat'],
|
||||
'ag': ['Secretariat', 'Area Director'],
|
||||
'area': ['Secretariat'],
|
||||
'dir': ['Secretariat'],
|
||||
'iab': ['Secretariat'],
|
||||
'iana': ['Secretariat'],
|
||||
'iesg': ['Secretariat'],
|
||||
'ietf': ['Secretariat'],
|
||||
'individ': [],
|
||||
'irtf': ['Secretariat'],
|
||||
'ise': ['Secretariat'],
|
||||
'isoc': ['Secretariat'],
|
||||
'nomcom': ['Secretariat'],
|
||||
'program': ['Secretariat', 'IAB'],
|
||||
'review': ['Secretariat'],
|
||||
'rfcedtyp': ['Secretariat'],
|
||||
'rg': ['Secretariat', 'IRTF Chair'],
|
||||
'sdo': ['Secretariat'],
|
||||
'team': ['Secretariat'],
|
||||
'wg': ['Secretariat', 'Area Director'],
|
||||
}
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
GroupFeatures = apps.get_model('group', 'GroupFeatures')
|
||||
for type_id, authroles in authroles_map.items():
|
||||
GroupFeatures.objects.filter(type_id=type_id).update(groupman_authroles=authroles)
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
pass
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0024_add_groupman_authroles'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse),
|
||||
]
|
36
ietf/group/migrations/0026_programs_meet.py
Normal file
36
ietf/group/migrations/0026_programs_meet.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.29 on 2020-05-01 12:54
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
GroupFeatures = apps.get_model('group', 'GroupFeatures')
|
||||
program = GroupFeatures.objects.get(type_id='program')
|
||||
program.has_meetings = True
|
||||
program.matman_roles = ['lead', 'chair', 'secr']
|
||||
program.docman_roles = ['lead', 'chair', 'secr']
|
||||
program.groupman_roles = ['lead', 'chair', 'secr']
|
||||
program.role_order = ['lead', 'chair', 'secr']
|
||||
program.save()
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
GroupFeatures = apps.get_model('group', 'GroupFeatures')
|
||||
program = GroupFeatures.objects.get(type_id='program')
|
||||
program.has_meetings = False
|
||||
program.matman_roles = ['lead', 'secr']
|
||||
program.docman_roles = ['lead', 'secr']
|
||||
program.groupman_roles = ['lead', 'secr']
|
||||
program.role_order = ['lead', 'secr']
|
||||
program.save()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0025_populate_groupman_authroles'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse),
|
||||
]
|
23
ietf/group/migrations/0027_programs_have_parents.py
Normal file
23
ietf/group/migrations/0027_programs_have_parents.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.29 on 2020-05-08 09:02
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
Group = apps.get_model('group','Group')
|
||||
iab = Group.objects.get(acronym='iab')
|
||||
Group.objects.filter(type_id='program').update(parent=iab)
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
pass # No point in removing the parents
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0026_programs_meet'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse),
|
||||
]
|
|
@ -65,9 +65,6 @@ class GroupInfo(models.Model):
|
|||
kwargs["group_type"] = self.type_id
|
||||
return urlreverse(self.features.about_page, kwargs=kwargs)
|
||||
|
||||
def interim_approval_roles(self):
|
||||
return list(set([ role for role in self.parent.role_set.filter(name__in=['ad', 'chair']) ]))
|
||||
|
||||
def is_bof(self):
|
||||
return self.state_id in ["bof", "bof-conc"]
|
||||
|
||||
|
@ -238,6 +235,7 @@ class GroupFeatures(models.Model):
|
|||
admin_roles = jsonfield.JSONField(max_length=64, blank=False, default=["chair"]) # Trac Admin
|
||||
docman_roles = jsonfield.JSONField(max_length=128, blank=False, default=["ad","chair","delegate","secr"])
|
||||
groupman_roles = jsonfield.JSONField(max_length=128, blank=False, default=["ad","chair",])
|
||||
groupman_authroles = jsonfield.JSONField(max_length=128, blank=False, default=["Secretariat",])
|
||||
matman_roles = jsonfield.JSONField(max_length=128, blank=False, default=["ad","chair","delegate","secr"])
|
||||
role_order = jsonfield.JSONField(max_length=128, blank=False, default=["chair","secr","member"],
|
||||
help_text="The order in which roles are shown, for instance on photo pages. Enter valid JSON.")
|
||||
|
|
|
@ -264,7 +264,7 @@ class GroupPagesTests(TestCase):
|
|||
can_edit = {
|
||||
'wg' : ['secretary','ad'],
|
||||
'rg' : ['secretary','irtf-chair'],
|
||||
'ag' : ['secretary', ],
|
||||
'ag' : ['secretary', 'ad' ],
|
||||
'team' : ['secretary',], # The code currently doesn't let ads edit teams or directorates. Maybe it should.
|
||||
'dir' : ['secretary',],
|
||||
'review' : ['secretary',],
|
||||
|
|
|
@ -15,7 +15,7 @@ import debug # pyflakes:ignore
|
|||
from ietf.community.models import CommunityList, SearchRule
|
||||
from ietf.community.utils import reset_name_contains_index_for_rule, can_manage_community_list
|
||||
from ietf.doc.models import Document, State
|
||||
from ietf.group.models import Group, RoleHistory, Role
|
||||
from ietf.group.models import Group, RoleHistory, Role, GroupFeatures
|
||||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.name.models import GroupTypeName
|
||||
from ietf.person.models import Email
|
||||
|
@ -105,6 +105,7 @@ def save_milestone_in_history(milestone):
|
|||
|
||||
return h
|
||||
|
||||
# TODO: rework this using features.groupman_authroles
|
||||
def can_manage_group_type(user, group, type_id=None):
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
|
@ -125,8 +126,11 @@ def can_manage_group_type(user, group, type_id=None):
|
|||
return has_role(user, ('Secretariat'))
|
||||
|
||||
def can_manage_group(user, group):
|
||||
if can_manage_group_type(user, group):
|
||||
return True
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
for authrole in group.features.groupman_authroles:
|
||||
if has_role(user, authrole):
|
||||
return True
|
||||
return group.has_role(user, group.features.groupman_roles)
|
||||
|
||||
def milestone_reviewer_for_group_type(group_type):
|
||||
|
@ -141,6 +145,18 @@ def can_manage_materials(user, group):
|
|||
def can_manage_session_materials(user, group, session):
|
||||
return has_role(user, 'Secretariat') or (group.has_role(user, group.features.matman_roles) and not session.is_material_submission_cutoff())
|
||||
|
||||
# Maybe this should be cached...
|
||||
def can_manage_some_groups(user):
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
for gf in GroupFeatures.objects.all():
|
||||
for authrole in gf.groupman_authroles:
|
||||
if has_role(user, authrole):
|
||||
return True
|
||||
if Role.objects.filter(name__in=gf.groupman_roles, group__type_id=gf.type_id, person__user=user).exists():
|
||||
return True
|
||||
return False
|
||||
|
||||
def can_provide_status_update(user, group):
|
||||
if not group.features.acts_like_wg:
|
||||
return False
|
||||
|
|
|
@ -70,6 +70,9 @@ def has_role(user, role_names, *args, **kwargs):
|
|||
"RG Secretary": Q(person=person,name="secr", group__type="rg", group__state__in=["active","proposed"]),
|
||||
"AG Secretary": Q(person=person,name="secr", group__type="ag", group__state__in=["active"]),
|
||||
"Team Chair": Q(person=person,name="chair", group__type="team", group__state="active"),
|
||||
"Program Lead": Q(person=person,name="lead", group__type="program", group__state="active"),
|
||||
"Program Secretary": Q(person=person,name="secr", group__type="program", group__state="active"),
|
||||
"Program Chair": Q(person=person,name="chair", group__type="program", group__state="active"),
|
||||
"Nomcom Chair": Q(person=person, name="chair", group__type="nomcom", group__acronym__icontains=kwargs.get('year', '0000')),
|
||||
"Nomcom Advisor": Q(person=person, name="advisor", group__type="nomcom", group__acronym__icontains=kwargs.get('year', '0000')),
|
||||
"Nomcom": Q(person=person, group__type="nomcom", group__acronym__icontains=kwargs.get('year', '0000')),
|
||||
|
|
|
@ -166,6 +166,8 @@ class Recipient(models.Model):
|
|||
addrs.extend(group.role_set.filter(name='ad').values_list('email__address',flat=True))
|
||||
if group.type_id=='rg':
|
||||
addrs.extend(Recipient.objects.get(slug='stream_managers').gather(**{'streams':['irtf']}))
|
||||
elif group.type_id=='program':
|
||||
addrs.extend(Recipient.objects.get(slug='iab').gather(**{}))
|
||||
return addrs
|
||||
|
||||
def gather_group_secretaries(self, **kwargs):
|
||||
|
|
|
@ -15,7 +15,7 @@ from django.forms import BaseInlineFormSet
|
|||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.models import Document, DocAlias, State, NewRevisionDocEvent
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.models import Group, GroupFeatures
|
||||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.meeting.models import Session, Meeting, Schedule, countries, timezones
|
||||
from ietf.meeting.helpers import get_next_interim_number, make_materials_directories
|
||||
|
@ -100,8 +100,7 @@ class InterimSessionInlineFormSet(BaseInlineFormSet):
|
|||
return # formset doesn't have cleaned_data
|
||||
|
||||
class InterimMeetingModelForm(forms.ModelForm):
|
||||
# TODO: Should area groups get to schedule Interims?
|
||||
group = GroupModelChoiceField(queryset=Group.objects.filter(type__in=('wg', 'rg', 'ag'), state__in=('active', 'proposed', 'bof')).order_by('acronym'), required=False)
|
||||
group = GroupModelChoiceField(queryset=Group.objects.filter(type_id__in=GroupFeatures.objects.filter(has_meetings=True).values_list('type_id',flat=True), state__in=('active', 'proposed', 'bof')).order_by('acronym'), required=False)
|
||||
in_person = forms.BooleanField(required=False)
|
||||
meeting_type = forms.ChoiceField(choices=(
|
||||
("single", "Single"),
|
||||
|
@ -156,13 +155,15 @@ class InterimMeetingModelForm(forms.ModelForm):
|
|||
return # don't reduce group options
|
||||
q_objects = Q()
|
||||
if has_role(self.user, "Area Director"):
|
||||
q_objects.add(Q(type="wg", state__in=("active", "proposed", "bof")), Q.OR)
|
||||
q_objects.add(Q(type__in=["wg", "ag"], state__in=("active", "proposed", "bof")), Q.OR)
|
||||
if has_role(self.user, "IRTF Chair"):
|
||||
q_objects.add(Q(type="rg", state__in=("active", "proposed")), Q.OR)
|
||||
if has_role(self.user, "WG Chair"):
|
||||
q_objects.add(Q(type="wg", state__in=("active", "proposed", "bof"), role__person=self.person, role__name="chair"), Q.OR)
|
||||
if has_role(self.user, "RG Chair"):
|
||||
q_objects.add(Q(type="rg", state__in=("active", "proposed"), role__person=self.person, role__name="chair"), Q.OR)
|
||||
if has_role(self.user, "Program Lead") or has_role(self.user, "Program Chair"):
|
||||
q_objects.add(Q(type="program", state__in=("active", "proposed"), role__person=self.person, role__name__in=["chair", "lead"]), Q.OR)
|
||||
|
||||
queryset = Group.objects.filter(q_objects).distinct().order_by('acronym')
|
||||
self.fields['group'].queryset = queryset
|
||||
|
|
|
@ -21,6 +21,7 @@ import debug # pyflakes:ignore
|
|||
|
||||
from ietf.doc.models import Document
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.utils import can_manage_some_groups, can_manage_group
|
||||
from ietf.ietfauth.utils import has_role, user_is_person
|
||||
from ietf.liaisons.utils import get_person_for_user
|
||||
from ietf.mailtrigger.utils import gather_address_lists
|
||||
|
@ -324,11 +325,14 @@ def can_approve_interim_request(meeting, user):
|
|||
if not session:
|
||||
return False
|
||||
group = session.group
|
||||
if group.type.slug == 'wg':
|
||||
if group.type.slug in ['wg','ag']:
|
||||
if group.parent.role_set.filter(name='ad', person=person) or group.role_set.filter(name='ad', person=person):
|
||||
return True
|
||||
if group.type.slug == 'rg' and group.parent.role_set.filter(name='chair', person=person):
|
||||
return True
|
||||
if group.type.slug == 'program':
|
||||
if person.role_set.filter(group__acronym='iab', name='member'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
@ -336,14 +340,13 @@ def can_edit_interim_request(meeting, user):
|
|||
'''Returns True if the user can edit the interim meeting request'''
|
||||
if meeting.type.slug != 'interim':
|
||||
return False
|
||||
if has_role(user, 'Secretariat'):
|
||||
if has_role(user, 'Secretariat'): # Consider removing - can_manage_group should handle this
|
||||
return True
|
||||
person = get_person_for_user(user)
|
||||
session = meeting.session_set.first()
|
||||
if not session:
|
||||
return False
|
||||
group = session.group
|
||||
if group.role_set.filter(name='chair', person=person):
|
||||
if can_manage_group(user, group):
|
||||
return True
|
||||
elif can_approve_interim_request(meeting, user):
|
||||
return True
|
||||
|
@ -352,29 +355,17 @@ def can_edit_interim_request(meeting, user):
|
|||
|
||||
|
||||
def can_request_interim_meeting(user):
|
||||
if has_role(user, ('Secretariat', 'Area Director', 'WG Chair', 'IRTF Chair', 'RG Chair')):
|
||||
return True
|
||||
return False
|
||||
|
||||
return can_manage_some_groups(user)
|
||||
|
||||
def can_view_interim_request(meeting, user):
|
||||
'''Returns True if the user can see the pending interim request in the pending interim view'''
|
||||
if meeting.type.slug != 'interim':
|
||||
return False
|
||||
if has_role(user, 'Secretariat'):
|
||||
return True
|
||||
person = get_person_for_user(user)
|
||||
session = meeting.session_set.first()
|
||||
if not session:
|
||||
return False
|
||||
group = session.group
|
||||
if has_role(user, 'Area Director') and group.type.slug == 'wg':
|
||||
return True
|
||||
if has_role(user, 'IRTF Chair') and group.type.slug == 'rg':
|
||||
return True
|
||||
if group.role_set.filter(name='chair', person=person):
|
||||
return True
|
||||
return False
|
||||
return can_manage_group(user, group)
|
||||
|
||||
|
||||
def create_interim_meeting(group, date, city='', country='', timezone='UTC',
|
||||
|
@ -512,11 +503,17 @@ def send_interim_approval_request(meetings):
|
|||
else:
|
||||
is_series = False
|
||||
approver_set = set()
|
||||
for role in group.interim_approval_roles():
|
||||
approver = "%s of the %s" % ( role.name.name, role.group.name)
|
||||
approver_set.add(approver)
|
||||
for authrole in group.features.groupman_authroles: # NOTE: This makes an assumption that the authroles are exactly the set of approvers
|
||||
approver_set.add(authrole)
|
||||
approvers = list(approver_set)
|
||||
context = locals() # TODO Unnecessarily complex, context needs to only contain what the template needs
|
||||
context = {
|
||||
'group': group,
|
||||
'is_series': is_series,
|
||||
'meetings': meetings,
|
||||
'approvers': approvers,
|
||||
'requester': requester,
|
||||
'approval_urls': approval_urls,
|
||||
}
|
||||
send_mail(None,
|
||||
to_email,
|
||||
from_email,
|
||||
|
|
|
@ -26,7 +26,8 @@ from django.db.models import F
|
|||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.models import Document
|
||||
from ietf.group.models import Group, Role
|
||||
from ietf.group.models import Group, Role, GroupFeatures
|
||||
from ietf.group.utils import can_manage_group
|
||||
from ietf.person.models import Person
|
||||
from ietf.meeting.helpers import can_approve_interim_request, can_view_interim_request
|
||||
from ietf.meeting.helpers import send_interim_approval_request
|
||||
|
@ -37,7 +38,7 @@ from ietf.meeting.test_data import make_meeting_test_data, make_interim_meeting
|
|||
from ietf.meeting.utils import finalize, condition_slide_order
|
||||
from ietf.meeting.utils import add_event_info_to_session_qs
|
||||
from ietf.meeting.views import session_draft_list
|
||||
from ietf.name.models import SessionStatusName, ImportantDateName
|
||||
from ietf.name.models import SessionStatusName, ImportantDateName, RoleName
|
||||
from ietf.utils.decorators import skip_coverage
|
||||
from ietf.utils.mail import outbox, empty_outbox, get_payload
|
||||
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
|
||||
|
@ -1555,7 +1556,8 @@ class InterimTests(TestCase):
|
|||
r = self.client.get("/meeting/interim/request/")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(Group.objects.filter(type__in=('wg', 'rg', 'ag'), state__in=('active', 'proposed')).count(),
|
||||
Group.objects.filter(type_id__in=GroupFeatures.objects.filter(has_meetings=True).values_list('type_id',flat=True), state__in=('active', 'proposed', 'bof'))
|
||||
self.assertEqual(Group.objects.filter(type_id__in=GroupFeatures.objects.filter(has_meetings=True).values_list('type_id',flat=True), state__in=('active', 'proposed', 'bof')).count(),
|
||||
len(q("#id_group option")) - 1) # -1 for options placeholder
|
||||
self.client.logout()
|
||||
|
||||
|
@ -1939,6 +1941,28 @@ class InterimTests(TestCase):
|
|||
user = User.objects.get(username='ameschairman')
|
||||
self.assertFalse(can_view_interim_request(meeting=meeting,user=user))
|
||||
|
||||
def test_can_manage_group(self):
|
||||
make_meeting_test_data()
|
||||
# unprivileged user
|
||||
user = User.objects.get(username='plain')
|
||||
group = Group.objects.get(acronym='mars')
|
||||
self.assertFalse(can_manage_group(user=user,group=group))
|
||||
# Secretariat
|
||||
user = User.objects.get(username='secretary')
|
||||
self.assertTrue(can_manage_group(user=user,group=group))
|
||||
# related AD
|
||||
user = User.objects.get(username='ad')
|
||||
self.assertTrue(can_manage_group(user=user,group=group))
|
||||
# other AD
|
||||
user = User.objects.get(username='ops-ad')
|
||||
self.assertTrue(can_manage_group(user=user,group=group))
|
||||
# WG Chair
|
||||
user = User.objects.get(username='marschairman')
|
||||
self.assertTrue(can_manage_group(user=user,group=group))
|
||||
# Other WG Chair
|
||||
user = User.objects.get(username='ameschairman')
|
||||
self.assertFalse(can_manage_group(user=user,group=group))
|
||||
|
||||
def test_interim_request_details(self):
|
||||
make_meeting_test_data()
|
||||
meeting = add_event_info_to_session_qs(Session.objects.filter(meeting__type='interim', group__acronym='mars')).filter(current_status='apprw').first().meeting
|
||||
|
@ -1983,13 +2007,6 @@ class InterimTests(TestCase):
|
|||
make_meeting_test_data()
|
||||
meeting = add_event_info_to_session_qs(Session.objects.filter(meeting__type='interim', group__acronym='mars')).filter(current_status='apprw').first().meeting
|
||||
url = urlreverse('ietf.meeting.views.interim_request_details', kwargs={'number': meeting.number})
|
||||
# ensure no cancel button for unauthorized user
|
||||
self.client.login(username="ameschairman", password="ameschairman+password")
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q("a.btn:contains('Cancel')")), 0)
|
||||
# ensure cancel button for authorized user
|
||||
self.client.login(username="marschairman", password="marschairman+password")
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
@ -2793,3 +2810,164 @@ class SessionTests(TestCase):
|
|||
})
|
||||
self.assertEqual(r.status_code,302)
|
||||
self.assertEqual(len(outbox),1)
|
||||
|
||||
class HasMeetingsTests(TestCase):
|
||||
|
||||
def do_request_interim(self, url, group, user, meeting_count):
|
||||
login_testing_unauthorized(self,user.username, url)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(q('#id_group option[value="%d"]'%group.pk))
|
||||
date = datetime.date.today() + datetime.timedelta(days=30+meeting_count)
|
||||
time = datetime.datetime.now().time().replace(microsecond=0,second=0)
|
||||
remote_instructions = 'Use webex'
|
||||
agenda = 'Intro. Slides. Discuss.'
|
||||
agenda_note = 'On second level'
|
||||
meeting_count = Meeting.objects.filter(number__contains='-%s-'%group.acronym, date__year=date.year).count()
|
||||
next_num = "%02d" % (meeting_count+1)
|
||||
data = {'group':group.pk,
|
||||
'meeting_type':'single',
|
||||
'city':'',
|
||||
'country':'',
|
||||
'time_zone':'UTC',
|
||||
'session_set-0-date':date.strftime("%Y-%m-%d"),
|
||||
'session_set-0-time':time.strftime('%H:%M'),
|
||||
'session_set-0-requested_duration':'03:00:00',
|
||||
'session_set-0-remote_instructions':remote_instructions,
|
||||
'session_set-0-agenda':agenda,
|
||||
'session_set-0-agenda_note':agenda_note,
|
||||
'session_set-TOTAL_FORMS':1,
|
||||
'session_set-INITIAL_FORMS':0,
|
||||
'session_set-MIN_NUM_FORMS':0,
|
||||
'session_set-MAX_NUM_FORMS':1000}
|
||||
|
||||
r = self.client.post(urlreverse("ietf.meeting.views.interim_request"),data)
|
||||
self.assertRedirects(r,urlreverse('ietf.meeting.views.upcoming'))
|
||||
meeting = Meeting.objects.order_by('id').last()
|
||||
self.assertEqual(meeting.type_id,'interim')
|
||||
self.assertEqual(meeting.date,date)
|
||||
self.assertEqual(meeting.number,'interim-%s-%s-%s' % (date.year, group.acronym, next_num))
|
||||
self.client.logout()
|
||||
|
||||
|
||||
def create_role_for_authrole(self, authrole):
|
||||
role = None
|
||||
if authrole == 'Secretariat':
|
||||
role = RoleFactory.create(group__acronym='secretariat',name_id='secr')
|
||||
elif authrole == 'Area Director':
|
||||
role = RoleFactory.create(name_id='ad', group__type_id='area')
|
||||
elif authrole == 'IAB':
|
||||
role = RoleFactory.create(name_id='member', group__acronym='iab')
|
||||
elif authrole == 'IRTF Chair':
|
||||
role = RoleFactory.create(name_id='chair', group__acronym='irtf')
|
||||
if role is None:
|
||||
self.assertIsNone("Can't test authrole:"+authrole)
|
||||
self.assertNotEqual(role, None)
|
||||
return role
|
||||
|
||||
|
||||
def test_can_request_interim(self):
|
||||
|
||||
url = urlreverse('ietf.meeting.views.interim_request')
|
||||
for gf in GroupFeatures.objects.filter(has_meetings=True):
|
||||
meeting_count = 0
|
||||
for role in gf.groupman_roles:
|
||||
role = RoleFactory(group__type_id=gf.type_id, name_id=role)
|
||||
self.do_request_interim(url, role.group, role.person.user, meeting_count)
|
||||
for authrole in gf.groupman_authroles:
|
||||
group = GroupFactory(type_id=gf.type_id)
|
||||
role = self.create_role_for_authrole(authrole)
|
||||
self.do_request_interim(url, group, role.person.user, 0)
|
||||
|
||||
|
||||
def test_cannot_request_interim(self):
|
||||
|
||||
url = urlreverse('ietf.meeting.views.interim_request')
|
||||
|
||||
self.client.login(username='secretary', password='secretary+password')
|
||||
nomeetings = []
|
||||
for gf in GroupFeatures.objects.exclude(has_meetings=True):
|
||||
nomeetings.append(GroupFactory(type_id=gf.type_id))
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
for group in nomeetings:
|
||||
self.assertFalse(q('#id_group option[value="%d"]'%group.pk))
|
||||
self.client.logout()
|
||||
|
||||
all_role_names = set(RoleName.objects.values_list('slug',flat=True))
|
||||
for gf in GroupFeatures.objects.filter(has_meetings=True):
|
||||
for role_name in all_role_names - set(gf.groupman_roles):
|
||||
role = RoleFactory(group__type_id=gf.type_id,name_id=role_name)
|
||||
self.client.login(username=role.person.user.username, password=role.person.user.username+'+password')
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 403)
|
||||
self.client.logout()
|
||||
|
||||
def test_appears_on_upcoming(self):
|
||||
url = urlreverse('ietf.meeting.views.upcoming')
|
||||
for gf in GroupFeatures.objects.filter(has_meetings=True):
|
||||
session = SessionFactory(
|
||||
group__type_id = gf.type_id,
|
||||
meeting__type_id='interim',
|
||||
meeting__date = datetime.datetime.today()+datetime.timedelta(days=30),
|
||||
status_id='sched',
|
||||
)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertIn(session.meeting.number, q('.interim-meeting-link').text())
|
||||
|
||||
|
||||
def test_appears_on_pending(self):
|
||||
url = urlreverse('ietf.meeting.views.interim_pending')
|
||||
for gf in GroupFeatures.objects.filter(has_meetings=True):
|
||||
group = GroupFactory(type_id=gf.type_id)
|
||||
meeting_date = datetime.datetime.today() + datetime.timedelta(days=30)
|
||||
session = SessionFactory(
|
||||
group=group,
|
||||
meeting__type_id='interim',
|
||||
meeting__date = meeting_date,
|
||||
meeting__number = 'interim-%d-%s-00'%(meeting_date.year,group.acronym),
|
||||
status_id='apprw',
|
||||
)
|
||||
for role_name in gf.groupman_roles:
|
||||
role = RoleFactory(group=group, name_id=role_name)
|
||||
self.client.login(username=role.person.user.username, password=role.person.user.username+'+password')
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertIn(session.meeting.number, q('.interim-meeting-link').text())
|
||||
self.client.logout()
|
||||
for authrole in gf.groupman_authroles:
|
||||
role = self.create_role_for_authrole(authrole)
|
||||
self.client.login(username=role.person.user.username, password=role.person.user.username+'+password')
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertIn(session.meeting.number, q('.interim-meeting-link').text())
|
||||
self.client.logout()
|
||||
|
||||
|
||||
def test_appears_on_announce(self):
|
||||
url = urlreverse('ietf.meeting.views.interim_announce')
|
||||
login_testing_unauthorized(self,"secretary",url)
|
||||
sessions=[]
|
||||
for gf in GroupFeatures.objects.filter(has_meetings=True):
|
||||
group = GroupFactory(type_id=gf.type_id)
|
||||
meeting_date = datetime.datetime.today() + datetime.timedelta(days=30)
|
||||
session = SessionFactory(
|
||||
group=group,
|
||||
meeting__type_id='interim',
|
||||
meeting__date = meeting_date,
|
||||
meeting__number = 'interim-%d-%s-00'%(meeting_date.year,group.acronym),
|
||||
status_id='scheda',
|
||||
)
|
||||
sessions.append(session)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
for session in sessions:
|
||||
self.assertIn(session.meeting.number, q('.interim-meeting-link').text())
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ from django.views.generic import RedirectView
|
|||
from ietf.doc.fields import SearchableDocumentsField
|
||||
from ietf.doc.models import Document, State, DocEvent, NewRevisionDocEvent, DocAlias
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.utils import can_manage_session_materials
|
||||
from ietf.group.utils import can_manage_session_materials, can_manage_some_groups, can_manage_group
|
||||
from ietf.person.models import Person
|
||||
from ietf.person.name import plain_name
|
||||
from ietf.ietfauth.utils import role_required, has_role
|
||||
|
@ -96,7 +96,7 @@ from .forms import (InterimMeetingModelForm, InterimAnnounceForm, InterimSession
|
|||
def get_interim_menu_entries(request):
|
||||
'''Setup menu entries for interim meeting view tabs'''
|
||||
entries = []
|
||||
if has_role(request.user, ('Area Director','Secretariat','IRTF Chair','WG Chair', 'RG Chair')):
|
||||
if can_manage_some_groups(request.user):
|
||||
entries.append(("Upcoming", reverse("ietf.meeting.views.upcoming")))
|
||||
entries.append(("Pending", reverse("ietf.meeting.views.interim_pending")))
|
||||
if has_role(request.user, "Secretariat"):
|
||||
|
@ -1508,7 +1508,7 @@ def meeting_requests(request, num=None):
|
|||
s.current_status_name = status_names.get(s.current_status, s.current_status)
|
||||
s.requested_by_person = session_requesters.get(s.requested_by)
|
||||
|
||||
groups_not_meeting = Group.objects.filter(state='Active',type__in=['wg','rg','ag','bof']).exclude(acronym__in = [session.group.acronym for session in sessions]).order_by("parent__acronym","acronym").prefetch_related("parent")
|
||||
groups_not_meeting = Group.objects.filter(state='Active',type__in=['wg','rg','ag','bof','program']).exclude(acronym__in = [session.group.acronym for session in sessions]).order_by("parent__acronym","acronym").prefetch_related("parent")
|
||||
|
||||
return render(request, "meeting/requests.html",
|
||||
{"meeting": meeting, "sessions":sessions,
|
||||
|
@ -2392,8 +2392,12 @@ def interim_skip_announcement(request, number):
|
|||
'meeting': meeting})
|
||||
|
||||
|
||||
@role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair')
|
||||
@login_required
|
||||
def interim_pending(request):
|
||||
|
||||
if not can_manage_some_groups(request.user):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
'''View which shows interim meeting requests pending approval'''
|
||||
meetings = data_for_meetings_overview(Meeting.objects.filter(type='interim').order_by('date'), interim_status='apprw')
|
||||
|
||||
|
@ -2411,8 +2415,12 @@ def interim_pending(request):
|
|||
'meetings': meetings})
|
||||
|
||||
|
||||
@role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair')
|
||||
@login_required
|
||||
def interim_request(request):
|
||||
|
||||
if not can_manage_some_groups(request.user):
|
||||
return HttpResponseForbidden("You don't have permission to request any interims")
|
||||
|
||||
'''View for requesting an interim meeting'''
|
||||
SessionFormset = inlineformset_factory(
|
||||
Meeting,
|
||||
|
@ -2497,15 +2505,15 @@ def interim_request(request):
|
|||
"formset": formset})
|
||||
|
||||
|
||||
@role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair')
|
||||
@login_required
|
||||
def interim_request_cancel(request, number):
|
||||
'''View for cancelling an interim meeting request'''
|
||||
meeting = get_object_or_404(Meeting, number=number)
|
||||
first_session = meeting.session_set.first()
|
||||
session_status = current_session_status(first_session)
|
||||
group = first_session.group
|
||||
if not can_view_interim_request(meeting, request.user):
|
||||
if not can_manage_group(request.user, group):
|
||||
return HttpResponseForbidden("You do not have permissions to cancel this meeting request")
|
||||
session_status = current_session_status(first_session)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = InterimCancelForm(request.POST)
|
||||
|
@ -2538,10 +2546,13 @@ def interim_request_cancel(request, number):
|
|||
})
|
||||
|
||||
|
||||
@role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair')
|
||||
@login_required
|
||||
def interim_request_details(request, number):
|
||||
'''View details of an interim meeting reqeust'''
|
||||
'''View details of an interim meeting request'''
|
||||
meeting = get_object_or_404(Meeting, number=number)
|
||||
group = meeting.session_set.first().group
|
||||
if not can_manage_group(request.user, group):
|
||||
return HttpResponseForbidden("You do not have permissions to manage this meeting request")
|
||||
sessions = meeting.session_set.all()
|
||||
can_edit = can_edit_interim_request(meeting, request.user)
|
||||
can_approve = can_approve_interim_request(meeting, request.user)
|
||||
|
@ -2582,7 +2593,7 @@ def interim_request_details(request, number):
|
|||
"can_approve": can_approve})
|
||||
|
||||
|
||||
@role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair')
|
||||
@login_required
|
||||
def interim_request_edit(request, number):
|
||||
'''Edit details of an interim meeting reqeust'''
|
||||
meeting = get_object_or_404(Meeting, number=number)
|
||||
|
|
|
@ -2484,6 +2484,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"lead\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": true,
|
||||
|
@ -2514,6 +2515,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2544,6 +2546,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\",\"delegate\",\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\",\"Area Director\"]",
|
||||
"groupman_roles": "[\"ad\",\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2574,6 +2577,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"ad\",\"delegate\",\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"ad\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2604,6 +2608,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"ad\",\"secr\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2634,6 +2639,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2664,6 +2670,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2694,6 +2701,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2724,6 +2732,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2754,6 +2763,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"auth\"]",
|
||||
"groupman_authroles": "[]",
|
||||
"groupman_roles": "[]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2784,6 +2794,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2814,6 +2825,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2844,6 +2856,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2874,6 +2887,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"advisor\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2903,21 +2917,22 @@
|
|||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"lead\",\"secr\"]",
|
||||
"groupman_roles": "[\"lead\",\"secr\"]",
|
||||
"docman_roles": "[\"lead\",\"chair\",\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\",\"IAB\"]",
|
||||
"groupman_roles": "[\"lead\",\"chair\",\"secr\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
"has_documents": true,
|
||||
"has_meetings": false,
|
||||
"has_meetings": true,
|
||||
"has_milestones": true,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"lead\",\"secr\"]",
|
||||
"matman_roles": "[\"lead\",\"chair\",\"secr\"]",
|
||||
"req_subm_approval": false,
|
||||
"role_order": "[\"lead\",\"secr\"]",
|
||||
"role_order": "[\"lead\",\"chair\",\"secr\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
|
@ -2934,6 +2949,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.review_requests",
|
||||
"docman_roles": "[\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"ad\",\"secr\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2964,6 +2980,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2994,6 +3011,7 @@
|
|||
"customize_workflow": true,
|
||||
"default_tab": "ietf.group.views.group_documents",
|
||||
"docman_roles": "[\"chair\",\"delegate\",\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\",\"IRTF Chair\"]",
|
||||
"groupman_roles": "[\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": true,
|
||||
"has_default_jabber": true,
|
||||
|
@ -3024,6 +3042,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"liaiman\",\"matman\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -3054,6 +3073,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -3084,6 +3104,7 @@
|
|||
"customize_workflow": true,
|
||||
"default_tab": "ietf.group.views.group_documents",
|
||||
"docman_roles": "[\"chair\",\"delegate\",\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\",\"Area Director\"]",
|
||||
"groupman_roles": "[\"ad\",\"chair\",\"delegate\",\"secr\"]",
|
||||
"has_chartering_process": true,
|
||||
"has_default_jabber": true,
|
||||
|
@ -5603,8 +5624,8 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"editor_label": "(1)",
|
||||
"desc": "",
|
||||
"editor_label": "(1)",
|
||||
"name": "Conflicts with",
|
||||
"order": 0,
|
||||
"penalty": 100000,
|
||||
|
@ -5616,9 +5637,10 @@
|
|||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
"editor_label": "time_relation",
|
||||
"name": "Preference for time between sessions",
|
||||
"order": 0,
|
||||
"penalty": 100000,
|
||||
"penalty": 1000,
|
||||
"used": true
|
||||
},
|
||||
"model": "name.constraintname",
|
||||
|
@ -5627,6 +5649,7 @@
|
|||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
"editor_label": "timerange",
|
||||
"name": "Can't meet within timerange",
|
||||
"order": 0,
|
||||
"penalty": 100000,
|
||||
|
@ -5638,9 +5661,10 @@
|
|||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
"editor_label": "wg_adjacent",
|
||||
"name": "Request for adjacent scheduling with another WG",
|
||||
"order": 0,
|
||||
"penalty": 100000,
|
||||
"penalty": 10000,
|
||||
"used": true
|
||||
},
|
||||
"model": "name.constraintname",
|
||||
|
@ -10181,6 +10205,17 @@
|
|||
"model": "name.importantdatename",
|
||||
"pk": "idcutoff"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"default_offset_days": 70,
|
||||
"desc": "Announcement of whether conditions have improved enough to hold an in-person meeting in Madrid, or if IETF 108 will be held as a virtual meeting",
|
||||
"name": "IETF 108 Go-ahead Announcement",
|
||||
"order": 0,
|
||||
"used": false
|
||||
},
|
||||
"model": "name.importantdatename",
|
||||
"pk": "ietf-108-go-ahead"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"default_offset_days": -82,
|
||||
|
@ -11268,6 +11303,16 @@
|
|||
"model": "name.rolename",
|
||||
"pk": "chair"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
"name": "Communications Director",
|
||||
"order": 0,
|
||||
"used": true
|
||||
},
|
||||
"model": "name.rolename",
|
||||
"pk": "comdir"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
|
@ -11420,7 +11465,7 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "Provides log-in permission to restricted Trac instances",
|
||||
"desc": "Provides log-in permission to restricted Trac instances. Used by the generate_apache_perms management command, called from ../../scripts/Cron-runner",
|
||||
"name": "Trac Editor",
|
||||
"order": 0,
|
||||
"used": true
|
||||
|
@ -11500,8 +11545,8 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "WebEx support",
|
||||
"name": "WebEx session",
|
||||
"desc": "Web streaming support",
|
||||
"name": "WebEx",
|
||||
"order": 0,
|
||||
"used": true
|
||||
},
|
||||
|
@ -14436,9 +14481,9 @@
|
|||
"fields": {
|
||||
"command": "xym",
|
||||
"switch": "--version",
|
||||
"time": "2020-02-19T00:13:43.554",
|
||||
"time": "2020-04-29T00:13:24.969",
|
||||
"used": true,
|
||||
"version": "xym 0.4"
|
||||
"version": "xym 0.4.8"
|
||||
},
|
||||
"model": "utils.versioninfo",
|
||||
"pk": 1
|
||||
|
@ -14447,9 +14492,9 @@
|
|||
"fields": {
|
||||
"command": "pyang",
|
||||
"switch": "--version",
|
||||
"time": "2020-02-19T00:13:44.450",
|
||||
"time": "2020-04-29T00:13:26.832",
|
||||
"used": true,
|
||||
"version": "pyang 2.1.1"
|
||||
"version": "pyang 2.2.1"
|
||||
},
|
||||
"model": "utils.versioninfo",
|
||||
"pk": 2
|
||||
|
@ -14458,9 +14503,9 @@
|
|||
"fields": {
|
||||
"command": "yanglint",
|
||||
"switch": "--version",
|
||||
"time": "2020-02-19T00:13:44.597",
|
||||
"time": "2020-04-29T00:13:27.209",
|
||||
"used": true,
|
||||
"version": "yanglint 0.14.80"
|
||||
"version": "yanglint SO 1.6.7"
|
||||
},
|
||||
"model": "utils.versioninfo",
|
||||
"pk": 3
|
||||
|
@ -14469,9 +14514,9 @@
|
|||
"fields": {
|
||||
"command": "xml2rfc",
|
||||
"switch": "--version",
|
||||
"time": "2020-02-19T00:13:45.481",
|
||||
"time": "2020-04-29T00:13:28.798",
|
||||
"used": true,
|
||||
"version": "xml2rfc 2.40.0"
|
||||
"version": "xml2rfc 2.44.0"
|
||||
},
|
||||
"model": "utils.versioninfo",
|
||||
"pk": 4
|
||||
|
|
|
@ -29,7 +29,8 @@ from ietf.mailtrigger.utils import gather_address_lists
|
|||
# -------------------------------------------------
|
||||
# Globals
|
||||
# -------------------------------------------------
|
||||
AUTHORIZED_ROLES=('WG Chair','WG Secretary','RG Chair','IAB Group Chair','Area Director','Secretariat','Team Chair','IRTF Chair')
|
||||
# TODO: This needs to be replaced with something that pays attention to groupfeatures
|
||||
AUTHORIZED_ROLES=('WG Chair','WG Secretary','RG Chair','IAB Group Chair','Area Director','Secretariat','Team Chair','IRTF Chair','Program Chair','Program Lead','Program Secretary')
|
||||
|
||||
# -------------------------------------------------
|
||||
# Helper Functions
|
||||
|
@ -319,7 +320,10 @@ def confirm(request, acronym):
|
|||
)
|
||||
if 'resources' in form.data:
|
||||
new_session.resources.set(session_data['resources'])
|
||||
if int(form.data.get('joint_for_session', '-1')) == count:
|
||||
jfs = form.data.get('joint_for_session', '-1')
|
||||
if not jfs: # jfs might be ''
|
||||
jfs = '-1'
|
||||
if int(jfs) == count:
|
||||
groups_split = form.cleaned_data.get('joint_with_groups').replace(',',' ').split()
|
||||
joint = Group.objects.filter(acronym__in=groups_split)
|
||||
new_session.joint_with_groups.set(joint)
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<td>{{ meeting.date }}</td>
|
||||
<td>{{ meeting.responsible_group.acronym }}</td>
|
||||
<td>
|
||||
<a href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">{{ meeting.number }}</a>
|
||||
<a class="interim-meeting-link" href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">{{ meeting.number }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -40,11 +40,7 @@
|
|||
<td>{{ meeting.date }}</td>
|
||||
<td>{{ meeting.responsible_group.acronym }}</td>
|
||||
<td>
|
||||
{% if meeting.type_id == "interim" %}
|
||||
<a href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">{{ meeting.number }}{% if meeting.interim_meeting_cancelled %} <span class="label label-warning">CANCELLED</span>{% endif %}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">IETF - {{ meeting.number }}</a>
|
||||
{% endif %}
|
||||
<a class="interim-meeting-link" href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">{{ meeting.number }}{% if meeting.interim_meeting_cancelled %} <span class="label label-warning">CANCELLED</span>{% endif %}</a>
|
||||
</td>
|
||||
<td>{% if meeting.can_approve %}<span class="label label-success">can be approved</span>{% endif %}</td>
|
||||
</tr>
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
{% with meeting=entry %}
|
||||
<td>{{ meeting.date }} - {{ meeting.end }}</td>
|
||||
<td>ietf</td>
|
||||
<td><a href="{% url 'ietf.meeting.views.agenda' num=meeting.number %}">IETF {{ meeting.number }}</a></td>
|
||||
<td><a class="ietf-meeting-link" href="{% url 'ietf.meeting.views.agenda' num=meeting.number %}">IETF {{ meeting.number }}</a></td>
|
||||
<td></td>
|
||||
{% endwith %}
|
||||
{% elif entry|classname == 'Session' %}
|
||||
|
@ -68,7 +68,7 @@
|
|||
<td>{{ session.official_timeslotassignment.timeslot.utc_start_time | date:"Y-m-d H:i"}} - {{ session.official_timeslotassignment.timeslot.utc_end_time | date:"H:i e" }}</td>
|
||||
<td><a href="{% url 'ietf.group.views.group_home' acronym=session.group.acronym %}">{{ session.group.acronym }}</a></td>
|
||||
<td>
|
||||
<a href="{% url 'ietf.meeting.views.session_details' num=session.meeting.number acronym=session.group.acronym %}">{{ session.meeting.number }}{% if session.current_status == 'canceled' %} <span class="label label-warning">CANCELLED</span>{% endif %}</a>
|
||||
<a class="interim-meeting-link" href="{% url 'ietf.meeting.views.session_details' num=session.meeting.number acronym=session.group.acronym %}">{{ session.meeting.number }}{% if session.current_status == 'canceled' %} <span class="label label-warning">CANCELLED</span>{% endif %}</a>
|
||||
</td>
|
||||
<td class='text-right'>
|
||||
{% include "meeting/interim_session_buttons.html" %}
|
||||
|
|
Loading…
Reference in a new issue