feat: SEO change history
This commit is contained in:
91
models/revision.go
Normal file
91
models/revision.go
Normal file
@@ -0,0 +1,91 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// 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")
|
||||
}
|
||||
28
models/revision/columns.yaml
Normal file
28
models/revision/columns.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
# History list columns (UI-SPEC C12). via_label, change and batch are
|
||||
# filled by the controller's ListExtendRecords.
|
||||
columns:
|
||||
created_at:
|
||||
label: golem15.seo::lang.history.when
|
||||
type: datetime
|
||||
sortable: true
|
||||
author_label:
|
||||
label: golem15.seo::lang.history.who
|
||||
type: text
|
||||
searchable: true
|
||||
via_label:
|
||||
label: golem15.seo::lang.history.via
|
||||
type: text
|
||||
sortable: false
|
||||
what:
|
||||
label: golem15.seo::lang.history.what
|
||||
type: text
|
||||
searchable: true
|
||||
change:
|
||||
label: golem15.seo::lang.history.change
|
||||
type: text
|
||||
sortable: false
|
||||
batch:
|
||||
label: golem15.seo::lang.history.batch
|
||||
type: text
|
||||
sortable: false
|
||||
invisible: true
|
||||
28
models/revision/fields.yaml
Normal file
28
models/revision/fields.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
# History preview (UI-SPEC C12): read-only fields, then the P5 diff.
|
||||
fields:
|
||||
created_at:
|
||||
label: golem15.seo::lang.history.when
|
||||
type: text
|
||||
span: left
|
||||
context: preview
|
||||
author_label:
|
||||
label: golem15.seo::lang.history.who
|
||||
type: text
|
||||
span: right
|
||||
context: preview
|
||||
via:
|
||||
label: golem15.seo::lang.history.via
|
||||
type: text
|
||||
span: left
|
||||
context: preview
|
||||
what:
|
||||
label: golem15.seo::lang.history.what
|
||||
type: text
|
||||
span: right
|
||||
context: preview
|
||||
_history_diff:
|
||||
label: golem15.seo::lang.history.change
|
||||
type: partial
|
||||
path: history_diff
|
||||
span: full
|
||||
context: preview
|
||||
Reference in New Issue
Block a user