Files
sm-feedback-plugin/updates/01_feedback.go
Jakub Zych b4b4135ad3 feat: golem15.feedback plugin with the widget config route
- plugin golem15.feedback (requires golem15.user), its config, lang (en, pl), models and migrations
- typed settings singleton golem15_feedback_settings with the WinterCMS defaults and a widget key generated on first creation
- GET /_feedback/api/v1/{key}/config behind the constant-time key check and the fail-closed Origin allow-list, with the feedback-config and feedback-submit buckets
2026-10-04 00:01:22 +02:00

96 lines
2.9 KiB
Go

package updates
import (
"github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm"
)
// The WinterCMS plugin's three migrations (create_feedback_submissions_table,
// add_type_and_locale_labels, create_user_preferences_table) give the two
// tables below; the type column is folded into the create. String columns
// are TEXT, as in every Go port (PHP's 255-character user_agent column
// would refuse the 500 characters its own validation allows on Postgres).
var submissionsMigration = &gormigrate.Migration{
ID: "202610030201_create_feedback_submissions",
Migrate: func(tx *gorm.DB) error {
for _, stmt := range []string{
`CREATE TABLE golem15_feedback_submissions (
id SERIAL PRIMARY KEY,
message TEXT NOT NULL,
type TEXT NOT NULL DEFAULT 'bug',
email TEXT,
page_url TEXT NOT NULL,
user_agent TEXT,
console_log TEXT,
status TEXT NOT NULL DEFAULT 'pending',
g15office_task_id TEXT,
g15office_error TEXT,
created_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ
)`,
`CREATE INDEX golem15_feedback_submissions_status_index ON golem15_feedback_submissions (status)`,
} {
if err := tx.Exec(stmt).Error; err != nil {
return err
}
}
return nil
},
Rollback: func(tx *gorm.DB) error {
return tx.Exec(`DROP TABLE IF EXISTS golem15_feedback_submissions`).Error
},
}
var userPreferencesMigration = &gormigrate.Migration{
ID: "202610030202_create_feedback_user_preferences",
Migrate: func(tx *gorm.DB) error {
return tx.Exec(`CREATE TABLE golem15_feedback_user_preferences (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
hidden BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ,
CONSTRAINT golem15_feedback_user_preferences_user_id_unique UNIQUE (user_id)
)`).Error
},
Rollback: func(tx *gorm.DB) error {
return tx.Exec(`DROP TABLE IF EXISTS golem15_feedback_user_preferences`).Error
},
}
// settingsMigration creates the typed settings singleton (D-18): the
// WinterCMS plugin kept these values in its system_settings row
// golem15_feedback_settings, which feedback:import-settings copies once.
var settingsMigration = &gormigrate.Migration{
ID: "202610030203_create_feedback_settings",
Migrate: func(tx *gorm.DB) error {
return tx.Exec(`CREATE TABLE golem15_feedback_settings (
id INTEGER PRIMARY KEY CHECK (id = 1),
enabled BOOLEAN NOT NULL DEFAULT TRUE,
widget_key TEXT NOT NULL,
allow_hide BOOLEAN NOT NULL DEFAULT FALSE,
position TEXT,
allowed_origins TEXT,
color_primary TEXT,
color_accent TEXT,
label_title_pl TEXT,
label_title_en TEXT,
label_placeholder_pl TEXT,
label_placeholder_en TEXT,
label_success_pl TEXT,
label_success_en TEXT,
g15office_task_status TEXT,
g15office_task_priority TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)`).Error
},
Rollback: func(tx *gorm.DB) error {
return tx.Exec(`DROP TABLE IF EXISTS golem15_feedback_settings`).Error
},
}
func init() {
Register(submissionsMigration, userPreferencesMigration, settingsMigration)
}