notatio/export.go
Musselman 2457ee9836
🐛 Fix: Error handling code for the makeFolder
The previous code had a condition where it was using the wrong variable, thus was impossible to reach.
2024-06-26 11:49:09 -05:00

289 lines
6.9 KiB
Go

package main
import (
"archive/zip"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"time"
)
// bundleFilesToZip bundles the files in the specified folder to a zip file
func bundleFilesToZip(folderPath string, destination string) error {
// Create the zip file
zipFile, err := os.Create(destination)
if err != nil {
log.Printf("Error creating zip file: %v", err)
return err
}
defer zipFile.Close() // Close the zip file at the end of the function execution using defer
// Create a new zip archive
archive := zip.NewWriter(zipFile)
defer archive.Close()
// Traverse the files and directories in the specified folder path
err = filepath.WalkDir(folderPath, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
// Get file/directory info
info, err := d.Info()
if err != nil {
return err
}
// Get the file info header for the entry in the zip file
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
// Set the header name to be relative to the folder path
relativePath, err := filepath.Rel(folderPath, path)
if err != nil {
return err
}
header.Name = relativePath
if info.IsDir() {
// Create the folder entry in the zip file
header.Name += "/"
header.Method = zip.Store
_, err = archive.CreateHeader(header)
if err != nil {
return err
}
} else {
// Create a file entry in the zip file
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
// Open the source file for reading
srcFile, err := os.Open(path)
if err != nil {
return err
}
defer srcFile.Close()
// Copy the file contents to the zip file
_, err = io.Copy(writer, srcFile)
if err != nil {
return err
}
}
return nil
})
if err != nil {
log.Printf("Error bundling files to zip: %v", err)
return err
}
return nil
}
// deleteFolder deletes the folder at the specified path
func deleteFolder(folderPath string) error {
err := os.RemoveAll(folderPath)
if err != nil {
log.Printf("Error deleting folder: %v", err)
return err
}
return nil
}
// exportFiles exports the files in a folder to a zip file and serves it as a download
func exportFiles(w http.ResponseWriter, r *http.Request) {
// Get the user's session for the folder path
userSession, err := validateSession(w, r)
if err != nil {
// Handle the error as needed
return
}
username := userSession.username
dateTime := time.Now().Format("2006-01-02_15-04-05") // Format the current date and time as "YYYY-MM-DD_HH-MM-SS"
// Get the folder path from the URL parameter
folderPath := r.URL.Query().Get("folder")
// If no folder path is given, export the user's folder
if folderPath == "" {
folderPath = filepath.Join(fileUploadPath, userSession.username)
}
// Create a temporary folder to store the exported files
tempFolder := filepath.Join(".", "temp")
err = makeFolder(tempFolder)
if err != nil {
http.Error(w, "Error creating temporary folder", http.StatusInternalServerError)
log.Println(err)
return
}
// Copy the user's folder to the temporary folder
err = copyFolder(folderPath, tempFolder)
if err != nil {
http.Error(w, "Error copying folder", http.StatusInternalServerError)
log.Println(err)
return
}
// Convert HTML files to Markdown in the temporary folder
err = filepath.WalkDir(tempFolder, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if strings.HasSuffix(path, ".md") {
content, err := os.ReadFile(path)
if err != nil {
log.Printf("Error reading file: %v", err)
return err
}
// Convert HTML to Markdown
markdown := convertHTMLtoMarkdown(string(content))
// Write the Markdown content back to the file
err = os.WriteFile(path, []byte(markdown), os.ModePerm)
if err != nil {
log.Printf("Error writing Markdown file: %v", err)
return err
}
}
return nil
})
if err != nil {
http.Error(w, "Error converting HTML files to Markdown", http.StatusInternalServerError)
log.Println(err)
return
}
// Generate a unique name for the zip file
zipFileName := username + "_" + dateTime + ".zip"
zipFilePath := filepath.Join(".", zipFileName)
// Bundle the files in the temporary folder into a zip file
err = bundleFilesToZip(tempFolder, zipFilePath)
if err != nil {
http.Error(w, "Error bundling files to zip", http.StatusInternalServerError)
log.Println(err)
return
}
// Delete the temporary folder
err = deleteFolder(tempFolder)
if err != nil {
log.Println(err)
}
// Open the zip file for reading
zipFile, err := os.Open(zipFilePath)
if err != nil {
http.Error(w, "Error opening zip file", http.StatusInternalServerError)
log.Println(err)
return
}
defer zipFile.Close()
// Set the response headers
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", zipFileName))
// Write the zip file contents to the response writer
_, err = io.Copy(w, zipFile)
if err != nil {
log.Println(err)
}
// Delete the generated zip file
err = os.Remove(zipFilePath)
if err != nil {
// Log the error, but don't interrupt the response handling
log.Printf("Error deleting zip file: %v", err)
}
}
// copyFolder copies the files and directories from the source path to the destination path
func copyFolder(source string, destination string) error {
// Traverse the files and directories in the specified folder path
err := filepath.WalkDir(source, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
// Skip the source folder itself
if path == source {
return nil
}
// Get the relative path within the source folder
relativePath, err := filepath.Rel(source, path)
if err != nil {
log.Printf("Error getting relative path: %v", err)
return err
}
// Create the corresponding destination path
destPath := filepath.Join(destination, relativePath)
if d.IsDir() {
// Create the directory in the destination
err := os.MkdirAll(destPath, os.ModePerm)
if err != nil {
log.Printf("Error creating destination folder: %v", err)
return err
}
} else {
// Copy the file from source to destination
err := copyFile(path, destPath)
if err != nil {
log.Printf("Error copying file: %v", err)
return err
}
}
return nil
})
if err != nil {
log.Printf("Error copying folder: %v", err)
return err
}
return nil
}
// copyFile copies a file from the source path to the destination path
func copyFile(source string, destination string) error {
srcFile, err := os.Open(source)
if err != nil {
log.Printf("Error opening source file: %v", err)
return err
}
defer srcFile.Close()
destFile, err := os.Create(destination)
if err != nil {
log.Printf("Error creating destination file: %v", err)
return err
}
defer destFile.Close()
_, err = io.Copy(destFile, srcFile)
if err != nil {
log.Printf("Error copying file: %v", err)
return err
}
return nil
}