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>
86 lines
2.7 KiB
Go
86 lines
2.7 KiB
Go
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())
|
||
}
|