Add a news review workflow and a staff notification area

News gains a PENDING_REVIEW status between draft and published. A
non-editor author (can_add_news but not can_publish_news -- a
coach_manager, not an ADMIN/EDITOR) gets a "Send for review" button
instead of Publish; an editor/admin always sees Publish directly, no
review step. Submitting notifies every ADMIN/EDITOR in-app only (see
notify_members' new send_email=False) -- a review queue that emailed
on every submission would get noisy fast.

The notification area itself: a topbar bell (badge + dropdown, same
<details>/<summary> convention as the sidebar's user-menu, generalised
to a shared .dismissable-details close handler) visible on every page,
plus a fuller "Notifications" card on the dashboard, both fed by a new
notification_bell context processor. "Mark all read" clears the
signed-in staff member's own unread notifications for this club.

This is the reusable notification system's first consumer beyond news
publishing itself -- validates that notify_members()/Notification
generalise the way they were meant to.

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 09:52:59 +02:00
parent 20a44a915f
commit 0ecdeac354
16 changed files with 421 additions and 26 deletions

View File

@@ -14,6 +14,7 @@ import markdown as _markdown
import nh3
from django.utils.html import strip_tags
from django.utils.text import Truncator
from django.utils.translation import gettext_lazy as _
_EXTENSIONS = [
"nl2br", # staff type in a plain textarea -- a single Enter should break the line,
@@ -39,3 +40,20 @@ def render_body_excerpt(body: str, *, words: int) -> str:
verbatim in what's meant to be a short teaser."""
plain_text = strip_tags(render_body_html(body))
return Truncator(plain_text).words(words, truncate="")
def notify_editors_of_pending_review(news_item):
"""In-app only (see notifications.services.notify_members's send_email
param) -- a review queue that emailed every editor/admin on every
submission would get noisy fast; the topbar bell and the dashboard card
are enough for this. Called from management.views.NewsSubmitForReviewView,
not from News.submit_for_review() itself, same as publish()/unpublish()
never send anything on their own either."""
from club.models import ClubRole
from members.models import Member
from notifications.services import notify_members
editors = Member.objects.filter(roles__club=news_item.club, roles__role__in=[ClubRole.Roles.ADMIN, ClubRole.Roles.EDITOR]).distinct()
title = _("%(news)s” is ready for review") % {"news": news_item.title}
body = _("%(author)s submitted this news item for review before it can go live.") % {"author": news_item.created_by or _("Someone")}
return notify_members(editors, club=news_item.club, title=title, body=body, source=news_item, send_email=False)