[CalendarServer-changes] [14929] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Jun 29 13:48:15 PDT 2015


Revision: 14929
          http://trac.calendarserver.org//changeset/14929
Author:   cdaboo at apple.com
Date:     2015-06-29 13:48:15 -0700 (Mon, 29 Jun 2015)
Log Message:
-----------
Fix recurrence splitting for all-day and floating events.

Modified Paths:
--------------
    CalendarServer/trunk/doc/Extensions/caldav-recursplit.txt
    CalendarServer/trunk/doc/Extensions/caldav-recursplit.xml
    CalendarServer/trunk/requirements-dev.txt
    CalendarServer/trunk/twistedcaldav/ical.py
    CalendarServer/trunk/txdav/caldav/datastore/scheduling/icalsplitter.py
    CalendarServer/trunk/txdav/caldav/datastore/sql.py
    CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py

Modified: CalendarServer/trunk/doc/Extensions/caldav-recursplit.txt
===================================================================
--- CalendarServer/trunk/doc/Extensions/caldav-recursplit.txt	2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/doc/Extensions/caldav-recursplit.txt	2015-06-29 20:48:15 UTC (rev 14929)
@@ -4,11 +4,11 @@
 
                                                                 C. Daboo
                                                                    Apple
-                                                        October 30, 2014
+                                                           June 26, 2015
 
 
              Smart Splitting of Recurring Events in CalDAV
-                          caldav-recursplit-01
+                          caldav-recursplit-02
 
 Abstract
 
@@ -22,7 +22,7 @@
    1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   1
    2.  Conventions Used in This Document . . . . . . . . . . . . . .   2
    3.  New behavior  . . . . . . . . . . . . . . . . . . . . . . . .   3
-     3.1.  Example . . . . . . . . . . . . . . . . . . . . . . . . .   5
+     3.1.  Example . . . . . . . . . . . . . . . . . . . . . . . . .   6
    4.  Server Initiated Splitting  . . . . . . . . . . . . . . . . .   8
    5.  Security Considerations . . . . . . . . . . . . . . . . . . .   8
    6.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .   8
@@ -53,9 +53,9 @@
 
 
 
-Daboo                      Expires May 3, 2015                  [Page 1]
+Daboo                   Expires December 28, 2015               [Page 1]
 
-                       CalDAV Recurrence Splitting          October 2014
+                       CalDAV Recurrence Splitting             June 2015
 
 
    instances from that point onwards.  Typically this is done by
@@ -109,9 +109,9 @@
 
 
 
-Daboo                      Expires May 3, 2015                  [Page 2]
+Daboo                   Expires December 28, 2015               [Page 2]
 
-                       CalDAV Recurrence Splitting          October 2014
+                       CalDAV Recurrence Splitting             June 2015
 
 
 3.  New behavior
@@ -128,16 +128,30 @@
 
    1.  "action" set to the value "split" - REQUIRED
 
-   2.  "rid" set to an iCalendar format DATE-TIME value in UTC
-       ("YYYYMMDDTHHMMSSZ" style format) - REQUIRED
+   2.  "rid" set to an iCalendar format DATE or DATE-TIME value (with
+       format choice determined as per description below) - REQUIRED
 
    3.  "uid" set to an iCalendar UID property value - OPTIONAL
 
    The "action" parameter is used to distinguish this operation from
    others that might be defined in the future for calendar object
-   resources.  The "rid" parameter specified the UTC date-time where the
-   split is to occur.  The actual split occurs at the next recurrence
-   instance on or after the "rid" parameter value - the "split point".
+   resources.
+
+   The "rid" parameter specifies the date or date-time where the split
+   is to occur.  The actual split occurs at the next recurrence instance
+   on or after the "rid" parameter value - the "split point".  The "rid"
+   parameter value is an iCalendar DATE or DATE-TIME value that follows
+   that matched the event's DTSTART value as follows:
+
+   +---------------------------+--------------------+------------------+
+   | DTSTART value             | rid value          | rid example      |
+   +---------------------------+--------------------+------------------+
+   | DATE                      | DATE               | 20150626         |
+   | DATE-TIME UTC             | DATE-TIME UTC      | 20150626T120000Z |
+   | DATE-TIME local+time zone | DATE-TIME UTC      | 20150626T120000Z |
+   | DATE-TIME floating        | DATE-TIME floating | 20150626T120000  |
+   +---------------------------+--------------------+------------------+
+
    The optional "uid" parameter can be used by the client to specify the
    iCalendar UID property value used in the new calendar object resource
    created by the server.  In the absence of the "uid" parameter, the
@@ -145,9 +159,17 @@
    resource.
 
    Clients MUST include both "action" and "rid" parameters in the POST
-   request and MUST ensure a valid date-time value is used.  The date-
-   time value MUST NOT be earlier than the start time of the first
+   request and MUST ensure a valid date-time value is used.  The "rid"
+   parameter value MUST NOT be earlier than the start time of the first
    instance of the recurrence set, and it MUST NOT be later than the
+
+
+
+Daboo                   Expires December 28, 2015               [Page 3]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
    start time of the last instance of the recurrence set.  If the "rid"
    parameter value is not of the correct format or missing, the server
    MUST return a DAV:error response with the CALDAV:valid-rid-parameter
@@ -162,14 +184,6 @@
    too long as per reasonable requirements), then it MUST return a
    DAV:error response with the CS:invalid-split pre-condition code.
 
-
-
-
-Daboo                      Expires May 3, 2015                  [Page 3]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
    Clients MAY include an HTTP "Prefer" request header including the
    value "return=representation" (see [RFC7240]).  That instructs the
    server to return a WebDAV multistatus response containing two
@@ -203,6 +217,15 @@
            by subtracting the number of instances prior to the split
            point.
 
+
+
+
+
+Daboo                   Expires December 28, 2015               [Page 4]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
        E.  The "DTSTART" property of the master instance is adjusted to
            the value of the first instance of the "RRULE" on or after
            the split point, or, in the absence of an "RRULE", to the
@@ -219,16 +242,10 @@
        C.  Any "RRULE" property that only generates instances on or
            after the split point is removed.
 
-
-
-Daboo                      Expires May 3, 2015                  [Page 4]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
        D.  Any remaining "RRULE" property has an "UNTIL" value applied,
-           with the until value being one second less than the split
-           point.
+           with the until value being one second (for a "rid" DATE-TIME
+           value) or one day (for a "rid" DATE value) less than the
+           split point.
 
        E.  The "UID" property of all components is changed to (the same)
            new value.
@@ -256,6 +273,15 @@
        attendee with both the modified (old) resource data and the new
        resource.  This will likely result in loss of per-attendee data
        such as alarms (though the participation status might be
+
+
+
+
+Daboo                   Expires December 28, 2015               [Page 5]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
        preserved if the calendar user agent processing the new iTIP
        message for the new resource allows it).
 
@@ -272,16 +298,6 @@
    Assume the following iCalendar data is stored in the resource with
    URI "/event.ics":
 
-
-
-
-
-
-Daboo                      Expires May 3, 2015                  [Page 5]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
    BEGIN:VCALENDAR
    PRODID:-//Example Inc.//Example Calendar//EN
    VERSION:2.0
@@ -314,6 +330,14 @@
    Content-Type: text/xml
    Content-Length: xxxx
 
+
+
+
+Daboo                   Expires December 28, 2015               [Page 6]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
    <?xml version='1.0' encoding='UTF-8'?>
    <multistatus xmlns='DAV:'>
      <response>
@@ -330,14 +354,6 @@
    DTSTART:20140110T120000Z
    DURATION:PT1H
    DTSTAMP:20140110T135358Z
-
-
-
-Daboo                      Expires May 3, 2015                  [Page 6]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
    RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:8DE45ECB-8145-
     4AEC-B3E1-11A9DB22A578
    RRULE:FREQ=DAILY;COUNT=11
@@ -370,6 +386,14 @@
    END:VEVENT
    END:VCALENDAR
    </calendar-data>
+
+
+
+Daboo                   Expires December 28, 2015               [Page 7]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
          </prop>
          <status>HTTP/1.1 200 OK</status>
        </propstat>
@@ -386,14 +410,6 @@
    "RELTYPE" parameter set to "X-CALENDARSERVER-RECURRENCE-SET" and a
    value set to a new "UID" value.
 
-
-
-
-Daboo                      Expires May 3, 2015                  [Page 7]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
 4.  Server Initiated Splitting
 
    Servers can automatically split events that have already been stored
@@ -426,6 +442,14 @@
               "Calendaring Extensions to WebDAV (CalDAV)", RFC 4791,
               March 2007.
 
+
+
+
+Daboo                   Expires December 28, 2015               [Page 8]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
    [RFC5545]  Desruisseaux, B., "Internet Calendaring and Scheduling
               Core Object Specification (iCalendar)", RFC 5545,
               September 2009.
@@ -439,17 +463,6 @@
 
    [RFC7240]  Snell, J., "Prefer Header for HTTP", RFC 7240, June 2014.
 
-
-
-
-
-
-
-Daboo                      Expires May 3, 2015                  [Page 8]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
 Appendix A.  Acknowledgments
 
    This specification is the result of discussions between the Apple
@@ -457,6 +470,14 @@
 
 Appendix B.  Change History
 
+   Changes since -02
+
+   1.  Clarify that rid query parameter value matches the event DTSTART
+       value type using the UNTIL "rules"
+
+   2.  Clarify that earlier event uses an UNTIL one second or one day
+       less that the "rid" value depending on the value type.
+
    Changes since -01
 
    1.  Added "uid" query parameter to POST request
@@ -480,25 +501,4 @@
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Daboo                      Expires May 3, 2015                  [Page 9]
+Daboo                   Expires December 28, 2015               [Page 9]

Modified: CalendarServer/trunk/doc/Extensions/caldav-recursplit.xml
===================================================================
--- CalendarServer/trunk/doc/Extensions/caldav-recursplit.xml	2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/doc/Extensions/caldav-recursplit.xml	2015-06-29 20:48:15 UTC (rev 14929)
@@ -18,7 +18,7 @@
 <?rfc compact="yes"?>
 <?rfc subcompact="no"?>
 <?rfc private="Calendar Server Extension"?>
-<rfc ipr="none" docName='caldav-recursplit-01'>
+<rfc ipr="none" docName='caldav-recursplit-02'>
     <front>
         <title abbrev="CalDAV Recurrence Splitting">Smart Splitting of Recurring Events in CalDAV</title> 
         <author initials="C." surname="Daboo" fullname="Cyrus Daboo">
@@ -79,12 +79,37 @@
           <t>To split an existing calendar object resource containing a recurring event, a client issues an HTTP POST resource with the request-uri set to the URI of the calendar object resource. The client also includes the following two URI query parameters, and one optional one:
             <list style='numbers'>
               <t>"action" set to the value "split" - REQUIRED</t>
-              <t>"rid" set to an iCalendar format DATE-TIME value in UTC ("YYYYMMDDTHHMMSSZ" style format) - REQUIRED</t>
+              <t>"rid" set to an iCalendar format DATE or DATE-TIME value (with format choice determined as per description below) - REQUIRED</t>
               <t>"uid" set to an iCalendar UID property value - OPTIONAL</t>
             </list>
-            The "action" parameter is used to distinguish this operation from others that might be defined in the future for calendar object resources. The "rid" parameter specified the UTC date-time where the split is to occur. The actual split occurs at the next recurrence instance on or after the "rid" parameter value - the "split point". The optional "uid" parameter can be used by the client to specify the iCalendar UID property value used in the new calendar object resource created by the server. In the absence of the "uid" parameter, the server will itself generate the UID value for the new calendar object resource.</t>
+            </t>
+            <t>The "action" parameter is used to distinguish this operation from others that might be defined in the future for calendar object resources.</t>
+            <t>The "rid" parameter specifies the date or date-time where the split is to occur. The actual split occurs at the next recurrence instance on or after the "rid" parameter value - the "split point". The "rid" parameter value is an iCalendar DATE or DATE-TIME value that follows that matched the event's DTSTART value as follows:</t>
+            <texttable>
+              <ttcol>DTSTART value</ttcol>
+              <ttcol>rid value</ttcol>
+              <ttcol>rid example</ttcol>
+
+              <c>DATE</c>
+              <c>DATE</c>
+              <c>20150626</c>
+
+              <c>DATE-TIME UTC</c>
+              <c>DATE-TIME UTC</c>
+              <c>20150626T120000Z</c>
+
+              <c>DATE-TIME local+time zone</c>
+              <c>DATE-TIME UTC</c>
+              <c>20150626T120000Z</c>
+
+              <c>DATE-TIME floating</c>
+              <c>DATE-TIME floating</c>
+              <c>20150626T120000</c>
+
+            </texttable>
+            <t>The optional "uid" parameter can be used by the client to specify the iCalendar UID property value used in the new calendar object resource created by the server. In the absence of the "uid" parameter, the server will itself generate the UID value for the new calendar object resource.</t>
             <t>
-            Clients MUST include both "action" and "rid" parameters in the POST request and MUST ensure a valid date-time value is used. The date-time value MUST NOT be earlier than the start time of the first instance of the recurrence set, and it MUST NOT be later than the start time of the last instance of the recurrence set. If the "rid" parameter value is not of the correct format or missing, the server MUST return a DAV:error response with the CALDAV:valid-rid-parameter pre-condition code. If the "rid" parameter is valid, but outside of the allowed range, or the targeted calendar object resource is not recurring, then the server MUST return a DAV:error response with the CS:invalid-split pre-condition code. The server MUST reject any attempt by an attendee to split their copy of a scheduled calendar object resource - only organizers are allowed to split events. If the optional "uid" parameter is used by the client, and the server determines that the specified value is i
 nvalid (e.g., too short or too long as per reasonable requirements), then it MUST return a DAV:error response with the CS:invalid-split pre-condition code.
+            Clients MUST include both "action" and "rid" parameters in the POST request and MUST ensure a valid date-time value is used. The "rid" parameter value MUST NOT be earlier than the start time of the first instance of the recurrence set, and it MUST NOT be later than the start time of the last instance of the recurrence set. If the "rid" parameter value is not of the correct format or missing, the server MUST return a DAV:error response with the CALDAV:valid-rid-parameter pre-condition code. If the "rid" parameter is valid, but outside of the allowed range, or the targeted calendar object resource is not recurring, then the server MUST return a DAV:error response with the CS:invalid-split pre-condition code. The server MUST reject any attempt by an attendee to split their copy of a scheduled calendar object resource - only organizers are allowed to split events. If the optional "uid" parameter is used by the client, and the server determines that the specified valu
 e is invalid (e.g., too short or too long as per reasonable requirements), then it MUST return a DAV:error response with the CS:invalid-split pre-condition code.
           </t>
           <t>
             Clients MAY include an HTTP "Prefer" request header including the value "return=representation" (see <xref target='RFC7240'/>). That instructs the server to return a WebDAV multistatus response containing two responses: one for the targeted resource and one for the new resource created as a result of the split. The multistatus response MUST include the DAV:getetag and CALDAV:calendar-data properties for each resource. In the absence of the "Prefer:return=representation" request header, the server MUST return an HTTP "Split-Component-URL" response header whose value is the URI of the new resource created as a result of the split.
@@ -107,7 +132,7 @@
                   <t>Any overridden components with a "RECURRENCE-ID" property value on or after the split point are removed.</t>
                   <t>Any "RDATE" or "EXDATE" property values on or after the split point are removed.</t>
                   <t>Any "RRULE" property that only generates instances on or after the split point is removed.</t>
-                  <t>Any remaining "RRULE" property has an "UNTIL" value applied, with the until value being one second less than the split point.</t>
+                  <t>Any remaining "RRULE" property has an "UNTIL" value applied, with the until value being one second (for a "rid" DATE-TIME value) or one day (for a "rid" DATE value) less than the split point.</t>
                   <t>The "UID" property of all components is changed to (the same) new value.</t>
                   <t>Attendee participation status MUST NOT be changed.</t>
                 </list>
@@ -259,6 +284,12 @@
             </t>
         </section>
         <section title='Change History'>
+          <t>Changes since -02
+            <list style='numbers'>
+              <t>Clarify that rid query parameter value matches the event DTSTART value type using the UNTIL "rules"</t>
+              <t>Clarify that earlier event uses an UNTIL one second or one day less that the "rid" value depending on the value type.</t>
+            </list>
+          </t>
           <t>Changes since -01
             <list style='numbers'>
               <t>Added "uid" query parameter to POST request</t>

Modified: CalendarServer/trunk/requirements-dev.txt
===================================================================
--- CalendarServer/trunk/requirements-dev.txt	2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/requirements-dev.txt	2015-06-29 20:48:15 UTC (rev 14929)
@@ -8,4 +8,4 @@
 q
 tl.eggdeps
 --editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVClientLibrary/trunk@14856#egg=CalDAVClientLibrary
---editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@14920#egg=CalDAVTester
+--editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@14928#egg=CalDAVTester

Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py	2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/twistedcaldav/ical.py	2015-06-29 20:48:15 UTC (rev 14929)
@@ -1255,7 +1255,10 @@
                     rrule.setUseUntil(True)
                     rrule.setUseCount(False)
                     until = rid.duplicate()
-                    until.offsetSeconds(-1)
+                    if until.isDateOnly():
+                        until.offsetDay(-1)
+                    else:
+                        until.offsetSeconds(-1)
                     rrule.setUntil(until)
 
             # Remove any RDATEs or EXDATEs in the future

Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/icalsplitter.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/scheduling/icalsplitter.py	2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/txdav/caldav/datastore/scheduling/icalsplitter.py	2015-06-29 20:48:15 UTC (rev 14929)
@@ -139,6 +139,15 @@
             # where the Organizer event has L{willSplit} == C{True}
             rid = break_point if allow_past_the_end else None
 
+        if rid is not None:
+            # rid value type must match
+            dtstart = ical.mainComponent().propertyValue("DTSTART")
+            if dtstart.isDateOnly():
+                rid.setDateOnly(True)
+            elif dtstart.floating():
+                rid.setTimezoneID(None)
+
+
         return rid
 
 

Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py	2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py	2015-06-29 20:48:15 UTC (rev 14929)
@@ -5153,6 +5153,19 @@
         if organizer is not None and organizerAddress.record.uid != self.calendar().ownerHome().uid():
             raise InvalidSplit("Only organizers can split events.")
 
+        # rid value type must match
+        dtstart = component.mainComponent().propertyValue("DTSTART")
+        if dtstart.isDateOnly():
+            if not rid.isDateOnly():
+                # We ought to reject this but for now we will fix it
+                rid.setDateOnly(True)
+        elif dtstart.floating():
+            if not rid.floating() or rid.isDateOnly():
+                raise InvalidSplit("rid parameter value type must match DTSTART value type.")
+        else:
+            if rid.floating():
+                raise InvalidSplit("rid parameter value type must match DTSTART value type.")
+
         # Determine valid split point
         splitter = iCalSplitter(1024, 14)
         rid = splitter.whereSplit(component, break_point=rid, allow_past_the_end=False)

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py	2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py	2015-06-29 20:48:15 UTC (rev 14929)
@@ -3183,8 +3183,14 @@
 
         self.now = DateTime.getNowUTC()
         self.now.setHHMMSS(0, 0, 0)
+        self.nowDate = self.now.duplicate()
+        self.nowDate.setDateOnly(True)
+        self.nowFloating = self.now.duplicate()
+        self.nowFloating.setTimezoneID(None)
 
         self.subs["now"] = self.now
+        self.subs["nowDate"] = self.nowDate
+        self.subs["nowFloating"] = self.nowFloating
 
         for i in range(30):
             attrname = "now_back%s" % (i + 1,)
@@ -3202,6 +3208,21 @@
             getattr(self, attrname_1).offsetSeconds(-1)
             self.subs[attrname_1] = getattr(self, attrname_1)
 
+            attrname = "nowDate_back%s" % (i + 1,)
+            setattr(self, attrname, self.nowDate.duplicate())
+            getattr(self, attrname).offsetDay(-(i + 1))
+            self.subs[attrname] = getattr(self, attrname)
+
+            attrname = "nowFloating_back%s" % (i + 1,)
+            setattr(self, attrname, self.nowFloating.duplicate())
+            getattr(self, attrname).offsetDay(-(i + 1))
+            self.subs[attrname] = getattr(self, attrname)
+
+            attrname_1 = "nowFloating_back%s_1" % (i + 1,)
+            setattr(self, attrname_1, getattr(self, attrname).duplicate())
+            getattr(self, attrname_1).offsetSeconds(-1)
+            self.subs[attrname_1] = getattr(self, attrname_1)
+
         for i in range(30):
             attrname = "now_fwd%s" % (i + 1,)
             setattr(self, attrname, self.now.duplicate())
@@ -3213,6 +3234,16 @@
             getattr(self, attrname_12h).offsetHours(12)
             self.subs[attrname_12h] = getattr(self, attrname_12h)
 
+            attrname = "nowDate_fwd%s" % (i + 1,)
+            setattr(self, attrname, self.nowDate.duplicate())
+            getattr(self, attrname).offsetDay(i + 1)
+            self.subs[attrname] = getattr(self, attrname)
+
+            attrname = "nowFloating_fwd%s" % (i + 1,)
+            setattr(self, attrname, self.nowFloating.duplicate())
+            getattr(self, attrname).offsetDay(i + 1)
+            self.subs[attrname] = getattr(self, attrname)
+
         self.patch(config, "MaxAllowedInstances", 500)
 
 
@@ -3453,6 +3484,428 @@
 
 
     @inlineCallbacks
+    def test_calendarObjectSplit_AllDay(self):
+        """
+        Test that (manual) splitting of all-day calendar objects works.
+        """
+
+        self.patch(config.Scheduling.Options.Splitting, "Enabled", False)
+        self.patch(config.Scheduling.Options.Splitting, "Size", 1024)
+        self.patch(config.Scheduling.Options.Splitting, "PastDays", 14)
+
+        # Create one event that will split
+        calendar = yield self.calendarUnderTest(name="calendar", home="user01")
+
+        data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:%(nowDate_back30)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+ATTENDEE:mailto:user3 at example.org
+ATTENDEE:mailto:user4 at example.org
+ATTENDEE:mailto:user5 at example.org
+ATTENDEE:mailto:user6 at example.org
+ATTENDEE:mailto:user7 at example.org
+ATTENDEE:mailto:user8 at example.org
+ATTENDEE:mailto:user9 at example.org
+ATTENDEE:mailto:user10 at example.org
+ATTENDEE:mailto:user11 at example.org
+ATTENDEE:mailto:user12 at example.org
+ATTENDEE:mailto:user13 at example.org
+ATTENDEE:mailto:user14 at example.org
+ATTENDEE:mailto:user15 at example.org
+ATTENDEE:mailto:user16 at example.org
+ATTENDEE:mailto:user17 at example.org
+ATTENDEE:mailto:user18 at example.org
+ATTENDEE:mailto:user19 at example.org
+ATTENDEE:mailto:user20 at example.org
+ATTENDEE:mailto:user21 at example.org
+ATTENDEE:mailto:user22 at example.org
+ATTENDEE:mailto:user23 at example.org
+ATTENDEE:mailto:user24 at example.org
+ATTENDEE:mailto:user25 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1 at example.org
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID;VALUE=DATE:%(nowDate_back25)s
+DTSTART;VALUE=DATE:%(nowDate_back25)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1 at example.org
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID;VALUE=DATE:%(nowDate_back24)s
+DTSTART;VALUE=DATE:%(nowDate_back24)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1 at example.org
+END:VEVENT
+END:VCALENDAR
+"""
+
+        data_future = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:%(nowDate_back14)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+ATTENDEE:mailto:user3 at example.org
+ATTENDEE:mailto:user4 at example.org
+ATTENDEE:mailto:user5 at example.org
+ATTENDEE:mailto:user6 at example.org
+ATTENDEE:mailto:user7 at example.org
+ATTENDEE:mailto:user8 at example.org
+ATTENDEE:mailto:user9 at example.org
+ATTENDEE:mailto:user10 at example.org
+ATTENDEE:mailto:user11 at example.org
+ATTENDEE:mailto:user12 at example.org
+ATTENDEE:mailto:user13 at example.org
+ATTENDEE:mailto:user14 at example.org
+ATTENDEE:mailto:user15 at example.org
+ATTENDEE:mailto:user16 at example.org
+ATTENDEE:mailto:user17 at example.org
+ATTENDEE:mailto:user18 at example.org
+ATTENDEE:mailto:user19 at example.org
+ATTENDEE:mailto:user20 at example.org
+ATTENDEE:mailto:user21 at example.org
+ATTENDEE:mailto:user22 at example.org
+ATTENDEE:mailto:user23 at example.org
+ATTENDEE:mailto:user24 at example.org
+ATTENDEE:mailto:user25 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1 at example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+RRULE:FREQ=DAILY
+SEQUENCE:1
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+"""
+
+        data_past = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:%(uid)s
+DTSTART;VALUE=DATE:%(nowDate_back30)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+ATTENDEE:mailto:user3 at example.org
+ATTENDEE:mailto:user4 at example.org
+ATTENDEE:mailto:user5 at example.org
+ATTENDEE:mailto:user6 at example.org
+ATTENDEE:mailto:user7 at example.org
+ATTENDEE:mailto:user8 at example.org
+ATTENDEE:mailto:user9 at example.org
+ATTENDEE:mailto:user10 at example.org
+ATTENDEE:mailto:user11 at example.org
+ATTENDEE:mailto:user12 at example.org
+ATTENDEE:mailto:user13 at example.org
+ATTENDEE:mailto:user14 at example.org
+ATTENDEE:mailto:user15 at example.org
+ATTENDEE:mailto:user16 at example.org
+ATTENDEE:mailto:user17 at example.org
+ATTENDEE:mailto:user18 at example.org
+ATTENDEE:mailto:user19 at example.org
+ATTENDEE:mailto:user20 at example.org
+ATTENDEE:mailto:user21 at example.org
+ATTENDEE:mailto:user22 at example.org
+ATTENDEE:mailto:user23 at example.org
+ATTENDEE:mailto:user24 at example.org
+ATTENDEE:mailto:user25 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1 at example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+RRULE:FREQ=DAILY;UNTIL=%(nowDate_back15)s
+SEQUENCE:1
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:%(uid)s
+RECURRENCE-ID;VALUE=DATE:%(nowDate_back25)s
+DTSTART;VALUE=DATE:%(nowDate_back25)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1 at example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+SEQUENCE:1
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:%(uid)s
+RECURRENCE-ID;VALUE=DATE:%(nowDate_back24)s
+DTSTART;VALUE=DATE:%(nowDate_back24)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1 at example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+SEQUENCE:1
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+"""
+
+        component = Component.fromString(data % self.subs)
+        cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
+        self.assertFalse(hasattr(cobj, "_workItems"))
+        yield self.commit()
+
+        w = schema.CALENDAR_OBJECT_SPLITTER_WORK
+        rows = yield Select(
+            [w.RESOURCE_ID, ],
+            From=w
+        ).on(self.transactionUnderTest())
+        self.assertEqual(len(rows), 0)
+        yield self.abort()
+
+        # Do manual split
+        cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
+        will = yield cobj.willSplit()
+        self.assertTrue(will)
+
+        yield cobj.split()
+        yield self.commit()
+
+        ical_future, ical_past, pastUID, relID, _ignore_new_name = yield self._splitDetails("user01")
+
+        title = "temp"
+        relsubs = dict(self.subs)
+        relsubs["uid"] = pastUID
+        relsubs["relID"] = relID
+        self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s %s" % (title, diff_iCalStrs(ical_future, data_future % relsubs)))
+        self.assertEqual(normalize_iCalStr(ical_past), normalize_iCalStr(data_past) % relsubs, "Failed past: %s %s" % (title, diff_iCalStrs(ical_past, data_past % relsubs)))
+
+
+    @inlineCallbacks
+    def test_calendarObjectSplit_Floating(self):
+        """
+        Test that (manual) splitting of floating calendar objects works.
+        """
+
+        self.patch(config.Scheduling.Options.Splitting, "Enabled", False)
+        self.patch(config.Scheduling.Options.Splitting, "Size", 1024)
+        self.patch(config.Scheduling.Options.Splitting, "PastDays", 14)
+
+        # Create one event that will split
+        calendar = yield self.calendarUnderTest(name="calendar", home="user01")
+
+        data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:%(nowFloating_back30)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+ATTENDEE:mailto:user3 at example.org
+ATTENDEE:mailto:user4 at example.org
+ATTENDEE:mailto:user5 at example.org
+ATTENDEE:mailto:user6 at example.org
+ATTENDEE:mailto:user7 at example.org
+ATTENDEE:mailto:user8 at example.org
+ATTENDEE:mailto:user9 at example.org
+ATTENDEE:mailto:user10 at example.org
+ATTENDEE:mailto:user11 at example.org
+ATTENDEE:mailto:user12 at example.org
+ATTENDEE:mailto:user13 at example.org
+ATTENDEE:mailto:user14 at example.org
+ATTENDEE:mailto:user15 at example.org
+ATTENDEE:mailto:user16 at example.org
+ATTENDEE:mailto:user17 at example.org
+ATTENDEE:mailto:user18 at example.org
+ATTENDEE:mailto:user19 at example.org
+ATTENDEE:mailto:user20 at example.org
+ATTENDEE:mailto:user21 at example.org
+ATTENDEE:mailto:user22 at example.org
+ATTENDEE:mailto:user23 at example.org
+ATTENDEE:mailto:user24 at example.org
+ATTENDEE:mailto:user25 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1 at example.org
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:%(nowFloating_back25)s
+DTSTART:%(nowFloating_back25)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1 at example.org
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:%(nowFloating_back24)s
+DTSTART:%(nowFloating_back24)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1 at example.org
+END:VEVENT
+END:VCALENDAR
+"""
+
+        data_future = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:%(nowFloating_back14)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+ATTENDEE:mailto:user3 at example.org
+ATTENDEE:mailto:user4 at example.org
+ATTENDEE:mailto:user5 at example.org
+ATTENDEE:mailto:user6 at example.org
+ATTENDEE:mailto:user7 at example.org
+ATTENDEE:mailto:user8 at example.org
+ATTENDEE:mailto:user9 at example.org
+ATTENDEE:mailto:user10 at example.org
+ATTENDEE:mailto:user11 at example.org
+ATTENDEE:mailto:user12 at example.org
+ATTENDEE:mailto:user13 at example.org
+ATTENDEE:mailto:user14 at example.org
+ATTENDEE:mailto:user15 at example.org
+ATTENDEE:mailto:user16 at example.org
+ATTENDEE:mailto:user17 at example.org
+ATTENDEE:mailto:user18 at example.org
+ATTENDEE:mailto:user19 at example.org
+ATTENDEE:mailto:user20 at example.org
+ATTENDEE:mailto:user21 at example.org
+ATTENDEE:mailto:user22 at example.org
+ATTENDEE:mailto:user23 at example.org
+ATTENDEE:mailto:user24 at example.org
+ATTENDEE:mailto:user25 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1 at example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+RRULE:FREQ=DAILY
+SEQUENCE:1
+END:VEVENT
+END:VCALENDAR
+"""
+
+        data_past = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:%(uid)s
+DTSTART:%(nowFloating_back30)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+ATTENDEE:mailto:user3 at example.org
+ATTENDEE:mailto:user4 at example.org
+ATTENDEE:mailto:user5 at example.org
+ATTENDEE:mailto:user6 at example.org
+ATTENDEE:mailto:user7 at example.org
+ATTENDEE:mailto:user8 at example.org
+ATTENDEE:mailto:user9 at example.org
+ATTENDEE:mailto:user10 at example.org
+ATTENDEE:mailto:user11 at example.org
+ATTENDEE:mailto:user12 at example.org
+ATTENDEE:mailto:user13 at example.org
+ATTENDEE:mailto:user14 at example.org
+ATTENDEE:mailto:user15 at example.org
+ATTENDEE:mailto:user16 at example.org
+ATTENDEE:mailto:user17 at example.org
+ATTENDEE:mailto:user18 at example.org
+ATTENDEE:mailto:user19 at example.org
+ATTENDEE:mailto:user20 at example.org
+ATTENDEE:mailto:user21 at example.org
+ATTENDEE:mailto:user22 at example.org
+ATTENDEE:mailto:user23 at example.org
+ATTENDEE:mailto:user24 at example.org
+ATTENDEE:mailto:user25 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1 at example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+RRULE:FREQ=DAILY;UNTIL=%(nowFloating_back14_1)s
+SEQUENCE:1
+END:VEVENT
+BEGIN:VEVENT
+UID:%(uid)s
+RECURRENCE-ID:%(nowFloating_back25)s
+DTSTART:%(nowFloating_back25)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1 at example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+SEQUENCE:1
+END:VEVENT
+BEGIN:VEVENT
+UID:%(uid)s
+RECURRENCE-ID:%(nowFloating_back24)s
+DTSTART:%(nowFloating_back24)s
+DURATION:P1D
+ATTENDEE:mailto:user1 at example.org
+ATTENDEE:mailto:user2 at example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1 at example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+SEQUENCE:1
+END:VEVENT
+END:VCALENDAR
+"""
+
+        component = Component.fromString(data % self.subs)
+        cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
+        self.assertFalse(hasattr(cobj, "_workItems"))
+        yield self.commit()
+
+        w = schema.CALENDAR_OBJECT_SPLITTER_WORK
+        rows = yield Select(
+            [w.RESOURCE_ID, ],
+            From=w
+        ).on(self.transactionUnderTest())
+        self.assertEqual(len(rows), 0)
+        yield self.abort()
+
+        # Do manual split
+        cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
+        will = yield cobj.willSplit()
+        self.assertTrue(will)
+
+        yield cobj.split()
+        yield self.commit()
+
+        ical_future, ical_past, pastUID, relID, _ignore_new_name = yield self._splitDetails("user01")
+
+        title = "temp"
+        relsubs = dict(self.subs)
+        relsubs["uid"] = pastUID
+        relsubs["relID"] = relID
+        self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s %s" % (title, diff_iCalStrs(ical_future, data_future % relsubs)))
+        self.assertEqual(normalize_iCalStr(ical_past), normalize_iCalStr(data_past) % relsubs, "Failed past: %s %s" % (title, diff_iCalStrs(ical_past, data_past % relsubs)))
+
+
+    @inlineCallbacks
     def test_calendarObjectSplit_work(self):
         """
         Test that splitting of calendar objects works.
@@ -7649,7 +8102,54 @@
         yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.subs), pastUID="12345-67890-existing"), InvalidSplit)
 
 
+    @inlineCallbacks
+    def test_calendarObjectSplit_splitat_wrong_value_type(self):
+        """
+        Test that user triggered splitting of calendar objects does not work if wrong rid value type is used.
+        """
 
+        yield self._setupSplitAt()
+
+        # DTSTART DATE-TIME UTC/rid DATE
+        cal = yield self.calendarUnderTest(name="calendar", home="user02")
+        cobjs = yield cal.calendarObjects()
+        self.assertEqual(len(cobjs), 1)
+        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(nowDate)s" % self.subs)), InvalidSplit)
+
+        # DTSTART DATE-TIME UTC/rid DATE-TIME floating
+        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(nowFloating)s" % self.subs)), InvalidSplit)
+
+        data_floating = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-existing
+DTSTART:%(nowFloating)s
+DURATION:P1D
+DTSTAMP:20051222T210507Z
+RRULE:FREQ=DAILY;COUNT=50
+SUMMARY:1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+END:VEVENT
+END:VCALENDAR
+"""
+
+        calendar = yield self.calendarUnderTest(name="calendar", home="user01")
+        component = Component.fromString(data_floating % self.subs)
+        yield calendar.createCalendarObjectWithName("data2.ics", component)
+        yield self.commit()
+
+        # DTSTART DATE/rid DATE-TIME floating
+        cobj = yield self.calendarObjectUnderTest(name="data2.ics", calendar_name="calendar", home="user01")
+        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(nowFloating)s" % self.subs)), InvalidSplit)
+
+        # DTSTART DATE/rid DATE-TIME UTC
+        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(now)s" % self.subs)), InvalidSplit)
+
+
+
 class TimeRangeUpdateOptimization(CommonCommonTests, unittest.TestCase):
     """
     CalendarObject time range optimization tests.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20150629/4324b965/attachment-0001.html>


More information about the calendarserver-changes mailing list