diff --git a/.travis.yml b/.travis.yml index d8268aa..f014078 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,8 @@ services: - docker python: - - "3.6" + - 2.7 + - 3.6 before_script: - cd tests && docker-compose up --build -d @@ -14,7 +15,7 @@ before_script: # commands to run tests script: - docker-compose run --rm python-api python3 -m pytest --cov . --cov-report xml --cov-report term .. - - docker-compose run --rm python-api python ../example.py + - docker-compose run --rm python-api python ../examples/user_management.py after_script: - codecov diff --git a/AUTHORS.rst b/AUTHORS.rst new file mode 100644 index 0000000..cb173f4 --- /dev/null +++ b/AUTHORS.rst @@ -0,0 +1,29 @@ + +This is Python wrapper for NextCloud's API had been made by… + +Main contributors +````````````````` +- Matěj Týč `@matejak ` active from 2018 +- Danil Topchiy `@danil-topchiy ` active 2018-2019 + + +Refactoring contributors +```````````````````````` +- Matěj Týč `@matejak ` active from 2018 +- Danil Topchiy `@danil-topchiy ` active 2018-2019 +- luffah `@luffah ` active 2021 + + +Original code +````````````` +The repo was originally nammed NEXT-OCS-API-forPy in 2017 +- どまお `@Dosugamea ` + + +Patches +``````` +- Hendrik Eckardt `@heck-gd ` +- Anonymous `@xr-muc ` +- tthmmts `@tthmmts ` +- Dylann Cordel `@webu ` `@DylannCordel ` +- scouderc `@scouderc ` diff --git a/README.md b/README.md index cfb607f..591a835 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This is Python wrapper for NextCloud's API. With it you can manage your NextCloud instances from Python scripts. Tested with : - * NextCloud 14, python 3.7 + * NextCloud 14, python 3.7 (automated test) * NextCloud 20, python 2.7 * NextCloud 20, python 3.6 diff --git a/requirements.in b/requirements.in index f3950c1..571af75 100644 --- a/requirements.in +++ b/requirements.in @@ -1,2 +1,3 @@ requests>=2.0.1 pytest>=4.6 +six diff --git a/requirements.txt b/requirements.txt index 6023ab7..21b9b5f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,15 +4,5 @@ # # pip-compile --output-file requirements.txt requirements.in # -atomicwrites==1.2.1 # via pytest -attrs==18.2.0 # via pytest -certifi==2018.11.29 # via requests -chardet==3.0.4 # via requests -idna==2.7 # via requests -more-itertools==4.3.0 # via pytest -pluggy==0.8.0 # via pytest -py==1.7.0 # via pytest -pytest==4.0.1 +pytest==4.6.1 requests==2.20.1 -six==1.11.0 # via more-itertools, pytest -urllib3==1.24.1 # via requests diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..c94a57e --- /dev/null +++ b/setup.cfg @@ -0,0 +1,69 @@ +[metadata] + +name = nextcloud +version = 0.2 +description= Python wrapper for NextCloud api +long_description = file: README.md +keywords = requests, api, wrapper, nextcloud, owncloud +license = GPLv3 + +url = https://nextcloud-api.readthedocs.io +project_urls = + Documentation = https://nextcloud-api.readthedocs.io + Source = https://github.com/EnterpriseyIntranet/nextcloud-API + +author = EnterpriseyIntranet +author_email = matej.tyc@gmail.com + +platforms = any + +classifiers = + Programming Language :: Python + Programming Language :: Python :: 2 + Programming Language :: Python :: 3 + Development Status :: 4 - Beta + Environment :: Web Environment + Intended Audience :: Developers + Topic :: Internet :: WWW/HTTP + Topic :: Software Development :: Libraries :: Python Modules + License :: OSI Approved :: GNU General Public License (GPL) + Operating System :: OS Independent + +[options] +zip_safe = False +include_package_data = True + +install_requires = + requests >=2.0.1, <3.0 + six + +[options.extras_require] +tests = + pytest >= 5.2 + +#[tool:pytest] +#addopts = --verbose --pylint-rcfile=setup.cfg +# --pylint --pycodestyle + +[pycodestyle] +max-line-length=120 +ignore=E4,E7,W3 + +# Configuration for pylint +[MASTER] +ignore=CVS +good-names=logger,e,i,j,n,m,f,_ + +[MESSAGES CONTROL] +disable=all +enable=unused-import, + fixme, + useless-object-inheritance, + unused-variable, + unused-argument, + unexpected-keyword-arg, + string, + unreachable, + invalid-name, + logging-not-lazy, + unnecesary-pass diff --git a/setup.py b/setup.py index 619ebf1..b0a84c8 100644 --- a/setup.py +++ b/setup.py @@ -1,38 +1,31 @@ -import os -import setuptools +""" +Setup script + +Usage : + python setup.py build + python setup.py install -SETUPDIR = os.path.dirname(__file__) -PKGDIR = os.path.join(SETUPDIR, 'src') +For repository admin: + python setup.py publish -with open(os.path.join(SETUPDIR, 'README.md'), 'r') as f: - long_description = f.read() +For testing: + test.sh +""" +import os +import sys +from setuptools import setup, find_packages +# 'setup.py publish' shortcut. +if sys.argv[-1] == 'publish': + # see https://twine.readthedocs.io/en/latest/ + os.system('%s %s sdist bdist_wheel' % (sys.executable, sys.argv[0])) + os.system('twine upload dist/*') + sys.exit() -setuptools.setup( - name='nextcloud', - version='0.0.2', - author='EnterpriseyIntranet', - description="Python wrapper for NextCloud api", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/EnterpriseyIntranet/nextcloud-API", - packages=setuptools.find_packages(PKGDIR), - include_package_data=True, - install_requires=[ - 'requests >= 2.0.1', - 'six' - ], - package_dir={'': 'src'}, - classifiers=[ - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 3', - 'Development Status :: 4 - Beta', - 'Environment :: Web Environment', - 'Intended Audience :: Developers', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'License :: OSI Approved :: GNU General Public License (GPL)', - "Operating System :: OS Independent", - ], +setup( + # see setup.cfg + # some variables are defined here for retro compat with setuptools >= 33 + package_dir = {'': 'src'}, + packages=find_packages(where=r'./src'), + long_description_content_type = 'text/markdown' ) diff --git a/src/nextcloud/api_wrappers/systemtags.py b/src/nextcloud/api_wrappers/systemtags.py index 55289e7..fed6ad9 100644 --- a/src/nextcloud/api_wrappers/systemtags.py +++ b/src/nextcloud/api_wrappers/systemtags.py @@ -37,6 +37,16 @@ def get_related_files(self, path=''): ) return ret.data or [] + def delete(self): + """ + Delete current tag + + :returns: True if success + """ + _id = int(self.id) + ret = self._wrapper.delete_systemtag(tag_id=_id) + return ret.is_ok + class File(webdav.File): @@ -114,11 +124,11 @@ def get_systemtag(self, name): :returns: Tag """ return self._get_tags_from_response( - self.fetch_sytemtag(name, json_output=False), + self.fetch_systemtag(name, json_output=False), one=True ) - def fetch_sytemtag(self, name, fields=None, json_output=None): + def fetch_systemtag(self, name, fields=None, json_output=None): """ Get attributes of a nammed tag @@ -181,11 +191,11 @@ def delete_systemtag(self, name=None, tag_id=None): :returns: requester response """ if not tag_id: - resp = self.get_sytemtag(name, ['id'], json_output=False) + resp = self.fetch_systemtag(name, ['id'], json_output=False) if resp.data: tag_id = resp.data[0].id - if not tag_id: # lint only - return None + if not tag_id: # lint only + return resp resp = self.requester.delete(url=(str(tag_id))) return resp @@ -203,7 +213,7 @@ def _get_fileid_from_path(self, path): return _id def _get_systemtag_id_from_name(self, name): - resp = self.client.fetch_sytemtag(name, ['id'], json_output=False) + resp = self.client.fetch_systemtag(name, ['id'], json_output=False) tag_id = None if resp.data: tag_id = int(resp.data[0].id) diff --git a/src/nextcloud/common/simplexml.py b/src/nextcloud/common/simplexml.py index 1de55ba..b69d5a9 100644 --- a/src/nextcloud/common/simplexml.py +++ b/src/nextcloud/common/simplexml.py @@ -10,6 +10,10 @@ def _prepare_xml_parsing(string): return encode_string(string) +def _safe_xml_val(val): + if isinstance(val, int): + val = str(val) + return val class SimpleXml: """ @@ -40,7 +44,7 @@ def _to_field_vals_list(cls, fields_hash): else: vals = fields_hash[field_type] for field in vals: - props_xml['{}:{}'.format(field_type, field)] = vals[field] + props_xml['{}:{}'.format(field_type, field)] = _safe_xml_val(vals[field]) return props_xml @@ -86,9 +90,7 @@ def build_propfind_datas(cls, instr=None, filter_rules=None, fields=None): for k in rules: rule = ET.SubElement(rule_group, k) val = rules[k] - if isinstance(val, int): - val = str(val) - rule.text = val + rule.text = _safe_xml_val(val) return cls._tostring(root) diff --git a/src/nextcloud/common/value_parsing.py b/src/nextcloud/common/value_parsing.py index 4c703f9..0a4fc8f 100644 --- a/src/nextcloud/common/value_parsing.py +++ b/src/nextcloud/common/value_parsing.py @@ -3,9 +3,14 @@ Extra tools for value parsing """ from datetime import datetime +import os from nextcloud.compat import datetime_to_timestamp +def datetime_to_expire_date(date): + return date.strftime("%Y-%m-%d") + + def timestamp_to_epoch_time(rfc1123_date=''): """ literal date time string (use in DAV:getlastmodified) to Epoch time @@ -19,8 +24,11 @@ def timestamp_to_epoch_time(rfc1123_date=''): int or None : Epoch time, if date string value is invalid return None """ try: + _tz = os.environ.get('TZ', '') + os.environ['TZ'] = 'UTC' _time = datetime.strptime( rfc1123_date, '%a, %d %b %Y %H:%M:%S GMT') + os.environ['TZ'] = _tz except ValueError: return else: diff --git a/src/nextcloud/requester.py b/src/nextcloud/requester.py index 3d061c4..ceadafd 100644 --- a/src/nextcloud/requester.py +++ b/src/nextcloud/requester.py @@ -4,7 +4,7 @@ """ from .response import WebDAVResponse, OCSResponse from .compat import encode_string -from .session import catch_connection_error +from .session import catch_connection_error, NextCloudConnectionError # from six.moves.urllib import parse diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..a95cc66 --- /dev/null +++ b/test.sh @@ -0,0 +1,96 @@ +#!/bin/sh +# Script for running tests +_usage(){ + cat <