From ae7e419a01d01eac1a10b5bf552735412070b815 Mon Sep 17 00:00:00 2001
From: Alexandre Norman
Date: Fri, 13 Apr 2018 11:43:34 +0200
Subject: [PATCH 1/7] Changes for Python 3 (and 2) support
---
seafileapi/client.py | 1 +
seafileapi/files.py | 8 +++++++-
seafileapi/repo.py | 6 +++++-
seafileapi/utils.py | 32 +++++++++++++++++++++++++-------
tests/test_files.py | 17 ++++++++++++++---
tests/utils.py | 2 +-
6 files changed, 53 insertions(+), 13 deletions(-)
diff --git a/seafileapi/client.py b/seafileapi/client.py
index 9bf79ee..d64874d 100644
--- a/seafileapi/client.py
+++ b/seafileapi/client.py
@@ -57,6 +57,7 @@ def _send_request(self, method, url, *args, **kwargs):
expected = kwargs.pop('expected', 200)
if not hasattr(expected, '__iter__'):
expected = (expected, )
+
resp = requests.request(method, url, *args, **kwargs)
if resp.status_code not in expected:
msg = 'Expected %s, but get %s' % \
diff --git a/seafileapi/files.py b/seafileapi/files.py
index d36f2ea..0ee01de 100644
--- a/seafileapi/files.py
+++ b/seafileapi/files.py
@@ -2,6 +2,7 @@
import os
import posixpath
import re
+import sys
from seafileapi.utils import querystr, utf8lize
ZERO_OBJ_ID = '0000000000000000000000000000000000000000'
@@ -157,12 +158,17 @@ def upload(self, fileobj, filename):
Return a :class:`SeafFile` object of the newly uploaded file.
"""
if isinstance(fileobj, str):
- fileobj = io.BytesIO(fileobj)
+ if sys.version_info.major > 2:
+ fileobj = io.BytesIO(bytes(fileobj, 'UTF-8'))
+ else:
+ fileobj = io.BytesIO(fileobj)
+
upload_url = self._get_upload_link()
files = {
'file': (filename, fileobj),
'parent_dir': self.path,
}
+ # print(files)
self.client.post(upload_url, files=files)
return self.repo.get_file(posixpath.join(self.path, filename))
diff --git a/seafileapi/repo.py b/seafileapi/repo.py
index ded895e..ab7dac5 100644
--- a/seafileapi/repo.py
+++ b/seafileapi/repo.py
@@ -1,4 +1,8 @@
-from urllib import urlencode
+import sys
+if sys.version_info.major > 2:
+ from urllib.parse import urlencode
+else:
+ from urllib import urlencode
from seafileapi.utils import utf8lize
from seafileapi.files import SeafDir, SeafFile
from seafileapi.utils import raise_does_not_exist
diff --git a/seafileapi/utils.py b/seafileapi/utils.py
index b529880..e4f4583 100644
--- a/seafileapi/utils.py
+++ b/seafileapi/utils.py
@@ -1,7 +1,13 @@
import string
import random
from functools import wraps
-from urllib import urlencode
+
+import sys
+if sys.version_info.major > 2:
+ from urllib.parse import urlencode
+else:
+ from urllib import urlencode
+
from seafileapi.exceptions import ClientHttpError, DoesNotExist
def randstring(length=0):
@@ -28,7 +34,7 @@ def decorator(func):
def wrapped(*args, **kwargs):
try:
return func(*args, **kwargs)
- except ClientHttpError, e:
+ except ClientHttpError as e:
if e.code == 404:
raise DoesNotExist(msg)
else:
@@ -37,8 +43,13 @@ def wrapped(*args, **kwargs):
return decorator
def to_utf8(obj):
- if isinstance(obj, unicode):
- return obj.encode('utf-8')
+ if sys.version_info.major > 2:
+ return obj
+ else:
+ unicode_type = unicode
+ if isinstance(obj, unicode_type):
+ return obj.encode('utf-8')
+
return obj
def querystr(**kwargs):
@@ -46,12 +57,19 @@ def querystr(**kwargs):
def utf8lize(obj):
if isinstance(obj, dict):
- return {k: to_utf8(v) for k, v in obj.iteritems()}
+ if sys.version_info.major > 2:
+ return {k: to_utf8(v) for k, v in obj.items()}
+ else:
+ return {k: to_utf8(v) for k, v in obj.iteritems()}
if isinstance(obj, list):
return [to_utf8(x) for x in ob]
- if instance(obj, unicode):
- return obj.encode('utf-8')
+ if sys.version_info.major > 2:
+ return obj
+ else:
+ unicode_type = unicode
+ if instance(obj, unicode_type):
+ return obj.encode('utf-8')
return obj
diff --git a/tests/test_files.py b/tests/test_files.py
index 5509da0..39f907e 100644
--- a/tests/test_files.py
+++ b/tests/test_files.py
@@ -1,6 +1,7 @@
#coding: UTF-8
import os
+import sys
import pytest
from tests.utils import randstring, datafile, filesize
@@ -59,10 +60,16 @@ def test_upload_file(repo, parentpath):
fname = 'aliedit.tar.gz'
fpath = datafile(fname)
- with open(fpath, 'r') as fp:
+
+ if sys.version_info.major > 2:
+ mode = 'rb'
+ else:
+ mode = 'r'
+
+ with open(fpath, mode) as fp:
testfile = parentdir.upload(fp, fname)
- with open(fpath, 'r') as fp:
+ with open(fpath, mode) as fp:
fcontent = fp.read()
assert testfile.size == filesize(fpath)
@@ -85,7 +92,11 @@ def test_upload_string_as_file_content(repo):
# test pass as string as file content when upload file
rootdir = repo.get_dir('/')
fname = u'testfile-%s' % randstring()
- fcontent = 'line 1\nline 2\n\r'
+ if sys.version_info.major > 2:
+ fcontent = b'line 1\nline 2\n\r'
+ else:
+ fcontent = 'line 1\nline 2\n\r'
+
f = rootdir.upload(fcontent, fname)
assert f.name == fname
assert f.get_content() == fcontent
diff --git a/tests/utils.py b/tests/utils.py
index 63cc8d6..de0d5ab 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -3,7 +3,7 @@
import random
def randstring(length=12):
- return ''.join(random.choice(string.lowercase) for i in range(length))
+ return ''.join(random.choice(string.ascii_lowercase) for i in range(length))
def datafile(filename):
return os.path.join(os.path.dirname(__file__), 'data', filename)
From 46ce11fc6e6fcde45be35eabb073e60fe33951e4 Mon Sep 17 00:00:00 2001
From: Alexandre Norman
Date: Fri, 13 Apr 2018 11:56:39 +0200
Subject: [PATCH 2/7] Update version
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index d2165df..e2c19f4 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
from setuptools import setup, find_packages
-__version__ = '0.1.1'
+__version__ = '0.2.0'
setup(name='seafileapi',
From 597a75bcca924dc51b564dc6dcc29ecd9b2f99c9 Mon Sep 17 00:00:00 2001
From: Alexandre Norman
Date: Fri, 13 Apr 2018 22:33:23 +0200
Subject: [PATCH 3/7] Add error reason from server on failures
---
seafileapi/client.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/seafileapi/client.py b/seafileapi/client.py
index d64874d..e9b5a9e 100644
--- a/seafileapi/client.py
+++ b/seafileapi/client.py
@@ -62,6 +62,7 @@ def _send_request(self, method, url, *args, **kwargs):
if resp.status_code not in expected:
msg = 'Expected %s, but get %s' % \
(' or '.join(map(str, expected)), resp.status_code)
+ msg += '\n' + resp.content.decode('utf-8')
raise ClientHttpError(resp.status_code, msg)
return resp
From ebdad63e5b7502eb74388aa174c26e100645c5fe Mon Sep 17 00:00:00 2001
From: Alexandre Norman
Date: Sat, 14 Apr 2018 23:30:51 +0200
Subject: [PATCH 4/7] Add put method on client
---
seafileapi/client.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/seafileapi/client.py b/seafileapi/client.py
index e9b5a9e..b069ba9 100644
--- a/seafileapi/client.py
+++ b/seafileapi/client.py
@@ -43,6 +43,9 @@ def get(self, *args, **kwargs):
def post(self, *args, **kwargs):
return self._send_request('POST', *args, **kwargs)
+ def put(self, *args, **kwargs):
+ return self._send_request('PUT', *args, **kwargs)
+
def delete(self, *args, **kwargs):
return self._send_request('delete', *args, **kwargs)
From 4bf914568664f0c9a4bf3d2bef05e9a3a3627c3a Mon Sep 17 00:00:00 2001
From: Alexandre Norman
Date: Sat, 14 Apr 2018 23:32:04 +0200
Subject: [PATCH 5/7] Update version number
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index e2c19f4..095c10a 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
from setuptools import setup, find_packages
-__version__ = '0.2.0'
+__version__ = '0.3.0'
setup(name='seafileapi',
From 1c802996342ea2b89e7f5c602dfe15237e808322 Mon Sep 17 00:00:00 2001
From: Alexandre Norman
Date: Sun, 15 Apr 2018 00:18:16 +0200
Subject: [PATCH 6/7] Add basic managing of Users and Groups
---
seafileapi/group.py | 93 ++++++++++++++++++++++++++++++++++------
seafileapi/user.py | 101 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 180 insertions(+), 14 deletions(-)
create mode 100644 seafileapi/user.py
diff --git a/seafileapi/group.py b/seafileapi/group.py
index 731d7ef..085af91 100644
--- a/seafileapi/group.py
+++ b/seafileapi/group.py
@@ -1,22 +1,87 @@
-
class Group(object):
- def __init__(self, client, group_id, group_name):
+ def __init__(self, client):
+ """
+ client -- Seafile client object
+ """
self.client = client
- self.group_id = group_id
- self.group_name = group_name
- def list_memebers(self):
- pass
+ def get_groups(self):
+ """
+ Returns list of groups
+ """
+ resp = self.client.get('/api2/groups/')
+ value = resp.json()
+ return value['groups']
+
+# def get_group_members(self, group_name):
+# """
+# Returns list of members of a group
+# """
+# groups = self.get_groups()
+# found = False
+# for i in groups:
+# if i['name'] == group_name:
+# url = '/api2/groups/{}/members/'.format(i['id'])
+# resp = self.client.get(url)
+# found = True
+# break
+# value = resp.json()
+# return value
+
+ def create_group(self, group_name):
+ """
+ Creates group
+
+ group_name -- name
+ """
+ data = {
+ 'group_name': group_name,
+ }
+ resp = self.client.put(
+ '/api2/groups/',
+ data=data,
+ )
+ value = resp.json()
+ return value
+
+ def delete_group(self, group_name):
+ """
+ Delete group
+
+ group_name -- name
+ """
+ url = '/api2/groups/{}'.format(self.get_id_from_group_name(group_name))
+ resp = self.client.delete(url)
+ value = resp.json()
+ return value
- def delete(self):
- pass
+ def get_id_from_group_name(self, group_name):
+ groups = self.get_groups()
+ for i in groups:
+ if i['name'] == group_name:
+ return i['id']
- def add_member(self, username):
- pass
+ raise ValueError('Group {} not found'.format(group_name))
- def remove_member(self, username):
- pass
- def list_group_repos(self):
- pass
+# class Group(object):
+# def __init__(self, client, group_id, group_name):
+# self.client = client
+# self.group_id = group_id
+# self.group_name = group_name
+#
+# def list_memebers(self):
+# pass
+#
+# def delete(self):
+# pass
+#
+# def add_member(self, username):
+# pass
+#
+# def remove_member(self, username):
+# pass
+#
+# def list_group_repos(self):
+# pass
diff --git a/seafileapi/user.py b/seafileapi/user.py
new file mode 100644
index 0000000..e254bc3
--- /dev/null
+++ b/seafileapi/user.py
@@ -0,0 +1,101 @@
+from group import Group
+
+
+class User(object):
+ def __init__(self, client):
+ """
+ client -- Seafile client object
+ """
+ self.client = client
+
+ def get_accounts(self):
+ """
+ Returns accounts list such as :
+
+ [{'source': 'DB', 'email': 'test@seafiletest.com'},
+ {'source': 'DB', 'email': 'admin@seafiletest.com'}]
+ """
+ url = '/api2/accounts/'
+ resp = self.client.get(url)
+ return resp.json()
+
+ def create_account(self, email, password, groups_names=[], name='', note='', is_staff=False, is_active=True):
+ """
+ Creates account
+
+ email -- email as login name
+ password -- plain text password
+ name -- full text display name
+ groups_names -- list of groups' names to add this user to
+ note -- description / comment / whatever
+ is_staff -- is admin, default False
+ is_active -- can connect, default True
+ """
+ data = {
+ 'password': password,
+ 'is_staff': is_staff,
+ 'is_active': is_active,
+ 'name': name[0:64],
+ 'note': note,
+ # 'storage': 'DB',
+ }
+ url = '/api2/accounts/{}/'.format(email)
+ resp = self.client.put(
+ url,
+ data=data,
+ expected=[200, 201],
+ )
+ user = resp.json()
+ for group_name in groups_names:
+ self.add_user_to_group(username=email, group_name=group_name)
+
+ return user
+
+ def delete_account(self, email):
+ """
+ Delete account
+
+ email -- email as login name
+ """
+ url = '/api2/accounts/{}/'.format(email)
+ resp = self.client.delete(url)
+ value = resp.json()
+ return value
+
+ def add_user_to_group(self, username, group_name):
+ """
+ Adds given username (email) to group (by group name)
+
+ username -- email / login name
+ group_name -- group to add user to
+ """
+ data = {
+ 'user_name': username,
+ }
+ url = '/api2/groups/{}/members/'.format(self.__get_id_from_group_name__(group_name))
+ resp = self.client.put(
+ url, data=data,
+ )
+
+ return resp.json()
+
+ def __get_groups__(self):
+ manage_group = Group(self.client)
+ return manage_group.get_groups()
+
+ def __get_id_from_group_name__(self, group_name):
+ manage_group = Group(self.client)
+ return manage_group.get_id_from_group_name(group_name)
+
+
+
+"""
+import __init__
+c=__init__.connect('http://127.0.0.1:8000', 'admin@seafiletest.com', 'adminadmin')
+from user import User
+u=User(c)
+u.create_account('none5@xael.org', 'node99', ['test'], 'Alexandre')
+# u.delete_group('TEST2')
+# u.delete_account('none4@xael.org')
+u.get_group_members('test')
+"""
From 2499fb511d95d08b1fef56037dad424b7931448e Mon Sep 17 00:00:00 2001
From: Alexandre Norman
Date: Sun, 15 Apr 2018 22:07:25 +0200
Subject: [PATCH 7/7] Update doc and change class names
---
doc.md | 203 +++++++++++++++++++++++++++++++++++++++++++
seafileapi/client.py | 12 +--
seafileapi/group.py | 2 +-
seafileapi/user.py | 4 +-
4 files changed, 210 insertions(+), 11 deletions(-)
diff --git a/doc.md b/doc.md
index c5092bf..bf3a7f0 100644
--- a/doc.md
+++ b/doc.md
@@ -31,6 +31,23 @@
Delete file
+
+ User
+
+
+
+ Group
+
+
@@ -429,3 +446,189 @@ None
**Return Type**
A Response Instance
+
+
+## User ##
+
+### Get accounts ###
+**Request Parameters**
+
+None
+
+**Sample Case**
+
+```python
+
+ import seafileapi
+
+ client = seafileapi.connect('http://127.0.0.1:8000', 'test@admin.com', 'password')
+ accounts = client.users.get_accounts()
+```
+
+**Return Type**
+
+A list of dictionnary containing source and email keys.
+
+**Exception**
+
+TBD
+
+### Create account ###
+**Request Parameters**
+
+* email -- email as login name
+* password -- plain text password
+* name -- full text display name
+* groups_names -- list of groups' names to add this user to
+* note -- description / comment / whatever
+* is_staff -- is admin, default False
+* is_active -- can connect, default True
+
+
+**Sample Case**
+
+```python
+
+ import seafileapi
+
+ client = seafileapi.connect('http://127.0.0.1:8000', 'test@admin.com', 'password')
+ accounts = client.users.create_account('test@admin.com', 'password', 'Test user', ['admins'])
+```
+
+**Return Type**
+
+A dictionnary, containing the created user.
+
+**Exception**
+
+TBD
+
+
+### Delete account ###
+**Request Parameters**
+
+* email -- email as login name
+
+
+**Sample Case**
+
+```python
+
+ import seafileapi
+
+ client = seafileapi.connect('http://127.0.0.1:8000', 'test@admin.com', 'password')
+ accounts = client.users.delete_account('test@admin.com')
+```
+
+**Return Type**
+
+TBD
+
+**Exception**
+
+TBD
+
+
+### Add account to group ###
+**Request Parameters**
+
+* username -- email as login name
+* groups_name -- group's name to add this user to
+
+**Sample Case**
+
+```python
+
+ import seafileapi
+
+ client = seafileapi.connect('http://127.0.0.1:8000', 'test@admin.com', 'password')
+ accounts = client.users.add_account_to_group('test@admin.com', 'admins')
+```
+
+**Return Type**
+
+TBD
+
+**Exception**
+
+TBD
+
+
+
+
+## Group ##
+
+### Get groups ###
+**Request Parameters**
+
+None
+
+**Sample Case**
+
+```python
+
+ import seafileapi
+
+ client = seafileapi.connect('http://127.0.0.1:8000', 'test@admin.com', 'password')
+ groups = client.groups.get_groups()
+```
+
+**Return Type**
+
+A list of groups.
+
+**Exception**
+
+TBD
+
+
+
+### Create group ###
+**Request Parameters**
+
+* group_name -- group's name
+
+
+**Sample Case**
+
+```python
+
+ import seafileapi
+
+ client = seafileapi.connect('http://127.0.0.1:8000', 'test@admin.com', 'password')
+ accounts = client.groups.create_group('admins')
+```
+
+**Return Type**
+
+TBD
+
+**Exception**
+
+TBD
+
+
+### Delete group ###
+**Request Parameters**
+
+* group_name -- group's name
+
+
+**Sample Case**
+
+```python
+
+ import seafileapi
+
+ client = seafileapi.connect('http://127.0.0.1:8000', 'test@admin.com', 'password')
+ accounts = client.groups.delete_group('admin')
+```
+
+**Return Type**
+
+TBD
+
+**Exception**
+
+TBD
+
diff --git a/seafileapi/client.py b/seafileapi/client.py
index b069ba9..75137de 100644
--- a/seafileapi/client.py
+++ b/seafileapi/client.py
@@ -2,6 +2,9 @@
from seafileapi.utils import urljoin
from seafileapi.exceptions import ClientHttpError
from seafileapi.repos import Repos
+from seafileapi.group import Groups
+from seafileapi.user import Users
+
class SeafileApiClient(object):
"""Wraps seafile web api"""
@@ -15,6 +18,7 @@ def __init__(self, server, username=None, password=None, token=None):
self.repos = Repos(self)
self.groups = Groups(self)
+ self.users = Users(self)
if token is None:
self._get_token()
@@ -69,11 +73,3 @@ def _send_request(self, method, url, *args, **kwargs):
raise ClientHttpError(resp.status_code, msg)
return resp
-
-
-class Groups(object):
- def __init__(self, client):
- pass
-
- def create_group(self, name):
- pass
diff --git a/seafileapi/group.py b/seafileapi/group.py
index 085af91..bfeccf1 100644
--- a/seafileapi/group.py
+++ b/seafileapi/group.py
@@ -1,5 +1,5 @@
-class Group(object):
+class Groups(object):
def __init__(self, client):
"""
client -- Seafile client object
diff --git a/seafileapi/user.py b/seafileapi/user.py
index e254bc3..2d1101c 100644
--- a/seafileapi/user.py
+++ b/seafileapi/user.py
@@ -1,7 +1,7 @@
from group import Group
-class User(object):
+class Users(object):
def __init__(self, client):
"""
client -- Seafile client object
@@ -62,7 +62,7 @@ def delete_account(self, email):
value = resp.json()
return value
- def add_user_to_group(self, username, group_name):
+ def add_account_to_group(self, username, group_name):
"""
Adds given username (email) to group (by group name)