From bc8e42240e793ac9e3ea444f65a4d6b635ae52bc Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Mon, 22 Jul 2013 11:54:42 +0200 Subject: [PATCH 1/4] correctly reference target (not 'context') --- organize/stateful/browser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/organize/stateful/browser.py b/organize/stateful/browser.py index 6d97497..fea8bf3 100644 --- a/organize/stateful/browser.py +++ b/organize/stateful/browser.py @@ -145,8 +145,8 @@ class ChangeState(ChangeStateBase, EditObject): def update(self): formData = self.request.form - # store data in context (unless field.nostore) - self.object = self.context + # store data in target object (unless field.nostore) + self.object = self.target formState = self.instance.applyTemplate(data=formData) # TODO: check formState # track all fields From 349dc89bb8c2408467eb8584c5942e2333574896 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Mon, 22 Jul 2013 11:55:38 +0200 Subject: [PATCH 2/4] work in progress: allow linking to parents from other loops sites: allow selection of foreign types --- browser/common.py | 22 ++++++++++++++++++++-- type.py | 19 +++++++++++++------ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/browser/common.py b/browser/common.py index d8886e3..d319f09 100644 --- a/browser/common.py +++ b/browser/common.py @@ -49,7 +49,7 @@ from zope.security import canAccess from zope.security.interfaces import ForbiddenAttribute, Unauthorized from zope.security.proxy import removeSecurityProxy from zope.traversing.browser import absoluteURL -from zope.traversing.api import getName, getParent +from zope.traversing.api import getName, getParent, traverse from cybertools.ajax.dojo import dojoMacroTemplate from cybertools.browser.view import GenericView @@ -70,7 +70,7 @@ from loops.organize.tracking import access from loops.resource import Resource from loops.security.common import checkPermission from loops.security.common import canAccessObject, canListObject, canWriteObject -from loops.type import ITypeConcept +from loops.type import ITypeConcept, LoopsTypeInfo from loops import util from loops.util import _, saveRequest from loops import version @@ -531,11 +531,29 @@ class BaseView(GenericView, I18NView): def conceptTypes(self): return util.KeywordVocabulary(self.listTypes(('concept',), ('hidden',))) + def parentTypesFromOtherSites(self): + result = [] + typeNames = self.typeOptions('parent_link_types') or [] + for path in self.typeOptions('parent_link_sites') or []: + site = traverse(self.loopsRoot, path, None) + if site is None: + continue + cm = site.getConceptManager() + for tname in typeNames: + t = cm.get(tname) + if t is not None: + type = LoopsTypeInfo(t) + type.isForeignReference = True + result.append(type) + return result + def listTypesForSearch(self, include=None, exclude=None, sortOn='title'): types = [dict(token=t.tokenForSearch, title=t.title) for t in ITypeManager(self.context).listTypes(include, exclude)] if sortOn: types.sort(key=lambda x: x[sortOn]) + for t in self.parentTypesFromOtherSites(): + types.append(dict(token=t.tokenForSearch, title=t.title)) return types def typesForSearch(self): diff --git a/type.py b/type.py index d6feec4..64f9615 100644 --- a/type.py +++ b/type.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2006 Helmut Merz helmutm@cy55.de +# Copyright (c) 2013 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,8 +18,6 @@ """ Type management stuff. - -$Id$ """ from zope import component, schema @@ -28,7 +26,7 @@ from zope.interface import implements from zope.cachedescriptors.property import Lazy from zope.dottedname.resolve import resolve from zope.security.proxy import removeSecurityProxy -from zope.traversing.api import getName +from zope.traversing.api import getName, getPath from cybertools.typology.type import BaseType, TypeManager from cybertools.typology.interfaces import ITypeManager @@ -50,10 +48,15 @@ class LoopsType(BaseType): #document=Document) containerMapping = dict(concept='concepts', resource='resources') + isForeignReference = False + @Lazy def title(self): tp = self.typeProvider - return tp is None and u'Unknown Type' or tp.title + title = tp is None and u'Unknown Type' or tp.title + if self.isForeignReference: + title += (' (Site: %s)' % getName(self.root)) + return title @Lazy def token(self): @@ -64,7 +67,11 @@ class LoopsType(BaseType): def tokenForSearch(self): tp = self.typeProvider typeName = tp is None and 'unknown' or str(getName(tp)) - return ':'.join(('loops', self.qualifiers[0], typeName,)) + if self.isForeignReference: + root = '/'.join(getPath(self.root)) + else: + root = 'loops' + return ':'.join((root, self.qualifiers[0], typeName,)) @Lazy def typeInterface(self): From ccb4673268f908b0cf0245f924bda19ec883f3da Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Mon, 22 Jul 2013 13:16:19 +0200 Subject: [PATCH 3/4] working: link to parents from other loops sites: query and assign type instances from foreign site --- expert/browser/search.py | 12 +++++++----- expert/concept.py | 12 ++++++++---- type.py | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/expert/browser/search.py b/expert/browser/search.py index af4f437..1776e57 100644 --- a/expert/browser/search.py +++ b/expert/browser/search.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2011 Helmut Merz helmutm@cy55.de +# Copyright (c) 2013 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -19,14 +19,12 @@ """ Definition of basic view classes and other browser related stuff for the loops.expert package. - -$Id$ """ from zope import interface, component from zope.app.pagetemplate import ViewPageTemplateFile from zope.cachedescriptors.property import Lazy -from zope.traversing.api import getName, getParent +from zope.traversing.api import getName, getParent, traverse from cybertools.browser.form import FormController from cybertools.stateful.interfaces import IStateful, IStatesDefinition @@ -150,12 +148,16 @@ class Search(ConceptView): if not isinstance(types, (list, tuple)): types = [types] for type in types: + site = self.loopsRoot + if type.startswith('/'): + parts = type.split(':') + site = traverse(self.loopsRoot, parts[0], site) result = self.executeQuery(title=title or None, type=type, exclude=('hidden',)) fv = FilterView(self.context, self.request) result = fv.apply(result) for o in result: - if o.getLoopsRoot() == self.loopsRoot: + if o.getLoopsRoot() == site: adObj = adapted(o, self.languageInfo) if filterMethod is not None and not filterMethod(adObj): continue diff --git a/expert/concept.py b/expert/concept.py index abd0b6f..d87dfcf 100644 --- a/expert/concept.py +++ b/expert/concept.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2008 Helmut Merz helmutm@cy55.de +# Copyright (c) 2013 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,8 +18,6 @@ """ Query concepts management stuff. - -$Id$ """ from BTrees.IOBTree import IOBTree @@ -29,6 +27,7 @@ from zope.interface import Interface, Attribute, implements from zope.app.catalog.interfaces import ICatalog from zope.app.intid.interfaces import IIntIds from zope.cachedescriptors.property import Lazy +from zope.traversing.api import traverse from cybertools.typology.interfaces import IType from loops.common import AdapterBase @@ -66,6 +65,11 @@ class BaseQuery(object): return self.context.context.getLoopsRoot() def queryConcepts(self, title=None, type=None, **kw): + site = self.loopsRoot + if type.startswith('/'): + parts = type.split(':') + site = traverse(self.loopsRoot, parts[0], site) + type = 'loops:' + ':'.join(parts[1:]) if type.endswith('*'): start = type[:-1] end = start + '\x7f' @@ -76,7 +80,7 @@ class BaseQuery(object): result = cat.searchResults(loops_type=(start, end), loops_title=title) else: result = cat.searchResults(loops_type=(start, end)) - result = set(r for r in result if r.getLoopsRoot() == self.loopsRoot + result = set(r for r in result if r.getLoopsRoot() == site and canListObject(r)) if 'exclude' in kw: r1 = set() diff --git a/type.py b/type.py index 64f9615..0f9ffee 100644 --- a/type.py +++ b/type.py @@ -68,7 +68,7 @@ class LoopsType(BaseType): tp = self.typeProvider typeName = tp is None and 'unknown' or str(getName(tp)) if self.isForeignReference: - root = '/'.join(getPath(self.root)) + root = getPath(self.root) else: root = 'loops' return ':'.join((root, self.qualifiers[0], typeName,)) From de822e717f308bf4e2cfd9f50f520ee978ae398c Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Wed, 24 Jul 2013 09:18:52 +0200 Subject: [PATCH 4/4] better name for option ('foreign_parent_...') --- browser/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser/common.py b/browser/common.py index d319f09..82c6d65 100644 --- a/browser/common.py +++ b/browser/common.py @@ -533,8 +533,8 @@ class BaseView(GenericView, I18NView): def parentTypesFromOtherSites(self): result = [] - typeNames = self.typeOptions('parent_link_types') or [] - for path in self.typeOptions('parent_link_sites') or []: + typeNames = self.typeOptions('foreign_parent_types') or [] + for path in self.typeOptions('foreign_parent_sites') or []: site = traverse(self.loopsRoot, path, None) if site is None: continue