Generate excel in memory

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-06-30 09:31:56 +02:00
parent 7268a731e1
commit 364c6e4499

View File

@@ -15,6 +15,7 @@
package probo package probo
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"io" "io"
@@ -587,14 +588,13 @@ func (s FrameworkService) StateOfApplicability(ctx context.Context, frameworkID
return err return err
} }
excelFilePath, err := s.createSOAExcelFile(framework, soaData) excelReader, err := s.createSOAExcelFile(framework, soaData)
if err != nil { if err != nil {
return err return err
} }
defer os.Remove(excelFilePath) // Clean up local file after upload
// Upload to S3 and get presigned URL // Upload to S3 and get presigned URL
presignedURL, err = s.uploadSOAToS3(ctx, framework, excelFilePath) presignedURL, err = s.uploadSOAToS3(ctx, framework, excelReader)
if err != nil { if err != nil {
return fmt.Errorf("cannot upload SOA to S3: %w", err) return fmt.Errorf("cannot upload SOA to S3: %w", err)
} }
@@ -720,7 +720,7 @@ func (s FrameworkService) buildSOARowData(ctx context.Context, conn pg.Conn, con
return rowData, nil return rowData, nil
} }
func (s FrameworkService) createSOAExcelFile(framework *coredata.Framework, soaData []soaRowData) (string, error) { func (s FrameworkService) createSOAExcelFile(framework *coredata.Framework, soaData []soaRowData) (io.Reader, error) {
f := excelize.NewFile() f := excelize.NewFile()
defer func() { defer func() {
if err := f.Close(); err != nil { if err := f.Close(); err != nil {
@@ -733,29 +733,29 @@ func (s FrameworkService) createSOAExcelFile(framework *coredata.Framework, soaD
styles, err := s.createExcelStyles(f) styles, err := s.createExcelStyles(f)
if err != nil { if err != nil {
return "", fmt.Errorf("cannot create Excel styles: %w", err) return nil, fmt.Errorf("cannot create Excel styles: %w", err)
} }
if err := s.setupExcelHeader(f, sheetName, styles); err != nil { if err := s.setupExcelHeader(f, sheetName, styles); err != nil {
return "", fmt.Errorf("cannot setup Excel header: %w", err) return nil, fmt.Errorf("cannot setup Excel header: %w", err)
} }
if err := s.populateExcelData(f, sheetName, soaData, styles); err != nil { if err := s.populateExcelData(f, sheetName, soaData, styles); err != nil {
return "", fmt.Errorf("cannot populate Excel data: %w", err) return nil, fmt.Errorf("cannot populate Excel data: %w", err)
} }
if err := s.applyExcelFormatting(f, sheetName, len(soaData)); err != nil { if err := s.applyExcelFormatting(f, sheetName, len(soaData)); err != nil {
return "", fmt.Errorf("cannot apply Excel formatting: %w", err) return nil, fmt.Errorf("cannot apply Excel formatting: %w", err)
} }
fileName := s.generateSOAFileName(framework) // Write to buffer
excelFilePath := filepath.Join("./", fileName) buffer, err := f.WriteToBuffer()
if err != nil {
if err := f.SaveAs(excelFilePath); err != nil { return nil, fmt.Errorf("cannot write Excel file to buffer: %w", err)
return "", fmt.Errorf("cannot save Excel file: %w", err)
} }
return excelFilePath, nil // Convert to bytes.Reader for seekability (required by S3 SDK)
return bytes.NewReader(buffer.Bytes()), nil
} }
func (s FrameworkService) createExcelStyles(f *excelize.File) (map[string]int, error) { func (s FrameworkService) createExcelStyles(f *excelize.File) (map[string]int, error) {
@@ -998,20 +998,14 @@ func (s FrameworkService) generateSOAFileName(framework *coredata.Framework) str
now.Format("20060102_150405")) now.Format("20060102_150405"))
} }
func (s FrameworkService) uploadSOAToS3(ctx context.Context, framework *coredata.Framework, excelFilePath string) (string, error) { func (s FrameworkService) uploadSOAToS3(ctx context.Context, framework *coredata.Framework, excelReader io.Reader) (string, error) {
file, err := os.Open(excelFilePath)
if err != nil {
return "", fmt.Errorf("cannot open Excel file: %w", err)
}
defer file.Close()
objectKey := fmt.Sprintf("soa/%s/%s", framework.ID, s.generateSOAFileName(framework)) objectKey := fmt.Sprintf("soa/%s/%s", framework.ID, s.generateSOAFileName(framework))
// Upload file to S3 // Upload file to S3 using bytes reader
_, err = s.svc.s3.PutObject(ctx, &s3.PutObjectInput{ _, err := s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(s.svc.bucket), Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey), Key: aws.String(objectKey),
Body: file, Body: excelReader,
}) })
if err != nil { if err != nil {
return "", fmt.Errorf("cannot upload SOA file to S3: %w", err) return "", fmt.Errorf("cannot upload SOA file to S3: %w", err)