10
10
from httpx import Response
11
11
12
12
from .._exceptions import NextcloudException , check_error
13
- from .._misc import clear_from_params_empty
13
+ from .._misc import check_capabilities , clear_from_params_empty
14
14
from . import FsNode , SystemTag
15
15
16
16
PROPFIND_PROPERTIES = [
29
29
"oc:share-types" ,
30
30
"oc:favorite" ,
31
31
"nc:is-encrypted" ,
32
+ ]
33
+
34
+ PROPFIND_LOCKING_PROPERTIES = [
32
35
"nc:lock" ,
33
36
"nc:lock-owner-displayname" ,
34
37
"nc:lock-owner" ,
35
38
"nc:lock-owner-type" ,
36
- "nc:lock-owner-editor" ,
37
- "nc:lock-time" ,
38
- "nc:lock-timeout" ,
39
+ "nc:lock-owner-editor" , # App id of an app owned lock
40
+ "nc:lock-time" , # Timestamp of the log creation time
41
+ "nc:lock-timeout" , # TTL of the lock in seconds staring from the creation time
39
42
]
40
43
41
44
SEARCH_PROPERTIES_MAP = {
@@ -57,15 +60,22 @@ class PropFindType(enum.IntEnum):
57
60
VERSIONS_FILE_ID = 3
58
61
59
62
60
- def build_find_request (req : list , path : str | FsNode , user : str ) -> ElementTree .Element :
63
+ def get_propfind_properties (capabilities : dict ) -> list :
64
+ r = PROPFIND_PROPERTIES
65
+ if not check_capabilities ("files.locking" , capabilities ):
66
+ r += PROPFIND_LOCKING_PROPERTIES
67
+ return r
68
+
69
+
70
+ def build_find_request (req : list , path : str | FsNode , user : str , capabilities : dict ) -> ElementTree .Element :
61
71
path = path .user_path if isinstance (path , FsNode ) else path
62
72
root = ElementTree .Element (
63
73
"d:searchrequest" ,
64
74
attrib = {"xmlns:d" : "DAV:" , "xmlns:oc" : "http://owncloud.org/ns" , "xmlns:nc" : "http://nextcloud.org/ns" },
65
75
)
66
76
xml_search = ElementTree .SubElement (root , "d:basicsearch" )
67
77
xml_select_prop = ElementTree .SubElement (ElementTree .SubElement (xml_search , "d:select" ), "d:prop" )
68
- for i in PROPFIND_PROPERTIES :
78
+ for i in get_propfind_properties ( capabilities ) :
69
79
ElementTree .SubElement (xml_select_prop , i )
70
80
xml_from_scope = ElementTree .SubElement (ElementTree .SubElement (xml_search , "d:from" ), "d:scope" )
71
81
href = f"/files/{ user } /{ path .removeprefix ('/' )} "
@@ -76,15 +86,17 @@ def build_find_request(req: list, path: str | FsNode, user: str) -> ElementTree.
76
86
return root
77
87
78
88
79
- def build_list_by_criteria_req (properties : list [str ] | None , tags : list [int | SystemTag ] | None ) -> ElementTree .Element :
89
+ def build_list_by_criteria_req (
90
+ properties : list [str ] | None , tags : list [int | SystemTag ] | None , capabilities : dict
91
+ ) -> ElementTree .Element :
80
92
if not properties and not tags :
81
93
raise ValueError ("Either specify 'properties' or 'tags' to filter results." )
82
94
root = ElementTree .Element (
83
95
"oc:filter-files" ,
84
96
attrib = {"xmlns:d" : "DAV:" , "xmlns:oc" : "http://owncloud.org/ns" , "xmlns:nc" : "http://nextcloud.org/ns" },
85
97
)
86
98
prop = ElementTree .SubElement (root , "d:prop" )
87
- for i in PROPFIND_PROPERTIES :
99
+ for i in get_propfind_properties ( capabilities ) :
88
100
ElementTree .SubElement (prop , i )
89
101
xml_filter_rules = ElementTree .SubElement (root , "oc:filter-rules" )
90
102
if properties and "favorite" in properties :
@@ -243,7 +255,7 @@ def etag_fileid_from_response(response: Response) -> dict:
243
255
return {"etag" : response .headers .get ("OC-Etag" , "" ), "file_id" : response .headers ["OC-FileId" ]}
244
256
245
257
246
- def _parse_record (full_path : str , prop_stats : list [dict ]) -> FsNode :
258
+ def _parse_record (full_path : str , prop_stats : list [dict ]) -> FsNode : # noqa pylint: disable = too-many-branches
247
259
fs_node_args = {}
248
260
for prop_stat in prop_stats :
249
261
if str (prop_stat .get ("d:status" , "" )).find ("200 OK" ) == - 1 :
@@ -274,7 +286,17 @@ def _parse_record(full_path: str, prop_stats: list[dict]) -> FsNode:
274
286
fs_node_args ["trashbin_original_location" ] = prop ["nc:trashbin-original-location" ]
275
287
if "nc:trashbin-deletion-time" in prop_keys :
276
288
fs_node_args ["trashbin_deletion_time" ] = prop ["nc:trashbin-deletion-time" ]
277
- # xz = prop.get("oc:dDC", "")
289
+ for k , v in {
290
+ "nc:lock" : "is_locked" ,
291
+ "nc:lock-owner-type" : "lock_owner_type" ,
292
+ "nc:lock-owner" : "lock_owner" ,
293
+ "nc:lock-owner-displayname" : "lock_owner_displayname" ,
294
+ "nc:lock-owner-editor" : "lock_owner_editor" ,
295
+ "nc:lock-time" : "lock_time" ,
296
+ "nc:lock-timeout" : "lock_ttl" ,
297
+ }.items ():
298
+ if k in prop_keys and prop [k ] is not None :
299
+ fs_node_args [v ] = prop [k ]
278
300
return FsNode (full_path , ** fs_node_args )
279
301
280
302
0 commit comments