Skip to content

Commit da376fe

Browse files
committed
Fix privacy bug with statistics
1 parent fd6d691 commit da376fe

2 files changed

Lines changed: 59 additions & 1 deletion

File tree

‎astra_app/core/tests/test_membership_stats_dashboard.py‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,62 @@ def test_membership_stats_data_returns_expected_top_level_shape(self) -> None:
11561156
self.assertIn("summary", payload)
11571157
self.assertIn("charts", payload)
11581158

1159+
def test_membership_stats_data_ignores_profile_privacy_for_aggregated_counts(self) -> None:
1160+
cache.clear()
1161+
1162+
MembershipTypeCategory.objects.update_or_create(
1163+
name="individual",
1164+
defaults={
1165+
"is_individual": True,
1166+
"is_organization": False,
1167+
"sort_order": 0,
1168+
},
1169+
)
1170+
MembershipType.objects.update_or_create(
1171+
code="individual",
1172+
defaults={
1173+
"name": "Individual",
1174+
"group_cn": "almalinux-individual",
1175+
"category_id": "individual",
1176+
"sort_order": 0,
1177+
"enabled": True,
1178+
},
1179+
)
1180+
Membership.objects.update_or_create(
1181+
target_username="alice",
1182+
membership_type_id="individual",
1183+
defaults={"expires_at": timezone.now() + datetime.timedelta(days=30)},
1184+
)
1185+
1186+
self._grant_membership_stats_permission()
1187+
self._login_as_freeipa_user("reviewer")
1188+
reviewer = self._reviewer_user()
1189+
country_attr = str(settings.SELF_SERVICE_ADDRESS_COUNTRY_ATTR).strip()
1190+
alice = FreeIPAUser(
1191+
"alice",
1192+
{
1193+
"uid": ["alice"],
1194+
country_attr: ["US"],
1195+
"fasIsPrivate": ["TRUE"],
1196+
"memberof_group": [],
1197+
},
1198+
)
1199+
1200+
def _all_users(*, respect_privacy: bool = True) -> list[FreeIPAUser]:
1201+
self.assertFalse(respect_privacy)
1202+
return [alice]
1203+
1204+
with patch("core.freeipa.user.FreeIPAUser.get", return_value=reviewer):
1205+
with patch("core.freeipa.user.FreeIPAUser.all", side_effect=_all_users):
1206+
resp = self.client.get(reverse("membership-stats-data"))
1207+
1208+
self.assertEqual(resp.status_code, 200)
1209+
payload = resp.json()
1210+
self.assertEqual(payload["summary"]["total_freeipa_users"], 1)
1211+
self.assertEqual(payload["summary"]["active_individual_memberships"], 1)
1212+
active_members = payload["charts"]["nationality_active_members"]
1213+
self.assertEqual(dict(zip(active_members["labels"], active_members["counts"], strict=False)), {"US": 1})
1214+
11591215
def test_membership_stats_expirations_chart_excludes_expiry_exactly_at_now(self) -> None:
11601216
frozen_now = datetime.datetime(2026, 1, 1, 12, 0, 0, tzinfo=datetime.UTC)
11611217

‎astra_app/core/views_membership_admin.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,9 @@ def membership_stats_data(request: HttpRequest) -> HttpResponse:
432432
trend_start = now - datetime.timedelta(days=days_window) if days_window is not None else None
433433

434434
def compute_payload() -> dict[str, object]:
435-
all_freeipa_users = FreeIPAUser.all()
435+
# Statistics are aggregated, so profile privacy redaction would only
436+
# hide data needed for accurate counts.
437+
all_freeipa_users = FreeIPAUser.all(respect_privacy=False)
436438
users_by_username = {u.username: u for u in all_freeipa_users if u.username}
437439
active_freeipa_users = [u for u in all_freeipa_users if u.is_active]
438440

0 commit comments

Comments
 (0)