Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement #328 event code url #329

Merged
merged 7 commits into from
Aug 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 104 additions & 39 deletions src/main/java/alfio/controller/EventController.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import alfio.manager.i18n.I18nManager;
import alfio.manager.system.ConfigurationManager;
import alfio.model.*;
import alfio.model.modification.TicketReservationModification;
import alfio.model.modification.support.LocationDescriptor;
import alfio.model.result.ValidationResult;
import alfio.model.system.Configuration;
Expand All @@ -44,6 +45,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.ServletWebRequest;
Expand All @@ -57,6 +59,7 @@
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static alfio.controller.EventController.CodeType.TICKET_CATEGORY_CODE;
import static alfio.controller.support.SessionUtil.addToFlash;
import static alfio.util.OptionalWrapper.optionally;

Expand Down Expand Up @@ -163,8 +166,8 @@ public ValidationResult savePromoCode(@PathVariable("eventName") String eventNam
Event event = optional.get();
ZonedDateTime now = ZonedDateTime.now(event.getZoneId());
Optional<String> maybeSpecialCode = Optional.ofNullable(StringUtils.trimToNull(promoCode));
Optional<SpecialPrice> specialCode = maybeSpecialCode.flatMap((trimmedCode) -> optionally(() -> specialPriceRepository.getByCode(trimmedCode)));
Optional<PromoCodeDiscount> promotionCodeDiscount = maybeSpecialCode.flatMap((trimmedCode) -> optionally(() -> promoCodeRepository.findPromoCodeInEventOrOrganization(event.getId(), trimmedCode)));
Optional<SpecialPrice> specialCode = maybeSpecialCode.flatMap((trimmedCode) -> specialPriceRepository.getByCode(trimmedCode));
Optional<PromoCodeDiscount> promotionCodeDiscount = maybeSpecialCode.flatMap((trimmedCode) -> promoCodeRepository.findPromoCodeInEventOrOrganization(event.getId(), trimmedCode));

if(specialCode.isPresent()) {
if (!optionally(() -> eventManager.getTicketCategoryById(specialCode.get().getTicketCategoryId(), event.getId())).isPresent()) {
Expand Down Expand Up @@ -198,10 +201,10 @@ public String showEvent(@PathVariable("eventName") String eventName,

return eventRepository.findOptionalByShortName(eventName).filter(e -> e.getStatus() != Event.Status.DISABLED).map(event -> {
Optional<String> maybeSpecialCode = SessionUtil.retrieveSpecialPriceCode(request);
Optional<SpecialPrice> specialCode = maybeSpecialCode.flatMap((trimmedCode) -> optionally(() -> specialPriceRepository.getByCode(trimmedCode)));
Optional<SpecialPrice> specialCode = maybeSpecialCode.flatMap((trimmedCode) -> specialPriceRepository.getByCode(trimmedCode));

Optional<PromoCodeDiscount> promoCodeDiscount = SessionUtil.retrievePromotionCodeDiscount(request)
.flatMap((code) -> optionally(() -> promoCodeRepository.findPromoCodeInEventOrOrganization(event.getId(), code)));
.flatMap((code) -> promoCodeRepository.findPromoCodeInEventOrOrganization(event.getId(), code));

final ZonedDateTime now = ZonedDateTime.now(event.getZoneId());
//hide access restricted ticket categories
Expand Down Expand Up @@ -264,6 +267,67 @@ public String showEvent(@PathVariable("eventName") String eventName,
}).orElse(REDIRECT + "/");
}


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 CodeType.NOT_FOUND;
}
}

@RequestMapping(value = "/event/{eventName}/code/{code}", method = {RequestMethod.GET, RequestMethod.HEAD})
public String handleCode(@PathVariable("eventName") String eventName, @PathVariable("code") String code, Model model, ServletWebRequest request, RedirectAttributes redirectAttributes, Locale locale) {
String trimmedCode = StringUtils.trimToNull(code);
return eventRepository.findOptionalByShortName(eventName).map(event -> {
String redirectToEvent = "redirect:/event/" + eventName + "/";
ValidationResult res = savePromoCode(eventName, trimmedCode, model, request.getRequest());
CodeType codeType = getCodeType(event.getId(), trimmedCode);
if(res.isSuccess() && codeType == CodeType.PROMO_CODE_DISCOUNT) {
return redirectToEvent;
} else if (codeType == CodeType.TICKET_CATEGORY_CODE) {
TicketCategory category = ticketCategoryRepository.findCodeInEvent(event.getId(), trimmedCode).get();
if(!category.isAccessRestricted()) {
return makeSimpleReservation(eventName, request, redirectAttributes, locale, null, event, category.getId());
} else {
Optional<SpecialPrice> specialPrice = specialPriceRepository.findActiveNotAssignedByCategoryId(category.getId()).stream().findFirst();
if(!specialPrice.isPresent()) {
return redirectToEvent;
}
savePromoCode(eventName, specialPrice.get().getCode(), model, request.getRequest());
return makeSimpleReservation(eventName, request, redirectAttributes, locale, specialPrice.get().getCode(), event, category.getId());
}
} else if (res.isSuccess() && codeType == CodeType.SPECIAL_PRICE) {
int ticketCategoryId = specialPriceRepository.getByCode(trimmedCode).get().getTicketCategoryId();
return makeSimpleReservation(eventName, request, redirectAttributes, locale, trimmedCode, event, ticketCategoryId);
} else {
return redirectToEvent;
}
}).orElse("redirect:/");
}

private String makeSimpleReservation(String eventName, ServletWebRequest request, RedirectAttributes redirectAttributes, Locale locale, String trimmedCode, Event event, int ticketCategoryId) {
ReservationForm form = new ReservationForm();
form.setPromoCode(trimmedCode);
TicketReservationModification reservation = new TicketReservationModification();
reservation.setAmount(1);
reservation.setTicketCategoryId(ticketCategoryId);
form.setReservation(Collections.singletonList(reservation));
return validateAndReserve(eventName, form, new BeanPropertyBindingResult(form, "reservationForm"), request, redirectAttributes, locale, event);
}

@RequestMapping(value = "/event/{eventName}/calendar/locale/{locale}", method = {RequestMethod.GET, RequestMethod.HEAD})
public void calendar(@PathVariable("eventName") String eventName, @PathVariable("locale") String locale, @RequestParam(value = "type", required = false) String calendarType, HttpServletResponse response) throws IOException {
Optional<Event> event = eventRepository.findOptionalByShortName(eventName);
Expand Down Expand Up @@ -299,46 +363,47 @@ public String reserveTicket(@PathVariable("eventName") String eventName,
ServletWebRequest request, RedirectAttributes redirectAttributes, Locale locale) {

return eventRepository.findOptionalByShortName(eventName).map(event -> {

final String redirectToEvent = "redirect:/event/" + eventName + "/";

if (request.getHttpMethod() == HttpMethod.GET) {
return redirectToEvent;
return "redirect:/event/" + eventName + "/";
} else {
return validateAndReserve(eventName, reservation, bindingResult, request, redirectAttributes, locale, event);
}
}).orElse("redirect:/");

return reservation.validate(bindingResult, ticketReservationManager, additionalServiceRepository, eventManager, event)
.map(selected -> {

Date expiration = DateUtils.addMinutes(new Date(), ticketReservationManager.getReservationTimeout(event));

try {
String reservationId = ticketReservationManager.createTicketReservation(event,
selected.getLeft(), selected.getRight(), expiration,
SessionUtil.retrieveSpecialPriceSessionId(request.getRequest()),
SessionUtil.retrievePromotionCodeDiscount(request.getRequest()),
locale, false);
return "redirect:/event/" + eventName + "/reservation/" + reservationId + "/book";
} catch (TicketReservationManager.NotEnoughTicketsException nete) {
bindingResult.reject(ErrorsCode.STEP_1_NOT_ENOUGH_TICKETS);
addToFlash(bindingResult, redirectAttributes);
return redirectToEvent;
} catch (TicketReservationManager.MissingSpecialPriceTokenException missing) {
bindingResult.reject(ErrorsCode.STEP_1_ACCESS_RESTRICTED);
addToFlash(bindingResult, redirectAttributes);
return redirectToEvent;
} catch (TicketReservationManager.InvalidSpecialPriceTokenException invalid) {
bindingResult.reject(ErrorsCode.STEP_1_CODE_NOT_FOUND);
addToFlash(bindingResult, redirectAttributes);
SessionUtil.removeSpecialPriceData(request.getRequest());
return redirectToEvent;
}
}).orElseGet(() -> {
}

private String validateAndReserve(String eventName, ReservationForm reservation, BindingResult bindingResult, ServletWebRequest request, RedirectAttributes redirectAttributes, Locale locale, Event event) {
final String redirectToEvent = "redirect:/event/" + eventName + "/";
return reservation.validate(bindingResult, ticketReservationManager, additionalServiceRepository, eventManager, event)
.map(selected -> {

Date expiration = DateUtils.addMinutes(new Date(), ticketReservationManager.getReservationTimeout(event));

try {
String reservationId = ticketReservationManager.createTicketReservation(event,
selected.getLeft(), selected.getRight(), expiration,
SessionUtil.retrieveSpecialPriceSessionId(request.getRequest()),
SessionUtil.retrievePromotionCodeDiscount(request.getRequest()),
locale, false);
return "redirect:/event/" + eventName + "/reservation/" + reservationId + "/book";
} catch (TicketReservationManager.NotEnoughTicketsException nete) {
bindingResult.reject(ErrorsCode.STEP_1_NOT_ENOUGH_TICKETS);
addToFlash(bindingResult, redirectAttributes);
return redirectToEvent;
});

}).orElse("redirect:/");

} catch (TicketReservationManager.MissingSpecialPriceTokenException missing) {
bindingResult.reject(ErrorsCode.STEP_1_ACCESS_RESTRICTED);
addToFlash(bindingResult, redirectAttributes);
return redirectToEvent;
} catch (TicketReservationManager.InvalidSpecialPriceTokenException invalid) {
bindingResult.reject(ErrorsCode.STEP_1_CODE_NOT_FOUND);
addToFlash(bindingResult, redirectAttributes);
SessionUtil.removeSpecialPriceData(request.getRequest());
return redirectToEvent;
}
}).orElseGet(() -> {
addToFlash(bindingResult, redirectAttributes);
return redirectToEvent;
});
}

private SaleableAdditionalService getSaleableAdditionalService(Event event, Locale locale, AdditionalService as, PromoCodeDiscount promoCodeDiscount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public List<EventListItem> listEvents(HttpServletRequest request) {
@RequestMapping("events/{shortName}")
public ResponseEntity<PublicEvent> showEvent(@PathVariable("shortName") String shortName, @RequestParam(value="specialCode", required = false) String specialCodeParam, HttpServletRequest request) {

Optional<SpecialPrice> specialCode = Optional.ofNullable(StringUtils.trimToNull(specialCodeParam)).flatMap((trimmedCode) -> optionally(() -> specialPriceRepository.getByCode(trimmedCode)));
Optional<SpecialPrice> specialCode = Optional.ofNullable(StringUtils.trimToNull(specialCodeParam)).flatMap((trimmedCode) -> specialPriceRepository.getByCode(trimmedCode));

return eventRepository.findOptionalByShortName(shortName).map((e) -> {
List<PublicCategory> categories = ticketCategoryRepository.findAllTicketCategories(e.getId()).stream()
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/alfio/controller/form/ReservationForm.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public Optional<Pair<List<TicketReservationWithOptionalCodeModification>, List<A
List<TicketReservationWithOptionalCodeModification> res = new ArrayList<>();
//
Optional<SpecialPrice> specialCode = Optional.ofNullable(StringUtils.trimToNull(promoCode)).flatMap(
(trimmedCode) -> OptionalWrapper.optionally(() -> tickReservationManager.getSpecialPriceByCode(trimmedCode)));
(trimmedCode) -> tickReservationManager.getSpecialPriceByCode(trimmedCode));
//
final ZonedDateTime now = ZonedDateTime.now(event.getZoneId());
maxTicketsByTicketReservation.forEach((pair) -> validateCategory(bindingResult, tickReservationManager, eventManager, event, pair.getRight(), res, specialCode, now, pair.getLeft()));
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/alfio/manager/AdminReservationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ private Result<TicketCategory> createCategory(TicketsInfo ti, Event event, Admin

int tickets = attendees.size();
TicketCategoryModification tcm = new TicketCategoryModification(category.getExistingCategoryId(), category.getName(), tickets,
inception, reservation.getExpiration(), Collections.emptyMap(), category.getPrice(), true, "", true);
inception, reservation.getExpiration(), Collections.emptyMap(), category.getPrice(), true, "", true, null);
int notAllocated = getNotAllocatedTickets(event);
int missingTickets = Math.max(tickets - notAllocated, 0);
Event modified = increaseSeatsIfNeeded(ti, event, missingTickets, event);
Expand Down Expand Up @@ -409,7 +409,7 @@ private Result<TicketCategory> checkExistingCategory(TicketsInfo ti, Event event
int maxTickets = existing.getMaxTickets() + (tickets - freeTicketsInCategory);
TicketCategoryModification tcm = new TicketCategoryModification(existingCategoryId, existing.getName(), maxTickets,
DateTimeModification.fromZonedDateTime(existing.getInception(modified.getZoneId())), DateTimeModification.fromZonedDateTime(existing.getExpiration(event.getZoneId())),
Collections.emptyMap(), existing.getPrice(), existing.isAccessRestricted(), "", true);
Collections.emptyMap(), existing.getPrice(), existing.isAccessRestricted(), "", true, existing.getCode());
return eventManager.updateCategory(existingCategoryId, modified, tcm, username);
}
return Result.success(existing);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/alfio/manager/EventManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ private void updateCategory(TicketCategoryModification tc, boolean freeOfCharge,
final int price = evaluatePrice(tc.getPriceInCents(), freeOfCharge);
TicketCategory original = ticketCategoryRepository.getById(tc.getId(), eventId);
ticketCategoryRepository.update(tc.getId(), tc.getName(), tc.getInception().toZonedDateTime(zoneId),
tc.getExpiration().toZonedDateTime(zoneId), tc.getMaxTickets(), tc.isTokenGenerationRequested(), price);
tc.getExpiration().toZonedDateTime(zoneId), tc.getMaxTickets(), tc.isTokenGenerationRequested(), price, StringUtils.trimToNull(tc.getCode()));
TicketCategory updated = ticketCategoryRepository.getById(tc.getId(), eventId);
int addedTickets = 0;
if(original.isBounded() ^ tc.isBounded()) {
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/alfio/manager/TicketReservationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public String createTicketReservation(Event event,
boolean forWaitingQueue) throws NotEnoughTicketsException, MissingSpecialPriceTokenException, InvalidSpecialPriceTokenException {
String reservationId = UUID.randomUUID().toString();

Optional<PromoCodeDiscount> discount = promotionCodeDiscount.flatMap((promoCodeDiscount) -> optionally(() -> promoCodeDiscountRepository.findPromoCodeInEventOrOrganization(event.getId(), promoCodeDiscount)));
Optional<PromoCodeDiscount> discount = promotionCodeDiscount.flatMap((promoCodeDiscount) -> promoCodeDiscountRepository.findPromoCodeInEventOrOrganization(event.getId(), promoCodeDiscount));

ticketReservationRepository.createNewReservation(reservationId, reservationExpiration, discount.map(PromoCodeDiscount::getId).orElse(null), locale.getLanguage(), event.getId());
list.forEach(t -> reserveTicketsForCategory(event, specialPriceSessionId, reservationId, t, locale, forWaitingQueue, discount.orElse(null)));
Expand Down Expand Up @@ -872,7 +872,7 @@ private void deleteReservations(List<String> reservationIdsToRemove) {
Validate.isTrue(removedReservation == 1, "expected exactly one removed reservation, got " + removedReservation);
}

public SpecialPrice getSpecialPriceByCode(String code) {
public Optional<SpecialPrice> getSpecialPriceByCode(String code) {
return specialPriceRepository.getByCode(code);
}

Expand All @@ -893,12 +893,12 @@ public Optional<SpecialPrice> renewSpecialPrice(Optional<SpecialPrice> specialPr

if(price.getStatus() == Status.FREE) {
specialPriceRepository.bindToSession(price.getId(), specialPriceSessionId.get());
return Optional.of(getSpecialPriceByCode(price.getCode()));
return getSpecialPriceByCode(price.getCode());
} else if(price.getStatus() == Status.PENDING) {
Optional<Ticket> optionalTicket = optionally(() -> ticketRepository.findBySpecialPriceId(price.getId()));
if(optionalTicket.isPresent()) {
cancelPendingReservation(optionalTicket.get().getTicketsReservationId(), false);
return Optional.of(getSpecialPriceByCode(price.getCode()));
return getSpecialPriceByCode(price.getCode());
}
}

Expand Down
Loading