292 lines
6.9 KiB
Go
292 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")
|
|
err2 := makeFolder(tempFolder)
|
|
if err != nil {
|
|
http.Error(w, "Error creating temporary folder", http.StatusInternalServerError)
|
|
log.Println(err2)
|
|
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
|
|
}
|