77import os
88try :
99 import pathlib
10- except :
10+ except ImportError :
1111 import pathlib2 as pathlib
1212
1313import xml .etree .ElementTree as ET
@@ -32,7 +32,7 @@ class File(PropertySet):
3232 Additionnally, provide an objective CRUD API
3333 (that probably consume more energy than fetching specific attributes)
3434
35- Example :
35+ Example :
3636 >>> root = nxc.get_folder() # get root
3737 >>> def _list_rec(d, indent=""):
3838 >>> # list files recursively
@@ -43,12 +43,19 @@ class File(PropertySet):
4343 >>>
4444 >>> _list_rec(root)
4545 """
46+
47+ @staticmethod
48+ def _extract_resource_type (file_property ):
49+ file_type = list (file_property )
50+ if file_type :
51+ return re .sub ('{.*}' , '' , file_type [0 ].tag )
52+ return None
53+
4654 _attrs = [
4755 Prop ('d:getlastmodified' ),
4856 Prop ('d:getetag' ),
4957 Prop ('d:getcontenttype' ),
50- Prop ('d:resourcetype' , parse_xml_value = (
51- lambda p : File ._extract_resource_type (p ))),
58+ Prop ('d:resourcetype' , parse_xml_value = File ._extract_resource_type ),
5259 Prop ('d:getcontentlength' ),
5360 Prop ('oc:id' ),
5461 Prop ('oc:fileid' ),
@@ -65,13 +72,6 @@ class File(PropertySet):
6572 Prop ('nc:has-preview' )
6673 ]
6774
68- @staticmethod
69- def _extract_resource_type (file_property ):
70- file_type = list (file_property )
71- if file_type :
72- return re .sub ('{.*}' , '' , file_type [0 ].tag )
73- return None
74-
7575 def isfile (self ):
7676 """ say if the file is a file /!\\ ressourcetype property shall be loaded """
7777 return not self .resource_type
@@ -105,32 +105,38 @@ def __eq__(self, b):
105105 def get_folder (self , path = None ):
106106 """
107107 Get folder (see WebDav wrapper)
108- :param subpath : if empty list current dir
108+ :param path : if empty list current dir
109109 :returns: a folder (File object)
110110
111111 Note : To check if sub folder exists, use get_file method
112112 """
113113 return self ._wrapper .get_folder (self ._get_remote_path (path ))
114114
115- def get_folder (self , path = None ):
115+ def get_file (self , path = None ):
116116 """
117- Get folder (see WebDav wrapper)
118- :param subpath : if empty list current dir
117+ Get file (see WebDav wrapper)
118+ :param path : if empty list current dir
119119 :returns: a file or folder (File object)
120120 """
121121 return self ._wrapper .get_file (self ._get_remote_path (path ))
122122
123- def list (self , subpath = '' ):
123+ def list (self , subpath = '' , filter_rules = None ):
124124 """
125125 List folder (see WebDav wrapper)
126126 :param subpath: if empty list current dir
127127 :returns: list of Files
128128 """
129- resp = self ._wrapper .list_folders (
130- self ._get_remote_path (subpath ),
131- depth = 1 ,
132- all_properties = True
133- )
129+ if filter_rules :
130+ resp = self ._wrapper .list_files_with_filter (
131+ path = self ._get_remote_path (subpath ),
132+ filter_rules = filter_rules
133+ )
134+ else :
135+ resp = self ._wrapper .list_folders (
136+ self ._get_remote_path (subpath ),
137+ depth = 1 ,
138+ all_properties = True
139+ )
134140 if resp .is_ok and resp .data :
135141 _dirs = resp .data
136142 # remove current dir
@@ -146,8 +152,8 @@ def upload_file(self, local_filepath, name, timestamp=None):
146152 :returns: True if success
147153 """
148154 resp = self ._wrapper .upload_file (local_filepath ,
149- self ._get_remote_path (name ),
150- timestamp = timestamp )
155+ self ._get_remote_path (name ),
156+ timestamp = timestamp )
151157 return resp .is_ok
152158
153159 def download (self , name = None , target_dir = None ):
@@ -158,7 +164,7 @@ def download(self, name=None, target_dir=None):
158164 """
159165 path = self ._get_remote_path (name )
160166 target_path , _file_info = self ._wrapper .download_file (path ,
161- target_dir = target_dir )
167+ target_dir = target_dir )
162168 assert os .path .isfile (target_path ), "Download failed"
163169 return target_path
164170
@@ -179,8 +185,7 @@ class WebDAV(WebDAVApiWrapper):
179185 def _get_path (self , path ):
180186 if path :
181187 return '/' .join ([self .client .user , path ]).replace ('//' , '/' )
182- else :
183- return self .client .user
188+ return self .client .user
184189
185190 def list_folders (self , path = None , depth = 1 , all_properties = False ,
186191 fields = None ):
@@ -227,7 +232,7 @@ def download_file(self, path, target_dir=None):
227232 a tuple (target_path, File object)
228233 """
229234 if not target_dir :
230- target_dir = './'
235+ target_dir = './'
231236 filename = path .split ('/' )[(- 1 )] if '/' in path else path
232237 file_data = self .get_file (path )
233238 if not file_data :
@@ -373,37 +378,71 @@ def copy_path(self, path, destination_path, overwrite=False):
373378 destination_path ),
374379 overwrite = overwrite )
375380
376- def set_favorites (self , path ):
381+ def set_file_property (self , path , update_rules ):
377382 """
378- Set files of a user favorite
383+ Set file property
379384
380385 Args:
381386 path (str): file or folder path to make favorite
387+ update_rules : a dict { namespace: {key : value } }
382388
383389 Returns:
384- requester response
390+ requester response with <list>File in data
391+
392+ Note :
393+ check keys in nextcloud.common.properties.NAMESPACES_MAP for namespace codes
394+ check object property xml_name for property name
385395 """
386- data = File .build_xml_propupdate ({ 'oc' : { 'favorite' : 1 }} )
396+ data = File .build_xml_propupdate (update_rules )
387397 return self .requester .proppatch (additional_url = self ._get_path (path ), data = data )
388398
389- def list_favorites (self , path = '' ):
399+ def list_files_with_filter (self , path = '' , filter_rules = '' ):
390400 """
391- List favorites ( files) of the user
401+ List files according to a filter
392402
393403 Args:
394- path (str): file or folder path to make favorite
404+ path (str): file or folder path to search
405+ filter_rules : a dict { namespace: {key : value } }
395406
396407 Returns:
397408 requester response with <list>File in data
409+
410+ Note :
411+ check keys in nextcloud.common.properties.NAMESPACES_MAP for namespace codes
412+ check object property xml_name for property name
398413 """
399414 data = File .build_xml_propfind (
400- instr = 'oc:filter-files' , filter_rules = { 'oc' : { 'favorite' : 1 }} )
415+ instr = 'oc:filter-files' , filter_rules = filter_rules )
401416 resp = self .requester .report (
402417 additional_url = self ._get_path (path ), data = data )
403418 return File .from_response (resp , json_output = self .json_output ,
404419 wrapper = self )
405420
406- def get_file_property (self , path , field , tag = 'oc' ):
421+ def set_favorites (self , path ):
422+ """
423+ Set files of a user favorite
424+
425+ Args:
426+ path (str): file or folder path to make favorite
427+
428+ Returns:
429+ requester response
430+ """
431+ return self .set_file_property (path , {'oc' : {'favorite' : 1 }})
432+
433+ def list_favorites (self , path = '' ):
434+ """
435+ List favorites (files) of the user
436+
437+ Args:
438+ path (str): file or folder path to search favorite
439+
440+ Returns:
441+ requester response with <list>File in data
442+ """
443+ return self .list_files_with_filter (path , {'oc' : {'favorite' : 1 }})
444+
445+ def get_file_property (self , path , field , ns = 'oc' ):
407446 """
408447 Fetch asked properties from a file path.
409448
@@ -415,9 +454,9 @@ def get_file_property(self, path, field, tag='oc'):
415454 requester response with asked value in data
416455 """
417456 if ':' in field :
418- tag , field = field .split (':' )
419- get_file_prop_xpath = '{DAV:}propstat/d:prop/%s:%s' % (tag , field )
420- data = File .build_xml_propfind (fields = {tag : [field ]})
457+ ns , field = field .split (':' )
458+ get_file_prop_xpath = '{DAV:}propstat/d:prop/%s:%s' % (ns , field )
459+ data = File .build_xml_propfind (fields = {ns : [field ]})
421460 resp = self .requester .propfind (additional_url = (self ._get_path (path )), headers = {'Depth' : str (0 )},
422461 data = data )
423462 response_data = resp .data
0 commit comments