This commit is contained in:
		| @@ -0,0 +1,31 @@ | ||||
| package de.jottyfan.camporganizer.module.ical; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
|  | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Controller; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @author jotty | ||||
|  * | ||||
|  */ | ||||
| @Controller | ||||
| public class ICalController { | ||||
|  | ||||
| 	@Autowired | ||||
| 	private IICalService service; | ||||
|  | ||||
| 	/** | ||||
| 	 * generate the ical response stream | ||||
| 	 * | ||||
| 	 * @throws IOException on io errors | ||||
| 	 */ | ||||
| 	@GetMapping("/ical") | ||||
| 	public void generate(HttpServletResponse response) throws IOException { | ||||
| 		service.generate(response); | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,23 @@ | ||||
| package de.jottyfan.camporganizer.module.ical; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @author jotty | ||||
|  * | ||||
|  */ | ||||
| public interface IICalService { | ||||
|  | ||||
| 	/** | ||||
| 	 * generate the ical | ||||
| 	 * | ||||
| 	 * @param response the response for the output stream | ||||
| 	 * | ||||
| 	 * @return true if successful, false otherwise | ||||
| 	 * @throws IOException on io errors | ||||
| 	 */ | ||||
| 	public Boolean generate(HttpServletResponse response) throws IOException; | ||||
| } | ||||
| @@ -0,0 +1,76 @@ | ||||
| package de.jottyfan.camporganizer.module.ical.impl; | ||||
|  | ||||
| import static de.jottyfan.camporganizer.db.jooq.Tables.T_CAMP; | ||||
| import static de.jottyfan.camporganizer.db.jooq.Tables.T_LOCATION; | ||||
|  | ||||
| import java.time.LocalDateTime; | ||||
| import java.time.ZoneId; | ||||
| import java.util.Date; | ||||
| import java.util.TimeZone; | ||||
|  | ||||
| import org.apache.logging.log4j.LogManager; | ||||
| import org.apache.logging.log4j.Logger; | ||||
| import org.jooq.DSLContext; | ||||
| import org.jooq.Record5; | ||||
| import org.jooq.SelectOnConditionStep; | ||||
| import org.jooq.exception.DataAccessException; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Repository; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
|  | ||||
| import biweekly.ICalendar; | ||||
| import biweekly.component.VEvent; | ||||
| import biweekly.io.TimezoneAssignment; | ||||
| import biweekly.property.Summary; | ||||
|  | ||||
| /** | ||||
| * | ||||
| * @author jotty | ||||
| * | ||||
| */ | ||||
| @Repository | ||||
| @Transactional(transactionManager = "transactionManager") | ||||
| public class ICalGateway { | ||||
| 	private static final Logger LOGGER = LogManager.getLogger(ICalGateway.class); | ||||
|  | ||||
| 	@Autowired | ||||
| 	private DSLContext jooq; | ||||
|  | ||||
| 	/** | ||||
| 	 * load all camp dates from db and generate an ical from it | ||||
| 	 * | ||||
| 	 * @return ical containing all (at least none) of the camp dates | ||||
| 	 * @throws DataAccessException | ||||
| 	 */ | ||||
| 	public ICalendar getIcal() throws DataAccessException { | ||||
| 		SelectOnConditionStep<Record5<String, LocalDateTime, LocalDateTime, String, String>> sql = jooq | ||||
| 		// @formatter:off | ||||
| 			.select(T_CAMP.NAME, | ||||
| 					    T_CAMP.ARRIVE, | ||||
| 					    T_CAMP.DEPART, | ||||
| 					    T_LOCATION.NAME, | ||||
| 					    T_LOCATION.URL) | ||||
| 			.from(T_CAMP) | ||||
| 		  .leftJoin(T_LOCATION).on(T_LOCATION.PK.eq(T_CAMP.FK_LOCATION)); | ||||
| 		// @formatter:on | ||||
| 		LOGGER.debug(sql.toString()); | ||||
| 		ICalendar ical = new ICalendar(); | ||||
| 		ical.getTimezoneInfo().setDefaultTimezone(TimezoneAssignment.download(TimeZone.getTimeZone("Europe/Berlin"), false)); | ||||
| 		for (Record5<String, LocalDateTime, LocalDateTime, String, String> r : sql.fetch()) { | ||||
| 			VEvent event = new VEvent(); | ||||
| 			Summary summary = event.setSummary(r.get(T_CAMP.NAME)); | ||||
| 			summary.setLanguage("de"); | ||||
| 			LocalDateTime startDate = r.get(T_CAMP.ARRIVE); | ||||
| 			LocalDateTime endDate = r.get(T_CAMP.DEPART); | ||||
| 			// because of the specification, end dates are exclusive - and without time, the day won't be counted | ||||
| 			endDate = endDate.plusDays(1l); | ||||
| 			event.setLocation(r.get(T_LOCATION.NAME)); | ||||
| 			event.setDateStart(startDate == null ? null : Date.from(startDate.atZone(ZoneId.of("Europe/Berlin")).toInstant()), false); | ||||
| 			event.setDateEnd(endDate == null ? null : Date.from(endDate.atZone(ZoneId.of("Europe/Berlin")).toInstant()), false); | ||||
| 			event.setUrl(r.get(T_LOCATION.URL)); | ||||
| 			event.setDescription("zur Anmeldung: http://anmeldung.onkelwernerfreizeiten.de"); | ||||
| 			ical.addEvent(event); | ||||
| 		} | ||||
| 		return ical; | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,41 @@ | ||||
| package de.jottyfan.camporganizer.module.ical.impl; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
|  | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| import biweekly.Biweekly; | ||||
| import biweekly.ICalendar; | ||||
| import de.jottyfan.camporganizer.module.ical.IICalService; | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @author jotty | ||||
|  * | ||||
|  */ | ||||
| @Service | ||||
| public class ICalService implements IICalService { | ||||
|  | ||||
| 	@Autowired | ||||
| 	private ICalGateway gateway; | ||||
|  | ||||
| 	@Override | ||||
| 	public Boolean generate(HttpServletResponse response) throws IOException { | ||||
| 		ICalendar ical = gateway.getIcal(); | ||||
| 		String content = Biweekly.write(ical).go(); | ||||
|  | ||||
| 		response.setHeader("charset", "UTF-8"); | ||||
| 		response.setHeader("Content-Type", "text/calendar"); | ||||
| 		response.setHeader("Content-Disposition", "attachment; filename=\"onkelwernerfreizeiten.de.ics\""); | ||||
|  | ||||
| 		response.getWriter().write(content); | ||||
| 		response.getWriter().flush(); | ||||
| 		response.flushBuffer(); | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -7,15 +7,15 @@ | ||||
| </head> | ||||
| <body> | ||||
| 	<header> | ||||
| 		<a th:href="@{/}" class="btn btn-secondary btn-icon-silent" title="aktualisieren"><i class="fas fa-sync"></i></a> | ||||
| 		<span>Das Buchungsportal des Onkel Werner Freizeiten e.V.</span> | ||||
| 		<a th:href="@{/ical}" class="btn btn-secondary btn-icon-silent" target="_blank" title="Freizeitdaten als ical herunterladen"><i class="far fa-calendar-alt"></i></a> <a th:href="@{/}" | ||||
| 			class="btn btn-secondary btn-icon-silent" title="aktualisieren"><i class="fas fa-sync"></i></a> | ||||
| 		<a class="btn btn-icon-silent" style="color: black !important; font-size: larger" href="http://anmeldung.onkelwernerfreizeiten.de">Unsere Freizeiten</a> | ||||
| 	</header> | ||||
| 	<content> | ||||
| 	<div class="mainpage"> | ||||
| 		<script type="text/javascript"> | ||||
| 			var mytoggle = new MyToggle(); | ||||
| 		</script> | ||||
| 		<h1>Unsere Freizeiten</h1> | ||||
| 		<div class="card bottomdist16" th:each="c : ${camps}"> | ||||
| 			<div class="card-header mytoggle_btn" th:onclick="mytoggle.toggle('campdiv_[[${c.pk}]]')"> | ||||
| 				<span th:text="${c.name}"></span> <span th:text="${#numbers.formatInteger(c.year, 0)}" th:if="${c.year != null}"></span> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user