feat: keep the materials index in sync and add bm:materials-reindex
- the materials admin syncs after create and update and removes after delete, once the save transaction commits (UseMaterialIndex, set at Boot) - POST and PUT /api/v1/bm/materials sync after the transaction, DELETE removes the document (its statement has no primary key, so no callback) - bm:materials-reindex [--fresh] [--if-configured] ensures the index and syncs every material; it refuses without an engine and runs nightly at 04:15 with --if-configured - TestMaterialSearchAgainstDatabase (Postgres) is written for the final verification phase
This commit is contained in:
46
plugin.go
46
plugin.go
@@ -3,6 +3,7 @@ package bm
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"errors"
|
||||
"io/fs"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||
@@ -32,6 +33,7 @@ var (
|
||||
_ pact.HasPermissions = (*Plugin)(nil)
|
||||
_ pact.HasNavigation = (*Plugin)(nil)
|
||||
_ pact.HasMiddleware = (*Plugin)(nil)
|
||||
_ pact.HasSchedule = (*Plugin)(nil)
|
||||
)
|
||||
|
||||
//go:embed config
|
||||
@@ -111,17 +113,29 @@ func (p *Plugin) AdminControllers() []pact.AdminController {
|
||||
return generatedAdminControllers()
|
||||
}
|
||||
|
||||
// Commands returns the generated commands, bm:seed, bm:chat-sync and
|
||||
// websockets:health. API tokens are managed application-wide by
|
||||
// golem15.user.
|
||||
// Commands returns the generated commands, bm:seed, bm:chat-sync,
|
||||
// bm:materials-reindex and websockets:health. API tokens are managed
|
||||
// application-wide by golem15.user.
|
||||
func (p *Plugin) Commands() []bonfire.Command {
|
||||
cmds := append(generatedCommands(), console.SeedCommand(p.withDB))
|
||||
cmds = append(cmds, console.ChatSyncCommand(p.withDB, func() (string, string) {
|
||||
return p.chatGroup(), p.chatModeratorGroup()
|
||||
}))
|
||||
cmds = append(cmds, console.MaterialsReindexCommand(console.MaterialsReindexDeps{DB: p.publishedDB, Index: p.materialIndex}))
|
||||
return append(cmds, centrifugo.Commands(p.app)...)
|
||||
}
|
||||
|
||||
// Schedule runs bm:materials-reindex every night (it exits 0 when search
|
||||
// is not configured). The index drifts without it: a course rename or a
|
||||
// meeting renumbering changes documents no material write syncs, a failed
|
||||
// sync is only logged, and a Typesense restart can lose data (RESEARCH
|
||||
// Pitfall 6).
|
||||
func (p *Plugin) Schedule() []pact.ScheduledCommand {
|
||||
return []pact.ScheduledCommand{
|
||||
{Command: console.MaterialsReindexName, Args: []string{"--if-configured"}, Cadence: pact.DailyAt(4, 15)},
|
||||
}
|
||||
}
|
||||
|
||||
// AdminFS is the admin YAML the controllers read.
|
||||
func (p *Plugin) AdminFS() fs.FS { return adminFS }
|
||||
|
||||
@@ -172,6 +186,32 @@ func (p *Plugin) withDB(ctx context.Context, fn func(*gorm.DB) error) error {
|
||||
return fn(gdb)
|
||||
}
|
||||
|
||||
// publishedDB returns the application's database published on the app: the
|
||||
// one serve published or, when a console command runs, one opened from the
|
||||
// config and published, because beachcomber syncs nothing without a
|
||||
// published database. done closes a pool this call opened and is a no-op
|
||||
// otherwise.
|
||||
func (p *Plugin) publishedDB(ctx context.Context) (*gorm.DB, func(), error) {
|
||||
if p.app == nil {
|
||||
return nil, nil, errors.New("jz.bm: app is nil")
|
||||
}
|
||||
if gdb, ok := p.app.Lookup[*gorm.DB](); ok && gdb != nil {
|
||||
return gdb, func() {}, nil
|
||||
}
|
||||
if lagoon.DSN(p.app.Config) == "" {
|
||||
return nil, nil, errors.New("jz.bm: database is not configured (set SUMMER_DATABASE__DSN)")
|
||||
}
|
||||
sqlDB, gdb, err := lagoon.OpenFromApp(ctx, p.app)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := lagoon.Publish(p.app, sqlDB, gdb); err != nil {
|
||||
_ = sqlDB.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
return gdb, func() { _ = sqlDB.Close() }, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
party.Register(&Plugin{})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user