From 129c9c432a6e3bd12782d62088dfa99e5767090a Mon Sep 17 00:00:00 2001 From: Jumpy Squirrel Date: Thu, 12 Dec 2024 10:38:26 +0100 Subject: [PATCH] feat(#239): support allowed_counts configuration, validate config, but do not check it yet --- docs/config-template.yaml | 17 ++++++++++++++++- go.mod | 2 +- internal/repository/config/structure.go | 1 + internal/repository/config/validation.go | 8 ++++++++ internal/repository/config/validation_test.go | 6 +++++- test/acceptance/attendee_acc_test.go | 10 +++++----- test/testconfig-base.yaml | 5 ++++- 7 files changed, 40 insertions(+), 9 deletions(-) diff --git a/docs/config-template.yaml b/docs/config-template.yaml index c1c6fb7..aa8f45c 100644 --- a/docs/config-template.yaml +++ b/docs/config-template.yaml @@ -394,12 +394,27 @@ choices: visible_for: - sponsordesk ultrasponsor: + allowed_counts: + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 8 + - 10 + - 15 + - 20 + - 30 + - 40 + - 50 + - 100 constraint: 'sponsor2' constraint_msg: Only available for supersponsors. description: Ultra Sponsor + max_count: 100 price: 5000 vat_percent: 19 - max_count: 100 visible_for: - regdesk - sponsordesk diff --git a/go.mod b/go.mod index 0dbb12d..843f226 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/eurofurence/reg-attendee-service -go 1.20 +go 1.21 require ( github.com/StephanHCB/go-autumn-logging v0.4.0 diff --git a/internal/repository/config/structure.go b/internal/repository/config/structure.go index 9a34f9b..9be64fd 100644 --- a/internal/repository/config/structure.go +++ b/internal/repository/config/structure.go @@ -124,6 +124,7 @@ type ( } ChoiceConfig struct { + AllowedCounts []int `yaml:"allowed_counts"` // only supported for packages, ignored unless you also set max_count Description string `yaml:"description"` Price int64 `yaml:"price"` VatPercent float64 `yaml:"vat_percent"` diff --git a/internal/repository/config/validation.go b/internal/repository/config/validation.go index 762f316..76e845f 100644 --- a/internal/repository/config/validation.go +++ b/internal/repository/config/validation.go @@ -7,6 +7,7 @@ import ( "github.com/golang-jwt/jwt/v4" "net/url" "os" + "slices" "strings" "time" ) @@ -169,6 +170,13 @@ func validatePackagesConfiguration(errs url.Values, c map[string]ChoiceConfig) { if v.AdminOnly { errs.Add("choices.packages."+k+".admin", "packages cannot be admin_only (they cost money). Try read_only instead.") } + if len(v.AllowedCounts) > 0 { + if v.MaxCount <= 1 { + errs.Add("choices.packages."+k+".allowed_counts", "can only list allowed counts if max_count is set to at least 2") + } else if slices.Max(v.AllowedCounts) > v.MaxCount { + errs.Add("choices.packages."+k+".allowed_counts", "maximum allowed_counts value cannot be larger than max_count for package") + } + } } } diff --git a/internal/repository/config/validation_test.go b/internal/repository/config/validation_test.go index 4177d5b..7372557 100644 --- a/internal/repository/config/validation_test.go +++ b/internal/repository/config/validation_test.go @@ -54,11 +54,15 @@ func TestCheckFlags(t *testing.T) { func TestCheckPackages(t *testing.T) { c := make(map[string]ChoiceConfig) c["myadmin"] = ChoiceConfig{Default: true, AdminOnly: true, Description: "admin only package - invalid"} + c["counttoohigh"] = ChoiceConfig{AllowedCounts: []int{1, 17, 34}, Description: "allowed_counts higher than max_count", MaxCount: 17} + c["maxcountunset"] = ChoiceConfig{AllowedCounts: []int{1, 17, 34}, Description: "allowed_counts but no max_count"} actualErrors := url.Values{} validatePackagesConfiguration(actualErrors, c) expectedErrors := url.Values{ - "choices.packages.myadmin.admin": []string{"packages cannot be admin_only (they cost money). Try read_only instead."}, + "choices.packages.myadmin.admin": []string{"packages cannot be admin_only (they cost money). Try read_only instead."}, + "choices.packages.counttoohigh.allowed_counts": []string{"maximum allowed_counts value cannot be larger than max_count for package"}, + "choices.packages.maxcountunset.allowed_counts": []string{"can only list allowed counts if max_count is set to at least 2"}, } prettyprintedActualErrors, _ := json.MarshalIndent(actualErrors, "", " ") prettyprintedExpectedErrors, _ := json.MarshalIndent(expectedErrors, "", " ") diff --git a/test/acceptance/attendee_acc_test.go b/test/acceptance/attendee_acc_test.go index 40f457e..b480b4f 100644 --- a/test/acceptance/attendee_acc_test.go +++ b/test/acceptance/attendee_acc_test.go @@ -869,13 +869,13 @@ func TestCreateNewAttendee_MultiPackageTooMany(t *testing.T) { docs.When("when they attempt to create a new attendee, adding a package too many times") attendeeSent := tstBuildValidAttendee("na67-") - tstAddPackages(&attendeeSent, "mountain-trip,mountain-trip,mountain-trip") + tstAddPackages(&attendeeSent, "mountain-trip,mountain-trip,mountain-trip,mountain-trip") response := tstPerformPost("/api/rest/v1/attendees", tstRenderJson(attendeeSent), token) docs.Then("then the attempt is rejected as invalid (400) with an appropriate error response") tstRequireErrorResponse(t, response, http.StatusBadRequest, "attendee.data.invalid", url.Values{ - "packages": []string{"package mountain-trip occurs too many times, can occur at most 2 times"}, - "packages_list": []string{"package mountain-trip occurs too many times, can occur at most 2 times"}, + "packages": []string{"package mountain-trip occurs too many times, can occur at most 3 times"}, + "packages_list": []string{"package mountain-trip occurs too many times, can occur at most 3 times"}, }) } @@ -1589,13 +1589,13 @@ func TestUpdateExistingAttendee_AddPackageTooManyTimes(t *testing.T) { docs.When("when they send updated attendee info and try to add a package too many times") changedAttendee := att - tstAddPackages(&changedAttendee, "mountain-trip,mountain-trip,mountain-trip") + tstAddPackages(&changedAttendee, "mountain-trip,mountain-trip,mountain-trip,mountain-trip") changedAttendee.Packages = att.Packages // should be ignored, so let's make it produce no error if used response := tstPerformPut(loc, tstRenderJson(changedAttendee), token) docs.Then("then the request fails with the expected error") tstRequireErrorResponse(t, response, http.StatusBadRequest, "attendee.data.invalid", url.Values{ - "packages_list": []string{"package mountain-trip occurs too many times, can occur at most 2 times"}, + "packages_list": []string{"package mountain-trip occurs too many times, can occur at most 3 times"}, }) } diff --git a/test/testconfig-base.yaml b/test/testconfig-base.yaml index 7abf1d5..4f70adf 100644 --- a/test/testconfig-base.yaml +++ b/test/testconfig-base.yaml @@ -124,10 +124,13 @@ choices: visible_for: - regdesk mountain-trip: + allowed_counts: + - 1 + - 3 description: 'Mountain Trip' price: 3000 vat_percent: 19 - max_count: 2 + max_count: 3 day-thu: description: 'Day Guest (Thursday)' price: 6000