From 6029204fd1d9d55c491b453798302fe534cb912a Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sat, 22 Jun 2019 13:59:24 +0200 Subject: [PATCH 01/29] #657 initial stubs for code-url feature --- .../controller/api/v2/model/EventCode.java | 2 +- .../api/v2/user/EventApiV2Controller.java | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/model/EventCode.java b/src/main/java/alfio/controller/api/v2/model/EventCode.java index 681c000c0d..6ecf0f6f3a 100644 --- a/src/main/java/alfio/controller/api/v2/model/EventCode.java +++ b/src/main/java/alfio/controller/api/v2/model/EventCode.java @@ -30,6 +30,6 @@ public class EventCode { private final String discountAmount; public enum EventCodeType { - @Deprecated SPECIAL_PRICE, DISCOUNT, ACCESS + @Deprecated SPECIAL_PRICE, DISCOUNT, ACCESS, NOT_FOUND } } diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index c231aa38d8..1ed85267de 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -484,7 +484,7 @@ public ResponseEntity> reserveTickets(@PathVariable("e @GetMapping(value = "event/{eventName}/validate-code") public ResponseEntity> validateCode(@PathVariable("eventName") String eventName, - @RequestParam("code") String code) { + @RequestParam("code") String code) { return eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName).map(e -> { var res = checkCode(e, code); @@ -507,6 +507,18 @@ public ResponseEntity> validateCode(@PathVariable(" } + @GetMapping("event/{eventName}/code/{code}") + public void handleCode(@PathVariable("eventName") String eventName, @PathVariable("code") String code) { + String trimmedCode = StringUtils.trimToNull(code); + eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName).map(e -> { + var checkedCode = checkCode(e, trimmedCode); + checkedCode.getValue(); + return null; + }); + } + + + private boolean shouldDisplayRestrictedCategory(Optional specialCode, alfio.model.TicketCategory c, Optional optionalPromoCode) { if(optionalPromoCode.isPresent()) { var promoCode = optionalPromoCode.get(); @@ -573,4 +585,14 @@ private boolean isCaptchaInvalid(String recaptchaResponse, HttpServletRequest re return configurationManager.isRecaptchaForTicketSelectionEnabled(event) && !recaptchaService.checkRecaptcha(recaptchaResponse, request); } + + public static EventCode.EventCodeType from(Optional specialPrice, Optional promoCodeDiscount) { + if (specialPrice.isPresent()) { + return EventCode.EventCodeType.SPECIAL_PRICE; + } else if (promoCodeDiscount.isPresent()) { + return promoCodeDiscount.map(pcd -> pcd.getCodeType() == PromoCodeDiscount.CodeType.ACCESS ? EventCode.EventCodeType.ACCESS : EventCode.EventCodeType.DISCOUNT).orElse(EventCode.EventCodeType.NOT_FOUND); + } else { + return EventCode.EventCodeType.NOT_FOUND; + } + } } From 4351a055a84b268fc7499b5a66bd22ae56290cc6 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sat, 22 Jun 2019 14:16:10 +0200 Subject: [PATCH 02/29] #657 add redirect from old url to api handler --- src/main/java/alfio/controller/IndexController.java | 11 +++++++++++ .../api/v2/user/ReservationFlowIntegrationTest.java | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/src/main/java/alfio/controller/IndexController.java b/src/main/java/alfio/controller/IndexController.java index e87c93fc21..27860d35b1 100644 --- a/src/main/java/alfio/controller/IndexController.java +++ b/src/main/java/alfio/controller/IndexController.java @@ -31,14 +31,17 @@ import org.springframework.security.web.csrf.CsrfToken; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.util.UriComponentsBuilder; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.security.Principal; +import java.util.Map; import static alfio.model.system.ConfigurationKeys.ENABLE_CAPTCHA_FOR_LOGIN; @@ -102,6 +105,14 @@ public void replyToIndex(HttpServletResponse response) throws IOException { } } + @RequestMapping("/event/{eventShortName}/code/{code}") + public String redirectCode(@PathVariable("eventShortName") String eventName, + @PathVariable("code") String code) { + return "redirect:" + UriComponentsBuilder.fromPath("/api/v2/public/event/{eventShortName}/code/{code}") + .build(Map.of("eventShortName", eventName, "code", code)) + .toString(); + } + // login related @RequestMapping(value="/authentication", method = RequestMethod.GET) diff --git a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java index 2fd738ff3b..470068543b 100644 --- a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java @@ -19,6 +19,7 @@ import alfio.TestConfiguration; import alfio.config.DataSourceConfiguration; import alfio.config.Initializer; +import alfio.controller.IndexController; import alfio.controller.api.AttendeeApiController; import alfio.controller.api.admin.AdditionalServiceApiController; import alfio.controller.api.admin.CheckInApiController; @@ -173,6 +174,9 @@ public static class ControllerConfiguration { @Autowired private TicketApiV2Controller ticketApiV2Controller; + + @Autowired + private IndexController indexController; // private Event event; @@ -357,6 +361,9 @@ public void reservationFlowTest() throws Exception { } + assertEquals("redirect:/api/v2/public/event/" + event.getShortName() + "/code/MY_CODE", indexController.redirectCode(event.getShortName(), "MY_CODE")); + + // check ticket & all, we have 2 ticket categories, 1 hidden assertEquals(HttpStatus.NOT_FOUND, eventApiV2Controller.getTicketCategories("NOT_EXISTING", null).getStatusCode()); { From 9df6306d7066e8df25d315fcc5c8c80261c61f0b Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sat, 22 Jun 2019 16:54:40 +0200 Subject: [PATCH 03/29] port old event code handling code #657 --- .../controller/api/v2/model/EventCode.java | 2 +- .../api/v2/user/EventApiV2Controller.java | 49 ++++++++++++++++--- .../repository/TicketCategoryRepository.java | 3 ++ 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/model/EventCode.java b/src/main/java/alfio/controller/api/v2/model/EventCode.java index 6ecf0f6f3a..681c000c0d 100644 --- a/src/main/java/alfio/controller/api/v2/model/EventCode.java +++ b/src/main/java/alfio/controller/api/v2/model/EventCode.java @@ -30,6 +30,6 @@ public class EventCode { private final String discountAmount; public enum EventCodeType { - @Deprecated SPECIAL_PRICE, DISCOUNT, ACCESS, NOT_FOUND + @Deprecated SPECIAL_PRICE, DISCOUNT, ACCESS } } diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index 1ed85267de..302bc67557 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -510,9 +510,32 @@ public ResponseEntity> validateCode(@PathVariable(" @GetMapping("event/{eventName}/code/{code}") public void handleCode(@PathVariable("eventName") String eventName, @PathVariable("code") String code) { String trimmedCode = StringUtils.trimToNull(code); - eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName).map(e -> { + eventRepository.findOptionalByShortName(eventName).map(e -> { + var checkedCode = checkCode(e, trimmedCode); - checkedCode.getValue(); + + var codeType = getCodeType(e.getId(), trimmedCode); + + if(checkedCode.isSuccess() && codeType == CodeType.PROMO_CODE_DISCOUNT) { + return null;//redirectToEvent + } else if(codeType == CodeType.TICKET_CATEGORY_CODE) { + var category = ticketCategoryRepository.findCodeInEvent(e.getId(), trimmedCode).get(); + if(!category.isAccessRestricted()) { + return null; //makeSimpleReservation(eventName, request, redirectAttributes, locale, null, event, category.getId()); + } else { + var specialPrice = specialPriceRepository.findActiveNotAssignedByCategoryId(category.getId()).stream().findFirst(); + if(!specialPrice.isPresent()) { + return null;//redirectToEvent; + } + //savePromoCode(eventName, specialPrice.get().getCode(), model, request.getRequest()); + return null;//makeSimpleReservation(eventName, request, redirectAttributes, locale, specialPrice.get().getCode(), event, category.getId()); + } + } else if (checkedCode.isSuccess() && codeType == CodeType.SPECIAL_PRICE) { + int ticketCategoryId = specialPriceRepository.getByCode(trimmedCode).get().getTicketCategoryId(); + } else { + return null;//redirectToEvent; + } + return null; }); } @@ -586,13 +609,23 @@ private boolean isCaptchaInvalid(String recaptchaResponse, HttpServletRequest re && !recaptchaService.checkRecaptcha(recaptchaResponse, request); } - public static EventCode.EventCodeType from(Optional specialPrice, Optional promoCodeDiscount) { - if (specialPrice.isPresent()) { - return EventCode.EventCodeType.SPECIAL_PRICE; - } else if (promoCodeDiscount.isPresent()) { - return promoCodeDiscount.map(pcd -> pcd.getCodeType() == PromoCodeDiscount.CodeType.ACCESS ? EventCode.EventCodeType.ACCESS : EventCode.EventCodeType.DISCOUNT).orElse(EventCode.EventCodeType.NOT_FOUND); + enum CodeType { + SPECIAL_PRICE, PROMO_CODE_DISCOUNT, TICKET_CATEGORY_CODE, NOT_FOUND + } + + //not happy with that code... + private CodeType getCodeType(int eventId, String code) { + String trimmedCode = StringUtils.trimToNull(code); + if(trimmedCode == null) { + return CodeType.NOT_FOUND; + } else if(specialPriceRepository.getByCode(trimmedCode).isPresent()) { + return CodeType.SPECIAL_PRICE; + } else if (promoCodeRepository.findPromoCodeInEventOrOrganization(eventId, trimmedCode).isPresent()) { + return CodeType.PROMO_CODE_DISCOUNT; + } else if (ticketCategoryRepository.findCodeInEvent(eventId, trimmedCode).isPresent()) { + return CodeType.TICKET_CATEGORY_CODE; } else { - return EventCode.EventCodeType.NOT_FOUND; + return CodeType.NOT_FOUND; } } } diff --git a/src/main/java/alfio/repository/TicketCategoryRepository.java b/src/main/java/alfio/repository/TicketCategoryRepository.java index aedf5cb7f6..0c485f3cb1 100644 --- a/src/main/java/alfio/repository/TicketCategoryRepository.java +++ b/src/main/java/alfio/repository/TicketCategoryRepository.java @@ -63,6 +63,9 @@ AffectedRowCountAndKey insert(@Bind("inception") ZonedDateTime inceptio @Query("select * from ticket_category where id in(:ids)") List findByIds(@Bind("ids") Collection ids); + @Query("select * from ticket_category where event_id = :eventId and category_code = :code and tc_status = 'ACTIVE'") + Optional findCodeInEvent(@Bind("eventId") int eventId, @Bind("code") String code); + @Query("select count(*) from ticket_category where event_id = :eventId and tc_status = 'ACTIVE' and bounded = false") Integer countUnboundedCategoriesByEventId(@Bind("eventId") int eventId); From 5d60c80d806f01da328661f5d965d1fc4257049a Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sat, 22 Jun 2019 17:04:35 +0200 Subject: [PATCH 04/29] refactor: move createticketreservation in a separate method #657 --- .../api/v2/user/EventApiV2Controller.java | 55 +++++++++++-------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index 302bc67557..18a819465d 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -31,6 +31,8 @@ import alfio.manager.i18n.I18nManager; import alfio.manager.system.ConfigurationManager; import alfio.model.*; +import alfio.model.modification.ASReservationWithOptionalCodeModification; +import alfio.model.modification.TicketReservationWithOptionalCodeModification; import alfio.model.modification.support.LocationDescriptor; import alfio.model.result.ValidationResult; import alfio.model.system.Configuration; @@ -448,28 +450,9 @@ public ResponseEntity> reserveTickets(@PathVariable("e bindingResult.reject(ErrorsCode.STEP_2_CAPTCHA_VALIDATION_FAILED); } - var reservationIdRes = reservation.validate(bindingResult, ticketReservationManager, additionalServiceRepository, eventManager, event).flatMap(selected -> { - Date expiration = DateUtils.addMinutes(new Date(), ticketReservationManager.getReservationTimeout(event)); - try { - String reservationId = ticketReservationManager.createTicketReservation(event, - selected.getLeft(), selected.getRight(), expiration, - specialPrice, - promoCodeDiscount, - locale, false); - return Optional.of(reservationId); - } catch (TicketReservationManager.NotEnoughTicketsException nete) { - bindingResult.reject(ErrorsCode.STEP_1_NOT_ENOUGH_TICKETS); - } catch (TicketReservationManager.MissingSpecialPriceTokenException missing) { - bindingResult.reject(ErrorsCode.STEP_1_ACCESS_RESTRICTED); - } catch (TicketReservationManager.InvalidSpecialPriceTokenException invalid) { - bindingResult.reject(ErrorsCode.STEP_1_CODE_NOT_FOUND); - SessionUtil.cleanupSession(request.getRequest()); - } catch (TicketReservationManager.TooManyTicketsForDiscountCodeException tooMany) { - bindingResult.reject(ErrorsCode.STEP_2_DISCOUNT_CODE_USAGE_EXCEEDED); - } - - return Optional.empty(); - }); + var reservationIdRes = reservation.validate(bindingResult, ticketReservationManager, additionalServiceRepository, eventManager, event).flatMap(selected -> + createTicketReservation(bindingResult, request, event, locale, specialPrice, promoCodeDiscount, selected) + ); if (bindingResult.hasErrors()) { return new ResponseEntity<>(ValidatedResponse.toResponse(bindingResult, (String) null), getCorsHeaders(), HttpStatus.UNPROCESSABLE_ENTITY); @@ -482,6 +465,34 @@ public ResponseEntity> reserveTickets(@PathVariable("e return r.orElseGet(() -> ResponseEntity.notFound().build()); } + private Optional createTicketReservation(BindingResult bindingResult, + ServletWebRequest request, + Event event, + Locale locale, + Optional specialPrice, + Optional promoCodeDiscount, + Pair, List> selected) { + Date expiration = DateUtils.addMinutes(new Date(), ticketReservationManager.getReservationTimeout(event)); + try { + String reservationId = ticketReservationManager.createTicketReservation(event, + selected.getLeft(), selected.getRight(), expiration, + specialPrice, + promoCodeDiscount, + locale, false); + return Optional.of(reservationId); + } catch (TicketReservationManager.NotEnoughTicketsException nete) { + bindingResult.reject(ErrorsCode.STEP_1_NOT_ENOUGH_TICKETS); + } catch (TicketReservationManager.MissingSpecialPriceTokenException missing) { + bindingResult.reject(ErrorsCode.STEP_1_ACCESS_RESTRICTED); + } catch (TicketReservationManager.InvalidSpecialPriceTokenException invalid) { + bindingResult.reject(ErrorsCode.STEP_1_CODE_NOT_FOUND); + SessionUtil.cleanupSession(request.getRequest()); + } catch (TicketReservationManager.TooManyTicketsForDiscountCodeException tooMany) { + bindingResult.reject(ErrorsCode.STEP_2_DISCOUNT_CODE_USAGE_EXCEEDED); + } + return Optional.empty(); + } + @GetMapping(value = "event/{eventName}/validate-code") public ResponseEntity> validateCode(@PathVariable("eventName") String eventName, @RequestParam("code") String code) { From f8a1135577d492f7770f03984a613187e02186b9 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sat, 22 Jun 2019 17:33:44 +0200 Subject: [PATCH 05/29] refactor: remove unused payment callback controller #657 --- .../controller/PaymentCallbackController.java | 138 ------------------ 1 file changed, 138 deletions(-) delete mode 100644 src/main/java/alfio/controller/PaymentCallbackController.java diff --git a/src/main/java/alfio/controller/PaymentCallbackController.java b/src/main/java/alfio/controller/PaymentCallbackController.java deleted file mode 100644 index 6535bd344f..0000000000 --- a/src/main/java/alfio/controller/PaymentCallbackController.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * This file is part of alf.io. - * - * alf.io is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * alf.io is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with alf.io. If not, see . - */ -package alfio.controller; - -import alfio.controller.support.SessionUtil; -import alfio.manager.PaymentManager; -import alfio.manager.TicketReservationManager; -import alfio.manager.payment.PaymentSpecification; -import alfio.manager.support.PaymentResult; -import alfio.model.Event; -import alfio.model.OrderSummary; -import alfio.model.TicketReservation; -import alfio.model.TotalPrice; -import alfio.model.transaction.PaymentContext; -import alfio.model.transaction.PaymentMethod; -import alfio.model.transaction.PaymentProxy; -import alfio.model.transaction.capabilities.ExternalProcessing; -import alfio.repository.EventRepository; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.lang3.tuple.Pair; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.util.MultiValueMap; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.servlet.mvc.support.RedirectAttributes; - -import javax.servlet.http.HttpServletRequest; -import java.util.Locale; -import java.util.Optional; - -@Controller -@RequestMapping("/event/{eventName}/reservation/{reservationId}/payment") -@RequiredArgsConstructor -@Log4j2 -public class PaymentCallbackController { - - private static final String REDIRECT_TO_ROOT = "redirect:/"; - private final TicketReservationManager ticketReservationManager; - private final EventRepository eventRepository; - private final PaymentManager paymentManager; - - @RequestMapping("/{paymentMethod}/confirm") - public String confirm(@PathVariable("eventName") String eventName, - @PathVariable("reservationId") String reservationId, - @PathVariable("paymentMethod") String method, - @RequestParam MultiValueMap requestParams, - HttpServletRequest request, - Model model, - BindingResult bindingResult, - RedirectAttributes redirectAttributes) { - - PaymentMethod paymentMethod = PaymentMethod.safeParse(method); - if(paymentMethod == null) { - log.warn("unrecognized payment method received: {}. Redirecting to list", method); - return REDIRECT_TO_ROOT; - } - return getEventAndReservation(eventName, reservationId) - .flatMap(pair -> { - Event event = pair.getLeft(); - TicketReservation reservation = pair.getRight(); - int organizationId = event.getOrganizationId(); - if(paymentManager.getActivePaymentMethods(event).stream().anyMatch(dto -> dto.getPaymentProxy().getPaymentMethod() == paymentMethod)) { - log.warn("Payment method {} is not active for organization {}", method, organizationId); - return Optional.empty(); - } - return paymentManager.lookupProviderByMethod(paymentMethod, new PaymentContext(event)) - .filter(ExternalProcessing.class::isInstance) - .map(provider -> { - TotalPrice reservationCost = ticketReservationManager.totalReservationCostWithVAT(reservationId); - OrderSummary orderSummary = ticketReservationManager.orderSummaryForReservationId(reservationId, event); - PaymentSpecification paymentSpecification = ((ExternalProcessing)provider).getSpecificationFromRequest(event, reservation, reservationCost, orderSummary).apply(requestParams); - - PaymentResult paymentResult = ticketReservationManager.performPayment(paymentSpecification, - reservationCost, - SessionUtil.retrieveSpecialPriceSessionId(request), - Optional.ofNullable(PaymentProxy.fromPaymentMethod(paymentMethod))); - - if(paymentResult.isRedirect()) { - return "redirect:"+paymentResult.getRedirectUrl(); - } - - if(paymentResult.isFailed()) { - bindingResult.reject(paymentResult.getErrorCode().orElse(null)); - SessionUtil.addToFlash(bindingResult, redirectAttributes); - } - - return "redirect:" +ticketReservationManager.reservationUrl(reservationId, event); - }); - }) - .orElse(REDIRECT_TO_ROOT); - - - } - - - @RequestMapping("/{paymentMethod}/cancel") - public String cancel(@PathVariable("eventName") String eventName, - @PathVariable("reservationId") String reservationId, - @PathVariable("paymentMethod") String paymentMethod, - Model model, - BindingResult bindingResult, - RedirectAttributes redirectAttributes) { - - return getEventAndReservation(eventName, reservationId) - .map(pair -> { - bindingResult.reject("error.STEP_2_PAYPAL_unexpected"); - SessionUtil.addToFlash(bindingResult, redirectAttributes); - return "redirect:" +ticketReservationManager.reservationUrl(reservationId, pair.getLeft()); - }) - .orElse(REDIRECT_TO_ROOT); - } - - private Optional> getEventAndReservation(@PathVariable("eventName") String eventName, @PathVariable("reservationId") String reservationId) { - return eventRepository.findOptionalByShortName(eventName) - .map(event -> Pair.of(event, ticketReservationManager.findById(reservationId))) - .filter(pair -> pair.getRight().isPresent()) - .map(pair -> Pair.of(pair.getLeft(), pair.getRight().orElseThrow(IllegalStateException::new))); - } - -} From 1491ad0570e838f6e026a0c1d887eec003c163e6 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sat, 22 Jun 2019 17:37:38 +0200 Subject: [PATCH 06/29] misc refactor: use try with resource --- src/main/java/alfio/controller/FileController.java | 4 +++- .../java/alfio/controller/api/pass/PassKitApiController.java | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/alfio/controller/FileController.java b/src/main/java/alfio/controller/FileController.java index 3664e8d94b..19f35d968f 100644 --- a/src/main/java/alfio/controller/FileController.java +++ b/src/main/java/alfio/controller/FileController.java @@ -54,7 +54,9 @@ public void showFile(@PathVariable("digest") String digest, HttpServletRequest r response.setContentLength(metadata.getContentSize()); response.setHeader("ETag", digest); response.setHeader("Cache-Control", MAX_AGE_6_MONTH); - manager.outputFile(digest, response.getOutputStream()); + try (var os = response.getOutputStream()) { + manager.outputFile(digest, os); + } } } else { response.sendError(HttpServletResponse.SC_NOT_FOUND); diff --git a/src/main/java/alfio/controller/api/pass/PassKitApiController.java b/src/main/java/alfio/controller/api/pass/PassKitApiController.java index 6dfc5f3336..fb088fa90f 100644 --- a/src/main/java/alfio/controller/api/pass/PassKitApiController.java +++ b/src/main/java/alfio/controller/api/pass/PassKitApiController.java @@ -52,9 +52,9 @@ public void getLatestVersion(@PathVariable("eventName") String eventName, response.sendError(HttpServletResponse.SC_NOT_FOUND); } else { Pair pair = validationResult.get(); - try { + try (var os = response.getOutputStream()) { response.setContentType("application/vnd.apple.pkpass"); - passKitManager.writePass(pair.getRight(), pair.getLeft(), response.getOutputStream()); + passKitManager.writePass(pair.getRight(), pair.getLeft(), os); } catch (Exception e) { log.warn("Error during pass generation", e); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); From 92f00f2eaee8a5615ca65f836ad5d943971198af Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sat, 22 Jun 2019 18:00:07 +0200 Subject: [PATCH 07/29] misc cleanup: remove unused code --- src/main/java/alfio/manager/CheckInManager.java | 4 ---- src/main/java/alfio/manager/SpecialPriceManager.java | 1 - .../java/alfio/manager/TicketReservationManager.java | 12 ------------ src/main/java/alfio/manager/WaitingQueueManager.java | 1 - .../java/alfio/manager/support/FeeCalculator.java | 1 - .../java/alfio/manager/system/MailgunMailer.java | 5 ++--- src/main/java/alfio/repository/TicketRepository.java | 4 ---- .../repository/TicketReservationRepository.java | 3 --- .../alfio/repository/UploadedResourceRepository.java | 1 - 9 files changed, 2 insertions(+), 30 deletions(-) diff --git a/src/main/java/alfio/manager/CheckInManager.java b/src/main/java/alfio/manager/CheckInManager.java index 4c5d61f7e2..10099de514 100644 --- a/src/main/java/alfio/manager/CheckInManager.java +++ b/src/main/java/alfio/manager/CheckInManager.java @@ -178,10 +178,6 @@ private Optional findAndLockTicket(String uuid) { return ticketRepository.findByUUIDForUpdate(uuid); } - public List findAllFullTicketInfo(int eventId) { - return ticketRepository.findAllFullTicketInfoAssignedByEventId(eventId); - } - public TicketAndCheckInResult evaluateTicketStatus(int eventId, String ticketIdentifier, Optional ticketCode) { return extractStatus(eventRepository.findOptionalById(eventId), ticketRepository.findOptionalByUUID(ticketIdentifier), ticketIdentifier, ticketCode); } diff --git a/src/main/java/alfio/manager/SpecialPriceManager.java b/src/main/java/alfio/manager/SpecialPriceManager.java index 01ad550374..d2c43521a1 100644 --- a/src/main/java/alfio/manager/SpecialPriceManager.java +++ b/src/main/java/alfio/manager/SpecialPriceManager.java @@ -36,7 +36,6 @@ import java.util.function.Predicate; import java.util.stream.Stream; -import static alfio.model.system.Configuration.from; import static alfio.model.system.ConfigurationKeys.USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL; import static java.util.stream.Collectors.toList; diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index df68b87371..7b8f918018 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -1357,12 +1357,6 @@ public Optional findFirstInReservation(String reservationId) { return ticketRepository.findFirstTicketInReservation(reservationId); } - public List, AdditionalServiceItem>> findAdditionalServicesInReservation(String reservationId) { - return additionalServiceItemRepository.findByReservationUuid(reservationId).stream() - .map(asi -> Triple.of(additionalServiceRepository.getById(asi.getAdditionalServiceId(), asi.getEventId()), additionalServiceTextRepository.findAllByAdditionalServiceId(asi.getAdditionalServiceId()), asi)) - .collect(toList()); - } - public Optional getVAT(EventAndOrganizationId event) { return configurationManager.getFor(event, ConfigurationKeys.VAT_NR).getValue(); } @@ -1722,12 +1716,6 @@ public void validateAndConfirmOfflinePayment(String reservationId, Event event, confirmOfflinePayment(event, reservation.getId(), username); } - private List> fetchWaitingForPayment(int eventId, Event event, Locale locale) { - return ticketReservationRepository.findAllReservationsWaitingForPaymentInEventId(eventId).stream() - .map(id -> Pair.of(ticketReservationRepository.findReservationById(id), orderSummaryForReservationId(id, event))) - .collect(toList()); - } - public List getPendingPayments(String eventName) { return eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName) .map(event -> ticketSearchRepository.findOfflineReservationsWithOptionalTransaction(event.getId())) diff --git a/src/main/java/alfio/manager/WaitingQueueManager.java b/src/main/java/alfio/manager/WaitingQueueManager.java index d8e6d6fe00..c79925e626 100644 --- a/src/main/java/alfio/manager/WaitingQueueManager.java +++ b/src/main/java/alfio/manager/WaitingQueueManager.java @@ -20,7 +20,6 @@ import alfio.model.*; import alfio.model.modification.TicketReservationModification; import alfio.model.modification.TicketReservationWithOptionalCodeModification; -import alfio.model.system.Configuration; import alfio.model.user.Organization; import alfio.repository.EventRepository; import alfio.repository.TicketCategoryRepository; diff --git a/src/main/java/alfio/manager/support/FeeCalculator.java b/src/main/java/alfio/manager/support/FeeCalculator.java index 29a8ee65b9..f1879c0e79 100644 --- a/src/main/java/alfio/manager/support/FeeCalculator.java +++ b/src/main/java/alfio/manager/support/FeeCalculator.java @@ -18,7 +18,6 @@ import alfio.manager.system.ConfigurationManager; import alfio.model.EventAndOrganizationId; -import alfio.model.system.Configuration; import alfio.util.MonetaryUtil; import java.math.BigDecimal; diff --git a/src/main/java/alfio/manager/system/MailgunMailer.java b/src/main/java/alfio/manager/system/MailgunMailer.java index 9b00b94ff0..112a0fce06 100644 --- a/src/main/java/alfio/manager/system/MailgunMailer.java +++ b/src/main/java/alfio/manager/system/MailgunMailer.java @@ -39,7 +39,7 @@ class MailgunMailer implements Mailer { private final ConfigurationManager configurationManager; - private static RequestBody prepareBody(EventAndOrganizationId event, String from, String to, String replyTo, List cc, String subject, String text, + private static RequestBody prepareBody(String from, String to, String replyTo, List cc, String subject, String text, Optional html, Attachment... attachments) { @@ -102,8 +102,7 @@ public void send(EventAndOrganizationId event, String fromName, String to, List< var replyTo = conf.get(MAIL_REPLY_TO).getValueOrDefault(""); - RequestBody formBody = prepareBody(event, from, to, replyTo, cc, subject, text, html, - attachment); + RequestBody formBody = prepareBody(from, to, replyTo, cc, subject, text, html, attachment); Request request = new Request.Builder() .url(baseUrl + domain + "/messages") diff --git a/src/main/java/alfio/repository/TicketRepository.java b/src/main/java/alfio/repository/TicketRepository.java index 0ef4251d07..b6d985fa53 100644 --- a/src/main/java/alfio/repository/TicketRepository.java +++ b/src/main/java/alfio/repository/TicketRepository.java @@ -210,10 +210,6 @@ default void bulkTicketUpdate(List ids, TicketCategory ticketCategory) " inner join tickets_reservation tr on t.tickets_reservation_id = tr.id " + " inner join ticket_category tc on t.category_id = tc.id "; - @Query(FIND_FULL_TICKET_INFO + - " where t.event_id = :eventId and t.full_name is not null and t.email_address is not null order by t.id asc") - List findAllFullTicketInfoAssignedByEventId(@Bind("eventId") int eventId); - @Query(FIND_FULL_TICKET_INFO + " where t.event_id = :eventId and t.full_name is not null and t.email_address is not null and t.id in (:ids) order by t.id asc") List findAllFullTicketInfoAssignedByEventId(@Bind("eventId") int eventId, @Bind("ids") List ids); diff --git a/src/main/java/alfio/repository/TicketReservationRepository.java b/src/main/java/alfio/repository/TicketReservationRepository.java index 5539519270..22234247da 100644 --- a/src/main/java/alfio/repository/TicketReservationRepository.java +++ b/src/main/java/alfio/repository/TicketReservationRepository.java @@ -68,9 +68,6 @@ int postponePayment(@Bind("reservationId") String reservationId, @Bind("validity @Query("update tickets_reservation set full_name = :fullName where id = :reservationId") int updateAssignee(@Bind("reservationId") String reservationId, @Bind("fullName") String fullName); - @Query("select id from tickets_reservation where status = 'OFFLINE_PAYMENT' and event_id_fk = :eventId") - List findAllReservationsWaitingForPaymentInEventId(@Bind("eventId") int eventId); - @Query("select count(id) from tickets_reservation where status = 'OFFLINE_PAYMENT' and event_id_fk = :eventId") Integer findAllReservationsWaitingForPaymentCountInEventId(@Bind("eventId") int eventId); diff --git a/src/main/java/alfio/repository/UploadedResourceRepository.java b/src/main/java/alfio/repository/UploadedResourceRepository.java index 098a9b45ef..0009344d7b 100644 --- a/src/main/java/alfio/repository/UploadedResourceRepository.java +++ b/src/main/java/alfio/repository/UploadedResourceRepository.java @@ -28,7 +28,6 @@ import org.springframework.jdbc.support.lob.DefaultLobHandler; import org.springframework.jdbc.support.lob.LobCreator; import org.springframework.jdbc.support.lob.LobHandler; -import org.springframework.util.StreamUtils; import java.io.IOException; import java.io.InputStream; From 61c8a6ca233d976efdc4f34ceadf3f67b3863ad3 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sun, 23 Jun 2019 13:48:20 +0200 Subject: [PATCH 08/29] #657 remove unused code --- .../api/admin/EventApiController.java | 6 +-- .../controller/api/support/DataLoader.java | 24 ---------- .../api/support/DescriptionsLoader.java | 48 ------------------- 3 files changed, 3 insertions(+), 75 deletions(-) delete mode 100644 src/main/java/alfio/controller/api/support/DataLoader.java delete mode 100644 src/main/java/alfio/controller/api/support/DescriptionsLoader.java diff --git a/src/main/java/alfio/controller/api/admin/EventApiController.java b/src/main/java/alfio/controller/api/admin/EventApiController.java index 16194b0afb..4fad17174f 100644 --- a/src/main/java/alfio/controller/api/admin/EventApiController.java +++ b/src/main/java/alfio/controller/api/admin/EventApiController.java @@ -16,7 +16,6 @@ */ package alfio.controller.api.admin; -import alfio.controller.api.support.DescriptionsLoader; import alfio.controller.api.support.EventListItem; import alfio.controller.api.support.PageAndContent; import alfio.controller.api.support.TicketHelper; @@ -34,6 +33,7 @@ import alfio.model.user.Role; import alfio.model.user.User; import alfio.repository.DynamicFieldTemplateRepository; +import alfio.repository.EventDescriptionRepository; import alfio.repository.SponsorScanRepository; import alfio.repository.TicketFieldRepository; import alfio.util.*; @@ -93,7 +93,7 @@ public class EventApiController { private final I18nManager i18nManager; private final TicketReservationManager ticketReservationManager; private final TicketFieldRepository ticketFieldRepository; - private final DescriptionsLoader descriptionsLoader; + private final EventDescriptionRepository eventDescriptionRepository; private final TicketHelper ticketHelper; private final DynamicFieldTemplateRepository dynamicFieldTemplateRepository; private final UserManager userManager; @@ -138,7 +138,7 @@ public List getAllEventsForExternal(Principal principal, HttpServ return eventManager.getActiveEvents().stream() .filter(e -> userOrganizations.contains(e.getOrganizationId())) .sorted(Comparator.comparing(e -> e.getBegin().withZoneSameInstant(ZoneId.systemDefault()))) - .map(s -> new EventListItem(s, request.getContextPath(), descriptionsLoader.eventDescriptions().load(s))) + .map(s -> new EventListItem(s, request.getContextPath(), eventDescriptionRepository.findByEventId(s.getId()))) .collect(toList()); } diff --git a/src/main/java/alfio/controller/api/support/DataLoader.java b/src/main/java/alfio/controller/api/support/DataLoader.java deleted file mode 100644 index 6d32d27c83..0000000000 --- a/src/main/java/alfio/controller/api/support/DataLoader.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * This file is part of alf.io. - * - * alf.io is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * alf.io is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with alf.io. If not, see . - */ -package alfio.controller.api.support; - -import java.util.List; - -@FunctionalInterface -public interface DataLoader { - List load(I input); -} diff --git a/src/main/java/alfio/controller/api/support/DescriptionsLoader.java b/src/main/java/alfio/controller/api/support/DescriptionsLoader.java deleted file mode 100644 index 2e36ca3e86..0000000000 --- a/src/main/java/alfio/controller/api/support/DescriptionsLoader.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * This file is part of alf.io. - * - * alf.io is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * alf.io is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with alf.io. If not, see . - */ -package alfio.controller.api.support; - -import alfio.model.Event; -import alfio.model.EventDescription; -import alfio.model.TicketCategory; -import alfio.model.TicketCategoryDescription; -import alfio.repository.EventDescriptionRepository; -import alfio.repository.TicketCategoryDescriptionRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - - -@Component -public class DescriptionsLoader { - - private final EventDescriptionRepository eventDescriptionRepository; - private final TicketCategoryDescriptionRepository categoryDescriptionRepository; - - @Autowired - public DescriptionsLoader(EventDescriptionRepository eventDescriptionRepository, TicketCategoryDescriptionRepository categoryDescriptionRepository) { - this.eventDescriptionRepository = eventDescriptionRepository; - this.categoryDescriptionRepository = categoryDescriptionRepository; - } - - public DataLoader eventDescriptions() { - return e -> eventDescriptionRepository.findByEventId(e.getId()); - } - - public DataLoader ticketCategoryDescriptions() { - return c -> categoryDescriptionRepository.findByTicketCategoryId(c.getId()); - } -} From 891667586a6be2de8bcb77757a3d70a87e08eb41 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sun, 23 Jun 2019 14:10:27 +0200 Subject: [PATCH 09/29] #657 refactor createTicketReservation --- .../api/v2/user/EventApiV2Controller.java | 75 ++++++++++++------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index 18a819465d..8d38a93857 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -31,8 +31,7 @@ import alfio.manager.i18n.I18nManager; import alfio.manager.system.ConfigurationManager; import alfio.model.*; -import alfio.model.modification.ASReservationWithOptionalCodeModification; -import alfio.model.modification.TicketReservationWithOptionalCodeModification; +import alfio.model.modification.TicketReservationModification; import alfio.model.modification.support.LocationDescriptor; import alfio.model.result.ValidationResult; import alfio.model.system.Configuration; @@ -49,6 +48,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.ServletWebRequest; @@ -450,9 +450,7 @@ public ResponseEntity> reserveTickets(@PathVariable("e bindingResult.reject(ErrorsCode.STEP_2_CAPTCHA_VALIDATION_FAILED); } - var reservationIdRes = reservation.validate(bindingResult, ticketReservationManager, additionalServiceRepository, eventManager, event).flatMap(selected -> - createTicketReservation(bindingResult, request, event, locale, specialPrice, promoCodeDiscount, selected) - ); + Optional reservationIdRes = createTicketReservation(reservation, bindingResult, request, event, locale, specialPrice, promoCodeDiscount); if (bindingResult.hasErrors()) { return new ResponseEntity<>(ValidatedResponse.toResponse(bindingResult, (String) null), getCorsHeaders(), HttpStatus.UNPROCESSABLE_ENTITY); @@ -465,32 +463,34 @@ public ResponseEntity> reserveTickets(@PathVariable("e return r.orElseGet(() -> ResponseEntity.notFound().build()); } - private Optional createTicketReservation(BindingResult bindingResult, + private Optional createTicketReservation(ReservationForm reservation, + BindingResult bindingResult, ServletWebRequest request, Event event, Locale locale, Optional specialPrice, - Optional promoCodeDiscount, - Pair, List> selected) { - Date expiration = DateUtils.addMinutes(new Date(), ticketReservationManager.getReservationTimeout(event)); - try { - String reservationId = ticketReservationManager.createTicketReservation(event, - selected.getLeft(), selected.getRight(), expiration, - specialPrice, - promoCodeDiscount, - locale, false); - return Optional.of(reservationId); - } catch (TicketReservationManager.NotEnoughTicketsException nete) { - bindingResult.reject(ErrorsCode.STEP_1_NOT_ENOUGH_TICKETS); - } catch (TicketReservationManager.MissingSpecialPriceTokenException missing) { - bindingResult.reject(ErrorsCode.STEP_1_ACCESS_RESTRICTED); - } catch (TicketReservationManager.InvalidSpecialPriceTokenException invalid) { - bindingResult.reject(ErrorsCode.STEP_1_CODE_NOT_FOUND); - SessionUtil.cleanupSession(request.getRequest()); - } catch (TicketReservationManager.TooManyTicketsForDiscountCodeException tooMany) { - bindingResult.reject(ErrorsCode.STEP_2_DISCOUNT_CODE_USAGE_EXCEEDED); - } - return Optional.empty(); + Optional promoCodeDiscount) { + return reservation.validate(bindingResult, ticketReservationManager, additionalServiceRepository, eventManager, event).flatMap(selected -> { + Date expiration = DateUtils.addMinutes(new Date(), ticketReservationManager.getReservationTimeout(event)); + try { + String reservationId = ticketReservationManager.createTicketReservation(event, + selected.getLeft(), selected.getRight(), expiration, + specialPrice, + promoCodeDiscount, + locale, false); + return Optional.of(reservationId); + } catch (TicketReservationManager.NotEnoughTicketsException nete) { + bindingResult.reject(ErrorsCode.STEP_1_NOT_ENOUGH_TICKETS); + } catch (TicketReservationManager.MissingSpecialPriceTokenException missing) { + bindingResult.reject(ErrorsCode.STEP_1_ACCESS_RESTRICTED); + } catch (TicketReservationManager.InvalidSpecialPriceTokenException invalid) { + bindingResult.reject(ErrorsCode.STEP_1_CODE_NOT_FOUND); + SessionUtil.cleanupSession(request.getRequest()); + } catch (TicketReservationManager.TooManyTicketsForDiscountCodeException tooMany) { + bindingResult.reject(ErrorsCode.STEP_2_DISCOUNT_CODE_USAGE_EXCEEDED); + } + return Optional.empty(); + }); } @GetMapping(value = "event/{eventName}/validate-code") @@ -519,7 +519,7 @@ public ResponseEntity> validateCode(@PathVariable(" @GetMapping("event/{eventName}/code/{code}") - public void handleCode(@PathVariable("eventName") String eventName, @PathVariable("code") String code) { + public void handleCode(@PathVariable("eventName") String eventName, @PathVariable("code") String code, ServletWebRequest request) { String trimmedCode = StringUtils.trimToNull(code); eventRepository.findOptionalByShortName(eventName).map(e -> { @@ -543,6 +543,7 @@ public void handleCode(@PathVariable("eventName") String eventName, @PathVariabl } } else if (checkedCode.isSuccess() && codeType == CodeType.SPECIAL_PRICE) { int ticketCategoryId = specialPriceRepository.getByCode(trimmedCode).get().getTicketCategoryId(); + //makeSimpleReservation } else { return null;//redirectToEvent; } @@ -551,6 +552,24 @@ public void handleCode(@PathVariable("eventName") String eventName, @PathVariabl }); } + private Optional makeSimpleReservation(Event event, + Locale locale, + int ticketCategoryId, + String promoCode, + ServletWebRequest request, + Optional specialPrice, + Optional promoCodeDiscount + ) { + ReservationForm form = new ReservationForm(); + form.setPromoCode(promoCode); + TicketReservationModification reservation = new TicketReservationModification(); + reservation.setAmount(1); + reservation.setTicketCategoryId(ticketCategoryId); + form.setReservation(Collections.singletonList(reservation)); + var bindingRes = new BeanPropertyBindingResult(form, "reservationForm"); + return createTicketReservation(form, bindingRes, request, event, locale, specialPrice.map(SpecialPrice::getCode), promoCodeDiscount.map(PromoCodeDiscount::getPromoCode)); + } + private boolean shouldDisplayRestrictedCategory(Optional specialCode, alfio.model.TicketCategory c, Optional optionalPromoCode) { From b97080206c41c91e083fdfddc4fe3c7b36809253 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sun, 23 Jun 2019 14:44:14 +0200 Subject: [PATCH 10/29] #657 fallback locale --- .../api/v2/user/EventApiV2Controller.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index 8d38a93857..5a549128e0 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -42,6 +42,7 @@ import alfio.repository.user.OrganizationRepository; import alfio.util.*; import lombok.AllArgsConstructor; +import org.apache.commons.collections4.IteratorUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.tuple.Pair; @@ -62,6 +63,7 @@ import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import static alfio.model.PromoCodeDiscount.categoriesOrNull; import static alfio.model.system.ConfigurationKeys.*; @@ -553,13 +555,13 @@ public void handleCode(@PathVariable("eventName") String eventName, @PathVariabl } private Optional makeSimpleReservation(Event event, - Locale locale, int ticketCategoryId, String promoCode, ServletWebRequest request, Optional specialPrice, - Optional promoCodeDiscount - ) { + Optional promoCodeDiscount) { + + Locale locale = getMatchingLocale(request, event); ReservationForm form = new ReservationForm(); form.setPromoCode(promoCode); TicketReservationModification reservation = new TicketReservationModification(); @@ -570,7 +572,21 @@ private Optional makeSimpleReservation(Event event, return createTicketReservation(form, bindingRes, request, event, locale, specialPrice.map(SpecialPrice::getCode), promoCodeDiscount.map(PromoCodeDiscount::getPromoCode)); } - + /** + * From a given request, return the best locale for the user + * + * @param request + * @param event + * @return + */ + private static Locale getMatchingLocale(ServletWebRequest request, Event event) { + var allowedLanguages = event.getContentLanguages().stream().map(ContentLanguage::getLanguage).collect(Collectors.toSet()); + var l = request.getNativeRequest(HttpServletRequest.class).getLocales(); + List locales = l != null ? IteratorUtils.toList(l.asIterator()) : Collections.emptyList(); + var selectedLocale = locales.stream().map(Locale::getLanguage).filter(allowedLanguages::contains).findFirst() + .orElseGet(() -> event.getContentLanguages().stream().findFirst().get().getLanguage()); + return LocaleUtil.forLanguageTag(selectedLocale); + } private boolean shouldDisplayRestrictedCategory(Optional specialCode, alfio.model.TicketCategory c, Optional optionalPromoCode) { if(optionalPromoCode.isPresent()) { From 825e499dff8c2913d8c39450c7d7154313776990 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Mon, 24 Jun 2019 15:32:59 +0200 Subject: [PATCH 11/29] enable partially the {code} functionality #657 --- .../api/v2/user/EventApiV2Controller.java | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index 5a549128e0..b0c17810de 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -53,6 +53,7 @@ import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.util.UriComponentsBuilder; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -63,7 +64,6 @@ import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; -import java.util.stream.StreamSupport; import static alfio.model.PromoCodeDiscount.categoriesOrNull; import static alfio.model.system.ConfigurationKeys.*; @@ -452,7 +452,7 @@ public ResponseEntity> reserveTickets(@PathVariable("e bindingResult.reject(ErrorsCode.STEP_2_CAPTCHA_VALIDATION_FAILED); } - Optional reservationIdRes = createTicketReservation(reservation, bindingResult, request, event, locale, specialPrice, promoCodeDiscount); + Optional reservationIdRes = createTicketReservation(reservation, bindingResult, request, event, locale, promoCodeDiscount); if (bindingResult.hasErrors()) { return new ResponseEntity<>(ValidatedResponse.toResponse(bindingResult, (String) null), getCorsHeaders(), HttpStatus.UNPROCESSABLE_ENTITY); @@ -470,14 +470,13 @@ private Optional createTicketReservation(ReservationForm reservation, ServletWebRequest request, Event event, Locale locale, - Optional specialPrice, Optional promoCodeDiscount) { return reservation.validate(bindingResult, ticketReservationManager, additionalServiceRepository, eventManager, event).flatMap(selected -> { Date expiration = DateUtils.addMinutes(new Date(), ticketReservationManager.getReservationTimeout(event)); try { String reservationId = ticketReservationManager.createTicketReservation(event, selected.getLeft(), selected.getRight(), expiration, - specialPrice, + Optional.empty(), //<- FIXME check specialPriceSessionId promoCodeDiscount, locale, false); return Optional.of(reservationId); @@ -521,44 +520,54 @@ public ResponseEntity> validateCode(@PathVariable(" @GetMapping("event/{eventName}/code/{code}") - public void handleCode(@PathVariable("eventName") String eventName, @PathVariable("code") String code, ServletWebRequest request) { + public ResponseEntity handleCode(@PathVariable("eventName") String eventName, @PathVariable("code") String code, ServletWebRequest request) { String trimmedCode = StringUtils.trimToNull(code); - eventRepository.findOptionalByShortName(eventName).map(e -> { + var url = eventRepository.findOptionalByShortName(eventName).flatMap(e -> { var checkedCode = checkCode(e, trimmedCode); var codeType = getCodeType(e.getId(), trimmedCode); + var maybeSpecialPrice = checkedCode.getValue().getLeft(); + var maybePromoCodeDiscount = checkedCode.getValue().getRight(); + if(checkedCode.isSuccess() && codeType == CodeType.PROMO_CODE_DISCOUNT) { - return null;//redirectToEvent + return Optional.empty();//TODO: redirectToEvent with code in query string? } else if(codeType == CodeType.TICKET_CATEGORY_CODE) { var category = ticketCategoryRepository.findCodeInEvent(e.getId(), trimmedCode).get(); if(!category.isAccessRestricted()) { - return null; //makeSimpleReservation(eventName, request, redirectAttributes, locale, null, event, category.getId()); + return makeSimpleReservation(e, category.getId(), trimmedCode, request, maybePromoCodeDiscount); } else { var specialPrice = specialPriceRepository.findActiveNotAssignedByCategoryId(category.getId()).stream().findFirst(); if(!specialPrice.isPresent()) { - return null;//redirectToEvent; + return Optional.empty(); //<- failure? TODO: add error code in query string? } - //savePromoCode(eventName, specialPrice.get().getCode(), model, request.getRequest()); - return null;//makeSimpleReservation(eventName, request, redirectAttributes, locale, specialPrice.get().getCode(), event, category.getId()); + var specialPriceP = specialPrice.get(); + + //<-FIXME currently this case does not work, + // I receive a InvalidSpecialPriceTokenException + return makeSimpleReservation(e, specialPriceP.getTicketCategoryId(), specialPriceP.getCode(), request, maybePromoCodeDiscount); } } else if (checkedCode.isSuccess() && codeType == CodeType.SPECIAL_PRICE) { int ticketCategoryId = specialPriceRepository.getByCode(trimmedCode).get().getTicketCategoryId(); - //makeSimpleReservation + return makeSimpleReservation(e, ticketCategoryId, trimmedCode, request, maybePromoCodeDiscount); } else { - return null;//redirectToEvent; + return Optional.empty(); // <- failure? TODO: add error code in query string? } - - return null; - }); + }).map(reservationId -> + UriComponentsBuilder.fromPath("/event/{eventShortName}/reservation/{reservationId}") + .build(Map.of("eventShortName", eventName, "reservationId", reservationId)) + .toString()) + .orElseGet(() -> + UriComponentsBuilder.fromPath("/event/{eventShortName}").build(Map.of("eventShortName", eventName)).toString() + ); + return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).header(HttpHeaders.LOCATION, url).build(); } private Optional makeSimpleReservation(Event event, int ticketCategoryId, String promoCode, ServletWebRequest request, - Optional specialPrice, Optional promoCodeDiscount) { Locale locale = getMatchingLocale(request, event); @@ -569,7 +578,7 @@ private Optional makeSimpleReservation(Event event, reservation.setTicketCategoryId(ticketCategoryId); form.setReservation(Collections.singletonList(reservation)); var bindingRes = new BeanPropertyBindingResult(form, "reservationForm"); - return createTicketReservation(form, bindingRes, request, event, locale, specialPrice.map(SpecialPrice::getCode), promoCodeDiscount.map(PromoCodeDiscount::getPromoCode)); + return createTicketReservation(form, bindingRes, request, event, locale, promoCodeDiscount.map(PromoCodeDiscount::getPromoCode)); } /** From 52194bc6d52b35dc8cd293a3fabd8185977f1aaa Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Mon, 24 Jun 2019 15:56:31 +0200 Subject: [PATCH 12/29] for {code} functionality: enable the case: restricted category+url code: disabled call to TicketReservationManager.renewSpecialPrice in flow #657 --- .../alfio/controller/api/v2/user/EventApiV2Controller.java | 4 +--- src/main/java/alfio/manager/TicketReservationManager.java | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index b0c17810de..59ac87ae9d 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -543,9 +543,7 @@ public ResponseEntity handleCode(@PathVariable("eventName") String eventNa return Optional.empty(); //<- failure? TODO: add error code in query string? } var specialPriceP = specialPrice.get(); - - //<-FIXME currently this case does not work, - // I receive a InvalidSpecialPriceTokenException + // <- work only when TicketReservationManager.renewSpecialPrice is commented out return makeSimpleReservation(e, specialPriceP.getTicketCategoryId(), specialPriceP.getCode(), request, maybePromoCodeDiscount); } } else if (checkedCode.isSuccess() && codeType == CodeType.SPECIAL_PRICE) { diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index 7b8f918018..df03715aaa 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -406,7 +406,7 @@ Optional fixToken(Optional token, int ticketCategory return Optional.empty(); } - Optional specialPrice = renewSpecialPrice(token, specialPriceSessionId); + Optional specialPrice = token;//renewSpecialPrice(token, specialPriceSessionId); if(token.isPresent() && specialPrice.isEmpty()) { //there is a special price in the request but this isn't valid anymore @@ -1320,7 +1320,7 @@ public Optional getSpecialPriceByCode(String code) { return specialPriceRepository.getByCode(code); } - public Optional renewSpecialPrice(Optional specialPrice, Optional specialPriceSessionId) { + /*public Optional renewSpecialPrice(Optional specialPrice, Optional specialPriceSessionId) { Validate.isTrue(specialPrice.isPresent(), "special price is not present"); SpecialPrice price = specialPrice.get(); @@ -1347,7 +1347,7 @@ public Optional renewSpecialPrice(Optional specialPr } return specialPrice; - } + }*/ public List findTicketsInReservation(String reservationId) { return ticketRepository.findTicketsInReservation(reservationId); From ad3cedc4a8ecf9c76583a710d830a5fb6c55f56c Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Mon, 24 Jun 2019 16:46:44 +0200 Subject: [PATCH 13/29] disable tests #657 --- .../manager/TicketReservationManagerTest.java | 36 ++++--------------- 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/src/test/java/alfio/manager/TicketReservationManagerTest.java b/src/test/java/alfio/manager/TicketReservationManagerTest.java index 74b83bac89..bb6e66cf5e 100644 --- a/src/test/java/alfio/manager/TicketReservationManagerTest.java +++ b/src/test/java/alfio/manager/TicketReservationManagerTest.java @@ -518,28 +518,6 @@ void neverReturnADateInThePast() { // } //fix token - @Test - void doNothingIfPrerequisitesAreNotSatisfied() { - //do nothing if the category is not restricted - assertFalse(trm.fixToken(Optional.empty(), TICKET_CATEGORY_ID, EVENT_ID, Optional.empty(), mock(TicketReservationWithOptionalCodeModification.class)).isPresent()); - //do nothing if special price status is pending and sessionId don't match - assertFalse(trm.renewSpecialPrice(Optional.of(specialPrice), Optional.empty()).isPresent()); - //do nothing if special price status is pending and sessionId don't match - when(specialPrice.getStatus()).thenReturn(SpecialPrice.Status.PENDING); - when(specialPrice.getSessionIdentifier()).thenReturn("another-id"); - assertFalse(trm.renewSpecialPrice(Optional.of(specialPrice), Optional.of(SPECIAL_PRICE_SESSION_ID)).isPresent()); - } - - @Test - void renewSpecialPrice() { - when(ticketCategory.isAccessRestricted()).thenReturn(true); - when(specialPrice.getStatus()).thenReturn(SpecialPrice.Status.FREE); - when(specialPriceRepository.getByCode(eq(SPECIAL_PRICE_CODE))).thenReturn(Optional.of(specialPrice)); - Optional renewed = trm.renewSpecialPrice(Optional.of(specialPrice), Optional.of(SPECIAL_PRICE_SESSION_ID)); - verify(specialPriceRepository).bindToSession(eq(SPECIAL_PRICE_ID), eq(SPECIAL_PRICE_SESSION_ID), isNull()); - assertTrue(renewed.isPresent()); - assertSame(specialPrice, renewed.get()); - } @Test void reserveTicketsForCategoryWithAccessCode() { @@ -585,14 +563,12 @@ void cancelPendingReservationAndRenewCode() { when(specialPriceRepository.getByCode(eq(SPECIAL_PRICE_CODE))).thenReturn(Optional.of(specialPrice)); when(specialPrice.getStatus()).thenReturn(SpecialPrice.Status.PENDING); when(specialPrice.getSessionIdentifier()).thenReturn(SPECIAL_PRICE_SESSION_ID); - Optional renewed = trm.renewSpecialPrice(Optional.of(specialPrice), Optional.of(SPECIAL_PRICE_SESSION_ID)); - verify(specialPriceRepository).resetToFreeAndCleanupForReservation(eq(singletonList(RESERVATION_ID))); - verify(ticketRepository).resetCategoryIdForUnboundedCategories(eq(singletonList(RESERVATION_ID))); - verify(ticketRepository).releaseExpiredTicket(eq(RESERVATION_ID), eq(EVENT_ID), eq(TICKET_ID), anyString()); - verify(ticketReservationRepository).remove(eq(singletonList(RESERVATION_ID))); - verify(waitingQueueManager).fireReservationExpired(eq(RESERVATION_ID)); - assertTrue(renewed.isPresent()); - assertSame(specialPrice, renewed.get()); + //verify(specialPriceRepository).resetToFreeAndCleanupForReservation(eq(singletonList(RESERVATION_ID))); + //verify(ticketRepository).resetCategoryIdForUnboundedCategories(eq(singletonList(RESERVATION_ID))); + //verify(ticketRepository).releaseExpiredTicket(eq(RESERVATION_ID), eq(EVENT_ID), eq(TICKET_ID), anyString()); + //verify(ticketReservationRepository).remove(eq(singletonList(RESERVATION_ID))); + //verify(waitingQueueManager).fireReservationExpired(eq(RESERVATION_ID)); + //FIXME, this test is most probably broken } //reserve tickets for category From 48e2a3880b32b660751c3aabf0df17238b18ad0b Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Mon, 24 Jun 2019 17:06:07 +0200 Subject: [PATCH 14/29] add integration test for {code} for hidden category #657 --- .../user/ReservationFlowIntegrationTest.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java index 470068543b..c99163517c 100644 --- a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java @@ -33,6 +33,7 @@ import alfio.manager.CheckInManager; import alfio.manager.EventManager; import alfio.manager.EventStatisticsManager; +import alfio.manager.SpecialPriceTokenGenerator; import alfio.manager.support.CheckInStatus; import alfio.manager.support.TicketAndCheckInResult; import alfio.manager.user.UserManager; @@ -67,6 +68,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -145,6 +147,9 @@ public static class ControllerConfiguration { @Autowired private AdditionalServiceApiController additionalServiceApiController; + @Autowired + private SpecialPriceTokenGenerator specialPriceTokenGenerator; + // @Autowired private CheckInApiController checkInApiController; @@ -190,6 +195,8 @@ public static class ControllerConfiguration { private static final String HIDDEN_CODE = "HIDDENNN"; + private static final String URL_CODE_HIDDEN = "CODE_CODE_CODE"; + private int hiddenCategoryId = Integer.MIN_VALUE; public void ensureConfiguration() { @@ -203,7 +210,7 @@ public void ensureConfiguration() { new TicketCategoryModification(null, "hidden", 2, new DateTimeModification(LocalDate.now().minusDays(1), LocalTime.now()), new DateTimeModification(LocalDate.now().plusDays(1), LocalTime.now()), - DESCRIPTION, BigDecimal.ONE, true, "", true, null, null, null, null, null) + DESCRIPTION, BigDecimal.ONE, true, "", true, URL_CODE_HIDDEN, null, null, null, null) ); Pair eventAndUser = initEvent(categories, organizationRepository, userManager, eventManager, eventRepository); @@ -258,6 +265,8 @@ public void ensureConfiguration() { configurationRepository.insertEventLevel(event.getOrganizationId(), event.getId(), ConfigurationKeys.ENABLE_WAITING_QUEUE.getValue(), "true", ""); configurationRepository.insertEventLevel(event.getOrganizationId(), event.getId(), ConfigurationKeys.ENABLE_PRE_REGISTRATION.getValue(), "true", ""); // + + specialPriceTokenGenerator.generatePendingCodes(); } @Test @@ -450,6 +459,16 @@ public void reservationFlowTest() throws Exception { } // + // check reservation auto creation with code: TODO: will need to check all the flows + { + var res = eventApiV2Controller.handleCode(event.getShortName(), URL_CODE_HIDDEN, new ServletWebRequest(new MockHttpServletRequest(), new MockHttpServletResponse())); + var reservationId = res.getHeaders().getLocation().toString().substring(("/event/" + event.getShortName() + "/reservation/").length()); + var reservationInfo = reservationApiV2Controller.getReservationInfo(event.getShortName(), reservationId, new MockHttpSession()); + assertEquals(HttpStatus.OK, reservationInfo.getStatusCode()); + assertEquals(reservationId, reservationInfo.getBody().getId()); + reservationApiV2Controller.cancelPendingReservation(event.getShortName(), reservationId, new MockHttpServletRequest()); + } + // discount check { From b6ae7d2e4f733ecfd865a14a433095d61076dc93 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Mon, 24 Jun 2019 17:09:54 +0200 Subject: [PATCH 15/29] integration test: special price repository: check count #657 --- .../api/v2/user/ReservationFlowIntegrationTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java index c99163517c..1c5ee3903c 100644 --- a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java @@ -150,6 +150,9 @@ public static class ControllerConfiguration { @Autowired private SpecialPriceTokenGenerator specialPriceTokenGenerator; + @Autowired + private SpecialPriceRepository specialPriceRepository; + // @Autowired private CheckInApiController checkInApiController; @@ -461,12 +464,20 @@ public void reservationFlowTest() throws Exception { // check reservation auto creation with code: TODO: will need to check all the flows { + + assertEquals(2, specialPriceRepository.findActiveNotAssignedByCategoryId(hiddenCategoryId).size()); + var res = eventApiV2Controller.handleCode(event.getShortName(), URL_CODE_HIDDEN, new ServletWebRequest(new MockHttpServletRequest(), new MockHttpServletResponse())); var reservationId = res.getHeaders().getLocation().toString().substring(("/event/" + event.getShortName() + "/reservation/").length()); var reservationInfo = reservationApiV2Controller.getReservationInfo(event.getShortName(), reservationId, new MockHttpSession()); assertEquals(HttpStatus.OK, reservationInfo.getStatusCode()); assertEquals(reservationId, reservationInfo.getBody().getId()); + + assertEquals(1, specialPriceRepository.findActiveNotAssignedByCategoryId(hiddenCategoryId).size()); + reservationApiV2Controller.cancelPendingReservation(event.getShortName(), reservationId, new MockHttpServletRequest()); + + assertEquals(2, specialPriceRepository.findActiveNotAssignedByCategoryId(hiddenCategoryId).size()); } From 94663bc04a3c7909023ee09b02d6f082128d461f Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Mon, 24 Jun 2019 17:34:44 +0200 Subject: [PATCH 16/29] handle #671 --- .../manager/AdminReservationManager.java | 3 +++ .../repository/SpecialPriceRepository.java | 5 ++++ .../user/ReservationFlowIntegrationTest.java | 27 +++++++++++++++---- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/main/java/alfio/manager/AdminReservationManager.java b/src/main/java/alfio/manager/AdminReservationManager.java index 000891df52..579b855f25 100644 --- a/src/main/java/alfio/manager/AdminReservationManager.java +++ b/src/main/java/alfio/manager/AdminReservationManager.java @@ -656,6 +656,8 @@ private Result> removeReservation(String eventNam TicketReservation reservation = res.getLeft(); List tickets = res.getMiddle(); + specialPriceRepository.resetToFreeAndCleanupForReservation(List.of(reservationId)); + removeTicketsFromReservation(reservation, e, tickets.stream().map(Ticket::getId).collect(toList()), notify, username, removeReservation, false); additionalServiceItemRepository.updateItemsStatusWithReservationUUID(reservation.getId(), AdditionalServiceItem.AdditionalServiceItemStatus.CANCELLED); @@ -713,6 +715,7 @@ private void removeTicketsFromReservation(TicketReservation reservation, Event e ticketRepository.resetCategoryIdForUnboundedCategoriesWithTicketIds(ticketIds); ticketFieldRepository.deleteAllValuesForTicketIds(ticketIds); + specialPriceRepository.resetToFreeAndCleanupForTickets(ticketIds); List reservationIds = ticketRepository.findReservationIds(ticketIds); List ticketUUIDs = ticketRepository.findUUIDs(ticketIds); diff --git a/src/main/java/alfio/repository/SpecialPriceRepository.java b/src/main/java/alfio/repository/SpecialPriceRepository.java index 64f3ade7da..a2515f4761 100644 --- a/src/main/java/alfio/repository/SpecialPriceRepository.java +++ b/src/main/java/alfio/repository/SpecialPriceRepository.java @@ -88,6 +88,11 @@ public interface SpecialPriceRepository { "or access_code_id_fk in (select promo_code_id_fk from tickets_reservation where id in (:reservationIds))") int resetToFreeAndCleanupForReservation(@Bind("reservationIds") List reservationIds); + + @Query("update special_price set status = 'FREE', session_id = null, sent_ts = null, recipient_name = null, recipient_email = null, access_code_id_fk = null " + + " where id in (select special_price_id_fk from ticket where ticket.id in (:ticketIds) and special_price_id_fk is not null) ") + int resetToFreeAndCleanupForTickets(@Bind("ticketIds") List ticketIds); + @Query("update special_price set code = :code, status = 'FREE', sent_ts = null where id = :id") int updateCode(@Bind("code") String code, @Bind("id") int id); diff --git a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java index 1c5ee3903c..e5c685b3f6 100644 --- a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java @@ -30,10 +30,7 @@ import alfio.controller.api.v2.model.EventCode; import alfio.controller.api.v2.model.Language; import alfio.controller.form.*; -import alfio.manager.CheckInManager; -import alfio.manager.EventManager; -import alfio.manager.EventStatisticsManager; -import alfio.manager.SpecialPriceTokenGenerator; +import alfio.manager.*; import alfio.manager.support.CheckInStatus; import alfio.manager.support.TicketAndCheckInResult; import alfio.manager.user.UserManager; @@ -165,6 +162,9 @@ public static class ControllerConfiguration { @Autowired private ScanAuditRepository scanAuditRepository; + + @Autowired + private AdminReservationManager adminReservationManager; // // @@ -466,7 +466,6 @@ public void reservationFlowTest() throws Exception { { assertEquals(2, specialPriceRepository.findActiveNotAssignedByCategoryId(hiddenCategoryId).size()); - var res = eventApiV2Controller.handleCode(event.getShortName(), URL_CODE_HIDDEN, new ServletWebRequest(new MockHttpServletRequest(), new MockHttpServletResponse())); var reservationId = res.getHeaders().getLocation().toString().substring(("/event/" + event.getShortName() + "/reservation/").length()); var reservationInfo = reservationApiV2Controller.getReservationInfo(event.getShortName(), reservationId, new MockHttpSession()); @@ -480,6 +479,24 @@ public void reservationFlowTest() throws Exception { assertEquals(2, specialPriceRepository.findActiveNotAssignedByCategoryId(hiddenCategoryId).size()); } + // check reservation auto creation with deletion from the admin side + { + + assertEquals(2, specialPriceRepository.findActiveNotAssignedByCategoryId(hiddenCategoryId).size()); + var res = eventApiV2Controller.handleCode(event.getShortName(), URL_CODE_HIDDEN, new ServletWebRequest(new MockHttpServletRequest(), new MockHttpServletResponse())); + var reservationId = res.getHeaders().getLocation().toString().substring(("/event/" + event.getShortName() + "/reservation/").length()); + var reservationInfo = reservationApiV2Controller.getReservationInfo(event.getShortName(), reservationId, new MockHttpSession()); + assertEquals(HttpStatus.OK, reservationInfo.getStatusCode()); + assertEquals(reservationId, reservationInfo.getBody().getId()); + + assertEquals(1, specialPriceRepository.findActiveNotAssignedByCategoryId(hiddenCategoryId).size()); + + adminReservationManager.removeReservation(event.getShortName(), reservationId, false, false, user); + + assertEquals(2, specialPriceRepository.findActiveNotAssignedByCategoryId(hiddenCategoryId).size()); + + } + // discount check { From 68d857b150fa8506a887a172414067a42a467bab Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Mon, 24 Jun 2019 21:46:30 +0200 Subject: [PATCH 17/29] refactor: remove specialPriceSessionId parameter #657 --- .../api/v2/user/EventApiV2Controller.java | 1 - .../manager/TicketReservationManager.java | 36 ++----------------- .../WaitingQueueSubscriptionProcessor.java | 1 - ...dminReservationManagerIntegrationTest.java | 2 +- .../manager/EventManagerIntegrationTest.java | 2 +- .../manager/GroupManagerIntegrationTest.java | 4 +-- ...cketReservationManagerIntegrationTest.java | 32 ++++++++--------- .../manager/TicketReservationManagerTest.java | 10 +++--- .../WaitingQueueManagerIntegrationTest.java | 12 +++---- ...WaitingQueueSubscriptionProcessorTest.java | 4 +-- .../system/DataMigratorIntegrationTest.java | 6 ++-- 11 files changed, 39 insertions(+), 71 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index 59ac87ae9d..1a9cb387ba 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -476,7 +476,6 @@ private Optional createTicketReservation(ReservationForm reservation, try { String reservationId = ticketReservationManager.createTicketReservation(event, selected.getLeft(), selected.getRight(), expiration, - Optional.empty(), //<- FIXME check specialPriceSessionId promoCodeDiscount, locale, false); return Optional.of(reservationId); diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index df03715aaa..acb8d653e5 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -234,7 +234,6 @@ public String createTicketReservation(Event event, List list, List additionalServices, Date reservationExpiration, - Optional specialPriceSessionId, Optional promotionCodeDiscount, Locale locale, boolean forWaitingQueue) throws NotEnoughTicketsException, MissingSpecialPriceTokenException, InvalidSpecialPriceTokenException { @@ -249,7 +248,7 @@ public String createTicketReservation(Event event, event.getId(), event.getVat(), event.isVatIncluded()); - list.forEach(t -> reserveTicketsForCategory(event, specialPriceSessionId, reservationId, t, locale, forWaitingQueue, discount.orElse(null))); + list.forEach(t -> reserveTicketsForCategory(event, reservationId, t, locale, forWaitingQueue, discount.orElse(null))); int ticketCount = list .stream() @@ -293,7 +292,7 @@ public Pair, Integer> findAllReservationsInEvent(int eve return Pair.of(reservationsForEvent, ticketSearchRepository.countReservationsForEvent(eventId, toSearch, toFilter)); } - void reserveTicketsForCategory(Event event, Optional specialPriceSessionId, String reservationId, TicketReservationWithOptionalCodeModification ticketReservation, Locale locale, boolean forWaitingQueue, PromoCodeDiscount discount) { + void reserveTicketsForCategory(Event event, String reservationId, TicketReservationWithOptionalCodeModification ticketReservation, Locale locale, boolean forWaitingQueue, PromoCodeDiscount discount) { List specialPrices; if(discount != null && discount.getCodeType() == PromoCodeDiscount.CodeType.ACCESS @@ -303,7 +302,7 @@ void reserveTicketsForCategory(Event event, Optional specialPriceSession specialPrices = reserveTokens(reservationId, ticketReservation, discount); } else { //first check if there is another pending special price token bound to the current sessionId - Optional specialPrice = fixToken(ticketReservation.getSpecialPrice(), ticketReservation.getTicketCategoryId(), event.getId(), specialPriceSessionId, ticketReservation); + Optional specialPrice = fixToken(ticketReservation.getSpecialPrice(), ticketReservation.getTicketCategoryId(), event.getId(), Optional.empty(), ticketReservation); specialPrices = specialPrice.stream().collect(toList()); } @@ -1320,35 +1319,6 @@ public Optional getSpecialPriceByCode(String code) { return specialPriceRepository.getByCode(code); } - /*public Optional renewSpecialPrice(Optional specialPrice, Optional specialPriceSessionId) { - Validate.isTrue(specialPrice.isPresent(), "special price is not present"); - - SpecialPrice price = specialPrice.get(); - - if(specialPriceSessionId.isEmpty()) { - log.warn("cannot renew special price {}: session identifier not found or not matching", price.getCode()); - return Optional.empty(); - } - - if(price.getStatus() == Status.PENDING && !StringUtils.equals(price.getSessionIdentifier(), specialPriceSessionId.get())) { - log.warn("cannot renew special price {}: session identifier not found or not matching", price.getCode()); - return Optional.empty(); - } - - if(price.getStatus() == Status.FREE) { - specialPriceRepository.bindToSession(price.getId(), specialPriceSessionId.get(), null); - return getSpecialPriceByCode(price.getCode()); - } else if(price.getStatus() == Status.PENDING) { - Optional optionalTicket = ticketRepository.findBySpecialPriceId(price.getId()); - if(optionalTicket.isPresent()) { - cancelPendingReservation(optionalTicket.get().getTicketsReservationId(), false, null); - return getSpecialPriceByCode(price.getCode()); - } - } - - return specialPrice; - }*/ - public List findTicketsInReservation(String reservationId) { return ticketRepository.findTicketsInReservation(reservationId); } diff --git a/src/main/java/alfio/manager/WaitingQueueSubscriptionProcessor.java b/src/main/java/alfio/manager/WaitingQueueSubscriptionProcessor.java index 55944a16ee..0e59f40c9c 100644 --- a/src/main/java/alfio/manager/WaitingQueueSubscriptionProcessor.java +++ b/src/main/java/alfio/manager/WaitingQueueSubscriptionProcessor.java @@ -133,7 +133,6 @@ private String createReservation(Event event, TicketReservationWithOptionalCodeM return ticketReservationManager.createTicketReservation(event, Collections.singletonList(reservation), Collections.emptyList(), Date.from(expiration.toInstant()), Optional.empty(), - Optional.empty(), locale, true); } diff --git a/src/test/java/alfio/manager/AdminReservationManagerIntegrationTest.java b/src/test/java/alfio/manager/AdminReservationManagerIntegrationTest.java index db670d61b4..161bd6fb6c 100644 --- a/src/test/java/alfio/manager/AdminReservationManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/AdminReservationManagerIntegrationTest.java @@ -306,7 +306,7 @@ private Triple performExistingCategoryTest(Lis trm.setAmount(reservedTickets); trm.setTicketCategoryId(existingCategories.get(0).getId()); TicketReservationWithOptionalCodeModification r = new TicketReservationWithOptionalCodeModification(trm, Optional.empty()); - ticketReservationManager.createTicketReservation(event, Collections.singletonList(r), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + ticketReservationManager.createTicketReservation(event, Collections.singletonList(r), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); } Result>> result = adminReservationManager.createReservation(modification, event.getShortName(), username); diff --git a/src/test/java/alfio/manager/EventManagerIntegrationTest.java b/src/test/java/alfio/manager/EventManagerIntegrationTest.java index eb66f78bde..d487bc9d91 100644 --- a/src/test/java/alfio/manager/EventManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/EventManagerIntegrationTest.java @@ -682,7 +682,7 @@ public void testNewBoundedCategoryWithExistingBoundedAndPendingTicket() { trm.setTicketCategoryId(ticketCategoryRepository.findByEventId(event.getId()).get(0).getId()); TicketReservationWithOptionalCodeModification reservation = new TicketReservationWithOptionalCodeModification(trm, Optional.empty()); ticketReservationManager.createTicketReservation(event, Collections.singletonList(reservation), Collections.emptyList(), - DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); TicketCategoryModification tcm = new TicketCategoryModification(null, "new", 1, DateTimeModification.fromZonedDateTime(ZonedDateTime.now()), DateTimeModification.fromZonedDateTime(ZonedDateTime.now().plusDays(1)), diff --git a/src/test/java/alfio/manager/GroupManagerIntegrationTest.java b/src/test/java/alfio/manager/GroupManagerIntegrationTest.java index 9674f08013..e6dc3cd840 100644 --- a/src/test/java/alfio/manager/GroupManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/GroupManagerIntegrationTest.java @@ -123,7 +123,7 @@ public void testLinkToEvent() { ticketReservation.setTicketCategoryId(categoryId); String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(new TicketReservationWithOptionalCodeModification(ticketReservation, Optional.empty())), - Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); Ticket ticket = ticketRepository.findFirstTicketInReservation(reservationId).orElseThrow(NullPointerException::new); ticketRepository.updateTicketOwnerById(ticket.getId(), "test@test.ch", "This is a Test", "This is", "a Test"); @@ -132,7 +132,7 @@ public void testLinkToEvent() { assertTrue("cannot confirm ticket", groupManager.acquireMemberForTicket(ticket)); reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(new TicketReservationWithOptionalCodeModification(ticketReservation, Optional.empty())), - Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); ticket = ticketRepository.findFirstTicketInReservation(reservationId).orElseThrow(NullPointerException::new); assertFalse("shouldn't be allowed", groupManager.acquireMemberForTicket(ticket)); diff --git a/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java b/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java index 7bd0ca32e2..bc70af652e 100644 --- a/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java @@ -119,7 +119,7 @@ public void testPriceIsOverridden() { TicketCategory category = ticketCategoryRepository.findByEventId(event.getId()).get(0); tr.setTicketCategoryId(category.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); - ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); List pendingTickets = ticketRepository.findPendingTicketsInCategories(Collections.singletonList(category.getId())); assertEquals(2, pendingTickets.size()); pendingTickets.forEach(t -> assertEquals(1000, t.getFinalPriceCts())); @@ -159,7 +159,7 @@ public void testTicketSelection() { TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); TicketReservationWithOptionalCodeModification mod2 = new TicketReservationWithOptionalCodeModification(tr2, Optional.empty()); - String reservationId = ticketReservationManager.createTicketReservation(event, Arrays.asList(mod, mod2), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Arrays.asList(mod, mod2), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); List reservations = ticketReservationManager.findAllReservationsInEvent(event.getId(), 0, null, null).getKey(); assertEquals(1, reservations.size()); @@ -211,7 +211,7 @@ public void testTicketSelection() { trForDelete.setAmount(1); trForDelete.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification modForDelete = new TicketReservationWithOptionalCodeModification(trForDelete, Optional.empty()); - String reservationId2 = ticketReservationManager.createTicketReservation(event, Collections.singletonList(modForDelete), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId2 = ticketReservationManager.createTicketReservation(event, Collections.singletonList(modForDelete), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); PaymentSpecification specification2 = new PaymentSpecification(reservationId2, null, totalPrice.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), @@ -247,7 +247,7 @@ public void testTicketWithDiscount() { tr.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.of("MYPROMOCODE"), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.of("MYPROMOCODE"), Locale.ENGLISH, false); TotalPrice totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId); @@ -268,7 +268,7 @@ public void testTicketWithDiscount() { trFixed.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification modFixed = new TicketReservationWithOptionalCodeModification(trFixed, Optional.empty()); - String reservationIdFixed = ticketReservationManager.createTicketReservation(event, Collections.singletonList(modFixed), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.of("MYFIXEDPROMO"), Locale.ENGLISH, false); + String reservationIdFixed = ticketReservationManager.createTicketReservation(event, Collections.singletonList(modFixed), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.of("MYFIXEDPROMO"), Locale.ENGLISH, false); TotalPrice totalPriceFixed = ticketReservationManager.totalReservationCostWithVAT(reservationIdFixed); @@ -291,7 +291,7 @@ public void testTicketWithDiscount() { trTooMuch.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification modTooMuch = new TicketReservationWithOptionalCodeModification(trTooMuch, Optional.empty()); try { - ticketReservationManager.createTicketReservation(event, Collections.singletonList(modTooMuch ), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.of("MYPROMOCODE"), Locale.ENGLISH, false); + ticketReservationManager.createTicketReservation(event, Collections.singletonList(modTooMuch ), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.of("MYPROMOCODE"), Locale.ENGLISH, false); Assert.fail("must not enter here"); } catch (TicketReservationManager.TooManyTicketsForDiscountCodeException e) { } @@ -330,7 +330,7 @@ public void testAdditionalServiceWithDiscount() { var additionalServices = List.of(new ASReservationWithOptionalCodeModification(firstAsModification, Optional.empty()), new ASReservationWithOptionalCodeModification(secondAsModification, Optional.empty())); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), additionalServices, DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.of("MYPROMOCODE"), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), additionalServices, DateUtils.addDays(new Date(), 1), Optional.of("MYPROMOCODE"), Locale.ENGLISH, false); TotalPrice totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId); @@ -366,7 +366,7 @@ private Triple testTicketsWithAccessCode() { tr.setTicketCategoryId(category.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.of(accessCode), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.of(accessCode), Locale.ENGLISH, false); TotalPrice totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId); @@ -393,7 +393,7 @@ public void testAccessCodeLimit() { trTooMuch.setTicketCategoryId(triple.getMiddle().getId()); TicketReservationWithOptionalCodeModification modTooMuch = new TicketReservationWithOptionalCodeModification(trTooMuch, Optional.empty()); try { - ticketReservationManager.createTicketReservation(triple.getLeft(), List.of(modTooMuch), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.of(ACCESS_CODE), Locale.ENGLISH, false); + ticketReservationManager.createTicketReservation(triple.getLeft(), List.of(modTooMuch), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.of(ACCESS_CODE), Locale.ENGLISH, false); Assert.fail("trigger is not working!"); } catch (TicketReservationManager.TooManyTicketsForDiscountCodeException e) { } @@ -409,7 +409,7 @@ public void testAccessCodeReleaseTickets() { ticketReservationManager.cancelPendingReservation(triple.getRight(), true, null); waitingQueueSubscriptionProcessor.handleWaitingTickets(); - var newReservationId = ticketReservationManager.createTicketReservation(triple.getLeft(), List.of(modTooMuch), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.of(ACCESS_CODE), Locale.ENGLISH, false); + var newReservationId = ticketReservationManager.createTicketReservation(triple.getLeft(), List.of(modTooMuch), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.of(ACCESS_CODE), Locale.ENGLISH, false); assertNotNull(newReservationId); } @@ -440,7 +440,7 @@ public void testWithAdditionalServices() { ASReservationWithOptionalCodeModification asMod = new ASReservationWithOptionalCodeModification(asrm, Optional.empty()); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.singletonList(asMod), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.of("MYPROMOCODE"), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.singletonList(asMod), DateUtils.addDays(new Date(), 1), Optional.of("MYPROMOCODE"), Locale.ENGLISH, false); TotalPrice totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId); @@ -476,7 +476,7 @@ public void testTicketSelectionNotEnoughTicketsAvailable() { tr.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); - ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); } @Test @@ -495,7 +495,7 @@ public void testDeletePendingPaymentUnboundedCategory() { tr.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); TotalPrice reservationCost = ticketReservationManager.totalReservationCostWithVAT(reservationId); PaymentSpecification specification = new PaymentSpecification(reservationId, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), @@ -506,7 +506,7 @@ public void testDeletePendingPaymentUnboundedCategory() { waitingQueueManager.distributeSeats(event); mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); - reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); reservationCost = ticketReservationManager.totalReservationCostWithVAT(reservationId); PaymentSpecification specification2 = new PaymentSpecification(reservationId, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), @@ -543,7 +543,7 @@ public void testCleanupExpiredReservations() { Assert.assertTrue(idsPendingQuery.get().isEmpty()); - String reservationId = ticketReservationManager.createTicketReservation(event, Arrays.asList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), -2), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Arrays.asList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), -2), Optional.empty(), Locale.ENGLISH, false); List reservationIdPending = idsPendingQuery.get(); Assert.assertEquals(1, reservationIdPending.size()); @@ -576,7 +576,7 @@ public void testCleanupOfflineExpiredReservations() { Date past = DateUtils.addDays(new Date(), -2); Date now = new Date(); - String reservationId = ticketReservationManager.createTicketReservation(event, Arrays.asList(mod), Collections.emptyList(), past, Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Arrays.asList(mod), Collections.emptyList(), past, Optional.empty(), Locale.ENGLISH, false); final Supplier> idsOfflinePayment = () -> jdbcTemplate.queryForList("select id from tickets_reservation where validity < :date and status = 'OFFLINE_PAYMENT'", Collections.singletonMap("date", now), String.class); diff --git a/src/test/java/alfio/manager/TicketReservationManagerTest.java b/src/test/java/alfio/manager/TicketReservationManagerTest.java index bb6e66cf5e..e4de02cf51 100644 --- a/src/test/java/alfio/manager/TicketReservationManagerTest.java +++ b/src/test/java/alfio/manager/TicketReservationManagerTest.java @@ -540,7 +540,7 @@ void reserveTicketsForCategoryWithAccessCode() { when(ticketRepository.findById(eq(TICKET_ID), eq(TICKET_CATEGORY_ID))).thenReturn(ticket); String query = "batch-reserve-tickets"; when(ticketRepository.batchReserveTicket()).thenReturn(query); - trm.reserveTicketsForCategory(event, Optional.empty(), RESERVATION_ID, reservationModification, Locale.ENGLISH, false, discount); + trm.reserveTicketsForCategory(event, RESERVATION_ID, reservationModification, Locale.ENGLISH, false, discount); verify(jdbcTemplate).batchUpdate(eq(query), any(SqlParameterSource[].class)); verify(specialPriceRepository).batchUpdateStatus(eq(List.of(1,2)), eq(SpecialPrice.Status.PENDING), eq(RESERVATION_ID), eq(accessCodeId)); } @@ -582,7 +582,7 @@ void reserveTicketsForBoundedCategories() { when(reservationModification.getAmount()).thenReturn(1); when(reservationModification.getTicketCategoryId()).thenReturn(TICKET_CATEGORY_ID); when(ticketRepository.findById(1, TICKET_CATEGORY_ID)).thenReturn(ticket); - trm.reserveTicketsForCategory(event, Optional.empty(), "trid", reservationModification, Locale.ENGLISH, false, null); + trm.reserveTicketsForCategory(event, "trid", reservationModification, Locale.ENGLISH, false, null); verify(ticketRepository).reserveTickets("trid", ids, TICKET_CATEGORY_ID, Locale.ENGLISH.getLanguage(), 0); } @@ -594,7 +594,7 @@ void reserveTicketsForBoundedCategoriesWaitingQueue() { when(reservationModification.getAmount()).thenReturn(1); when(reservationModification.getTicketCategoryId()).thenReturn(TICKET_CATEGORY_ID); when(ticketRepository.findById(1, TICKET_CATEGORY_ID)).thenReturn(ticket); - trm.reserveTicketsForCategory(event, Optional.empty(), "trid", reservationModification, Locale.ENGLISH, true, null); + trm.reserveTicketsForCategory(event, "trid", reservationModification, Locale.ENGLISH, true, null); verify(ticketRepository).reserveTickets("trid", ids, TICKET_CATEGORY_ID, Locale.ENGLISH.getLanguage(), 0); } @@ -606,7 +606,7 @@ void reserveTicketsForUnboundedCategories() { when(reservationModification.getAmount()).thenReturn(1); when(reservationModification.getTicketCategoryId()).thenReturn(TICKET_CATEGORY_ID); when(ticketRepository.findById(1, TICKET_CATEGORY_ID)).thenReturn(ticket); - trm.reserveTicketsForCategory(event, Optional.empty(), "trid", reservationModification, Locale.ENGLISH, false, null); + trm.reserveTicketsForCategory(event, "trid", reservationModification, Locale.ENGLISH, false, null); verify(ticketRepository).reserveTickets("trid", ids, TICKET_CATEGORY_ID, Locale.ENGLISH.getLanguage(), 0); } @@ -618,7 +618,7 @@ void reserveTicketsForUnboundedCategoriesWaitingQueue() { when(reservationModification.getAmount()).thenReturn(1); when(reservationModification.getTicketCategoryId()).thenReturn(TICKET_CATEGORY_ID); when(ticketRepository.findById(1, TICKET_CATEGORY_ID)).thenReturn(ticket); - trm.reserveTicketsForCategory(event, Optional.empty(), "trid", reservationModification, Locale.ENGLISH, true, null); + trm.reserveTicketsForCategory(event, "trid", reservationModification, Locale.ENGLISH, true, null); verify(ticketRepository).reserveTickets("trid", ids, TICKET_CATEGORY_ID, Locale.ENGLISH.getLanguage(), 0); } diff --git a/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java b/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java index 7a9453183a..a5c4ee85ff 100644 --- a/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java @@ -173,7 +173,7 @@ public void testWaitingQueueForUnboundedCategory() { tr.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); TotalPrice reservationCost = ticketReservationManager.totalReservationCostWithVAT(reservationId); //FIXME re-enable test //PaymentSpecification spec = new PaymentSpecification( reservationId, null, 0, event, "test@test.ch", new CustomerName("Full Name", "Full", "Name", event.mustUseFirstAndLastName()) ); @@ -210,7 +210,7 @@ public void testAssignTicketToWaitingQueueUnboundedCategory() { TicketReservationWithOptionalCodeModification multi = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); TicketReservationWithOptionalCodeModification single = new TicketReservationWithOptionalCodeModification(tr2, Optional.empty()); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(multi), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(multi), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); TotalPrice reservationCost = ticketReservationManager.totalReservationCostWithVAT(reservationId); PaymentSpecification specification = new PaymentSpecification(reservationId, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), @@ -218,7 +218,7 @@ public void testAssignTicketToWaitingQueueUnboundedCategory() { PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); assertTrue(result.isSuccessful()); - String reservationIdSingle = ticketReservationManager.createTicketReservation(event, Collections.singletonList(single), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationIdSingle = ticketReservationManager.createTicketReservation(event, Collections.singletonList(single), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); TotalPrice reservationCostSingle = ticketReservationManager.totalReservationCostWithVAT(reservationIdSingle); specification = new PaymentSpecification(reservationIdSingle, null, reservationCostSingle.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), @@ -270,7 +270,7 @@ public void testAssignTicketToWaitingQueueBoundedCategory() { TicketReservationWithOptionalCodeModification multi = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); TicketReservationWithOptionalCodeModification single = new TicketReservationWithOptionalCodeModification(tr2, Optional.empty()); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(multi), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(multi), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); TotalPrice reservationCost = ticketReservationManager.totalReservationCostWithVAT(reservationId); PaymentSpecification specification = new PaymentSpecification(reservationId, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), @@ -278,7 +278,7 @@ public void testAssignTicketToWaitingQueueBoundedCategory() { PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); assertTrue(result.isSuccessful()); - String reservationIdSingle = ticketReservationManager.createTicketReservation(event, Collections.singletonList(single), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationIdSingle = ticketReservationManager.createTicketReservation(event, Collections.singletonList(single), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); TotalPrice reservationCostSingle = ticketReservationManager.totalReservationCostWithVAT(reservationIdSingle); specification = new PaymentSpecification(reservationIdSingle, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), @@ -367,7 +367,7 @@ private String reserveTickets(Event event, TicketCategory category, int num) { tr.setAmount(num); tr.setTicketCategoryId(category.getId()); TicketReservationWithOptionalCodeModification tcm = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(tcm), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(tcm), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); TotalPrice reservationCost = ticketReservationManager.totalReservationCostWithVAT(reservationId); PaymentSpecification specification = new PaymentSpecification(reservationId, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), diff --git a/src/test/java/alfio/manager/WaitingQueueSubscriptionProcessorTest.java b/src/test/java/alfio/manager/WaitingQueueSubscriptionProcessorTest.java index 37e7c6c574..b76d14c62d 100644 --- a/src/test/java/alfio/manager/WaitingQueueSubscriptionProcessorTest.java +++ b/src/test/java/alfio/manager/WaitingQueueSubscriptionProcessorTest.java @@ -118,9 +118,9 @@ void processPendingTickets() { ZonedDateTime expiration = ZonedDateTime.now().plusDays(1); when(waitingQueueManager.distributeSeats(eq(event))).thenReturn(Stream.of(Triple.of(subscription, reservation, expiration))); String reservationId = "reservation-id"; - when(ticketReservationManager.createTicketReservation(eq(event), anyList(), anyList(), any(Date.class), eq(Optional.empty()), eq(Optional.empty()), any(Locale.class), eq(true))).thenReturn(reservationId); + when(ticketReservationManager.createTicketReservation(eq(event), anyList(), anyList(), any(Date.class), eq(Optional.empty()), any(Locale.class), eq(true))).thenReturn(reservationId); processor.handleWaitingTickets(); - verify(ticketReservationManager).createTicketReservation(eq(event), eq(Collections.singletonList(reservation)), anyList(), eq(Date.from(expiration.toInstant())), eq(Optional.empty()), eq(Optional.empty()), eq(Locale.ENGLISH), eq(true)); + verify(ticketReservationManager).createTicketReservation(eq(event), eq(Collections.singletonList(reservation)), anyList(), eq(Date.from(expiration.toInstant())), eq(Optional.empty()), eq(Locale.ENGLISH), eq(true)); verify(notificationManager).sendSimpleEmail(eq(event), eq(reservationId), eq("me"), eq("subject"), any(TextTemplateGenerator.class)); } } \ No newline at end of file diff --git a/src/test/java/alfio/manager/system/DataMigratorIntegrationTest.java b/src/test/java/alfio/manager/system/DataMigratorIntegrationTest.java index 45d0816bf4..3472aa4e79 100644 --- a/src/test/java/alfio/manager/system/DataMigratorIntegrationTest.java +++ b/src/test/java/alfio/manager/system/DataMigratorIntegrationTest.java @@ -259,7 +259,7 @@ public void testUpdateTicketReservation() { trm.setTicketCategoryId(eventManager.loadTicketCategories(event).get(0).getId()); TicketReservationWithOptionalCodeModification r = new TicketReservationWithOptionalCodeModification(trm, Optional.empty()); Date expiration = DateUtils.addDays(new Date(), 1); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(r), Collections.emptyList(), expiration, Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(r), Collections.emptyList(), expiration, Optional.empty(), Locale.ENGLISH, false); dataMigrator.fillReservationsLanguage(); TicketReservation ticketReservation = ticketReservationManager.findById(reservationId).get(); assertEquals("en", ticketReservation.getUserLanguage()); @@ -283,7 +283,7 @@ public void testUpdateGender() throws IOException { trm.setTicketCategoryId(eventManager.loadTicketCategories(event).get(0).getId()); TicketReservationWithOptionalCodeModification r = new TicketReservationWithOptionalCodeModification(trm, Optional.empty()); Date expiration = DateUtils.addDays(new Date(), 1); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(r), Collections.emptyList(), expiration, Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(r), Collections.emptyList(), expiration, Optional.empty(), Locale.ENGLISH, false); // ticketReservationManager.performPayment("TOKEN", null, event, reservationId, "email@email.ch", new CustomerName("Full Name", "Full", "Name", event), Locale.ENGLISH, null, null, new TotalPrice(1000, 10, 0, 0), Optional.empty(), Optional.of(PaymentProxy.ON_SITE), false, null, null, null, false, false); List tickets = ticketRepository.findTicketsInReservation(reservationId); UpdateTicketOwnerForm first = new UpdateTicketOwnerForm(); @@ -347,7 +347,7 @@ public void testFixStuckTickets() { trm.setTicketCategoryId(eventManager.loadTicketCategories(event).get(0).getId()); TicketReservationWithOptionalCodeModification r = new TicketReservationWithOptionalCodeModification(trm, Optional.empty()); Date expiration = DateUtils.addDays(new Date(), 1); - String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(r), Collections.emptyList(), expiration, Optional.empty(), Optional.empty(), Locale.ENGLISH, false); + String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(r), Collections.emptyList(), expiration, Optional.empty(), Locale.ENGLISH, false); //simulate the effect of a reservation cancellation after #392, as described in #391 ticketReservationRepository.updateReservationStatus(reservationId, TicketReservation.TicketReservationStatus.CANCELLED.name()); List ticketsInReservation = ticketRepository.findTicketsInReservation(reservationId); From fd775a164ffc80fc6fda235fc092b6d21001b3c2 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Mon, 24 Jun 2019 21:58:51 +0200 Subject: [PATCH 18/29] refactor: remove specialPriceSessionId parameter #657 --- .../v2/user/ReservationApiV2Controller.java | 3 +-- .../alfio/controller/support/SessionUtil.java | 20 ------------------- .../manager/AdminReservationManager.java | 2 +- .../manager/TicketReservationManager.java | 13 +++++------- ...cketReservationManagerIntegrationTest.java | 10 +++++----- .../manager/TicketReservationManagerTest.java | 8 ++++---- .../WaitingQueueManagerIntegrationTest.java | 10 +++++----- 7 files changed, 21 insertions(+), 45 deletions(-) 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 d687154b33..8b4c856c99 100644 --- a/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java @@ -309,8 +309,7 @@ public ResponseEntity> confirmOvervi orderSummary, ticketReservation.getVatCountryCode(), ticketReservation.getVatNr(), ticketReservation.getVatStatus(), Boolean.TRUE.equals(paymentForm.getTermAndConditionsAccepted()), Boolean.TRUE.equals(paymentForm.getPrivacyPolicyAccepted())); - final PaymentResult status = ticketReservationManager.performPayment(spec, reservationCost, SessionUtil.retrieveSpecialPriceSessionId(request), - Optional.ofNullable(paymentForm.getPaymentMethod())); + final PaymentResult status = ticketReservationManager.performPayment(spec, reservationCost, Optional.ofNullable(paymentForm.getPaymentMethod())); if (status.isRedirect()) { diff --git a/src/main/java/alfio/controller/support/SessionUtil.java b/src/main/java/alfio/controller/support/SessionUtil.java index 93a4ba6287..ad6b4ff0a1 100644 --- a/src/main/java/alfio/controller/support/SessionUtil.java +++ b/src/main/java/alfio/controller/support/SessionUtil.java @@ -17,39 +17,19 @@ package alfio.controller.support; import alfio.manager.PaymentManager; -import org.springframework.validation.BindingResult; -import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import java.util.Optional; public final class SessionUtil { - - private static final String SPECIAL_PRICE_CODE_SESSION_ID = "SPECIAL_PRICE_CODE_SESSION_ID"; - private static final String SPECIAL_PRICE_CODE = "SPECIAL_PRICE_CODE"; - - private static final String PROMOTIONAL_CODE_DISCOUNT = "PROMOTIONAL_CODE_DISCOUNT"; private SessionUtil() {} - public static Optional retrieveSpecialPriceSessionId(HttpServletRequest request) { - return Optional.ofNullable((String)request.getSession().getAttribute(SPECIAL_PRICE_CODE_SESSION_ID)); - } public static void cleanupSession(HttpServletRequest request) { - HttpSession session = request.getSession(); - session.removeAttribute(SPECIAL_PRICE_CODE_SESSION_ID); - session.removeAttribute(SPECIAL_PRICE_CODE); - session.removeAttribute(PROMOTIONAL_CODE_DISCOUNT); removePaymentToken(request); } public static void removePaymentToken(HttpServletRequest request) { request.getSession().removeAttribute(PaymentManager.PAYMENT_TOKEN); } - - public static void addToFlash(BindingResult bindingResult, RedirectAttributes redirectAttributes) { - redirectAttributes.addFlashAttribute("error", bindingResult).addFlashAttribute("hasErrors", true); - } } diff --git a/src/main/java/alfio/manager/AdminReservationManager.java b/src/main/java/alfio/manager/AdminReservationManager.java index 579b855f25..beb5ab008f 100644 --- a/src/main/java/alfio/manager/AdminReservationManager.java +++ b/src/main/java/alfio/manager/AdminReservationManager.java @@ -313,7 +313,7 @@ private Result, Event>> performConfirmati original.getBillingAddress(), original.getCustomerReference(), LocaleUtil.forLanguageTag(original.getUserLanguage()), false, false, null, null, null, null, false, false); - ticketReservationManager.completeReservation(spec, Optional.empty(), PaymentProxy.ADMIN, notification.isCustomer(), notification.isAttendees()); + ticketReservationManager.completeReservation(spec, PaymentProxy.ADMIN, notification.isCustomer(), notification.isAttendees()); return loadReservation(reservationId); } catch(Exception e) { return Result.error(ErrorCode.ReservationError.UPDATE_FAILED); diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index acb8d653e5..6f13e186f0 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -430,7 +430,6 @@ Optional fixToken(Optional token, int ticketCategory public PaymentResult performPayment(PaymentSpecification spec, TotalPrice reservationCost, - Optional specialPriceSessionId, Optional method) { PaymentProxy paymentProxy = evaluatePaymentProxy(method, reservationCost); @@ -464,7 +463,7 @@ public PaymentResult performPayment(PaymentSpecification spec, if (paymentResult.isSuccessful()) { reservation = ticketReservationRepository.findReservationById(spec.getReservationId()); - transitionToComplete(spec, reservationCost, specialPriceSessionId, paymentProxy); + transitionToComplete(spec, reservationCost, paymentProxy); } else if(paymentResult.isFailed()) { reTransitionToPending(spec.getReservationId()); } @@ -481,9 +480,9 @@ public PaymentResult performPayment(PaymentSpecification spec, } - private void transitionToComplete(PaymentSpecification spec, TotalPrice reservationCost, Optional specialPriceSessionId, PaymentProxy paymentProxy) { + private void transitionToComplete(PaymentSpecification spec, TotalPrice reservationCost, PaymentProxy paymentProxy) { generateInvoiceNumber(spec, reservationCost); - completeReservation(spec, specialPriceSessionId, paymentProxy, true, true); + completeReservation(spec, paymentProxy, true, true); } private void generateInvoiceNumber(PaymentSpecification spec, TotalPrice reservationCost) { @@ -883,7 +882,7 @@ public Optional> from(String eventName, /** * Set the tickets attached to the reservation to the ACQUIRED state and the ticket reservation to the COMPLETE state. Additionally it will save email/fullName/billingaddress/userLanguage. */ - void completeReservation(PaymentSpecification spec, Optional specialPriceSessionId, PaymentProxy paymentProxy, boolean sendReservationConfirmationEmail, boolean sendTickets) { + void completeReservation(PaymentSpecification spec, PaymentProxy paymentProxy, boolean sendReservationConfirmationEmail, boolean sendTickets) { String reservationId = spec.getReservationId(); int eventId = spec.getEvent().getId(); final TicketReservation reservation = ticketReservationRepository.findReservationById(reservationId); @@ -892,8 +891,6 @@ void completeReservation(PaymentSpecification spec, Optional specialPric acquireItems(paymentProxy, reservationId, spec.getEmail(), spec.getCustomerName(), spec.getLocale().getLanguage(), spec.getBillingAddress(), spec.getCustomerReference(), spec.getEvent(), sendTickets); extensionManager.handleReservationConfirmation(reservation, ticketReservationRepository.getBillingDetailsForReservation(reservationId), eventId); } - //cleanup unused special price codes... - specialPriceSessionId.ifPresent(specialPriceRepository::unbindFromSession); Date eventTime = new Date(); auditingRepository.insert(reservationId, null, eventId, Audit.EventType.RESERVATION_COMPLETE, eventTime, Audit.EntityType.RESERVATION, reservationId); @@ -1847,7 +1844,7 @@ public PaymentWebhookResult processTransactionWebhook(String body, String signat var paymentToken = paymentWebhookResult.getPaymentToken(); var paymentSpecification = new PaymentSpecification(reservation, totalPrice, event, paymentToken, orderSummaryForReservation(reservation, event), true, eventHasPrivacyPolicy(event)); - transitionToComplete(paymentSpecification, totalPrice, Optional.empty(), paymentToken.getPaymentProvider()); + transitionToComplete(paymentSpecification, totalPrice, paymentToken.getPaymentProvider()); break; } case FAILED: { diff --git a/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java b/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java index bc70af652e..072eb2b3f2 100644 --- a/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java @@ -181,7 +181,7 @@ public void testTicketSelection() { event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), "billing address", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); - PaymentResult confirm = ticketReservationManager.performPayment(specification, totalPrice, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); + PaymentResult confirm = ticketReservationManager.performPayment(specification, totalPrice, Optional.of(PaymentProxy.OFFLINE)); assertTrue(confirm.isSuccessful()); assertEquals(TicketReservation.TicketReservationStatus.OFFLINE_PAYMENT, ticketReservationManager.findById(reservationId).get().getStatus()); @@ -217,7 +217,7 @@ public void testTicketSelection() { event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), "billing address", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); - PaymentResult confirm2 = ticketReservationManager.performPayment(specification2, totalPrice, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); + PaymentResult confirm2 = ticketReservationManager.performPayment(specification2, totalPrice, Optional.of(PaymentProxy.OFFLINE)); assertTrue(confirm2.isSuccessful()); ticketReservationManager.deleteOfflinePayment(event, reservationId2, false, false, null); @@ -500,7 +500,7 @@ public void testDeletePendingPaymentUnboundedCategory() { PaymentSpecification specification = new PaymentSpecification(reservationId, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), "billing address", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); - PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); + PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.of(PaymentProxy.OFFLINE)); assertTrue(result.isSuccessful()); ticketReservationManager.deleteOfflinePayment(event, reservationId, false, false, null); waitingQueueManager.distributeSeats(event); @@ -511,7 +511,7 @@ public void testDeletePendingPaymentUnboundedCategory() { PaymentSpecification specification2 = new PaymentSpecification(reservationId, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), "billing address", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); - result = ticketReservationManager.performPayment(specification2, reservationCost, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); + result = ticketReservationManager.performPayment(specification2, reservationCost, Optional.of(PaymentProxy.OFFLINE)); assertTrue(result.isSuccessful()); } @@ -586,7 +586,7 @@ public void testCleanupOfflineExpiredReservations() { PaymentSpecification specification = new PaymentSpecification(reservationId, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), "billing address", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); - PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); + PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.of(PaymentProxy.OFFLINE)); assertTrue(result.isSuccessful()); diff --git a/src/test/java/alfio/manager/TicketReservationManagerTest.java b/src/test/java/alfio/manager/TicketReservationManagerTest.java index e4de02cf51..46196b0675 100644 --- a/src/test/java/alfio/manager/TicketReservationManagerTest.java +++ b/src/test/java/alfio/manager/TicketReservationManagerTest.java @@ -826,7 +826,7 @@ private void testPaidReservation(boolean enableTicketTransfer, boolean successfu new CustomerName("Full Name", null, null, event.mustUseFirstAndLastName()), "", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); when(ticketReservation.getStatus()).thenReturn(IN_PAYMENT); - PaymentResult result = trm.performPayment(spec, new TotalPrice(100, 0, 0, 0), Optional.empty(), Optional.of(PaymentProxy.STRIPE)); + PaymentResult result = trm.performPayment(spec, new TotalPrice(100, 0, 0, 0), Optional.of(PaymentProxy.STRIPE)); if(successful) { assertTrue(result.isSuccessful()); assertEquals(Optional.of(TRANSACTION_ID), result.getGatewayId()); @@ -856,7 +856,7 @@ void returnFailureCodeIfPaymentNotSuccessful() { when(paymentManager.lookupProviderByMethod(eq(PaymentMethod.CREDIT_CARD), any())).thenReturn(Optional.of(stripeCreditCardManager)); when(stripeCreditCardManager.getTokenAndPay(any())).thenReturn(PaymentResult.failed("error-code")); PaymentSpecification spec = new PaymentSpecification(RESERVATION_ID, new StripeCreditCardToken(GATEWAY_TOKEN), 100, event, "email@user", new CustomerName("Full Name", null, null, event.mustUseFirstAndLastName()), null, null, Locale.ENGLISH, true, false, null, "IT", "12345", PriceContainer.VatStatus.INCLUDED, true, false); - PaymentResult result = trm.performPayment(spec, new TotalPrice(100, 0, 0, 0), Optional.empty(), Optional.of(PaymentProxy.STRIPE)); + PaymentResult result = trm.performPayment(spec, new TotalPrice(100, 0, 0, 0), Optional.of(PaymentProxy.STRIPE)); assertFalse(result.isSuccessful()); assertFalse(result.getGatewayId().isPresent()); assertEquals(Optional.of("error-code"), result.getErrorCode()); @@ -885,7 +885,7 @@ void handleOnSitePaymentMethod() { new CustomerName("Full Name", null, null, event.mustUseFirstAndLastName()), "", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); when(ticketReservationRepository.updateTicketReservation(eq(RESERVATION_ID), anyString(), anyString(), anyString(), isNull(), isNull(), eq(Locale.ENGLISH.getLanguage()), isNull(), any(), any(), isNull())).thenReturn(1); - PaymentResult result = trm.performPayment(spec, new TotalPrice(100, 0, 0, 0), Optional.empty(), Optional.of(PaymentProxy.ON_SITE)); + PaymentResult result = trm.performPayment(spec, new TotalPrice(100, 0, 0, 0), Optional.of(PaymentProxy.ON_SITE)); assertTrue(result.isSuccessful()); assertEquals(Optional.of(TicketReservationManager.NOT_YET_PAID_TRANSACTION_ID), result.getGatewayId()); verify(ticketReservationRepository).updateTicketReservation(eq(RESERVATION_ID), eq(TicketReservationStatus.COMPLETE.toString()), anyString(), anyString(), isNull(), isNull(), anyString(), anyString(), any(), eq(PaymentProxy.ON_SITE.toString()), isNull()); @@ -911,7 +911,7 @@ void handleOfflinePaymentMethod() { PaymentSpecification spec = new PaymentSpecification(RESERVATION_ID, new StripeCreditCardToken(GATEWAY_TOKEN), 100, event, "test@email", new CustomerName("Full Name", null, null, event.mustUseFirstAndLastName()), "", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); - PaymentResult result = trm.performPayment(spec, new TotalPrice(100, 0, 0, 0), Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); + PaymentResult result = trm.performPayment(spec, new TotalPrice(100, 0, 0, 0), Optional.of(PaymentProxy.OFFLINE)); assertTrue(result.isSuccessful()); assertEquals(Optional.of(TicketReservationManager.NOT_YET_PAID_TRANSACTION_ID), result.getGatewayId()); verify(waitingQueueManager, never()).fireReservationConfirmed(eq(RESERVATION_ID)); diff --git a/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java b/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java index a5c4ee85ff..f144e3338c 100644 --- a/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java @@ -215,7 +215,7 @@ public void testAssignTicketToWaitingQueueUnboundedCategory() { PaymentSpecification specification = new PaymentSpecification(reservationId, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), "billing address", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); - PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); + PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.of(PaymentProxy.OFFLINE)); assertTrue(result.isSuccessful()); String reservationIdSingle = ticketReservationManager.createTicketReservation(event, Collections.singletonList(single), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); @@ -223,7 +223,7 @@ public void testAssignTicketToWaitingQueueUnboundedCategory() { specification = new PaymentSpecification(reservationIdSingle, null, reservationCostSingle.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), "billing address", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); - PaymentResult resultSingle = ticketReservationManager.performPayment(specification, reservationCostSingle, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); + PaymentResult resultSingle = ticketReservationManager.performPayment(specification, reservationCostSingle, Optional.of(PaymentProxy.OFFLINE)); assertTrue(resultSingle.isSuccessful()); @@ -275,7 +275,7 @@ public void testAssignTicketToWaitingQueueBoundedCategory() { PaymentSpecification specification = new PaymentSpecification(reservationId, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), "billing address", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); - PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); + PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.of(PaymentProxy.OFFLINE)); assertTrue(result.isSuccessful()); String reservationIdSingle = ticketReservationManager.createTicketReservation(event, Collections.singletonList(single), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false); @@ -283,7 +283,7 @@ public void testAssignTicketToWaitingQueueBoundedCategory() { specification = new PaymentSpecification(reservationIdSingle, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), "billing address", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); - PaymentResult resultSingle = ticketReservationManager.performPayment(specification, reservationCostSingle, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); + PaymentResult resultSingle = ticketReservationManager.performPayment(specification, reservationCostSingle, Optional.of(PaymentProxy.OFFLINE)); assertTrue(resultSingle.isSuccessful()); assertEquals(0, eventRepository.findStatisticsFor(event.getId()).getDynamicAllocation()); @@ -372,7 +372,7 @@ private String reserveTickets(Event event, TicketCategory category, int num) { PaymentSpecification specification = new PaymentSpecification(reservationId, null, reservationCost.getPriceWithVAT(), event, "email@example.com", new CustomerName("full name", "full", "name", event.mustUseFirstAndLastName()), "billing address", null, Locale.ENGLISH, true, false, null, "IT", "123456", PriceContainer.VatStatus.INCLUDED, true, false); - PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.empty(), Optional.of(PaymentProxy.OFFLINE)); + PaymentResult result = ticketReservationManager.performPayment(specification, reservationCost, Optional.of(PaymentProxy.OFFLINE)); assertTrue(result.isSuccessful()); return reservationId; } From ef0bb93d9fcf8dc2df7245404e6d344f0c5469e4 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Mon, 24 Jun 2019 22:09:56 +0200 Subject: [PATCH 19/29] refactor: remove specialPriceSessionId parameter+misc conf manager #657 --- .../alfio/manager/TicketReservationManager.java | 13 +++++++------ .../alfio/repository/SpecialPriceRepository.java | 6 ------ src/main/java/alfio/util/TemplateManager.java | 5 +---- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index 6f13e186f0..ddeae7c482 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -302,7 +302,7 @@ void reserveTicketsForCategory(Event event, String reservationId, TicketReservat specialPrices = reserveTokens(reservationId, ticketReservation, discount); } else { //first check if there is another pending special price token bound to the current sessionId - Optional specialPrice = fixToken(ticketReservation.getSpecialPrice(), ticketReservation.getTicketCategoryId(), event.getId(), Optional.empty(), ticketReservation); + Optional specialPrice = fixToken(ticketReservation.getSpecialPrice(), ticketReservation.getTicketCategoryId(), event.getId(), ticketReservation); specialPrices = specialPrice.stream().collect(toList()); } @@ -398,19 +398,20 @@ List reserveTickets(int eventId , int categoryId, int qty, List fixToken(Optional token, int ticketCategoryId, int eventId, Optional specialPriceSessionId, TicketReservationWithOptionalCodeModification ticketReservation) { + Optional fixToken(Optional token, int ticketCategoryId, int eventId, TicketReservationWithOptionalCodeModification ticketReservation) { TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(ticketCategoryId, eventId); if(!ticketCategory.isAccessRestricted()) { return Optional.empty(); } - Optional specialPrice = token;//renewSpecialPrice(token, specialPriceSessionId); + Optional specialPrice = token;//note, we don't use anymore, renewSpecialPrice(token, specialPriceSessionId); - if(token.isPresent() && specialPrice.isEmpty()) { + // TODO: check. this condition cannot be true. In theory, you cannot have an invalid one when you enter here + //if(token.isPresent() && specialPrice.isEmpty()) { //there is a special price in the request but this isn't valid anymore - throw new InvalidSpecialPriceTokenException(); - } + //throw new InvalidSpecialPriceTokenException(); + //} boolean canAccessRestrictedCategory = specialPrice.isPresent() && specialPrice.get().getStatus() == SpecialPrice.Status.FREE diff --git a/src/main/java/alfio/repository/SpecialPriceRepository.java b/src/main/java/alfio/repository/SpecialPriceRepository.java index a2515f4761..ac9fa40a61 100644 --- a/src/main/java/alfio/repository/SpecialPriceRepository.java +++ b/src/main/java/alfio/repository/SpecialPriceRepository.java @@ -73,12 +73,6 @@ public interface SpecialPriceRepository { @Query("update special_price set status = :status, session_id = :sessionId, access_code_id_fk = :accessCodeId where id = :id") int updateStatus(@Bind("id") int id, @Bind("status") String status, @Bind("sessionId") String sessionIdentifier, @Bind("accessCodeId") Integer accessCodeId); - @Query("update special_price set session_id = :sessionId, access_code_id_fk = :accessCodeId where id = :id") - int bindToSession(@Bind("id") int id, @Bind("sessionId") String sessionIdentifier, @Bind("accessCodeId") Integer accessCodeId); - - @Query("update special_price set session_id = null, status = 'FREE', access_code_id_fk = null where session_id = :sessionId and status in ('FREE', 'PENDING')") - int unbindFromSession(@Bind("sessionId") String sessionIdentifier); - @Query("update special_price set status = :status where id in (select special_price_id_fk from ticket where tickets_reservation_id in (:reservationIds) and special_price_id_fk is not null) " + " or access_code_id_fk in (select promo_code_id_fk from tickets_reservation where id in(:reservationIds) and promo_code_id_fk is not null)") int updateStatusForReservation(@Bind("reservationIds") List reservationIds, @Bind("status") String status); diff --git a/src/main/java/alfio/util/TemplateManager.java b/src/main/java/alfio/util/TemplateManager.java index f8fd983d8a..81089810e0 100644 --- a/src/main/java/alfio/util/TemplateManager.java +++ b/src/main/java/alfio/util/TemplateManager.java @@ -19,7 +19,6 @@ import alfio.manager.UploadedResourceManager; import alfio.manager.system.ConfigurationManager; import alfio.model.EventAndOrganizationId; -import alfio.model.system.Configuration; import alfio.model.system.ConfigurationKeys; import com.samskivert.mustache.Mustache; import com.samskivert.mustache.Mustache.Compiler; @@ -123,9 +122,7 @@ public static String getVATString(EventAndOrganizationId event, MessageSource me String locale = messageSource.getMessage("locale", null, loc); String translatedVat = messageSource.getMessage("common.vat", null, loc); ConfigurationKeys vatKey = ConfigurationKeys.valueOf("TRANSLATION_OVERRIDE_VAT_"+locale.toUpperCase(Locale.ENGLISH)); - Configuration.ConfigurationPathKey vatPathKey = Optional.ofNullable(event).map(e -> alfio.model.system.Configuration.from(e, vatKey)) - .orElseGet(() -> alfio.model.system.Configuration.getSystemConfiguration(vatKey)); - return configurationManager.getStringConfigValue(vatPathKey, translatedVat); + return configurationManager.getFor(event, vatKey).getValueOrDefault(translatedVat); } private String render(Resource resource, Map model, Locale locale, TemplateOutput templateOutput) { From bf7eadb5f147a3e9a0efa13a94851aed9200d787 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Mon, 24 Jun 2019 22:38:18 +0200 Subject: [PATCH 20/29] remove use of special price session id in admin reservation manager #657 --- .../java/alfio/manager/AdminReservationManager.java | 11 +++++------ .../java/alfio/manager/TicketReservationManager.java | 5 +---- src/main/java/alfio/model/SpecialPrice.java | 6 +++--- .../java/alfio/repository/SpecialPriceRepository.java | 4 ++-- .../java/alfio/manager/SpecialPriceManagerTest.java | 2 +- .../alfio/manager/TicketReservationManagerTest.java | 8 ++++---- 6 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/main/java/alfio/manager/AdminReservationManager.java b/src/main/java/alfio/manager/AdminReservationManager.java index beb5ab008f..1a325e4a70 100644 --- a/src/main/java/alfio/manager/AdminReservationManager.java +++ b/src/main/java/alfio/manager/AdminReservationManager.java @@ -369,7 +369,6 @@ private Result>> createReservation(Result { String reservationId = UUID.randomUUID().toString(); - String specialPriceSessionId = UUID.randomUUID().toString(); Date validity = Date.from(arm.getExpiration().toZonedDateTime(event.getZoneId()).toInstant()); ticketReservationRepository.createNewReservation(reservationId, ZonedDateTime.now(event.getZoneId()), validity, null, arm.getLanguage(), event.getId(), event.getVat(), event.isVatIncluded()); @@ -379,7 +378,7 @@ private Result>> createReservation(Result> result = flattenTicketsInfo(event, empty, t) - .map(pair -> reserveForTicketsInfo(event, arm, reservationId, specialPriceSessionId, pair)) + .map(pair -> reserveForTicketsInfo(event, arm, reservationId, pair)) .reduce(this::reduceReservationResults) .orElseGet(() -> Result.error(ErrorCode.custom("", "unknown error"))); @@ -387,7 +386,7 @@ private Result>> createReservation(Result> reserveForTicketsInfo(Event event, AdminReservationModification arm, String reservationId, String specialPriceSessionId, Pair pair) { + private Result> reserveForTicketsInfo(Event event, AdminReservationModification arm, String reservationId, Pair pair) { TicketCategory category = pair.getLeft(); TicketsInfo ticketsInfo = pair.getRight(); int categoryId = category.getId(); @@ -400,7 +399,7 @@ private Result> reserveForTicketsInfo(Event event, AdminReservation Ticket ticket = ticketRepository.findById(reservedForUpdate.get(0), categoryId); TicketPriceContainer priceContainer = TicketPriceContainer.from(ticket, null, event.getCurrency(), event.getVat(), event.getVatStatus(), null); ticketRepository.updateTicketPrice(reservedForUpdate, categoryId, event.getId(), category.getSrcPriceCts(), MonetaryUtil.unitToCents(priceContainer.getFinalPrice()), MonetaryUtil.unitToCents(priceContainer.getVAT()), MonetaryUtil.unitToCents(priceContainer.getAppliedDiscount())); - List codes = category.isAccessRestricted() ? bindSpecialPriceTokens(specialPriceSessionId, categoryId, attendees) : Collections.emptyList(); + List codes = category.isAccessRestricted() ? bindSpecialPriceTokens(categoryId, attendees) : Collections.emptyList(); assignTickets(event, attendees, categoryId, reservedForUpdate, codes, reservationId, arm.getLanguage(), category.getSrcPriceCts()); List tickets = reservedForUpdate.stream().map(id -> ticketRepository.findById(id, categoryId)).collect(toList()); return Result.success(tickets); @@ -446,13 +445,13 @@ private Stream> flattenTicketsInfo(Event event }); } - private List bindSpecialPriceTokens(String specialPriceSessionId, int categoryId, List attendees) { + private List bindSpecialPriceTokens(int categoryId, List attendees) { specialPriceTokenGenerator.generatePendingCodesForCategory(categoryId); List codes = specialPriceRepository.findActiveNotAssignedByCategoryId(categoryId) .stream() .limit(attendees.size()) .collect(toList()); - codes.forEach(c -> specialPriceRepository.updateStatus(c.getId(), SpecialPrice.Status.PENDING.toString(), specialPriceSessionId, null)); + codes.forEach(c -> specialPriceRepository.updateStatus(c.getId(), SpecialPrice.Status.PENDING.toString(), null, null)); return codes; } diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index ddeae7c482..29dc0aebf6 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -326,7 +326,7 @@ void reserveTicketsForCategory(Event event, String reservationId, TicketReservat var sp = specialPrices.get(0); var accessCodeId = discount != null && discount.getHiddenCategoryId() != null ? discount.getId() : null; ticketRepository.reserveTicket(reservationId, ticketId,sp.getId(), locale.getLanguage(), category.getSrcPriceCts()); - specialPriceRepository.updateStatus(sp.getId(), Status.PENDING.toString(), sp.getSessionIdentifier(), accessCodeId); + specialPriceRepository.updateStatus(sp.getId(), Status.PENDING.toString(), null, accessCodeId); } else { jdbcTemplate.batchUpdate(ticketRepository.batchReserveTicket(), ticketsAndSpecialPrices.stream().map( pair -> new MapSqlParameterSource("reservationId", reservationId) @@ -335,12 +335,9 @@ void reserveTicketsForCategory(Event event, String reservationId, TicketReservat .addValue("userLanguage", locale.getLanguage()) .addValue("srcPriceCts", category.getSrcPriceCts()) ).toArray(MapSqlParameterSource[]::new)); - - var firstSpecialPrice = specialPrices.get(0); specialPriceRepository.batchUpdateStatus( specialPrices.stream().map(SpecialPrice::getId).collect(toList()), Status.PENDING, - firstSpecialPrice.getSessionIdentifier(), Objects.requireNonNull(discount).getId()); } } else { diff --git a/src/main/java/alfio/model/SpecialPrice.java b/src/main/java/alfio/model/SpecialPrice.java index 866beb6b83..476164f969 100644 --- a/src/main/java/alfio/model/SpecialPrice.java +++ b/src/main/java/alfio/model/SpecialPrice.java @@ -33,7 +33,7 @@ public enum Status { private final int priceInCents; private final int ticketCategoryId; private final Status status; - private final String sessionIdentifier; + //private final String sessionIdentifier; private final ZonedDateTime sentTimestamp; private final String recipientName; private final String recipientEmail; @@ -44,7 +44,7 @@ public SpecialPrice(@Column("id") int id, @Column("price_cts") int priceInCents, @Column("ticket_category_id") int ticketCategoryId, @Column("status") String status, - @Column("session_id") String sessionIdentifier, + //@Column("session_id") String sessionIdentifier, @Column("sent_ts") ZonedDateTime sentTimestamp, @Column("recipient_name") String recipientName, @Column("recipient_email") String recipientEmail, @@ -54,7 +54,7 @@ public SpecialPrice(@Column("id") int id, this.priceInCents = priceInCents; this.ticketCategoryId = ticketCategoryId; this.status = Status.valueOf(status); - this.sessionIdentifier = sessionIdentifier; + //this.sessionIdentifier = sessionIdentifier; this.sentTimestamp = sentTimestamp; this.recipientName = recipientName; this.recipientEmail = recipientEmail; diff --git a/src/main/java/alfio/repository/SpecialPriceRepository.java b/src/main/java/alfio/repository/SpecialPriceRepository.java index ac9fa40a61..7e1866740d 100644 --- a/src/main/java/alfio/repository/SpecialPriceRepository.java +++ b/src/main/java/alfio/repository/SpecialPriceRepository.java @@ -67,8 +67,8 @@ public interface SpecialPriceRepository { @Query("select count(*) from special_price where code = :code") Integer countByCode(@Bind("code") String code); - @Query("update special_price set status = :status, session_id = :sessionId, access_code_id_fk = :accessCodeId where id in (:ids)") - int batchUpdateStatus(@Bind("ids") List ids, @Bind("status") SpecialPrice.Status status, @Bind("sessionId") String sessionIdentifier, @Bind("accessCodeId") Integer accessCodeId); + @Query("update special_price set status = :status, session_id = null, access_code_id_fk = :accessCodeId where id in (:ids)") + int batchUpdateStatus(@Bind("ids") List ids, @Bind("status") SpecialPrice.Status status, @Bind("accessCodeId") Integer accessCodeId); @Query("update special_price set status = :status, session_id = :sessionId, access_code_id_fk = :accessCodeId where id = :id") int updateStatus(@Bind("id") int id, @Bind("status") String status, @Bind("sessionId") String sessionIdentifier, @Bind("accessCodeId") Integer accessCodeId); diff --git a/src/test/java/alfio/manager/SpecialPriceManagerTest.java b/src/test/java/alfio/manager/SpecialPriceManagerTest.java index 05f11558e0..033f07aa54 100644 --- a/src/test/java/alfio/manager/SpecialPriceManagerTest.java +++ b/src/test/java/alfio/manager/SpecialPriceManagerTest.java @@ -72,7 +72,7 @@ public void init() { i18nManager = mock(I18nManager.class); configurationManager = mock(ConfigurationManager.class); - List specialPrices = asList(new SpecialPrice(0, "123", 0, 0, "FREE", null, null, null, null, null), new SpecialPrice(0, "456", 0, 0, "FREE", null, null, null, null, null)); + List specialPrices = asList(new SpecialPrice(0, "123", 0, 0, "FREE", null, null, null, null), new SpecialPrice(0, "456", 0, 0, "FREE", null, null, null, null)); when(i18nManager.getEventLanguages(anyInt())).thenReturn(Collections.singletonList(ContentLanguage.ITALIAN)); when(messageSource.getMessage(anyString(), any(), any())).thenReturn("text"); when(eventManager.getSingleEvent(anyString(), anyString())).thenReturn(event); diff --git a/src/test/java/alfio/manager/TicketReservationManagerTest.java b/src/test/java/alfio/manager/TicketReservationManagerTest.java index 46196b0675..251b572d98 100644 --- a/src/test/java/alfio/manager/TicketReservationManagerTest.java +++ b/src/test/java/alfio/manager/TicketReservationManagerTest.java @@ -533,8 +533,8 @@ void reserveTicketsForCategoryWithAccessCode() { when(ticket.getSrcPriceCts()).thenReturn(1000); when(specialPriceRepository.bindToSession(eq(RESERVATION_ID), eq(TICKET_CATEGORY_ID), eq(accessCodeId), eq(2))).thenReturn(2); when(specialPriceRepository.findBySessionIdAndAccessCodeId(eq(RESERVATION_ID), eq(accessCodeId))).thenReturn(List.of( - new SpecialPrice(1, "AAAA", 0, TICKET_CATEGORY_ID, SpecialPrice.Status.FREE.name(), RESERVATION_ID, null, null, null, accessCodeId), - new SpecialPrice(2, "BBBB", 0, TICKET_CATEGORY_ID, SpecialPrice.Status.FREE.name(), RESERVATION_ID, null, null, null, accessCodeId) + new SpecialPrice(1, "AAAA", 0, TICKET_CATEGORY_ID, SpecialPrice.Status.FREE.name(), null, null, null, accessCodeId), + new SpecialPrice(2, "BBBB", 0, TICKET_CATEGORY_ID, SpecialPrice.Status.FREE.name(), null, null, null, accessCodeId) )); when(ticketRepository.selectNotAllocatedTicketsForUpdateSkipLocked(eq(EVENT_ID), eq(2), eq(List.of("FREE")))).thenReturn(List.of(TICKET_ID,2)); when(ticketRepository.findById(eq(TICKET_ID), eq(TICKET_CATEGORY_ID))).thenReturn(ticket); @@ -542,7 +542,7 @@ void reserveTicketsForCategoryWithAccessCode() { when(ticketRepository.batchReserveTicket()).thenReturn(query); trm.reserveTicketsForCategory(event, RESERVATION_ID, reservationModification, Locale.ENGLISH, false, discount); verify(jdbcTemplate).batchUpdate(eq(query), any(SqlParameterSource[].class)); - verify(specialPriceRepository).batchUpdateStatus(eq(List.of(1,2)), eq(SpecialPrice.Status.PENDING), eq(RESERVATION_ID), eq(accessCodeId)); + verify(specialPriceRepository).batchUpdateStatus(eq(List.of(1,2)), eq(SpecialPrice.Status.PENDING), eq(accessCodeId)); } @Test @@ -562,7 +562,7 @@ void cancelPendingReservationAndRenewCode() { when(ticketReservationRepository.remove(eq(singletonList(RESERVATION_ID)))).thenReturn(1); when(specialPriceRepository.getByCode(eq(SPECIAL_PRICE_CODE))).thenReturn(Optional.of(specialPrice)); when(specialPrice.getStatus()).thenReturn(SpecialPrice.Status.PENDING); - when(specialPrice.getSessionIdentifier()).thenReturn(SPECIAL_PRICE_SESSION_ID); + //when(specialPrice.getSessionIdentifier()).thenReturn(SPECIAL_PRICE_SESSION_ID); //verify(specialPriceRepository).resetToFreeAndCleanupForReservation(eq(singletonList(RESERVATION_ID))); //verify(ticketRepository).resetCategoryIdForUnboundedCategories(eq(singletonList(RESERVATION_ID))); //verify(ticketRepository).releaseExpiredTicket(eq(RESERVATION_ID), eq(EVENT_ID), eq(TICKET_ID), anyString()); From 78bc78d13c06609bafca3d87743fdda6a0453bee Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Tue, 25 Jun 2019 16:42:24 +0200 Subject: [PATCH 21/29] add test for reservation for hidden category #657 --- build.gradle | 2 +- .../api/v2/user/EventApiV2Controller.java | 1 - .../manager/TicketReservationManager.java | 4 ++- .../user/ReservationFlowIntegrationTest.java | 30 +++++++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 44427230b0..5485fae06b 100644 --- a/build.gradle +++ b/build.gradle @@ -131,7 +131,7 @@ dependencies { compile "org.springframework.security:spring-security-web:$springSecurityConfigVersion" compile "org.springframework.security:spring-security-config:$springSecurityConfigVersion" compile 'org.springframework.session:spring-session:1.3.5.RELEASE' - compile "ch.digitalfondue.npjt-extra:npjt-extra:2.0.0" + compile "ch.digitalfondue.npjt-extra:npjt-extra:2.0.1" compile "com.samskivert:jmustache:1.14" compile "com.github.sps.mustache:mustache-spring-view:1.4" compile "javax.mail:mail:1.5.0-b01" diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index 1a9cb387ba..2fd3cb4305 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -527,7 +527,6 @@ public ResponseEntity handleCode(@PathVariable("eventName") String eventNa var codeType = getCodeType(e.getId(), trimmedCode); - var maybeSpecialPrice = checkedCode.getValue().getLeft(); var maybePromoCodeDiscount = checkedCode.getValue().getRight(); if(checkedCode.isSuccess() && codeType == CodeType.PROMO_CODE_DISCOUNT) { diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index 29dc0aebf6..c4932b453e 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -1708,7 +1708,7 @@ public boolean hasPaidSupplements(String reservationId) { return additionalServiceItemRepository.hasPaidSupplements(reservationId); } - void revertTicketsToFreeIfAccessRestricted(int eventId) { + public int revertTicketsToFreeIfAccessRestricted(int eventId) { List restrictedCategories = ticketCategoryRepository.findByEventId(eventId).stream() .filter(TicketCategory::isAccessRestricted) .map(TicketCategory::getId) @@ -1718,7 +1718,9 @@ void revertTicketsToFreeIfAccessRestricted(int eventId) { if(count > 0) { log.debug("reverted {} tickets for categories {}", count, restrictedCategories); } + return count; } + return 0; } diff --git a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java index e5c685b3f6..12c17e5647 100644 --- a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java @@ -165,6 +165,12 @@ public static class ControllerConfiguration { @Autowired private AdminReservationManager adminReservationManager; + + @Autowired + private TicketReservationManager ticketReservationManager; + + @Autowired + private WaitingQueueSubscriptionProcessor waitingQueueSubscriptionProcessor; // // @@ -459,6 +465,24 @@ public void reservationFlowTest() throws Exception { assertEquals("1.00", hiddenCat.getFormattedFinalPrice()); assertFalse(hiddenCat.isHasDiscount()); assertTrue(hiddenCat.isAccessRestricted()); + + // do a reservation for a hidden category+cancel + var form = new ReservationForm(); + var ticketReservation = new TicketReservationModification(); + form.setPromoCode(HIDDEN_CODE); + ticketReservation.setAmount(1); + ticketReservation.setTicketCategoryId(hiddenCat.getId()); + form.setReservation(Collections.singletonList(ticketReservation)); + var res = eventApiV2Controller.reserveTickets(event.getShortName(), "en", form, new BeanPropertyBindingResult(form, "reservation"), new ServletWebRequest(new MockHttpServletRequest(), new MockHttpServletResponse())); + assertEquals(HttpStatus.OK, res.getStatusCode()); + var reservationInfo = reservationApiV2Controller.getReservationInfo(event.getShortName(), res.getBody().getValue(), new MockHttpSession()); + assertEquals(HttpStatus.OK, reservationInfo.getStatusCode()); + assertEquals("1.00", reservationInfo.getBody().getOrderSummary().getTotalPrice()); + assertEquals("hidden", reservationInfo.getBody().getOrderSummary().getSummary().get(0).getName()); + reservationApiV2Controller.cancelPendingReservation(event.getShortName(), res.getBody().getValue(), new MockHttpServletRequest()); + + // this is run by a job, but given the fact that it's in another separate transaction, it cannot work in this test (WaitingQueueSubscriptionProcessor.handleWaitingTickets) + assertEquals(1, ticketReservationManager.revertTicketsToFreeIfAccessRestricted(event.getId())); } // @@ -477,6 +501,9 @@ public void reservationFlowTest() throws Exception { reservationApiV2Controller.cancelPendingReservation(event.getShortName(), reservationId, new MockHttpServletRequest()); assertEquals(2, specialPriceRepository.findActiveNotAssignedByCategoryId(hiddenCategoryId).size()); + + // this is run by a job, but given the fact that it's in another separate transaction, it cannot work in this test (WaitingQueueSubscriptionProcessor.handleWaitingTickets) + assertEquals(1, ticketReservationManager.revertTicketsToFreeIfAccessRestricted(event.getId())); } // check reservation auto creation with deletion from the admin side @@ -495,6 +522,9 @@ public void reservationFlowTest() throws Exception { assertEquals(2, specialPriceRepository.findActiveNotAssignedByCategoryId(hiddenCategoryId).size()); + // this is run by a job, but given the fact that it's in another separate transaction, it cannot work in this test (WaitingQueueSubscriptionProcessor.handleWaitingTickets) + assertEquals(1, ticketReservationManager.revertTicketsToFreeIfAccessRestricted(event.getId())); + } From e9d5d6a624abef2529e5e1530d26df69f4987fc9 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Tue, 25 Jun 2019 17:12:20 +0200 Subject: [PATCH 22/29] remove last piece of sessionId in special price #657 --- .../java/alfio/manager/TicketReservationManager.java | 10 +++++----- src/main/java/alfio/model/SpecialPrice.java | 3 --- .../java/alfio/repository/SpecialPriceRepository.java | 10 ++++------ .../alfio/manager/TicketReservationManagerTest.java | 3 +-- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index c4932b453e..314e8be807 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -299,7 +299,7 @@ void reserveTicketsForCategory(Event event, String reservationId, TicketReservat && ticketReservation.getTicketCategoryId().equals(discount.getHiddenCategoryId()) && ticketCategoryRepository.isAccessRestricted(discount.getHiddenCategoryId()) ) { - specialPrices = reserveTokens(reservationId, ticketReservation, discount); + specialPrices = reserveTokens(ticketReservation, discount); } else { //first check if there is another pending special price token bound to the current sessionId Optional specialPrice = fixToken(ticketReservation.getSpecialPrice(), ticketReservation.getTicketCategoryId(), event.getId(), ticketReservation); @@ -348,13 +348,13 @@ void reserveTicketsForCategory(Event event, String reservationId, TicketReservat ticketRepository.updateTicketPrice(reservedForUpdate, category.getId(), event.getId(), category.getSrcPriceCts(), MonetaryUtil.unitToCents(priceContainer.getFinalPrice()), MonetaryUtil.unitToCents(priceContainer.getVAT()), MonetaryUtil.unitToCents(priceContainer.getAppliedDiscount())); } - private List reserveTokens(String reservationId, TicketReservationWithOptionalCodeModification ticketReservation, PromoCodeDiscount discount) { + private List reserveTokens(TicketReservationWithOptionalCodeModification ticketReservation, PromoCodeDiscount discount) { try { - int count = specialPriceRepository.bindToSession(reservationId, ticketReservation.getTicketCategoryId(), discount.getId(), ticketReservation.getAmount()); - if(count != ticketReservation.getAmount()) { + List boundSpecialPrices = specialPriceRepository.bindToAccessCode(ticketReservation.getTicketCategoryId(), discount.getId(), ticketReservation.getAmount()); + if(boundSpecialPrices.size() != ticketReservation.getAmount()) { throw new NotEnoughTicketsException(); } - return specialPriceRepository.findBySessionIdAndAccessCodeId(reservationId, discount.getId()); + return boundSpecialPrices; } catch (Exception e) { log.trace("constraints violated", e); if(e instanceof NotEnoughTicketsException) { diff --git a/src/main/java/alfio/model/SpecialPrice.java b/src/main/java/alfio/model/SpecialPrice.java index 476164f969..aa3706ffe8 100644 --- a/src/main/java/alfio/model/SpecialPrice.java +++ b/src/main/java/alfio/model/SpecialPrice.java @@ -33,7 +33,6 @@ public enum Status { private final int priceInCents; private final int ticketCategoryId; private final Status status; - //private final String sessionIdentifier; private final ZonedDateTime sentTimestamp; private final String recipientName; private final String recipientEmail; @@ -44,7 +43,6 @@ public SpecialPrice(@Column("id") int id, @Column("price_cts") int priceInCents, @Column("ticket_category_id") int ticketCategoryId, @Column("status") String status, - //@Column("session_id") String sessionIdentifier, @Column("sent_ts") ZonedDateTime sentTimestamp, @Column("recipient_name") String recipientName, @Column("recipient_email") String recipientEmail, @@ -54,7 +52,6 @@ public SpecialPrice(@Column("id") int id, this.priceInCents = priceInCents; this.ticketCategoryId = ticketCategoryId; this.status = Status.valueOf(status); - //this.sessionIdentifier = sessionIdentifier; this.sentTimestamp = sentTimestamp; this.recipientName = recipientName; this.recipientEmail = recipientEmail; diff --git a/src/main/java/alfio/repository/SpecialPriceRepository.java b/src/main/java/alfio/repository/SpecialPriceRepository.java index 7e1866740d..0f39185913 100644 --- a/src/main/java/alfio/repository/SpecialPriceRepository.java +++ b/src/main/java/alfio/repository/SpecialPriceRepository.java @@ -21,6 +21,7 @@ import ch.digitalfondue.npjt.Bind; import ch.digitalfondue.npjt.Query; import ch.digitalfondue.npjt.QueryRepository; +import ch.digitalfondue.npjt.QueryType; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -47,13 +48,10 @@ public interface SpecialPriceRepository { @Query(SELECT_FREE) List findActiveNotAssignedByCategoryId(@Bind("ticketCategoryId") int ticketCategoryId); - @Query("update special_price set session_id = :sessionId, access_code_id_fk = :accessCodeId where id in (" + + @Query(type= QueryType.MODIFYING_WITH_RETURN, value = "update special_price set access_code_id_fk = :accessCodeId where id in (" + "select id from special_price where ticket_category_id = :ticketCategoryId and " +IS_FREE+ " and access_code_id_fk is null limit :limitTo" + - ")") - int bindToSession(@Bind("sessionId") String sessionIdentifier, @Bind("ticketCategoryId") int ticketCategoryId, @Bind("accessCodeId") Integer accessCodeId, @Bind("limitTo") int limitTo); - - @Query("select * from special_price where session_id = :sessionId and access_code_id_fk = :accessCodeId") - List findBySessionIdAndAccessCodeId(@Bind("sessionId") String sessionIdentifier, @Bind("accessCodeId") int accessCodeId); + ") returning *") + List bindToAccessCode(@Bind("ticketCategoryId") int ticketCategoryId, @Bind("accessCodeId") Integer accessCodeId, @Bind("limitTo") int limitTo); @Query("update special_price set sent_ts = :timestamp, recipient_name = :recipientName, recipient_email = :recipientAddress where code = :code") int markAsSent(@Bind("timestamp") ZonedDateTime timestamp, @Bind("recipientName") String recipientName, @Bind("recipientAddress") String recipientAddress, @Bind("code") String code); diff --git a/src/test/java/alfio/manager/TicketReservationManagerTest.java b/src/test/java/alfio/manager/TicketReservationManagerTest.java index 251b572d98..48f448af12 100644 --- a/src/test/java/alfio/manager/TicketReservationManagerTest.java +++ b/src/test/java/alfio/manager/TicketReservationManagerTest.java @@ -531,8 +531,7 @@ void reserveTicketsForCategoryWithAccessCode() { when(ticketCategoryRepository.isAccessRestricted(eq(TICKET_CATEGORY_ID))).thenReturn(true); when(ticketReservation.getSrcPriceCts()).thenReturn(1000); when(ticket.getSrcPriceCts()).thenReturn(1000); - when(specialPriceRepository.bindToSession(eq(RESERVATION_ID), eq(TICKET_CATEGORY_ID), eq(accessCodeId), eq(2))).thenReturn(2); - when(specialPriceRepository.findBySessionIdAndAccessCodeId(eq(RESERVATION_ID), eq(accessCodeId))).thenReturn(List.of( + when(specialPriceRepository.bindToAccessCode(eq(TICKET_CATEGORY_ID), eq(accessCodeId), eq(2))).thenReturn(List.of( new SpecialPrice(1, "AAAA", 0, TICKET_CATEGORY_ID, SpecialPrice.Status.FREE.name(), null, null, null, accessCodeId), new SpecialPrice(2, "BBBB", 0, TICKET_CATEGORY_ID, SpecialPrice.Status.FREE.name(), null, null, null, accessCodeId) )); From 243ba1bdd7aea02273f95838fd2dbe9109516b3d Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Tue, 25 Jun 2019 17:18:09 +0200 Subject: [PATCH 23/29] refactor: switch from Integer to int for param #657 --- src/main/java/alfio/repository/SpecialPriceRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/alfio/repository/SpecialPriceRepository.java b/src/main/java/alfio/repository/SpecialPriceRepository.java index 0f39185913..50c1ff5b56 100644 --- a/src/main/java/alfio/repository/SpecialPriceRepository.java +++ b/src/main/java/alfio/repository/SpecialPriceRepository.java @@ -51,7 +51,7 @@ public interface SpecialPriceRepository { @Query(type= QueryType.MODIFYING_WITH_RETURN, value = "update special_price set access_code_id_fk = :accessCodeId where id in (" + "select id from special_price where ticket_category_id = :ticketCategoryId and " +IS_FREE+ " and access_code_id_fk is null limit :limitTo" + ") returning *") - List bindToAccessCode(@Bind("ticketCategoryId") int ticketCategoryId, @Bind("accessCodeId") Integer accessCodeId, @Bind("limitTo") int limitTo); + List bindToAccessCode(@Bind("ticketCategoryId") int ticketCategoryId, @Bind("accessCodeId") int accessCodeId, @Bind("limitTo") int limitTo); @Query("update special_price set sent_ts = :timestamp, recipient_name = :recipientName, recipient_email = :recipientAddress where code = :code") int markAsSent(@Bind("timestamp") ZonedDateTime timestamp, @Bind("recipientName") String recipientName, @Bind("recipientAddress") String recipientAddress, @Bind("code") String code); From e92662e75e120176249a39db63a68e704c28e1ac Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Tue, 25 Jun 2019 21:50:06 +0200 Subject: [PATCH 24/29] select for update skip locked for special price #657 --- .../java/alfio/manager/TicketReservationManager.java | 9 ++++----- .../java/alfio/repository/SpecialPriceRepository.java | 5 ++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index 314e8be807..f742867568 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -402,13 +402,12 @@ Optional fixToken(Optional token, int ticketCategory return Optional.empty(); } - Optional specialPrice = token;//note, we don't use anymore, renewSpecialPrice(token, specialPriceSessionId); + Optional specialPrice = token.map(SpecialPrice::getCode).flatMap(specialPriceRepository::getForUpdateByCode); - // TODO: check. this condition cannot be true. In theory, you cannot have an invalid one when you enter here - //if(token.isPresent() && specialPrice.isEmpty()) { + if(token.isPresent() && specialPrice.isEmpty()) { //there is a special price in the request but this isn't valid anymore - //throw new InvalidSpecialPriceTokenException(); - //} + throw new InvalidSpecialPriceTokenException(); + } boolean canAccessRestrictedCategory = specialPrice.isPresent() && specialPrice.get().getStatus() == SpecialPrice.Status.FREE diff --git a/src/main/java/alfio/repository/SpecialPriceRepository.java b/src/main/java/alfio/repository/SpecialPriceRepository.java index 50c1ff5b56..dae9155a9f 100644 --- a/src/main/java/alfio/repository/SpecialPriceRepository.java +++ b/src/main/java/alfio/repository/SpecialPriceRepository.java @@ -49,7 +49,7 @@ public interface SpecialPriceRepository { List findActiveNotAssignedByCategoryId(@Bind("ticketCategoryId") int ticketCategoryId); @Query(type= QueryType.MODIFYING_WITH_RETURN, value = "update special_price set access_code_id_fk = :accessCodeId where id in (" + - "select id from special_price where ticket_category_id = :ticketCategoryId and " +IS_FREE+ " and access_code_id_fk is null limit :limitTo" + + "select id from special_price where ticket_category_id = :ticketCategoryId and " +IS_FREE+ " and access_code_id_fk is null for update skip locked limit :limitTo" + ") returning *") List bindToAccessCode(@Bind("ticketCategoryId") int ticketCategoryId, @Bind("accessCodeId") int accessCodeId, @Bind("limitTo") int limitTo); @@ -62,6 +62,9 @@ public interface SpecialPriceRepository { @Query("select * from special_price where code = :code") Optional getByCode(@Bind("code") String code); + @Query("select * from special_price where code = :code for update skip locked") + Optional getForUpdateByCode(@Bind("code") String code); + @Query("select count(*) from special_price where code = :code") Integer countByCode(@Bind("code") String code); From ed0c61887ddb845ef7441428e374934d56fbe2bc Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Wed, 26 Jun 2019 14:08:31 +0200 Subject: [PATCH 25/29] return binding result #657 --- .../controller/api/v2/user/EventApiV2Controller.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index 2fd3cb4305..dfcb85fbea 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -444,7 +444,7 @@ public ResponseEntity> reserveTickets(@PathVariable("e } codeCheck = Optional.of(resCheck); } - Optional specialPrice = codeCheck.map(ValidatedResponse::getValue).flatMap(Pair::getLeft).map(SpecialPrice::getCode); + Optional promoCodeDiscount = codeCheck.map(ValidatedResponse::getValue).flatMap(Pair::getRight).map(PromoCodeDiscount::getPromoCode); @@ -534,7 +534,7 @@ public ResponseEntity handleCode(@PathVariable("eventName") String eventNa } else if(codeType == CodeType.TICKET_CATEGORY_CODE) { var category = ticketCategoryRepository.findCodeInEvent(e.getId(), trimmedCode).get(); if(!category.isAccessRestricted()) { - return makeSimpleReservation(e, category.getId(), trimmedCode, request, maybePromoCodeDiscount); + return makeSimpleReservation(e, category.getId(), trimmedCode, request, maybePromoCodeDiscount).getLeft(); } else { var specialPrice = specialPriceRepository.findActiveNotAssignedByCategoryId(category.getId()).stream().findFirst(); if(!specialPrice.isPresent()) { @@ -542,11 +542,11 @@ public ResponseEntity handleCode(@PathVariable("eventName") String eventNa } var specialPriceP = specialPrice.get(); // <- work only when TicketReservationManager.renewSpecialPrice is commented out - return makeSimpleReservation(e, specialPriceP.getTicketCategoryId(), specialPriceP.getCode(), request, maybePromoCodeDiscount); + return makeSimpleReservation(e, specialPriceP.getTicketCategoryId(), specialPriceP.getCode(), request, maybePromoCodeDiscount).getLeft(); } } else if (checkedCode.isSuccess() && codeType == CodeType.SPECIAL_PRICE) { int ticketCategoryId = specialPriceRepository.getByCode(trimmedCode).get().getTicketCategoryId(); - return makeSimpleReservation(e, ticketCategoryId, trimmedCode, request, maybePromoCodeDiscount); + return makeSimpleReservation(e, ticketCategoryId, trimmedCode, request, maybePromoCodeDiscount).getLeft(); } else { return Optional.empty(); // <- failure? TODO: add error code in query string? } @@ -560,7 +560,7 @@ public ResponseEntity handleCode(@PathVariable("eventName") String eventNa return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).header(HttpHeaders.LOCATION, url).build(); } - private Optional makeSimpleReservation(Event event, + private Pair, BindingResult> makeSimpleReservation(Event event, int ticketCategoryId, String promoCode, ServletWebRequest request, @@ -574,7 +574,7 @@ private Optional makeSimpleReservation(Event event, reservation.setTicketCategoryId(ticketCategoryId); form.setReservation(Collections.singletonList(reservation)); var bindingRes = new BeanPropertyBindingResult(form, "reservationForm"); - return createTicketReservation(form, bindingRes, request, event, locale, promoCodeDiscount.map(PromoCodeDiscount::getPromoCode)); + return Pair.of(createTicketReservation(form, bindingRes, request, event, locale, promoCodeDiscount.map(PromoCodeDiscount::getPromoCode)), bindingRes); } /** From ac5f085d3a844a79fb553f2d266a9a2ee2b375df Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Wed, 26 Jun 2019 14:44:17 +0200 Subject: [PATCH 26/29] {code} flow: add query string for errors #657 --- .../api/v2/user/EventApiV2Controller.java | 34 ++++++++++++++----- .../user/ReservationFlowIntegrationTest.java | 13 +++++++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index dfcb85fbea..32eb13633e 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -521,6 +521,7 @@ public ResponseEntity> validateCode(@PathVariable(" @GetMapping("event/{eventName}/code/{code}") public ResponseEntity handleCode(@PathVariable("eventName") String eventName, @PathVariable("code") String code, ServletWebRequest request) { String trimmedCode = StringUtils.trimToNull(code); + Map queryStrings = new HashMap<>(); var url = eventRepository.findOptionalByShortName(eventName).flatMap(e -> { var checkedCode = checkCode(e, trimmedCode); @@ -530,32 +531,49 @@ public ResponseEntity handleCode(@PathVariable("eventName") String eventNa var maybePromoCodeDiscount = checkedCode.getValue().getRight(); if(checkedCode.isSuccess() && codeType == CodeType.PROMO_CODE_DISCOUNT) { - return Optional.empty();//TODO: redirectToEvent with code in query string? + queryStrings.put("code", trimmedCode); + return Optional.empty(); } else if(codeType == CodeType.TICKET_CATEGORY_CODE) { var category = ticketCategoryRepository.findCodeInEvent(e.getId(), trimmedCode).get(); if(!category.isAccessRestricted()) { - return makeSimpleReservation(e, category.getId(), trimmedCode, request, maybePromoCodeDiscount).getLeft(); + var res = makeSimpleReservation(e, category.getId(), trimmedCode, request, maybePromoCodeDiscount); + return res.getLeft(); } else { var specialPrice = specialPriceRepository.findActiveNotAssignedByCategoryId(category.getId()).stream().findFirst(); if(!specialPrice.isPresent()) { - return Optional.empty(); //<- failure? TODO: add error code in query string? + queryStrings.put("errors", ErrorsCode.STEP_1_CODE_NOT_FOUND); + return Optional.empty(); } var specialPriceP = specialPrice.get(); // <- work only when TicketReservationManager.renewSpecialPrice is commented out - return makeSimpleReservation(e, specialPriceP.getTicketCategoryId(), specialPriceP.getCode(), request, maybePromoCodeDiscount).getLeft(); + var res = makeSimpleReservation(e, specialPriceP.getTicketCategoryId(), specialPriceP.getCode(), request, maybePromoCodeDiscount); + + if (res.getRight().hasErrors()) { + queryStrings.put("errors", res.getRight().getAllErrors().stream().map(oe -> oe.getCode()).collect(Collectors.joining(","))); + } + + return res.getLeft(); } } else if (checkedCode.isSuccess() && codeType == CodeType.SPECIAL_PRICE) { int ticketCategoryId = specialPriceRepository.getByCode(trimmedCode).get().getTicketCategoryId(); - return makeSimpleReservation(e, ticketCategoryId, trimmedCode, request, maybePromoCodeDiscount).getLeft(); + var res = makeSimpleReservation(e, ticketCategoryId, trimmedCode, request, maybePromoCodeDiscount); + if (res.getRight().hasErrors()) { + queryStrings.put("errors", res.getRight().getAllErrors().stream().map(oe -> oe.getCode()).collect(Collectors.joining(","))); + } + return res.getLeft(); } else { - return Optional.empty(); // <- failure? TODO: add error code in query string? + queryStrings.put("errors", ErrorsCode.STEP_1_CODE_NOT_FOUND); + return Optional.empty(); } }).map(reservationId -> UriComponentsBuilder.fromPath("/event/{eventShortName}/reservation/{reservationId}") .build(Map.of("eventShortName", eventName, "reservationId", reservationId)) .toString()) - .orElseGet(() -> - UriComponentsBuilder.fromPath("/event/{eventShortName}").build(Map.of("eventShortName", eventName)).toString() + .orElseGet(() -> { + var backToEvent = UriComponentsBuilder.fromPath("/event/{eventShortName}"); + queryStrings.forEach(backToEvent::queryParam); + return backToEvent.build(Map.of("eventShortName", eventName)).toString(); + } ); return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).header(HttpHeaders.LOCATION, url).build(); } diff --git a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java index 12c17e5647..a5cae78869 100644 --- a/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/ReservationFlowIntegrationTest.java @@ -489,6 +489,19 @@ public void reservationFlowTest() throws Exception { // check reservation auto creation with code: TODO: will need to check all the flows { + // code not found + var notFoundRes = eventApiV2Controller.handleCode(event.getShortName(), "NOT_EXIST", new ServletWebRequest(new MockHttpServletRequest(), new MockHttpServletResponse())); + assertEquals("/event/" + event.getShortName(), notFoundRes.getHeaders().getLocation().getPath()); + assertEquals("errors=error.STEP_1_CODE_NOT_FOUND", notFoundRes.getHeaders().getLocation().getQuery()); + // + + // promo code, we expect a redirect to event with the code in the query string + var redirectPromoCodeRes = eventApiV2Controller.handleCode(event.getShortName(), PROMO_CODE, new ServletWebRequest(new MockHttpServletRequest(), new MockHttpServletResponse())); + assertEquals("/event/" + event.getShortName(), redirectPromoCodeRes.getHeaders().getLocation().getPath()); + assertEquals("code=MYPROMOCODE", redirectPromoCodeRes.getHeaders().getLocation().getQuery()); + + + // code existing assertEquals(2, specialPriceRepository.findActiveNotAssignedByCategoryId(hiddenCategoryId).size()); var res = eventApiV2Controller.handleCode(event.getShortName(), URL_CODE_HIDDEN, new ServletWebRequest(new MockHttpServletRequest(), new MockHttpServletResponse())); var reservationId = res.getHeaders().getLocation().toString().substring(("/event/" + event.getShortName() + "/reservation/").length()); From ccc7719ff5c6faf95b32e0a0832a587deeddc9b9 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Wed, 26 Jun 2019 14:59:43 +0200 Subject: [PATCH 27/29] {code} flow: add query string for errors #657 --- .../api/v2/user/EventApiV2Controller.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index 32eb13633e..ef438a9296 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -62,6 +62,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.*; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -522,6 +523,14 @@ public ResponseEntity> validateCode(@PathVariable(" public ResponseEntity handleCode(@PathVariable("eventName") String eventName, @PathVariable("code") String code, ServletWebRequest request) { String trimmedCode = StringUtils.trimToNull(code); Map queryStrings = new HashMap<>(); + + Function, BindingResult>, Optional> handleErrors = (res) -> { + if (res.getRight().hasErrors()) { + queryStrings.put("errors", res.getRight().getAllErrors().stream().map(oe -> oe.getCode()).collect(Collectors.joining(","))); + } + return res.getLeft(); + }; + var url = eventRepository.findOptionalByShortName(eventName).flatMap(e -> { var checkedCode = checkCode(e, trimmedCode); @@ -537,7 +546,7 @@ public ResponseEntity handleCode(@PathVariable("eventName") String eventNa var category = ticketCategoryRepository.findCodeInEvent(e.getId(), trimmedCode).get(); if(!category.isAccessRestricted()) { var res = makeSimpleReservation(e, category.getId(), trimmedCode, request, maybePromoCodeDiscount); - return res.getLeft(); + return handleErrors.apply(res); } else { var specialPrice = specialPriceRepository.findActiveNotAssignedByCategoryId(category.getId()).stream().findFirst(); if(!specialPrice.isPresent()) { @@ -547,20 +556,12 @@ public ResponseEntity handleCode(@PathVariable("eventName") String eventNa var specialPriceP = specialPrice.get(); // <- work only when TicketReservationManager.renewSpecialPrice is commented out var res = makeSimpleReservation(e, specialPriceP.getTicketCategoryId(), specialPriceP.getCode(), request, maybePromoCodeDiscount); - - if (res.getRight().hasErrors()) { - queryStrings.put("errors", res.getRight().getAllErrors().stream().map(oe -> oe.getCode()).collect(Collectors.joining(","))); - } - - return res.getLeft(); + return handleErrors.apply(res); } } else if (checkedCode.isSuccess() && codeType == CodeType.SPECIAL_PRICE) { int ticketCategoryId = specialPriceRepository.getByCode(trimmedCode).get().getTicketCategoryId(); var res = makeSimpleReservation(e, ticketCategoryId, trimmedCode, request, maybePromoCodeDiscount); - if (res.getRight().hasErrors()) { - queryStrings.put("errors", res.getRight().getAllErrors().stream().map(oe -> oe.getCode()).collect(Collectors.joining(","))); - } - return res.getLeft(); + return handleErrors.apply(res); } else { queryStrings.put("errors", ErrorsCode.STEP_1_CODE_NOT_FOUND); return Optional.empty(); From 8102450a8eae53325ec4b599b3e1403cb305e8f9 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Wed, 26 Jun 2019 15:17:16 +0200 Subject: [PATCH 28/29] update frontend #657 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 0d0d06e648..58ec9185e4 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=c397155127 \ No newline at end of file +alfioPublicFrontendVersion=a46a930667 \ No newline at end of file From 5d5c2800b3df99559d41b855c6b073200813d2be Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Wed, 26 Jun 2019 15:42:28 +0200 Subject: [PATCH 29/29] update frontend #657 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 58ec9185e4..efe92b4d54 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=a46a930667 \ No newline at end of file +alfioPublicFrontendVersion=328724c45d \ No newline at end of file