Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added archived teams page. #1741

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions djangoproject/templates/members/team_archive.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{% extends "base_foundation.html" %}

{% block og_title %}Team History | Django Software Foundation{% endblock %}
{% block og_description %}{% spaceless %}
This is a record of former team members and archived teams within the
Django Software Foundation.
{% endspaceless %}{% endblock %}

{% block content %}

<h2>Team Archive</h2>
<p>This is a record of former team members and archived teams.</p>
<p>See the <a href="{% url 'members:teams' %}">Teams</a> page for details on current teams.</p>

<h3>Former Team Members</h3>
{% if teams %}
{% for team in teams %}
<div class="section">
<h4 id="{{ team.slug }}-team">{{ team.name }}<a class="plink" href="#{{ team.slug }}-team">¶</a></h4>
<p>{{ team.description|safe }}</p>
<ul>
{% for member in team.previousteammembership_set.all %}
<li>{{ member.member.name }}{% if member.details %} ({{ member.details }}){% endif %}</li>
{% endfor %}
</ul>
</div>
{% endfor %}
{% else %}
<p>We have no record of former members at this time.</p>
{% endif %}

<h3>Archived Teams</h3>
{% if archived_teams %}
{% for team in archived_teams %}
<div class="section">
<h4 id="{{ team.slug }}-team">{{ team.name }}<a class="plink" href="#{{ team.slug }}-team">¶</a></h4>
<p>{{ team.description|safe }}</p>
<ul>
{% for member in team.members.all %}
<li>{{ member.name }}</li>
{% endfor %}
{% for member in team.previousteammembership_set.all %}
<li>{{ member.member.name }}{% if member.details %} ({{ member.details }}){% endif %}</li>
{% endfor %}
</ul>
</div>
{% endfor %}
{% else %}
<p>We have no record of archived teams at this time.</p>
{% endif %}

{% endblock %}
1 change: 1 addition & 0 deletions djangoproject/templates/members/team_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

<h2>Teams</h2>
<p>Teams indicate who is actively contributing in certain areas.</p>
<p>See the <a href="{% url 'members:teams-archive' %}">Teams Archive</a> page for details on former team members and archived teams.</p>

{% for team in teams %}
<div class="section">
Expand Down
20 changes: 19 additions & 1 deletion members/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
from django.utils.formats import localize
from django.utils.html import format_html

from members.models import CorporateMember, IndividualMember, Invoice, Team
from members.models import (
CorporateMember,
IndividualMember,
Invoice,
PreviousTeamMembership,
Team,
)


@admin.register(IndividualMember)
Expand Down Expand Up @@ -106,3 +112,15 @@ def membership_expires(self, obj):
class TeamAdmin(admin.ModelAdmin):
filter_horizontal = ["members"]
prepopulated_fields = {"slug": ("name",)}


@admin.register(PreviousTeamMembership)
class PreviousTeamMembershipAdmin(admin.ModelAdmin):
list_display = [
"member",
"team",
]
search_fields = ["member__name", "team__name"]

def get_queryset(self, request):
return super().get_queryset(request).select_related("team", "member")
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Generated by Django 5.0.9 on 2024-11-16 04:54

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('members', '0009_alter_individualmember_add_reason_help_text'),
]

operations = [
migrations.AddField(
model_name='team',
name='archived',
field=models.BooleanField(default=False),
),
migrations.CreateModel(
name='PreviousTeamMembership',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('details', models.TextField(blank=True, help_text='Use for details such as term dates. This is publicly displayed within brackets next to the members name. <strong>Do not include confidential details.</strong>')),
('member', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='members.individualmember')),
('team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='members.team')),
],
),
migrations.AddField(
model_name='team',
name='former_members',
field=models.ManyToManyField(related_name='teams_former_member', through='members.PreviousTeamMembership', to='members.individualmember'),
),
]
20 changes: 20 additions & 0 deletions members/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,30 @@ class Team(models.Model):
description = models.TextField(help_text="HTML, without surrounding <p> tags.")
members = models.ManyToManyField(IndividualMember)

archived = models.BooleanField(default=False)
former_members = models.ManyToManyField(
IndividualMember,
through="PreviousTeamMembership",
related_name="teams_former_member",
)

def __str__(self):
return self.name


class PreviousTeamMembership(models.Model):
team = models.ForeignKey(Team, on_delete=models.CASCADE)
member = models.ForeignKey(IndividualMember, on_delete=models.CASCADE)
details = models.TextField(
blank=True,
help_text=mark_safe(
"Use for details such as term dates. This is publicly displayed "
"within brackets next to the members name. "
"<strong>Do not include confidential details.</strong>"
),
)


class CorporateMemberManager(models.Manager):
def for_public_display(self):
objs = (
Expand Down
69 changes: 68 additions & 1 deletion members/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.test import TestCase
from django.urls import reverse

from .models import CorporateMember, IndividualMember, Team
from .models import CorporateMember, IndividualMember, PreviousTeamMembership, Team
from .utils import get_temporary_image


Expand Down Expand Up @@ -164,3 +164,70 @@ def test_get(self):
)
self.assertContains(response, "<p>Ops stuff.</p>")
self.assertContains(response, "<ul><li>DjangoDeveloper</li></ul>", html=True)

def test_archived_team_excluded(self):
Team.objects.create(name="Technical team", archived=True)
response = self.client.get(self.url)
self.assertNotContains(response, "Technical team")


class TeamsArchiveViewTests(TestCase):
url = reverse("members:teams-archive")

def test_no_data(self):
response = self.client.get(self.url)

self.assertContains(response, "<h3>Former Team Members</h3>", html=True)
self.assertContains(
response, "We have no record of former members at this time."
)
self.assertContains(response, "<h3>Archived Teams</h3>", html=True)
self.assertContains(
response, "We have no record of archived teams at this time."
)

def test_former_team_member(self):
alice = IndividualMember.objects.create(name="Alice", email="[email protected]")
jessica = IndividualMember.objects.create(name="Jessica", email="[email protected]")
priya = IndividualMember.objects.create(name="Priya", email="[email protected]")
security_team = Team.objects.create(name="Security team")
security_team.members.add(alice)

PreviousTeamMembership.objects.create(
team=security_team, member=jessica, details="2010-2011"
)
PreviousTeamMembership.objects.create(team=security_team, member=priya)

response = self.client.get(self.url)

self.assertContains(response, "<h3>Former Team Members</h3>", html=True)
self.assertNotContains(
response, "We have no record of former members at this time."
)
self.assertContains(response, "Security team")
self.assertNotContains(response, "Alice")
self.assertContains(response, "Jessica (2010-2011)")
self.assertContains(response, "Priya")

def test_archived_team(self):
alice = IndividualMember.objects.create(name="Alice", email="[email protected]")
jessica = IndividualMember.objects.create(name="Jessica", email="[email protected]")
priya = IndividualMember.objects.create(name="Priya", email="[email protected]")
technical_team = Team.objects.create(name="Technical team", archived=True)
technical_team.members.add(alice)

PreviousTeamMembership.objects.create(
team=technical_team, member=jessica, details="2010-2011"
)
PreviousTeamMembership.objects.create(team=technical_team, member=priya)

response = self.client.get(self.url)

self.assertContains(response, "<h3>Archived Teams</h3>", html=True)
self.assertNotContains(
response, "We have no record of archived teams at this time."
)
self.assertContains(response, "Technical team")
self.assertContains(response, "Alice")
self.assertContains(response, "Jessica (2010-2011)")
self.assertContains(response, "Priya")
2 changes: 2 additions & 0 deletions members/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
CorporateMemberRenewView,
CorporateMemberSignUpView,
IndividualMemberListView,
TeamsArchiveView,
TeamsListView,
corporate_member_list_view,
)
Expand Down Expand Up @@ -46,4 +47,5 @@
name="corporate-members-badges",
),
path("teams/", TeamsListView.as_view(), name="teams"),
path("teams/archive/", TeamsArchiveView.as_view(), name="teams-archive"),
]
47 changes: 46 additions & 1 deletion members/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.core import signing
from django.db.models import Count, Prefetch
from django.http import Http404
from django.shortcuts import render
from django.urls import reverse
Expand All @@ -10,6 +11,7 @@
CORPORATE_MEMBERSHIP_AMOUNTS,
CorporateMember,
IndividualMember,
PreviousTeamMembership,
Team,
)

Expand Down Expand Up @@ -99,4 +101,47 @@ class TeamsListView(ListView):
context_object_name = "teams"

def get_queryset(self):
return self.model.objects.prefetch_related("members").order_by("name")
return (
self.model.objects.filter(archived=False)
.prefetch_related("members")
.order_by("name")
)


class TeamsArchiveView(TemplateView):
template_name = "members/team_archive.html"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)

previous_team_membership_qs = PreviousTeamMembership.objects.select_related(
"member"
)
archived_teams = (
Team.objects.filter(archived=True)
.prefetch_related(
"members",
Prefetch(
"previousteammembership_set",
queryset=previous_team_membership_qs,
),
)
.order_by("name")
)

# Active teams with former members.
teams = (
Team.objects.prefetch_related(
Prefetch(
"previousteammembership_set",
queryset=previous_team_membership_qs,
)
)
.annotate(former_member_count=Count("former_members", distinct=True))
.filter(former_member_count__gt=0, archived=False)
.order_by("name")
)

context["teams"] = teams
context["archived_teams"] = archived_teams
return context