diff --git a/cmd/web/main.go b/cmd/web/main.go index 3d7fb96..7b678b6 100644 --- a/cmd/web/main.go +++ b/cmd/web/main.go @@ -59,13 +59,19 @@ func main() { sessionManager: sessionManager, websites: &models.WebsiteModel{DB: db}, guestbooks: &models.GuestbookModel{DB: db}, - users: &models.UserModel{DB: db}, + users: &models.UserModel{DB: db, Settings: make(map[string]models.Setting)}, guestbookComments: &models.GuestbookCommentModel{DB: db}, formDecoder: formDecoder, debug: *debug, timezones: getAvailableTimezones(), } + err = app.users.InitializeSettingsMap() + if err != nil { + logger.Error(err.Error()) + os.Exit(1) + } + tlsConfig := &tls.Config{ CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256}, } diff --git a/internal/models/guestbook.go b/internal/models/guestbook.go index 21d899e..c072c3b 100644 --- a/internal/models/guestbook.go +++ b/internal/models/guestbook.go @@ -5,6 +5,14 @@ import ( "time" ) +type GuestbookSettings struct { + IsCommentingEnabled bool + ReenableCommenting time.Time + IsVisible bool + FilteredWords []string + AllowRemoteHostAccess bool +} + type Guestbook struct { ID int64 ShortId uint64 @@ -13,6 +21,7 @@ type Guestbook struct { Created time.Time Deleted time.Time IsActive bool + Settings GuestbookSettings } type GuestbookModel struct { @@ -70,3 +79,47 @@ func (m *GuestbookModel) GetAll(userId int64) ([]Guestbook, error) { } return guestbooks, nil } + +func (m *GuestbookModel) initializeGuestbookSettings(guestbookId int64, settings UserSettings) error { + stmt := `INSERT INTO guestbook_settings (GuestbookId, SettingId, AllowedSettingValueId, UnconstrainedValue) VALUES + (?, ?, ?, ?), + (?, ?, ?, ?), + (?, ?, ?, ?), + (?, ?, ?, ?), + (?, ?, ?, ?)` + _ = len(stmt) + return nil +} + +func (m *GuestbookModel) UpdateSetting(guestbookId int64, value string) { + stmt := `UPDATE guestbook_settings SET + AllowedSettingValueId=IFNULL((SELECT Id FROM allowed_setting_values WHERE SettingId = guestbook_settings.SettingId AND ItemValue = ?), AllowedSettingValueId), + UnconstrainedValue=(SELECT ? FROM settings WHERE settings.Id = guestbook_settings.SettingId AND settings.Constrained=0) + WHERE GuestbookId = ? + AND SettingId = (SELECT Id from Settings WHERE Description=?);` + _ = len(stmt) +} + +func (m *GuestbookModel) SetCommentingEnabled(guestbookId int64, enabled bool) error { + return nil +} + +func (m *GuestbookModel) SetReenableCommentingDate(guestbookId int64, reenableTime time.Time) error { + return nil +} + +func (m *GuestbookModel) SetVisible(guestbookId int64, visible bool) error { + return nil +} + +func (m *GuestbookModel) AddFilteredWord(guestbookId int64, word string) error { + return nil +} + +func (m *GuestbookModel) RemoveFilteredWord(guestbookId int64, word string) error { + return nil +} + +func (m *GuestbookModel) SetRemoteHostAccess(guestbookId int64, allowed bool) error { + return nil +} diff --git a/internal/models/settings.go b/internal/models/settings.go index 4e976c3..3666e58 100644 --- a/internal/models/settings.go +++ b/internal/models/settings.go @@ -7,6 +7,13 @@ import ( "time" ) +type SettingModel struct { + DB *sql.DB +} + +type SettingConfig struct { +} + type SettingGroup int const ( @@ -48,14 +55,16 @@ func (s *AllowedSettingValue) Caption() string { } 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 + id int + description string + constrained bool + dataType SettingDataType + dataTypeDesc string + settingGroup SettingGroup + settingGroupDesc string + minValue string // TODO: Maybe should be int? + maxValue string + allowedValues map[int]AllowedSettingValue } func (s *Setting) Id() int { @@ -173,6 +182,18 @@ func (s *Setting) validateAlphanum(value string) bool { return true } +func (s Setting) Validate(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 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 = ? diff --git a/internal/models/user.go b/internal/models/user.go index 5dbad1e..5925441 100644 --- a/internal/models/user.go +++ b/internal/models/user.go @@ -10,14 +10,14 @@ import ( "golang.org/x/crypto/bcrypt" ) -const ( - u_timezone = 1 -) - type UserSettings struct { LocalTimezone *time.Location } +const ( + USER_TIMEZONE = "local_timezone" +) + type User struct { ID int64 ShortId uint64 @@ -35,6 +35,38 @@ type UserModel struct { Settings map[string]Setting } +func (m *UserModel) InitializeSettingsMap() error { + if m.Settings == nil { + m.Settings = make(map[string]Setting) + } + stmt := `SELECT settings.Id, settings.Description, Constrained, d.Id, d.Description, g.Id, g.Description, MinValue, MaxValue + FROM settings + LEFT JOIN setting_data_types d ON settings.DataType = d.Id + LEFT JOIN setting_groups g ON settings.SettingGroup = g.Id + WHERE SettingGroup = (SELECT Id FROM setting_groups WHERE Description = 'user' LIMIT 1)` + result, err := m.DB.Query(stmt) + if err != nil { + return err + } + for result.Next() { + var s Setting + var mn sql.NullString + var mx sql.NullString + err := result.Scan(&s.id, &s.description, &s.constrained, &s.dataType, &s.dataTypeDesc, &s.settingGroup, &s.settingGroupDesc, &mn, &mx) + if mn.Valid { + s.minValue = mn.String + } + if mx.Valid { + s.maxValue = mx.String + } + if err != nil { + return err + } + m.Settings[s.description] = s + } + return nil +} + func (m *UserModel) Insert(shortId uint64, username string, email string, password string, settings UserSettings) error { hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 12) if err != nil { @@ -169,7 +201,7 @@ func (m *UserModel) GetSettings(userId int64) (UserSettings, error) { return settings, err } switch id { - case u_timezone: + case m.Settings[USER_TIMEZONE].id: settings.LocalTimezone, err = time.LoadLocation(unconstrainedValue.String) if err != nil { panic(err) @@ -180,8 +212,9 @@ func (m *UserModel) GetSettings(userId int64) (UserSettings, error) { } func (m *UserModel) initializeUserSettings(userId int64, settings UserSettings) error { - stmt := `INSERT INTO user_settings (UserId, SettingId, AllowedSettingValueId, UnconstrainedValue) VALUES (?, ?, ?, ?)` - _, err := m.DB.Exec(stmt, userId, u_timezone, nil, settings.LocalTimezone.String()) + stmt := `INSERT INTO user_settings (UserId, SettingId, AllowedSettingValueId, UnconstrainedValue) + VALUES (?, ?, ?, ?)` + _, err := m.DB.Exec(stmt, userId, m.Settings[USER_TIMEZONE].id, nil, settings.LocalTimezone.String()) if err != nil { return err } @@ -189,7 +222,7 @@ func (m *UserModel) initializeUserSettings(userId int64, settings UserSettings) } func (m *UserModel) UpdateUserSettings(userId int64, settings UserSettings) error { - err := m.UpdateSetting(userId, m.Settings["local_timezone"], settings.LocalTimezone.String()) + err := m.UpdateSetting(userId, m.Settings[USER_TIMEZONE], settings.LocalTimezone.String()) if err != nil { return err } @@ -198,11 +231,13 @@ func (m *UserModel) UpdateUserSettings(userId int64, settings UserSettings) erro func (m *UserModel) UpdateSetting(userId int64, setting Setting, value string) error { stmt := `UPDATE user_settings SET - AllowedSettingValueId=(SELECT Id FROM allowed_setting_values WHERE SettingId = user_settings.SettingId AND ItemValue = ?), + AllowedSettingValueId=IFNULL( + (SELECT Id FROM allowed_setting_values WHERE SettingId = user_settings.SettingId AND ItemValue = ?), AllowedSettingValueId + ), UnconstrainedValue=(SELECT ? FROM settings WHERE settings.Id = user_settings.SettingId AND settings.Constrained=0) WHERE userId = ? AND SettingId = (SELECT Id from Settings WHERE Description=?);` - result, err := m.DB.Exec(stmt, value, value, userId) + result, err := m.DB.Exec(stmt, value, value, userId, setting.description) if err != nil { return err } @@ -211,21 +246,18 @@ func (m *UserModel) UpdateSetting(userId int64, setting Setting, value string) e return err } if rows != 1 { - return err + return ErrInvalidSettingValue } return nil } func (m *UserModel) SetLocalTimezone(userId int64, timezone string) error { - valid, err := validateSetting(m.DB, u_timezone, timezone) - if err != nil { - return err - } + setting := m.Settings[USER_TIMEZONE] + valid := setting.Validate(timezone) if !valid { return ErrInvalidSettingValue } - stmt := `UPDATE user_settings SET UnconstrainedValue = ? WHERE UserId = ?` - _, err = m.DB.Exec(stmt, timezone, userId) + err := m.UpdateSetting(userId, setting, timezone) if err != nil { return err } diff --git a/ui/views/common_templ.go b/ui/views/common_templ.go index 895a1cd..f707c81 100644 --- a/ui/views/common_templ.go +++ b/ui/views/common_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.857 +// templ: version: v0.3.833 package views //lint:file-ignore SA4006 This context is only used if a nested component is present. diff --git a/ui/views/guestbooks_templ.go b/ui/views/guestbooks_templ.go index 21732fa..c5242f4 100644 --- a/ui/views/guestbooks_templ.go +++ b/ui/views/guestbooks_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.857 +// templ: version: v0.3.833 package views //lint:file-ignore SA4006 This context is only used if a nested component is present. diff --git a/ui/views/home_templ.go b/ui/views/home_templ.go index 4829e83..23a3c6d 100644 --- a/ui/views/home_templ.go +++ b/ui/views/home_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.857 +// templ: version: v0.3.833 package views //lint:file-ignore SA4006 This context is only used if a nested component is present. diff --git a/ui/views/users_settings_templ.go b/ui/views/users_settings_templ.go index 5660866..1528730 100644 --- a/ui/views/users_settings_templ.go +++ b/ui/views/users_settings_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.857 +// templ: version: v0.3.833 package views //lint:file-ignore SA4006 This context is only used if a nested component is present. diff --git a/ui/views/users_templ.go b/ui/views/users_templ.go index 81e1a2d..5b51716 100644 --- a/ui/views/users_templ.go +++ b/ui/views/users_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.857 +// templ: version: v0.3.833 package views //lint:file-ignore SA4006 This context is only used if a nested component is present. diff --git a/ui/views/websites_templ.go b/ui/views/websites_templ.go index c29b127..0e47209 100644 --- a/ui/views/websites_templ.go +++ b/ui/views/websites_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.857 +// templ: version: v0.3.833 package views //lint:file-ignore SA4006 This context is only used if a nested component is present.