Browse Source

fix: memory limitations due to 32 bit architecture; now using manual form field/file processing; hopefully it continues to work

document-upload-removal-layout-update
nic 10 months ago
parent
commit
c005620e84
  1. 197
      internal/handlers/web/documents.go

197
internal/handlers/web/documents.go

@ -6,12 +6,9 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"mime/multipart"
"net/http" "net/http"
"path/filepath" "path/filepath"
"regexp"
"sort" "sort"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -197,25 +194,84 @@ func UploadDocumentsHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
// Parse the multipart form with a 30MB limit // Custom multipart form processing for 32-bit systems
if err := r.ParseMultipartForm(30 << 20); err != nil { reader, err := r.MultipartReader()
http.Error(w, fmt.Sprintf("Unable to parse form: %v", err), http.StatusBadRequest) if err != nil {
http.Error(w, "Unable to get multipart reader: "+err.Error(), http.StatusBadRequest)
return return
} }
// Get the job numbers from either of the possible form fields // Store form values and file parts
jobNumbers := r.FormValue("jobNumbers") formValues := make(map[string]string)
// Read all file contents
type DocumentWithContent struct {
Name string
Type string
FileContent []byte
FormField string // Store the original form field name
}
var docsWithContent []DocumentWithContent
// First pass: collect all form fields and files
log.Printf("--- Starting multipart form processing ---")
for {
part, err := reader.NextPart()
if err == io.EOF {
break
}
if err != nil {
log.Printf("Error reading multipart part: %v", err)
break
}
formName := part.FormName()
fileName := part.FileName()
// If not a file, it's a regular form value
if fileName == "" {
// Read the form field value
valueBytes, err := io.ReadAll(part)
if err != nil {
log.Printf("Error reading form field %s: %v", formName, err)
continue
}
value := string(valueBytes)
formValues[formName] = value
log.Printf("Form field: %s = %s", formName, value)
} else if strings.HasPrefix(formName, "document-file-") {
// It's a file upload field
// Read file content
fileContent, err := io.ReadAll(part)
if err != nil {
log.Printf("Error reading file content for %s: %v", fileName, err)
continue
}
log.Printf("Found file: %s (size: %d bytes) in field: %s",
fileName, len(fileContent), formName)
// Store the file with its original field name for later processing
docsWithContent = append(docsWithContent, DocumentWithContent{
Name: fileName, // Default to original filename, will be updated with form values
Type: "", // Will be set from form values
FileContent: fileContent,
FormField: formName,
})
}
}
// Get job numbers from form values
jobNumbers := formValues["jobNumbers"]
if jobNumbers == "" { if jobNumbers == "" {
jobNumbers = r.FormValue("job-ids") jobNumbers = formValues["job-ids"]
if jobNumbers == "" { if jobNumbers == "" {
log.Printf("No job numbers provided. Form data: %+v", r.Form) log.Printf("No job numbers found in form values: %+v", formValues)
http.Error(w, "No job numbers provided", http.StatusBadRequest) http.Error(w, "No job numbers provided", http.StatusBadRequest)
return return
} }
} }
// Log the form data for debugging
log.Printf("Form data: %+v", r.Form)
log.Printf("Job numbers: %s", jobNumbers) log.Printf("Job numbers: %s", jobNumbers)
// Split the job numbers // Split the job numbers
@ -225,110 +281,51 @@ func UploadDocumentsHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
// Regular expression to match file field patterns // Second pass: process document metadata
filePattern := regexp.MustCompile(`document-file-(\d+)`) for i, doc := range docsWithContent {
suffix := strings.TrimPrefix(doc.FormField, "document-file-")
// Collect document data nameField := "document-name-" + suffix
type DocumentData struct { typeField := "document-type-" + suffix
File multipart.File
Header *multipart.FileHeader
Name string
Type string
Index int
}
var documents []DocumentData // Get custom document name if provided
customName := formValues[nameField]
// First, identify all available indices if customName != "" {
var indices []int
for key := range r.MultipartForm.File {
if matches := filePattern.FindStringSubmatch(key); len(matches) > 1 {
if index, err := strconv.Atoi(matches[1]); err == nil {
indices = append(indices, index)
}
}
}
// Process each document
for _, index := range indices {
fileKey := fmt.Sprintf("document-file-%d", index)
nameKey := fmt.Sprintf("document-name-%d", index)
typeKey := fmt.Sprintf("document-type-%d", index)
fileHeaders := r.MultipartForm.File[fileKey]
if len(fileHeaders) == 0 {
continue // Skip if no file uploaded
}
fileHeader := fileHeaders[0]
file, err := fileHeader.Open()
if err != nil {
log.Printf("Error opening file %s: %v", fileHeader.Filename, err)
continue
}
// Get document name (use filename if not provided)
documentName := r.FormValue(nameKey)
if documentName == "" {
documentName = fileHeader.Filename
} else {
// If a custom name is provided without extension, add the original file extension // If a custom name is provided without extension, add the original file extension
if !strings.Contains(documentName, ".") { if !strings.Contains(customName, ".") {
extension := filepath.Ext(fileHeader.Filename) extension := filepath.Ext(doc.Name)
if extension != "" { if extension != "" {
documentName = documentName + extension customName = customName + extension
} }
} }
docsWithContent[i].Name = customName
} }
log.Printf("Using document name: %s (original filename: %s)", documentName, fileHeader.Filename)
// Get document type // Get document type
documentType := r.FormValue(typeKey) docType := formValues[typeField]
if documentType == "" { if docType == "" {
log.Printf("No document type for file %s", fileHeader.Filename) log.Printf("No document type for file %s, skipping", doc.Name)
continue continue
} }
// Log the document type for debugging docsWithContent[i].Type = docType
log.Printf("Document type for %s: '%s'", documentName, documentType) log.Printf("Processing document: %s (type: %s) from field: %s",
docsWithContent[i].Name, docType, doc.FormField)
documents = append(documents, DocumentData{
File: file,
Header: fileHeader,
Name: documentName,
Type: documentType,
Index: index,
})
} }
if len(documents) == 0 { // Filter out documents with no type
http.Error(w, "No valid documents selected for upload", http.StatusBadRequest) var validDocs []DocumentWithContent
return for _, doc := range docsWithContent {
if doc.Type != "" {
validDocs = append(validDocs, doc)
}
} }
docsWithContent = validDocs
// Read all file contents first to avoid keeping files open during concurrent uploads log.Printf("Total valid documents to upload: %d", len(docsWithContent))
type DocumentWithContent struct {
Name string
Type string
FileContent []byte
}
var docsWithContent []DocumentWithContent if len(docsWithContent) == 0 {
for _, doc := range documents { http.Error(w, "No valid documents selected for upload", http.StatusBadRequest)
// Read file content return
fileContent, err := io.ReadAll(doc.File)
if err != nil {
log.Printf("Error reading file %s: %v", doc.Header.Filename, err)
continue
}
doc.File.Close() // Close the file as soon as we're done with it
docsWithContent = append(docsWithContent, DocumentWithContent{
Name: doc.Name,
Type: doc.Type,
FileContent: fileContent,
})
} }
// Concurrent upload with throttling // Concurrent upload with throttling

Loading…
Cancel
Save