feat: add group leadership list (#8135)
* feat: add Group Leadership list * fix: only offer export to staff * fix: fix export button conditional * fix: improve tests. black format --------- Co-authored-by: Robert Sparks <rjsparks@nostrum.com>
This commit is contained in:
parent
8bc51e3cc2
commit
b07d4dbebc
|
@ -65,6 +65,53 @@ class StreamTests(TestCase):
|
|||
self.assertTrue(Role.objects.filter(name="delegate", group__acronym=stream_acronym, email__address="ad2@ietf.org"))
|
||||
|
||||
|
||||
class GroupLeadershipTests(TestCase):
|
||||
def test_leadership_wg(self):
|
||||
# setup various group states
|
||||
bof_role = RoleFactory(
|
||||
group__type_id="wg", group__state_id="bof", name_id="chair"
|
||||
)
|
||||
proposed_role = RoleFactory(
|
||||
group__type_id="wg", group__state_id="proposed", name_id="chair"
|
||||
)
|
||||
active_role = RoleFactory(
|
||||
group__type_id="wg", group__state_id="active", name_id="chair"
|
||||
)
|
||||
conclude_role = RoleFactory(
|
||||
group__type_id="wg", group__state_id="conclude", name_id="chair"
|
||||
)
|
||||
url = urlreverse(
|
||||
"ietf.group.views.group_leadership", kwargs={"group_type": "wg"}
|
||||
)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertContains(r, "Group Leadership")
|
||||
self.assertContains(r, bof_role.person.last_name())
|
||||
self.assertContains(r, proposed_role.person.last_name())
|
||||
self.assertContains(r, active_role.person.last_name())
|
||||
self.assertNotContains(r, conclude_role.person.last_name())
|
||||
|
||||
def test_leadership_wg_csv(self):
|
||||
url = urlreverse(
|
||||
"ietf.group.views.group_leadership_csv", kwargs={"group_type": "wg"}
|
||||
)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r["Content-Type"], "text/csv")
|
||||
self.assertContains(r, "Chairman, Sops")
|
||||
|
||||
def test_leadership_rg(self):
|
||||
role = RoleFactory(group__type_id="rg", name_id="chair")
|
||||
url = urlreverse(
|
||||
"ietf.group.views.group_leadership", kwargs={"group_type": "rg"}
|
||||
)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertContains(r, "Group Leadership")
|
||||
self.assertContains(r, role.person.last_name())
|
||||
self.assertNotContains(r, "Chairman, Sops")
|
||||
|
||||
|
||||
class GroupStatsTests(TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
|
|
@ -57,7 +57,9 @@ info_detail_urls = [
|
|||
|
||||
|
||||
group_urls = [
|
||||
url(r'^$', views.active_groups),
|
||||
url(r'^$', views.active_groups),
|
||||
url(r'^leadership/(?P<group_type>(wg|rg))/$', views.group_leadership),
|
||||
url(r'^leadership/(?P<group_type>(wg|rg))/csv/$', views.group_leadership_csv),
|
||||
url(r'^groupstats.json', views.group_stats_data, None, 'ietf.group.views.group_stats_data'),
|
||||
url(r'^groupmenu.json', views.group_menu_data, None, 'ietf.group.views.group_menu_data'),
|
||||
url(r'^chartering/$', views.chartering_groups),
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
|
||||
import copy
|
||||
import csv
|
||||
import datetime
|
||||
import itertools
|
||||
import math
|
||||
|
@ -437,6 +438,48 @@ def prepare_group_documents(request, group, clist):
|
|||
|
||||
return docs, meta, docs_related, meta_related
|
||||
|
||||
|
||||
def get_leadership(group_type):
|
||||
people = Person.objects.filter(
|
||||
role__name__slug="chair",
|
||||
role__group__type=group_type,
|
||||
role__group__state__slug__in=("active", "bof", "proposed"),
|
||||
).distinct()
|
||||
leaders = []
|
||||
for person in people:
|
||||
parts = person.name_parts()
|
||||
groups = [
|
||||
r.group.acronym
|
||||
for r in person.role_set.filter(
|
||||
name__slug="chair",
|
||||
group__type=group_type,
|
||||
group__state__slug__in=("active", "bof", "proposed"),
|
||||
)
|
||||
]
|
||||
entry = {"name": "%s, %s" % (parts[3], parts[1]), "groups": ", ".join(groups)}
|
||||
leaders.append(entry)
|
||||
return sorted(leaders, key=lambda a: a["name"])
|
||||
|
||||
|
||||
def group_leadership(request, group_type=None):
|
||||
context = {}
|
||||
context["leaders"] = get_leadership(group_type)
|
||||
context["group_type"] = group_type
|
||||
return render(request, "group/group_leadership.html", context)
|
||||
|
||||
|
||||
def group_leadership_csv(request, group_type=None):
|
||||
leaders = get_leadership(group_type)
|
||||
response = HttpResponse(content_type="text/csv")
|
||||
response["Content-Disposition"] = (
|
||||
f'attachment; filename="group_leadership_{group_type}.csv"'
|
||||
)
|
||||
writer = csv.writer(response, dialect=csv.excel, delimiter=str(","))
|
||||
writer.writerow(["Name", "Groups"])
|
||||
for leader in leaders:
|
||||
writer.writerow([leader["name"], leader["groups"]])
|
||||
return response
|
||||
|
||||
def group_home(request, acronym, group_type=None):
|
||||
group = get_group_or_404(acronym, group_type)
|
||||
kwargs = dict(acronym=group.acronym)
|
||||
|
|
34
ietf/templates/group/group_leadership.html
Normal file
34
ietf/templates/group/group_leadership.html
Normal file
|
@ -0,0 +1,34 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2024, All Rights Reserved #}
|
||||
{% load origin static person_filters ietf_filters %}
|
||||
{% block pagehead %}
|
||||
<link rel="stylesheet" href="{% static 'ietf/css/list.css' %}">
|
||||
{% endblock %}
|
||||
{% block title %}Group Leadership{% endblock %}
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>Group Leadership ({{ group_type }})</h1>
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
<div class="text-end">
|
||||
<a class="btn btn-primary" href="{% url 'ietf.group.views.group_leadership_csv' group_type=group_type %}">
|
||||
<i class="bi bi-file-ruled"></i> Export as CSV
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Leader</th>
|
||||
<th scope="col">Groups</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for leader in leaders %}
|
||||
<tr>
|
||||
<td>{{ leader.name }}</td>
|
||||
<td>{{ leader.groups }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
Loading…
Reference in a new issue