287 lines
7.7 KiB
Go
287 lines
7.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"gobsidian/internal/utils"
|
|
)
|
|
|
|
func (h *Handlers) CreateNotePageHandler(c *gin.Context) {
|
|
folderPath := c.Query("folder")
|
|
if folderPath == "" {
|
|
folderPath = ""
|
|
}
|
|
|
|
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, "create", gin.H{
|
|
"app_name": h.config.AppName,
|
|
"folder_path": folderPath,
|
|
"notes_tree": notesTree,
|
|
"active_path": utils.GetActivePath(folderPath),
|
|
"current_note": nil,
|
|
"breadcrumbs": utils.GenerateBreadcrumbs(folderPath),
|
|
"ContentTemplate": "create_content",
|
|
"ScriptsTemplate": "create_scripts",
|
|
"Page": "create",
|
|
})
|
|
}
|
|
|
|
func (h *Handlers) CreateNoteHandler(c *gin.Context) {
|
|
folderPath := strings.TrimSpace(c.PostForm("folder_path"))
|
|
title := strings.TrimSpace(c.PostForm("title"))
|
|
content := c.PostForm("content")
|
|
|
|
if title == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Title is required"})
|
|
return
|
|
}
|
|
|
|
// Security check
|
|
if strings.Contains(folderPath, "..") || strings.Contains(title, "..") {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid path or title"})
|
|
return
|
|
}
|
|
|
|
// Check if path is in skipped directories
|
|
if utils.IsPathInSkippedDirs(folderPath, h.config.NotesDirSkip) {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "Cannot create notes in this directory"})
|
|
return
|
|
}
|
|
|
|
// Ensure title ends with .md
|
|
if !strings.HasSuffix(title, ".md") {
|
|
title += ".md"
|
|
}
|
|
|
|
// Create full path
|
|
var notePath string
|
|
if folderPath == "" {
|
|
notePath = title
|
|
} else {
|
|
notePath = filepath.Join(folderPath, title)
|
|
}
|
|
|
|
fullPath := filepath.Join(h.config.NotesDir, notePath)
|
|
|
|
// Check if file already exists
|
|
if _, err := os.Stat(fullPath); !os.IsNotExist(err) {
|
|
c.JSON(http.StatusConflict, gin.H{"error": "A note with this title already exists"})
|
|
return
|
|
}
|
|
|
|
// Ensure directory exists
|
|
dir := filepath.Dir(fullPath)
|
|
if err := utils.EnsureDir(dir); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create directory"})
|
|
return
|
|
}
|
|
|
|
// Write file
|
|
if err := os.WriteFile(fullPath, []byte(content), 0644); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create note"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"message": "Note created successfully",
|
|
"note_path": notePath,
|
|
"redirect": "/note/" + notePath,
|
|
})
|
|
}
|
|
|
|
func (h *Handlers) EditNotePageHandler(c *gin.Context) {
|
|
notePath := strings.TrimPrefix(c.Param("path"), "/")
|
|
|
|
if !strings.HasSuffix(notePath, ".md") {
|
|
c.HTML(http.StatusBadRequest, "error", gin.H{
|
|
"error": "Invalid note path",
|
|
"app_name": h.config.AppName,
|
|
"message": "Note path must end with .md",
|
|
"ContentTemplate": "error_content",
|
|
"ScriptsTemplate": "error_scripts",
|
|
"Page": "error",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Security check
|
|
if strings.Contains(notePath, "..") {
|
|
c.HTML(http.StatusBadRequest, "error", gin.H{
|
|
"error": "Invalid path",
|
|
"app_name": h.config.AppName,
|
|
"message": "Path traversal is not allowed",
|
|
"ContentTemplate": "error_content",
|
|
"ScriptsTemplate": "error_scripts",
|
|
"Page": "error",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Check if path is in skipped directories
|
|
if utils.IsPathInSkippedDirs(notePath, h.config.NotesDirSkip) {
|
|
c.HTML(http.StatusForbidden, "error", gin.H{
|
|
"error": "Access denied",
|
|
"app_name": h.config.AppName,
|
|
"message": "This note cannot be edited",
|
|
"ContentTemplate": "error_content",
|
|
"ScriptsTemplate": "error_scripts",
|
|
"Page": "error",
|
|
})
|
|
return
|
|
}
|
|
|
|
fullPath := filepath.Join(h.config.NotesDir, notePath)
|
|
|
|
if _, err := os.Stat(fullPath); os.IsNotExist(err) {
|
|
c.HTML(http.StatusNotFound, "error", gin.H{
|
|
"error": "Note not found",
|
|
"app_name": h.config.AppName,
|
|
"message": "The requested note does not exist",
|
|
"ContentTemplate": "error_content",
|
|
"ScriptsTemplate": "error_scripts",
|
|
"Page": "error",
|
|
})
|
|
return
|
|
}
|
|
|
|
content, err := os.ReadFile(fullPath)
|
|
if err != nil {
|
|
c.HTML(http.StatusInternalServerError, "error", gin.H{
|
|
"error": "Failed to read note",
|
|
"app_name": h.config.AppName,
|
|
"message": err.Error(),
|
|
"ContentTemplate": "error_content",
|
|
"ScriptsTemplate": "error_scripts",
|
|
"Page": "error",
|
|
})
|
|
return
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
title := strings.TrimSuffix(filepath.Base(notePath), ".md")
|
|
folderPath := filepath.Dir(notePath)
|
|
if folderPath == "." {
|
|
folderPath = ""
|
|
}
|
|
|
|
c.HTML(http.StatusOK, "edit", gin.H{
|
|
"app_name": h.config.AppName,
|
|
"title": title,
|
|
"content": string(content),
|
|
"note_path": notePath,
|
|
"folder_path": folderPath,
|
|
"notes_tree": notesTree,
|
|
"active_path": utils.GetActivePath(folderPath),
|
|
"current_note": notePath,
|
|
"breadcrumbs": utils.GenerateBreadcrumbs(folderPath),
|
|
"ContentTemplate": "edit_content",
|
|
"ScriptsTemplate": "edit_scripts",
|
|
"Page": "edit",
|
|
})
|
|
}
|
|
|
|
func (h *Handlers) EditNoteHandler(c *gin.Context) {
|
|
notePath := strings.TrimPrefix(c.Param("path"), "/")
|
|
content := c.PostForm("content")
|
|
|
|
if !strings.HasSuffix(notePath, ".md") {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid note path"})
|
|
return
|
|
}
|
|
|
|
// Security check
|
|
if strings.Contains(notePath, "..") {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid path"})
|
|
return
|
|
}
|
|
|
|
// Check if path is in skipped directories
|
|
if utils.IsPathInSkippedDirs(notePath, h.config.NotesDirSkip) {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "This note cannot be edited"})
|
|
return
|
|
}
|
|
|
|
fullPath := filepath.Join(h.config.NotesDir, notePath)
|
|
|
|
if _, err := os.Stat(fullPath); os.IsNotExist(err) {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Note not found"})
|
|
return
|
|
}
|
|
|
|
// Write updated content
|
|
if err := os.WriteFile(fullPath, []byte(content), 0644); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save note"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"message": "Note saved successfully",
|
|
"redirect": "/note/" + notePath,
|
|
})
|
|
}
|
|
|
|
func (h *Handlers) DeleteHandler(c *gin.Context) {
|
|
filePath := strings.TrimPrefix(c.Param("path"), "/")
|
|
|
|
// Security check
|
|
if strings.Contains(filePath, "..") {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid path"})
|
|
return
|
|
}
|
|
|
|
// Check if path is in skipped directories
|
|
if utils.IsPathInSkippedDirs(filePath, h.config.NotesDirSkip) {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "Cannot delete files in this directory"})
|
|
return
|
|
}
|
|
|
|
fullPath := filepath.Join(h.config.NotesDir, filePath)
|
|
|
|
if _, err := os.Stat(fullPath); os.IsNotExist(err) {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "File not found"})
|
|
return
|
|
}
|
|
|
|
// Delete file or directory
|
|
if err := os.RemoveAll(fullPath); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete file"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"message": "File deleted successfully",
|
|
})
|
|
}
|