""" Utility classes & functions for ZSyncer and UIs. """ # Std. lib imports. import types # Zope imports. import Acquisition from Acquisition import aq_base from AccessControl import ClassSecurityInfo import DateTime from DateTime.DateTime import DateTimeError from DocumentTemplate.DT_Util import html_quote import Globals # ZSyncer imports. import Config class ZSyncerConfigError(Exception): """There is a problem with the configuration of this ZSyncer. """ class ZSyncerObjNotFound(Exception): """ZSyncer could not find an object at the path. """ ########################################################################## # Logging & UI messages ########################################################################## class TextMsg: """For logging & output of arbitrary text. """ color = 'black' status = 200 def __init__(self, msg): self.msg = msg def __str__(self): return str(self.msg) def html(self): return '
%s
\n' % (self.color, html_quote(self.msg)) class StatusMsg(TextMsg): #, Acquisition.Implicit): """For logging & output of remote call results. """ def __init__(self, msg, status, context=None): """msg may be a text string or a TextMsg. """ status = int(status) if isinstance(msg, TextMsg): msg = msg.msg self.status = status if status == 200: self.color = Config.color_200 if not msg.startswith('OK'): msg = 'OK: %s' % msg self.msg = msg else: self.color = Config.color_error self.msg = '%s: %s' % (Config.error_messages.get(str(status), 'Unknown error!'), msg) def __eq__(self, other): # Useful for testing. return (other.msg == self.msg and other.status == self.status) def __repr__(self): # Useful for testing. return '%s("%s", %s)' % (self.__class__.__name__, self.msg, self.status) # This is necessary in order to use the Msg classes in untrusted code. from Products.PythonScripts.Utility import allow_class allow_class(StatusMsg) allow_class(TextMsg) ############################################################################ # Utility classes & functions ############################################################################ def normalizeRelativeURL(url): """ utility function - does basically what os.path.normpath() does for filesystem paths, but for URLs instead. Does not verify whether anything exists at the path. """ if not isinstance(url, types.StringType): raise TypeError url = url.strip() elements = url.split('/') if not elements: return '/' norm_elements = [] for e in elements: e = e.strip() if e in ('', '.'): continue elif e == '..': try: norm_elements.pop() except IndexError: continue else: norm_elements.append(e) result = '/'.join(norm_elements) # We've thrown away any leading slashes, so put one back if needed. if url and url[0] == '/': result = '/' + result return result def isZClassFolder(obj): base_obj = aq_base(obj) is_zclass = (getattr(base_obj, 'meta_type', None) == 'Z Class' and getattr(base_obj, 'propertysheets', None) and getattr(base_obj.propertysheets, 'methods', None) ) return not not is_zclass # boolean hack for compatibility with py 2.1 def lstrip(astring, prefix=' '): """Workaround for the fact that ''.lstrip() takes no arguments in python 2.1. This can be deleted and replaced with ''.lstrip() once we require zope 2.7. """ pre_len = len(prefix) while prefix and astring[:pre_len] == prefix: astring = astring[pre_len:] return astring def normalize_time(datetime): """Convert datetime to string representing time in local zone. The datetime arg can be either a string parsable by DateTime.DateTime(), or it can already be a DateTime instance. Output is sort of like that used by ls -l (i.e. only show year if it's not this year), e.g.: 'Aug 5 2003' or 'Sep 21 23:22'. If the input is a string that cannot be parsed, return ''. """ # XXX I wanted to have it possible to pass a timezone string # like "UTC" and see the time represented in that zone, # but this does not work because DateTime().strftime() # always shows you the result in the local timezone regardless # of the args used to construct the DateTime instance. # The methods with names ending in Z do preserve the timezone, # but you have no real control over the output format. Bah. # There does not seem to be any good solution. if type(datetime) is types.StringType: try: datetime = DateTime.DateTime(datetime) except DateTimeError: return '' ##show_zone = zone ##zone = zone or DateTime().localZone() ##datetime = DateTime(datetime, zone) # show year, and no hour/minute, if the day is not in this year. if not datetime.isCurrentYear(): fmt = r'%b %d, %Y' else: fmt = r'%b %d %H:%M' # Timezone only makes sense if we're showing hour/minute. # XXX aargh, we cannot control the timezone displayed, see above. ##if show_zone: ## fmt = fmt + r' %Z' return datetime.strftime(fmt) def listSyncers(context): """Get a list of dicts representing all acquirable syncers. Useful for ZMI 'sync' tab. Dictionary keys are: 'url', 'syncer'. """ zsyncers = context.superValues('ZSyncer') tools = context.superValues('Portal ZSyncer Tool') for tool in tools: zsyncers.extend(tool.objectValues('ZSyncer')) urls = [] for zs in zsyncers: try: rel_path = '/'.join(zs._getRelativePhysicalPath(context, strict=1)) except ValueError: # The context is not within the base path of that # syncer, so, skip it. continue url = '%s/manage_sync?folder=%s' % (zs.absolute_url(), rel_path) urls.append({'syncer': zs, 'url': url}) return urls