Просмотр исходного кода

start creating test for rrule expand property, fix expand processing

Georgiy 1 год назад
Родитель
Сommit
513415d201
3 измененных файлов с 105 добавлено и 20 удалено
  1. 34 20
      radicale/app/report.py
  2. 28 0
      radicale/tests/static/event_daily_rrule.ics
  3. 43 0
      radicale/tests/test_base.py

+ 34 - 20
radicale/app/report.py

@@ -172,9 +172,9 @@ def xml_report(base_prefix: str, path: str, xml_request: Optional[ET.Element],
                         end, '%Y%m%dT%H%M%SZ'
                     ).replace(tzinfo=datetime.timezone.utc)
 
-                    expanded_elements = _expand(
+                    expanded_element = _expand(
                         element, copy.copy(item), start, end)
-                    found_props.extend(expanded_elements)
+                    found_props.append(expanded_element)
                 else:
                     found_props.append(element)
             else:
@@ -195,34 +195,46 @@ def _expand(
         item: radicale_item.Item,
         start: datetime.datetime,
         end: datetime.datetime,
-) -> List[ET.Element]:
+) -> ET.Element:
+    rruleset = None
+    if hasattr(item.vobject_item.vevent, 'rrule'):
+        rruleset = item.vobject_item.vevent.getrruleset()
+
     expanded_item = _make_vobject_expanded_item(item)
-    element.text = expanded_item.vobject_item.serialize()
-    expanded = [element]
 
-    if hasattr(item.vobject_item.vevent, "rrule"):
-        rulleset = item.vobject_item.vevent.getrruleset()
-        recurrences = rulleset.between(start, end)
+    if rruleset:
+        recurrences = rruleset.between(start, end)
 
-        expanded = []
+        expanded = None
         for recurrence_dt in recurrences:
+            expanded_item_ = copy.copy(expanded_item)
+
             try:
-                delattr(expanded_item.vobject_item.vevent, 'recurrence-id')
+                delattr(expanded_item_.vobject_item.vevent, 'recurrence-id')
             except AttributeError:
                 pass
 
             recurrence_utc = recurrence_dt.astimezone(datetime.timezone.utc)
 
-            expanded_item.vobject_item.vevent.recurrence_id = ContentLine(
+            vevent = copy.deepcopy(expanded_item_.vobject_item.vevent)
+            recurrence_id = ContentLine(
                 name='RECURRENCE-ID',
                 value=recurrence_utc.strftime('%Y%m%dT%H%M%SZ'), params={}
             )
+            vevent.add(recurrence_id)
 
-            element = copy.copy(element)
-            element.text = expanded_item.vobject_item.serialize()
-            expanded.append(element)
+            if expanded is None:
+                expanded_item_.vobject_item.vevent.add(recurrence_id)
+                expanded_item_.vobject_item.remove(expanded_item_.vobject_item.vevent)
+                expanded = expanded_item_
+            else:
+                expanded.vobject_item.add(vevent)
 
-    return expanded
+        element.text = expanded.vobject_item.serialize()
+    else:
+        element.text = expanded_item.vobject_item.serialize()
+
+    return element
 
 
 def _make_vobject_expanded_item(
@@ -239,14 +251,16 @@ def _make_vobject_expanded_item(
     vevent = item.vobject_item.vevent
 
     start_utc = vevent.dtstart.value.astimezone(datetime.timezone.utc)
-    end_utc = vevent.dtend.value.astimezone(datetime.timezone.utc)
-
     vevent.dtstart = ContentLine(
         name='DTSTART',
         value=start_utc.strftime('%Y%m%dT%H%M%SZ'), params={})
-    vevent.dtend = ContentLine(
-        name='DTEND',
-        value=end_utc.strftime('%Y%m%dT%H%M%SZ'), params={})
+
+    dt_end = getattr(vevent, 'dtend', None)
+    if dt_end is not None:
+        end_utc = dt_end.value.astimezone(datetime.timezone.utc)
+        vevent.dtend = ContentLine(
+            name='DTEND',
+            value=end_utc.strftime('%Y%m%dT%H%M%SZ'), params={})
 
     timezones_to_remove = []
     for component in item.vobject_item.components():

+ 28 - 0
radicale/tests/static/event_daily_rrule.ics

@@ -0,0 +1,28 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+BEGIN:VTIMEZONE
+LAST-MODIFIED:20040110T032845Z
+TZID:US/Eastern
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART;TZID=US/Eastern:20060102T120000
+DURATION:PT1H
+RRULE:FREQ=DAILY;COUNT=5
+SUMMARY:Recurring event
+UID:event_daily_rrule
+END:VEVENT
+END:VCALENDAR

+ 43 - 0
radicale/tests/test_base.py

@@ -1525,6 +1525,49 @@ permissions: RrWw""")
             calendar_path, "http://radicale.org/ns/sync/INVALID")
         assert not sync_token
 
+    def test_report_with_expand_property(self) -> None:
+        self.put("/calendar.ics/", get_file_content("event_daily_rrule.ics"))
+
+        req_body = \
+            """<?xml version="1.0" encoding="utf-8" ?>
+            <C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
+                <D:prop>
+                    <C:calendar-data>
+                        <C:expand start="20060103T000000Z" end="20060105T000000Z"/>
+                    </C:calendar-data>
+                </D:prop>
+                <C:filter>
+                    <C:comp-filter name="VCALENDAR">
+                        <C:comp-filter name="VEVENT">
+                            <C:time-range start="20060103T000000Z" end="20060105T000000Z"/>
+                        </C:comp-filter>
+                    </C:comp-filter>
+                </C:filter>
+            </C:calendar-query>
+            """
+
+        # status, _, answer = self.request("REPORT", "/calendar.ics/", req_body, check=207)
+        # print(status, answer)
+
+        _, responses = self.report("/calendar.ics/", req_body)
+        assert len(responses) == 1
+        response = responses['/calendar.ics/event_daily_rrule.ics']
+        status, element = list(response.values())[0]
+        assert status == 200
+
+        print("resp", status, element, flush=True)
+
+        uids = []
+        for line in element.text.split("\n"):
+            print("line", line, line.startswith("UID:"))
+            if line.startswith("UID:"):
+                uid = line[len("UID:"):]
+                assert uid == "event_daily_rrule"
+                uids.append(uids)
+
+        assert len(uids) == 3
+        assert False
+
     def test_propfind_sync_token(self) -> None:
         """Retrieve the sync-token with a propfind request"""
         calendar_path = "/calendar.ics/"