export txt, ics
This commit is contained in:
7
pom.xml
7
pom.xml
@@ -4,7 +4,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>de.mbremer</groupId>
|
<groupId>de.mbremer</groupId>
|
||||||
<artifactId>buerokalender</artifactId>
|
<artifactId>buerokalender</artifactId>
|
||||||
<version>1.0.1</version>
|
<version>1.1.0</version>
|
||||||
<properties>
|
<properties>
|
||||||
<compiler-plugin.version>3.8.1</compiler-plugin.version>
|
<compiler-plugin.version>3.8.1</compiler-plugin.version>
|
||||||
<maven.compiler.parameters>true</maven.compiler.parameters>
|
<maven.compiler.parameters>true</maven.compiler.parameters>
|
||||||
@@ -103,6 +103,11 @@
|
|||||||
<artifactId>bootstrap-icons</artifactId>
|
<artifactId>bootstrap-icons</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.webjars</groupId>
|
||||||
|
<artifactId>popper.js</artifactId>
|
||||||
|
<version>2.9.2</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
|
|||||||
@@ -20,4 +20,8 @@ public class CommonExtensions {
|
|||||||
public static int plus(int a, int b) {
|
public static int plus(int a, int b) {
|
||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String rightPad(String str, int length) {
|
||||||
|
return String.format("%1$-" + length + "s", str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
35
src/main/java/de/mbremer/kalender/Event.java
Normal file
35
src/main/java/de/mbremer/kalender/Event.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package de.mbremer.kalender;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class Event {
|
||||||
|
private final String created;
|
||||||
|
private final String dtStart;
|
||||||
|
private final String dtEnd;
|
||||||
|
private final String uid;
|
||||||
|
|
||||||
|
public Event(@NotNull LocalDateTime created, LocalDate date) {
|
||||||
|
this.created = created.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
|
||||||
|
.replaceAll("[-:]", "") + "Z";
|
||||||
|
this.dtStart = date.format(DateTimeFormatter.ISO_LOCAL_DATE)
|
||||||
|
.replace("-", "");
|
||||||
|
this.dtEnd = date.plusDays(1).format(DateTimeFormatter.ISO_LOCAL_DATE)
|
||||||
|
.replace("-", "");
|
||||||
|
this.uid = UUID.randomUUID().toString() + "@buerokalender";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastModified() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDtStamp() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.mbremer.kalender;
|
package de.mbremer.kalender;
|
||||||
|
|
||||||
import de.mbremer.secutity.User;
|
import de.mbremer.secutity.User;
|
||||||
|
import io.quarkus.qute.Location;
|
||||||
import io.quarkus.qute.Template;
|
import io.quarkus.qute.Template;
|
||||||
import io.quarkus.qute.TemplateInstance;
|
import io.quarkus.qute.TemplateInstance;
|
||||||
import io.quarkus.security.identity.SecurityIdentity;
|
import io.quarkus.security.identity.SecurityIdentity;
|
||||||
@@ -14,6 +15,7 @@ import javax.transaction.Transactional;
|
|||||||
import javax.ws.rs.*;
|
import javax.ws.rs.*;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@@ -28,35 +30,32 @@ public class KalenderResource {
|
|||||||
SecurityIdentity identity;
|
SecurityIdentity identity;
|
||||||
@Inject
|
@Inject
|
||||||
Template kalenderpage;
|
Template kalenderpage;
|
||||||
|
@Inject
|
||||||
|
@Location("export/textExport.txt")
|
||||||
|
Template textExport;
|
||||||
|
@Location("export/icsExport.ics")
|
||||||
|
Template icsExport;
|
||||||
|
|
||||||
@Path("")
|
@Path("")
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.TEXT_HTML)
|
@Produces(MediaType.TEXT_HTML)
|
||||||
public TemplateInstance kalender() {
|
public TemplateInstance kalender(@QueryParam("offset") @DefaultValue("0") int offsetInWeeks) {
|
||||||
return kalenderWithOffset(0);
|
List<KalenderTag> week = getWeek(offsetInWeeks);
|
||||||
}
|
|
||||||
|
|
||||||
@Path("offset/{weeks}")
|
|
||||||
@GET
|
|
||||||
@Produces(MediaType.TEXT_HTML)
|
|
||||||
public TemplateInstance kalenderWithOffset(@PathParam("weeks") int offsetInWeeks) {
|
|
||||||
User currentUser = User.find("username", identity.getPrincipal().getName()).singleResult();
|
|
||||||
LocalDate today = LocalDate.now();
|
|
||||||
|
|
||||||
LocalDate montag = today.minusDays(today.getDayOfWeek().getValue() - 1).plusDays(7 * offsetInWeeks);
|
|
||||||
|
|
||||||
List<KalenderTag> week = getWeek(currentUser, montag);
|
|
||||||
|
|
||||||
return kalenderpage
|
return kalenderpage
|
||||||
.data("today", today)
|
.data("today", LocalDate.now())
|
||||||
.data("offset", offsetInWeeks)
|
.data("offset", offsetInWeeks)
|
||||||
.data("week", week);
|
.data("week", week);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<KalenderTag> getWeek(User currentUser, LocalDate start) {
|
private List<KalenderTag> getWeek(int offsetInWeeks) {
|
||||||
|
User currentUser = getCurrentUser();
|
||||||
|
LocalDate today = LocalDate.now();
|
||||||
|
LocalDate montag = today.minusDays(today.getDayOfWeek().getValue() - 1).plusDays(7 * offsetInWeeks);
|
||||||
|
|
||||||
return Stream.iterate(0, i -> i < 5, i -> ++i)
|
return Stream.iterate(0, i -> i < 5, i -> ++i)
|
||||||
.map(d -> {
|
.map(d -> {
|
||||||
LocalDate day = start.plusDays(d);
|
LocalDate day = montag.plusDays(d);
|
||||||
KalenderTag tag = (KalenderTag) KalenderTag.find("day", day).singleResultOptional().orElse(new KalenderTag(day));
|
KalenderTag tag = (KalenderTag) KalenderTag.find("day", day).singleResultOptional().orElse(new KalenderTag(day));
|
||||||
tag.setCurrentUserInOffice(currentUser.equals(tag.getInOffice()));
|
tag.setCurrentUserInOffice(currentUser.equals(tag.getInOffice()));
|
||||||
tag.setToday(LocalDate.now().equals(day));
|
tag.setToday(LocalDate.now().equals(day));
|
||||||
@@ -65,6 +64,14 @@ public class KalenderResource {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Event> getEvents(int offsetInWeeks) {
|
||||||
|
List<KalenderTag> week = getWeek(offsetInWeeks);
|
||||||
|
return week.stream()
|
||||||
|
.filter(d -> d.isCurrentUserInOffice())
|
||||||
|
.map(d-> new Event(LocalDateTime.now(), d.getDay()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Transactional
|
@Transactional
|
||||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||||
@@ -73,7 +80,7 @@ public class KalenderResource {
|
|||||||
@QueryParam("offset") int offsetInWeeks, @MultipartForm KalenderTagForm kalenderForm) {
|
@QueryParam("offset") int offsetInWeeks, @MultipartForm KalenderTagForm kalenderForm) {
|
||||||
LocalDate dayParsed = LocalDate.parse(day);
|
LocalDate dayParsed = LocalDate.parse(day);
|
||||||
|
|
||||||
User currentUser = User.find("username", identity.getPrincipal().getName()).singleResult();
|
User currentUser = getCurrentUser();
|
||||||
try {
|
try {
|
||||||
KalenderTag tag = KalenderTag.find("day", dayParsed).singleResult();
|
KalenderTag tag = KalenderTag.find("day", dayParsed).singleResult();
|
||||||
if (kalenderForm.isInOffice() && tag.getInOffice() == null) {
|
if (kalenderForm.isInOffice() && tag.getInOffice() == null) {
|
||||||
@@ -87,6 +94,24 @@ public class KalenderResource {
|
|||||||
tag.persist();
|
tag.persist();
|
||||||
}
|
}
|
||||||
|
|
||||||
return kalenderWithOffset(offsetInWeeks);
|
return kalender(offsetInWeeks);
|
||||||
|
}
|
||||||
|
|
||||||
|
private User getCurrentUser() {
|
||||||
|
return User.find("username", identity.getPrincipal().getName()).singleResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.TEXT_PLAIN)
|
||||||
|
@Path("export/txt")
|
||||||
|
public TemplateInstance exportTxt(@QueryParam("offset") int offset) {
|
||||||
|
return textExport.data("week", getWeek(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Produces("text/calendar")
|
||||||
|
@Path("export/ics")
|
||||||
|
public TemplateInstance exportIcs(@QueryParam("offset") int offset) {
|
||||||
|
return icsExport.data("events", getEvents(offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
{#if info}<div class="alert alert-primary" role="alert">{info}</div>{/if}
|
{#if info}<div class="alert alert-primary" role="alert">{info}</div>{/if}
|
||||||
{#insert contents}No contents!{/}
|
{#insert contents}No contents!{/}
|
||||||
</div>
|
</div>
|
||||||
|
<script src="/webjars/popper.js/2.9.2/umd/popper.min.js"></script>
|
||||||
<script src="/webjars/bootstrap/5.0.0/js/bootstrap.min.js"></script>
|
<script src="/webjars/bootstrap/5.0.0/js/bootstrap.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
19
src/main/resources/templates/export/icsExport.ics
Normal file
19
src/main/resources/templates/export/icsExport.ics
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
BEGIN:VCALENDAR
|
||||||
|
VERSION:2.0
|
||||||
|
METHOD:PUBLISH
|
||||||
|
PRODID:-//kalender.bremer.rocks//iCal Generator//DE
|
||||||
|
{#for event in events}
|
||||||
|
BEGIN:VEVENT
|
||||||
|
CREATED:{event.created}
|
||||||
|
LAST-MODIFIED:{event.lastModified}
|
||||||
|
DTSTAMP:{event.dtStamp}
|
||||||
|
SUMMARY:VIT
|
||||||
|
DTSTART;VALUE=DATE:{event.dtStart}
|
||||||
|
DTEND;VALUE=DATE:{event.dtEnd}
|
||||||
|
URL:https://kalender.bremer.rocks
|
||||||
|
DESCRIPTION:Arbeit im VIT-Buero
|
||||||
|
TRANSP:TRANSPARENT
|
||||||
|
UID:{event.uid}
|
||||||
|
END:VEVENT
|
||||||
|
{/for}
|
||||||
|
END:VCALENDAR
|
||||||
3
src/main/resources/templates/export/textExport.txt
Normal file
3
src/main/resources/templates/export/textExport.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{#for day in week}
|
||||||
|
{day.day.formatCommon.rightPad(30)} {#if day.inOffice}{day.inOffice.username}{/if}
|
||||||
|
{/for}
|
||||||
@@ -6,17 +6,17 @@
|
|||||||
Heute ist {today.formatCommon}
|
Heute ist {today.formatCommon}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-2">
|
<div class="mt-3">
|
||||||
<nav aria-label="Page navigation example">
|
<nav aria-label="Page navigation example">
|
||||||
<ul class="pagination">
|
<ul class="pagination">
|
||||||
<li class="page-item"><a class="page-link" href="/kalender">aktuelle Woche</a></li>
|
<li class="page-item"><a class="page-link" href="/kalender">aktuelle Woche</a></li>
|
||||||
<li class="page-item">
|
<li class="page-item">
|
||||||
<a class="page-link" href="/kalender/offset/{offset.minus(1)}" aria-label="Previous">
|
<a class="page-link" href="/kalender?offset={offset.minus(1)}" aria-label="Previous">
|
||||||
<span aria-hidden="true">«</span>
|
<span aria-hidden="true">«</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item">
|
<li class="page-item">
|
||||||
<a class="page-link" href="/kalender/offset/{offset.plus(1)}" aria-label="Next">
|
<a class="page-link" href="/kalender?offset={offset.plus(1)}" aria-label="Next">
|
||||||
<span aria-hidden="true">»</span>
|
<span aria-hidden="true">»</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-2">
|
<div>
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-striped table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -57,5 +57,17 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-2">
|
||||||
|
<div class="btn-group">
|
||||||
|
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
Export
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a class="dropdown-item" href="/kalender/export/txt?offset={offset}" target="_blank">txt für alle</a></li>
|
||||||
|
<li><a class="dropdown-item" href="/kalender/export/ics?offset={offset}">ics für mich</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/contents}
|
{/contents}
|
||||||
{/include}
|
{/include}
|
||||||
@@ -12,4 +12,9 @@ class CommonExtensionsTest {
|
|||||||
void testFormatCommon() {
|
void testFormatCommon() {
|
||||||
assertEquals("Sonntag, 4.7.2021", CommonExtensions.formatCommon(LocalDate.of(2021, 7, 4)));
|
assertEquals("Sonntag, 4.7.2021", CommonExtensions.formatCommon(LocalDate.of(2021, 7, 4)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRightPad() {
|
||||||
|
assertEquals("foo ", CommonExtensions.rightPad("foo", 5));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
34
src/test/java/de/mbremer/kalender/EventTest.java
Normal file
34
src/test/java/de/mbremer/kalender/EventTest.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package de.mbremer.kalender;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class EventTest {
|
||||||
|
@Test
|
||||||
|
void getCreated() {
|
||||||
|
Event event = new Event(LocalDateTime.of(2021, 7, 18, 14, 25, 45), LocalDate.of(2022, 1, 2));
|
||||||
|
|
||||||
|
assertEquals("20210718T142545Z", event.getCreated());
|
||||||
|
assertEquals("20210718T142545Z", event.getLastModified());
|
||||||
|
assertEquals("20210718T142545Z", event.getDtStamp());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getDtstartEnd() {
|
||||||
|
Event event = new Event(LocalDateTime.of(2021, 7, 18, 14, 25, 45), LocalDate.of(2022, 1, 2));
|
||||||
|
|
||||||
|
assertEquals("20220102", event.getDtStart());
|
||||||
|
assertEquals("20220103", event.getDtEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getUid() {
|
||||||
|
Event event = new Event(LocalDateTime.of(2021, 7, 18, 14, 25, 45), LocalDate.of(2022, 1, 2));
|
||||||
|
|
||||||
|
assertTrue(event.getUid().matches("([a-f0-9]{8}(-[a-f0-9]{4}){4}[a-f0-9]{8})@buerokalender"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user