add other files view/edit
This commit is contained in:
@@ -67,10 +67,28 @@ func (h *Handlers) CreateNoteHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure title ends with .md
|
||||
if !strings.HasSuffix(title, ".md") {
|
||||
title += ".md"
|
||||
}
|
||||
// Determine extension logic
|
||||
ext := strings.TrimPrefix(strings.ToLower(filepath.Ext(title)), ".")
|
||||
if ext == "" {
|
||||
// No extension provided: default to markdown
|
||||
title += ".md"
|
||||
ext = "md"
|
||||
} else {
|
||||
// Has extension: allow if md or in allowed file extensions
|
||||
allowed := ext == "md"
|
||||
if !allowed {
|
||||
for _, a := range h.config.AllowedFileExtensions {
|
||||
if strings.EqualFold(a, ext) {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !allowed {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "File extension not allowed"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Create full path
|
||||
var notePath string
|
||||
@@ -101,12 +119,18 @@ func (h *Handlers) CreateNoteHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"message": "Note created successfully",
|
||||
"note_path": notePath,
|
||||
"redirect": "/note/" + notePath,
|
||||
})
|
||||
// Redirect based on extension
|
||||
redirect := "/note/" + notePath
|
||||
if strings.ToLower(ext) != "md" {
|
||||
redirect = "/view_text/" + notePath
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"message": "Note created successfully",
|
||||
"note_path": notePath,
|
||||
"redirect": redirect,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handlers) EditNotePageHandler(c *gin.Context) {
|
||||
|
||||
@@ -24,6 +24,137 @@ type Handlers struct {
|
||||
renderer *markdown.Renderer
|
||||
}
|
||||
|
||||
// EditTextPageHandler renders an editor for allowed text files (json, html, xml, yaml, etc.)
|
||||
func (h *Handlers) EditTextPageHandler(c *gin.Context) {
|
||||
filePath := strings.TrimPrefix(c.Param("path"), "/")
|
||||
|
||||
// Security check
|
||||
if strings.Contains(filePath, "..") {
|
||||
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
|
||||
}
|
||||
|
||||
fullPath := filepath.Join(h.config.NotesDir, filePath)
|
||||
|
||||
// Ensure file exists
|
||||
if _, err := os.Stat(fullPath); os.IsNotExist(err) {
|
||||
c.HTML(http.StatusNotFound, "error", gin.H{
|
||||
"error": "File not found",
|
||||
"app_name": h.config.AppName,
|
||||
"message": "The requested file does not exist",
|
||||
"ContentTemplate": "error_content",
|
||||
"ScriptsTemplate": "error_scripts",
|
||||
"Page": "error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Only allow editing of configured text file types (not markdown here)
|
||||
ext := filepath.Ext(fullPath)
|
||||
ftype := models.GetFileType(ext, h.config.AllowedImageExtensions, h.config.AllowedFileExtensions)
|
||||
if ftype != models.FileTypeText {
|
||||
c.HTML(http.StatusForbidden, "error", gin.H{
|
||||
"error": "Editing not allowed",
|
||||
"app_name": h.config.AppName,
|
||||
"message": "This file type cannot be edited here",
|
||||
"ContentTemplate": "error_content",
|
||||
"ScriptsTemplate": "error_scripts",
|
||||
"Page": "error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Load content
|
||||
data, err := os.ReadFile(fullPath)
|
||||
if err != nil {
|
||||
c.HTML(http.StatusInternalServerError, "error", gin.H{
|
||||
"error": "Failed to read file",
|
||||
"app_name": h.config.AppName,
|
||||
"message": err.Error(),
|
||||
"ContentTemplate": "error_content",
|
||||
"ScriptsTemplate": "error_scripts",
|
||||
"Page": "error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Build notes tree
|
||||
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 notes tree",
|
||||
"app_name": h.config.AppName,
|
||||
"message": err.Error(),
|
||||
"ContentTemplate": "error_content",
|
||||
"ScriptsTemplate": "error_scripts",
|
||||
"Page": "error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
folderPath := filepath.Dir(filePath)
|
||||
if folderPath == "." {
|
||||
folderPath = ""
|
||||
}
|
||||
|
||||
c.HTML(http.StatusOK, "edit_text", gin.H{
|
||||
"app_name": h.config.AppName,
|
||||
"title": filepath.Base(filePath),
|
||||
"content": string(data),
|
||||
"file_path": filePath,
|
||||
"file_ext": strings.TrimPrefix(strings.ToLower(ext), "."),
|
||||
"folder_path": folderPath,
|
||||
"notes_tree": notesTree,
|
||||
"active_path": utils.GetActivePath(folderPath),
|
||||
"breadcrumbs": utils.GenerateBreadcrumbs(folderPath),
|
||||
"ContentTemplate": "edit_text_content",
|
||||
"ScriptsTemplate": "edit_text_scripts",
|
||||
"Page": "edit_text",
|
||||
})
|
||||
}
|
||||
|
||||
// PostEditTextHandler saves changes to an allowed text file
|
||||
func (h *Handlers) PostEditTextHandler(c *gin.Context) {
|
||||
filePath := strings.TrimPrefix(c.Param("path"), "/")
|
||||
|
||||
if strings.Contains(filePath, "..") {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid path"})
|
||||
return
|
||||
}
|
||||
|
||||
fullPath := filepath.Join(h.config.NotesDir, filePath)
|
||||
|
||||
// Enforce allowed file type
|
||||
ext := filepath.Ext(fullPath)
|
||||
ftype := models.GetFileType(ext, h.config.AllowedImageExtensions, h.config.AllowedFileExtensions)
|
||||
if ftype != models.FileTypeText {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "This file type cannot be edited"})
|
||||
return
|
||||
}
|
||||
|
||||
content := c.PostForm("content")
|
||||
|
||||
// Ensure parent directory exists
|
||||
if err := os.MkdirAll(filepath.Dir(fullPath), 0o755); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create parent directory"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := os.WriteFile(fullPath, []byte(content), 0o644); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "redirect": "/view_text/" + filePath})
|
||||
}
|
||||
|
||||
func New(cfg *config.Config, store *sessions.CookieStore) *Handlers {
|
||||
return &Handlers{
|
||||
config: cfg,
|
||||
@@ -431,11 +562,18 @@ func (h *Handlers) ViewTextHandler(c *gin.Context) {
|
||||
folderPath = ""
|
||||
}
|
||||
|
||||
// Determine extension and whether file is editable as text
|
||||
ext := filepath.Ext(filePath)
|
||||
ftype := models.GetFileType(ext, h.config.AllowedImageExtensions, h.config.AllowedFileExtensions)
|
||||
isEditable := ftype == models.FileTypeText
|
||||
|
||||
c.HTML(http.StatusOK, "view_text", gin.H{
|
||||
"app_name": h.config.AppName,
|
||||
"file_name": filepath.Base(filePath),
|
||||
"file_path": filePath,
|
||||
"content": string(content),
|
||||
"file_ext": strings.TrimPrefix(strings.ToLower(ext), "."),
|
||||
"is_editable": isEditable,
|
||||
"folder_path": folderPath,
|
||||
"notes_tree": notesTree,
|
||||
"active_path": utils.GetActivePath(folderPath),
|
||||
|
||||
Reference in New Issue
Block a user