Skip to content

Commit

Permalink
[WIP] systemtags-relation : optimize add_systemtags_relation
Browse files Browse the repository at this point in the history
  • Loading branch information
luffah committed May 5, 2021
1 parent f7cdc46 commit d54f795
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 49 deletions.
28 changes: 18 additions & 10 deletions src/nextcloud/api_wrappers/systemtags.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def create_systemtag(self, name, **kwargs):
:param name: tag name
:returns: requester response with tag id as data
"""
data = Tag.default_get(name=name, **kwargs)
data = Tag.default_get(display_name=name, **kwargs)
resp = self.requester.post(
data=json.dumps(data),
headers={
Expand Down Expand Up @@ -139,9 +139,9 @@ def get_systemtags_relation(self, file_id=None, **kwargs):
resp = self.requester.propfind(additional_url=file_id, data=data)
return Tag.from_response(resp, json_output=(self.json_output))

def delete_systemtags_relation(self, file_id=None, tag_id=None, **kwargs):
def remove_systemtags_relation(self, file_id=None, tag_id=None, **kwargs):
"""
Delete a tag from a given file/folder
Remove a tag from a given file/folder
:param file_id (int): id found in file object
:param tag_id (int): id found in tag object
Expand All @@ -152,6 +152,10 @@ def delete_systemtags_relation(self, file_id=None, tag_id=None, **kwargs):
"""
file_id, tag_id = self._arguments_get([
'file_id', 'tag_id'], dict(file_id=file_id, tag_id=tag_id, **kwargs))
if not file_id:
raise ValueError('No file found')
if not tag_id:
raise ValueError('No tag found (%s)' % kwargs.get('tag_name', None))
resp = self.requester.delete(url=('{}/{}'.format(file_id, tag_id)))
return resp

Expand All @@ -168,13 +172,17 @@ def add_systemtags_relation(self, file_id=None, tag_id=None, **kwargs):
"""
file_id, tag_id = self._arguments_get([
'file_id', 'tag_id'], locals())
if not tag_id:
if 'tag_name' in kwargs:
resp = self.client.create_systemtag(kwargs['tag_name'])
if not resp.is_ok:
return resp
tag_id = resp.data
if not file_id:
raise ValueError('No file found')
resp = self.requester.put(url=('{}/{}'.format(file_id, tag_id)))
if not tag_id:
data = Tag.default_get(display_name=kwargs.get('tag_name'), **kwargs)
resp = self.requester.post(
url=file_id,
data=json.dumps(data),
headers={'Content-Type': 'application/json'})
# resp = self.client.create_systemtag(kwargs['tag_name'])
# if not resp.is_ok:
return resp
# tag_id = resp.data
resp = self.requester.put(url='{}/{}'.format(file_id, tag_id))
return resp
117 changes: 78 additions & 39 deletions src/nextcloud/api_wrappers/webdav.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import os
try:
import pathlib
except:
except ImportError:
import pathlib2 as pathlib

import xml.etree.ElementTree as ET
Expand All @@ -32,7 +32,7 @@ class File(PropertySet):
Additionnally, provide an objective CRUD API
(that probably consume more energy than fetching specific attributes)
Example :
Example :
>>> root = nxc.get_folder() # get root
>>> def _list_rec(d, indent=""):
>>> # list files recursively
Expand All @@ -43,12 +43,19 @@ class File(PropertySet):
>>>
>>> _list_rec(root)
"""

@staticmethod
def _extract_resource_type(file_property):
file_type = list(file_property)
if file_type:
return re.sub('{.*}', '', file_type[0].tag)
return None

_attrs = [
Prop('d:getlastmodified'),
Prop('d:getetag'),
Prop('d:getcontenttype'),
Prop('d:resourcetype', parse_xml_value=(
lambda p: File._extract_resource_type(p))),
Prop('d:resourcetype', parse_xml_value=File._extract_resource_type),
Prop('d:getcontentlength'),
Prop('oc:id'),
Prop('oc:fileid'),
Expand All @@ -65,13 +72,6 @@ class File(PropertySet):
Prop('nc:has-preview')
]

@staticmethod
def _extract_resource_type(file_property):
file_type = list(file_property)
if file_type:
return re.sub('{.*}', '', file_type[0].tag)
return None

def isfile(self):
""" say if the file is a file /!\\ ressourcetype property shall be loaded """
return not self.resource_type
Expand Down Expand Up @@ -105,32 +105,38 @@ def __eq__(self, b):
def get_folder(self, path=None):
"""
Get folder (see WebDav wrapper)
:param subpath: if empty list current dir
:param path: if empty list current dir
:returns: a folder (File object)
Note : To check if sub folder exists, use get_file method
"""
return self._wrapper.get_folder(self._get_remote_path(path))

def get_folder(self, path=None):
def get_file(self, path=None):
"""
Get folder (see WebDav wrapper)
:param subpath: if empty list current dir
Get file (see WebDav wrapper)
:param path: if empty list current dir
:returns: a file or folder (File object)
"""
return self._wrapper.get_file(self._get_remote_path(path))

def list(self, subpath=''):
def list(self, subpath='', filter_rules=None):
"""
List folder (see WebDav wrapper)
:param subpath: if empty list current dir
:returns: list of Files
"""
resp = self._wrapper.list_folders(
self._get_remote_path(subpath),
depth=1,
all_properties=True
)
if filter_rules:
resp = self._wrapper.list_files_with_filter(
path=self._get_remote_path(subpath),
filter_rules=filter_rules
)
else:
resp = self._wrapper.list_folders(
self._get_remote_path(subpath),
depth=1,
all_properties=True
)
if resp.is_ok and resp.data:
_dirs = resp.data
# remove current dir
Expand All @@ -146,8 +152,8 @@ def upload_file(self, local_filepath, name, timestamp=None):
:returns: True if success
"""
resp = self._wrapper.upload_file(local_filepath,
self._get_remote_path(name),
timestamp=timestamp)
self._get_remote_path(name),
timestamp=timestamp)
return resp.is_ok

def download(self, name=None, target_dir=None):
Expand All @@ -158,7 +164,7 @@ def download(self, name=None, target_dir=None):
"""
path = self._get_remote_path(name)
target_path, _file_info = self._wrapper.download_file(path,
target_dir=target_dir)
target_dir=target_dir)
assert os.path.isfile(target_path), "Download failed"
return target_path

Expand All @@ -179,8 +185,7 @@ class WebDAV(WebDAVApiWrapper):
def _get_path(self, path):
if path:
return '/'.join([self.client.user, path]).replace('//', '/')
else:
return self.client.user
return self.client.user

def list_folders(self, path=None, depth=1, all_properties=False,
fields=None):
Expand Down Expand Up @@ -227,7 +232,7 @@ def download_file(self, path, target_dir=None):
a tuple (target_path, File object)
"""
if not target_dir:
target_dir='./'
target_dir = './'
filename = path.split('/')[(-1)] if '/' in path else path
file_data = self.get_file(path)
if not file_data:
Expand Down Expand Up @@ -373,37 +378,71 @@ def copy_path(self, path, destination_path, overwrite=False):
destination_path),
overwrite=overwrite)

def set_favorites(self, path):
def set_file_property(self, path, update_rules):
"""
Set files of a user favorite
Set file property
Args:
path (str): file or folder path to make favorite
update_rules : a dict { namespace: {key : value } }
Returns:
requester response
requester response with <list>File in data
Note :
check keys in nextcloud.common.properties.NAMESPACES_MAP for namespace codes
check object property xml_name for property name
"""
data = File.build_xml_propupdate({'oc': {'favorite': 1}})
data = File.build_xml_propupdate(update_rules)
return self.requester.proppatch(additional_url=self._get_path(path), data=data)

def list_favorites(self, path=''):
def list_files_with_filter(self, path='', filter_rules=''):
"""
List favorites (files) of the user
List files according to a filter
Args:
path (str): file or folder path to make favorite
path (str): file or folder path to search
filter_rules : a dict { namespace: {key : value } }
Returns:
requester response with <list>File in data
Note :
check keys in nextcloud.common.properties.NAMESPACES_MAP for namespace codes
check object property xml_name for property name
"""
data = File.build_xml_propfind(
instr='oc:filter-files', filter_rules={'oc': {'favorite': 1}})
instr='oc:filter-files', filter_rules=filter_rules)
resp = self.requester.report(
additional_url=self._get_path(path), data=data)
return File.from_response(resp, json_output=self.json_output,
wrapper=self)

def get_file_property(self, path, field, tag='oc'):
def set_favorites(self, path):
"""
Set files of a user favorite
Args:
path (str): file or folder path to make favorite
Returns:
requester response
"""
return self.set_file_property(path, {'oc': {'favorite': 1}})

def list_favorites(self, path=''):
"""
List favorites (files) of the user
Args:
path (str): file or folder path to search favorite
Returns:
requester response with <list>File in data
"""
return self.list_files_with_filter(path, {'oc': {'favorite': 1}})

def get_file_property(self, path, field, ns='oc'):
"""
Fetch asked properties from a file path.
Expand All @@ -415,9 +454,9 @@ def get_file_property(self, path, field, tag='oc'):
requester response with asked value in data
"""
if ':' in field:
tag, field = field.split(':')
get_file_prop_xpath = '{DAV:}propstat/d:prop/%s:%s' % (tag, field)
data = File.build_xml_propfind(fields={tag: [field]})
ns, field = field.split(':')
get_file_prop_xpath = '{DAV:}propstat/d:prop/%s:%s' % (ns, field)
data = File.build_xml_propfind(fields={ns: [field]})
resp = self.requester.propfind(additional_url=(self._get_path(path)), headers={'Depth': str(0)},
data=data)
response_data = resp.data
Expand Down
1 change: 1 addition & 0 deletions src/nextcloud/codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class WebDAVCode(enum.IntEnum):
MULTISTATUS = 207
NOT_AUTHENTICATED = 401
ALREADY_EXISTS = 405
CONFLICT = 409
PRECONDITION_FAILED = 412


Expand Down

0 comments on commit d54f795

Please sign in to comment.