Files
sm-seo-plugin/models/revision.go
Jakub Zych 9e802ec850 feat: page registry with its admin screen and signpost type
- golem15_seo_pages (migration 202610280002): the site's own frontend pages
  with an address and a name per locale, kind, origin, parent, content date
  and note; settings routes_reported_at
- SEO > Pages (golem15.seo.pages) after URL rules: list with kind, origin
  and missing filters and the missing row state, form with the P9 partial;
  the plugin's form extension saves the address and name per locale and
  refuses url_required, url_invalid, url_taken and url_owned
- menu item type seo-page with a content descriptor, so each page gets
  the SEO tab, resolves ok and is listed in the sitemaps grouped by kind
  (pages, offers, services, landing-pages, titled per locale)
- management API GET/POST /_seo/api/v1/pages, PUT/DELETE /pages/{id} and
  the MCP tools seo_list_pages, seo_create_page, seo_update_page,
  seo_delete_page (in this commit because the operations parity test maps
  every Pages operation to its tool)
2026-11-04 13:20:45 +01:00

94 lines
3.0 KiB
Go

package models
import (
"time"
"gorm.io/gorm"
)
// The writers of a history entry (D-13).
const (
ViaAdmin = "admin"
ViaMCP = "mcp"
ViaImport = "import"
ViaAuto = "auto"
ViaUndo = "undo"
)
// The subjects of a history entry.
const (
SubjectEntry = "entry"
SubjectRule = "rule"
SubjectRedirect = "redirect"
SubjectRobots = "robots"
SubjectSettings = "settings"
SubjectNotFound = "notfound"
// SubjectPage is a page of the page registry (D-33).
SubjectPage = "page"
)
// Revision is one recorded SEO change on golem15_seo_revisions (D-13): who
// made it (AuthorID and AuthorLabel, the label kept when the administrator
// is gone), through what (Via), on which object (SubjectKind and
// SubjectID: an entry as "<model type>|<record id>|<locale>", a rule by
// id, settings as "1" or "type:<key>"), a readable description (What) and
// the changed fields only, before and after. A created object has no
// Before and a deleted one no After. BatchID groups the changes of one
// batch; UndoneAt marks an undone change.
type Revision struct {
ID uint `gorm:"column:id;primaryKey"`
BatchID *string `gorm:"column:batch_id"`
AuthorID *uint `gorm:"column:author_id"`
AuthorLabel string `gorm:"column:author_label"`
Via string `gorm:"column:via"`
SubjectKind string `gorm:"column:subject_kind"`
SubjectID string `gorm:"column:subject_id"`
What string `gorm:"column:what"`
Before JSONMap `gorm:"column:before"`
After JSONMap `gorm:"column:after"`
UndoneAt *time.Time `gorm:"column:undone_at"`
UndoneByID *uint `gorm:"column:undone_by_id"`
CreatedAt time.Time `gorm:"column:created_at"`
// Change is the list's summary of the changed fields and ViaLabel the
// via column's label, filled by the history controller.
Change string `gorm:"-:all;column:change"`
ViaLabel string `gorm:"-:all;column:via_label"`
Batch string `gorm:"-:all;column:batch"`
}
func (Revision) TableName() string { return "golem15_seo_revisions" }
// Fillable is empty: history is written by the service only.
func (Revision) Fillable() []string { return []string{} }
// Rules is empty: history is never edited.
func (Revision) Rules() map[string]string { return map[string]string{} }
// FilterVia is the history list's via filter scope.
const FilterVia = "FilterVia"
// Vias lists the writers in display order.
var Vias = []string{ViaAdmin, ViaMCP, ViaImport, ViaAuto, ViaUndo}
func init() {
Register(Revision{})
}
// FilterScopes lists the history list's filter scopes.
func (Revision) FilterScopes() []string { return []string{FilterVia} }
// FilterScope narrows the history list to one writer; an unknown value
// matches nothing.
func (Revision) FilterScope(name string, db *gorm.DB, value any) *gorm.DB {
if db == nil || name != FilterVia {
return db
}
s, _ := value.(string)
for _, v := range Vias {
if v == s {
return db.Where("golem15_seo_revisions.via = ?", s)
}
}
return db.Where("1 = 0")
}