feat(19.3-04): purge the host site's page cache after FAQ saves and deletes

- FormAfterCreate/FormAfterUpdate run the locale check, then register a
  purge of kind faq through cooler.PurgeSiteCacheAfterCommit
- new FormAfterDelete purges after the delete commits
- purgeSiteCache helper takes the save transaction from cabana.TxFromContext
  and the purger from cooler.SiteCacheFromApp (site_cache.* keys)
- TestFaqAdminPurgesSiteCache on Postgres
This commit is contained in:
Jakub Zych
2026-10-15 18:22:40 +02:00
parent 919cf06eca
commit c60ae6e5d1
4 changed files with 278 additions and 8 deletions

View File

@@ -49,16 +49,39 @@ func (faqsAdminController) AdminFieldRelations() []cabana.FieldRelationContract
// errLocaleRequired is the field message of a FAQ saved without a locale.
const errLocaleRequired = "golem15.faq::lang.errors.locale_required"
// siteCacheKind is the kind a FAQ save's site-cache purge carries.
const siteCacheKind = "faq"
// FormAfterCreate refuses a FAQ without a locale. cabana writes locale_id
// from the relation field after the model rules ran, so the check runs here,
// inside the save's transaction: the refusal rolls the row back.
func (faqsAdminController) FormAfterCreate(_ context.Context, model any) error {
return requireLocale(model)
// inside the save's transaction: the refusal rolls the row back. A FAQ that
// passes purges the host site's page caches once the save commits.
func (c faqsAdminController) FormAfterCreate(ctx context.Context, model any) error {
return c.afterSave(ctx, model)
}
// FormAfterUpdate applies the same check to an update.
func (faqsAdminController) FormAfterUpdate(_ context.Context, model any) error {
return requireLocale(model)
// FormAfterUpdate applies the same check and purge to an update.
func (c faqsAdminController) FormAfterUpdate(ctx context.Context, model any) error {
return c.afterSave(ctx, model)
}
// FormAfterDelete purges the host site's page caches once the delete
// commits.
func (c faqsAdminController) FormAfterDelete(ctx context.Context, model any) error {
if faq, ok := model.(*models.FAQ); ok && faq != nil {
purgeSiteCache(ctx, c.app, siteCacheKind, faq.Slug)
}
return nil
}
func (c faqsAdminController) afterSave(ctx context.Context, model any) error {
if err := requireLocale(model); err != nil {
return err
}
if faq, ok := model.(*models.FAQ); ok && faq != nil {
purgeSiteCache(ctx, c.app, siteCacheKind, faq.Slug)
}
return nil
}
func requireLocale(model any) error {
@@ -72,6 +95,7 @@ func requireLocale(model any) error {
var (
_ pact.FormAfterCreate = faqsAdminController{}
_ pact.FormAfterUpdate = faqsAdminController{}
_ pact.FormAfterDelete = faqsAdminController{}
_ pact.AdminController = faqsAdminController{}
_ pact.AdminPermissioned = faqsAdminController{}
_ pact.AdminRecordSource = faqsAdminController{}

32
controllers/site_cache.go Normal file
View File

@@ -0,0 +1,32 @@
package controllers
import (
"context"
"git.golem15.com/golem15/summercms/modules/backpack"
"git.golem15.com/golem15/summercms/modules/cabana"
"git.golem15.com/golem15/summercms/modules/cooler"
)
// purgeSiteCache registers one site-cache purge of kind and slug, sent by
// the framework's purger (site_cache.purge_url and purge_token) after the
// save transaction of ctx commits. Without a purge configured, or outside a
// save transaction, it does nothing. A purge never fails the save.
func purgeSiteCache(ctx context.Context, app func() *backpack.App, kind, slug string) {
if app == nil {
return
}
a := app()
if a == nil {
return
}
tx, ok := cabana.TxFromContext(ctx)
if !ok {
return
}
purger := cooler.SiteCacheFromApp(a)
if purger == nil {
return
}
cooler.PurgeSiteCacheAfterCommit(ctx, tx, purger, kind, slug)
}