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 }