diff --git a/djangoproject/scss/_style.scss b/djangoproject/scss/_style.scss
index 27bf24b36..4fcccf526 100644
--- a/djangoproject/scss/_style.scss
+++ b/djangoproject/scss/_style.scss
@@ -1459,7 +1459,7 @@ a.cta {
margin-bottom: 5px;
}
- li {
+ > li {
border-top: 1px solid var(--hairline-color);
margin-top: 35px;
padding-top: 10px;
diff --git a/djangoproject/templates/base_foundation.html b/djangoproject/templates/base_foundation.html
index cec983f3d..f63f04838 100644
--- a/djangoproject/templates/base_foundation.html
+++ b/djangoproject/templates/base_foundation.html
@@ -1,5 +1,5 @@
{% extends "base.html" %}
-{% load fundraising_extras %}
+{% load fundraising_extras meetings i18n %}
{% block og_title %}Django Software Foundation{% endblock %}
@@ -25,5 +25,8 @@
About the foundation
Contributor license agreements
Organizing a Django conference
+ {% translate "Latest DSF meeting minutes" %}
+ {% render_latest_meeting_minute_entries 2 %}
+ {% translate "More meeting minutes" %}
{% endblock %}
diff --git a/djangoproject/templates/foundation/meeting_snippet.html b/djangoproject/templates/foundation/meeting_snippet.html
new file mode 100644
index 000000000..0e72198eb
--- /dev/null
+++ b/djangoproject/templates/foundation/meeting_snippet.html
@@ -0,0 +1,25 @@
+{% load i18n %}
+
diff --git a/foundation/templatetags/__init__.py b/foundation/templatetags/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/foundation/templatetags/meetings.py b/foundation/templatetags/meetings.py
new file mode 100644
index 000000000..80aeec8e8
--- /dev/null
+++ b/foundation/templatetags/meetings.py
@@ -0,0 +1,11 @@
+from django import template
+
+from ..models import Meeting
+
+register = template.Library()
+
+
+@register.inclusion_tag("foundation/meeting_snippet.html")
+def render_latest_meeting_minute_entries(num):
+ meetings = Meeting.objects.order_by("-date").prefetch_related("business")[:num]
+ return {"meetings": meetings}
diff --git a/foundation/tests.py b/foundation/tests.py
index 11cbd2786..38569f375 100644
--- a/foundation/tests.py
+++ b/foundation/tests.py
@@ -5,13 +5,23 @@
from django.urls import reverse
from djmoney.money import Money
-from .models import ApprovedGrant, BoardMember, Meeting, Office, Term
+from .models import ApprovedGrant, BoardMember, Business, Meeting, Office, Term
class MeetingTestCase(TestCase):
+ @classmethod
+ def setUpTestData(cls):
+ cls.user = User.objects.create_superuser(
+ "admin", "admin@example.com", "password"
+ )
+ cls.member = BoardMember.objects.create(
+ account=cls.user,
+ office=Office.objects.create(name="treasurer"),
+ term=Term.objects.create(year=2023),
+ )
+
def test_meeting_initial(self):
- user = User.objects.create_superuser("admin", "admin@example.com", "password")
- self.client.force_login(user)
+ self.client.force_login(self.user)
response = self.client.get(reverse("admin:foundation_meeting_add"))
self.assertContains(response, "DSF Board monthly meeting")
self.assertContains(response, "dsf-board-monthly-meeting")
@@ -20,17 +30,11 @@ def test_meeting_minutes_feed(self):
"""
Make sure that the meeting minutes RSS feed works
"""
- user = User.objects.create_superuser("admin", "admin@example.com", "password")
- member = BoardMember.objects.create(
- account=user,
- office=Office.objects.create(name="treasurer"),
- term=Term.objects.create(year=2023),
- )
Meeting.objects.create(
date=date.today(),
title="DSF Board monthly meeting",
slug="dsf-board-monthly-meeting",
- leader=member,
+ leader=self.member,
treasurer_report="Hello World",
)
@@ -39,18 +43,11 @@ def test_meeting_minutes_feed(self):
self.assertIn(b"DSF Board monthly meeting", response.content)
def test_meeting_details(self):
- user = User.objects.create_superuser("admin", "admin@example.com", "password")
- self.client.force_login(user)
- member = BoardMember.objects.create(
- account=user,
- office=Office.objects.create(name="treasurer"),
- term=Term.objects.create(year=2023),
- )
meeting = Meeting.objects.create(
date=date(2023, 1, 12),
title="DSF Board monthly meeting",
slug="dsf-board-monthly-meeting",
- leader=member,
+ leader=self.member,
treasurer_report="Hello World",
)
ApprovedGrant.objects.create(
@@ -77,3 +74,42 @@ def test_meeting_details(self):
self.assertContains(response, "DSF Board monthly meeting")
self.assertContains(response, "USD $10,000.00")
self.assertContains(response, "EUR €5,000.00")
+
+ def test_latest_meeting_minutes(self):
+ common_meeting_data = {
+ "slug": "dsf-board-monthly-meeting",
+ "leader": self.member,
+ "treasurer_report": "Hello World",
+ "title": "DSF Board monthly meeting",
+ }
+ latest_meeting = Meeting.objects.create(
+ date=date(2023, 5, 12), **common_meeting_data
+ )
+ previous_meeting = Meeting.objects.create(
+ date=date(2023, 4, 12), **common_meeting_data
+ )
+ Meeting.objects.create(date=date(2023, 3, 12), **common_meeting_data)
+ common_business_data = {
+ "body": "Example",
+ "body_html": "Example",
+ "business_type": "New",
+ "meeting": latest_meeting,
+ }
+ Business.objects.create(title="Business item 1", **common_business_data)
+ Business.objects.create(title="Business item 2", **common_business_data)
+ Business.objects.create(title="Business item 3", **common_business_data)
+
+ response = self.client.get(reverse("foundation_meeting_archive_index"))
+
+ self.assertContains(response, "Latest DSF meeting minutes")
+
+ self.assertContains(response, "DSF Board monthly meeting, May 12, 2023")
+ self.assertContains(response, latest_meeting.get_absolute_url())
+ self.assertContains(response, "DSF Board monthly meeting, April 12, 2023")
+ self.assertContains(response, previous_meeting.get_absolute_url())
+ self.assertNotContains(response, "DSF Board monthly meeting, March 12, 2023")
+
+ self.assertContains(response, "New and Ongoing business", count=1)
+ self.assertContains(response, "Business item 1")
+ self.assertContains(response, "Business item 2")
+ self.assertContains(response, "Business item 3")