Skip to content

Commit 298d456

Browse files
authored
raise session expired exception instead of not logged in (#316)
* raise session expired exception instead of not logged in catch upload errors and raise exceptions update direct-io docs * resolve lint errors
1 parent b3eb291 commit 298d456

File tree

9 files changed

+103
-18
lines changed

9 files changed

+103
-18
lines changed

cterasdk/asynchronous/core/files/io.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ async def versions(core, path):
4040

4141

4242
async def walk(core, scope, path, include_deleted=False):
43+
target = fs.CorePath.instance(scope, path)
44+
await ensure_directory(core, target)
4345
paths = [fs.CorePath.instance(scope, path)]
4446
while len(paths) > 0:
4547
path = paths.pop(0)
@@ -53,7 +55,7 @@ async def walk(core, scope, path, include_deleted=False):
5355
async def mkdir(core, path):
5456
with fs.makedir(path) as param:
5557
response = await core.v1.api.execute('', 'makeCollection', param)
56-
fs.accept_response(response)
58+
fs.accept_error(response)
5759

5860

5961
async def makedirs(core, path):
@@ -173,7 +175,7 @@ async def wrapper(core):
173175
"""
174176
uid, filename, directory = await _validate_destination(core, name, destination)
175177
with fs.upload(core, filename, directory, size, fd) as param:
176-
return await core.io.upload(str(uid), param)
178+
return fs.validate_transfer_success(await core.io.upload(str(uid), param), destination.join(name).reference.as_posix())
177179
return wrapper
178180

179181

cterasdk/cio/core.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
from contextlib import contextmanager
44
from ..objects.uri import quote, unquote
55
from ..common import Object, DateTimeUtils
6-
from ..core.enum import ProtectionLevel, CollaboratorType, SearchType, PortalAccountType, FileAccessMode, FileAccessError
6+
from ..core.enum import ProtectionLevel, CollaboratorType, SearchType, PortalAccountType, FileAccessMode, FileAccessError, \
7+
UploadError
78
from ..core.types import PortalAccount, UserAccount, GroupAccount
8-
from ..exceptions.io import ResourceExistsError, PathValidationError, NameSyntaxError, ReservedNameError, RestrictedRoot
9+
from ..exceptions.io import ResourceExistsError, PathValidationError, NameSyntaxError, \
10+
ReservedNameError, RestrictedRoot, InsufficientPermission
11+
from ..exceptions.io import UploadException, OutOfQuota, RejectedByPolicy, NoStorageBucket, WindowsACLError
912
from ..lib.iterator import DefaultResponse
1013
from . import common
1114

@@ -181,7 +184,7 @@ def build(self):
181184
class FetchResourcesResponse(DefaultResponse):
182185

183186
def __init__(self, response):
184-
accept_response(response.errorType)
187+
accept_error(response.errorType)
185188
super().__init__(response)
186189

187190
@property
@@ -291,7 +294,7 @@ def handle(path):
291294

292295

293296
def destination_prerequisite_conditions(destination, name):
294-
if not destination.reference.root:
297+
if not len(destination.reference.parts) > 0:
295298
raise RestrictedRoot()
296299
if any(c in name for c in ['\\', '/', ':', '?', '&', '<', '>', '"', '|']):
297300
raise NameSyntaxError()
@@ -311,6 +314,26 @@ def upload(core, name, destination, size, fd):
311314
yield param
312315

313316

317+
def validate_transfer_success(response, path):
318+
if response.rc:
319+
logger.error('Upload of file: "%s" failed.', path)
320+
if response.msg == UploadError.UserQuotaViolation:
321+
raise OutOfQuota('User', path)
322+
if response.msg == UploadError.PortalQuotaViolation:
323+
raise OutOfQuota('Team Portal', path)
324+
if response.msg == UploadError.FolderQuotaViolation:
325+
raise OutOfQuota('Cloud drive folder', path)
326+
if response.msg == UploadError.RejectedByPolicy:
327+
raise RejectedByPolicy(path)
328+
if response.msg == UploadError.WindowsACL:
329+
raise WindowsACLError(path)
330+
if response.msg.startswith(UploadError.NoStorageBucket):
331+
raise NoStorageBucket(path)
332+
raise UploadException(f'Upload failed. Reason: {response.msg}', path)
333+
if not response.rc and response.msg == 'OK':
334+
logger.info('Upload successful. Saved to: %s', path)
335+
336+
314337
@contextmanager
315338
def handle_many(directory, objects):
316339
param = Object()
@@ -508,15 +531,16 @@ def obtain_current_accounts(param):
508531
return current_accounts
509532

510533

511-
def accept_response(error_type):
534+
def accept_error(error_type):
512535
"""
513536
Check if response contains an error.
514537
"""
515538
error = {
516539
FileAccessError.FileWithTheSameNameExist: ResourceExistsError(),
517540
FileAccessError.DestinationNotExists: PathValidationError(),
518541
FileAccessError.InvalidName: NameSyntaxError(),
519-
FileAccessError.ReservedName: ReservedNameError()
542+
FileAccessError.ReservedName: ReservedNameError(),
543+
FileAccessError.PermissionDenied: InsufficientPermission()
520544
}.get(error_type, None)
521545
try:
522546
if error:

cterasdk/cio/edge.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def makedir(path):
6969
yield path.absolute
7070
except CTERAException as error:
7171
try:
72-
accept_response(error.response.message.msg, directory)
72+
accept_error(error.response.message.msg, directory)
7373
except ResourceExistsError:
7474
logger.info('Directory already exists: %s', directory)
7575
logger.info('Directory created: %s', directory)
@@ -126,7 +126,7 @@ def upload(name, destination, fd):
126126
yield param
127127

128128

129-
def accept_response(response, reference):
129+
def accept_error(response, reference):
130130
error = {
131131
"File exists": ResourceExistsError(),
132132
"Creating a folder in this location is forbidden": RestrictedPathError(),

cterasdk/clients/clients.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ async def download_zip(self, path, data, **kwargs):
4949
class AsyncUpload(AsyncClient):
5050

5151
async def upload(self, path, data, **kwargs):
52-
return await super().form_data(path, data, **kwargs)
52+
response = await super().form_data(path, data, **kwargs)
53+
return await response.xml()
5354

5455

5556
class AsyncWebDAV(AsyncClient):
@@ -253,7 +254,8 @@ def download_zip(self, path, data, **kwargs):
253254
class Upload(Client):
254255

255256
def upload(self, path, data, **kwargs):
256-
return super().form_data(path, data, **kwargs)
257+
response = super().form_data(path, data, **kwargs)
258+
return response.xml()
257259

258260

259261
class WebDAV(Client):

cterasdk/clients/decorators.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def authenticate_then_execute(self, *args, **kwargs):
1616
except SessionExpired:
1717
logger.error('Session expired.')
1818
self.cookies.clear()
19+
raise
1920
logger.error('Not logged in.')
2021
raise NotLoggedIn()
2122
return authenticate_then_execute

cterasdk/core/enum.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,21 @@ class Reports:
646646
FolderGroups = 'folderGroupsStatisticsReport'
647647

648648

649+
class UploadError:
650+
"""
651+
Upload Error
652+
653+
:ivar QuotaViolation: User is out of quota.
654+
:ivar RejectedByPolicy: Rejected by Cloud Drive policy rule.
655+
"""
656+
FolderQuotaViolation = 'Folder is out of quota'
657+
UserQuotaViolation = 'User is out of quota'
658+
PortalQuotaViolation = 'Portal is out of quota'
659+
RejectedByPolicy = "Rejected by Cloud Drive policy rule"
660+
NoStorageBucket = "No available storage location"
661+
WindowsACL = "Illegal access to NTACL folder"
662+
663+
649664
class FileAccessError:
650665
"""
651666
File Access Error

cterasdk/core/files/io.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ def versions(core, path):
4141

4242

4343
def walk(core, scope, path, include_deleted=False):
44-
ensure_directory(core, path)
45-
paths = [fs.CorePath.instance(scope, path)]
44+
target = fs.CorePath.instance(scope, path)
45+
ensure_directory(core, target)
46+
paths = [target]
4647
while len(paths) > 0:
4748
path = paths.pop(0)
4849
entries = listdir(core, path, include_deleted=include_deleted)
@@ -55,7 +56,7 @@ def walk(core, scope, path, include_deleted=False):
5556
def mkdir(core, path):
5657
with fs.makedir(path) as param:
5758
response = core.api.execute('', 'makeCollection', param)
58-
fs.accept_response(response)
59+
fs.accept_error(response)
5960

6061

6162
def makedirs(core, path):
@@ -175,7 +176,7 @@ def wrapper(core):
175176
"""
176177
uid, filename, directory = _validate_destination(core, name, destination)
177178
with fs.upload(core, filename, directory, size, fd) as param:
178-
return core.io.upload(str(uid), param)
179+
return fs.validate_transfer_success(core.io.upload(str(uid), param), destination.join(name).reference.as_posix())
179180
return wrapper
180181

181182

cterasdk/exceptions/io.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,43 @@ class RestrictedRoot(RemoteStorageException):
5858

5959
def __init__(self):
6060
super().__init__('Storing files to the root directory is forbidden.', '/')
61+
62+
63+
class InsufficientPermission(RemoteStorageException):
64+
65+
def __init__(self):
66+
super().__init__('Permission denied: You must have appropriate permissions to access this resource.')
67+
68+
69+
class UploadException(RemoteStorageException):
70+
"""
71+
Upload Exception
72+
73+
:ivar str path: Path
74+
"""
75+
def __init__(self, message, path):
76+
super().__init__(f'Upload failed: {message}.', path)
77+
78+
79+
class OutOfQuota(UploadException):
80+
81+
def __init__(self, entity, path):
82+
super().__init__(f'{entity} is out of quota', path)
83+
84+
85+
class RejectedByPolicy(UploadException):
86+
87+
def __init__(self, path):
88+
super().__init__('Rejected by Cloud Drive policy rule', path)
89+
90+
91+
class NoStorageBucket(UploadException):
92+
93+
def __init__(self, path):
94+
super().__init__('No available storage location', path)
95+
96+
97+
class WindowsACLError(UploadException):
98+
99+
def __init__(self, path):
100+
super().__init__('Unable to store file in a Windows ACL-enabled cloud folder', path)

docs/source/UserGuides/DataServices/DirectIO.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ During testing, you may need to disable TLS verification if the Portal or Object
8585
Blocks API
8686
==========
8787

88-
.. automethod:: cterasdk.direct.client.Client.blocks
88+
.. automethod:: cterasdk.direct.client.DirectIO.blocks
8989
:noindex:
9090

9191

@@ -122,7 +122,7 @@ Blocks API
122122
Streamer API
123123
============
124124

125-
.. automethod:: cterasdk.direct.client.Client.streamer
125+
.. automethod:: cterasdk.direct.client.DirectIO.streamer
126126
:noindex:
127127

128128
.. code-block:: python

0 commit comments

Comments
 (0)