diff --git a/apps/backend/.dockerignore b/apps/backend/.dockerignore index 19d2d19..9d7bfab 100644 --- a/apps/backend/.dockerignore +++ b/apps/backend/.dockerignore @@ -1,4 +1,5 @@ images +videos tmp vscode .vscode diff --git a/apps/backend/.gitignore b/apps/backend/.gitignore index f62a31b..0186753 100644 --- a/apps/backend/.gitignore +++ b/apps/backend/.gitignore @@ -1,5 +1,6 @@ tmp images +videos bkp.xml .bin web.config diff --git a/apps/backend/miogest_handler.go b/apps/backend/miogest_handler.go index c763a48..38ab146 100644 --- a/apps/backend/miogest_handler.go +++ b/apps/backend/miogest_handler.go @@ -260,7 +260,7 @@ func extractData_update(annuncio *typesdefs.AnnuncioXML, updateImages bool, upda tmp.Desc_en = annuncio.DescrizioneEn if annuncio.Dettaglio != nil { - disp, parm, pers, err := parser.ParseDettaglio(*annuncio.Dettaglio) + disp, parm, pers, err := parser.ParseDettaglio(*annuncio.Dettaglio, tmp.Consegna) if err == nil { tmp.Disponibile_da = disp tmp.Permanenza = parm diff --git a/apps/backend/parser/parser.go b/apps/backend/parser/parser.go index 4c1a65a..489ac2b 100644 --- a/apps/backend/parser/parser.go +++ b/apps/backend/parser/parser.go @@ -2,38 +2,60 @@ package parser import ( "backend/utils" - "fmt" "regexp" "strconv" "strings" "time" ) -func ParseDettaglio(dettaglio string) (disp_time *string, perm_arr *[]int, persone_arr *[]string, err error) { +func parseDispTime(disp string, currConsegna *int) *string { + if currConsegna == nil { + return nil + } + var day int + var err error + if disp != "" { + //get only the day part from disp + parts := strings.Split(disp, "/") + dayStr := strings.TrimSpace(parts[0]) + + day, err = strconv.Atoi(dayStr) + if err != nil || day < 1 || day > 31 { + // Invalid day, default to 1 + day = 1 + } + } else { + day = 1 + } + month := *currConsegna + currMonth := int(time.Now().Month()) + year := time.Now().Year() + if month < currMonth { + year++ + } + + t := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC) + if t.Day() != day { + // Invalid day for month, default to first day of month + t = time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC) + + } + formatted := t.Format(time.DateOnly) + return &formatted +} + +func ParseDettaglio(dettaglio string, currConsegna *int) (disp_time *string, perm_arr *[]int, persone_arr *[]string, err error) { dettaglio = strings.TrimSpace(dettaglio) - if dettaglio == "" { - return - } - disp := getKeyValueUpToXorWhitespace(dettaglio, "disp:", "perm:") perm := getKeyValueUpToXorWhitespace(dettaglio, "perm:", "persone:") persone := getKeyValueUpToXorWhitespace(dettaglio, "persone:", "") - if disp != "" { - withAnno := fmt.Sprintf("%s/%d", disp, time.Now().Year()) - // Validate date format - t, err := time.Parse("02/01/2006", withAnno) - if err != nil { - disp_time = nil - } else { - formatted := t.Format(time.DateOnly) - disp_time = &formatted - } - } + disp_time = parseDispTime(disp, currConsegna) + if perm != "" { parts := strings.Split(perm, "-") for _, part := range parts { diff --git a/apps/backend/parser/parser_test.go b/apps/backend/parser/parser_test.go index 2cbc301..c0aae2e 100644 --- a/apps/backend/parser/parser_test.go +++ b/apps/backend/parser/parser_test.go @@ -9,201 +9,274 @@ import ( ) func TestParseDettaglio(t *testing.T) { + // Helper to build expected date string + buildExpectedDate := func(day int, month int) string { + year := time.Now().Year() + currMonth := int(time.Now().Month()) + if month < currMonth { + year++ + } + return fmt.Sprintf("%d-%02d-%02d", year, month, day) + } + + consegnaOct := utils.Ptr(10) // October + consegnaFeb := utils.Ptr(2) // February + tests := []struct { - input string - wantDisp *string - wantPerm *[]int - wantPers *[]string + name string + input string + currConsegna *int + wantDisp *string + wantPerm *[]int + wantPers *[]string }{ { - input: "disp:01/10 perm:3-6 persone:single", - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "all fields present", + input: "disp:01/10 perm:3-6 persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp: perm: persone:", - wantDisp: nil, - wantPerm: nil, - wantPers: nil, + name: "all fields empty", + input: "disp: perm: persone:", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), // defaults to 1st + wantPerm: nil, + wantPers: nil, }, { - input: "disp: perm:3-6 persone:single", // disp missing - wantDisp: nil, - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "disp missing value", + input: "disp: perm:3-6 persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), // defaults to 1st + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:01/10 perm: persone:single", // perm missing - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: nil, - wantPers: utils.Ptr([]string{"single"}), + name: "perm missing", + input: "disp:01/10 perm: persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: nil, + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:01/10 perm:3-6 persone:", // persone missing - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: nil, + name: "persone missing", + input: "disp:01/10 perm:3-6 persone:", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: nil, }, { - input: "disp: perm: persone:", // all fields missing - wantDisp: nil, - wantPerm: nil, - wantPers: nil, + name: "invalid date - defaults to 1st", + input: "disp:bad_date perm:3-6 persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), // defaults to 1st + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:bad_date perm:3-6 persone:single", // invalid date - wantDisp: nil, - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "non-numeric perm", + input: "disp:01/10 perm:abc-6 persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:01/10 perm:abc-6 persone:single", // non-numeric perm - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{6}), - wantPers: utils.Ptr([]string{"single"}), + name: "trailing delimiter in perm", + input: "disp:01/10 perm:3- persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:01/10 perm:3- persone:single", // trailing delimiter in perm - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3}), - wantPers: utils.Ptr([]string{"single"}), + name: "leading delimiter in perm", + input: "disp:01/10 perm:-6 persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:01/10 perm:-6 persone:single", // leading delimiter in perm - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{6}), - wantPers: utils.Ptr([]string{"single"}), + name: "trailing delimiter in persone", + input: "disp:01/10 perm:3-6 persone:single/", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:01/10 perm:3-6 persone:single/", // trailing delimiter in persone - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "leading delimiter in persone", + input: "disp:01/10 perm:3-6 persone:/single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:01/10 perm:3-6 persone:/single", // leading delimiter in persone - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "double delimiter in persone", + input: "disp:01/10 perm:3-6 persone:single//coppia", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single", "coppia"}), }, { - input: "disp:01/10 perm:3-6 persone:single//coppia", // double delimiter in persone - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single", "coppia"}), + name: "no disp field", + input: "perm:3-6 persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "perm:3-6 persone:single", // disp missing - wantDisp: nil, - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "no persone field", + input: "disp:01/10 perm:3-6", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: nil, }, { - input: "disp:01/10 perm:3-6", // persone missing - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: nil, + name: "empty string", + input: "", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: nil, + wantPers: nil, }, { - input: "disp:01/10 perm: persone:", // perm empty - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: nil, - wantPers: nil, + name: "whitespace in values", + input: "disp: 01/10 perm: 3-6 persone: single ", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "", // completely empty string - wantDisp: nil, - wantPerm: nil, - wantPers: nil, + name: "different order", + input: "persone:single perm:3-6 disp:01/10", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp: 01/10 perm: 3-6 persone: single ", - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "double dash in perm", + input: "disp:01/10 perm:3--6 persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "persone:single perm:3-6 disp:01/10", - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "tab separators", + input: "disp:01/10\tperm:3-6\tpersone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:01/10 perm:3--6 persone:single", - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "special chars in persone", + input: "disp:01/10 perm:3-6 persone:single/coppia!", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single", "coppia!"}), }, { - input: "disp:01/10\tperm:3-6\tpersone:single", - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "duplicate disp - first wins", + input: "disp:01/10 disp:02/11 perm:3-6 persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:01/10 perm:3-6 persone:single/coppia!", - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single", "coppia!"}), + name: "no spaces between fields", + input: "disp:01/10perm:3-6persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(1, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:01/10 disp:02/11 perm:3-6 persone:single", - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), // Only first disp: is parsed - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "day only in disp", + input: "disp:15 perm:3-6 persone:single", + currConsegna: consegnaOct, + wantDisp: utils.Ptr(buildExpectedDate(15, 10)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, { - input: "disp:01/10perm:3-6persone:single", - wantDisp: utils.Ptr(fmt.Sprintf("01/10/%d", time.Now().Year())), - wantPerm: utils.Ptr([]int{3, 6}), - wantPers: utils.Ptr([]string{"single"}), + name: "invalid day 31 for February", + input: "disp:31 perm:3-6 persone:single", + currConsegna: consegnaFeb, + wantDisp: utils.Ptr(buildExpectedDate(1, 2)), + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), + }, + { + name: "nil currConsegna", + input: "disp:01/10 perm:3-6 persone:single", + currConsegna: nil, + wantDisp: nil, + wantPerm: utils.Ptr([]int{3, 6}), + wantPers: utils.Ptr([]string{"single"}), }, } for _, tt := range tests { - disp_time, perm_arr, persone_arr, _ := parser.ParseDettaglio(tt.input) + t.Run(tt.name, func(t *testing.T) { + disp_time, perm_arr, persone_arr, _ := parser.ParseDettaglio(tt.input, tt.currConsegna) - //Handle *string comparison, including nil - if tt.wantDisp != nil { - if disp_time == nil { - t.Errorf("disp_time: got nil, want %v, input: %v", *tt.wantDisp, tt.input) - } else if *disp_time != *tt.wantDisp { - t.Errorf("disp_time: got %v, want %v, input: %v", *disp_time, *tt.wantDisp, tt.input) + // Handle *string comparison, including nil + if tt.wantDisp != nil { + if disp_time == nil { + t.Errorf("disp_time: got nil, want %v", *tt.wantDisp) + } else if *disp_time != *tt.wantDisp { + t.Errorf("disp_time: got %v, want %v", *disp_time, *tt.wantDisp) + } + } else if disp_time != nil { + t.Errorf("disp_time: got %v, want nil", *disp_time) } - } else if disp_time != nil { - t.Errorf("disp_time: got %v, want nil, input: %v", *disp_time, tt.input) - } - // Handle *[]int comparison, including nil - if tt.wantPerm != nil { - if perm_arr == nil || len(*perm_arr) != len(*tt.wantPerm) { - t.Errorf("perm_arr: got %v, want %v, input: %v", perm_arr, *tt.wantPerm, tt.input) - } else { - for i := range *perm_arr { - if (*perm_arr)[i] != (*tt.wantPerm)[i] { - t.Errorf("perm_arr[%d]: got %v, want %v, input: %v", i, (*perm_arr)[i], (*tt.wantPerm)[i], tt.input) + // Handle *[]int comparison, including nil + if tt.wantPerm != nil { + if perm_arr == nil || len(*perm_arr) != len(*tt.wantPerm) { + t.Errorf("perm_arr: got %v, want %v", perm_arr, *tt.wantPerm) + } else { + for i := range *perm_arr { + if (*perm_arr)[i] != (*tt.wantPerm)[i] { + t.Errorf("perm_arr[%d]: got %v, want %v", i, (*perm_arr)[i], (*tt.wantPerm)[i]) + } } } + } else if perm_arr != nil && len(*perm_arr) != 0 { + t.Errorf("perm_arr: got %v, want nil", perm_arr) } - } else if perm_arr != nil && len(*perm_arr) != 0 { - t.Errorf("perm_arr: got %v, want nil, input: %v", perm_arr, tt.input) - } - // Handle *[]string comparison, including nil - if tt.wantPers != nil { - if persone_arr == nil || len(*persone_arr) != len(*tt.wantPers) { - t.Errorf("persone_arr: got %v, want %v, input: %v", persone_arr, *tt.wantPers, tt.input) - } else { - for i := range *persone_arr { - if (*persone_arr)[i] != (*tt.wantPers)[i] { - t.Errorf("persone_arr[%d]: got %v, want %v, input: %v", i, (*persone_arr)[i], (*tt.wantPers)[i], tt.input) + // Handle *[]string comparison, including nil + if tt.wantPers != nil { + if persone_arr == nil || len(*persone_arr) != len(*tt.wantPers) { + t.Errorf("persone_arr: got %v, want %v", persone_arr, *tt.wantPers) + } else { + for i := range *persone_arr { + if (*persone_arr)[i] != (*tt.wantPers)[i] { + t.Errorf("persone_arr[%d]: got %v, want %v", i, (*persone_arr)[i], (*tt.wantPers)[i]) + } } } + } else if persone_arr != nil && len(*persone_arr) != 0 { + t.Errorf("persone_arr: got %v, want nil", persone_arr) } - } else if persone_arr != nil && len(*persone_arr) != 0 { - t.Errorf("persone_arr: got %v, want nil, input: %v", persone_arr, tt.input) - } + }) } }