This commit is contained in:
parent
2126f4de62
commit
500ec2b9ad
@ -12,6 +12,13 @@
|
|||||||
<attribute name="gradle_used_by_scope" value="main,test"/>
|
<attribute name="gradle_used_by_scope" value="main,test"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
|
<classpathentry kind="src" output="bin/test" path="src/test/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="gradle_scope" value="test"/>
|
||||||
|
<attribute name="gradle_used_by_scope" value="test"/>
|
||||||
|
<attribute name="test" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17/"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17/"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
|
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer">
|
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer">
|
||||||
|
@ -1,13 +1,2 @@
|
|||||||
arguments=
|
|
||||||
auto.sync=false
|
|
||||||
build.scans.enabled=false
|
|
||||||
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
|
|
||||||
connection.project.dir=
|
connection.project.dir=
|
||||||
eclipse.preferences.version=1
|
eclipse.preferences.version=1
|
||||||
gradle.user.home=
|
|
||||||
java.home=
|
|
||||||
jvm.arguments=
|
|
||||||
offline.mode=false
|
|
||||||
override.workspace.settings=false
|
|
||||||
show.console.view=false
|
|
||||||
show.executions.view=false
|
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
|
||||||
<project-modules id="moduleCoreId" project-version="1.5.0">
|
|
||||||
<wb-module deploy-name="camporganizer2">
|
<wb-module deploy-name="CampOrganizer2">
|
||||||
<property name="context-root" value="camporganizer2"/>
|
|
||||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/resources"/>
|
<property name="context-root" value="CampOrganizer2"/>
|
||||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/java"/>
|
|
||||||
</wb-module>
|
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/resources"/>
|
||||||
|
|
||||||
|
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/java"/>
|
||||||
|
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/java"/>
|
||||||
|
|
||||||
|
</wb-module>
|
||||||
|
|
||||||
</project-modules>
|
</project-modules>
|
||||||
|
@ -18,7 +18,7 @@ apply plugin: 'war'
|
|||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
|
|
||||||
group = 'de.jottyfan.camporganizer'
|
group = 'de.jottyfan.camporganizer'
|
||||||
version = '0.0.9'
|
version = '0.1.0'
|
||||||
sourceCompatibility = 17
|
sourceCompatibility = 17
|
||||||
mainClassName = "de.jottyfan.camporganizer.Main"
|
mainClassName = "de.jottyfan.camporganizer.Main"
|
||||||
|
|
||||||
@ -51,6 +51,8 @@ dependencies {
|
|||||||
implementation 'org.webjars:datatables:1.11.4'
|
implementation 'org.webjars:datatables:1.11.4'
|
||||||
implementation 'org.webjars:select2:4.0.13'
|
implementation 'org.webjars:select2:4.0.13'
|
||||||
|
|
||||||
|
implementation 'net.sf.biweekly:biweekly:0.6.6'
|
||||||
|
|
||||||
implementation 'org.keycloak:keycloak-spring-boot-starter'
|
implementation 'org.keycloak:keycloak-spring-boot-starter'
|
||||||
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-jooq'
|
implementation 'org.springframework.boot:spring-boot-starter-jooq'
|
||||||
|
@ -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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<a th:href="@{/}" class="btn btn-secondary btn-icon-silent" title="aktualisieren"><i class="fas fa-sync"></i></a>
|
<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="@{/}"
|
||||||
<span>Das Buchungsportal des Onkel Werner Freizeiten e.V.</span>
|
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>
|
</header>
|
||||||
<content>
|
<content>
|
||||||
<div class="mainpage">
|
<div class="mainpage">
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var mytoggle = new MyToggle();
|
var mytoggle = new MyToggle();
|
||||||
</script>
|
</script>
|
||||||
<h1>Unsere Freizeiten</h1>
|
|
||||||
<div class="card bottomdist16" th:each="c : ${camps}">
|
<div class="card bottomdist16" th:each="c : ${camps}">
|
||||||
<div class="card-header mytoggle_btn" th:onclick="mytoggle.toggle('campdiv_[[${c.pk}]]')">
|
<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>
|
<span th:text="${c.name}"></span> <span th:text="${#numbers.formatInteger(c.year, 0)}" th:if="${c.year != null}"></span>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user