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{}) }