feat(go): add support for user settings;

This commit is contained in:
Vishal Dalwadi 2025-07-21 12:14:09 +05:30
parent a6469c7e2a
commit eb40471a6f
4 changed files with 90 additions and 12 deletions

View file

@ -47,6 +47,8 @@ func userHandlers(r *mux.Router) {
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet)
r.HandleFunc("/api/users/{username}/enable", logic.SecurityCheck(true, http.HandlerFunc(enableUserAccount))).Methods(http.MethodPost)
r.HandleFunc("/api/users/{username}/disable", logic.SecurityCheck(true, http.HandlerFunc(disableUserAccount))).Methods(http.MethodPost)
r.HandleFunc("/api/users/{username}/settings", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserSettings)))).Methods(http.MethodGet)
r.HandleFunc("/api/users/{username}/settings", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(updateUserSettings)))).Methods(http.MethodPut)
r.HandleFunc("/api/v1/users", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserV1)))).Methods(http.MethodGet)
r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet)
r.HandleFunc("/api/v1/users/roles", logic.SecurityCheck(true, http.HandlerFunc(ListRoles))).Methods(http.MethodGet)
@ -731,6 +733,46 @@ func disableUserAccount(w http.ResponseWriter, r *http.Request) {
logic.ReturnSuccessResponse(w, r, "user account disabled")
}
// @Summary Get a user's preferences and settings
// @Router /api/users/{username}/settings [get]
// @Tags Users
// @Param username path string true "Username of the user"
// @Success 200 {object} models.SuccessResponse
func getUserSettings(w http.ResponseWriter, r *http.Request) {
userID := r.Header.Get("user")
userSettings := logic.GetUserSettings(userID)
logic.ReturnSuccessResponseWithJson(w, r, userSettings, "fetched user settings")
}
// @Summary Update a user's preferences and settings
// @Router /api/users/{username}/settings [put]
// @Tags Users
// @Param username path string true "Username of the user"
// @Success 200 {object} models.SuccessResponse
// @Failure 400 {object} models.ErrorResponse
// @Failure 500 {object} models.ErrorResponse
func updateUserSettings(w http.ResponseWriter, r *http.Request) {
userID := r.Header.Get("user")
var req models.UserSettings
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
logger.Log(0, "failed to decode request body: ", err.Error())
err = fmt.Errorf("invalid request body: %v", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
err = logic.UpsertUserSettings(userID, req)
if err != nil {
err = fmt.Errorf("failed to update user settings: %v", err.Error())
logger.Log(0, err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
logic.ReturnSuccessResponseWithJson(w, r, req, "updated user settings")
}
// swagger:route GET /api/v1/users user getUserV1
//
// Get an individual user with role info.

View file

@ -15,11 +15,17 @@ import (
"github.com/gravitl/netmaker/servercfg"
)
var serverSettingsDBKey = "server_cfg"
var ServerSettingsDBKey = "server_cfg"
var SettingsMutex = &sync.RWMutex{}
var defaultUserSettings = models.UserSettings{
TextSize: "16",
Theme: models.Dark,
ReducedMotion: false,
}
func GetServerSettings() (s models.ServerSettings) {
data, err := database.FetchRecord(database.SERVER_SETTINGS, serverSettingsDBKey)
data, err := database.FetchRecord(database.SERVER_SETTINGS, ServerSettingsDBKey)
if err != nil {
return
}
@ -37,13 +43,43 @@ func UpsertServerSettings(s models.ServerSettings) error {
if err != nil {
return err
}
err = database.Insert(serverSettingsDBKey, string(data), database.SERVER_SETTINGS)
err = database.Insert(ServerSettingsDBKey, string(data), database.SERVER_SETTINGS)
if err != nil {
return err
}
return nil
}
func GetUserSettings(userID string) models.UserSettings {
data, err := database.FetchRecord(database.SERVER_SETTINGS, userID)
if err != nil {
return defaultUserSettings
}
var userSettings models.UserSettings
err = json.Unmarshal([]byte(data), &userSettings)
if err != nil {
return defaultUserSettings
}
return userSettings
}
func UpsertUserSettings(userID string, userSettings models.UserSettings) error {
if userSettings.TextSize == "" {
userSettings.TextSize = "16"
}
if userSettings.Theme == "" {
userSettings.Theme = models.Dark
}
data, err := json.Marshal(userSettings)
if err != nil {
return err
}
return database.Insert(userID, string(data), database.SERVER_SETTINGS)
}
func ValidateNewSettings(req models.ServerSettings) bool {
// TODO: add checks for different fields
return true
@ -76,9 +112,6 @@ func GetServerSettingsFromEnv() (s models.ServerSettings) {
DefaultDomain: servercfg.GetDefaultDomain(),
Stun: servercfg.IsStunEnabled(),
StunServers: servercfg.GetStunServers(),
TextSize: "16",
Theme: models.Dark,
ReducedMotion: false,
}
return

View file

@ -25,7 +25,7 @@ import (
// Run - runs all migrations
func Run() {
settings()
migrateSettings()
updateEnrollmentKeys()
assignSuperAdmin()
createDefaultTagsAndPolicies()
@ -629,8 +629,8 @@ func migrateToEgressV1() {
}
}
func settings() {
_, err := database.FetchRecords(database.SERVER_SETTINGS)
func migrateSettings() {
_, err := database.FetchRecord(database.SERVER_SETTINGS, logic.ServerSettingsDBKey)
if database.IsEmptyRecord(err) {
logic.UpsertServerSettings(logic.GetServerSettingsFromEnv())
}

View file

@ -40,8 +40,11 @@ type ServerSettings struct {
DefaultDomain string `json:"default_domain"`
Stun bool `json:"stun"`
StunServers string `json:"stun_servers"`
Theme Theme `json:"theme"`
TextSize string `json:"text_size"`
ReducedMotion bool `json:"reduced_motion"`
AuditLogsRetentionPeriodInDays int `json:"audit_logs_retention_period"`
}
type UserSettings struct {
Theme Theme `json:"theme"`
TextSize string `json:"text_size"`
ReducedMotion bool `json:"reduced_motion"`
}