Files
navidrome/core/user.go
2026-02-08 09:57:30 -05:00

77 lines
2.2 KiB
Go

package core
import (
"context"
"github.com/deluan/rest"
"github.com/navidrome/navidrome/model"
)
// PluginUnloader defines the interface for unloading disabled plugins.
// This is satisfied by plugins.Manager but defined here to avoid import cycles.
type PluginUnloader interface {
UnloadDisabledPlugins(ctx context.Context)
}
// User provides business logic for user management with plugin coordination.
type User interface {
NewRepository(ctx context.Context) rest.Repository
}
type userService struct {
ds model.DataStore
pluginManager PluginUnloader
}
// NewUser creates a new User service
func NewUser(ds model.DataStore, pluginManager PluginUnloader) User {
return &userService{
ds: ds,
pluginManager: pluginManager,
}
}
// NewRepository returns a REST repository wrapper for user operations.
// The wrapper intercepts Delete operations to coordinate plugin unloading.
func (s *userService) NewRepository(ctx context.Context) rest.Repository {
repo := s.ds.User(ctx)
wrapper := &userRepositoryWrapper{
ctx: ctx,
UserRepository: repo,
pluginManager: s.pluginManager,
}
return wrapper
}
type userRepositoryWrapper struct {
model.UserRepository
ctx context.Context
pluginManager PluginUnloader
}
// Save implements rest.Persistable by delegating to the underlying repository.
func (r *userRepositoryWrapper) Save(entity any) (string, error) {
return r.UserRepository.(rest.Persistable).Save(entity)
}
// Update implements rest.Persistable by delegating to the underlying repository.
func (r *userRepositoryWrapper) Update(id string, entity any, cols ...string) error {
return r.UserRepository.(rest.Persistable).Update(id, entity, cols...)
}
// Delete implements rest.Persistable and coordinates plugin unloading.
func (r *userRepositoryWrapper) Delete(id string) error {
// The underlying repository Delete handles the database cleanup
// including calling cleanupPluginUserReferences
err := r.UserRepository.(rest.Persistable).Delete(id)
if err != nil {
return err
}
// After successful deletion, check if any plugins were auto-disabled
// and need to be unloaded from memory
r.pluginManager.UnloadDisabledPlugins(r.ctx)
return nil
}