|
1 | 1 | """Helper functions for **FilesAPI** and **AsyncFilesAPI** classes."""
|
2 | 2 |
|
3 | 3 | import enum
|
| 4 | +from datetime import datetime, timezone |
4 | 5 | from io import BytesIO
|
5 | 6 | from json import dumps, loads
|
| 7 | +from typing import Any |
6 | 8 | from urllib.parse import unquote
|
7 | 9 | from xml.etree import ElementTree
|
8 | 10 |
|
@@ -69,6 +71,16 @@ def get_propfind_properties(capabilities: dict) -> list:
|
69 | 71 | return r
|
70 | 72 |
|
71 | 73 |
|
| 74 | +def _dav_literal(val: Any) -> str: |
| 75 | + """Return a string suitable for <d:literal>.""" |
| 76 | + if isinstance(val, datetime): |
| 77 | + # make timezone-aware, force UTC, second precision |
| 78 | + dt = val if val.tzinfo else val.replace(tzinfo=timezone.utc) |
| 79 | + dt = dt.astimezone(timezone.utc).replace(microsecond=0) |
| 80 | + return dt.isoformat().replace("+00:00", "Z") # 2025-03-10T12:34:56Z |
| 81 | + return str(val) |
| 82 | + |
| 83 | + |
72 | 84 | def build_find_request(req: list, path: str | FsNode, user: str, capabilities: dict) -> ElementTree.Element:
|
73 | 85 | path = path.user_path if isinstance(path, FsNode) else path
|
74 | 86 | root = ElementTree.Element(
|
@@ -126,7 +138,7 @@ def _add_value(xml_element, val=None) -> None:
|
126 | 138 | ElementTree.SubElement(_, SEARCH_PROPERTIES_MAP[req.pop(0)])
|
127 | 139 | _ = ElementTree.SubElement(_root, "d:literal")
|
128 | 140 | value = req.pop(0)
|
129 |
| - _.text = value if isinstance(value, str) else str(value) |
| 141 | + _.text = _dav_literal(value) |
130 | 142 |
|
131 | 143 | while len(req):
|
132 | 144 | where_part = req.pop(0)
|
|
0 commit comments