ci / module boundaries / boundaries (push) Successful in 6s
ci / api / api (push) Successful in 47s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m2s
ci / db / db (push) Successful in 1m4s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m30s
ci / ts / ts (packages + web) (push) Successful in 2m54s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m14s
71 lines
2.2 KiB
Go
71 lines
2.2 KiB
Go
package library
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"log/slog"
|
|
|
|
"pipu/api/internal/auth"
|
|
"pipu/api/internal/platform/apperr"
|
|
)
|
|
|
|
// Коды ошибок библиотеки.
|
|
const (
|
|
CodeSourceNotFound = "library.source_not_found"
|
|
CodeScanRunning = "library.scan_running"
|
|
CodeSourceOffline = "library.source_offline"
|
|
CodePatternInvalid = "validation.pattern_invalid"
|
|
CodeNFSInvalid = "validation.nfs_invalid"
|
|
CodeLocalPathInvalid = "validation.local_path_invalid"
|
|
CodeNameInvalid = "validation.name_invalid"
|
|
CodeIntervalInvalid = "validation.scan_interval_invalid"
|
|
CodeNotFound = "catalog.not_found"
|
|
CodeTemplateInvalid = "validation.template_invalid"
|
|
CodeTemplateNone = "library.template_unavailable"
|
|
)
|
|
|
|
// Config — пути к хранилищам в файловой системе api.
|
|
type Config struct {
|
|
LibraryRoot string // точки монтирования NFS: <root>/<source_id>
|
|
HostRoot string // LIBRARY_HOST внутри контейнера, для local-источников
|
|
}
|
|
|
|
// Service preserves the API while each use case owns only its dependencies.
|
|
type Service struct {
|
|
*SourceService
|
|
*TemplateService
|
|
*ScanService
|
|
*Scheduler
|
|
}
|
|
|
|
func NewService(store *Store, scanner *Scanner, board *ProgressBoard, agent Agent, prober Prober, cfg Config, log *slog.Logger) *Service {
|
|
sources := &SourceService{store: store, board: board, agent: agent, cfg: cfg, log: log}
|
|
scans := &ScanService{store: store, scanner: scanner, board: board, root: sources.Root}
|
|
return &Service{
|
|
SourceService: sources,
|
|
TemplateService: &TemplateService{store: store, prober: prober, root: sources.Root},
|
|
ScanService: scans,
|
|
Scheduler: &Scheduler{store: store, sources: sources, scans: scans, log: log},
|
|
}
|
|
}
|
|
|
|
func forbidden() error { return apperr.Forbidden(auth.CodeForbidden, "not allowed") }
|
|
|
|
func requirePerm(ctx context.Context, perm auth.Permission) error {
|
|
p, ok := auth.PrincipalFrom(ctx)
|
|
if !ok {
|
|
return apperr.Unauthorized(auth.CodeUnauthorized, "not authenticated")
|
|
}
|
|
if !auth.Can(p.Role, perm) {
|
|
return forbidden()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func notFound(err error) error {
|
|
if errors.Is(err, ErrNotFound) {
|
|
return apperr.NotFound(CodeSourceNotFound, "source not found")
|
|
}
|
|
return err
|
|
}
|