[Commits] (morgen) Added better error handling,
and added a "Test WebDAV settings" button the accounts dialog
commits at osafoundation.org
commits at osafoundation.org
Thu Feb 3 10:02:08 PST 2005
Commit by: morgen
Modified files:
chandler/application/dialogs/AccountPreferences.py 1.23 1.24
chandler/application/dialogs/AccountPreferences.wdr 1.10 1.11
chandler/application/dialogs/AccountPreferences_wdr.xrc 1.9 1.10
chandler/parcels/osaf/framework/sharing/Sharing.py 1.57 1.58
chandler/parcels/osaf/framework/sharing/WebDAV.py 1.11 1.12
Log message:
Added better error handling, and added a "Test WebDAV settings" button the accounts dialog
ViewCVS links:
http://cvs.osafoundation.org/index.cgi/chandler/application/dialogs/AccountPreferences.py.diff?r1=text&tr1=1.23&r2=text&tr2=1.24
http://cvs.osafoundation.org/index.cgi/chandler/application/dialogs/AccountPreferences.wdr.diff?r1=text&tr1=1.10&r2=text&tr2=1.11
http://cvs.osafoundation.org/index.cgi/chandler/application/dialogs/AccountPreferences_wdr.xrc.diff?r1=text&tr1=1.9&r2=text&tr2=1.10
http://cvs.osafoundation.org/index.cgi/chandler/parcels/osaf/framework/sharing/Sharing.py.diff?r1=text&tr1=1.57&r2=text&tr2=1.58
http://cvs.osafoundation.org/index.cgi/chandler/parcels/osaf/framework/sharing/WebDAV.py.diff?r1=text&tr1=1.11&r2=text&tr2=1.12
Index: chandler/parcels/osaf/framework/sharing/WebDAV.py
diff -u chandler/parcels/osaf/framework/sharing/WebDAV.py:1.11 chandler/parcels/osaf/framework/sharing/WebDAV.py:1.12
--- chandler/parcels/osaf/framework/sharing/WebDAV.py:1.11 Wed Feb 2 19:10:47 2005
+++ chandler/parcels/osaf/framework/sharing/WebDAV.py Thu Feb 3 10:02:07 2005
@@ -1,5 +1,5 @@
-__version__ = "$Revision: 1.11 $"
-__date__ = "$Date: 2005/02/03 03:10:47 $"
+__version__ = "$Revision: 1.12 $"
+__date__ = "$Date: 2005/02/03 18:02:07 $"
__copyright__ = "Copyright (c) 2005 Open Source Applications Foundation"
__license__ = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
@@ -48,6 +48,16 @@
self.conn = httplib.HTTPConnection(self.host, self.port)
self.conn.debuglevel = 0
+ try:
+ logger.debug("Connecting to %s" % self.host)
+ self.conn.connect()
+ except socket.gaierror, err:
+ # @@@MOR can these exceptions mean anything else?
+ message = "Unknown host %s" % self.host
+ raise ConnectionError(message=message)
+ except socket.herror, err:
+ message = "Unknown host %s" % self.host
+ raise ConnectionError(message=message)
def mkcol(self, url, extraHeaders={ }):
return self._request('MKCOL', url, extraHeaders=extraHeaders)
@@ -92,7 +102,7 @@
resources = []
resp = self.propfind(url, depth=1, extraHeaders=extraHeaders)
if resp.status != httplib.MULTI_STATUS:
- raise WebDAVException() # @@@MOR Any way to recover from this?
+ raise WebDAVException(status=resp.status)
# Parse the propfind, pulling out the URLs for each child along
# with their ETAGs, and storing them in the resourceList dictionary:
@@ -104,6 +114,7 @@
except:
logging.error("Parsing response failed: %s" % text)
raise
+
node = doc.children.children
while node:
if node.type == "element":
@@ -208,7 +219,8 @@
continue
else:
logger.debug("Illegal redirect: %s to %s" % (url, newurl))
- raise IllegalRedirect()
+ message = "Illegal redirect: %s to %s" % (url, newurl)
+ raise IllegalRedirect(message=message)
return response
@@ -217,7 +229,9 @@
raise ConnectionError()
class WebDAVException(Exception):
- pass
+ def __init__(self, status=None, message=None):
+ self.status = status
+ self.message = message
class ConnectionError(WebDAVException):
pass
@@ -235,9 +249,10 @@
# ----------------------------------------------------------------------------
-NO_ACCESS = 0
-READ_ONLY = 1
-READ_WRITE = 2
+CANT_CONNECT = -1
+NO_ACCESS = 0
+READ_ONLY = 1
+READ_WRITE = 2
def checkAccess(host, port=80, useSSL=False, username=None, password=None,
path=None):
@@ -262,8 +277,12 @@
portString = ":%d" % port
url = "%s://%s%s%s" % (scheme, host, portString, path)
- response = client.propfind(url, depth=0)
- body = response.read()
+ try:
+ response = client.propfind(url, depth=0)
+ body = response.read()
+ except ConnectionError, err:
+ return (CANT_CONNECT, None)
+
status = response.status
# print "PROPFIND:", url, status
if status < 200 or status >= 300: # failed to read
Index: chandler/application/dialogs/AccountPreferences_wdr.xrc
diff -u chandler/application/dialogs/AccountPreferences_wdr.xrc:1.9 chandler/application/dialogs/AccountPreferences_wdr.xrc:1.10
--- chandler/application/dialogs/AccountPreferences_wdr.xrc:1.9 Tue Feb 1 12:44:25 2005
+++ chandler/application/dialogs/AccountPreferences_wdr.xrc Thu Feb 3 10:02:07 2005
@@ -474,6 +474,20 @@
<label>Use as default account for sharing</label>
</object>
</object>
+ <object class="sizeritem">
+ <flag>wxALIGN_CENTER|wxALL</flag>
+ <border>5</border>
+ <object class="wxStaticText" name="ID_TEXT">
+ <label></label>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>
+ <border>5</border>
+ <object class="wxButton" name="WEBDAV_TEST">
+ <label>Click to test this account now</label>
+ </object>
+ </object>
</object>
</object>
</object>
Index: chandler/application/dialogs/AccountPreferences.py
diff -u chandler/application/dialogs/AccountPreferences.py:1.23 chandler/application/dialogs/AccountPreferences.py:1.24
--- chandler/application/dialogs/AccountPreferences.py:1.23 Tue Feb 1 12:44:25 2005
+++ chandler/application/dialogs/AccountPreferences.py Thu Feb 3 10:02:06 2005
@@ -5,6 +5,7 @@
from repository.item.Query import KindQuery
import osaf.contentmodel.mail.Mail as Mail
import application.dialogs.Util
+import osaf.framework.sharing.WebDAV as WebDAV
# Used to lookup the mail model parcel:
MAIL_MODEL = "http://osafoundation.org/parcels/osaf/contentmodel/mail"
@@ -44,6 +45,7 @@
for (field, desc) in fields.iteritems():
item.setAttributeValue(desc['attr'], values[field])
+
# Used to map form fields to item attributes:
PANELS = {
"IMAP" : {
@@ -156,6 +158,9 @@
},
},
"id" : "WebDAVPanel",
+ "callbacks" : (
+ ("WEBDAV_TEST", "OnTestWebDAV"),
+ )
},
}
@@ -366,6 +371,9 @@
wx.EVT_RADIOBUTTON(control, control.GetId(),
self.OnExclusiveRadioButton)
+ for callbackReg in PANELS[self.currentPanelType].get('callbacks', ()):
+ self.Bind(wx.EVT_BUTTON, getattr(self, callbackReg[1]),
+ id=wx.xrc.XRCID(callbackReg[0]))
def __StoreFormData(self, panelType, panel, data):
@@ -400,6 +408,38 @@
def OnCancel(self, evt):
self.EndModal(False)
+ def OnTestWebDAV(self, evt):
+ self.__StoreFormData(self.currentPanelType, self.currentPanel,
+ self.data[self.currentIndex]['values'])
+
+ data = self.data[self.currentIndex]['values']
+
+ host = data['WEBDAV_SERVER']
+ port = data['WEBDAV_PORT']
+ useSSL = data['WEBDAV_USE_SSL']
+ username = data['WEBDAV_USERNAME']
+ password = data['WEBDAV_PASSWORD']
+ path = data['WEBDAV_PATH']
+ access = WebDAV.checkAccess(host, port=port, useSSL=useSSL,
+ username=username, password=password,
+ path=path)
+ result = access[0]
+ status = access[1]
+ if result == WebDAV.CANT_CONNECT:
+ msg = "Couldn't connect to %s.\nPlease double-check the server name and port settings." % host
+ elif result == WebDAV.NO_ACCESS:
+ msg = "Permission denied by server '%s'." % host
+ elif result == WebDAV.READ_ONLY:
+ msg = "You have read access but not write access."
+ elif result == WebDAV.READ_WRITE:
+ msg = "Test was successful.\nThis account has read/write access."
+ else:
+ # This shouldn't happen
+ msg = "Test failed with an unknown response."
+
+ application.dialogs.Util.ok(self, "WebDAV Test Results", msg)
+
+
def OnAccountSel(self, evt):
# Huh? This is always False!
# if not evt.IsSelection(): return
Index: chandler/parcels/osaf/framework/sharing/Sharing.py
diff -u chandler/parcels/osaf/framework/sharing/Sharing.py:1.57 chandler/parcels/osaf/framework/sharing/Sharing.py:1.58
--- chandler/parcels/osaf/framework/sharing/Sharing.py:1.57 Wed Feb 2 12:35:55 2005
+++ chandler/parcels/osaf/framework/sharing/Sharing.py Thu Feb 3 10:02:07 2005
@@ -1,5 +1,5 @@
-__version__ = "$Revision: 1.57 $"
-__date__ = "$Date: 2005/02/02 20:35:55 $"
+__version__ = "$Revision: 1.58 $"
+__date__ = "$Date: 2005/02/03 18:02:07 $"
__copyright__ = "Copyright (c) 2004 Open Source Applications Foundation"
__license__ = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
@@ -585,7 +585,6 @@
def getLocation(self): # must implement
""" Return the url of the share """
- # @@@MOR need to handle https
(host, port, sharePath, username, password, useSSL) = self.__getSettings()
scheme = "http"
@@ -649,8 +648,16 @@
def exists(self):
super(WebDAVConduit, self).exists()
- resp = self.__getClient().head(self.getLocation())
- resp.read()
+ try:
+ resp = self.__getClient().head(self.getLocation())
+ resp.read()
+ except WebDAV.ConnectionError, err:
+ raise CouldNotConnect(message=err.message)
+
+ if resp.status == httplib.UNAUTHORIZED:
+ message = "Not authorized to PUT %s" % url
+ raise NotAuthorized(message=message)
+
if resp.status == httplib.NOT_FOUND:
return False
else:
@@ -663,9 +670,36 @@
if style == ImportExportFormat.STYLE_DIRECTORY:
url = self.getLocation()
- resp = self.__getClient().mkcol(url)
- resp.read() # Always need to read each response
- # @@@MOR Raise an exception if already exists?
+ try:
+ resp = self.__getClient().mkcol(url)
+ resp.read() # Always need to read each response
+ except WebDAV.ConnectionError, err:
+ raise CouldNotConnect(message=err.message)
+
+ if resp.status == httplib.METHOD_NOT_ALLOWED:
+ # already exists
+ message = "Collection at %s already exists" % url
+ raise AlreadyExists(message=message)
+
+ if resp.status == httplib.UNAUTHORIZED:
+ # not authorized
+ message = "Not authorized to create collection %s" % url
+ raise NotAuthorized(message=message)
+
+ if resp.status == httplib.CONFLICT:
+ # this happens if you try to create a collection within a
+ # nonexistent collection
+ message = "Parent collection for %s not found" % url
+ raise NotFound(message=message)
+
+ if resp.status == httplib.FORBIDDEN:
+ # the server doesn't allow the creation of a collection here
+ message = "Server doesn't allow the creation of collections at %s" % url
+ raise IllegalOperation(message=message)
+
+ if resp.status != httplib.CREATED:
+ message = "WebDAV error, status = %d" % resp.status
+ raise IllegalOperation(message=message)
def destroy(self):
print " @@@MOR unimplemented"
@@ -678,13 +712,34 @@
"""
url = self.__getItemURL(item)
text = self.share.format.exportProcess(item)
- resp = self.__getClient().put(url, text)
- resp.read() # Always need to read each response
+
+ try:
+ resp = self.__getClient().put(url, text)
+ resp.read() # Always need to read each response
+ except WebDAV.ConnectionError, err:
+ raise CouldNotConnect(message=err.message)
+
+ # 201 = new, 204 = overwrite
+
+ if resp.status == httplib.UNAUTHORIZED:
+ message = "Not authorized to PUT %s" % url
+ raise NotAuthorized(message=message)
+
+ if resp.status == httplib.FORBIDDEN or resp.status == httplib.CONFLICT:
+ # seen if trying to PUT to a nonexistent collection (@@@MOR verify)
+ message = "Parent collection for %s is not found" % url
+ raise NotFound(message=message)
+
etag = resp.getheader('ETag', None)
if not etag:
# mod_dav doesn't give us back an etag upon PUT
- resp = self.__getClient().head(url)
- resp.read() # Always need to read each response
+
+ try:
+ resp = self.__getClient().head(url)
+ resp.read() # Always need to read each response
+ except WebDAV.ConnectionError, err:
+ raise CouldNotConnect(message=err.message)
+
etag = resp.getheader('ETag', None)
if not etag:
print "HEAD didn't give me an etag"
@@ -705,13 +760,30 @@
def _deleteItem(self, itemPath): # must implement
itemURL = self.__URLFromPath(itemPath)
logger.info("...removing from server: %s" % itemURL)
- resp = self.__getClient().delete(itemURL)
- deleteResp = resp.read()
+
+ try:
+ resp = self.__getClient().delete(itemURL)
+ deleteResp = resp.read()
+ except WebDAV.ConnectionError, err:
+ raise CouldNotConnect(message=err.message)
def _getItem(self, itemPath, into=None): # must implement
itemURL = self.__URLFromPath(itemPath)
- resp = self.__getClient().get(itemURL)
- text = resp.read()
+
+ try:
+ resp = self.__getClient().get(itemURL)
+ text = resp.read()
+ except WebDAV.ConnectionError, err:
+ raise CouldNotConnect(message=err.message)
+
+ if resp.status == httplib.NOT_FOUND:
+ message = "Not found: %s" % url
+ raise NotFound(message=message)
+
+ if resp.status == httplib.UNAUTHORIZED:
+ message = "Not authorized to get %s" % url
+ raise NotAuthorized(message=message)
+
etag = resp.getheader('ETag', None)
etag = self.__cleanEtag(etag)
item = self.share.format.importProcess(text, item=into)
@@ -726,14 +798,42 @@
if style == ImportExportFormat.STYLE_DIRECTORY:
- resources = self.__getClient().ls(location + "/")
+ try:
+ resources = self.__getClient().ls(location + "/")
+
+ except WebDAV.ConnectionError, err:
+ raise CouldNotConnect(message=err.message)
+
+ except WebDAV.WebDAVException, e:
+
+ if e.status == httplib.NOT_FOUND:
+ raise NotFound(message="Not found: %s" % location)
+
+ if e.status == httplib.UNAUTHORIZED:
+ raise NotAllowed(message="Not allowed: %s" % location)
+
+ raise
+
for (path, etag) in resources:
etag = self.__cleanEtag(etag)
resourceList[path] = { 'data' : etag }
elif style == ImportExportFormat.STYLE_SINGLE:
- resp = self.__getClient().head(location)
- resp.read() # Always need to read each response
+
+ try:
+ resp = self.__getClient().head(location)
+ resp.read() # Always need to read each response
+ except WebDAV.ConnectionError, err:
+ raise CouldNotConnect(message=err.message)
+
+ if resp.status == httplib.NOT_FOUND:
+ message = "Not found: %s" % url
+ raise NotFound(message=message)
+
+ if resp.status == httplib.UNAUTHORIZED:
+ message = "Not authorized to get %s" % url
+ raise NotAuthorized(message=message)
+
etag = resp.getheader('ETag', None)
etag = self.__cleanEtag(etag)
path = urlparse.urlparse(location)[2]
@@ -763,23 +863,30 @@
class SharingError(Exception):
""" Generic Sharing exception. """
- pass
+ def __init__(self, message=None):
+ self.message = message
class AlreadyExists(SharingError):
""" Exception raised if a share already exists. """
- pass
class NotFound(SharingError):
""" Exception raised if a share/resource wasn't found. """
- pass
class NotAllowed(SharingError):
""" Exception raised if we don't have access. """
- pass
class Misconfigured(SharingError):
""" Exception raised if a share isn't properly configured. """
- pass
+
+class CouldNotConnect(SharingError):
+ """ Exception raised if a conduit can't connect to an external entity
+ due to DNS/network problems.
+ """
+
+class IllegalOperation(SharingError):
+ """ Exception raised if the entity a conduit is communicating with is
+ denying an operation for some reason not covered by other exceptions.
+ """
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
@@ -1542,6 +1649,13 @@
return False
+def syncShare(share):
+ """ @@@MOR In progress
+ try:
+ share.sync()
+ except WebDAV.ConnectionError, err:
+ """
+
def syncAll(view):
""" Synchronize all active shares.
More information about the Commits
mailing list