diff --git a/browser/common.py b/browser/common.py index a6bd733..bbb9c1e 100755 --- a/browser/common.py +++ b/browser/common.py @@ -1010,7 +1010,7 @@ class BaseView(GenericView, I18NView, SortableMixin): def registerDojoComboBox(self): self.registerDojo() jsCall = ('dojo.require("dijit.form.ComboBox");') - self.controller.macros.register('js-execute', + self.controller.macros.register('js-execute', 'dojo.require.ComboBox', jsCall=jsCall) def registerDojoFormAll(self): @@ -1066,6 +1066,7 @@ class LoggedIn(object): params = parse_qsl(qs) params = [(k, v) for k, v in params if k != 'loops.messages.top:record'] params.append(('loops.messages.top:record', message.encode('UTF-8'))) + url = url.encode('utf-8') return '%s?%s' % (url, urlencode(params)) # vocabulary stuff diff --git a/browser/node.py b/browser/node.py index e38983f..12bc893 100755 --- a/browser/node.py +++ b/browser/node.py @@ -954,7 +954,8 @@ class NodeTraverser(ItemTraverser): if context.nodeType == 'menu': setViewConfiguration(context, request) if name == '.loops': - return self.context.getLoopsRoot() + name = self.getTargetUid(request) + #return self.context.getLoopsRoot() if name.startswith('.'): name = self.cleanUpTraversalStack(request, name)[1:] target = self.getTarget(name) @@ -981,17 +982,34 @@ class NodeTraverser(ItemTraverser): obj = super(NodeTraverser, self).publishTraverse(request, name) return obj + def getTargetUid(self, request): + parent = self.context.getLoopsRoot() + stack = request._traversal_stack + for i in range(2): + name = stack.pop() + obj = parent.get(name) + if not obj: + return name + parent = obj + return '.' + util.getUidForObject(obj) + def cleanUpTraversalStack(self, request, name): - traversalStack = request._traversal_stack - while traversalStack and traversalStack[0].startswith('.'): + #traversalStack = request._traversal_stack + #while traversalStack and traversalStack[0].startswith('.'): # skip obsolete target references in the url - name = traversalStack.pop(0) + # name = traversalStack.pop(0) traversedNames = request._traversed_names - if traversedNames: - lastTraversed = traversedNames[-1] - if lastTraversed.startswith('.') and lastTraversed != name: + for n in list(traversedNames): + if n.startswith('.'): + # remove obsolete target refs + traversedNames.remove(n) + #if traversedNames: + # lastTraversed = traversedNames[-1] + # if lastTraversed.startswith('.') and lastTraversed != name: # let tag show the current object - traversedNames[-1] = name + # traversedNames[-1] = name + # let tag show the current object + traversedNames.append(name) return name def getTarget(self, name): diff --git a/data/loops_std_de.dmp b/data/loops_std_de.dmp index 3bb354a..4f5c97c 100644 --- a/data/loops_std_de.dmp +++ b/data/loops_std_de.dmp @@ -1,6 +1,8 @@ # types type(u'query', u'Abfrage', options=u'', typeInterface='loops.expert.concept.IQueryConcept', viewName=u'') +type(u'datatable', u'Datentabelle', options=u'action.portlet:edit_concept', + typeInterface='loops.table.IDataTable', viewName=u'') type(u'task', u'Aufgabe', options=u'', typeInterface='loops.knowledge.interfaces.ITask', viewName=u'') type(u'domain', u'Bereich', options=u'', typeInterface=u'', viewName=u'') diff --git a/data/loops_std_update_de.dmp b/data/loops_std_update_de.dmp new file mode 100644 index 0000000..23c9be3 --- /dev/null +++ b/data/loops_std_update_de.dmp @@ -0,0 +1,9 @@ +# update for old loops sites + +type(u'datatable', u'Datentabelle', options=u'action.portlet:edit_concept', + typeInterface='loops.table.IDataTable', viewName=u'') + +concept(u'issubtype', u'is Subtype', u'predicate') + +child(u'general', u'issubtype', u'datatable') +child(u'system', u'issubtype', u'standard') diff --git a/external/pyfunc.py b/external/pyfunc.py index 83a0293..b4f7969 100644 --- a/external/pyfunc.py +++ b/external/pyfunc.py @@ -44,11 +44,15 @@ class PyReader(object): class InputProcessor(dict): + _constants = dict(True=True, False=False) + def __init__(self): self.elements = [] - self['__builtins__'] = {} # security! + self['__builtins__'] = dict() # security! def __getitem__(self, key): + if key in self._constants: + return self._constants[key] def factory(*args, **kw): element = elementTypes[key](*args, **kw) if key in toplevelElements: diff --git a/integrator/browser.py b/integrator/browser.py index aeafa87..e76c012 100644 --- a/integrator/browser.py +++ b/integrator/browser.py @@ -44,5 +44,7 @@ class ExternalCollectionView(ConceptView): cta.update() if cta.updateMessage is not None: self.request.form['message'] = cta.updateMessage + if 'no_show_page' in self.request.form: + return False return True diff --git a/integrator/collection.py b/integrator/collection.py index 167974b..b33fe4f 100644 --- a/integrator/collection.py +++ b/integrator/collection.py @@ -24,8 +24,10 @@ file system. from datetime import datetime from logging import getLogger import os, re, stat +import transaction from zope.app.container.interfaces import INameChooser +from zope.app.container.contained import ObjectRemovedEvent from zope.cachedescriptors.property import Lazy from zope import component from zope.component import adapts @@ -51,6 +53,8 @@ from loops.versioning.interfaces import IVersionable TypeInterfaceSourceList.typeInterfaces += (IExternalCollection,) +logger = getLogger('loops.integrator.collection') + class ExternalCollectionAdapter(AdapterBase): """ A concept adapter for accessing an external collection. @@ -66,7 +70,7 @@ class ExternalCollectionAdapter(AdapterBase): newResources = None updateMessage = None - + def getExclude(self): return getattr(self.context, '_exclude', None) or [] def setExclude(self, value): @@ -83,10 +87,11 @@ class ExternalCollectionAdapter(AdapterBase): print '###', vaddr, vobj, vid versions.add(vaddr) new = [] - oldFound = [] + oldFound = set([]) provider = component.getUtility(IExternalCollectionProvider, name=self.providerName or '') #print '*** old', old, versions, self.lastUpdated + changeCount = 0 for addr, mdate in provider.collect(self): #print '***', addr, mdate if addr in versions: @@ -94,8 +99,9 @@ class ExternalCollectionAdapter(AdapterBase): if addr in old: # may be it would be better to return a file's hash # for checking for changes... - oldFound.append(addr) + oldFound.add(addr) if self.lastUpdated is None or (mdate and mdate > self.lastUpdated): + changeCount +=1 obj = old[addr] # update settings and regenerate scale variant for media asset adobj = adapted(obj) @@ -110,29 +116,41 @@ class ExternalCollectionAdapter(AdapterBase): self.updateMessage = message # force reindexing notify(ObjectModifiedEvent(obj)) + if changeCount % 10 == 0: + logger.info('Updated: %i.' % changeCount) + transaction.commit() else: new.append(addr) + logger.info('%i objects updated.' % changeCount) + transaction.commit() if new: self.newResources = provider.createExtFileObjects(self, new) for r in self.newResources: self.context.assignResource(r) + logger.info('%i objects created.' % len(new)) + transaction.commit() for addr in old: if str(addr) not in oldFound: # not part of the collection any more # TODO: only remove from collection but keep object? self.remove(old[addr]) + transaction.commit() for r in self.context.getResources(): adobj = adapted(r) if self.metaInfo != adobj.metaInfo and ( not adobj.metaInfo or self.overwriteMetaInfo): adobj.metaInfo = self.metaInfo self.lastUpdated = datetime.today() + logger.info('External collection updated.') + transaction.commit() def clear(self): for obj in self.context.getResources(): self.remove(obj) def remove(self, obj): + logger.info('Removing object: %s.' % getName(obj)) + notify(ObjectRemovedEvent(obj)) del self.resourceManager[getName(obj)] @Lazy @@ -187,7 +205,7 @@ class DirectoryCollectionProvider(object): for k, v in self.extFileTypeMapping.items()) container = client.context.getLoopsRoot().getResourceManager() directory = self.getDirectory(client) - for addr in addresses: + for idx, addr in enumerate(addresses): name = self.generateName(container, addr) title = self.generateTitle(addr) contentType = guess_content_type(addr, @@ -200,9 +218,8 @@ class DirectoryCollectionProvider(object): if extFileType is None: extFileType = extFileTypes['image/*'] if extFileType is None: - getLogger('loops.integrator.collection.DirectoryCollectionProvider' - ).warn('No external file type found for %r, ' - 'content type: %r' % (name, contentType)) + logger.warn('No external file type found for %r, ' + 'content type: %r' % (name, contentType)) obj = addAndConfigureObject( container, Resource, name, title=title, @@ -219,6 +236,9 @@ class DirectoryCollectionProvider(object): message = client.updateMessage or u'' message += u'
'.join(adobj.processingErrors) client.updateMessage = message + if idx and idx % 10 == 0: + logger.info('Created: %i.' % idx) + transaction.commit() yield obj def getDirectory(self, client): diff --git a/integrator/collection_macros.pt b/integrator/collection_macros.pt index 8c3e898..57e5a4b 100644 --- a/integrator/collection_macros.pt +++ b/integrator/collection_macros.pt @@ -2,7 +2,7 @@ + tal:condition="item/update"> Send Link by Email - -
- +
-
-
-
- + +
+
+
-
- + +
+
+ +
diff --git a/organize/party.py b/organize/party.py index 64247b3..0fbc05b 100644 --- a/organize/party.py +++ b/organize/party.py @@ -24,6 +24,7 @@ from persistent.mapping import PersistentMapping from zope import interface, component from zope.app.principalannotation import annotations from zope.app.security.interfaces import IAuthentication, PrincipalLookupError +from zope.app.security.interfaces import IUnauthenticatedPrincipal from zope.component import adapts from zope.interface import implements from zope.cachedescriptors.property import Lazy @@ -60,10 +61,10 @@ def getPersonForUser(context, request=None, principal=None): if context is None: return None if principal is None: - if request is None: - principal = getCurrentPrincipal() - else: + if request is not None: principal = getattr(request, 'principal', None) + else: + principal = getPrincipal(context) if principal is None: return None loops = context.getLoopsRoot() @@ -78,6 +79,15 @@ def getPersonForUser(context, request=None, principal=None): return pa.get(util.getUidForObject(loops)) +def getPrincipal(context): + principal = getCurrentPrincipal() + if principal is not None: + if IUnauthenticatedPrincipal.providedBy(principal): + return None + return principal + return None + + class Person(AdapterBase, BasePerson): """ typeInterface adapter for concepts of type 'person'. """ diff --git a/organize/tracking/report.pt b/organize/tracking/report.pt index 41ee48f..a34ed9f 100644 --- a/organize/tracking/report.pt +++ b/organize/tracking/report.pt @@ -79,7 +79,7 @@ - 1.1 diff --git a/organize/tracking/report.py b/organize/tracking/report.py index d1ee35e..a019865 100644 --- a/organize/tracking/report.py +++ b/organize/tracking/report.py @@ -275,7 +275,9 @@ class TrackDetails(BaseView): else: title = view.listingTitle versionable = IVersionable(self.object, None) - version = versionable is not None and versionable.versionId or '' + version = ((versionable is not None and + not (versionable.notVersioned) and + versionable.versionId) or '') return dict(object=obj, title=title, type=self.longTypeTitle, url=url, version=version, canAccess=canAccessObject(obj))