Java tutorial
/** * 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 <http://www.gnu.org/licenses/>. */ package alfio.util; import alfio.controller.decorator.SaleableTicketCategory; import alfio.manager.system.ConfigurationManager; import alfio.model.*; import alfio.model.system.Configuration; import biweekly.ICalVersion; import biweekly.ICalendar; import biweekly.component.VEvent; import biweekly.io.text.ICalWriter; import lombok.experimental.UtilityClass; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.web.util.UriComponentsBuilder; import java.io.IOException; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.util.*; import java.util.function.Predicate; import java.util.stream.Stream; import static alfio.model.system.ConfigurationKeys.*; import static java.time.temporal.ChronoField.*; @UtilityClass @Log4j2 public class EventUtil { private static final DateTimeFormatter JSON_TIME_FORMATTER = new DateTimeFormatterBuilder() .appendValue(HOUR_OF_DAY, 2).appendLiteral(':').appendValue(MINUTE_OF_HOUR, 2).optionalStart() .appendLiteral(':').appendValue(SECOND_OF_MINUTE, 2).toFormatter(Locale.ROOT); public static final DateTimeFormatter JSON_DATETIME_FORMATTER = new DateTimeFormatterBuilder() .parseCaseInsensitive().append(DateTimeFormatter.ISO_LOCAL_DATE).appendLiteral('T') .append(JSON_TIME_FORMATTER).appendLiteral('Z').toFormatter(Locale.ROOT); public static boolean displayWaitingQueueForm(Event event, List<SaleableTicketCategory> categories, ConfigurationManager configurationManager, Predicate<Event> noTicketsAvailable) { return !configurationManager.getBooleanConfigValue( Configuration.from(event.getOrganizationId(), event.getId(), STOP_WAITING_QUEUE_SUBSCRIPTIONS), false) && checkWaitingQueuePreconditions(event, categories, configurationManager, noTicketsAvailable); } public static boolean checkWaitingQueuePreconditions(Event event, List<SaleableTicketCategory> categories, ConfigurationManager configurationManager, Predicate<Event> noTicketsAvailable) { return findLastCategory(categories).map(lastCategory -> { ZonedDateTime now = ZonedDateTime.now(event.getZoneId()); if (isPreSales(event, categories)) { return configurationManager.getBooleanConfigValue( Configuration.from(event.getOrganizationId(), event.getId(), ENABLE_PRE_REGISTRATION), false); } else if (configurationManager.getBooleanConfigValue( Configuration.from(event.getOrganizationId(), event.getId(), ENABLE_WAITING_QUEUE), false)) { return now.isBefore(lastCategory.getZonedExpiration()) && noTicketsAvailable.test(event); } return false; }).orElse(false); } private static Optional<SaleableTicketCategory> findLastCategory(List<SaleableTicketCategory> categories) { return sortCategories(categories, (c1, c2) -> c2.getUtcExpiration().compareTo(c1.getUtcExpiration())) .findFirst(); } private static Optional<SaleableTicketCategory> findFirstCategory(List<SaleableTicketCategory> categories) { return sortCategories(categories, Comparator.comparing(SaleableTicketCategory::getUtcExpiration)) .findFirst(); } private static Stream<SaleableTicketCategory> sortCategories(List<SaleableTicketCategory> categories, Comparator<SaleableTicketCategory> comparator) { return Optional.ofNullable(categories).orElse(Collections.emptyList()).stream().sorted(comparator); } public static boolean isPreSales(Event event, List<SaleableTicketCategory> categories) { ZonedDateTime now = ZonedDateTime.now(event.getZoneId()); return findFirstCategory(categories).map(c -> now.isBefore(c.getZonedInception())).orElse(false); } public static Stream<MapSqlParameterSource> generateEmptyTickets(Event event, Date creationDate, int limit, Ticket.TicketStatus ticketStatus) { return generateStreamForTicketCreation(limit) .map(ps -> buildTicketParams(event.getId(), creationDate, Optional.empty(), 0, ps, ticketStatus)); } public static Stream<MapSqlParameterSource> generateStreamForTicketCreation(int limit) { return Stream.generate(MapSqlParameterSource::new).limit(limit); } public static MapSqlParameterSource buildTicketParams(int eventId, Date creation, Optional<TicketCategory> tc, int srcPriceCts, MapSqlParameterSource ps) { return buildTicketParams(eventId, creation, tc, srcPriceCts, ps, Ticket.TicketStatus.FREE); } private static MapSqlParameterSource buildTicketParams(int eventId, Date creation, Optional<TicketCategory> tc, int srcPriceCts, MapSqlParameterSource ps, Ticket.TicketStatus ticketStatus) { return ps.addValue("uuid", UUID.randomUUID().toString()).addValue("creation", creation) .addValue("categoryId", tc.map(TicketCategory::getId).orElse(null)).addValue("eventId", eventId) .addValue("status", ticketStatus.name()).addValue("srcPriceCts", srcPriceCts); } public static int evaluatePrice(int price, boolean freeOfCharge) { return freeOfCharge ? 0 : price; } public static int determineAvailableSeats(TicketCategoryStatisticView tc, EventStatisticView e) { return tc.isBounded() ? tc.getNotSoldTicketsCount() : e.getDynamicAllocation(); } public static Optional<byte[]> getIcalForEvent(Event event, TicketCategory ticketCategory, String description) { ICalendar ical = new ICalendar(); VEvent vEvent = new VEvent(); vEvent.setSummary(event.getDisplayName()); vEvent.setDescription(description); vEvent.setLocation(StringUtils.replacePattern(event.getLocation(), "[\n\r\t]+", " ")); ZonedDateTime begin = Optional.ofNullable(ticketCategory) .map(tc -> tc.getTicketValidityStart(event.getZoneId())).orElse(event.getBegin()); ZonedDateTime end = Optional.ofNullable(ticketCategory) .map(tc -> tc.getTicketValidityEnd(event.getZoneId())).orElse(event.getEnd()); vEvent.setDateStart(Date.from(begin.toInstant())); vEvent.setDateEnd(Date.from(end.toInstant())); vEvent.setUrl(event.getWebsiteUrl()); ical.addEvent(vEvent); StringWriter strWriter = new StringWriter(); try (ICalWriter writer = new ICalWriter(strWriter, ICalVersion.V2_0)) { writer.write(ical); return Optional.of(strWriter.toString().getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { log.warn("was not able to generate iCal for event " + event.getShortName(), e); return Optional.empty(); } } public static String getGoogleCalendarURL(Event event, TicketCategory category, String description) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyMMdd'T'HHmmss"); ZonedDateTime validityStart = Optional.ofNullable(category).map(TicketCategory::getTicketValidityStart) .map(d -> d.withZoneSameInstant(event.getZoneId())).orElse(event.getBegin()); ZonedDateTime validityEnd = Optional.ofNullable(category).map(TicketCategory::getTicketValidityEnd) .map(d -> d.withZoneSameInstant(event.getZoneId())).orElse(event.getEnd()); return UriComponentsBuilder.fromUriString("https://www.google.com/calendar/event") .queryParam("action", "TEMPLATE") .queryParam("dates", validityStart.format(formatter) + "/" + validityEnd.format(formatter)) .queryParam("ctz", event.getTimeZone()).queryParam("text", event.getDisplayName()) .queryParam("location", event.getLocation()).queryParam("detail", description).toUriString(); } }