From 4e2321f37ffd8092e20e13787a56fcd01499601b Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Wed, 27 Aug 2014 15:30:48 +0200
Subject: [PATCH] no-jira: fix a NPE if a calendar is persisted with an event
 without end date

---
 .../calendar/ICalFileCalendarManager.java     | 23 +++++++----
 .../calendar/ICalFileCalendarManagerTest.java | 39 +++++++++++++++++--
 .../commons/calendar/cal_without_dtend.ics    | 15 +++++++
 3 files changed, 67 insertions(+), 10 deletions(-)
 create mode 100644 src/test/resources/org/olat/commons/calendar/cal_without_dtend.ics

diff --git a/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java b/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java
index 03e8df7a8ae..450674f1dac 100644
--- a/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java
+++ b/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java
@@ -147,6 +147,7 @@ public class ICalFileCalendarManager extends BasicManager implements CalendarMan
 	 * @param type
 	 * @return
 	 */
+	@Override
 	public boolean calendarExists(String calendarType, String calendarID) {
 		return getCalendarFile(calendarType, calendarID).exists();
 	}
@@ -155,6 +156,7 @@ public class ICalFileCalendarManager extends BasicManager implements CalendarMan
 	 * 
 	 * @see org.olat.calendar.CalendarManager#createClaendar(java.lang.String)
 	 */
+	@Override
 	public Kalendar createCalendar(String type, String calendarID) {
 		return new Kalendar(calendarID, type);
 	}
@@ -185,6 +187,7 @@ public class ICalFileCalendarManager extends BasicManager implements CalendarMan
 	/**
 	 * {@inheritDoc}
 	 */
+	@Override
 	public OLATResourceable getOresHelperFor(Kalendar cal) {
 		return OresHelper.createOLATResourceableType(getKeyFor(cal.getType(), cal.getCalendarID()));
 	}
@@ -224,6 +227,7 @@ public class ICalFileCalendarManager extends BasicManager implements CalendarMan
   /**
    * Internal read calendar file from filesystem
    */
+	@Override
   public Calendar readCalendar(String type, String calendarID) {
   	log.debug("readCalendar from file, type=" + type + "  calendarID=" + calendarID);
 		File calendarFile = getCalendarFile(type, calendarID);
@@ -247,7 +251,8 @@ public class ICalFileCalendarManager extends BasicManager implements CalendarMan
 		}
     return calendar;
   }
-  
+
+	@Override
   public Kalendar buildKalendarFrom(String calendarContent, String calType, String calId) {
   	Kalendar kalendar = null;
   	BufferedReader reader = new BufferedReader(new StringReader(calendarContent));
@@ -354,9 +359,13 @@ public class ICalFileCalendarManager extends BasicManager implements CalendarMan
 			if(tz != null) {
 				dtBegin.setTimeZone(tz);
 			}
-			DateTime dtEnd = new DateTime(kEvent.getEnd());
-			if(tz != null) {
-				dtEnd.setTimeZone(tz);
+			DateTime dtEnd = null;
+			Date kEventEnd = kEvent.getEnd();
+			if(kEventEnd != null) {
+				dtEnd = new DateTime();
+				if(tz != null) {
+					dtEnd.setTimeZone(tz);
+				}
 			}
 			vEvent = new VEvent(dtBegin, dtEnd, kEvent.getSubject());
 		} else {
@@ -496,9 +505,9 @@ public class ICalFileCalendarManager extends BasicManager implements CalendarMan
 		if (isAllDay) {
 			//Make sure the time of the dates are 00:00 localtime because DATE fields in iCal are GMT 00:00 
 			//Note that start date and end date can have different offset because of daylight saving switch
-			java.util.TimeZone tz = java.util.GregorianCalendar.getInstance().getTimeZone();
-			start = new Date(start.getTime() - tz.getOffset(start.getTime()));
-			end   = new Date(end.getTime()   - tz.getOffset(end.getTime()));
+			java.util.TimeZone timezone = java.util.GregorianCalendar.getInstance().getTimeZone();
+			start = new Date(start.getTime() - timezone.getOffset(start.getTime()));
+			end   = new Date(end.getTime()   - timezone.getOffset(end.getTime()));
 			
 			// adjust end date: ICal sets end dates to the next day
 			end = new Date(end.getTime() - (1000 * 60 * 60 * 24));
diff --git a/src/test/java/org/olat/commons/calendar/ICalFileCalendarManagerTest.java b/src/test/java/org/olat/commons/calendar/ICalFileCalendarManagerTest.java
index a2dd21a141d..0cd0c3f2929 100644
--- a/src/test/java/org/olat/commons/calendar/ICalFileCalendarManagerTest.java
+++ b/src/test/java/org/olat/commons/calendar/ICalFileCalendarManagerTest.java
@@ -32,16 +32,23 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.commons.io.FileUtils;
+import org.jcodec.common.Assert;
 import org.junit.Test;
 import org.olat.commons.calendar.model.Kalendar;
 import org.olat.commons.calendar.model.KalendarEvent;
+import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLog;
@@ -50,7 +57,6 @@ import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
 
 
-
 public class ICalFileCalendarManagerTest extends OlatTestCase {
 
 	private static final OLog log = Tracing.createLoggerFor(ICalFileCalendarManagerTest.class);
@@ -63,7 +69,7 @@ public class ICalFileCalendarManagerTest extends OlatTestCase {
 		CalendarManager manager = CalendarManagerFactory.getJUnitInstance().getCalendarManager();
 		Kalendar cal = manager.getPersonalCalendar(test).getKalendar();
 		// 1. Test Add Event
-		KalendarEvent testEvent = new KalendarEvent(TEST_EVENT_ID,"testEvent", new Date(), 1);
+		KalendarEvent testEvent = new KalendarEvent(TEST_EVENT_ID, "testEvent", new Date(), 1);
 		manager.addEventTo(cal, testEvent);
 		// set manager null to force reload of calendar from file-system
 		manager = null;
@@ -91,7 +97,34 @@ public class ICalFileCalendarManagerTest extends OlatTestCase {
 		assertNull("Found removed event", removedEvent);
 	}
 
-
+	/**
+	 * Check a NPE
+	 * @throws IOException
+	 */
+	@Test
+	public void testPersistCalendarWithoutDTEndEvent() throws IOException {
+		//replace the standard calendar with a forged one
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("cal-test-1-");
+		CalendarManager calManager = CalendarManagerFactory.getInstance().getCalendarManager();
+		File calendarFile = calManager.getCalendarFile("user", identity.getName());
+		if(calendarFile.exists()) {
+			calendarFile.delete();
+		}
+		File newCalendarFile = new File(calendarFile.getParentFile(), calendarFile.getName());
+		InputStream in = CalendarImportTest.class.getResourceAsStream("cal_without_dtend.ics");
+		FileUtils.copyInputStreamToFile(in, newCalendarFile);
+		
+		//load the calendar
+		KalendarRenderWrapper reloadCalWrapper = calManager.getPersonalCalendar(identity);
+		//check if its the right calendar
+		Collection<KalendarEvent> events = reloadCalWrapper.getKalendar().getEvents();
+		Assert.assertNotNull(events);
+		Assert.assertEquals(1, events.size());
+		
+		//persist
+		calManager.persistCalendar(reloadCalWrapper.getKalendar());
+	}
+	
 	/**
 	 * Test concurrent add event with two threads and code-point to control concurrency.
 	 *
diff --git a/src/test/resources/org/olat/commons/calendar/cal_without_dtend.ics b/src/test/resources/org/olat/commons/calendar/cal_without_dtend.ics
new file mode 100644
index 00000000000..ccedb43c32e
--- /dev/null
+++ b/src/test/resources/org/olat/commons/calendar/cal_without_dtend.ics
@@ -0,0 +1,15 @@
+BEGIN:VCALENDAR
+PRODID:-//Ben Fortuna//iCal4j 1.0//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+DTSTAMP:20140115T112220Z
+DTSTART;TZID=Europe/Zurich:20100319T090000
+SUMMARY:Arbeitszeit: 1-3h
+CREATED:20100308T103303Z
+LAST-MODIFIED:20100416T052451Z
+UID:e73iiu9masoddi4g0vllmi2ht0@google.com
+CLASS:PRIVATE
+LOCATION:
+END:VEVENT
+END:VCALENDAR
\ No newline at end of file
-- 
GitLab