From 704b5d27d8de4f3c5f1eabaaebe6d799f1f42e95 Mon Sep 17 00:00:00 2001 From: J Sen Ooi Date: Sun, 17 Dec 2023 19:13:25 +0800 Subject: [PATCH 1/3] Imported files header validation --- .../core/services/reporting/io_sheet.go | 6 +++++ .../internal/core/services/service_items.go | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/backend/internal/core/services/reporting/io_sheet.go b/backend/internal/core/services/reporting/io_sheet.go index 6fb0c9d..1d9c22d 100644 --- a/backend/internal/core/services/reporting/io_sheet.go +++ b/backend/internal/core/services/reporting/io_sheet.go @@ -41,6 +41,12 @@ func (s *IOSheet) indexHeaders() { } } +// Ooi J Sen +// function to return headers from excel sheet +func (s *IOSheet) GetHeaders() []string { + return s.headers +} + func (s *IOSheet) GetColumn(str string) (col int, ok bool) { if s.index == nil { s.indexHeaders() diff --git a/backend/internal/core/services/service_items.go b/backend/internal/core/services/service_items.go index 3ea79e2..a4d5e47 100644 --- a/backend/internal/core/services/service_items.go +++ b/backend/internal/core/services/service_items.go @@ -89,6 +89,20 @@ func serializeLocation[T ~[]string](location T) string { return strings.Join(location, "/") } +// Ooi J Sen +// Function to validate headers +func validateHeaders(expected, actual []string) bool { + if len(expected) != len(actual) { + return false + } + for i := range expected { + if expected[i] != actual[i] { + return false + } + } + return true +} + // CsvImport imports items from a CSV file. using the standard defined format. // // CsvImport applies the following rules/operations @@ -103,6 +117,16 @@ func (svc *ItemService) CsvImport(ctx context.Context, GID uuid.UUID, data io.Re if err != nil { return 0, err } + + // Ooi J Sen + // Access excel sheet headers + headers := sheet.GetHeaders() + + // Validate column headers + expectedHeaders := []string{"HB.import_ref", "HB.location", "HB.labels", "HB.asset_id", "HB.archived", "HB.name", "HB.quantity", "HB.description", "HB.insured", "HB.notes", "HB.purchase_price", "HB.purchase_from", "HB.purchase_time", "HB.manufacturer", "HB.model_number", "HB.serial_number", "HB.lifetime_warranty", "HB.warranty_expires", "HB.warranty_details", "HB.sold_to", "HB.sold_price", "HB.sold_time", "HB.sold_notes",} + if !validateHeaders(expectedHeaders, headers) { + return 0, fmt.Errorf("CSV columns do not match the expected format") + } // ======================================== // Labels From 0d4dc2cc12a4f4f939ca33876f627dc902ffb38b Mon Sep 17 00:00:00 2001 From: J Sen Ooi Date: Sun, 17 Dec 2023 19:48:57 +0800 Subject: [PATCH 2/3] Simple validation for negative values of integer fields --- .../internal/core/services/service_items.go | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/backend/internal/core/services/service_items.go b/backend/internal/core/services/service_items.go index a4d5e47..aae2e01 100644 --- a/backend/internal/core/services/service_items.go +++ b/backend/internal/core/services/service_items.go @@ -185,8 +185,12 @@ func (svc *ItemService) CsvImport(ctx context.Context, GID uuid.UUID, data io.Re finished := 0 + var errorMessage string + for i := range sheet.Rows { row := sheet.Rows[i] + + var hasNegativeValues bool createRequired := true @@ -202,6 +206,25 @@ func (svc *ItemService) CsvImport(ctx context.Context, GID uuid.UUID, data io.Re createRequired = false } } + + // Ooi J Sen + // Check integer fields for negative values + if row.Quantity < 0 { + errorMessage += fmt.Sprintf("Negative quantity at row %d\n", i+1) + hasNegativeValues = true + } + if row.PurchasePrice < 0 { + errorMessage += fmt.Sprintf("Negative purchase price at row %d\n", i+1) + hasNegativeValues = true + } + if row.SoldPrice < 0 { + errorMessage += fmt.Sprintf("Negative sold price at row %d\n", i+1) + hasNegativeValues = true + } + + if (hasNegativeValues) { + continue + } // ======================================== // Pre-Create Labels as necessary @@ -350,6 +373,15 @@ func (svc *ItemService) CsvImport(ctx context.Context, GID uuid.UUID, data io.Re finished++ } + // Ooi J Sen + // Display error messages in console + if errorMessage != "" { + // Log or handle the error message here + fmt.Println("Error Messages:") + fmt.Println(errorMessage) + return 0, fmt.Errorf("Errors detected in CSV:\n%s", errorMessage) + } + return finished, nil } From 703e3283e41018a96596f6568098960d37673ea6 Mon Sep 17 00:00:00 2001 From: J Sen Ooi Date: Tue, 19 Dec 2023 00:21:30 +0800 Subject: [PATCH 3/3] Changes to header validation method --- .../internal/core/services/service_items.go | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/backend/internal/core/services/service_items.go b/backend/internal/core/services/service_items.go index aae2e01..af26427 100644 --- a/backend/internal/core/services/service_items.go +++ b/backend/internal/core/services/service_items.go @@ -92,17 +92,33 @@ func serializeLocation[T ~[]string](location T) string { // Ooi J Sen // Function to validate headers func validateHeaders(expected, actual []string) bool { - if len(expected) != len(actual) { - return false + actualHeaderCount := make(map[string]int) + + // Count occurrences of headers in the actual slice + for _, header := range actual { + actualHeaderCount[header]++ } - for i := range expected { - if expected[i] != actual[i] { + + // Check if all actual headers are within the expected headers + for header, count := range actualHeaderCount { + if count > 0 && !contains(expected, header) { return false } } + return true } +// Function to check if a string slice contains a specific string +func contains(slice []string, str string) bool { + for _, s := range slice { + if s == str { + return true + } + } + return false +} + // CsvImport imports items from a CSV file. using the standard defined format. // // CsvImport applies the following rules/operations