224 lines
5.9 KiB
Go
224 lines
5.9 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
|
||
|
md "github.com/JohannesKaufmann/html-to-markdown"
|
||
|
"github.com/JohannesKaufmann/html-to-markdown/plugin"
|
||
|
"github.com/gomarkdown/markdown"
|
||
|
"github.com/microcosm-cc/bluemonday"
|
||
|
)
|
||
|
|
||
|
type Template struct {
|
||
|
TemplateName string `json:"templateName"`
|
||
|
Filename string `json:"filename"`
|
||
|
}
|
||
|
|
||
|
func EditFile(w http.ResponseWriter, r *http.Request) {
|
||
|
userSession, err := validateSession(w, r)
|
||
|
if err != nil {
|
||
|
handleError(w, "Error validating session", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Get template and filename from query parameters
|
||
|
templateName := r.URL.Query().Get("template")
|
||
|
filename := r.URL.Query().Get("filename")
|
||
|
filePath := filepath.Join(fileUploadPath, userSession.username, filename)
|
||
|
|
||
|
// Read file content
|
||
|
fileContent, err := readFileContent(filePath)
|
||
|
if err != nil {
|
||
|
handleError(w, "Error reading file content", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Apply template content if specified
|
||
|
if templateName != "" {
|
||
|
templatePath := filepath.Join(templateFilePath, templateName)
|
||
|
templateContent, err := readFileContent(templatePath)
|
||
|
if err != nil {
|
||
|
handleError(w, "Error reading template content", err)
|
||
|
return
|
||
|
}
|
||
|
// overwrites file content. Could also change this to append.
|
||
|
//TODO: Give user setting to choose which method of usage.
|
||
|
fileContent = markdown.ToHTML([]byte(templateContent), nil, nil)
|
||
|
}
|
||
|
|
||
|
// Sanitize file content
|
||
|
sanitizedContent := sanitizeHTML(fileContent)
|
||
|
|
||
|
// Convert file content based on file type
|
||
|
if filepath.Ext(filename) == ".md" {
|
||
|
// Convert Markdown to HTML
|
||
|
htmlContent := markdown.ToHTML([]byte(sanitizedContent), nil, nil)
|
||
|
fileContent = []byte(htmlContent)
|
||
|
} else if filepath.Ext(filename) == ".html" {
|
||
|
// Sanitize HTML content to prevent any malicious code
|
||
|
fileContent = []byte(sanitizedContent)
|
||
|
}
|
||
|
|
||
|
templates, err := getTemplateList()
|
||
|
if err != nil {
|
||
|
handleError(w, "Error getting template list", err)
|
||
|
return
|
||
|
}
|
||
|
// Update the Templates slice to assign the current filename
|
||
|
for i := range templates {
|
||
|
templates[i].Filename = filename
|
||
|
}
|
||
|
data := struct {
|
||
|
Filename string
|
||
|
FileContent string
|
||
|
Templates []Template // Update type to []Template
|
||
|
}{
|
||
|
Filename: filename,
|
||
|
FileContent: string(fileContent),
|
||
|
Templates: templates, // Assign the template list
|
||
|
}
|
||
|
|
||
|
renderTemplate(w, "edit.html", data)
|
||
|
}
|
||
|
|
||
|
func SaveFile(w http.ResponseWriter, r *http.Request) {
|
||
|
userSession, err := validateSession(w, r)
|
||
|
if err != nil {
|
||
|
handleError(w, "Error validating session", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Get filename from query parameters
|
||
|
filename := r.URL.Query().Get("filename")
|
||
|
newFilename := r.FormValue("filename") // Retrieve the new filename from the form
|
||
|
filePath := filepath.Join(fileUploadPath, userSession.username, filename)
|
||
|
newFilePath := filepath.Join(fileUploadPath, userSession.username, newFilename) // Create the new file path
|
||
|
|
||
|
// If the new filename is different from the expected filename
|
||
|
if newFilename != filename {
|
||
|
|
||
|
// Check if the file with the new filename already exists
|
||
|
_, err = os.Stat(newFilePath)
|
||
|
if err == nil {
|
||
|
// File with new filename already exists, generate a new unique filename
|
||
|
count := 1
|
||
|
extension := filepath.Ext(newFilename)
|
||
|
filenameWithoutExt := strings.TrimSuffix(newFilename, extension)
|
||
|
|
||
|
// Keep incrementing the count until a unique filename is found
|
||
|
for err == nil {
|
||
|
newFilename = fmt.Sprintf("%s_%d%s", filenameWithoutExt, count, extension)
|
||
|
newFilePath = filepath.Join(fileUploadPath, userSession.username, newFilename)
|
||
|
_, err = os.Stat(newFilePath)
|
||
|
count++
|
||
|
}
|
||
|
} else if !os.IsNotExist(err) {
|
||
|
// Error accessing the file, handle the error or return an error response
|
||
|
handleError(w, "Error: Unable to access file", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
err := updateFilename(userSession.username, filename, newFilename)
|
||
|
if err != nil {
|
||
|
handleError(w, "Error updating filename", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
err = os.Rename(filePath, newFilePath) // Rename the file to the new filename
|
||
|
if err != nil {
|
||
|
handleError(w, "Error renaming file", err)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Create or open the file
|
||
|
file, err := os.Create(newFilePath)
|
||
|
if err != nil {
|
||
|
handleError(w, "Error creating file", err)
|
||
|
return
|
||
|
}
|
||
|
defer file.Close()
|
||
|
|
||
|
// Read the edited content from the request form
|
||
|
editedContent := r.FormValue("editor")
|
||
|
// Convert edited content from HTML to Markdown if the file extension is .md
|
||
|
if strings.HasSuffix(newFilename, ".md") {
|
||
|
editedContent = convertHTMLtoMarkdown(editedContent)
|
||
|
}
|
||
|
// Write the edited content to the file
|
||
|
_, err = file.WriteString(editedContent)
|
||
|
if err != nil {
|
||
|
handleError(w, "Error writing edited content to file", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Update the edited timestamp for the user and file
|
||
|
UpdateEditedTimestamp(userSession.username, newFilename)
|
||
|
|
||
|
http.Redirect(w, r, "/home", http.StatusSeeOther)
|
||
|
}
|
||
|
|
||
|
func handleError(w http.ResponseWriter, errMsg string, err error) {
|
||
|
log.Printf("%s: %v", errMsg, err)
|
||
|
}
|
||
|
|
||
|
func readFileContent(filePath string) ([]byte, error) {
|
||
|
file, err := os.Open(filePath)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer file.Close()
|
||
|
|
||
|
return io.ReadAll(file)
|
||
|
}
|
||
|
|
||
|
func sanitizeHTML(htmlContent []byte) []byte {
|
||
|
return bluemonday.UGCPolicy().SanitizeBytes(htmlContent)
|
||
|
}
|
||
|
|
||
|
func convertHTMLtoMarkdown(html string) string {
|
||
|
options := md.Options{
|
||
|
EscapeMode: "disabled",
|
||
|
}
|
||
|
converter := md.NewConverter("", true, &options)
|
||
|
converter.Use(plugin.Table())
|
||
|
converter.Use(plugin.Strikethrough("~~"))
|
||
|
markdown, err := converter.ConvertString(html)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
return markdown
|
||
|
}
|
||
|
|
||
|
func getTemplateList() ([]Template, error) {
|
||
|
dir, err := os.Open(templateFilePath)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer dir.Close()
|
||
|
|
||
|
fileInfos, err := dir.Readdir(-1)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
templates := make([]Template, 0)
|
||
|
for _, fileInfo := range fileInfos {
|
||
|
if !fileInfo.IsDir() {
|
||
|
template := Template{
|
||
|
TemplateName: fileInfo.Name(),
|
||
|
Filename: "",
|
||
|
}
|
||
|
templates = append(templates, template)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return templates, nil
|
||
|
}
|