Skip to content

Commit

Permalink
[IMP] File object methods : get_tags, add_tag, remove_tag ; Tag objec…
Browse files Browse the repository at this point in the history
…t methods : get_related_files
  • Loading branch information
luffah committed May 5, 2021
1 parent d54f795 commit 7cc2e47
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 24 deletions.
149 changes: 133 additions & 16 deletions src/nextcloud/api_wrappers/systemtags.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from nextcloud.base import WebDAVApiWrapper
from nextcloud.common.collections import PropertySet
from nextcloud.common.properties import Property as Prop
from nextcloud.api_wrappers import webdav


class Tag(PropertySet):
Expand All @@ -19,18 +20,111 @@ class Tag(PropertySet):
Prop('oc:user-assignable', json='userAssignable', default=True)
]

def __repr__(self):
add_info = (' %s' % repr(self.display_name)) if hasattr(
self, 'display_name') else ''
return super(Tag, self).__repr__(add_info=add_info)

def get_related_files(self, path=''):
"""
Get files related to current tag
:param path: (optionnal) a path to search in
"""
_id = int(self.id)
ret = self._wrapper.client.fetch_files_with_filter(
path=path,
filter_rules={'oc': {'systemtag': _id}}
)
return ret.data or []


class File(webdav.File):

def _get_file_kwargs(self):
kwargs = {}
if not getattr(self, 'file_id', False):
kwargs['path'] = self._get_remote_path()
else:
kwargs['file_id'] = self.file_id
return kwargs

def get_tags(self):
"""
Get tags related to current file
:returns : list<Tag>
"""
kwargs = self._get_file_kwargs()
return self._wrapper.client.get_systemtags_relation(**kwargs)

def add_tag(self, **kwargs):
"""
Assign tag to the current file
:param tag_id: tag id
:param tag_name: tag name (if tag_id in not provided)
:returns : False if failure
"""
kwargs.update(self._get_file_kwargs())
resp = self._wrapper.client.add_systemtags_relation(**kwargs)
return resp.is_ok

def remove_tag(self, **kwargs):
"""
Unassign tag to the current file
:param tag_id: tag id
:param tag_name: tag name (if tag_id in not provided)
:returns : False if failure
"""
kwargs.update(self._get_file_kwargs())
resp = self._wrapper.client.remove_systemtags_relation(**kwargs)
return resp.is_ok


webdav.File = File

class SystemTags(WebDAVApiWrapper):
""" SystemTags API wrapper """
API_URL = '/remote.php/dav/systemtags'

def get_sytemtag(self, name, fields=None, json_output=None):
@classmethod
def _get_tags_from_response(cls, ret, one=False):
if ret.data:
ret = ret.data
if ret[0].href.endswith('/'):
ret = ret[1:]
else:
ret = []
if one:
return ret[0] if ret else None
return ret

def get_systemtags(self):
"""
Get list of all tags
:returns: list<Tag>
"""
return self._get_tags_from_response(
self.fetch_systemtags(json_output=False)
)

def get_systemtag(self, name):
"""
Return a nammed tag
:returns: Tag
"""
return self._get_tags_from_response(
self.fetch_sytemtag(name, json_output=False),
one=True
)

def fetch_sytemtag(self, name, fields=None, json_output=None):
"""
Get attributes of a nammed tag
:param name (str): tag name
:param fields (<list>str): field names
:returns: requester response with <list>Tag in data
:returns: requester response with list<Tag> in data
"""
if not fields:
fields = Tag._fields
Expand All @@ -40,21 +134,24 @@ def get_sytemtag(self, name, fields=None, json_output=None):
}))
if json_output is None:
json_output = self.json_output
return Tag.from_response(resp,
return Tag.from_response(resp, wrapper=self,
json_output=json_output,
init_attrs=True,
filtered=lambda t: t.display_name == name)

def get_systemtags(self):
def fetch_systemtags(self, json_output=None):
"""
Get list of all tags
List of all tags
:returns: requester response with <list>Tag in data
:returns: requester response with list<Tag> in data
"""
resp = self.requester.propfind(
data=Tag.build_xml_propfind(use_default=True)
)
return Tag.from_response(resp, json_output=self.json_output)
if json_output is None:
json_output = self.json_output
return Tag.from_response(resp, wrapper=self,
json_output=json_output)

def create_systemtag(self, name, **kwargs):
"""
Expand Down Expand Up @@ -100,13 +197,13 @@ class SystemTagsRelation(WebDAVApiWrapper):
def _get_fileid_from_path(self, path):
""" Tricky function to fetch file """
resp = self.client.get_file_property(path, 'fileid')
id_ = None
_id = None
if resp.data:
id_ = int(resp.data)
return id_
_id = int(resp.data)
return _id

def _get_systemtag_id_from_name(self, name):
resp = self.client.get_sytemtag(name, ['id'], json_output=False)
resp = self.client.fetch_sytemtag(name, ['id'], json_output=False)
tag_id = None
if resp.data:
tag_id = int(resp.data[0].id)
Expand All @@ -131,13 +228,31 @@ def get_systemtags_relation(self, file_id=None, **kwargs):
:param file_id (int): file id found from file object
:param path (str): if no file_id provided, path to file/folder
:returns: requester response with <list>Tag in data
:returns: requester response with list<Tag> in data
"""
return SystemTags._get_tags_from_response(
self.fetch_systemtags_relation(file_id=file_id,
json_output=False, **kwargs)
)

def fetch_systemtags_relation(self, file_id=None, json_output=None, **kwargs):
"""
Get all tags from a given file/folder
:param file_id (int): file id found from file object
:param path (str): if no file_id provided, path to file/folder
:returns: requester response with list<Tag> in data
"""
file_id, = self._arguments_get(['file_id'], dict(file_id=file_id,
**kwargs))
data = Tag.build_xml_propfind()
data = Tag.build_xml_propfind(use_default=True)
resp = self.requester.propfind(additional_url=file_id, data=data)
return Tag.from_response(resp, json_output=(self.json_output))
return Tag.from_response(resp,
json_output=(
self.json_output if
json_output is None else json_output)
)

def remove_systemtags_relation(self, file_id=None, tag_id=None, **kwargs):
"""
Expand All @@ -155,7 +270,8 @@ def remove_systemtags_relation(self, file_id=None, tag_id=None, **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))
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 @@ -175,7 +291,8 @@ def add_systemtags_relation(self, file_id=None, tag_id=None, **kwargs):
if not file_id:
raise ValueError('No file found')
if not tag_id:
data = Tag.default_get(display_name=kwargs.get('tag_name'), **kwargs)
data = Tag.default_get(
display_name=kwargs.get('tag_name'), **kwargs)
resp = self.requester.post(
url=file_id,
data=json.dumps(data),
Expand Down
14 changes: 7 additions & 7 deletions src/nextcloud/api_wrappers/webdav.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def _extract_resource_type(file_property):
Prop('d:getlastmodified'),
Prop('d:getetag'),
Prop('d:getcontenttype'),
Prop('d:resourcetype', parse_xml_value=File._extract_resource_type),
Prop('d:resourcetype', parse_xml_value=(lambda p: File._extract_resource_type(p))),
Prop('d:getcontentlength'),
Prop('oc:id'),
Prop('oc:fileid'),
Expand Down Expand Up @@ -127,7 +127,7 @@ def list(self, subpath='', filter_rules=None):
:returns: list of Files
"""
if filter_rules:
resp = self._wrapper.list_files_with_filter(
resp = self._wrapper.fetch_files_with_filter(
path=self._get_remote_path(subpath),
filter_rules=filter_rules
)
Expand Down Expand Up @@ -387,7 +387,7 @@ def set_file_property(self, path, update_rules):
update_rules : a dict { namespace: {key : value } }
Returns:
requester response with <list>File in data
requester response with list<File> in data
Note :
check keys in nextcloud.common.properties.NAMESPACES_MAP for namespace codes
Expand All @@ -396,7 +396,7 @@ def set_file_property(self, path, update_rules):
data = File.build_xml_propupdate(update_rules)
return self.requester.proppatch(additional_url=self._get_path(path), data=data)

def list_files_with_filter(self, path='', filter_rules=''):
def fetch_files_with_filter(self, path='', filter_rules=''):
"""
List files according to a filter
Expand All @@ -405,7 +405,7 @@ def list_files_with_filter(self, path='', filter_rules=''):
filter_rules : a dict { namespace: {key : value } }
Returns:
requester response with <list>File in data
requester response with list<File> in data
Note :
check keys in nextcloud.common.properties.NAMESPACES_MAP for namespace codes
Expand Down Expand Up @@ -438,9 +438,9 @@ def list_favorites(self, path=''):
path (str): file or folder path to search favorite
Returns:
requester response with <list>File in data
requester response with list<File> in data
"""
return self.list_files_with_filter(path, {'oc': {'favorite': 1}})
return self.fetch_files_with_filter(path, {'oc': {'favorite': 1}})

def get_file_property(self, path, field, ns='oc'):
"""
Expand Down
8 changes: 7 additions & 1 deletion src/nextcloud/common/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ def _fetch_property(cls, key, attr='xml_key'):
if getattr(k, attr) == key:
return k

def __repr__(self, add_info=''):
return "<%s %s%s>" % (self.__class__.__name__, self.href, add_info)

def __init__(self, xml_data, init_attrs=False, wrapper=None):
if init_attrs:
for attr in self._attrs:
Expand Down Expand Up @@ -101,7 +104,10 @@ def from_response(cls, resp, json_output=None, filtered=None,
if filtered:
if callable(filtered):
attr_datas = [
attr_data for attr_data in attr_datas if filtered(attr_data)]
attr_data
for attr_data in attr_datas
if filtered(attr_data)
]
resp.data = attr_datas if not json_output else [
attr_data.as_dict() for attr_data in attr_datas]
return resp
Expand Down

0 comments on commit 7cc2e47

Please sign in to comment.