Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package de.appsolve.padelcampus.controller.events; import de.appsolve.padelcampus.constants.BookingType; import de.appsolve.padelcampus.constants.EventType; import de.appsolve.padelcampus.constants.PaymentMethod; import de.appsolve.padelcampus.controller.BaseController; import de.appsolve.padelcampus.controller.bookings.BookingsPayDirektController; import de.appsolve.padelcampus.controller.bookings.BookingsPayMillController; import de.appsolve.padelcampus.controller.bookings.BookingsPayPalController; import de.appsolve.padelcampus.controller.bookings.BookingsVoucherController; import de.appsolve.padelcampus.db.dao.*; import de.appsolve.padelcampus.db.model.*; import de.appsolve.padelcampus.exceptions.MailException; import de.appsolve.padelcampus.spring.PlayerCollectionEditor; import de.appsolve.padelcampus.utils.*; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.joda.time.LocalDateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.validation.Validator; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.transaction.Transactional; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; import static org.springframework.web.bind.annotation.RequestMethod.GET; import static org.springframework.web.bind.annotation.RequestMethod.POST; /** * @author dominik */ @Controller() @RequestMapping("/events/bookings") public class EventsBookingController extends BaseController { private static final Logger LOG = Logger.getLogger(EventsBookingController.class); @Autowired EventDAOI eventDAO; @Autowired SessionUtil sessionUtil; @Autowired PlayerDAOI playerDAO; @Autowired Validator validator; @Autowired BookingDAOI bookingDAO; @Autowired CommunityDAOI communityDAO; @Autowired BookingsPayPalController bookingsPayPalController; @Autowired BookingsPayDirektController bookingsPayDirektController; @Autowired BookingsPayMillController bookingsPayMillController; @Autowired BookingsVoucherController bookingsVoucherController; @Autowired BookingUtil bookingUtil; @Autowired TeamDAOI teamDAO; @Autowired GameUtil gameUtil; @Autowired PlayerCollectionEditor playerCollectionEditor; @InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(Set.class, "players", playerCollectionEditor); } @RequestMapping(method = GET, value = "/{eventId}/participate") public ModelAndView participate(@PathVariable("eventId") Long eventId, HttpServletRequest request) { Player user = sessionUtil.getUser(request); if (user == null) { return getLoginRequiredView(request, msg.get("Participate")); } Event event = eventDAO.findById(eventId); EventBookingRequest eventBookingRequest = new EventBookingRequest(); if (event.getEventType().equals(EventType.CommunityRoundRobin)) { Integer maxNumberOfNewPlayers = Math.max(0, event.getMaxNumberOfParticipants() - event.getParticipants().size()); List<Player> newPlayers = new ArrayList<>(); for (int i = 0; i < maxNumberOfNewPlayers; i++) { newPlayers.add(new Player()); } eventBookingRequest.setNewPlayers(newPlayers); eventBookingRequest.setPlayers(Stream.of(user).collect(Collectors.toSet())); } return participateView(eventId, eventBookingRequest); } @RequestMapping(method = POST, value = "/{eventId}/participate") @Transactional public ModelAndView postParticipate(@PathVariable("eventId") Long eventId, HttpServletRequest request, final @ModelAttribute("EventBookingRequest") EventBookingRequest eventBookingRequest, BindingResult bindingResult) { ModelAndView participateView = participateView(eventId, eventBookingRequest); try { Player user = sessionUtil.getUser(request); if (user == null) { return getLoginRequiredView(request, msg.get("Participate")); } Event event = eventDAO.findByIdFetchWithParticipantsAndCommunities(eventId); Booking booking = new Booking(); booking.setPlayer(user); booking.setBookingDate(event.getStartDate()); booking.setBookingTime(event.getStartTime()); booking.setAmount(event.getPrice()); booking.setCurrency(event.getCurrency()); booking.setPaymentMethod(eventBookingRequest.getPaymentMethod()); booking.setBookingType(BookingType.loggedIn); booking.setEvent(event); switch (event.getEventType()) { case PullRoundRobin: break; case CommunityRoundRobin: // remove players without any information List<Player> newPlayers = StreamSupport .stream(eventBookingRequest.getNewPlayers().spliterator(), false) .filter(player -> !(StringUtils.isEmpty(player.getFirstName()) && StringUtils.isEmpty(player.getLastName()) && StringUtils.isEmpty(player.getEmail()) && StringUtils.isEmpty(player.getPhone()))) .collect(Collectors.toList()); // if at least one field is given, validate all data newPlayers.forEach(player -> validator.validate(player, bindingResult)); if (bindingResult.hasErrors()) { return participateView; } // make sure at least one person participates if (newPlayers.isEmpty() && (eventBookingRequest.getPlayers() == null || eventBookingRequest.getPlayers().isEmpty())) { throw new Exception(msg.get("PleaseAddParticipants")); } // check if email already exists for (Player player : newPlayers) { if (playerDAO.findByEmail(player.getEmail()) != null) { throw new Exception(msg.get("EmailAlreadyRegistered")); } } // make sure community name exists Community community = eventBookingRequest.getCommunity(); if (StringUtils.isEmpty(community.getName())) { throw new Exception(msg.get("PleaseAddCommunityName")); } booking.setCommunity(community); Set<Player> allPlayers = new HashSet<>(eventBookingRequest.getPlayers()); newPlayers.forEach(newPlayer -> allPlayers.add(playerDAO.saveOrUpdate(newPlayer))); //do not add user as this would cause duplicate key (player and players go into the same table), instead use transient boolean value allPlayers.remove(user); booking.setPlayers(allPlayers); booking.setPlayerParticipates(eventBookingRequest.getPlayers() != null && eventBookingRequest.getPlayers().contains(user)); break; default: Player player = eventBookingRequest.getPlayer(); Player partner; if (player.getUUID() == null) { validator.validate(player, bindingResult); if (bindingResult.hasErrors()) { return participateView; } if (playerDAO.findByEmail(player.getEmail()) != null) { throw new Exception(msg.get("EmailAlreadyRegistered")); } partner = playerDAO.saveOrUpdate(player); } else { partner = playerDAO.findByUUID(player.getUUID()); if (partner == null) { throw new Exception(msg.get("ChoosePartner")); } if (partner.equals(user)) { throw new Exception(msg.get("ChooseDifferentPartner")); } } Set<Player> participants = new HashSet<>(); //do not add user as this would cause duplicate key (player and players go into the same table) participants.add(partner); //extra fields booking.setPlayers(participants); } isEventBookingPossible(booking); sessionUtil.setBooking(request, booking); return new ModelAndView("redirect:/events/bookings/" + event.getId() + "/confirm"); } catch (Exception e) { bindingResult.addError(new ObjectError("*", e.getMessage())); return participateView; } } @RequestMapping(value = "{eventId}/confirm") public ModelAndView showConfirmView(HttpServletRequest request) { Booking booking = sessionUtil.getBooking(request); ModelAndView confirmView = getBookingConfirmView(booking); try { if (booking == null || booking.getPlayer() == null) { throw new Exception(msg.get("SessionTimeout")); } isEventBookingPossible(booking); } catch (Exception e) { LOG.warn("Error while processing booking request: " + e.getMessage(), e); confirmView.addObject("error", e.getMessage()); return confirmView; } return confirmView; } @RequestMapping(value = "{eventId}/confirm", method = POST) public ModelAndView confirmBooking(HttpServletRequest request) throws Exception { Booking booking = sessionUtil.getBooking(request); ModelAndView confirmView = getBookingConfirmView(booking); try { if (booking == null) { throw new Exception(msg.get("SessionTimeout")); } String publicBooking = request.getParameter("public-booking"); Boolean isPublicBooking = !StringUtils.isEmpty(publicBooking) && publicBooking.equalsIgnoreCase("on"); booking.setPublicBooking(isPublicBooking); String cancellationPolicyCheckbox = request.getParameter("accept-cancellation-policy"); if (StringUtils.isEmpty(cancellationPolicyCheckbox) || !cancellationPolicyCheckbox.equals("on")) { throw new Exception(msg.get("BookingCancellationPolicyNotAccepted")); } if (booking.getConfirmed()) { throw new Exception(msg.get("BookingAlreadyConfirmed")); } isEventBookingPossible(booking); booking.setBlockingTime(new LocalDateTime()); booking.setUUID(BookingUtil.generateUUID()); if (booking.getCommunity() != null) { SortedSet<Player> communityPlayers = new TreeSet<>(); if (booking.getPlayerParticipates()) { communityPlayers.add(booking.getPlayer()); } communityPlayers.addAll(booking.getPlayers()); booking.getCommunity().setPlayers(communityPlayers); booking.setCommunity(communityDAO.saveOrUpdate(booking.getCommunity())); } bookingDAO.saveOrUpdate(booking); switch (booking.getPaymentMethod()) { case Cash: case ExternalVoucher: if (booking.getConfirmed()) { throw new Exception(msg.get("BookingAlreadyConfirmed")); } return new ModelAndView("redirect:/events/bookings/" + booking.getUUID() + "/success"); case PayPal: return bookingsPayPalController.redirectToPaypal(booking, request); case PayDirekt: return bookingsPayDirektController.redirectToPayDirekt(booking, request); case DirectDebit: return bookingsPayMillController.redirectToDirectDebit(booking); case CreditCard: return bookingsPayMillController.redirectToCreditCard(booking); case Voucher: return bookingsVoucherController.redirectToVoucher(booking); default: confirmView.addObject("error", booking.getPaymentMethod() + " not implemented"); return confirmView; } } catch (Exception e) { LOG.warn("Error while processing booking request: " + e.getMessage(), e); confirmView.addObject("error", e.getMessage()); return confirmView; } } @RequestMapping(value = "/{UUID}/success") public ModelAndView showSuccessView(@PathVariable("UUID") String UUID, HttpServletRequest request) { ModelAndView mav = getBookingSuccessView(); Booking booking = bookingDAO.findByUUIDWithEventAndPlayers(UUID); try { if (!(booking.getPaymentMethod().equals(PaymentMethod.Cash) || booking.getPaymentMethod().equals(PaymentMethod.ExternalVoucher)) && !booking.getPaymentConfirmed()) { throw new Exception(msg.get("PaymentHasNotBeenConfirmed")); } if (booking.getConfirmed()) { throw new Exception(msg.get("BookingAlreadyConfirmed")); } Event event = eventDAO.findByIdFetchWithParticipantsAndGames(booking.getEvent().getId()); switch (event.getEventType()) { case PullRoundRobin: event.getParticipants().add(booking.getPlayer()); eventDAO.saveOrUpdate(event); break; case CommunityRoundRobin: event.getCommunities().add(booking.getCommunity()); eventDAO.saveOrUpdate(event); break; default: Set<Player> players = new HashSet<>(); players.add(booking.getPlayer()); players.addAll(booking.getPlayers()); //figure out if team already exists Team team = teamDAO.findByPlayers(players); //create team if it does not exist if (team == null) { team = new Team(); team.setPlayers(players); team.setName(TeamUtil.getTeamName(team)); team = teamDAO.saveOrUpdate(team); } //add team to participant list event.getParticipants().add(team); event = eventDAO.saveOrUpdate(event); if (event.getEventType().equals(EventType.SingleRoundRobin)) { gameUtil.createMissingGames(event, event.getParticipants()); } } booking.setConfirmed(true); bookingDAO.saveOrUpdate(booking); bookingUtil.sendEventBookingConfirmation(request, booking); booking.setConfirmationMailSent(true); bookingDAO.saveOrUpdate(booking); bookingUtil.sendNewBookingNotification(request, booking); } catch (MailException | IOException ex) { LOG.error("Error while sending booking confirmation email", ex); mav.addObject("error", msg.get("FailedToSendBookingConfirmationEmail", new Object[] { FormatUtils.DATE_MEDIUM.print(booking.getBookingDate()), FormatUtils.TIME_HUMAN_READABLE.print(booking.getBookingTime()) })); } catch (Exception e) { LOG.error(e.getMessage(), e); mav.addObject("error", e.getMessage()); } return mav; } @RequestMapping(value = "/{UUID}/abort") public ModelAndView abortBooking(@PathVariable("UUID") String UUID, HttpServletRequest request) { Booking booking = bookingDAO.findByUUIDWithEvent(UUID); booking.setBlockingTime(null); booking.setCancelled(Boolean.TRUE); booking.setCancelReason("User cancelled during payment process"); bookingDAO.saveOrUpdate(booking); return new ModelAndView("redirect:/events/event/" + booking.getEvent().getId()); } private ModelAndView participateView(Long eventId, EventBookingRequest eventBookingRequest) { Event event = eventDAO.findById(eventId); ModelAndView mav; switch (event.getEventType()) { case PullRoundRobin: mav = new ModelAndView("events/bookings/participate/pull"); break; case CommunityRoundRobin: mav = new ModelAndView("events/bookings/participate/community"); break; default: mav = new ModelAndView("events/bookings/participate/index"); } mav.addObject("Model", event); mav.addObject("EventBookingRequest", eventBookingRequest); return mav; } private ModelAndView getBookingConfirmView(Booking booking) { ModelAndView mav = new ModelAndView("events/bookings/confirm"); mav.addObject("Booking", booking); return mav; } private ModelAndView getBookingSuccessView() { return new ModelAndView("events/bookings/success"); } private void isEventBookingPossible(Booking booking) throws Exception { Event event = booking.getEvent(); Set<Participant> participants = new HashSet<>(); switch (event.getEventType()) { case CommunityRoundRobin: event = eventDAO.findByIdFetchWithParticipantsAndCommunities(event.getId()); for (Community community : event.getCommunities()) { if (community.getPlayers() != null) { participants.addAll(community.getPlayers()); } } if (booking.getPlayerParticipates() != null && booking.getPlayerParticipates()) { checkPlayerNotParticipating(participants, booking.getPlayer()); } break; default: Event eventWithPlayers = eventDAO.findByIdFetchWithParticipantsAndPlayers(event.getId()); participants = eventWithPlayers.getParticipants(); checkPlayerNotParticipating(participants, booking.getPlayer()); } if (booking.getPlayers() != null) { for (Player player : booking.getPlayers()) { checkPlayerNotParticipating(participants, player); } } if (participants.size() >= event.getMaxNumberOfParticipants()) { throw new Exception(msg.get("EventBookedOut")); } } private void checkPlayerNotParticipating(Collection<Participant> participants, Player user) throws Exception { for (Participant p : participants) { if (p instanceof Team) { Team team = (Team) p; if (team.getPlayers().contains(user)) { throw new Exception(msg.get("AlreadyParticipatesInThisEvent", new Object[] { user })); } } else { if (p.equals(user)) { throw new Exception(msg.get("AlreadyParticipatesInThisEvent", new Object[] { user })); } } } } }