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
This commit is contained in:
54
models/user_preference.go
Normal file
54
models/user_preference.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// UserPreference is one user's widget preference
|
||||
// (golem15_feedback_user_preferences, one row per user who ever changed
|
||||
// it). The hidden column is the signal, not the row: a row may hold
|
||||
// hidden=false after the user showed the widget again.
|
||||
type UserPreference struct {
|
||||
ID uint `gorm:"column:id;primaryKey"`
|
||||
UserID uint `gorm:"column:user_id"`
|
||||
Hidden bool `gorm:"column:hidden"`
|
||||
CreatedAt time.Time `gorm:"column:created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at"`
|
||||
}
|
||||
|
||||
// TableName is golem15_feedback_user_preferences.
|
||||
func (UserPreference) TableName() string { return "golem15_feedback_user_preferences" }
|
||||
|
||||
// IsWidgetHidden is UserPreference::isWidgetHidden: the user's hidden flag,
|
||||
// false without a row.
|
||||
func IsWidgetHidden(ctx context.Context, db *gorm.DB, userID uint) (bool, error) {
|
||||
var p UserPreference
|
||||
err := db.WithContext(ctx).Select("hidden").Where("user_id = ?", userID).Take(&p).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return p.Hidden, nil
|
||||
}
|
||||
|
||||
// SetWidgetHidden is UserPreference::setWidgetHidden (updateOrCreate on
|
||||
// user_id): one atomic upsert of the user's row.
|
||||
func SetWidgetHidden(ctx context.Context, db *gorm.DB, userID uint, hidden bool) error {
|
||||
now := time.Now()
|
||||
row := UserPreference{UserID: userID, Hidden: hidden, CreatedAt: now, UpdatedAt: now}
|
||||
return db.WithContext(ctx).Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "user_id"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"hidden", "updated_at"}),
|
||||
}).Create(&row).Error
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register(UserPreference{})
|
||||
}
|
||||
Reference in New Issue
Block a user