guestbook/internal/models/settings.go
2025-05-09 20:24:53 -07:00

203 lines
3.9 KiB
Go

package models
import (
"database/sql"
"maps"
"strconv"
"time"
)
type SettingGroup int
const (
SettingGroupUser SettingGroup = 1
SettingGroupGuestbook SettingGroup = 2
)
type SettingDataType int
const (
SettingTypeInt SettingDataType = 1
SettingTypeDate SettingDataType = 2
SettingTypeAlphanum SettingDataType = 3
)
type SettingValue struct {
Id int
SettingId int
AllowedSettingId int
UnconstrainedValue string
}
type AllowedSettingValue struct {
id int
itemValue string
caption string
}
func (s *AllowedSettingValue) Id() int {
return s.id
}
func (s *AllowedSettingValue) ItemValue() string {
return s.itemValue
}
func (s *AllowedSettingValue) Caption() string {
return s.caption
}
type Setting struct {
id int
description string
constrained bool
dataType SettingDataType
settingGroup SettingGroup
minValue string // TODO: Maybe should be int?
maxValue string
allowedValues map[int]AllowedSettingValue
}
func (s *Setting) Id() int {
return s.id
}
func (s *Setting) Description() string {
return s.description
}
func (s *Setting) Constrained() bool {
return s.constrained
}
func (s *Setting) DataType() SettingDataType {
return s.dataType
}
func (s *Setting) SettingGroup() SettingGroup {
return s.settingGroup
}
func (s *Setting) MinValue() string {
return s.minValue
}
func (s *Setting) MaxValue() string {
return s.maxValue
}
func (s *Setting) AllowedValues() map[int]AllowedSettingValue {
result := make(map[int]AllowedSettingValue, 50)
maps.Copy(result, s.allowedValues)
return result
}
func (s *Setting) ValidateUnconstrained(value string) bool {
switch s.dataType {
case SettingTypeInt:
return s.validateInt(value)
case SettingTypeAlphanum:
return s.validateAlphanum(value)
case SettingTypeDate:
return s.validateDatetime(value)
}
return false
}
func (s *Setting) ValidateConstrained(value *AllowedSettingValue) bool {
_, exists := s.allowedValues[value.id]
if s.constrained && exists {
return true
}
return false
}
func (s *Setting) validateInt(value string) bool {
v, err := strconv.ParseInt(value, 10, 0)
if err != nil {
return false
}
var min int64
var max int64
if len(s.minValue) > 0 {
min, err = strconv.ParseInt(s.minValue, 10, 0)
if err != nil {
return false
}
if v < min {
return false
}
}
if len(s.maxValue) > 0 {
max, err = strconv.ParseInt(s.maxValue, 10, 0)
if err != nil {
return false
}
if v < max {
return false
}
}
return true
}
func (s *Setting) validateDatetime(value string) bool {
v, err := time.Parse(time.DateTime, value)
if err != nil {
return false
}
var min time.Time
var max time.Time
if len(s.minValue) > 0 {
min, err = time.Parse(time.DateTime, s.minValue)
if err != nil {
return false
}
if v.Before(min) {
return false
}
}
if len(s.maxValue) > 0 {
max, err = time.Parse(time.DateTime, s.maxValue)
if err != nil {
return false
}
if v.After(max) {
return false
}
}
return false
}
func (s *Setting) validateAlphanum(value string) bool {
return true
}
func validateSetting(db *sql.DB, settingId int, value string) (bool, error) {
stmt := `SELECT s.Id, Description, Constrained, DataType, SettingGroup, MinValue, MaxValue, a.Id
FROM settings AS s LEFT JOIN allowed_setting_values AS a ON s.Id = a.SettingId AND a.ItemValue = ?
WHERE s.Id = ?`
result := db.QueryRow(stmt, value, settingId)
var s Setting
var minval sql.NullString
var maxval sql.NullString
var allowedId sql.NullInt64
err := result.Scan(&s.id, &s.description, &s.constrained, &s.dataType, &s.settingGroup, &minval, &maxval, &allowedId)
if err != nil {
return false, err
}
if s.constrained && allowedId.Valid {
return true, nil
}
switch s.dataType {
case SettingTypeInt:
return s.validateInt(value), nil
case SettingTypeAlphanum:
return s.validateAlphanum(value), nil
case SettingTypeDate:
return s.validateDatetime(value), nil
}
return false, nil
}