feat(notifications): requests and flags reach the people who act on them (#5340)
- A new request still pending after any auto-approval notifies the admins (request_pending), but not the requester if they are an admin. A request that dedups into one already in flight is not announced again. - Approving or rejecting a request notifies the requester, and a rejection carries the admin's notes as the reason. An admin deciding their own request gets nothing. - The reconciler notifies the requester when their request arrives (request_completed), linking the matched album or artist. - A request the re-acquisition sweeper files and cannot approve itself notifies the admins. - A quarantine flag notifies every admin except the flagger, naming the track, the flagger and the reason. lidarrrequests.Service.CreateTracked reports whether a request was inserted or deduped; Create wraps it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
"git.fabledsword.com/bvandeusen/minstrel/internal/dbtest"
|
||||
"git.fabledsword.com/bvandeusen/minstrel/internal/lidarrconfig"
|
||||
"git.fabledsword.com/bvandeusen/minstrel/internal/lidarrrequests"
|
||||
"git.fabledsword.com/bvandeusen/minstrel/internal/notifications"
|
||||
"git.fabledsword.com/bvandeusen/minstrel/internal/tags"
|
||||
)
|
||||
|
||||
@@ -84,9 +85,10 @@ func TestSweep_RequestsAlbumsByReleaseGroup_Integration(t *testing.T) {
|
||||
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||
q := dbq.New(pool)
|
||||
|
||||
if _, err := q.CreateUser(ctx, dbq.CreateUserParams{
|
||||
admin, err := q.CreateUser(ctx, dbq.CreateUserParams{
|
||||
Username: dbtest.TestUserPrefix + "sweepadmin", PasswordHash: "x", ApiTokenHash: "x", IsAdmin: true,
|
||||
}); err != nil {
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
settings, err := NewSettingsService(ctx, pool, logger)
|
||||
@@ -105,6 +107,7 @@ func TestSweep_RequestsAlbumsByReleaseGroup_Integration(t *testing.T) {
|
||||
|
||||
requests := lidarrrequests.NewService(pool, lidarrconfig.New(pool), nil, nil)
|
||||
s := NewSweeper(pool, settings, requests, logger)
|
||||
s.SetNotifier(notifications.New(pool, nil, nil))
|
||||
asked := map[string]int{}
|
||||
s.releaseGroup = func(_ context.Context, release string) (string, error) {
|
||||
asked[release]++
|
||||
@@ -153,6 +156,20 @@ SELECT lr.lidarr_album_mbid
|
||||
if attempts != 0 {
|
||||
t.Errorf("unresolvable album spent an attempt (%d state rows)", attempts)
|
||||
}
|
||||
// M489: the two requests filed without auto-approval wait on an admin,
|
||||
// so each reaches the admins' inbox; the unresolvable album filed none.
|
||||
inbox, err := q.ListNotifications(ctx, dbq.ListNotificationsParams{UserID: admin.ID, PageLimit: 10})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(inbox) != 2 {
|
||||
t.Errorf("admin inbox holds %d notifications, want 2", len(inbox))
|
||||
}
|
||||
for _, n := range inbox {
|
||||
if n.Kind != string(notifications.KindRequestPending) {
|
||||
t.Errorf("admin inbox holds %q, want request_pending", n.Kind)
|
||||
}
|
||||
}
|
||||
var stray int
|
||||
if err := pool.QueryRow(ctx, "SELECT count(*) FROM lidarr_requests WHERE lidarr_album_mbid LIKE 'release-%'").Scan(&stray); err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
Reference in New Issue
Block a user