This commit is contained in:
Deluan Quintão 2026-10-06 09:50:59 -04:00 • committed by GitHub
commit 38960501fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
91 changed files with 7115 additions and 157 deletions

View file

@ -37,6 +37,7 @@ type DataStore interface {
Plugin() PluginRepository
Artwork() ArtworkRepository
ArtworkQueue() ArtworkQueueRepository
Grant() GrantRepository
WithTx(block func(tx DataStore) error, scope ...string) error
WithTxImmediate(block func(tx DataStore) error, scope ...string) error

67
model/grant.go Normal file
View file

@ -0,0 +1,67 @@
package model
import (
"context"
"database/sql/driver"
"fmt"
"strings"
"time"
)
type Grant struct {
ID string `structs:"id" json:"id"`
UserID string `structs:"user_id" json:"userId"`
Name string `structs:"name" json:"name"`
Client string `structs:"client" json:"client"`
ClientVersion string `structs:"client_version" json:"clientVersion"`
Scopes Scopes `structs:"scopes" json:"scopes"`
Provider string `structs:"provider" json:"provider"`
SecretHash string `structs:"secret_hash" json:"-"`
UserEpoch int `structs:"user_epoch" json:"-"`
CreatedAt time.Time `structs:"created_at" json:"createdAt"`
LastUsedAt *time.Time `structs:"last_used_at" json:"lastUsedAt"`
LastUsedIP string `structs:"last_used_ip" json:"lastUsedIp"`
}
func (g Grant) LastActivity() time.Time {
if g.LastUsedAt != nil {
return *g.LastUsedAt
}
return g.CreatedAt
}
type Grants []Grant
// Scopes is stored as a single space-separated column.
type Scopes []string
func (s Scopes) Value() (driver.Value, error) {
return strings.Join(s, " "), nil
}
func (s *Scopes) Scan(src any) error {
switch v := src.(type) {
case string:
*s = strings.Fields(v)
case []byte:
*s = strings.Fields(string(v))
case nil:
*s = nil
default:
return fmt.Errorf("cannot scan %T into Scopes", src)
}
return nil
}
type GrantRepository interface {
Put(ctx context.Context, g *Grant) error
Get(ctx context.Context, id string) (*Grant, error)
FindBySecretHash(ctx context.Context, hash string) (*Grant, error)
GetAllForUser(ctx context.Context, userID string, epoch int, idleSince time.Time, offset, limit int) (Grants, error)
CountForUser(ctx context.Context, userID string, epoch int, idleSince time.Time) (int64, error)
DeleteForUser(ctx context.Context, userID, id string) error
DeleteStaleEpochs(ctx context.Context, userID string, currentEpoch int) error
SetEpoch(ctx context.Context, userID string, fromEpoch, toEpoch int, onlyID string) error
Touch(ctx context.Context, id, ip string, at, notSince time.Time) error
DeleteIdle(ctx context.Context, idleSince time.Time) (int64, error)
}

24
model/grant_test.go Normal file
View file

@ -0,0 +1,24 @@
package model_test
import (
"time"
"github.com/navidrome/navidrome/model"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("Grant", func() {
Describe("LastActivity", func() {
created := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
It("is the creation time for a grant never used", func() {
Expect(model.Grant{CreatedAt: created}.LastActivity()).To(Equal(created))
})
It("is the last use once the grant was used", func() {
used := created.Add(time.Hour)
Expect(model.Grant{CreatedAt: created, LastUsedAt: &used}.LastActivity()).To(Equal(used))
})
})
})