281 lines
9.8 KiB
Go
281 lines
9.8 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"gobsidian/internal/utils"
|
|
)
|
|
|
|
func (h *Handlers) SettingsPageHandler(c *gin.Context) {
|
|
notesTree, err := utils.BuildTreeStructure(h.config.NotesDir, h.config.NotesDirHideSidepane, h.config)
|
|
if err != nil {
|
|
c.HTML(http.StatusInternalServerError, "error", gin.H{
|
|
"error": "Failed to build tree structure",
|
|
"app_name": h.config.AppName,
|
|
"message": err.Error(),
|
|
"ContentTemplate": "error_content",
|
|
"ScriptsTemplate": "error_scripts",
|
|
"Page": "error",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.HTML(http.StatusOK, "settings", gin.H{
|
|
"app_name": h.config.AppName,
|
|
"notes_tree": notesTree,
|
|
"active_path": []string{},
|
|
"current_note": nil,
|
|
"breadcrumbs": utils.GenerateBreadcrumbs(""),
|
|
"Authenticated": isAuthenticated(c),
|
|
"IsAdmin": isAdmin(c),
|
|
"ContentTemplate": "settings_content",
|
|
"ScriptsTemplate": "settings_scripts",
|
|
"Page": "settings",
|
|
})
|
|
}
|
|
|
|
func (h *Handlers) GetImageStorageSettingsHandler(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"mode": h.config.ImageStorageMode,
|
|
"path": h.config.ImageStoragePath,
|
|
"subfolder": h.config.ImageSubfolderName,
|
|
})
|
|
}
|
|
|
|
func (h *Handlers) PostImageStorageSettingsHandler(c *gin.Context) {
|
|
modeStr := c.PostForm("storage_mode")
|
|
path := strings.TrimSpace(c.PostForm("storage_path"))
|
|
subfolder := strings.TrimSpace(c.PostForm("subfolder_name"))
|
|
|
|
mode, err := strconv.Atoi(modeStr)
|
|
if err != nil || mode < 1 || mode > 4 {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid storage mode"})
|
|
return
|
|
}
|
|
|
|
// Validate path for mode 2
|
|
if mode == 2 && path == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Storage path is required for mode 2"})
|
|
return
|
|
}
|
|
|
|
// Validate subfolder name for mode 4
|
|
if mode == 4 && subfolder == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Subfolder name is required for mode 4"})
|
|
return
|
|
}
|
|
|
|
// Save settings
|
|
if err := h.config.SaveSetting("MD_NOTES_APP", "IMAGE_STORAGE_MODE", modeStr); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save storage mode"})
|
|
return
|
|
}
|
|
|
|
if mode == 2 {
|
|
if err := h.config.SaveSetting("MD_NOTES_APP", "IMAGE_STORAGE_PATH", path); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save storage path"})
|
|
return
|
|
}
|
|
}
|
|
|
|
if mode == 4 {
|
|
if err := h.config.SaveSetting("MD_NOTES_APP", "IMAGE_SUBFOLDER_NAME", subfolder); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save subfolder name"})
|
|
return
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"message": "Image storage settings updated successfully",
|
|
"reload_required": true,
|
|
})
|
|
}
|
|
|
|
func (h *Handlers) GetNotesDirSettingsHandler(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"notes_dir": h.config.NotesDir,
|
|
})
|
|
}
|
|
|
|
func (h *Handlers) PostNotesDirSettingsHandler(c *gin.Context) {
|
|
newDir := strings.TrimSpace(c.PostForm("notes_dir"))
|
|
if newDir == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Notes directory is required"})
|
|
return
|
|
}
|
|
|
|
// Convert to absolute path
|
|
if !filepath.IsAbs(newDir) {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Please provide an absolute path"})
|
|
return
|
|
}
|
|
|
|
// Ensure directory exists
|
|
if err := utils.EnsureDir(newDir); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create directory: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
// Save setting
|
|
if err := h.config.SaveSetting("MD_NOTES_APP", "NOTES_DIR", newDir); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save notes directory"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"message": "Notes directory updated successfully",
|
|
"reload_required": true,
|
|
})
|
|
}
|
|
|
|
func (h *Handlers) GetFileExtensionsSettingsHandler(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"allowed_image_extensions": strings.Join(h.config.AllowedImageExtensions, ", "),
|
|
"allowed_file_extensions": strings.Join(h.config.AllowedFileExtensions, ", "),
|
|
"images_hide": h.config.ImagesHide,
|
|
"show_images_in_tree": h.config.ShowImagesInTree,
|
|
"show_files_in_tree": h.config.ShowFilesInTree,
|
|
"show_images_in_folder": h.config.ShowImagesInFolder,
|
|
"show_files_in_folder": h.config.ShowFilesInFolder,
|
|
})
|
|
}
|
|
|
|
func (h *Handlers) PostFileExtensionsSettingsHandler(c *gin.Context) {
|
|
imageExtensions := strings.TrimSpace(c.PostForm("allowed_image_extensions"))
|
|
fileExtensions := strings.TrimSpace(c.PostForm("allowed_file_extensions"))
|
|
imagesHide := c.PostForm("images_hide") == "true" || c.PostForm("images_hide") == "on"
|
|
showImagesInTree := c.PostForm("show_images_in_tree") == "true" || c.PostForm("show_images_in_tree") == "on"
|
|
showFilesInTree := c.PostForm("show_files_in_tree") == "true" || c.PostForm("show_files_in_tree") == "on"
|
|
showImagesInFolder := c.PostForm("show_images_in_folder") == "true" || c.PostForm("show_images_in_folder") == "on"
|
|
showFilesInFolder := c.PostForm("show_files_in_folder") == "true" || c.PostForm("show_files_in_folder") == "on"
|
|
|
|
// Save settings
|
|
if err := h.config.SaveSetting("MD_NOTES_APP", "ALLOWED_IMAGE_EXTENSIONS", imageExtensions); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save image extensions"})
|
|
return
|
|
}
|
|
|
|
if err := h.config.SaveSetting("MD_NOTES_APP", "ALLOWED_FILE_EXTENSIONS", fileExtensions); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file extensions"})
|
|
return
|
|
}
|
|
|
|
imagesHideStr := "false"
|
|
if imagesHide {
|
|
imagesHideStr = "true"
|
|
}
|
|
if err := h.config.SaveSetting("MD_NOTES_APP", "IMAGES_HIDE", imagesHideStr); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save images hide setting"})
|
|
return
|
|
}
|
|
|
|
if err := h.config.SaveSetting("MD_NOTES_APP", "SHOW_IMAGES_IN_TREE", boolToStr(showImagesInTree)); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save SHOW_IMAGES_IN_TREE"})
|
|
return
|
|
}
|
|
if err := h.config.SaveSetting("MD_NOTES_APP", "SHOW_FILES_IN_TREE", boolToStr(showFilesInTree)); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save SHOW_FILES_IN_TREE"})
|
|
return
|
|
}
|
|
if err := h.config.SaveSetting("MD_NOTES_APP", "SHOW_IMAGES_IN_FOLDER", boolToStr(showImagesInFolder)); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save SHOW_IMAGES_IN_FOLDER"})
|
|
return
|
|
}
|
|
if err := h.config.SaveSetting("MD_NOTES_APP", "SHOW_FILES_IN_FOLDER", boolToStr(showFilesInFolder)); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save SHOW_FILES_IN_FOLDER"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"message": "File extension settings updated successfully",
|
|
"reload_required": true,
|
|
})
|
|
}
|
|
|
|
func boolToStr(b bool) string {
|
|
if b {
|
|
return "true"
|
|
}
|
|
return "false"
|
|
}
|
|
|
|
// --- Security (IP Ban & Thresholds) Settings ---
|
|
|
|
// GetSecuritySettingsHandler returns current security-related config
|
|
func (h *Handlers) GetSecuritySettingsHandler(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"pwd_failures_threshold": h.config.PwdFailuresThreshold,
|
|
"mfa_failures_threshold": h.config.MFAFailuresThreshold,
|
|
"failures_window_minutes": h.config.FailuresWindowMinutes,
|
|
"auto_ban_duration_hours": h.config.AutoBanDurationHours,
|
|
"auto_ban_permanent": h.config.AutoBanPermanent,
|
|
})
|
|
}
|
|
|
|
// PostSecuritySettingsHandler validates and saves security-related config
|
|
func (h *Handlers) PostSecuritySettingsHandler(c *gin.Context) {
|
|
pwdStr := strings.TrimSpace(c.PostForm("pwd_failures_threshold"))
|
|
mfaStr := strings.TrimSpace(c.PostForm("mfa_failures_threshold"))
|
|
winStr := strings.TrimSpace(c.PostForm("failures_window_minutes"))
|
|
durStr := strings.TrimSpace(c.PostForm("auto_ban_duration_hours"))
|
|
permStr := strings.TrimSpace(c.PostForm("auto_ban_permanent"))
|
|
|
|
// basic validation
|
|
if pwdStr == "" || mfaStr == "" || winStr == "" || durStr == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "All numeric fields are required"})
|
|
return
|
|
}
|
|
if _, err := strconv.Atoi(pwdStr); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid password failures threshold"})
|
|
return
|
|
}
|
|
if _, err := strconv.Atoi(mfaStr); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid MFA failures threshold"})
|
|
return
|
|
}
|
|
if _, err := strconv.Atoi(winStr); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid failures window (minutes)"})
|
|
return
|
|
}
|
|
if _, err := strconv.Atoi(durStr); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid auto-ban duration (hours)"})
|
|
return
|
|
}
|
|
|
|
// normalize perm
|
|
perm := strings.EqualFold(permStr, "true") || permStr == "1" || strings.EqualFold(permStr, "on")
|
|
permStr = boolToStr(perm)
|
|
|
|
// Save values
|
|
if err := h.config.SaveSetting("SECURITY", "PWD_FAILURES_THRESHOLD", pwdStr); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save PWD_FAILURES_THRESHOLD"})
|
|
return
|
|
}
|
|
if err := h.config.SaveSetting("SECURITY", "MFA_FAILURES_THRESHOLD", mfaStr); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save MFA_FAILURES_THRESHOLD"})
|
|
return
|
|
}
|
|
if err := h.config.SaveSetting("SECURITY", "FAILURES_WINDOW_MINUTES", winStr); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save FAILURES_WINDOW_MINUTES"})
|
|
return
|
|
}
|
|
if err := h.config.SaveSetting("SECURITY", "AUTO_BAN_DURATION_HOURS", durStr); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save AUTO_BAN_DURATION_HOURS"})
|
|
return
|
|
}
|
|
if err := h.config.SaveSetting("SECURITY", "AUTO_BAN_PERMANENT", permStr); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save AUTO_BAN_PERMANENT"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
|
}
|