diff --git a/gradle.properties b/gradle.properties index 4c646fb86b..b607e87cdd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,4 +14,4 @@ junitVersion=5.1.0 systemProp.jdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2" # https://jitpack.io/#alfio-event/alf.io-public-frontend -> go to commit tab, set the version -alfioPublicFrontendVersion=48b776bdbc \ No newline at end of file +alfioPublicFrontendVersion=b1ddbe29d9 \ No newline at end of file diff --git a/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java index ea88a69876..eb473472a8 100644 --- a/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java @@ -632,7 +632,7 @@ private static ReservationInfo.BookingInfoTicket toBookingInfoTicket(Ticket tick .map(tfc -> { var tfd = descriptionsByTicketFieldId.get(tfc.getId()).get(0);//take first, temporary! var fieldValue = valueById.get(tfc.getId()); - var t = new TicketFieldConfigurationDescriptionAndValue(tfc, tfd, 1, fieldValue == null ? null : fieldValue.getValue()); + var t = new TicketFieldConfigurationDescriptionAndValue(tfc, tfd, tfc.getCount(), fieldValue == null ? null : fieldValue.getValue()); var descs = fromFieldDescriptions(descriptionsByTicketFieldId.get(t.getTicketFieldConfigurationId())); return toAdditionalField(t, descs); }).collect(Collectors.toList()); diff --git a/src/main/java/alfio/manager/EventManager.java b/src/main/java/alfio/manager/EventManager.java index e2dec8ccff..3c97f3cc3b 100644 --- a/src/main/java/alfio/manager/EventManager.java +++ b/src/main/java/alfio/manager/EventManager.java @@ -25,6 +25,7 @@ import alfio.model.PromoCodeDiscount.DiscountType; import alfio.model.Ticket.TicketStatus; import alfio.model.TicketFieldConfiguration.Context; +import alfio.model.api.v1.admin.EventCreationRequest; import alfio.model.modification.*; import alfio.model.modification.EventModification.AdditionalField; import alfio.model.result.ErrorCode; @@ -239,11 +240,11 @@ private void createAdditionalFields(EventAndOrganizationId event, EventModificat } private static String toSerializedRestrictedValues(EventModification.WithRestrictedValues f) { - return "select".equals(f.getType()) ? generateJsonForList(f.getRestrictedValuesAsString()) : null; + return EventCreationRequest.WITH_RESTRICTED_VALUES.contains(f.getType()) ? generateJsonForList(f.getRestrictedValuesAsString()) : null; } private static String toSerializedDisabledValues(EventModification.WithRestrictedValues f) { - return "select".equals(f.getType()) ? generateJsonForList(f.getDisabledValuesAsString()) : null; + return EventCreationRequest.WITH_RESTRICTED_VALUES.contains(f.getType()) ? generateJsonForList(f.getDisabledValuesAsString()) : null; } private static String generateJsonForList(Collection values) { diff --git a/src/main/java/alfio/model/TicketFieldConfiguration.java b/src/main/java/alfio/model/TicketFieldConfiguration.java index 9b639c3a5c..1d6e511c66 100644 --- a/src/main/java/alfio/model/TicketFieldConfiguration.java +++ b/src/main/java/alfio/model/TicketFieldConfiguration.java @@ -91,6 +91,14 @@ public boolean isSelectField() { return "select".equals(type); } + public int getCount() { + if ("checkbox".equals(type) && this.restrictedValues != null) { + return Math.max(this.restrictedValues.size(), 1); + } else { + return 1; + } + } + public boolean isEuVat() { return "vat:eu".equals(type); } diff --git a/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java b/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java index ec427b8398..66e8129c6d 100644 --- a/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java +++ b/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java @@ -358,7 +358,9 @@ enum AdditionalInfoType { MULTI_LINE_TEXT("textarea"), LIST_BOX("select"), COUNTRY("country"), - EU_VAT_NR("vat:eu"); + EU_VAT_NR("vat:eu"), + CHECKBOX("checkbox"), + RADIO("radio"); private final String code; @@ -368,6 +370,8 @@ enum AdditionalInfoType { } + public static Set WITH_RESTRICTED_VALUES = Set.of(AdditionalInfoType.LIST_BOX.code, AdditionalInfoType.CHECKBOX.code, AdditionalInfoType.RADIO.code); + @Getter @AllArgsConstructor public static class ContentLengthRequest { diff --git a/src/main/java/alfio/util/EventUtil.java b/src/main/java/alfio/util/EventUtil.java index e108d84c95..760505b1c9 100644 --- a/src/main/java/alfio/util/EventUtil.java +++ b/src/main/java/alfio/util/EventUtil.java @@ -207,7 +207,7 @@ public static Function .filter(f -> f.getContext() == ATTENDEE || Optional.ofNullable(f.getAdditionalServiceId()).filter(additionalServiceIds::contains).isPresent()) .filter(f -> CollectionUtils.isEmpty(f.getCategoryIds()) || f.getCategoryIds().contains(ticket.getCategoryId())) .map(f-> { - int count = Math.max(1, Optional.ofNullable(f.getAdditionalServiceId()).map(id -> (int) additionalServiceItems.stream().filter(i -> i.getAdditionalServiceId() == id).count()).orElse(1)); + int count = Math.max(1, Optional.ofNullable(f.getAdditionalServiceId()).map(id -> (int) additionalServiceItems.stream().filter(i -> i.getAdditionalServiceId() == id).count()).orElse(f.getCount())); return new TicketFieldConfigurationDescriptionAndValue(f, descriptions.getOrDefault(f.getId(), TicketFieldDescription.MISSING_FIELD), count, extractor.apply(f)); }) .collect(Collectors.toList()); diff --git a/src/main/java/alfio/util/Validator.java b/src/main/java/alfio/util/Validator.java index 28d0619940..4f40cd2023 100644 --- a/src/main/java/alfio/util/Validator.java +++ b/src/main/java/alfio/util/Validator.java @@ -269,6 +269,12 @@ public static ValidationResult validateTicketAssignment(UpdateTicketOwnerForm fo } List values = Optional.ofNullable(form.getAdditional().get(fieldConf.getName())).orElse(Collections.emptyList()); + + //handle required for multiple choice (checkbox) where required is interpreted as at least one! + if (fieldConf.isRequired() && fieldConf.getCount() > 1 && values.stream().allMatch(StringUtils::isBlank)) { + errors.rejectValue(prefixForLambda + "additional["+fieldConf.getName()+"]", ErrorsCode.EMPTY_FIELD); + } + for(int i = 0; i < values.size(); i++) { String formValue = values.get(i); if(fieldConf.isMaxLengthDefined()) { @@ -284,7 +290,7 @@ public static ValidationResult validateTicketAssignment(UpdateTicketOwnerForm fo "error.restrictedValue", fieldConf.getRestrictedValues(), errors); } - if(fieldConf.isRequired() && StringUtils.isBlank(formValue)){ + if(fieldConf.isRequired() && fieldConf.getCount() == 1 && StringUtils.isBlank(formValue)){ errors.rejectValue(prefixForLambda + "additional["+fieldConf.getName()+"]["+i+"]", ErrorsCode.EMPTY_FIELD); } diff --git a/src/main/webapp/resources/js/admin/feature/event-data-to-collect/edit-field-modal.html b/src/main/webapp/resources/js/admin/feature/event-data-to-collect/edit-field-modal.html index 9fff6adb84..ae100bcdc5 100644 --- a/src/main/webapp/resources/js/admin/feature/event-data-to-collect/edit-field-modal.html +++ b/src/main/webapp/resources/js/admin/feature/event-data-to-collect/edit-field-modal.html @@ -75,7 +75,7 @@

Configuration

-
+
diff --git a/src/main/webapp/resources/js/admin/feature/event-data-to-collect/event-data-to-collect.js b/src/main/webapp/resources/js/admin/feature/event-data-to-collect/event-data-to-collect.js index 76eeb40a8c..cbea9dfca8 100644 --- a/src/main/webapp/resources/js/admin/feature/event-data-to-collect/event-data-to-collect.js +++ b/src/main/webapp/resources/js/admin/feature/event-data-to-collect/event-data-to-collect.js @@ -5,7 +5,9 @@ 'input:text': 'Generic Text Input', 'input:tel': 'Phone Number', 'textarea': 'Multi-line Text', - 'select': 'List Box', + 'select': 'Drop-down list', + 'checkbox': 'Multiple choice (checkbox)', + 'radio': 'One choice list (radio button)', 'country': 'Country', 'vat:eu': 'EU VAT' };