refactor: Remove secr groups app (#5334)
This commit is contained in:
parent
a544cc91f9
commit
abc70ae650
|
@ -1,117 +0,0 @@
|
||||||
import re
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
from django.db.models import Count
|
|
||||||
|
|
||||||
from ietf.group.models import Group, Role
|
|
||||||
from ietf.name.models import GroupStateName, GroupTypeName, RoleName
|
|
||||||
from ietf.person.models import Person, Email
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------
|
|
||||||
# Select Choices
|
|
||||||
# ---------------------------------------------
|
|
||||||
SEARCH_MEETING_CHOICES = (('',''),('NO','NO'),('YES','YES'))
|
|
||||||
|
|
||||||
# ---------------------------------------------
|
|
||||||
# Functions
|
|
||||||
# ---------------------------------------------
|
|
||||||
def get_person(name):
|
|
||||||
'''
|
|
||||||
This function takes a string which is in the name autocomplete format "name - (id)"
|
|
||||||
and returns a person object
|
|
||||||
'''
|
|
||||||
|
|
||||||
match = re.search(r'\((\d+)\)', name)
|
|
||||||
if not match:
|
|
||||||
return None
|
|
||||||
id = match.group(1)
|
|
||||||
try:
|
|
||||||
person = Person.objects.get(id=id)
|
|
||||||
except (Person.ObjectDoesNoExist, Person.MultipleObjectsReturned):
|
|
||||||
return None
|
|
||||||
return person
|
|
||||||
|
|
||||||
def get_parent_group_choices():
|
|
||||||
area_choices = [(g.id, g.name) for g in Group.objects.filter(type='area',state='active')]
|
|
||||||
other_parents = Group.objects.annotate(children=Count('group')).filter(children__gt=0).order_by('name').exclude(type='area')
|
|
||||||
other_choices = [(g.id, g.name) for g in other_parents]
|
|
||||||
choices = (('Working Group Areas',area_choices),('Other',other_choices))
|
|
||||||
return choices
|
|
||||||
|
|
||||||
# ---------------------------------------------
|
|
||||||
# Forms
|
|
||||||
# ---------------------------------------------
|
|
||||||
|
|
||||||
class DescriptionForm (forms.Form):
|
|
||||||
description = forms.CharField(widget=forms.Textarea(attrs={'rows':'20'}),required=True, strip=False)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RoleForm(forms.Form):
|
|
||||||
name = forms.ModelChoiceField(RoleName.objects.filter(slug__in=('chair','editor','secr','techadv')),empty_label=None)
|
|
||||||
person = forms.CharField(max_length=50,widget=forms.TextInput(attrs={'class':'name-autocomplete'}),help_text="To see a list of people type the first name, or last name, or both.")
|
|
||||||
email = forms.CharField(widget=forms.Select(),help_text="Select an email")
|
|
||||||
group_acronym = forms.CharField(widget=forms.HiddenInput(),required=False)
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.group = kwargs.pop('group')
|
|
||||||
super(RoleForm, self).__init__(*args,**kwargs)
|
|
||||||
# this form is re-used in roles app, use different roles in select
|
|
||||||
if self.group.features.custom_group_roles:
|
|
||||||
self.fields['name'].queryset = RoleName.objects.all()
|
|
||||||
|
|
||||||
# check for id within parenthesis to ensure name was selected from the list
|
|
||||||
def clean_person(self):
|
|
||||||
person = self.cleaned_data.get('person', '')
|
|
||||||
m = re.search(r'(\d+)', person)
|
|
||||||
if person and not m:
|
|
||||||
raise forms.ValidationError("You must select an entry from the list!")
|
|
||||||
|
|
||||||
# return person object
|
|
||||||
return get_person(person)
|
|
||||||
|
|
||||||
# check that email exists and return the Email object
|
|
||||||
def clean_email(self):
|
|
||||||
email = self.cleaned_data['email']
|
|
||||||
try:
|
|
||||||
obj = Email.objects.get(address=email)
|
|
||||||
except Email.ObjectDoesNoExist:
|
|
||||||
raise forms.ValidationError("Email address not found!")
|
|
||||||
|
|
||||||
# return email object
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
# here we abort if there are any errors with individual fields
|
|
||||||
# One predictable problem is that the user types a name rather then
|
|
||||||
# selecting one from the list, as instructed to do. We need to abort
|
|
||||||
# so the error is displayed before trying to call get_person()
|
|
||||||
if any(self.errors):
|
|
||||||
# Don't bother validating the formset unless each form is valid on its own
|
|
||||||
return
|
|
||||||
super(RoleForm, self).clean()
|
|
||||||
cleaned_data = self.cleaned_data
|
|
||||||
person = cleaned_data['person']
|
|
||||||
email = cleaned_data['email']
|
|
||||||
name = cleaned_data['name']
|
|
||||||
group_acronym = cleaned_data['group_acronym']
|
|
||||||
|
|
||||||
if email.person != person:
|
|
||||||
raise forms.ValidationError('ERROR: The person associated with the chosen email address is different from the chosen person')
|
|
||||||
|
|
||||||
if Role.objects.filter(name=name,group=self.group,person=person,email=email):
|
|
||||||
raise forms.ValidationError('ERROR: This is a duplicate entry')
|
|
||||||
|
|
||||||
if not group_acronym:
|
|
||||||
raise forms.ValidationError('You must select a group.')
|
|
||||||
|
|
||||||
return cleaned_data
|
|
||||||
|
|
||||||
class SearchForm(forms.Form):
|
|
||||||
group_acronym = forms.CharField(max_length=12,required=False)
|
|
||||||
group_name = forms.CharField(max_length=80,required=False)
|
|
||||||
primary_area = forms.ModelChoiceField(queryset=Group.objects.filter(type='area',state='active'),required=False)
|
|
||||||
type = forms.ModelChoiceField(queryset=GroupTypeName.objects.all(),required=False)
|
|
||||||
meeting_scheduled = forms.CharField(widget=forms.Select(choices=SEARCH_MEETING_CHOICES),required=False)
|
|
||||||
state = forms.ModelChoiceField(queryset=GroupStateName.objects.exclude(slug__in=('dormant','unknown')),required=False)
|
|
|
@ -1,69 +0,0 @@
|
||||||
# Copyright The IETF Trust 2013-2020, All Rights Reserved
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
from django.urls import reverse
|
|
||||||
from ietf.utils.test_utils import TestCase
|
|
||||||
from ietf.group.models import Group
|
|
||||||
from ietf.secr.groups.forms import get_parent_group_choices
|
|
||||||
from ietf.group.factories import GroupFactory, RoleFactory
|
|
||||||
from ietf.meeting.factories import MeetingFactory
|
|
||||||
from ietf.person.factories import PersonFactory
|
|
||||||
import debug # pyflakes:ignore
|
|
||||||
|
|
||||||
class GroupsTest(TestCase):
|
|
||||||
def test_get_parent_group_choices(self):
|
|
||||||
GroupFactory(type_id='area')
|
|
||||||
choices = get_parent_group_choices()
|
|
||||||
area = Group.objects.filter(type='area',state='active').first()
|
|
||||||
# This is opaque. Can it be rewritten to be more self-documenting?
|
|
||||||
self.assertEqual(choices[0][1][0][0],area.id)
|
|
||||||
|
|
||||||
# ------- Test Search -------- #
|
|
||||||
def test_search(self):
|
|
||||||
"Test Search"
|
|
||||||
MeetingFactory(type_id='ietf')
|
|
||||||
group = GroupFactory()
|
|
||||||
url = reverse('ietf.secr.groups.views.search')
|
|
||||||
post_data = {'group_acronym':group.acronym,'submit':'Search'}
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.post(url,post_data,follow=True)
|
|
||||||
self.assertContains(response, group.acronym)
|
|
||||||
|
|
||||||
# ------- Test View -------- #
|
|
||||||
def test_view(self):
|
|
||||||
MeetingFactory(type_id='ietf')
|
|
||||||
group = GroupFactory()
|
|
||||||
url = reverse('ietf.secr.groups.views.view', kwargs={'acronym':group.acronym})
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
|
|
||||||
# ------- Test People -------- #
|
|
||||||
def test_people_delete(self):
|
|
||||||
role = RoleFactory(name_id='member')
|
|
||||||
group = role.group
|
|
||||||
id = role.id
|
|
||||||
url = reverse('ietf.secr.groups.views.delete_role', kwargs={'acronym':group.acronym,'id':role.id})
|
|
||||||
target = reverse('ietf.secr.groups.views.people', kwargs={'acronym':group.acronym})
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
response = self.client.post(url, {'post':'yes'})
|
|
||||||
self.assertRedirects(response, target)
|
|
||||||
self.assertFalse(group.role_set.filter(id=id))
|
|
||||||
|
|
||||||
def test_people_add(self):
|
|
||||||
person = PersonFactory()
|
|
||||||
group = GroupFactory()
|
|
||||||
url = reverse('ietf.secr.groups.views.people', kwargs={'acronym':group.acronym})
|
|
||||||
post_data = {'group_acronym':group.acronym,
|
|
||||||
'name':'chair',
|
|
||||||
'person':'Joe Smith - (%s)' % person.id,
|
|
||||||
'email':person.email_set.all()[0].address,
|
|
||||||
'submit':'Add'}
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.post(url,post_data,follow=True)
|
|
||||||
self.assertRedirects(response, url)
|
|
||||||
self.assertContains(response, 'added successfully')
|
|
|
@ -1,14 +0,0 @@
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from ietf.secr.groups import views
|
|
||||||
from ietf.utils.urls import url
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^$', views.search),
|
|
||||||
url(r'^blue-dot-report/$', views.blue_dot),
|
|
||||||
#(r'^ajax/get_ads/$', views.get_ads),
|
|
||||||
url(r'^%(acronym)s/$' % settings.URL_REGEXPS, views.view),
|
|
||||||
url(r'^%(acronym)s/delete/(?P<id>\d{1,6})/$' % settings.URL_REGEXPS, views.delete_role),
|
|
||||||
url(r'^%(acronym)s/charter/$' % settings.URL_REGEXPS, views.charter),
|
|
||||||
url(r'^%(acronym)s/people/$' % settings.URL_REGEXPS, views.people),
|
|
||||||
]
|
|
|
@ -1,301 +0,0 @@
|
||||||
from django.contrib import messages
|
|
||||||
from django.conf import settings
|
|
||||||
from django.shortcuts import render, get_object_or_404, redirect
|
|
||||||
|
|
||||||
from ietf.group.models import Group, GroupEvent, Role
|
|
||||||
from ietf.group.utils import save_group_in_history, get_charter_text
|
|
||||||
from ietf.ietfauth.utils import role_required
|
|
||||||
from ietf.person.models import Person
|
|
||||||
from ietf.secr.groups.forms import RoleForm, SearchForm
|
|
||||||
from ietf.secr.utils.meeting import get_current_meeting
|
|
||||||
from ietf.liaisons.views import contacts_from_roles
|
|
||||||
|
|
||||||
# -------------------------------------------------
|
|
||||||
# Helper Functions
|
|
||||||
# -------------------------------------------------
|
|
||||||
|
|
||||||
def add_legacy_fields(group):
|
|
||||||
'''
|
|
||||||
This function takes a Group object as input and adds legacy attributes:
|
|
||||||
start_date,proposed_date,concluded_date,meeting_scheduled
|
|
||||||
'''
|
|
||||||
# it's possible there could be multiple records of a certain type in which case
|
|
||||||
# we just return the latest record
|
|
||||||
query = GroupEvent.objects.filter(group=group, type="changed_state").order_by('time')
|
|
||||||
proposed = query.filter(changestategroupevent__state="proposed")
|
|
||||||
meeting = get_current_meeting()
|
|
||||||
|
|
||||||
if proposed:
|
|
||||||
group.proposed_date = proposed[0].time
|
|
||||||
active = query.filter(changestategroupevent__state="active")
|
|
||||||
if active:
|
|
||||||
group.start_date = active[0].time
|
|
||||||
concluded = query.filter(changestategroupevent__state="conclude")
|
|
||||||
if concluded:
|
|
||||||
group.concluded_date = concluded[0].time
|
|
||||||
|
|
||||||
if group.session_set.filter(meeting__number=meeting.number):
|
|
||||||
group.meeting_scheduled = 'YES'
|
|
||||||
else:
|
|
||||||
group.meeting_scheduled = 'NO'
|
|
||||||
|
|
||||||
group.chairs = group.role_set.filter(name="chair")
|
|
||||||
group.techadvisors = group.role_set.filter(name="techadv")
|
|
||||||
group.editors = group.role_set.filter(name="editor")
|
|
||||||
group.secretaries = group.role_set.filter(name="secr")
|
|
||||||
# Note: liaison_contacts is now a dict instead of a model instance with fields. In
|
|
||||||
# templates, the dict can still be accessed using '.contacts' and .cc_contacts', though.
|
|
||||||
group.liaison_contacts = dict(
|
|
||||||
contacts=contacts_from_roles(group.role_set.filter(name='liaison_contact')),
|
|
||||||
cc_contacts=contacts_from_roles(group.role_set.filter(name='liaison_cc_contact')),
|
|
||||||
)
|
|
||||||
|
|
||||||
#fill_in_charter_info(group)
|
|
||||||
|
|
||||||
#--------------------------------------------------
|
|
||||||
# AJAX Functions
|
|
||||||
# -------------------------------------------------
|
|
||||||
'''
|
|
||||||
def get_ads(request):
|
|
||||||
""" AJAX function which takes a URL parameter, "area" and returns the area directors
|
|
||||||
in the form of a list of dictionaries with "id" and "value" keys(in json format).
|
|
||||||
Used to populate select options.
|
|
||||||
"""
|
|
||||||
|
|
||||||
results=[]
|
|
||||||
area = request.GET.get('area','')
|
|
||||||
qs = AreaDirector.objects.filter(area=area)
|
|
||||||
for item in qs:
|
|
||||||
d = {'id': item.id, 'value': item.person.first_name + ' ' + item.person.last_name}
|
|
||||||
results.append(d)
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps(results), content_type='application/javascript')
|
|
||||||
'''
|
|
||||||
# -------------------------------------------------
|
|
||||||
# Standard View Functions
|
|
||||||
# -------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def blue_dot(request):
|
|
||||||
'''
|
|
||||||
This is a report view. It returns a text/plain listing of working group chairs.
|
|
||||||
'''
|
|
||||||
people = Person.objects.filter(role__name__slug='chair',
|
|
||||||
role__group__type='wg',
|
|
||||||
role__group__state__slug__in=('active','bof','proposed')).distinct()
|
|
||||||
chairs = []
|
|
||||||
for person in people:
|
|
||||||
parts = person.name_parts()
|
|
||||||
groups = [ r.group.acronym for r in person.role_set.filter(name__slug='chair',
|
|
||||||
group__type='wg',
|
|
||||||
group__state__slug__in=('active','bof','proposed')) ]
|
|
||||||
entry = {'name':'%s, %s' % (parts[3], parts[1]),
|
|
||||||
'groups': ', '.join(groups)}
|
|
||||||
chairs.append(entry)
|
|
||||||
|
|
||||||
# sort the list
|
|
||||||
sorted_chairs = sorted(chairs, key = lambda a: a['name'])
|
|
||||||
|
|
||||||
return render(request, 'groups/blue_dot_report.txt', { 'chairs':sorted_chairs },
|
|
||||||
content_type="text/plain; charset=%s"%settings.DEFAULT_CHARSET,
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def charter(request, acronym):
|
|
||||||
"""
|
|
||||||
View Group Charter
|
|
||||||
|
|
||||||
**Templates:**
|
|
||||||
|
|
||||||
* ``groups/charter.html``
|
|
||||||
|
|
||||||
**Template Variables:**
|
|
||||||
|
|
||||||
* group, charter_text
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
group = get_object_or_404(Group, acronym=acronym)
|
|
||||||
# TODO: get_charter_text() should be updated to return None
|
|
||||||
if group.charter:
|
|
||||||
charter_text = get_charter_text(group)
|
|
||||||
else:
|
|
||||||
charter_text = ''
|
|
||||||
|
|
||||||
return render(request, 'groups/charter.html', {
|
|
||||||
'group': group,
|
|
||||||
'charter_text': charter_text},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def delete_role(request, acronym, id):
|
|
||||||
"""
|
|
||||||
Handle deleting roles for groups (chair, editor, advisor, secretary)
|
|
||||||
|
|
||||||
**Templates:**
|
|
||||||
|
|
||||||
* none
|
|
||||||
|
|
||||||
Redirects to people page on success.
|
|
||||||
|
|
||||||
"""
|
|
||||||
group = get_object_or_404(Group, acronym=acronym)
|
|
||||||
role = get_object_or_404(Role, id=id)
|
|
||||||
|
|
||||||
if request.method == 'POST' and request.POST['post'] == 'yes':
|
|
||||||
# save group
|
|
||||||
save_group_in_history(group)
|
|
||||||
|
|
||||||
role.delete()
|
|
||||||
messages.success(request, 'The entry was deleted successfully')
|
|
||||||
return redirect('ietf.secr.groups.views.people', acronym=acronym)
|
|
||||||
|
|
||||||
return render(request, 'confirm_delete.html', {'object': role})
|
|
||||||
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def people(request, acronym):
|
|
||||||
"""
|
|
||||||
Edit Group Roles (Chairs, Secretary, etc)
|
|
||||||
|
|
||||||
**Templates:**
|
|
||||||
|
|
||||||
* ``groups/people.html``
|
|
||||||
|
|
||||||
**Template Variables:**
|
|
||||||
|
|
||||||
* form, group
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
group = get_object_or_404(Group, acronym=acronym)
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
# we need to pass group for form validation
|
|
||||||
form = RoleForm(request.POST,group=group)
|
|
||||||
if form.is_valid():
|
|
||||||
name = form.cleaned_data['name']
|
|
||||||
person = form.cleaned_data['person']
|
|
||||||
email = form.cleaned_data['email']
|
|
||||||
|
|
||||||
# save group
|
|
||||||
save_group_in_history(group)
|
|
||||||
|
|
||||||
Role.objects.create(name=name,
|
|
||||||
person=person,
|
|
||||||
email=email,
|
|
||||||
group=group)
|
|
||||||
|
|
||||||
if not email.origin or email.origin == person.user.username:
|
|
||||||
email.origin = "role: %s %s" % (group.acronym, name.slug)
|
|
||||||
email.save()
|
|
||||||
|
|
||||||
messages.success(request, 'New %s added successfully!' % name)
|
|
||||||
return redirect('ietf.secr.groups.views.people', acronym=group.acronym)
|
|
||||||
else:
|
|
||||||
form = RoleForm(initial={'name':'chair', 'group_acronym':group.acronym}, group=group)
|
|
||||||
|
|
||||||
return render(request, 'groups/people.html', {
|
|
||||||
'form':form,
|
|
||||||
'group':group},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def search(request):
|
|
||||||
"""
|
|
||||||
Search IETF Groups
|
|
||||||
|
|
||||||
**Templates:**
|
|
||||||
|
|
||||||
* ``groups/search.html``
|
|
||||||
|
|
||||||
**Template Variables:**
|
|
||||||
|
|
||||||
* form, results
|
|
||||||
|
|
||||||
"""
|
|
||||||
results = []
|
|
||||||
if request.method == 'POST':
|
|
||||||
form = SearchForm(request.POST)
|
|
||||||
|
|
||||||
if form.is_valid():
|
|
||||||
kwargs = {}
|
|
||||||
group_acronym = form.cleaned_data['group_acronym']
|
|
||||||
group_name = form.cleaned_data['group_name']
|
|
||||||
primary_area = form.cleaned_data['primary_area']
|
|
||||||
meeting_scheduled = form.cleaned_data['meeting_scheduled']
|
|
||||||
state = form.cleaned_data['state']
|
|
||||||
type = form.cleaned_data['type']
|
|
||||||
meeting = get_current_meeting()
|
|
||||||
|
|
||||||
# construct search query
|
|
||||||
if group_acronym:
|
|
||||||
kwargs['acronym__istartswith'] = group_acronym
|
|
||||||
if group_name:
|
|
||||||
kwargs['name__istartswith'] = group_name
|
|
||||||
if primary_area:
|
|
||||||
kwargs['parent'] = primary_area
|
|
||||||
if state:
|
|
||||||
kwargs['state'] = state
|
|
||||||
if type:
|
|
||||||
kwargs['type'] = type
|
|
||||||
#else:
|
|
||||||
# kwargs['type__in'] = ('wg','rg','ietf','ag','sdo','team')
|
|
||||||
|
|
||||||
if meeting_scheduled == 'YES':
|
|
||||||
kwargs['session__meeting__number'] = meeting.number
|
|
||||||
# perform query
|
|
||||||
if kwargs:
|
|
||||||
if meeting_scheduled == 'NO':
|
|
||||||
qs = Group.objects.filter(**kwargs).exclude(session__meeting__number=meeting.number).distinct()
|
|
||||||
else:
|
|
||||||
qs = Group.objects.filter(**kwargs).distinct()
|
|
||||||
else:
|
|
||||||
qs = Group.objects.all()
|
|
||||||
results = qs.order_by('acronym')
|
|
||||||
|
|
||||||
# if there's just one result go straight to view
|
|
||||||
if len(results) == 1:
|
|
||||||
return redirect('ietf.secr.groups.views.view', acronym=results[0].acronym)
|
|
||||||
|
|
||||||
# process GET argument to support link from area app
|
|
||||||
elif 'primary_area' in request.GET:
|
|
||||||
area = request.GET.get('primary_area','')
|
|
||||||
results = Group.objects.filter(parent__id=area,type='wg',state__in=('bof','active','proposed')).order_by('name')
|
|
||||||
form = SearchForm({'primary_area':area,'state':'','type':'wg'})
|
|
||||||
else:
|
|
||||||
form = SearchForm(initial={'state':'active'})
|
|
||||||
|
|
||||||
# loop through results and tack on meeting_scheduled because it is no longer an
|
|
||||||
# attribute of the meeting model
|
|
||||||
for result in results:
|
|
||||||
add_legacy_fields(result)
|
|
||||||
|
|
||||||
return render(request, 'groups/search.html', {
|
|
||||||
'results': results,
|
|
||||||
'form': form},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def view(request, acronym):
|
|
||||||
"""
|
|
||||||
View IETF Group details
|
|
||||||
|
|
||||||
**Templates:**
|
|
||||||
|
|
||||||
* ``groups/view.html``
|
|
||||||
|
|
||||||
**Template Variables:**
|
|
||||||
|
|
||||||
* group
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
group = get_object_or_404(Group, acronym=acronym)
|
|
||||||
|
|
||||||
add_legacy_fields(group)
|
|
||||||
|
|
||||||
return render(request, 'groups/view.html', { 'group': group } )
|
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
<!-- <li><button type="button" onclick="window.location='../../'">Back</button></li> -->
|
<!-- <li><button type="button" onclick="window.location='../../'">Back</button></li> -->
|
||||||
<li><button type="button" onclick="window.location='edit/'">Edit</button></li>
|
<li><button type="button" onclick="window.location='edit/'">Edit</button></li>
|
||||||
<li><button type="button" onclick="window.location='people/'">People</button></li>
|
<li><button type="button" onclick="window.location='people/'">People</button></li>
|
||||||
<li><button type="button" onclick="window.location='{% url 'ietf.secr.groups.views.search' %}?primary_area={{ area.id }}'">Groups</button></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div> <!-- button-group -->
|
</div> <!-- button-group -->
|
||||||
</div> <!-- module -->
|
</div> <!-- module -->
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
BLUE DOT REPORT
|
|
||||||
|
|
||||||
NAMES ROSTER BADGE
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
{% for chair in chairs %}{{ chair.name|safe|stringformat:"-33s" }}{{ chair.groups|stringformat:"-36s" }}BLUE
|
|
||||||
{% endfor %}
|
|
|
@ -1,25 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Groups - Charter{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Groups</a>
|
|
||||||
» <a href="../">{{ group.acronym }}</a>
|
|
||||||
» Charter
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module group-container">
|
|
||||||
<h2>Groups - Charter</h2>
|
|
||||||
<pre>
|
|
||||||
{% if charter_txt %}{{ charter_text }}{% else %}Charter not found.{% endif %}
|
|
||||||
</pre>
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,72 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles widget_tweaks %}
|
|
||||||
|
|
||||||
{% block title %}Groups - People{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<link rel="stylesheet" href="{% static 'ietf/css/jquery-ui.css' %}">
|
|
||||||
<script src="{% static 'ietf/js/jquery-ui.js' %}"></script>
|
|
||||||
<script src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Groups</a>
|
|
||||||
» <a href="../">{{ group.acronym }}</a>
|
|
||||||
» People
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module">
|
|
||||||
<h2>People</h2>
|
|
||||||
<table class="full-width">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">Role</th>
|
|
||||||
<th scope="col">Name</th>
|
|
||||||
<th scope="col">Email</th>
|
|
||||||
<th scope="col">Action</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
{% if group.role_set.all %}
|
|
||||||
<tbody>
|
|
||||||
{% for role in group.role_set.all %}
|
|
||||||
<tr class="{% cycle 'row1' 'row2' %}">
|
|
||||||
<td>{{ role.name }}</td>
|
|
||||||
<td>{{ role.person }}</td>
|
|
||||||
<td>{{ role.email }}</td>
|
|
||||||
<td><a href="{% url 'ietf.secr.groups.views.delete_role' acronym=group.acronym id=role.id %}">Delete</a></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
{% endif %}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="inline-related">
|
|
||||||
<!-- <hr><br> -->
|
|
||||||
<h3>Add Role</h3>
|
|
||||||
<form id="groups-people" method="post">{% csrf_token %}
|
|
||||||
{{ form.non_field_errors }}
|
|
||||||
{{ form.group_acronym }}
|
|
||||||
<table class="full-width">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>{{ form.name.errors }}{{ form.name|attr:"aria-label:Name" }}</td>
|
|
||||||
<td>{{ form.person.errors }}{{ form.person|attr:"aria-label:Person" }}{% if form.person.help_text %}<br>{{ form.person.help_text }}{% endif %}</td>
|
|
||||||
<td>{{ form.email.errors }}{{ form.email|attr:"aria-label:Email" }}{% if form.email.help_text %}<br>{{ form.email.help_text }}{% endif %}</td>
|
|
||||||
<td><button type="submit" name="submit">Add</button></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
</div> <!-- inline-related -->
|
|
||||||
|
|
||||||
<div class="button-group">
|
|
||||||
<ul>
|
|
||||||
<li><button type="button" onclick="window.location='../'">Back</button></li>
|
|
||||||
</ul>
|
|
||||||
</div> <!-- button-group -->
|
|
||||||
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,39 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Groups - Search{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
|
|
||||||
<script src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
<script src="{% static "ietf/js/list.js" %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» Groups
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module group-container">
|
|
||||||
<h2>Groups - Search</h2>
|
|
||||||
<form enctype="multipart/form-data" method="post">{% csrf_token %}
|
|
||||||
<table class="full-width amstable">
|
|
||||||
<tbody>
|
|
||||||
<!-- [html-validate-disable-block wcag/h63 -- FIXME: as_table renders without scope] -->
|
|
||||||
{{ form.as_table }}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% include "includes/buttons_search.html" %}
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="inline-related">
|
|
||||||
<h2>Search Results</h2>
|
|
||||||
{% include "includes/group_search_results.html" %}
|
|
||||||
{% if not_found %}{{ not_found }}{% endif %}
|
|
||||||
</div> <!-- inline-group -->
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,123 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Groups - View{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../">Groups</a>
|
|
||||||
» {{ group.acronym }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module group-container">
|
|
||||||
<div id="groups-view-col1">
|
|
||||||
<h2>Groups - View</h2>
|
|
||||||
<table >
|
|
||||||
<tbody>
|
|
||||||
<tr><td>Group Acronym:</td><td>{{ group.acronym }}</td></tr>
|
|
||||||
<tr><td>Group Name:</td><td>{{ group.name }}</td></tr>
|
|
||||||
<tr><td>Status:</td><td>{{ group.state }}</td></tr>
|
|
||||||
<tr><td>Type:</td><td>{{ group.type }}</td></tr>
|
|
||||||
<tr><td>Proposed Date:</td><td>{{ group.proposed_date|date:"Y-m-d" }}</td></tr>
|
|
||||||
<tr><td>Start Date:</td><td>{{ group.start_date|date:"Y-m-d" }}</td></tr>
|
|
||||||
<tr><td>Concluded Date:</td><td>{{ group.concluded_date|date:"Y-m-d" }}</td></tr>
|
|
||||||
{% comment %}
|
|
||||||
Here we need to check that group.area_director and group.area_director.area are defined before referencing.
|
|
||||||
Otherwise the template would raise errors if the group area director record didn't exist or
|
|
||||||
in the case of Area Director = TBD, the area field is NULL
|
|
||||||
{% endcomment %}
|
|
||||||
<tr><td>Primary Area:</td>
|
|
||||||
<td>{% if not group.parent %}(No Data){% else %}
|
|
||||||
<a href="{% url "ietf.secr.areas.views.view" name=group.parent.acronym %}">{{ group.parent }}</a>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>Primary Area Director:</td>
|
|
||||||
<td>{% if group.ad_role %}
|
|
||||||
<a href="{% url 'ietf.secr.rolodex.views.view' id=group.ad_role.person.id %}">{{ group.ad_role.person }}</a>
|
|
||||||
{% endif %}
|
|
||||||
</td></tr>
|
|
||||||
<tr><td>Meeting Scheduled:</td><td>{{ group.meeting_scheduled}}</td></tr>
|
|
||||||
<tr><td>Email Address:</td><td>{{ group.list_email }}</td></tr>
|
|
||||||
<tr><td>Email Subscription:</td><td>{{ group.list_subscribe }}</td></tr>
|
|
||||||
<tr><td>Email Archive:</td><td>{{ group.list_archive }}</td></tr>
|
|
||||||
{% if group.liaison_contacts %}
|
|
||||||
<tr><td>Default Liaison Contacts:</td><td>{{ group.liaison_contacts.contacts }}</td></tr>
|
|
||||||
{% endif %}
|
|
||||||
{% if group.features.has_chartering_process %}
|
|
||||||
<tr><td>Charter:</td><td><a href="{% url 'ietf.secr.groups.views.charter' acronym=group.acronym %}">View Charter</a></td></tr>
|
|
||||||
{% else %}
|
|
||||||
<tr><td>Description:</td><td>{{ group.description }}</td></tr>
|
|
||||||
{% endif %}
|
|
||||||
<tr><td>Comments:</td><td>{{ group.comments }}</td></tr>
|
|
||||||
<tr><td>Last Modified Date:</td><td>{{ group.time }}</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
</div> <!-- groups-view-col1 -->
|
|
||||||
<div id="groups-view-col2">
|
|
||||||
<div class="inline-related">
|
|
||||||
<h2>Chairperson(s)</h2>
|
|
||||||
{% if group.chairs %}
|
|
||||||
<table>
|
|
||||||
{% for role in group.chairs %}
|
|
||||||
<tr><td><a href="{% url 'ietf.secr.rolodex.views.view' id=role.person.id %}">{{ role.person }}</a></td></tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% endif %}
|
|
||||||
</div> <!-- inline-related -->
|
|
||||||
|
|
||||||
<div class="inline-related">
|
|
||||||
<h2>Document Editor(s)</h2>
|
|
||||||
{% if group.editors %}
|
|
||||||
<table>
|
|
||||||
{% for role in group.editors %}
|
|
||||||
<tr><td><a href="{% url 'ietf.secr.rolodex.views.view' id=role.person.id %}">{{ role.person }}</a></td></tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% endif %}
|
|
||||||
</div> <!-- inline-related -->
|
|
||||||
|
|
||||||
<div class="inline-related">
|
|
||||||
<h2>Technical Advisor(s)</h2>
|
|
||||||
{% if group.techadvisors %}
|
|
||||||
<table>
|
|
||||||
{% for role in group.techadvisors %}
|
|
||||||
<tr><td><a href="{% url 'ietf.secr.rolodex.views.view' id=role.person.id %}">{{ role.person }}</a></td></tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% endif %}
|
|
||||||
</div> <!-- inline-related -->
|
|
||||||
|
|
||||||
<div class="inline-related">
|
|
||||||
<h2>Secretary(ies)</h2>
|
|
||||||
{% if group.secretaries %}
|
|
||||||
<table>
|
|
||||||
{% for role in group.secretaries %}
|
|
||||||
<tr><td><a href="{% url 'ietf.secr.rolodex.views.view' id=role.person.id %}">{{ role.person }}</a></td></tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% endif %}
|
|
||||||
</div> <!-- inline-related -->
|
|
||||||
|
|
||||||
</div> <!-- groups-view-col2 -->
|
|
||||||
|
|
||||||
<div class="button-group">
|
|
||||||
<ul>
|
|
||||||
<li><button type="button" onclick="window.location='edit/'">Edit</button></li>
|
|
||||||
<li><button type="button" onclick="window.location='people/'">People</button></li>
|
|
||||||
{% comment %}
|
|
||||||
<li><button type="button" onclick="window.location='{% url "sec.ids.views.search" id=group.group_acronym.acronym_id %}'">Drafts</button></li>
|
|
||||||
<li><button type="button" onclick="window.location='{% url "sec.rfcs.views.search" id=group.group_acronym.acronym_id %}'">RFCs</button></li>
|
|
||||||
{% endcomment %}
|
|
||||||
</ul>
|
|
||||||
</div> <!-- button-group -->
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,24 +0,0 @@
|
||||||
<table id="group-search-results" class="center" cellspacing="0">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">Group Name</th>
|
|
||||||
<th scope="col">Group Acronym</th>
|
|
||||||
<th scope="col">Status</th>
|
|
||||||
<th scope="col">Type</th>
|
|
||||||
<th scope="col">Meeting Scheduled</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for item in results %}
|
|
||||||
<tr class="{% cycle 'row1' 'row2' %}">
|
|
||||||
<td><a href="{% url 'ietf.secr.groups.views.view' acronym=item.acronym %}">{{item.name}}</a></td>
|
|
||||||
<td>{{item.acronym}}</td>
|
|
||||||
<td>{{item.state}}</td>
|
|
||||||
<td>{{item.type}}</td>
|
|
||||||
<td>{{item.meeting_scheduled}}</td>
|
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr><td><b>No Results</b></td></tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
|
@ -21,7 +21,6 @@
|
||||||
<h2>IDs and WGs Process</h2>
|
<h2>IDs and WGs Process</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li> <a href="{% url "ietf.secr.areas.views.list_areas" %}"><b>Areas</b></a></li>
|
<li> <a href="{% url "ietf.secr.areas.views.list_areas" %}"><b>Areas</b></a></li>
|
||||||
<li> <a href="{% url 'ietf.secr.groups.views.search' %}"><b>Groups</b></a></li>
|
|
||||||
<li> <a href="{% url 'ietf.secr.rolodex.views.search' %}"><b>Rolodex</b></a></li>
|
<li> <a href="{% url 'ietf.secr.rolodex.views.search' %}"><b>Rolodex</b></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
{% if role.group.type.slug == "area" %}
|
{% if role.group.type.slug == "area" %}
|
||||||
<a href="{% url "ietf.secr.areas.views.view" name=role.group.acronym %}">{{ role.group.acronym }}{% if role.group.state.slug == "conclude" %} (concluded){% endif %}</a>
|
<a href="{% url "ietf.secr.areas.views.view" name=role.group.acronym %}">{{ role.group.acronym }}{% if role.group.state.slug == "conclude" %} (concluded){% endif %}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'ietf.secr.groups.views.view' acronym=role.group.acronym %}">{{ role.group.acronym }}{% if role.group.state.slug == "conclude" %} (concluded){% endif %}</a>
|
<a href="{% url 'ietf.group.views.group_home' acronym=role.group.acronym %}">{{ role.group.acronym }}{% if role.group.state.slug == "conclude" %} (concluded){% endif %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ role.email }}</td>
|
<td>{{ role.email }}</td>
|
||||||
|
|
|
@ -6,7 +6,6 @@ urlpatterns = [
|
||||||
url(r'^announcement/', include('ietf.secr.announcement.urls')),
|
url(r'^announcement/', include('ietf.secr.announcement.urls')),
|
||||||
url(r'^areas/', include('ietf.secr.areas.urls')),
|
url(r'^areas/', include('ietf.secr.areas.urls')),
|
||||||
url(r'^console/', include('ietf.secr.console.urls')),
|
url(r'^console/', include('ietf.secr.console.urls')),
|
||||||
url(r'^groups/', include('ietf.secr.groups.urls')),
|
|
||||||
url(r'^meetings/', include('ietf.secr.meetings.urls')),
|
url(r'^meetings/', include('ietf.secr.meetings.urls')),
|
||||||
url(r'^rolodex/', include('ietf.secr.rolodex.urls')),
|
url(r'^rolodex/', include('ietf.secr.rolodex.urls')),
|
||||||
url(r'^sreq/', include('ietf.secr.sreq.urls')),
|
url(r'^sreq/', include('ietf.secr.sreq.urls')),
|
||||||
|
|
|
@ -476,7 +476,6 @@ INSTALLED_APPS = [
|
||||||
# IETF Secretariat apps
|
# IETF Secretariat apps
|
||||||
'ietf.secr.announcement',
|
'ietf.secr.announcement',
|
||||||
'ietf.secr.areas',
|
'ietf.secr.areas',
|
||||||
'ietf.secr.groups',
|
|
||||||
'ietf.secr.meetings',
|
'ietf.secr.meetings',
|
||||||
'ietf.secr.rolodex',
|
'ietf.secr.rolodex',
|
||||||
'ietf.secr.sreq',
|
'ietf.secr.sreq',
|
||||||
|
|
Loading…
Reference in a new issue