97 lines
3.2 KiB
Go
97 lines
3.2 KiB
Go
|
|
package usecase
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
|
||
|
|
"apps/backend/internal/module/scout/domain"
|
||
|
|
|
||
|
|
"github.com/google/uuid"
|
||
|
|
)
|
||
|
|
|
||
|
|
func (s *Service) GetRun(ctx context.Context, ownerUID int64, runID string) (*domain.Run, error) {
|
||
|
|
if s == nil || s.Repo == nil || runID == "" {
|
||
|
|
return nil, domain.ErrValidation
|
||
|
|
}
|
||
|
|
return s.Repo.GetRun(ctx, ownerUID, runID)
|
||
|
|
}
|
||
|
|
|
||
|
|
// CreateQueuedRun creates one independent run for every scan request. The
|
||
|
|
// job_id is bound in a second guarded write after job scheduling succeeds.
|
||
|
|
func (s *Service) CreateQueuedRun(ctx context.Context, ownerUID int64, brief *domain.RunBrief) (*domain.Run, error) {
|
||
|
|
if s == nil || s.Repo == nil || brief == nil || ownerUID == 0 {
|
||
|
|
return nil, domain.ErrValidation
|
||
|
|
}
|
||
|
|
run := domain.NewRun("run_"+uuid.NewString(), "", ownerUID, *brief, domain.NowNano())
|
||
|
|
if err := s.Repo.CreateRun(ctx, run); err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
return run, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Service) BindRunJob(ctx context.Context, ownerUID int64, runID, jobID string) (*domain.Run, error) {
|
||
|
|
if s == nil || s.Repo == nil || runID == "" || jobID == "" {
|
||
|
|
return nil, domain.ErrValidation
|
||
|
|
}
|
||
|
|
run, err := s.Repo.GetRun(ctx, ownerUID, runID)
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
if run.JobID != "" && run.JobID != jobID {
|
||
|
|
return nil, domain.ErrIllegalRunStatus
|
||
|
|
}
|
||
|
|
run.JobID = jobID
|
||
|
|
if err := s.Repo.ReplaceRunGuarded(ctx, ownerUID, runID, []string{domain.RunQueued}, run); err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
return run, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// ListRuns returns only runs owned by ownerUID. Pagination is normalized here
|
||
|
|
// so every caller (HTTP, worker and tests) observes the same page contract.
|
||
|
|
func (s *Service) ListRuns(ctx context.Context, ownerUID int64, brandID, mode string, page, pageSize int) (domain.RunPage, error) {
|
||
|
|
if s == nil || s.Repo == nil {
|
||
|
|
return domain.RunPage{}, domain.ErrValidation
|
||
|
|
}
|
||
|
|
pageInfo := domain.NormalizePage(page, pageSize)
|
||
|
|
return s.Repo.ListRuns(ctx, domain.RunFilter{
|
||
|
|
OwnerUID: ownerUID,
|
||
|
|
BrandID: brandID,
|
||
|
|
Mode: mode,
|
||
|
|
Page: pageInfo.Page,
|
||
|
|
PageSize: pageInfo.PageSize,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// ListRunPosts returns the selected run and its independently paged results.
|
||
|
|
// Repository implementations hide staged results until the run succeeds.
|
||
|
|
func (s *Service) ListRunPosts(ctx context.Context, ownerUID int64, runID string, page, pageSize int) (domain.RunPostPage, error) {
|
||
|
|
if s == nil || s.Repo == nil {
|
||
|
|
return domain.RunPostPage{}, domain.ErrValidation
|
||
|
|
}
|
||
|
|
if runID == "" {
|
||
|
|
return domain.RunPostPage{}, domain.ErrValidation
|
||
|
|
}
|
||
|
|
pageInfo := domain.NormalizePage(page, pageSize)
|
||
|
|
return s.Repo.ListRunPosts(ctx, ownerUID, runID, pageInfo.Page, pageInfo.PageSize)
|
||
|
|
}
|
||
|
|
|
||
|
|
// RemoveRun only permits terminal runs to be removed. Returning the same
|
||
|
|
// guarded transition error for queued/running keeps the API from exposing
|
||
|
|
// implementation details while allowing response mapping to a 409 conflict.
|
||
|
|
func (s *Service) RemoveRun(ctx context.Context, ownerUID int64, runID string) error {
|
||
|
|
if s == nil || s.Repo == nil {
|
||
|
|
return domain.ErrValidation
|
||
|
|
}
|
||
|
|
if runID == "" {
|
||
|
|
return domain.ErrValidation
|
||
|
|
}
|
||
|
|
r, err := s.Repo.GetRun(ctx, ownerUID, runID)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
if !domain.IsRunTerminal(r.Status) {
|
||
|
|
return domain.ErrIllegalRunStatus
|
||
|
|
}
|
||
|
|
return s.Repo.DeleteRun(ctx, ownerUID, runID)
|
||
|
|
}
|