Notify members when a new event is planned

New events.tasks.notify_new_event, scheduled from
management.views.EventCreateView.form_valid -- the deliberate "a staff
member planned one new event" action, not every Event row that happens
to get created. A recurring series' rolling-horizon extension
(extend_event_series) and bulk fixture imports are NOT wired to this on
purpose: either would flood everyone with one push per occurrence
instead of the single, deliberate action this is meant to catch.

Notifies whoever is still NO_RESPONSE right after creation -- exactly
"everyone who needs to respond", using the existing notify_members() ->
Notification -> mobile.signals push chain already in place, so this is
in-app (visible in the M7 inbox, mark read/mark-all-read) and a push
notification both, with no new plumbing needed there.

Generalized mobile.views.NotificationsView's News-only "tap to open the
source" handling (previously isinstance(source, News)) into
_notification_source_link, covering Event sources too -- tapping an
"new event" notification now marks it read and opens the event's answer
screen, the same way a news notification already opened the article.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
This commit is contained in:
2026-08-21 17:03:26 +02:00
parent 1bf3a9d37a
commit 81f8f7f7dd
6 changed files with 101 additions and 28 deletions

View File

@@ -897,6 +897,17 @@ class NotificationsViewTests(TestCase):
redirect_response = self._post({"action": "mark_read", "notification_id": str(notification.pk)})
self.assertRedirects(redirect_response, reverse("mobile:news_detail", kwargs={"slug": news_item.slug}), fetch_redirect_response=False)
def test_notification_with_an_event_source_is_labelled_and_mark_read_redirects_to_it(self):
event = Event.objects.create(club=self.club, title="Practice", start=timezone.now() + datetime.timedelta(days=1))
notification = Notification.objects.create(club=self.club, member=self.member, title="New event", body="Body.", source=event)
self.client.force_login(self.user)
response = self._get()
self.assertContains(response, "New event")
redirect_response = self._post({"action": "mark_read", "notification_id": str(notification.pk)})
self.assertRedirects(redirect_response, reverse("mobile:event_detail", kwargs={"pk": event.pk}), fetch_redirect_response=False)
def test_empty_account_gets_a_graceful_empty_state(self):
bare_user = User.objects.create_user(email="new@example.com", password="pw-secret-123")
self.client.force_login(bare_user)