87 lines
2.8 KiB
Go
87 lines
2.8 KiB
Go
package seo
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.golem15.com/golem15/sm-seo-plugin/classes"
|
|
"git.golem15.com/golem15/summercms/modules/bonfire"
|
|
"git.golem15.com/golem15/summercms/modules/lagoon"
|
|
"git.golem15.com/golem15/summercms/modules/pact"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// Commands registers seo:generate-entries.
|
|
func (p *Plugin) Commands() []bonfire.Command {
|
|
return []bonfire.Command{{
|
|
Name: "seo:generate-entries",
|
|
Description: "Queue the job that creates missing SEO entries",
|
|
Long: `Queues the entry generation job on the background queue. The job walks the
|
|
published records of every content type registered in signpost (or of the
|
|
one named by --type), creates the missing SEO entry of each locale with its
|
|
current address and refreshes the address and the effective title and
|
|
description of existing entries. Values set in the SEO tab are never
|
|
changed. A worker (summer serve or queue:work) runs the job.`,
|
|
Flags: []bonfire.Flag{
|
|
{Name: "type", Description: "Content type key (signpost menu item type) to limit the run to"},
|
|
},
|
|
Examples: []bonfire.Example{
|
|
{Command: "seo:generate-entries", Description: "Queue generation for every content type"},
|
|
{Command: "seo:generate-entries --type journal-post", Description: "Queue generation for one content type"},
|
|
},
|
|
Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error {
|
|
typeKey, _ := in.Flag("type")
|
|
typeKey = strings.TrimSpace(typeKey)
|
|
svc := p.Service()
|
|
if svc == nil {
|
|
return classes.ErrNotBooted
|
|
}
|
|
if typeKey != "" {
|
|
if reg := svc.Registry(); reg != nil {
|
|
if _, ok := reg.ContentType(typeKey); !ok {
|
|
return fmt.Errorf("Content type %q is not registered", typeKey)
|
|
}
|
|
}
|
|
}
|
|
db, done, err := p.commandDB(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer done()
|
|
id, err := svc.EnqueueGenerate(ctx, db, typeKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
out.Success(fmt.Sprintf("Queued SEO entry generation (job #%d).", id))
|
|
return nil
|
|
},
|
|
}}
|
|
}
|
|
|
|
// commandDB returns the app database, opening database.dsn when the binary
|
|
// published none for console commands. done closes a pool it opened.
|
|
func (p *Plugin) commandDB(ctx context.Context) (*gorm.DB, func(), error) {
|
|
app := p.app
|
|
if app == nil {
|
|
return nil, nil, classes.ErrNotBooted
|
|
}
|
|
if db, ok := app.Lookup[*gorm.DB](); ok && db != nil {
|
|
return db, func() {}, nil
|
|
}
|
|
if lagoon.DSN(app.Config) == "" {
|
|
return nil, nil, fmt.Errorf("golem15.seo: database is not configured (set SUMMER_DATABASE__DSN)")
|
|
}
|
|
sqlDB, gdb, err := lagoon.OpenFromApp(ctx, app)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := lagoon.Publish(app, sqlDB, gdb); err != nil {
|
|
_ = sqlDB.Close()
|
|
return nil, nil, err
|
|
}
|
|
return gdb, func() { _ = sqlDB.Close() }, nil
|
|
}
|
|
|
|
var _ pact.HasCommands = (*Plugin)(nil)
|