diff --git a/owncloud/owncloud.py b/owncloud/owncloud.py index 3c92f43..840f9e4 100644 --- a/owncloud/owncloud.py +++ b/owncloud/owncloud.py @@ -43,15 +43,17 @@ def __init__(self, res): class PublicShare(): """Public share information""" - def __init__(self, share_id, target_file, link, token): + def __init__(self, share_id, target_file, link, token, **kwargs): self.share_id = share_id self.target_file = target_file self.link = link self.token = token + self.permissions = kwargs.get('permissions', None) + self.expiration = kwargs.get('expiration', None) def __str__(self): - return 'PublicShare(id=%i,path=%s,link=%s,token=%s)' % \ - (self.share_id, self.target_file, self.link, self.token) + return 'PublicShare(id=%i,path=%s,link=%s,token=%s,permissions=%s,expiration=%s)' % \ + (self.share_id, self.target_file, self.link, self.token, self.permissions, self.expiration) class UserShare(): @@ -596,6 +598,7 @@ def update_share(self, share_id, **kwargs): :param perms: (int) update permissions (see share_file_with_user() below) :param password: (string) updated password for public link Share :param public_upload: (boolean) enable/disable public upload for public shares + :param expiration: (optional) expiration date object, or string in format 'YYYY-MM-DD' :returns: True if the operation succeeded, False otherwise :raises: HTTPResponseError in case an HTTP error status was returned """ @@ -603,9 +606,10 @@ def update_share(self, share_id, **kwargs): perms = kwargs.get('perms', None) password = kwargs.get('password', None) public_upload = kwargs.get('public_upload', None) + expiration = kwargs.get('expiration', None) if (isinstance(perms, int)) and (perms > self.OCS_PERMISSION_ALL): perms = None - if not (perms or password or (public_upload is not None)): + if not (perms or password or (public_upload is not None) or (expiration is not None)): return False if not isinstance(share_id, int): return False @@ -617,6 +621,8 @@ def update_share(self, share_id, **kwargs): data['password'] = password if (public_upload is not None) and (isinstance(public_upload, bool)): data['publicUpload'] = str(public_upload).lower() + if expiration is not None: + data['expireDate'] = self.__parse_expiration_date(expiration) res = self.__make_ocs_request( 'PUT', @@ -660,6 +666,7 @@ def share_file_with_link(self, path, **kwargs): defaults to read only (1) :param public_upload (optional): allows users to upload files or folders :param password (optional): sets a password + :param expiration: (optional) expiration date object, or string in format 'YYYY-MM-DD' http://doc.owncloud.org/server/6.0/admin_manual/sharing_api/index.html :returns: instance of :class:`PublicShare` with the share info or False if the operation failed @@ -667,8 +674,8 @@ def share_file_with_link(self, path, **kwargs): """ perms = kwargs.get('perms', None) public_upload = kwargs.get('public_upload', 'false') - password = kwargs.get('password', None) - + password = kwargs.get('password', None) + expiration = kwargs.get('expiration', None) path = self.__normalize_path(path) post_data = { @@ -681,6 +688,8 @@ def share_file_with_link(self, path, **kwargs): post_data['password'] = password if perms: post_data['permissions'] = perms + if expiration is not None: + post_data['expireDate'] = self.__parse_expiration_date(expiration) res = self.__make_ocs_request( 'POST', @@ -692,11 +701,24 @@ def share_file_with_link(self, path, **kwargs): tree = ET.fromstring(res.content) self.__check_ocs_status(tree) data_el = tree.find('data') + + expiration = None + exp_el = data_el.find('expiration') + if exp_el is not None and exp_el.text is not None and len(exp_el.text) > 0: + expiration = exp_el.text + + permissions = None + perms_el = data_el.find('permissions') + if perms_el is not None and perms_el.text is not None and len(perms_el.text) > 0: + permissions = int(perms_el.text) + return PublicShare( int(data_el.find('id').text), path, data_el.find('url').text, - data_el.find('token').text + data_el.find('token').text, + permissions=permissions, + expiration=expiration ) raise HTTPResponseError(res) @@ -818,24 +840,24 @@ def user_exists(self, user_name): """Checks a user via provisioning API. If you get back an error 999, then the provisioning API is not enabled. - :param user_name: name of user to be checked - :returns: True if user found - + :param user_name: name of user to be checked + :returns: True if user found + """ users=self.search_users(user_name) - + if len(users) > 0: for user in users: if user.text == user_name: return True - + return False def search_users(self, user_name): """Searches for users via provisioning API. If you get back an error 999, then the provisioning API is not enabled. - :param user_name: name of user to be searched for + :param user_name: name of user to be searched for :returns: list of users :raises: HTTPResponseError in case an HTTP error status was returned @@ -850,7 +872,7 @@ def search_users(self, user_name): tree = ET.fromstring(res.text) users = tree.find('data/users') - return users + return users raise HTTPResponseError(res) @@ -1371,6 +1393,22 @@ def __encode_string(s): return s.encode('utf-8') return s + @staticmethod + def __parse_expiration_date(date): + """Converts the given datetime object into the format required + by the share API + + :param date: datetime object + :returns: string encoded to use as expireDate parameter in the share API + """ + if date is None: + return None + + if isinstance(date, datetime.datetime): + return date.strftime('YYYY-MM-DD') + + return date + @staticmethod def __check_ocs_status(tree, accepted_codes=[100]): """Checks the status code of an OCS request @@ -1491,7 +1529,7 @@ def __strip_dav_path(self, path): if path.startswith(self.__davpath): return path[len(self.__davpath):] return path - + def __webdav_move_copy(self,remote_path_source,remote_path_target,operation): """Copies or moves a remote file or directory diff --git a/owncloud/test/test.py b/owncloud/test/test.py index 1affd33..41486ac 100644 --- a/owncloud/test/test.py +++ b/owncloud/test/test.py @@ -562,7 +562,7 @@ def test_share_with_link(self, file_name): path = self.test_root + file_name self.assertTrue(self.client.put_file_contents(path, 'hello world!')) - share_info = self.client.share_file_with_link(path, public_upload=True, password='1234') + share_info = self.client.share_file_with_link(path, public_upload=True, password='1234', expiration='2150-02-04') self.assertTrue(self.client.is_shared(path)) self.assertTrue(isinstance(share_info, owncloud.PublicShare)) @@ -570,8 +570,8 @@ def test_share_with_link(self, file_name): self.assertEquals(share_info.target_file, path) self.assertTrue(type(share_info.link) is str) self.assertTrue(type(share_info.token) is str) - - + self.assertEquals(share_info.permissions, 7) + self.assertEquals(share_info.expiration, '2150-02-04') def test_share_with_link_non_existing_file(self): """Test sharing a file with link""" @@ -731,6 +731,19 @@ def test_update_share_password(self): self.assertIsNotNone(share_info['share_with_displayname']) self.assertTrue(self.client.delete_share(share_id)) + def test_update_share_expiration(self): + """Test updating a share parameters - expiration date""" + path = self.test_root + 'update_share_expiration' + self.client.mkdir(path) + + share_info = self.client.share_file_with_link(path) + share_id = share_info.share_id + self.assertTrue(self.client.update_share(share_id, expiration='2150-02-04')) + share_info = self.client.get_shares(path)[0] + self.assertTrue('expiration' in share_info) + self.assertEquals(share_info['expiration'], '2150-02-04') + self.assertTrue(self.client.delete_share(share_id)) + class TestPrivateDataAccess(unittest.TestCase): attrs = lambda: (