Repository: urlaubsverwaltung/urlaubsverwaltung
Pull request #4734 (2024-06-20 10:56:50)

Bump org.mnode.ical4j:ical4j from 3.2.18 to 4.0.0
Bumps [org.mnode.ical4j:ical4j](https://github.com/ical4j/ical4j) from 3.2.18 to 4.0.0.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/ical4j/ical4j/commit/f4cec5ed560bd5dfcdd6c68993c4246355084583"><code>f4cec5e</code></a> Merge pull request <a href="https://redirect.github.com/ical4j/ical4j/issues/699">#699</a> from ical4j/develop</li>
<li><a href="https://github.com/ical4j/ical4j/commit/f1a99402699d3d8692ece4eefe0a17ffa586e5b9"><code>f1a9940</code></a> Added 3.x maintenance branch</li>
<li><a href="https://github.com/ical4j/ical4j/commit/79a07b2427a3b3465367c2ed4d6be134edcbea30"><code>79a07b2</code></a> Merge pull request <a href="https://redirect.github.com/ical4j/ical4j/issues/698">#698</a> from ical4j/feature/jsr-310-localdate</li>
<li><a href="https://github.com/ical4j/ical4j/commit/001241ac1204875208d770a0b41b25545c0c7b27"><code>001241a</code></a> Merge branch 'refs/heads/master' into feature/jsr-310-localdate</li>
<li><a href="https://github.com/ical4j/ical4j/commit/382017ceb1816c7fd987cf2f863e70ca23cc3e64"><code>382017c</code></a> Merge pull request <a href="https://redirect.github.com/ical4j/ical4j/issues/697">#697</a> from ical4j/develop</li>
<li><a href="https://github.com/ical4j/ical4j/commit/e8f66fac819105b377e82bb136230e21372e25ec"><code>e8f66fa</code></a> Merge branch 'master' into develop</li>
<li><a href="https://github.com/ical4j/ical4j/commit/db184d10caa654907e81ac267d2a47b599699ea1"><code>db184d1</code></a> updated timezone definitions (tzdata 2024a)</li>
<li><a href="https://github.com/ical4j/ical4j/commit/81e5189eef6fe5f6fb11afaf75e95b88b4dd50f8"><code>81e5189</code></a> Merge branch 'refs/heads/develop' into feature/jsr-310-localdate</li>
<li><a href="https://github.com/ical4j/ical4j/commit/c8f114e890ca3597c17046b5165ea10b2920b42f"><code>c8f114e</code></a> Reduce log severity for optional tz aliases</li>
<li><a href="https://github.com/ical4j/ical4j/commit/891c54f3672fd068072ad0b43e9315eae33aee5e"><code>891c54f</code></a> Merge branch 'refs/heads/develop' into feature/jsr-310-localdate</li>
<li>Additional commits viewable in <a href="https://github.com/ical4j/ical4j/compare/ical4j-3.2.18...ical4j-4.0.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.mnode.ical4j:ical4j&package-manager=maven&previous-version=3.2.18&new-version=4.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/pom.xml b/pom.xml
index 8c59df609..875ac4900 100644
--- a/pom.xml
+++ b/pom.xml
@@ -179,7 +179,7 @@
     <dependency>
       <groupId>org.mnode.ical4j</groupId>
       <artifactId>ical4j</artifactId>
-      <version>3.2.18</version>
+      <version>4.0.0</version>
     </dependency>
 
     <!-- GOOGLE CALENDAR SYNC -->
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/calendar/ICalService.java b/src/main/java/org/synyx/urlaubsverwaltung/calendar/ICalService.java
index cef396e8c..0ff3122cb 100644
--- a/src/main/java/org/synyx/urlaubsverwaltung/calendar/ICalService.java
+++ b/src/main/java/org/synyx/urlaubsverwaltung/calendar/ICalService.java
@@ -2,8 +2,6 @@ package org.synyx.urlaubsverwaltung.calendar;
 
 import net.fortuna.ical4j.data.CalendarOutputter;
 import net.fortuna.ical4j.model.Calendar;
-import net.fortuna.ical4j.model.Date;
-import net.fortuna.ical4j.model.DateTime;
 import net.fortuna.ical4j.model.ParameterList;
 import net.fortuna.ical4j.model.component.VEvent;
 import net.fortuna.ical4j.model.parameter.Cn;
@@ -17,7 +15,6 @@ import net.fortuna.ical4j.model.property.Uid;
 import net.fortuna.ical4j.model.property.XProperty;
 import net.fortuna.ical4j.validate.ValidationException;
 import org.apache.commons.codec.digest.DigestUtils;
-import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.io.ByteArrayResource;
 import org.springframework.stereotype.Service;
@@ -27,20 +24,15 @@ import org.synyx.urlaubsverwaltung.person.Person;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.net.URI;
-import java.text.ParseException;
 import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
 import java.util.List;
 import java.util.Optional;
 
-import static java.lang.invoke.MethodHandles.lookup;
-import static java.util.Date.from;
 import static net.fortuna.ical4j.model.parameter.Role.REQ_PARTICIPANT;
-import static net.fortuna.ical4j.model.property.CalScale.GREGORIAN;
-import static net.fortuna.ical4j.model.property.Method.CANCEL;
 import static net.fortuna.ical4j.model.property.Transp.VALUE_TRANSPARENT;
-import static net.fortuna.ical4j.model.property.Version.VERSION_2_0;
-import static org.slf4j.LoggerFactory.getLogger;
+import static net.fortuna.ical4j.model.property.immutable.ImmutableCalScale.GREGORIAN;
+import static net.fortuna.ical4j.model.property.immutable.ImmutableMethod.CANCEL;
+import static net.fortuna.ical4j.model.property.immutable.ImmutableVersion.VERSION_2_0;
 import static org.synyx.urlaubsverwaltung.calendar.ICalType.CANCELLED;
 import static org.synyx.urlaubsverwaltung.calendar.ICalType.PUBLISHED;
 
@@ -48,12 +40,8 @@ import static org.synyx.urlaubsverwaltung.calendar.ICalType.PUBLISHED;
 @Service
 public class ICalService {
 
-    private static final Logger LOG = getLogger(lookup().lookupClass());
-
     private final CalendarProperties calendarProperties;
 
-    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
-
     @Autowired
     ICalService(CalendarProperties calendarProperties) {
         this.calendarProperties = calendarProperties;
@@ -71,8 +59,8 @@ public class ICalService {
 
     private Calendar generateCalendar(String title, List<Absence> absences, Person recipient) {
         final Calendar calendar = prepareCalendar(absences, PUBLISHED, recipient);
-        calendar.getProperties().add(new XProperty("X-WR-CALNAME", title));
-        calendar.getProperties().add(new RefreshInterval(new ParameterList(), calendarProperties.getRefreshInterval()));
+        calendar.add(new XProperty("X-WR-CALNAME", title));
+        calendar.add(new RefreshInterval(new ParameterList(), calendarProperties.getRefreshInterval()));
         return calendar;
     }
 
@@ -82,20 +70,20 @@ public class ICalService {
 
     private Calendar prepareCalendar(List<Absence> absences, ICalType method, Person recipient) {
         final Calendar calendar = new Calendar();
-        calendar.getProperties().add(VERSION_2_0);
-        calendar.getProperties().add(new ProdId("-//Urlaubsverwaltung//iCal4j 1.0//DE"));
-        calendar.getProperties().add(GREGORIAN);
-        calendar.getProperties().add(new XProperty("X-MICROSOFT-CALSCALE", GREGORIAN.getValue()));
+        calendar.add(VERSION_2_0);
+        calendar.add(new ProdId("-//Urlaubsverwaltung//iCal4j 1.0//DE"));
+        calendar.add(GREGORIAN);
+        calendar.add(new XProperty("X-MICROSOFT-CALSCALE", GREGORIAN.getValue()));
 
         if (method == CANCELLED) {
-            calendar.getProperties().add(CANCEL);
+            calendar.add(CANCEL);
         }
 
         absences.stream()
             .map(absence -> this.toVEvent(absence, method, absence.getPerson().equals(recipient)))
             .filter(Optional::isPresent)
             .map(Optional::get)
-            .forEach(event -> calendar.getComponents().add(event));
+            .forEach(calendar::add);
 
         return calendar;
     }
@@ -107,51 +95,38 @@ public class ICalService {
 
         final VEvent event;
         if (absence.isAllDay()) {
-            try {
-                final Date startDate = new Date(startDateTime.format(formatter));
-                if (isSameDay(startDateTime, endDateTime)) {
-                    event = new VEvent(startDate, absence.getEventSubject());
-                } else {
-                    final Date endDate = new Date(endDateTime.format(formatter));
-                    event = new VEvent(new Date(startDate), new Date(endDate), absence.getEventSubject());
-                }
-            } catch (ParseException e) {
-                LOG.warn("Could not generate all day ical event for absence {}", absence, e);
-                return Optional.empty();
+            if (isSameDay(startDateTime, endDateTime)) {
+                event = new VEvent(startDateTime, absence.getEventSubject());
+            } else {
+                event = new VEvent(startDateTime, endDateTime, absence.getEventSubject());
             }
-
-            event.getProperties().add(new XProperty("X-MICROSOFT-CDO-ALLDAYEVENT", "TRUE"));
+            event.add(new XProperty("X-MICROSOFT-CDO-ALLDAYEVENT", "TRUE"));
         } else {
-            final DateTime start = new DateTime(from(startDateTime.toInstant()));
-            start.setUtc(true);
-            final DateTime end = new DateTime(from(endDateTime.toInstant()));
-            end.setUtc(true);
-
-            event = new VEvent(start, end, absence.getEventSubject());
+            event = new VEvent(startDateTime, endDateTime, absence.getEventSubject());
         }
 
-        event.getProperties().add(new Uid(generateUid(absence)));
+        event.add(new Uid(generateUid(absence)));
         if (absence.getPerson().getEmail() != null) {
-            event.getProperties().add(generateAttendee(absence));
+            event.add(generateAttendee(absence));
         }
 
         if (absence.isHolidayReplacement() || !isOwn) {
-            event.getProperties().add(new Transp(VALUE_TRANSPARENT));
+            event.add(new Transp(VALUE_TRANSPARENT));
         }
 
         if (method == CANCELLED) {
-            event.getProperties().add(new Sequence(1));
+            event.add(new Sequence(1));
         }
 
-        event.getProperties().add(new Organizer(URI.create("mailto:" + calendarProperties.getOrganizer())));
+        event.add(new Organizer(URI.create("mailto:" + calendarProperties.getOrganizer())));
 
         return Optional.of(event);
     }
 
     private Attendee generateAttendee(Absence absence) {
         final Attendee attendee = new Attendee(URI.create("mailto:" + absence.getPerson().getEmail()));
-        attendee.getParameters().add(REQ_PARTICIPANT);
-        attendee.getParameters().add(new Cn(absence.getPerson().getNiceName()));
+        attendee.add(REQ_PARTICIPANT);
+        attendee.add(new Cn(absence.getPerson().getNiceName()));
 
         return attendee;
     }


Test patch:
diff --git a/src/test/java/org/synyx/urlaubsverwaltung/calendar/ICalServiceTest.java b/src/test/java/org/synyx/urlaubsverwaltung/calendar/ICalServiceTest.java
index f17463f75..053995688 100644
--- a/src/test/java/org/synyx/urlaubsverwaltung/calendar/ICalServiceTest.java
+++ b/src/test/java/org/synyx/urlaubsverwaltung/calendar/ICalServiceTest.java
@@ -72,7 +72,7 @@ class ICalServiceTest {
 
             .contains("SUMMARY:Marlene Muster abwesend")
             .contains("X-MICROSOFT-CDO-ALLDAYEVENT:TRUE")
-            .contains("DTSTART;VALUE=DATE:20190326")
+            .contains("DTSTART;TZID=Etc/UTC:20190326T000000")
 
             .contains("ORGANIZER:mailto:no-reply@example.org")
 
@@ -97,8 +97,8 @@ class ICalServiceTest {
             .contains("REFRESH-INTERVAL:P1D")
 
             .contains("SUMMARY:Marlene Muster abwesend")
-            .contains("DTSTART:20190426T080000Z")
-            .contains("DTEND:20190426T120000Z")
+            .contains("DTSTART;TZID=Etc/UTC:20190426T080000")
+            .contains("DTEND;TZID=Etc/UTC:20190426T120000")
 
             .contains("ORGANIZER:mailto:no-reply@example.org")
 
@@ -125,8 +125,8 @@ class ICalServiceTest {
 
             .contains("SUMMARY:Marlene Muster abwesend")
             .contains("X-MICROSOFT-CDO-ALLDAYEVENT:TRUE")
-            .contains("DTSTART;VALUE=DATE:20190326")
-            .contains("DTEND;VALUE=DATE:20190402")
+            .contains("DTSTART;TZID=Etc/UTC:20190326T000000")
+            .contains("DTEND;TZID=Etc/UTC:20190402T000000")
 
             .contains("ORGANIZER:mailto:no-reply@example.org")
 
@@ -151,8 +151,8 @@ class ICalServiceTest {
             .contains("REFRESH-INTERVAL:P1D")
 
             .contains("SUMMARY:Marlene Muster abwesend")
-            .contains("DTSTART:20190526T120000Z")
-            .contains("DTEND:20190526T160000Z")
+            .contains("DTSTART;TZID=Etc/UTC:20190526T120000")
+            .contains("DTEND;TZID=Etc/UTC:20190526T160000")
 
             .contains("ORGANIZER:mailto:no-reply@example.org")
 
@@ -181,8 +181,8 @@ class ICalServiceTest {
 
             .contains("UID:BB2267885BD8DF263E88D3062853E8A7")
             .contains("SUMMARY:Marlene Muster abwesend")
-            .contains("DTSTART:20190526T120000Z")
-            .contains("DTEND:20190526T160000Z")
+            .contains("DTSTART;TZID=Etc/UTC:20190526T120000")
+            .contains("DTEND;TZID=Etc/UTC:20190526T160000")
             .contains("ORGANIZER:mailto:no-reply@example.org")
             .contains("ATTENDEE;ROLE=REQ-PARTICIPANT;CN=Marlene Muster:mailto:muster@example.org")
 
@@ -210,8 +210,8 @@ class ICalServiceTest {
             .contains("METHOD:CANCEL")
 
             .contains("SUMMARY:Marlene Muster abwesend")
-            .contains("DTSTART:20190526T120000Z")
-            .contains("DTEND:20190526T160000Z")
+            .contains("DTSTART;TZID=Etc/UTC:20190526T120000")
+            .contains("DTEND;TZID=Etc/UTC:20190526T160000")
             .contains("UID:BB2267885BD8DF263E88D3062853E8A7")
             .contains("SEQUENCE:1")
 
@@ -240,8 +240,8 @@ class ICalServiceTest {
             .contains("X-MICROSOFT-CALSCALE:GREGORIAN")
 
             .contains("SUMMARY:Marlene Muster abwesend")
-            .contains("DTSTART:20190526T120000Z")
-            .contains("DTEND:20190526T160000Z")
+            .contains("DTSTART;TZID=Etc/UTC:20190526T120000")
+            .contains("DTEND;TZID=Etc/UTC:20190526T160000")
             .contains("UID:BB2267885BD8DF263E88D3062853E8A7")
 
             .contains("ORGANIZER:mailto:no-reply@example.org")
@@ -274,7 +274,7 @@ class ICalServiceTest {
 
             .contains("SUMMARY:Marlene Muster abwesend")
             .contains("X-MICROSOFT-CDO-ALLDAYEVENT:TRUE")
-            .contains("DTSTART;VALUE=DATE:20190526")
+            .contains("DTSTART;TZID=Etc/UTC:20190526T000000")
             .contains("TRANSP:TRANSPARENT")
             .contains("UID:22D8DC26F4271C049ED5601345B58D9C")
 
@@ -306,7 +306,7 @@ class ICalServiceTest {
 
             .contains("SUMMARY:Marlene Muster abwesend")
             .contains("X-MICROSOFT-CDO-ALLDAYEVENT:TRUE")
-            .contains("DTSTART;VALUE=DATE:20190526")
+            .contains("DTSTART;TZID=Etc/UTC:20190526T000000")
             .contains("TRANSP:TRANSPARENT")
             .contains("UID:22D8DC26F4271C049ED5601345B58D9C")
 
@@ -334,7 +334,7 @@ class ICalServiceTest {
 
             .contains("SUMMARY:Vertretung für Marlene Muster")
             .contains("X-MICROSOFT-CDO-ALLDAYEVENT:TRUE")
-            .contains("DTSTART;VALUE=DATE:20190526")
+            .contains("DTSTART;TZID=Etc/UTC:20190526T000000")
             .contains("TRANSP:TRANSPARENT")
             .contains("UID:D2A4772AEB3FD20D5F6997FCD8F28719")