package models import ( "context" "encoding/json" "fmt" "time" cairnapi "github.com/mattnite/cairn/internal/api" "gorm.io/gorm" ) type CreateCampaignParams struct { RepositoryID uint Name string Type string Tags json.RawMessage Metadata json.RawMessage } func CreateCampaign(ctx context.Context, db *gorm.DB, p CreateCampaignParams) (*cairnapi.Campaign, error) { if p.Tags == nil { p.Tags = json.RawMessage("{}") } if p.Metadata == nil { p.Metadata = json.RawMessage("{}") } campaign := &Campaign{ RepositoryID: p.RepositoryID, Name: p.Name, Type: p.Type, Status: "running", StartedAt: time.Now(), Tags: p.Tags, Metadata: p.Metadata, } if err := db.WithContext(ctx).Create(campaign).Error; err != nil { return nil, fmt.Errorf("creating campaign: %w", err) } return enrichCampaign(ctx, db, *campaign) } func FinishCampaign(ctx context.Context, db *gorm.DB, id uint) error { now := time.Now() if err := db.WithContext(ctx).Model(&Campaign{}).Where("id = ?", id).Updates(map[string]any{ "status": "finished", "finished_at": now, }).Error; err != nil { return fmt.Errorf("finishing campaign: %w", err) } return nil } func GetCampaign(ctx context.Context, db *gorm.DB, id uint) (*cairnapi.Campaign, error) { campaign := &Campaign{} if err := db.WithContext(ctx).First(campaign, id).Error; err != nil { return nil, fmt.Errorf("getting campaign: %w", err) } return enrichCampaign(ctx, db, *campaign) } func ListCampaigns(ctx context.Context, db *gorm.DB, repoID *uint, limit, offset int) ([]cairnapi.Campaign, int64, error) { if limit <= 0 { limit = 50 } query := db.WithContext(ctx).Model(&Campaign{}) if repoID != nil { query = query.Where("repository_id = ?", *repoID) } var total int64 if err := query.Count(&total).Error; err != nil { return nil, 0, fmt.Errorf("counting campaigns: %w", err) } var dbCampaigns []Campaign if err := query.Order("created_at DESC").Limit(limit).Offset(offset).Find(&dbCampaigns).Error; err != nil { return nil, 0, fmt.Errorf("listing campaigns: %w", err) } campaigns := make([]cairnapi.Campaign, 0, len(dbCampaigns)) for _, m := range dbCampaigns { c, err := enrichCampaign(ctx, db, m) if err != nil { return nil, 0, err } campaigns = append(campaigns, *c) } return campaigns, total, nil } func enrichCampaign(ctx context.Context, db *gorm.DB, model Campaign) (*cairnapi.Campaign, error) { repo := &Repository{} if err := db.WithContext(ctx).First(repo, model.RepositoryID).Error; err != nil { return nil, fmt.Errorf("loading campaign repository: %w", err) } var count int64 if err := db.WithContext(ctx).Model(&Artifact{}).Where("campaign_id = ?", model.ID).Count(&count).Error; err != nil { return nil, fmt.Errorf("counting campaign artifacts: %w", err) } campaign := campaignFromModel(model) campaign.RepoName = repo.Name campaign.ArtifactCount = count return &campaign, nil } func campaignFromModel(m Campaign) cairnapi.Campaign { return cairnapi.Campaign{ ID: m.ID, RepositoryID: m.RepositoryID, Name: m.Name, Type: m.Type, Status: m.Status, StartedAt: m.StartedAt, FinishedAt: m.FinishedAt, Tags: m.Tags, Metadata: m.Metadata, CreatedAt: m.CreatedAt, } }