Files
minstrel/internal/api/notify_producers.go
T
bvandeusenandClaude Opus 5.5 08a2c06b85 docs: api comments say what the endpoints do, not how they came to be (#6277)
Rewrites the internal/api comment blocks to rule 32: task, milestone and
rule ids gone, the stories behind them restated as the constraint they
left, stale references corrected (the stream secret is wired from config,
the timezone handler already refreshes the scheduler, the Android app is
the native client, the design docs cited are not in the repo). Also
rewraps comment lines over 80 columns left by the earlier batches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 12:23:58 -04:00

86 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package api
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
"git.fabledsword.com/bvandeusen/minstrel/internal/library"
"git.fabledsword.com/bvandeusen/minstrel/internal/notifications"
"git.fabledsword.com/bvandeusen/minstrel/internal/requests"
)
// Helpers for the handlers that produce notifications. Every call is
// NotifyLogged: a notification never fails the action that caused it.
// userLabel is how a user is named to someone else: their display name, or
// their username when they have none.
func userLabel(u dbq.User) string {
if u.DisplayName != nil && *u.DisplayName != "" {
return *u.DisplayName
}
return u.Username
}
func requestPayload(row dbq.Request) notifications.Payload {
return notifications.Payload{
RequestID: uuidToString(row.ID),
RequestKind: string(row.Kind),
Name: requests.DisplayName(row),
}
}
// notifyRequestDecided tells the requester an admin approved or declined
// their request. An admin deciding their own request needs no notice.
func (h *handlers) notifyRequestDecided(ctx context.Context, kind notifications.Kind, admin dbq.User, row dbq.Request, reason string) {
if row.UserID == admin.ID {
return
}
p := requestPayload(row)
p.Reason = reason
h.notifier.NotifyLogged(ctx, kind, notifications.ToUser(row.UserID), p.Map())
}
// quarantineReasonLabel is a flag reason as the flag popover words it, in
// lower case to sit inside a sentence ("flagged X: bad rip").
func quarantineReasonLabel(reason string) string {
switch reason {
case "bad_rip":
return "bad rip"
case "wrong_file":
return "wrong file"
case "wrong_tags":
return "wrong tags"
case "duplicate":
return "duplicate"
default:
return ""
}
}
// trackLabel names a track "Artist – Title" for a notification, falling back
// to the title alone, or to nothing, rather than failing the caller.
func (h *handlers) trackLabel(ctx context.Context, trackID pgtype.UUID) string {
q := dbq.New(h.pool)
t, err := q.GetTrackByID(ctx, trackID)
if err != nil {
return ""
}
if a, aerr := q.GetArtistByID(ctx, t.ArtistID); aerr == nil {
return library.TrackLabel(a.Name, t.Title)
}
return t.Title
}
// notifyPlaybackErrors tells admins a track failed to play, naming it and who
// it failed for. The notice coalesces: while it is unread each report
// adds one to its count and its name to the front of the list.
func (h *handlers) notifyPlaybackErrors(ctx context.Context, trackID pgtype.UUID, user dbq.User) {
p := notifications.Payload{Count: 1}
if name := h.trackLabel(ctx, trackID); name != "" {
p.Items = []string{name + " (" + userLabel(user) + ")"}
}
h.notifier.NotifyLogged(ctx, notifications.KindPlaybackErrors, notifications.ToAdmins(pgtype.UUID{}), p.Map())
}