package sites import ( "context" "errors" "github.com/jackc/pgx/v5" "lmika.dev/lmika/hugo-cms/config" "lmika.dev/lmika/hugo-cms/models" "lmika.dev/lmika/hugo-cms/providers/db" "lmika.dev/lmika/hugo-cms/providers/themes" "lmika.dev/lmika/hugo-cms/services/jobs" "lmika.dev/lmika/hugo-cms/services/sitebuilder" "strings" "unicode" ) type Service struct { cfg config.Config db *db.DB themes *themes.Provider sb *sitebuilder.Service jobs *jobs.Service } func NewService( cfg config.Config, db *db.DB, themes *themes.Provider, sb *sitebuilder.Service, jobs *jobs.Service, ) *Service { return &Service{ cfg: cfg, db: db, themes: themes, sb: sb, jobs: jobs, } } func (s *Service) GetSite(ctx context.Context, id int) (models.Site, error) { return s.db.GetSite(ctx, int64(id)) } func (s *Service) GetProdTargetOfSite(ctx context.Context, siteID int) (models.PublishTarget, error) { return s.db.GetPublishTargetBySiteRole(ctx, int64(siteID), models.TargetRoleProduction) } func (s *Service) SaveSettings(ctx context.Context, site models.Site, newSettings NewSettings) error { _, ok := s.themes.Lookup(newSettings.SiteTheme) if !ok { return errors.New("theme not found") } newSite := site newSite.Title = newSettings.SiteTitle newSite.Name = normaliseName(newSite.Title) newSite.Theme = newSettings.SiteTheme if err := s.db.UpdateSite(ctx, newSite); err != nil { return err } pubTarget, err := s.db.GetPublishTargetBySiteRole(ctx, newSite.ID, models.TargetRoleProduction) if err == nil { pubTarget.TargetRef = newSettings.TargetRef pubTarget.URL = newSettings.TargetURL if err := s.db.UpdatePublishTarget(ctx, pubTarget); err != nil { return err } } else if errors.Is(err, pgx.ErrNoRows) { pubTarget = models.PublishTarget{ SiteID: newSite.ID, Role: models.TargetRoleProduction, Type: models.TargetTypeNetlify, URL: newSettings.TargetURL, TargetRef: newSettings.TargetRef, } if err := s.db.InsertPublishTarget(ctx, &pubTarget); err != nil { return err } } else { return err } return s.jobs.Queue(ctx, s.sb.RebuildSite(site, newSite)) } type NewSettings struct { SiteTitle string `form:"site_title"` SiteTheme string `form:"site_theme"` TargetURL string `form:"target_url"` TargetRef string `form:"target_ref"` } func (s *Service) Rebuild(ctx context.Context, site models.Site) error { if site.ID == 0 { return errors.New("site id required") } return s.jobs.Queue(ctx, s.sb.RebuildSite(site, site)) } func (s *Service) Themes() []models.ThemeMeta { return s.themes.Themes() } func normaliseName(name string) string { var sb strings.Builder seenDash := false for _, r := range strings.TrimSpace(name) { if unicode.IsLetter(r) || unicode.IsNumber(r) { sb.WriteRune(unicode.ToLower(r)) seenDash = false } else if r == '_' || r == '-' || r == '.' || unicode.IsSpace(r) { if !seenDash { sb.WriteRune('-') } seenDash = true } } return sb.String() }