diff --git a/pom.xml b/pom.xml index 5b48f90..48eb615 100644 --- a/pom.xml +++ b/pom.xml @@ -73,6 +73,18 @@ io.quarkus quarkus-container-image-docker + + io.quarkus + quarkus-rest-client-jsonb + + + io.quarkus + quarkus-rest-client + + + io.quarkus + quarkus-jsonp + io.quarkus quarkus-junit5 diff --git a/src/main/java/de/mbremer/holiday/HolidayRestClient.java b/src/main/java/de/mbremer/holiday/HolidayRestClient.java new file mode 100644 index 0000000..c97531f --- /dev/null +++ b/src/main/java/de/mbremer/holiday/HolidayRestClient.java @@ -0,0 +1,23 @@ +package de.mbremer.holiday; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +import javax.json.JsonObject; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; + +/** + * curl -H "X-DFA-Token: dfa" -X POST https://deutsche-feiertage-api.de/api/v1/2018-10-03 + */ +@Path("/api/v1") +@RegisterRestClient +public interface HolidayRestClient { + + /** + * @param date yyyy-MM-DD + */ + @POST + @Path("/{date}") + @Produces(MediaType.APPLICATION_JSON) + JsonObject getHoliday(@PathParam("date") String date, @HeaderParam("X-DFA-Token") String token); +} diff --git a/src/main/java/de/mbremer/holiday/HolidayService.java b/src/main/java/de/mbremer/holiday/HolidayService.java new file mode 100644 index 0000000..d36f87c --- /dev/null +++ b/src/main/java/de/mbremer/holiday/HolidayService.java @@ -0,0 +1,32 @@ +package de.mbremer.holiday; + +import org.eclipse.microprofile.rest.client.inject.RestClient; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.json.JsonObject; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +@ApplicationScoped +public class HolidayService { + + private static final String TOKEN = "dfa"; + + @Inject + @RestClient + HolidayRestClient holidayRestClient; + + /** + * @return Holiday name or null if it's not a holiday; + */ + public String getHolidayNiedersachsen(LocalDate date) { + // TODO Token via Filter + // TODO Fehlertolerant + // TODO Caching + // TODO Test via Wiremock + JsonObject holiday = holidayRestClient.getHoliday(date.format(DateTimeFormatter.ISO_DATE), TOKEN); + return holiday.getBoolean("result", false) && holiday.getJsonObject("holiday").getJsonObject("regions").getBoolean("ni", false) ? + holiday.getJsonObject("holiday").getString("name") : null; + } +} diff --git a/src/main/java/de/mbremer/kalender/KalenderResource.java b/src/main/java/de/mbremer/kalender/KalenderResource.java index 055d81c..42d59bf 100644 --- a/src/main/java/de/mbremer/kalender/KalenderResource.java +++ b/src/main/java/de/mbremer/kalender/KalenderResource.java @@ -1,14 +1,15 @@ package de.mbremer.kalender; import de.mbremer.secutity.User; +import de.mbremer.secutity.UserService; import io.quarkus.qute.Location; import io.quarkus.qute.Template; import io.quarkus.qute.TemplateInstance; -import io.quarkus.security.identity.SecurityIdentity; import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.providers.multipart.MultipartForm; import javax.annotation.security.RolesAllowed; +import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.persistence.NoResultException; import javax.transaction.Transactional; @@ -18,16 +19,18 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; -import java.util.stream.Stream; @Path("/kalender") @RolesAllowed({"USER", "ADMIN"}) +@ApplicationScoped public class KalenderResource { @Inject Logger log; @Inject - SecurityIdentity identity; + UserService userService; + @Inject + KalenderService kalenderService; @Inject Template kalenderpage; @Inject @@ -40,7 +43,7 @@ public class KalenderResource { @GET @Produces(MediaType.TEXT_HTML) public TemplateInstance kalender(@QueryParam("offset") @DefaultValue("0") int offsetInWeeks) { - List week = getWeek(offsetInWeeks); + List week = kalenderService.getWeek(offsetInWeeks); return kalenderpage .data("today", LocalDate.now()) @@ -48,24 +51,8 @@ public class KalenderResource { .data("week", week); } - private List 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) - .map(d -> { - LocalDate day = montag.plusDays(d); - KalenderTag tag = (KalenderTag) KalenderTag.find("day", day).singleResultOptional().orElse(new KalenderTag(day)); - tag.setCurrentUserInOffice(currentUser.equals(tag.getInOffice())); - tag.setToday(LocalDate.now().equals(day)); - return tag; - }) - .collect(Collectors.toList()); - } - private List getEvents(int offsetInWeeks) { - List week = getWeek(offsetInWeeks); + List week = kalenderService.getWeek(offsetInWeeks); return week.stream() .filter(d -> d.isCurrentUserInOffice()) .map(d-> new Event(LocalDateTime.now(), d.getDay())) @@ -80,7 +67,7 @@ public class KalenderResource { @QueryParam("offset") int offsetInWeeks, @MultipartForm KalenderTagForm kalenderForm) { LocalDate dayParsed = LocalDate.parse(day); - User currentUser = getCurrentUser(); + User currentUser = userService.getCurrentUser(); try { KalenderTag tag = KalenderTag.find("day", dayParsed).singleResult(); if (kalenderForm.isInOffice() && tag.getInOffice() == null) { @@ -97,15 +84,13 @@ public class KalenderResource { return kalender(offsetInWeeks); } - private User getCurrentUser() { - return User.find("username", identity.getPrincipal().getName()).singleResult(); - } + // Exports @GET @Produces(MediaType.TEXT_PLAIN) @Path("export/txt") public TemplateInstance exportTxt(@QueryParam("offset") int offset) { - return textExport.data("week", getWeek(offset)); + return textExport.data("week", kalenderService.getWeek(offset)); } @GET diff --git a/src/main/java/de/mbremer/kalender/KalenderService.java b/src/main/java/de/mbremer/kalender/KalenderService.java new file mode 100644 index 0000000..7e73b46 --- /dev/null +++ b/src/main/java/de/mbremer/kalender/KalenderService.java @@ -0,0 +1,38 @@ +package de.mbremer.kalender; + +import de.mbremer.holiday.HolidayService; +import de.mbremer.secutity.User; +import de.mbremer.secutity.UserService; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import java.time.LocalDate; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@ApplicationScoped +public class KalenderService { + + @Inject + UserService userService; + @Inject + HolidayService holidayService; + + List getWeek(int offsetInWeeks) { + User currentUser = userService.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) + .map(d -> { + LocalDate day = montag.plusDays(d); + KalenderTag tag = (KalenderTag) KalenderTag.find("day", day).singleResultOptional().orElse(new KalenderTag(day)); + tag.setCurrentUserInOffice(currentUser.equals(tag.getInOffice())); + tag.setToday(LocalDate.now().equals(day)); + tag.setHolidayname(holidayService.getHolidayNiedersachsen(day)); + return tag; + }) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/de/mbremer/kalender/KalenderTag.java b/src/main/java/de/mbremer/kalender/KalenderTag.java index ba9bd2b..4eba25e 100644 --- a/src/main/java/de/mbremer/kalender/KalenderTag.java +++ b/src/main/java/de/mbremer/kalender/KalenderTag.java @@ -24,8 +24,18 @@ public class KalenderTag extends PanacheEntity { private boolean currentUserInOffice; @Transient private boolean today; + @Transient + private String holidayname; public KalenderTag(LocalDate day) { this.day = day; } + + public boolean istHoliday() { + return holidayname != null; + } + + public boolean isPast() { + return day.isBefore(LocalDate.now()); + } } diff --git a/src/main/java/de/mbremer/secutity/UserResource.java b/src/main/java/de/mbremer/secutity/UserResource.java index a01e2a2..06ea71f 100644 --- a/src/main/java/de/mbremer/secutity/UserResource.java +++ b/src/main/java/de/mbremer/secutity/UserResource.java @@ -9,6 +9,7 @@ import org.jboss.resteasy.annotations.providers.multipart.MultipartForm; import javax.annotation.security.PermitAll; import javax.annotation.security.RolesAllowed; +import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.transaction.Transactional; import javax.ws.rs.*; @@ -21,6 +22,7 @@ import static de.mbremer.secutity.Role.ADMIN; @Path("/user") @RolesAllowed("ADMIN") +@ApplicationScoped public class UserResource { @Inject diff --git a/src/main/java/de/mbremer/secutity/UserService.java b/src/main/java/de/mbremer/secutity/UserService.java new file mode 100644 index 0000000..368f67b --- /dev/null +++ b/src/main/java/de/mbremer/secutity/UserService.java @@ -0,0 +1,19 @@ +package de.mbremer.secutity; + +import io.quarkus.security.identity.SecurityIdentity; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; + +@RequestScoped +public class UserService { + @Inject + SecurityIdentity identity; + + /** + * Returns the user currently logged in. + */ + public User getCurrentUser() { + return User.find("username", identity.getPrincipal().getName()).singleResult(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c189b11..47eac6c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,6 +2,7 @@ %prod.quarkus.datasource.jdbc.url = jdbc:postgresql://${POSTGRES_HOST:db}:${POSTGRES_PORT:5432}/buerokalender %prod.quarkus.datasource.username = ${POSTGRES_USER:buerokalender} %prod.quarkus.datasource.password = ${POSTGRES_PASSWORD:buerokalender} +# max JDBC pool size %prod.quarkus.datasource.jdbc.max-size=16 quarkus.datasource.db-kind=postgresql @@ -15,6 +16,10 @@ quarkus.http.auth.form.enabled=true # 24h quarkus.http.auth.form.timeout=86400 +# REST-CLient +de.mbremer.holiday.HolidayRestClient/mp-rest/url=https://deutsche-feiertage-api.de +de.mbremer.holiday.HolidayRestClient/mp-rest/scope=javax.inject.Singleton + # Deployment quarkus.container-image.additional-tags= 1 quarkus.container-image.group = mattbremer diff --git a/src/main/resources/templates/kalenderpage.html b/src/main/resources/templates/kalenderpage.html index 46fb3db..339cd3e 100644 --- a/src/main/resources/templates/kalenderpage.html +++ b/src/main/resources/templates/kalenderpage.html @@ -40,6 +40,7 @@
@@ -48,6 +49,7 @@ {day.day.formatCommon} + {#if day.istHoliday}{day.holidayname}{/if} {#if day.inOffice}{day.inOffice.username}{/if} diff --git a/src/test/java/de/mbremer/kalender/KalenderResourceTest.java b/src/test/java/de/mbremer/kalender/KalenderResourceTest.java index b9c90ae..4327c4e 100644 --- a/src/test/java/de/mbremer/kalender/KalenderResourceTest.java +++ b/src/test/java/de/mbremer/kalender/KalenderResourceTest.java @@ -22,6 +22,8 @@ class KalenderResourceTest { @InjectMock SecurityIdentity identity; + @InjectMock + KalenderService kalenderService; @Test @TestSecurity(authorizationEnabled = false)