Skip to content

Commit 7cc2e47

Browse files
committed
[IMP] File object methods : get_tags, add_tag, remove_tag ; Tag object methods : get_related_files
1 parent d54f795 commit 7cc2e47

File tree

3 files changed

+147
-24
lines changed

3 files changed

+147
-24
lines changed

src/nextcloud/api_wrappers/systemtags.py

Lines changed: 133 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from nextcloud.base import WebDAVApiWrapper
88
from nextcloud.common.collections import PropertySet
99
from nextcloud.common.properties import Property as Prop
10+
from nextcloud.api_wrappers import webdav
1011

1112

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

23+
def __repr__(self):
24+
add_info = (' %s' % repr(self.display_name)) if hasattr(
25+
self, 'display_name') else ''
26+
return super(Tag, self).__repr__(add_info=add_info)
27+
28+
def get_related_files(self, path=''):
29+
"""
30+
Get files related to current tag
31+
:param path: (optionnal) a path to search in
32+
"""
33+
_id = int(self.id)
34+
ret = self._wrapper.client.fetch_files_with_filter(
35+
path=path,
36+
filter_rules={'oc': {'systemtag': _id}}
37+
)
38+
return ret.data or []
39+
40+
41+
class File(webdav.File):
42+
43+
def _get_file_kwargs(self):
44+
kwargs = {}
45+
if not getattr(self, 'file_id', False):
46+
kwargs['path'] = self._get_remote_path()
47+
else:
48+
kwargs['file_id'] = self.file_id
49+
return kwargs
50+
51+
def get_tags(self):
52+
"""
53+
Get tags related to current file
54+
:returns : list<Tag>
55+
"""
56+
kwargs = self._get_file_kwargs()
57+
return self._wrapper.client.get_systemtags_relation(**kwargs)
58+
59+
def add_tag(self, **kwargs):
60+
"""
61+
Assign tag to the current file
62+
:param tag_id: tag id
63+
:param tag_name: tag name (if tag_id in not provided)
64+
:returns : False if failure
65+
"""
66+
kwargs.update(self._get_file_kwargs())
67+
resp = self._wrapper.client.add_systemtags_relation(**kwargs)
68+
return resp.is_ok
69+
70+
def remove_tag(self, **kwargs):
71+
"""
72+
Unassign tag to the current file
73+
:param tag_id: tag id
74+
:param tag_name: tag name (if tag_id in not provided)
75+
:returns : False if failure
76+
"""
77+
kwargs.update(self._get_file_kwargs())
78+
resp = self._wrapper.client.remove_systemtags_relation(**kwargs)
79+
return resp.is_ok
80+
81+
82+
webdav.File = File
2283

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

27-
def get_sytemtag(self, name, fields=None, json_output=None):
88+
@classmethod
89+
def _get_tags_from_response(cls, ret, one=False):
90+
if ret.data:
91+
ret = ret.data
92+
if ret[0].href.endswith('/'):
93+
ret = ret[1:]
94+
else:
95+
ret = []
96+
if one:
97+
return ret[0] if ret else None
98+
return ret
99+
100+
def get_systemtags(self):
101+
"""
102+
Get list of all tags
103+
104+
:returns: list<Tag>
105+
"""
106+
return self._get_tags_from_response(
107+
self.fetch_systemtags(json_output=False)
108+
)
109+
110+
def get_systemtag(self, name):
111+
"""
112+
Return a nammed tag
113+
114+
:returns: Tag
115+
"""
116+
return self._get_tags_from_response(
117+
self.fetch_sytemtag(name, json_output=False),
118+
one=True
119+
)
120+
121+
def fetch_sytemtag(self, name, fields=None, json_output=None):
28122
"""
29123
Get attributes of a nammed tag
30124
31125
:param name (str): tag name
32126
:param fields (<list>str): field names
33-
:returns: requester response with <list>Tag in data
127+
:returns: requester response with list<Tag> in data
34128
"""
35129
if not fields:
36130
fields = Tag._fields
@@ -40,21 +134,24 @@ def get_sytemtag(self, name, fields=None, json_output=None):
40134
}))
41135
if json_output is None:
42136
json_output = self.json_output
43-
return Tag.from_response(resp,
137+
return Tag.from_response(resp, wrapper=self,
44138
json_output=json_output,
45139
init_attrs=True,
46140
filtered=lambda t: t.display_name == name)
47141

48-
def get_systemtags(self):
142+
def fetch_systemtags(self, json_output=None):
49143
"""
50-
Get list of all tags
144+
List of all tags
51145
52-
:returns: requester response with <list>Tag in data
146+
:returns: requester response with list<Tag> in data
53147
"""
54148
resp = self.requester.propfind(
55149
data=Tag.build_xml_propfind(use_default=True)
56150
)
57-
return Tag.from_response(resp, json_output=self.json_output)
151+
if json_output is None:
152+
json_output = self.json_output
153+
return Tag.from_response(resp, wrapper=self,
154+
json_output=json_output)
58155

59156
def create_systemtag(self, name, **kwargs):
60157
"""
@@ -100,13 +197,13 @@ class SystemTagsRelation(WebDAVApiWrapper):
100197
def _get_fileid_from_path(self, path):
101198
""" Tricky function to fetch file """
102199
resp = self.client.get_file_property(path, 'fileid')
103-
id_ = None
200+
_id = None
104201
if resp.data:
105-
id_ = int(resp.data)
106-
return id_
202+
_id = int(resp.data)
203+
return _id
107204

108205
def _get_systemtag_id_from_name(self, name):
109-
resp = self.client.get_sytemtag(name, ['id'], json_output=False)
206+
resp = self.client.fetch_sytemtag(name, ['id'], json_output=False)
110207
tag_id = None
111208
if resp.data:
112209
tag_id = int(resp.data[0].id)
@@ -131,13 +228,31 @@ def get_systemtags_relation(self, file_id=None, **kwargs):
131228
:param file_id (int): file id found from file object
132229
:param path (str): if no file_id provided, path to file/folder
133230
134-
:returns: requester response with <list>Tag in data
231+
:returns: requester response with list<Tag> in data
232+
"""
233+
return SystemTags._get_tags_from_response(
234+
self.fetch_systemtags_relation(file_id=file_id,
235+
json_output=False, **kwargs)
236+
)
237+
238+
def fetch_systemtags_relation(self, file_id=None, json_output=None, **kwargs):
239+
"""
240+
Get all tags from a given file/folder
241+
242+
:param file_id (int): file id found from file object
243+
:param path (str): if no file_id provided, path to file/folder
244+
245+
:returns: requester response with list<Tag> in data
135246
"""
136247
file_id, = self._arguments_get(['file_id'], dict(file_id=file_id,
137248
**kwargs))
138-
data = Tag.build_xml_propfind()
249+
data = Tag.build_xml_propfind(use_default=True)
139250
resp = self.requester.propfind(additional_url=file_id, data=data)
140-
return Tag.from_response(resp, json_output=(self.json_output))
251+
return Tag.from_response(resp,
252+
json_output=(
253+
self.json_output if
254+
json_output is None else json_output)
255+
)
141256

142257
def remove_systemtags_relation(self, file_id=None, tag_id=None, **kwargs):
143258
"""
@@ -155,7 +270,8 @@ def remove_systemtags_relation(self, file_id=None, tag_id=None, **kwargs):
155270
if not file_id:
156271
raise ValueError('No file found')
157272
if not tag_id:
158-
raise ValueError('No tag found (%s)' % kwargs.get('tag_name', None))
273+
raise ValueError('No tag found (%s)' %
274+
kwargs.get('tag_name', None))
159275
resp = self.requester.delete(url=('{}/{}'.format(file_id, tag_id)))
160276
return resp
161277

@@ -175,7 +291,8 @@ def add_systemtags_relation(self, file_id=None, tag_id=None, **kwargs):
175291
if not file_id:
176292
raise ValueError('No file found')
177293
if not tag_id:
178-
data = Tag.default_get(display_name=kwargs.get('tag_name'), **kwargs)
294+
data = Tag.default_get(
295+
display_name=kwargs.get('tag_name'), **kwargs)
179296
resp = self.requester.post(
180297
url=file_id,
181298
data=json.dumps(data),

src/nextcloud/api_wrappers/webdav.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def _extract_resource_type(file_property):
5555
Prop('d:getlastmodified'),
5656
Prop('d:getetag'),
5757
Prop('d:getcontenttype'),
58-
Prop('d:resourcetype', parse_xml_value=File._extract_resource_type),
58+
Prop('d:resourcetype', parse_xml_value=(lambda p: File._extract_resource_type(p))),
5959
Prop('d:getcontentlength'),
6060
Prop('oc:id'),
6161
Prop('oc:fileid'),
@@ -127,7 +127,7 @@ def list(self, subpath='', filter_rules=None):
127127
:returns: list of Files
128128
"""
129129
if filter_rules:
130-
resp = self._wrapper.list_files_with_filter(
130+
resp = self._wrapper.fetch_files_with_filter(
131131
path=self._get_remote_path(subpath),
132132
filter_rules=filter_rules
133133
)
@@ -387,7 +387,7 @@ def set_file_property(self, path, update_rules):
387387
update_rules : a dict { namespace: {key : value } }
388388
389389
Returns:
390-
requester response with <list>File in data
390+
requester response with list<File> in data
391391
392392
Note :
393393
check keys in nextcloud.common.properties.NAMESPACES_MAP for namespace codes
@@ -396,7 +396,7 @@ def set_file_property(self, path, update_rules):
396396
data = File.build_xml_propupdate(update_rules)
397397
return self.requester.proppatch(additional_url=self._get_path(path), data=data)
398398

399-
def list_files_with_filter(self, path='', filter_rules=''):
399+
def fetch_files_with_filter(self, path='', filter_rules=''):
400400
"""
401401
List files according to a filter
402402
@@ -405,7 +405,7 @@ def list_files_with_filter(self, path='', filter_rules=''):
405405
filter_rules : a dict { namespace: {key : value } }
406406
407407
Returns:
408-
requester response with <list>File in data
408+
requester response with list<File> in data
409409
410410
Note :
411411
check keys in nextcloud.common.properties.NAMESPACES_MAP for namespace codes
@@ -438,9 +438,9 @@ def list_favorites(self, path=''):
438438
path (str): file or folder path to search favorite
439439
440440
Returns:
441-
requester response with <list>File in data
441+
requester response with list<File> in data
442442
"""
443-
return self.list_files_with_filter(path, {'oc': {'favorite': 1}})
443+
return self.fetch_files_with_filter(path, {'oc': {'favorite': 1}})
444444

445445
def get_file_property(self, path, field, ns='oc'):
446446
"""

src/nextcloud/common/collections.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ def _fetch_property(cls, key, attr='xml_key'):
3434
if getattr(k, attr) == key:
3535
return k
3636

37+
def __repr__(self, add_info=''):
38+
return "<%s %s%s>" % (self.__class__.__name__, self.href, add_info)
39+
3740
def __init__(self, xml_data, init_attrs=False, wrapper=None):
3841
if init_attrs:
3942
for attr in self._attrs:
@@ -101,7 +104,10 @@ def from_response(cls, resp, json_output=None, filtered=None,
101104
if filtered:
102105
if callable(filtered):
103106
attr_datas = [
104-
attr_data for attr_data in attr_datas if filtered(attr_data)]
107+
attr_data
108+
for attr_data in attr_datas
109+
if filtered(attr_data)
110+
]
105111
resp.data = attr_datas if not json_output else [
106112
attr_data.as_dict() for attr_data in attr_datas]
107113
return resp

0 commit comments

Comments
 (0)