user settings
This commit is contained in:
parent
82c00b9a01
commit
3ce55bb870
@ -147,7 +147,7 @@ func (app *application) putUserSettings(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
form.CheckField(validator.PermittedValue(form.LocalTimezone, app.timezones...), "timezone", "Invalid value")
|
form.CheckField(validator.PermittedValue(form.LocalTimezone, app.timezones...), "timezone", "Invalid value")
|
||||||
if !form.Valid() {
|
if !form.Valid() {
|
||||||
// rerender template with errors
|
// TODO: rerender template with errors
|
||||||
app.clientError(w, http.StatusUnprocessableEntity)
|
app.clientError(w, http.StatusUnprocessableEntity)
|
||||||
}
|
}
|
||||||
err = app.users.SetLocalTimezone(userId, form.LocalTimezone)
|
err = app.users.SetLocalTimezone(userId, form.LocalTimezone)
|
||||||
|
@ -38,7 +38,7 @@ CREATE TABLE user_settings (
|
|||||||
Id integer primary key autoincrement,
|
Id integer primary key autoincrement,
|
||||||
UserId integer NOT NULL,
|
UserId integer NOT NULL,
|
||||||
SettingId integer NOT NULL,
|
SettingId integer NOT NULL,
|
||||||
AllowedSettingValueId integer NOT NULL,
|
AllowedSettingValueId integer,
|
||||||
UnconstrainedValue varchar(256),
|
UnconstrainedValue varchar(256),
|
||||||
FOREIGN KEY (UserId) REFERENCES users(Id)
|
FOREIGN KEY (UserId) REFERENCES users(Id)
|
||||||
ON DELETE RESTRICT
|
ON DELETE RESTRICT
|
||||||
@ -55,7 +55,7 @@ CREATE TABLE guestbook_settings (
|
|||||||
Id integer primary key autoincrement,
|
Id integer primary key autoincrement,
|
||||||
GuestbookId integer NOT NULL,
|
GuestbookId integer NOT NULL,
|
||||||
SettingId integer NOT NULL,
|
SettingId integer NOT NULL,
|
||||||
AllowedSettingValueId integer NOT NULL,
|
AllowedSettingValueId integer,
|
||||||
UnconstrainedValue varchar(256),
|
UnconstrainedValue varchar(256),
|
||||||
FOREIGN KEY (GuestbookId) REFERENCES guestbooks(Id)
|
FOREIGN KEY (GuestbookId) REFERENCES guestbooks(Id)
|
||||||
ON DELETE RESTRICT
|
ON DELETE RESTRICT
|
||||||
|
@ -8,4 +8,6 @@ var (
|
|||||||
ErrInvalidCredentials = errors.New("models: invalid credentials")
|
ErrInvalidCredentials = errors.New("models: invalid credentials")
|
||||||
|
|
||||||
ErrDuplicateEmail = errors.New("models: duplicate email")
|
ErrDuplicateEmail = errors.New("models: duplicate email")
|
||||||
|
|
||||||
|
ErrInvalidSettingValue = errors.New("models: invalid setting value")
|
||||||
)
|
)
|
||||||
|
202
internal/models/settings.go
Normal file
202
internal/models/settings.go
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
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
|
||||||
|
}
|
@ -54,13 +54,7 @@ func (m *UserModel) Insert(shortId uint64, username string, email string, passwo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
settingsStmt := `INSERT INTO user_settings
|
err = m.initializeUserSettings(id, settings)
|
||||||
(UserId, SettingId, AllowedSettingValueId, UnconstrainedValue)
|
|
||||||
VALUES (?, ?, ?, ?)`
|
|
||||||
_, err = m.DB.Exec(settingsStmt, id, u_timezone, nil, settings.LocalTimezone.String())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,9 +178,25 @@ func (m *UserModel) GetSettings(userId int64) (UserSettings, error) {
|
|||||||
return settings, err
|
return settings, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *UserModel) SetLocalTimezone(userId int64, timezone string) error {
|
func (m *UserModel) initializeUserSettings(userId int64, settings UserSettings) error {
|
||||||
stmt := `UPDATE user_settings SET UnconstrainedValue = ? WHERE UserId = ?`
|
stmt := `INSERT INTO user_settings (UserId, SettingId, AllowedSettingValueId, UnconstrainedValue) VALUES (?, ?, ?, ?)`
|
||||||
_, err := m.DB.Exec(stmt, timezone, userId)
|
_, err := m.DB.Exec(stmt, userId, u_timezone, nil, settings.LocalTimezone.String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UserModel) SetLocalTimezone(userId int64, timezone string) error {
|
||||||
|
valid, err := validateSetting(m.DB, u_timezone, timezone)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !valid {
|
||||||
|
return ErrInvalidSettingValue
|
||||||
|
}
|
||||||
|
stmt := `UPDATE user_settings SET UnconstrainedValue = ? WHERE UserId = ?`
|
||||||
|
_, err = m.DB.Exec(stmt, timezone, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user